all.equal中的舍入问题

时间:2013-09-13 19:49:10

标签: r

我正在阅读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无法区分2和1.981,容差为0.01?

修改

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

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

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

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

2 个答案:

答案 0 :(得分:6)

这与浮点精度有关。乍一看手册并不完全清楚,但在您的示例中,mean absolute difference的{​​{1}}为2-1.981 0.019 >,{{1} }}。 0.01也是tolerance。因此,所做的比较是通过平均绝对差异缩放的相对差异。嗯?

使用scale意味着您关心所涉及数字的大小。 Relative difference不是说差异有多大(绝对值),而是对于被比较的数字相对有多大。鉴于链接中的示例,5和6之间的差异更多重要(我使用松散术语)而不是NULLtolerance之间。

因此,如果两个数字之间的相对差异小于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"