双精度理论

时间:2014-12-29 10:46:58

标签: java c# double

以下表达式返回false(例如,在Java和C#中)

0.1 + 0.1 + 0.1 == 0.3

所以我们了解到我们总是像这样比较双打和浮动

Math.abs(double1 - double2) < epsilon

但为什么

0.1 + 0.1 == 0.2 returns true and 
0.1 + 0.1 + 0.1 == 0.3 returns false?

我知道它与尾数有关,但我没有 完全明白。

2 个答案:

答案 0 :(得分:7)

Float / double存储为二进制分数,而不是小数分数。

有些数字无法用十进制表示法完全表示。例如,十进制表示法中的1/3是0.3333333 ...除了不能精确表示的数字不同之外,二进制表示法中也会发生同样的事情。其中数字是1/10。二进制表示法为0.000110011001100 ...

由于二进制表示法无法精确存储,因此它以四舍五入的方式存储。因此你的问题。

你不应该以你喜欢的方式比较双打:0.1 + 0.1 + 0.1 == 0.3,因为你永远不知道它们是如何存储在内存中的,你永远不会知道这种比较的结果是什么。

答案 1 :(得分:4)

@msporek 他的解释是正确的。这里详细说明了为什么在两种情况下都会出现错误或真实的原因。

首先,让我们0.1 + 0.1手动 Dec IEEE 754 52-bit mantisse ---------------------------------------------------- 0.1 = 1.1001100110011001100110011001100110011001100110011010 * 2^-4 0.1 = 1.1001100110011001100110011001100110011001100110011010 * 2^-4 + ------------------------------------------------------------------- 0.2 = 11.0011001100110011001100110011001100110011001100110100 * 2^-4 = 1.1001100110011001100110011001100110011001100110011010 * 2^-3

    Dec    IEEE 754            52-bit mantisse
             ----------------------------------------------------
    0.2 =  1.1001100110011001100110011001100110011001100110011010 * 2^-3
    0.1 =  1.1001100110011001100110011001100110011001100110011010 * 2^-4
 +  -------------------------------------------------------------------
    0.2 =  1.1001100110011001100110011001100110011001100110011010 * 2^-3
    0.1 =  0.1100110011001100110011001100110011001100110011001101 * 2^-3
 +  -------------------------------------------------------------------
    0.3 = 10.0110011001100110011001100110011001100110011001100111  * 2^-3
        =  1.00110011001100110011001100110011001100110011001100111 * 2^-2
        =  1.0011001100110011001100110011001100110011001100110100  * 2^-2
                                                              ^^^
                                                          These bits

这是一个完美的匹配,这意味着将0.2转换为IEEE 754并且IEEE 754中的0.1和0.1的总和逐位相等。现在让我们来看看:0.2 + 0.1

        Dec    IEEE 754            52-bit mantisse
                 ----------------------------------------------------
        0.3 =  1.0011001100110011001100110011001100110011001100110011 * 2^-2
  0.2 + 0.1 =  1.0011001100110011001100110011001100110011001100110100 * 2^-2

现在,看一下加法结果的最后几位:它是100.而0.3应该有一个011作为最后一位。 (我们将通过下面的测试程序验证这一点。)

你可能认为现在CPU有80位mantisse的FPU,这是正确的,我认为行为非常依赖于硬件和硬件。有可能它被舍入到52位精度。

额外检查使用测试程序在内存中生成IEEE 754表示:
现在用计算机做这个就得到了这个结果,这与我手工完成的结果完全一致:

{{1}}

确实:最后三位是不同的。