10

我正在阅读The R Inferno,并且遇到了一些我不明白的事情。除了 Inferno 中的第 8.2.23 节之外,还有一些关于比较浮点数的好问题:question1question2

但是,我在使用all.equal. 使用默认值all.equal,我得到了我期望的结果(大部分)。

> all.equal(2,1.99999997)
[1] "Mean relative difference: 1.5e-08"
> all.equal(2,1.99999998) #I expected FALSE here
[1] TRUE
> all.equal(2,1.99999999)
[1] TRUE

我不确定为什么在 1.99999998 函数返回TRUE,但这并不像我指定容差级别的以下行为那样令人担忧:

> all.equal(2,1.98,tolerance=0.01) #Behaves as expected
[1] "Mean relative difference: 0.01"
> all.equal(2,1.981,tolerance=0.01) #Does not behave as expected
[1] TRUE

此外,

> all.equal(2,1.980000000001,tolerance=0.01)
[1] TRUE 

但是如果我们计算:

> diff(c(1.981,2))
[1] 0.019

很明显,

> diff(c(1.981,2)) >= 0.01
[1] TRUE

那么,为什么all.equal不能以 0.01 的容差区分 2 和 1.981?

编辑

来自文档:scale = NULL (默认值)的数值比较是通过首先计算两个数值向量的平均绝对差来完成的。如果这小于公差或不是有限的,则使用绝对差,否则使用平均绝对差缩放相对差。

在这里我不明白这种行为。我可以看到这diff(1.981,2)不是有限的:

> sprintf("%.25f",diff(c(1.981,2)))
[1] "0.0189999999999999058530875"

但是,它是通过什么来衡量的呢?当每个向量的长度为 1 时,平均绝对差应该等于两个数字的差,除以平均绝对差会得到 1。显然,我理解这里的逻辑是错误的。

4

2 回答 2

7

这与浮点精度有关。乍一看,该手册并不完全清楚,但在您的示例中,mean absolute differenceof2-1.9810.019which > 0.01tolerance. scale也是NULL。因此,所进行的比较是由平均绝对差缩放的相对差。诶?!

使用tolerance意味着您关心所涉及数字的大小。相对差异不是说明差异有多大(绝对术语),而是说明对于被比较的数字有多大。鉴于链接中的示例, 5 和 6 之间的差异比 between and更显(我松散地使用该术语)。1,000,000,0001,000,000,001

因此,如果两个数字之间的相对差异小于tolerance这些数字,则认为它们相等。对于两个单个数字(如本例中),相对差异由下式给出:

( current - target ) / current

哪个是

( 2 - 1.981 ) / 2 == 0.0095

因此,您指定的公差是0.01数字被认为是相等的,因为相对差异小于这个。这些数字之间的差异±,相对差异也恰好是最小的可表示浮点数!

identical( abs( ( 2 - 0.0095 ) - ( 1.981 + 0.0095 ) ) , .Machine$double.eps )
[1] TRUE

现在尝试:

all.equal( 2 , 1.981 , 0.00949999999999 )
[1] "Mean relative difference: 0.0095"
于 2013-09-13T21:36:26.597 回答
6

发生这种情况是因为在这种情况下all.equal检查相对差异。如果您设置scale=1,即没有缩放,将进行绝对比较并all.equal按照您的预期进行。

有关详细信息,请参阅有关scale参数的文档。

> all.equal(2,1.980000000001,tolerance=0.01)
[1] TRUE
> all.equal(2,1.980000000001,tolerance=0.01,scale=1)
[1] "Mean scaled difference: 0.02"
于 2013-09-13T20:01:47.090 回答