【问题标题】:Rounding issue in all.equalall.equal 中的舍入问题
【发布时间】:2013-09-18 14:27:46
【问题描述】:

我正在阅读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。显然,我理解这里的逻辑是错误的。

【问题讨论】:

  • 来自帮助文件:all.equal(x, y) 是一个用于比较 R 对象 x 和 y 测试“近似相等”的实用程序(注意:near )
  • is.finite 表示哪些元素是有限的(不是无限的且不会丢失)或无限的(如Inf-Inf,不重复小数!

标签: r


【解决方案1】:

这是因为在这种情况下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"

【讨论】:

  • 感谢您对规模的澄清。但是,我仍然对scale = NULL 的默认行为感到困惑。
  • "scale = NULL(默认值)的数值比较是通过首先计算两个数值向量的平均绝对差来完成的。如果这小于公差或不是有限的,则使用绝对差,否则相对差异按平均绝对差异衡量。” (文档)——好吧,其实我也不明白。
【解决方案2】:

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

使用tolerance 意味着您关心所涉及数字的大小。 Relative difference 说明的不是差异有多大(绝对术语),而是差异有多大,相对与被比较的数字有关。鉴于链接中的示例,5 和 6 之间的区别比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"

【讨论】:

    猜你喜欢
    • 2012-11-24
    • 1970-01-01
    • 2013-04-12
    • 2011-08-23
    • 2011-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多