all.equal中的舍入问题

day*_*yne 9 r

我正在阅读The R Inferno,并遇到了一些我不理解的事情.除了Inferno的第8.2.23节之外,还有一些关于比较浮点数的好问题:问题1,问题2.

但是,我仍在使用中遇到问题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
Run Code Online (Sandbox Code Playgroud)

我不确定为什么在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
Run Code Online (Sandbox Code Playgroud)

此外,

> all.equal(2,1.980000000001,tolerance=0.01)
[1] TRUE 
Run Code Online (Sandbox Code Playgroud)

但是如果我们计算:

> diff(c(1.981,2))
[1] 0.019
Run Code Online (Sandbox Code Playgroud)

显然,

> diff(c(1.981,2)) >= 0.01
[1] TRUE
Run Code Online (Sandbox Code Playgroud)

那么,为什么all.equal无法区分2和1.981,容差为0.01?

编辑

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

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

> sprintf("%.25f",diff(c(1.981,2)))
[1] "0.0189999999999999058530875"
Run Code Online (Sandbox Code Playgroud)

但那么它的缩放是什么?当每个向量的长度为1时,平均绝对差值应该等于两个数字的差值,除以平均绝对差值就会得到1.显然,我理解这里的逻辑是错误的.

Sim*_*lon 6

这与浮点精度有关.该手册是不是第一眼完全清楚,但在你的例子中mean absolute difference2-1.9810.019这是> 0.01,该tolerance.scale也是NULL.因此,所做的比较是通过平均绝对差异缩放的相对差异.嗯?

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

因此,如果两个数字之间的相对差异小于tolerance数字被认为是相等的.对于两个单个数字(如本例所示),相对差异由下式给出:

( current - target ) / current
Run Code Online (Sandbox Code Playgroud)

这是

( 2 - 1.981 ) / 2 == 0.0095
Run Code Online (Sandbox Code Playgroud)

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

identical( abs( ( 2 - 0.0095 ) - ( 1.981 + 0.0095 ) ) , .Machine$double.eps )
[1] TRUE
Run Code Online (Sandbox Code Playgroud)

现在尝试:

all.equal( 2 , 1.981 , 0.00949999999999 )
[1] "Mean relative difference: 0.0095"
Run Code Online (Sandbox Code Playgroud)


ROL*_*OLO 5

这是因为在这种情况下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"
Run Code Online (Sandbox Code Playgroud)