我正在阅读The R Inferno,并遇到了一些我不理解的事情。除了Inferno的第8.2.23节之外,还有一些关于比较浮点数的好问题:question1,question2。
但是,我仍然遇到使用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
无法区分2和1.981,容差为0.01?
修改
从文档中: scale = NULL(默认值)的数值比较是通过首先计算两个数值向量的平均绝对差值来完成的。如果这小于容差或不是有限的,则使用绝对差异,否则相对差异按平均绝对差异缩放。
这里我不明白这种行为。我可以看到diff(1.981,2)
不是有限的:
> sprintf("%.25f",diff(c(1.981,2)))
[1] "0.0189999999999999058530875"
但那么它的缩放是什么?当每个向量长度为1时,平均绝对差值应该等于两个数字的差值,除以平均绝对差值就会得到1.显然,我理解这里的逻辑是错误的。
答案 0 :(得分:6)
这与浮点精度有关。乍一看手册并不完全清楚,但在您的示例中,mean absolute difference
的{{1}}为2-1.981
0.019
>
,{{1} }}。 0.01
也是tolerance
。因此,所做的比较是通过平均绝对差异缩放的相对差异。嗯?
使用scale
意味着您关心所涉及数字的大小。 Relative difference不是说差异有多大(绝对值),而是对于被比较的数字相对有多大。鉴于链接中的示例,5和6之间的差异更多重要(我使用松散术语)而不是NULL
和tolerance
之间。
因此,如果两个数字之间的相对差异小于1,000,000,000
,则认为数字相等。对于两个单个数字(如本例所示),相对差异由下式给出:
1,000,000,001
哪个是
tolerance
您指定的容差为( current - target ) / current
因此,数字被视为相等,因为相对差异小于此值。这些数字之间的差异( 2 - 1.981 ) / 2 == 0.0095
相对差异也恰好是最小的可表示浮点数!
0.01
现在尝试:
±
答案 1 :(得分: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"