Lola1993
Lola1993

Reputation: 161

Have three significant decimal digits even with 0 and no decimals in R

I would like to return all numbers with 3 significant digits after the decimal, even if the third digit is zero.

For instance suppose I have

x <- 0.8579
y <- 0.21
z <- 924894.2595

Then if I do

x <- signif(x, digits=3) 
y <- signif(y, digits=3) 
z <- signif(z, digits=3) 

I get x = 0.857 y=0.21 and z=924894

This is almost what I want. What i actually want is

x = 0.857 y=0.210 and z=924894

I have tried using

format(round(x,3), digits=3)

But doing this I get

x = 0.857 y=0.210 and z=924894.259

So now I have an issue on z, since I actually want z=924894.

Does anyone know of an answer in between to solve my issue?

Upvotes: 0

Views: 846

Answers (1)

r2evans
r2evans

Reputation: 160417

Your expected "signif digits" for 924894 is not correct, though, since it is showing 6 signif digits. If you want to "violate" that technicality, then perhaps

vec <- c(0.857,0.210,924894.259)
dig <- 3
sprintf(paste0("%0.", ifelse(vec >= (10^dig), "0", dig), "f"), vec)
# [1] "0.857"  "0.210"  "924894"

(I'm being a little sloppy with ifelse here: technically, "0" is character and dig is numeric/integer. This should be discouraged in general, and is enforced by dplyr::if_else and data.table::fifelse. This might mean that the return value from the ifelse expression may be character (if anything is large enough) or integer/numeric (if nothing is large enough); fortunately, however, paste0 will deal with it exactly the same, so the slop of class-imprecision is acceptable here. If I wanted to be thorough, I'd use as.character(dig) instead.)


An alternative, that reacts to the apparent scale of each number individually:

vec <- c(0.857,0.210,924894.259,1)
sprintf(paste0("%0.", pmax(floor(3 - log(abs(vec)+0.001, 10)), 0), "f"), vec)
# [1] "0.857"  "0.210"  "924894" "1.00"  

Upvotes: 4

Related Questions