0

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?

r2evans
  • 141,215
  • 6
  • 77
  • 149
Lola1993
  • 151
  • 6
  • You're doing this for reporting, right? Once you use `format` or similar, you no longer have numbers. – r2evans Apr 09 '21 at 19:04
  • BTW, please be a little more mindful of the tags on your question, since the StackExchange tag recommendation is imperfect. I removed three tags that seem to have nothing directly to do with your question: [tag:dplyr], [tag:tidyverse], and [tag:readr]. – r2evans Apr 09 '21 at 20:51
  • Thank you SO UNBELIEVABLY much! sorry about the tags! – Lola1993 Apr 09 '21 at 22:35
  • The tags are really minor, just bringing it to your attention in case you believed the tag-recommendation engine knew something you did not (it does not). Glad it worked! – r2evans Apr 09 '21 at 23:57

1 Answers1

4

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"  
r2evans
  • 141,215
  • 6
  • 77
  • 149
  • 1
    Hey r2Evans, where exactly do you paste this? I keep gettting an error : "dig not found" – Lola1993 May 14 '21 at 19:09
  • r2evans, I am super sorry but will go back to this... In fact, it does not achieve the desired output. For instance, if i input it 1 it outputs 1.000 whereas it should output 1.00 (three digits of significance) do you have any idea? – Lola1993 May 15 '21 at 01:06
  • Lola1993 see my edit, perhaps it's closer. – r2evans May 15 '21 at 15:46
  • 1
    You're the best r2evans! Thank you so unbelievably much - I would have never figured it out myself! – Lola1993 May 15 '21 at 20:19