Ale*_*own 34

解答修复你的程序:

> all.equal(0.9,1.1-0.2)
[1] TRUE
> all.equal(0.9, 1.1-0.3)
[1] "Mean relative difference: 0.1111111"
> isTRUE(all.equal(0.9, 1.1-0.3)
[1] FALSE
Run Code Online (Sandbox Code Playgroud)

如果在代码中使用:

if(isTRUE(all.equal(0.9,1.1-0.2)) {
   ....
}
Run Code Online (Sandbox Code Playgroud)

或在矢量中:

> vec1=0.9
> vec2=c(1.1-0.2,1.3-0.4,1.0-0.2)
> mapply(function(...)isTRUE(all.equal(...)),vec1, vec2)
[1]  TRUE  TRUE FALSE
Run Code Online (Sandbox Code Playgroud)

回答明智的人:

我建议你阅读" 每个计算机科学家应该知道的浮点数 ".(或这里).

此外,Richie指出R faq提到了这个问题.你应该真正阅读整个R FAQ.

答案为masochists:

您遇到的问题是浮点在大多数情况下不能完全表示小数分数,这意味着您经常会发现完全匹配失败.

当你说:当你说:

> 1.1-0.2
[1] 0.9
> 0.9
[1] 0.9
Run Code Online (Sandbox Code Playgroud)

您可以通过十进制找出它的真实想法:

> sprintf("%.54f",1.1-0.2)
[1] "0.900000000000000133226762955018784850835800170898437500"
> sprintf("%.54f",0.9)
[1] "0.900000000000000022204460492503130808472633361816406250"
Run Code Online (Sandbox Code Playgroud)

您可以看到这些数字不同,但表示有点笨拙.如果我们用二进制(嗯,十六进制,等价)来看它们,我们会得到更清晰的图像:

> sprintf("%a",0.9)
[1] "0x1.ccccccccccccdp-1"
> sprintf("%a",1.1-0.2)
[1] "0x1.ccccccccccccep-1"
> sprintf("%a",1.1-0.2-0.9)
[1] "0x1p-53"
Run Code Online (Sandbox Code Playgroud)

您可以看到它们的区别2^-53,这很重要,因为这个数字是两个数值之间的最小可表示差异,其值接近1,因为这是.

通过查看R的机器字段,我们可以找出任何给定的计算机这个最小的可表示数字是什么:

 > ?.Machine
 ....
 double.eps  the smallest positive floating-point number x 
 such that 1 + x != 1. It equals base^ulp.digits if either 
 base is 2 or rounding is 0; otherwise, it is 
 (base^ulp.digits) / 2. Normally 2.220446e-16.
 ....
 > .Machine$double.eps
 [1] 2.220446e-16
 > sprintf("%a",.Machine$double.eps)
 [1] "0x1p-52"
Run Code Online (Sandbox Code Playgroud)

您可以使用此事实创建一个"近似等于"函数,该函数检查差异是否接近浮点中的最小可表示数字.事实上,这已经存在(感谢评论者).

> ?all.equal
....
all.equal(x,y) is a utility to compare R objects x and y testing ‘near equality’.
....
all.equal(target, current,
      tolerance = .Machine$double.eps ^ 0.5,
      scale = NULL, check.attributes = TRUE, ...)
....

> all.equal(0.9,1.1-0.2)
[1] TRUE
Run Code Online (Sandbox Code Playgroud)

所以all.equal函数实际上是检查数字之间的差异是两个尾数之间最小差异的平方根.

这个算法在称为非正规数的极小数字附近有点滑稽,但你不必担心这一点.

  • 在R中,它是`abs`而不是'fabs`.或者可能是'isTRUE(all.equal(a,b))`. (2认同)
  • 你说"二进制分数也不能用十进制表示正确" - 这是什么意思?那些sprintfed值是这些二进制值的精确十进制等值. (2认同)

Geo*_*tas 5

当您想要测试两个计算的数字是否相等时,您需要小心编程.R将假设您的意思是"完全相等",这意味着什么取决于机器精度.大多数数字舍入到53位二进制数字精度.因此,通常情况下,两个浮点数不会可靠地相等,除非它们是由相同的算法计算的,并且并非总是如此.你可以通过平方2的平方根看到这个:当然这些值是一样的吗?

x <- sqrt(2)
x * x == 2
[1] FALSE
Run Code Online (Sandbox Code Playgroud)

我们可以通过减法看出这两个值有多大差异:

1.1 - 0.2 - 0.9
[1] 1.110223e-16
Run Code Online (Sandbox Code Playgroud)