问题在于浮点格式将分数表示为二进制。
第一个分数位是1/2,第二个是1/4,以此类推,表示为1/2的n次方。
而问题是,不是每个有理数(可以表示为两个整数之比的数字)在这种二进制格式中都有有限表示。
(这使得浮点格式在货币价值方面难以使用。虽然这些价值总是有理数(n/100),但只有.00、.25、.50和.75实际上在任意数量的二进制小数位中具有确切表示。)
无论如何,当你把它们加起来时,系统最终有机会将结果四舍五入为它可以准确表示的数字。
在某个时候,它发现自己将.666...数加到.333...数上,就像这样:
00111110 1 .o10101010 10101010 10101011
+ 00111111 0 .10101010 10101010 10101011o
00111111 1 (1).0000000 00000000 0000000x # the x isn't in the final result
左侧的位是符号位,接下来的八位是指数位,剩余的位是小数位。在指数位和小数位之间,有一个假定的"1"始终存在,因此没有被实际存储为规范化的最左侧小数位。我已经将实际不存在的零用单独的位
o
表示。
在这里发生了很多事情,在每个步骤中,FPU采取了相当英勇的措施对结果进行四舍五入。保留了两个额外的精度数字(超出结果能够容纳的),并且在许多情况下,FPU知道剩余最右侧的位是否为1或至少为1。如果是,则分数的该部分大于0.5(按比例缩放),因此向上舍入。中间舍入的值使FPU可以将最右侧的位一直带到整数部分,最终舍入到正确的答案。
这不是因为任何人添加了0.5而发生的;FPU只是尽力在格式的限制范围内做得最好。浮点数实际上并不是不准确的。它是完全准确的,但我们在基于10进制和有理数的世界观中期望看到的大多数数字都不能由格式的基于2进制的小数表示。实际上,可以表示的数字非常少。