我们知道floating point is broken,因为十进制数字总是可以完美地用二进制表示。它们四舍五入为可以以二进制表示的数字;有时这个数字更高,有时它更低。在这种情况下,使用无处不在的IEEE 754 double format更高的0.1和0.4轮:
0.1 = 0.1000000000000000055511151231257827021181583404541015625
0.4 = 0.40000000000000002220446049250313080847263336181640625
由于这两个数字都很高,你也期望它们的总和也很高。完美的添加应该会给你0.5000000000000000277555756156289135105907917022705078125
,但你会得到一个很好的确切0.5
。为什么?
答案 0 :(得分:4)
此计算的行为方式是这样的,因为加法会将结果推送到另一个(二进制)数量级。这会在左侧(最重要的一侧)增加一个重要位,因此必须在右侧(最不重要的一侧)下降一点。
第一个数字0.1
以二进制形式存储为2^-4 == 1/16
和2^-3 == 1/8
之间的数字。第二个数字0.4
以二进制形式存储为2^-2 == 1/4
和2^-1 == 1/2
之间的数字。总和0.5
是2^-1 == 1/2
或更大的数字。这是幅度不匹配,可能导致数字丢失。
这是一个更容易理解的例子。假设我们正在使用十进制计算机,它可以在浮点数中存储四位十进制数字。我们还要说我们要添加数字10/3
和20/3
。这些可能最终存储为
3.334
和
6.667
两者都有点高。当我们得到这些数字时,我们预计总和也会有点高,即
10.001
但请注意,我们的结果已经进入了一个新的数量级。完整结果有五位十进制数字,不适合。因此,计算机将结果四舍五入为四位十进制数并得到总和
10.00
令人惊讶的是10/3 + 20/3
的正确答案。
我在美国高中化学和物理课上经常得到同样的东西。当计算移动到新的数量级时,奇怪的事情会发生精确和有效数字。
答案 1 :(得分:3)
虽然大多数十进制数需要舍入以适合二进制,但有些则不需要。 0.5
可以用二进制表示,因为它是2 -1 。
浮点不仅仅是二进制,它的精度也有限。以下是两侧的确切总和和两个最接近的IEEE 754双重可表示数字:
0.5000000000000000277555756156289135105907917022705078125
0.5000000000000000000000000000000000000000000000000000000
0.5000000000000001110223024625156540423631668090820312500
很明显,精确的0.5最接近真实总和。 IEEE 754有关于简单数学运算的规则,规定了如何进行结果舍入,并且通常可以依赖于最接近的结果。