【问题标题】:What is the difference between these two comparisons? [duplicate]这两个比较有什么区别? [复制]
【发布时间】:2011-01-14 17:24:11
【问题描述】:

可能重复:
Why are these numbers not equal?

0.9 == 1-0.1 >>> TRUE
0.9 == 1.1-0.2 >>> FALSE

【问题讨论】:

    标签: r floating-accuracy


    【解决方案1】:

    修复程序的答案:

    > all.equal(0.9,1.1-0.2)
    [1] TRUE
    > all.equal(0.9, 1.1-0.3)
    [1] "Mean relative difference: 0.1111111"
    > isTRUE(all.equal(0.9, 1.1-0.3)
    [1] FALSE
    

    如果在代码中使用:

    if(isTRUE(all.equal(0.9,1.1-0.2)) {
       ....
    }
    

    或在向量中:

    > vec1=0.9
    > vec2=c(1.1-0.2,1.3-0.4,1.0-0.2)
    > mapply(function(...)isTRUE(all.equal(...)),vec1, vec2)
    [1]  TRUE  TRUE FALSE
    

    聪明人的回答:

    我建议您阅读“what every computer scientist should know about floating point numbers”。 (or here)。

    Richie 还指出了 R faq mentions this 问题。您真的应该阅读整个 R 常见问题解答。

    受虐狂的回答:

    您遇到的问题是浮点数在大多数情况下不能准确表示小数,这意味着您会经常发现完全匹配失败。

    而当你说:

    > 1.1-0.2
    [1] 0.9
    > 0.9
    [1] 0.9
    

    你可以用十进制找出它真正的想法:

    > sprintf("%.54f",1.1-0.2)
    [1] "0.900000000000000133226762955018784850835800170898437500"
    > sprintf("%.54f",0.9)
    [1] "0.900000000000000022204460492503130808472633361816406250"
    

    您可以看到这些数字不同,但表示方式有点笨拙。如果我们以二进制(好吧,十六进制,这是等效的)查看它们,我们会得到更清晰的图像:

    > sprintf("%a",0.9)
    [1] "0x1.ccccccccccccdp-1"
    > sprintf("%a",1.1-0.2)
    [1] "0x1.ccccccccccccep-1"
    > sprintf("%a",1.1-0.2-0.9)
    [1] "0x1p-53"
    

    您可以看到它们相差2^-53,这很重要,因为这个数字是值接近 1 的两个数字之间可表示的最小差异,因为这是。

    我们可以通过查看 R 的机器域来找出任何给定计算机的最小可表示数字是什么:

     > ?.Machine
     ....
     double.eps  the smallest positive floating-point number x 
     such that 1 + x != 1. It equals base^ulp.digits if either 
     base is 2 or rounding is 0; otherwise, it is 
     (base^ulp.digits) / 2. Normally 2.220446e-16.
     ....
     > .Machine$double.eps
     [1] 2.220446e-16
     > sprintf("%a",.Machine$double.eps)
     [1] "0x1p-52"
    

    您可以使用这个事实来创建一个“几乎等于”函数,该函数检查差异是否接近浮点中可表示的最小数字。事实上,这已经存在(感谢评论者)。

    > ?all.equal
    ....
    all.equal(x,y) is a utility to compare R objects x and y testing ‘near equality’.
    ....
    all.equal(target, current,
          tolerance = .Machine$double.eps ^ 0.5,
          scale = NULL, check.attributes = TRUE, ...)
    ....
    
    > all.equal(0.9,1.1-0.2)
    [1] TRUE
    

    所以 all.equal 函数实际上是检查数字之间的差是两个尾数之间最小差的平方根。

    这个算法在被称为非正规数的极小数附近有点有趣,但你不必担心。

    【讨论】:

    • 在 R 中,它是 abs 而不是 fabs。或者可能是isTRUE(all.equal(a, b))
    • 谢谢,太好了。我将添加所有等于答案。
    • 您说“二进制分数也不能正确地用十进制表示”——这是什么意思?这些 sprintfed 值是这些二进制值的精确十进制等值。
    • 呵呵,你是对的,谢谢你指出这一点。我会删除有问题的评论。
    • @AlexBrown 您的第一个链接似乎已损坏。
    【解决方案2】:

    当你想测试两个计算是否被计算时,你需要小心编程 数相等。 R 会假设你的意思是“完全相等”,这意味着什么 取决于机器精度。大多数数字四舍五入到 53 位二进制精度。 因此,通常两个浮点数不会可靠地相等,除非它们是 由相同的算法计算,即使那样也不总是。你可以通过平方看到这个 2 的平方根:这些值肯定是相同的吗?

    x <- sqrt(2)
    x * x == 2
    [1] FALSE
    

    我们可以通过减法看出这两个值相差多少:

    1.1 - 0.2 - 0.9
    [1] 1.110223e-16
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-08
    • 2019-11-15
    • 2012-03-21
    • 2013-12-17
    • 2013-02-19
    • 2020-07-22
    相关资源
    最近更新 更多