Search code examples
rsignificant-digits

Floor and ceiling with 2 or more significant digits


It is possible to round results into two significant digits using signif:

> signif(12500,2)
[1] 12000
> signif(12501,2)
[1] 13000

But are there an equally handy functions, like the fictitious functions below signif.floor and signif.ceiling, so that I could get two or more significant digits with flooring or ceiling?

> signif.ceiling(12500,2)
[1] 13000
> signif.floor(12501,2)
[1] 12000

EDIT:

The existing signif function works with negative numbers and decimal numbers.

Therefore, the possible solution would preferably work also with negative numbers:

> signif(-125,2)
[1] -120
> signif.floor(-125,2)
[1] -130

and decimal numbers:

> signif(1.23,2)
[1] 1.2
> signif.ceiling(1.23,2)
[1] 1.3

As a special case, also 0 should return 0:

> signif.floor(0,2)
[1] 0

Solution

  • I think this approach is proper for all types of numbers (i.e. integers, negative, decimal).

    The floor function

    signif.floor <- function(x, n){
      pow <- floor( log10( abs(x) ) ) + 1 - n
      y <- floor(x / 10 ^ pow) * 10^pow
      # handle the x = 0 case
      y[x==0] <- 0
      y
    }
    

    The ceiling function

    signif.ceiling <- function(x, n){
      pow <- floor( log10( abs(x) ) ) + 1 - n
      y <- ceiling(x / 10 ^ pow) * 10^pow
      # handle the x = 0 case
      y[x==0] <- 0
      y
    }
    

    They both do the same thing. First count the number of digits, next use the standard floor/ceiling function. Check if it works for you.

    Edit 1 Added the handler for the case of x = 0 as suggested in the comments by Heikki.

    Edit 2 Again following Heikki I add some examples:

    Testing different values of x

    # for negative values
    > values <- -0.12151 * 10^(0:4); values
    # [1]    -0.12151    -1.21510   -12.15100  -121.51000 -1215.10000
    > sapply(values, function(x) signif.floor(x, 2))
    # [1]    -0.13    -1.30   -13.00  -130.00 -1300.00
    > sapply(values, function(x) signif.ceiling(x, 2))
    # [1]    -0.12    -1.20   -12.00  -120.00 -1200.00
    
    # for positive values
    > sapply(-values, function(x) signif.floor(x, 2))
    # [1]    0.12    1.20   12.00  120.00 1200.00
    > sapply(-values, function(x) signif.ceiling(x, 2))
    # [1]    0.13    1.30   13.00  130.00 1300.00
    

    Testing different values of n

    > sapply(1:5, function(n) signif.floor(-121.51,n))
    # [1] -200.00 -130.00 -122.00 -121.60 -121.51
    > sapply(1:5, function(n) signif.ceiling(-121.51,n))
    # [1] -100.00 -120.00 -121.00 -121.50 -121.51