以下表达式返回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?
我知道它与尾数有关,但我没有 完全明白。
答案 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}}
确实:最后三位是不同的。