How does the digits parameter in R's prettyNum() function work? - r

In R I'm using the prettyNum() function to format some numbers but I'm having a hard time getting the number of digits I want. The help docs say:
the desired number of digits after the decimal point (format = "f") or significant digits (format = "g", = "e" or = "fg").
Default: 2 for integer, 4 for real numbers. If less than 0, the C default of 6 digits is used. If specified as more than 50, 50 will be used with a warning unless format = "f" where it is limited to typically 324. (Not more than 15–21 digits need be accurate, depending on the OS and compiler used. This limit is just a precaution against segfaults in the underlying C runtime.)
To me, this seems to mean that prettyNum(404.5142, digits = 2) should give me "404.51" but in reality it produces "405". Can someone explain how to get it to round to a fixed number (say 2) of digits after the decimal place? I'd like it to include tailing 0s too.

The help file for prettyNum is also documenting formatC, to which the parameter digits belongs. The prettyNum function does not have a parameter called digits.
The reason why this doesn't result in an error is that your argument digits is being passed via ... to format.
...       arguments passed to format.
In format, the parameter digits is different to the digits parameter in formatC. It means the number of significant digits, not the number of digits after the decimal point. Yes, this is a bit confusing in the documents, but it means for example that you could do:
prettyNum(404.5142, digits = 5)
#> [1] "404.51"
However, this will give you the wrong number of digits if you do, for example:
prettyNum(44.5142, digits = 5)
#> [1] "44.514"
And therefore you would be safer to use something like formatC, which allows
formatC(404.5142, format = "f", digits = 2)
#> [1] "404.51"
and
formatC(44.5142, format = "f", digits = 2)
#> 1] "44.51"
Which seems to be what you are looking for.

Related

how many digits does R carry in a numeric calculation (how to increase number of digits in R Numeric) [duplicate]

There is an option in R to get control over digit display. For example:
options(digits=10)
is supposed to give the calculation results in 10 digits till the end of R session. In the help file of R, the definition for digits parameter is as follows:
digits: controls the number of digits
to print when printing numeric values.
It is a suggestion only. Valid values
are 1...22 with default 7
So, it says this is a suggestion only. What if I like to always display 10 digits, not more or less?
My second question is, what if I like to display more than 22 digits, i.e. for more precise calculations like 100 digits? Is it possible with base R, or do I need an additional package/function for that?
Edit: Thanks to jmoy's suggestion, I tried sprintf("%.100f",pi) and it gave
[1] "3.1415926535897931159979634685441851615905761718750000000000000000000000000000000000000000000000000000"
which has 48 decimals. Is this the maximum limit R can handle?
The reason it is only a suggestion is that you could quite easily write a print function that ignored the options value. The built-in printing and formatting functions do use the options value as a default.
As to the second question, since R uses finite precision arithmetic, your answers aren't accurate beyond 15 or 16 decimal places, so in general, more aren't required. The gmp and rcdd packages deal with multiple precision arithmetic (via an interace to the gmp library), but this is mostly related to big integers rather than more decimal places for your doubles.
Mathematica or Maple will allow you to give as many decimal places as your heart desires.
EDIT:
It might be useful to think about the difference between decimal places and significant figures. If you are doing statistical tests that rely on differences beyond the 15th significant figure, then your analysis is almost certainly junk.
On the other hand, if you are just dealing with very small numbers, that is less of a problem, since R can handle number as small as .Machine$double.xmin (usually 2e-308).
Compare these two analyses.
x1 <- rnorm(50, 1, 1e-15)
y1 <- rnorm(50, 1 + 1e-15, 1e-15)
t.test(x1, y1) #Should throw an error
x2 <- rnorm(50, 0, 1e-15)
y2 <- rnorm(50, 1e-15, 1e-15)
t.test(x2, y2) #ok
In the first case, differences between numbers only occur after many significant figures, so the data are "nearly constant". In the second case, Although the size of the differences between numbers are the same, compared to the magnitude of the numbers themselves they are large.
As mentioned by e3bo, you can use multiple-precision floating point numbers using the Rmpfr package.
mpfr("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825")
These are slower and more memory intensive to use than regular (double precision) numeric vectors, but can be useful if you have a poorly conditioned problem or unstable algorithm.
If you are producing the entire output yourself, you can use sprintf(), e.g.
> sprintf("%.10f",0.25)
[1] "0.2500000000"
specifies that you want to format a floating point number with ten decimal points (in %.10f the f is for float and the .10 specifies ten decimal points).
I don't know of any way of forcing R's higher level functions to print an exact number of digits.
Displaying 100 digits does not make sense if you are printing R's usual numbers, since the best accuracy you can get using 64-bit doubles is around 16 decimal digits (look at .Machine$double.eps on your system). The remaining digits will just be junk.
One more solution able to control the how many decimal digits to print out based on needs (if you don't want to print redundant zero(s))
For example, if you have a vector as elements and would like to get sum of it
elements <- c(-1e-05, -2e-04, -3e-03, -4e-02, -5e-01, -6e+00, -7e+01, -8e+02)
sum(elements)
## -876.5432
Apparently, the last digital as 1 been truncated, the ideal result should be -876.54321, but if set as fixed printing decimal option, e.g sprintf("%.10f", sum(elements)), redundant zero(s) generate as -876.5432100000
Following the tutorial here: printing decimal numbers, if able to identify how many decimal digits in the certain numeric number, like here in -876.54321, there are 5 decimal digits need to print, then we can set up a parameter for format function as below:
decimal_length <- 5
formatC(sum(elements), format = "f", digits = decimal_length)
## -876.54321
We can change the decimal_length based on each time query, so it can satisfy different decimal printing requirement.
If you work primarily with tibbles, there is a function that enforces digits: num().
Here is an example:
library(tidyverse)
data <- tribble(
~ weight, ~ weight_selfreport,
81.5,81.66969147005445,
72.6,72.59528130671505,
92.9,93.01270417422867,
79.4,79.4010889292196,
94.6,96.64246823956442,
80.2,79.4010889292196,
116.2,113.43012704174228,
95.4,95.73502722323049,
99.5,99.8185117967332
)
data <-
data %>%
mutate(across(where(is.numeric), ~ num(., digits = 3)))
data
#> # A tibble: 9 × 2
#> weight weight_selfreport
#> <num:.3!> <num:.3!>
#> 1 81.500 81.670
#> 2 72.600 72.595
#> 3 92.900 93.013
#> 4 79.400 79.401
#> 5 94.600 96.642
#> 6 80.200 79.401
#> 7 116.200 113.430
#> 8 95.400 95.735
#> 9 99.500 99.819
Thus you can even decide to have different rounding options depending on what your needs are. I find it very helpful and a rather quick solution to printing dfs.

Wrong number of digits in format.pval()?

When specifying 3 digits in format.pval(), why does, say, 0.019950 outputs 4 digits:
format.pval(0.019950, eps=.001, digits=3, nsmall=3)
"0.0199"
But, say, 0.019951 outputs 3 digits:
format.pval(0.019951, eps=.001, digits=3, nsmall=3)
"0.020"
Edit (Solution):
The solution to having 3 digits while preserving the p-value formatting, based on dcarlson's answer, was simply to round the value to 3 digits before passing it to format.pval():
format.pval(round(0.019950, digits=3), eps=.001, digits=3, nsmall=3)
"0.020"
To address your first question "why does, say, 0.019950 outputs 4 digits": With the argument digits = 3 you specify that you'd like to show the first 3 significant digits after the decimal point (which are 199). From ?format.pval
digits: how many significant digits are to be used.
In response to your second question: 0.019951 with digits = 3 first gets rounded to "0.02" (you can confirm that by looking at the output of format.pval(0.019951, eps=.001, digits=3)). Then by setting nsmall = 3 you ask for 3 digits after the decimal point, which turns "0.02" into "0.020".
The digits= argument here and elsewhere in R is SIGNIFICANT digits, not decimal digits. Significant digits ignore leading 0's in a decimal so the first response is 3 significant digits since you do not count the 0 following the decimal point. In the second example the answer is rounded up to .02, but nsmall=3 forces the additional trailing 0.
In addition, specifying a digits= argument in R is usually treated as advisory so it may not be followed. You can always force R to print the number of decimals using round or the formatting function sprintf.
format.pval(round(0.019950, 3), digits=3, nsmall=3)
# [1] "0.020"
sprintf("%.3f", .019950)
# [1] "0.020"

how to get more decimal places in round function in R [duplicate]

There is an option in R to get control over digit display. For example:
options(digits=10)
is supposed to give the calculation results in 10 digits till the end of R session. In the help file of R, the definition for digits parameter is as follows:
digits: controls the number of digits
to print when printing numeric values.
It is a suggestion only. Valid values
are 1...22 with default 7
So, it says this is a suggestion only. What if I like to always display 10 digits, not more or less?
My second question is, what if I like to display more than 22 digits, i.e. for more precise calculations like 100 digits? Is it possible with base R, or do I need an additional package/function for that?
Edit: Thanks to jmoy's suggestion, I tried sprintf("%.100f",pi) and it gave
[1] "3.1415926535897931159979634685441851615905761718750000000000000000000000000000000000000000000000000000"
which has 48 decimals. Is this the maximum limit R can handle?
The reason it is only a suggestion is that you could quite easily write a print function that ignored the options value. The built-in printing and formatting functions do use the options value as a default.
As to the second question, since R uses finite precision arithmetic, your answers aren't accurate beyond 15 or 16 decimal places, so in general, more aren't required. The gmp and rcdd packages deal with multiple precision arithmetic (via an interace to the gmp library), but this is mostly related to big integers rather than more decimal places for your doubles.
Mathematica or Maple will allow you to give as many decimal places as your heart desires.
EDIT:
It might be useful to think about the difference between decimal places and significant figures. If you are doing statistical tests that rely on differences beyond the 15th significant figure, then your analysis is almost certainly junk.
On the other hand, if you are just dealing with very small numbers, that is less of a problem, since R can handle number as small as .Machine$double.xmin (usually 2e-308).
Compare these two analyses.
x1 <- rnorm(50, 1, 1e-15)
y1 <- rnorm(50, 1 + 1e-15, 1e-15)
t.test(x1, y1) #Should throw an error
x2 <- rnorm(50, 0, 1e-15)
y2 <- rnorm(50, 1e-15, 1e-15)
t.test(x2, y2) #ok
In the first case, differences between numbers only occur after many significant figures, so the data are "nearly constant". In the second case, Although the size of the differences between numbers are the same, compared to the magnitude of the numbers themselves they are large.
As mentioned by e3bo, you can use multiple-precision floating point numbers using the Rmpfr package.
mpfr("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825")
These are slower and more memory intensive to use than regular (double precision) numeric vectors, but can be useful if you have a poorly conditioned problem or unstable algorithm.
If you are producing the entire output yourself, you can use sprintf(), e.g.
> sprintf("%.10f",0.25)
[1] "0.2500000000"
specifies that you want to format a floating point number with ten decimal points (in %.10f the f is for float and the .10 specifies ten decimal points).
I don't know of any way of forcing R's higher level functions to print an exact number of digits.
Displaying 100 digits does not make sense if you are printing R's usual numbers, since the best accuracy you can get using 64-bit doubles is around 16 decimal digits (look at .Machine$double.eps on your system). The remaining digits will just be junk.
One more solution able to control the how many decimal digits to print out based on needs (if you don't want to print redundant zero(s))
For example, if you have a vector as elements and would like to get sum of it
elements <- c(-1e-05, -2e-04, -3e-03, -4e-02, -5e-01, -6e+00, -7e+01, -8e+02)
sum(elements)
## -876.5432
Apparently, the last digital as 1 been truncated, the ideal result should be -876.54321, but if set as fixed printing decimal option, e.g sprintf("%.10f", sum(elements)), redundant zero(s) generate as -876.5432100000
Following the tutorial here: printing decimal numbers, if able to identify how many decimal digits in the certain numeric number, like here in -876.54321, there are 5 decimal digits need to print, then we can set up a parameter for format function as below:
decimal_length <- 5
formatC(sum(elements), format = "f", digits = decimal_length)
## -876.54321
We can change the decimal_length based on each time query, so it can satisfy different decimal printing requirement.
If you work primarily with tibbles, there is a function that enforces digits: num().
Here is an example:
library(tidyverse)
data <- tribble(
~ weight, ~ weight_selfreport,
81.5,81.66969147005445,
72.6,72.59528130671505,
92.9,93.01270417422867,
79.4,79.4010889292196,
94.6,96.64246823956442,
80.2,79.4010889292196,
116.2,113.43012704174228,
95.4,95.73502722323049,
99.5,99.8185117967332
)
data <-
data %>%
mutate(across(where(is.numeric), ~ num(., digits = 3)))
data
#> # A tibble: 9 × 2
#> weight weight_selfreport
#> <num:.3!> <num:.3!>
#> 1 81.500 81.670
#> 2 72.600 72.595
#> 3 92.900 93.013
#> 4 79.400 79.401
#> 5 94.600 96.642
#> 6 80.200 79.401
#> 7 116.200 113.430
#> 8 95.400 95.735
#> 9 99.500 99.819
Thus you can even decide to have different rounding options depending on what your needs are. I find it very helpful and a rather quick solution to printing dfs.

r keeping only specific digits after the decimal point and printing the number

In R, How can I ensure that i only print 3 characters/numbers after the decimal point?
I thought that format command with nsmall parameter is sufficient but i am not getting required answer
> format(0.6791787, nsmall=3)
[1] "0.6791787"
I want 0.679
Using sprintf it would be
sprintf("%.3f", 0.6791787)
# [1] "0.679"
The number after the . and before the f is the number of digits to print after the decimal.

How to make "pretty rounding"?

I need to do a rounding like this and convert it as a character:
as.character(round(5.9999,2))
I expect it to become 6.00, but it just gives me 6
Is there anyway that I can make it show 6.00?
Try either one of these:
> sprintf("%3.2f", round(5.9999, digits=2))
[1] "6.00
> sprintf("%3.2f", 5.999) # no round needed either
[1] "6.00
There are also formatC() and prettyNum().
To help explain what's going on - the round(5.9999, 2) call is rounding your number to the nearest hundredths place, which gives you the number (not string) very close to (or exactly equal to, if you get lucky with floating-point representations) 6.00. Then as.character() looks at that number, takes up to 15 significant digits of it (see ?as.character) in order to represent it to sufficient accuracy, and determines that only 1 significant digit is necessary. So that's what you get.
As Dirk indicated, formatC() is another option.
formatC(x = 5.999, digits = 2, format = 'f')

Resources