Andrew
Andrew

Reputation: 38639

Round to significant digits *only* with decimal portion of number in R

The signif() function rounds values based on the specificed number of significant digits in a given value. The function applies to all the digits in the number, though, so numbers of different orders of magnitude are rounded and truncated differently. For instance, with this vector x

x <- c(100.1303421, 10.03421, 1.3421, 0.0003421)
lapply(x, signif, 2)
#> [[1]]
#> [1] 100
#> 
#> [[2]]
#> [1] 10
#> 
#> [[3]]
#> [1] 1.3
#> 
#> [[4]]
#> [1] 0.00034

… the first and second values are truncated to 100 and 10 and the decimal values disappear, while the third and fourth values maintain decimals (though different numbers). This is the expected output from signif()—it rightfully takes into account all the digits when determining significant.

Is it possible to ignore the integer part of each number and only format the decimal part with a set number of significant digits? I'd like to be able to return these values: c(100.13, 10.034, 1.34, 0.00034); that is, the complete integer preceding the ., followed by the significant digits of the decimal portion of the number.

For now, I've created a function that separates values into integer and fraction components and runs signif() only on the fraction component, but this seems exceptionally hacky.

signif_ignore_integer <- function(x, digits = 2) {
  as.integer(x) + signif(x - as.integer(x), digits)
}

lapply(x, signif_ignore_integer, 2)
#> [[1]]
#> [1] 100.13
#> 
#> [[2]]
#> [1] 10.034
#> 
#> [[3]]
#> [1] 1.34
#> 
#> [[4]]
#> [1] 0.00034

Is there a better, more recommended way (possibly with some fancy sprintf() format) to round values to a given number of significant digits while ignoring their integer components?

Upvotes: 4

Views: 3709

Answers (1)

eipi10
eipi10

Reputation: 93811

There may be a better way, but your general approach doesn't seem unreasonable. However, you can streamline it by using floor, taking advantage of vectorization to avoid lapply, and using the mod operator to return the fractional part of each number:

my_signif = function(x, digits) floor(x) + signif(x %% 1, digits)

my_signif(x, 2)
[1] 100.13000  10.03400   1.34000   0.00034

Upvotes: 1

Related Questions