Count the number of integer digits

前端 未结 2 1551
我在风中等你
我在风中等你 2021-01-04 06:01

I want to count the number of digits before the decimal point for a numeric vector x with numbers greater or equal to 1. For example, if the vector is

x &l         


        
相关标签:
2条回答
  • 2021-01-04 06:36

    Character Counting

    For small problems, I like the nchar() solution the best, with one modification for negative values:

    nDigits <- function(x) nchar( trunc( abs(x) ) )
    
    # Test
    nDigits(100)
    nDigits(-100)
    # both have 3 digits
    
    nDigits(3)
    nDigits(-3)
    nDigits(0.1)
    nDigits(-0.1)
    # all have 1 digit
    
    nDigits(1 / .Machine$double.eps)
    nDigits(-1 / .Machine$double.eps)
    # both have 16 digits
    

    Base 10 Logarithm

    If you want to make the logarithm solution work, then you need considerations for negative values and values between 0 and 1. To me, this solution is a tad more complicated:

    nDigits2 <- function(x){
    
      truncX <- floor(abs(x))
    
      if(truncX != 0){
        floor(log10(truncX)) + 1
      } else {
        1
      }
    
    }
    

    Speed Performance

    Here is the output from the microbenchmark comparison (100,000 reps). The code for the character-counting solution is simpler, but slower (by a factor of 3-4):

    For integers > 1 (Unit: nanoseconds):

              expr  min   lq      mean median   uq     max neval
      nDigits(100) 1711 2139 2569.2819   2566 2994 2234046 1e+05
     nDigits2(100)    0  428  861.5435    856  856 5670216 1e+05
    

    For really tiny decimals (Unit: nanoseconds):

                               expr  min   lq     mean median   uq     max neval
     nDigits(1/.Machine$double.eps) 2994 4277 5066.321   4705 4705 4477928 1e+05
    nDigits2(1/.Machine$double.eps)  428 1283 1588.382   1284 1711 2042458 1e+05
    
    0 讨论(0)
  • 2021-01-04 06:50

    This is probably the best way (for positive numbers):

    floor(log10(x)) + 1
    

    If you want an answer that works for negative numbers too, add in an abs():

    floor(log10(abs(x))) + 1
    

    The log10 method will not work if the input is exactly 0, so if you want a robust solution with that method, handle 0 as a special case:

    n_int_digits = function(x) {
      result = floor(log10(abs(x)))
      result[!is.finite(result)] = 0
      result
    }
    

    You can also use nchar(trunc(x)), but this seems to behave poorly for large numbers. It will also count leading 0s, whereas the log method will not.

    0 讨论(0)
提交回复
热议问题