问题描述
我在R中编写了此函数,并且该函数中的模运算符存在一些问题。此函数的目的是,如果数字在小数点后有任何数字,则将1返回n + 1个小数位;否则,对于任何整数,例如,返回1。返回0.1表示1,返回1表示50,依此类推。
代码是
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,因此看来小数位数似乎不会引起奇怪的警告消息和错误的结果。实际上,当我更改数字时,例如,小数点后三位都可以正常工作
> 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,"\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
在这种情况下,您很幸运,由于缺乏精度,初始浮点噪声(因为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