当将某些数字与模数函数一起使用时,模数警告可能完全失去准确性和不正确的结果

Probable complete loss of accuracy in modulus warning and incorrect results when using certain numbers with the modulus function

我在 R 中编写了这个函数,但我在这个函数中的模数运算符上遇到了一些问题。这个函数的作用是return1到小数点后n+1位,如果小数点后有任何数字,否则return1为任何整数,例如return 1 为 0.1,return 50 为 1,等等

密码是

tolerance <- function(x){
  constant <- 1
  if (x < 0){
    constant <- -1
    x <- constant * x
  }
  exponent <- 0
  if (is.numeric(x) & !is.integer(x)) {
    while(x %% 10 > 0) {
      x <- 10 * x
      exponent <- exponent + 1
    }
    return(constant * 10 ^ (-exponent))
  }
}

这些是我得到的结果

> for (i in c(1,0.1,0.11,0.111, 0.1111)) {
+   print(tolerance(i))
+ }
[1] 0.1
[1] 0.01
[1] 0.001
[1] 1e-24
[1] 1e-05
Warning messages:
1: In tolerance(i) : probable complete loss of accuracy in modulus
2: In tolerance(i) : probable complete loss of accuracy in modulus
3: In tolerance(i) : probable complete loss of accuracy in modulus
4: In tolerance(i) : probable complete loss of accuracy in modulus

如您所见,异常行为发生在 0.111 而不是 0.1111,因此小数位数似乎不会导致奇怪的警告消息和不正确的结果。事实上,当我更改数字时,小数点后 3 位工作正常,例如

> tolerance(5.111)
[1] 1e-04

0.0001 是预期的正确结果,因此问题似乎只出现在某些数字上。我没有将非常大的数字传递给此函数,因为我知道 R 不能很好地处理具有大量数字的数字数据类型。我通常将小数点后最多 6 位数字传递给此函数。

问题是否与处理数字时将十进制数转换为二进制数有关?还是完全不同?

我认为是模数运算符的部分导致了问题,因为当我在不使用模数运算符而是使用字符串操作的情况下重写此函数时,代码似乎按预期工作。

有什么想法吗?

这基本上是 why are these numbers not equal?

主题的百万变体之一

这只是部分答案,但试试这个(调试语句,删除否定代码 x):

tolerance <- function(x){
  constant <- 1
  exponent <- 0
  if (is.numeric(x) & !is.integer(x)) {
    while(x %% 10 > 0) {          
      x <- 10 * x
      exponent <- exponent + 1
      cat("x ",format(x,digits=22), "\n")
      cat("x %% 10",format(x %% 10,digits=22), "\n")
    }
    return(constant * 10 ^ (-exponent))
  }
}

对于 x=0.11,

tolerance(0.11)
## x  1.100000000000000088818 
## x %% 10 1.100000000000000088818 
## x  11 
## x %% 10 1 
## x  110 
## x %% 10 0 

在这种情况下,您很幸运,初始的 floating-point 噪声(因为 0.11 不能用有限数量的二进制数字精确表示)由于缺乏精度而从末尾被丢弃。

对于 x=0.111,取消的模式不同(不幸的是)。

tolerance(0.111)
x  1.1100000000000000977 
x %% 10 1.1100000000000000977 
x  11.10000000000000142109 
x %% 10 1.100000000000001421085 
x  111.0000000000000142109 
x %% 10 1.000000000000014210855 
x  1110.000000000000227374 
x %% 10 2.273736754432320594788e-13 
x  11100.00000000000181899 
x %% 10 1.81898940354585647583e-12 
x  111000.0000000000145519 
x %% 10 1.455191522836685180664e-11 
x  1110000.000000000232831 
x %% 10 2.328306436538696289062e-10 
x  11100000.00000000186265 
x %% 10 1.86264514923095703125e-09 
x  111000000.0000000149012 
x %% 10 1.490116119384765625e-08 
x  1110000000.000000238419 
x %% 10 2.384185791015625e-07 
x  11100000000.00000190735 
x %% 10 1.9073486328125e-06 
x  111000000000.0000152588 
x %% 10 1.52587890625e-05 
x  1110000000000.000244141 
x %% 10 0.000244140625 
x  11100000000000.00195312 
x %% 10 0.001953125 
x  111000000000000.015625 
x %% 10 0.015625 
x  1110000000000000.125 
x %% 10 0.125 
x  11100000000000002 
x %% 10 2 
x  111000000000000016 
x %% 10 6 
x  1110000000000000128 
x %% 10 8 
x  11100000000000002048 
x %% 10 8 
x  111000000000000016384 
x %% 10 4 
x  1110000000000000131072 
x %% 10 2 
x  11100000000000001048576 
x %% 10 6 
x  111000000000000010485760 
x %% 10 0 
[1] 1e-24