【问题标题】:Count the number of integer digits计算整数位数
【发布时间】:2017-11-08 22:20:24
【问题描述】:

我想计算数字大于或等于 1 的数字向量 x 的小数点前的位数。例如,如果向量是

x <- c(2.85, 356.01, 66.1, 210.0, 1445.11, 13.000)

我的代码应该返回一个包含整数 1、3、2、3、4、2 的向量

有人知道怎么做吗?

【问题讨论】:

标签: r


【解决方案1】:

这可能是最好的方法(对于正数):

floor(log10(x)) + 1

如果您想要一个也适用于负数的答案,请添加abs()

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

如果输入正好为 0,log10 方法将不起作用,因此如果您想要使用该方法的稳健解决方案,请将 0 作为特殊情况处理:

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

您也可以使用nchar(trunc(x)),但这对于大量数字似乎表现不佳。它还会计算前导 0,而 log 方法不会。

【讨论】:

  • OP 的问题专门针对大于 1 的数字。小于 1 的数字需要额外处理,例如 ifelse(x &lt; 1, 0, ::code from the answer::)... 取决于您希望如何处理负数。
  • nchar(trunc(x)) 对负数失败。我知道你在讨论对数解决方案,但我想我也会指出这一点。
  • nchar(trunc(x)) 因大量数字而失败。例如,n&lt;-1.23e+20nchar(trunc(n)) 视为 8!
【解决方案2】:

字符计数

对于小问题,我最喜欢nchar() 解决方案,对负值进行了一次修改:

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

以 10 为底的对数

如果您想让对数解决方案起作用,那么您需要考虑负值和 0 到 1 之间的值。对我来说,这个解决方案有点复杂:

nDigits2 <- function(x){

  truncX <- floor(abs(x))

  if(truncX != 0){
    floor(log10(truncX)) + 1
  } else {
    1
  }

}

速度表现

这是微基准比较的输出(100,000 次重复)。字符计数解决方案的代码更简单,但速度较慢(3-4 倍):

对于大于 1 的整数(单位:纳秒):

          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

对于非常小的小数(单位:纳秒):

                           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

【讨论】:

    猜你喜欢
    • 2021-11-10
    • 2016-03-11
    • 2013-01-28
    • 1970-01-01
    • 2018-09-02
    • 2014-12-11
    • 1970-01-01
    • 2012-07-07
    相关资源
    最近更新 更多