让我们解码一些浮点数,看看实际发生了什么!我将使用 Common Lisp,它有一个方便的函数来获取浮点数的有效位(又名尾数)和指数,而无需旋转任何位。使用的所有浮点数都是 IEEE 双精度浮点数。
> (integer-decode-float 1.0d0)
4503599627370496
-52
1
也就是说,如果我们将存储在有效数字中的值视为整数,则它是可用的 2 的最大幂 (4503599627370496 = 2^52),按比例缩小 (2^-52)。(它不存储为指数为 0 的 1,因为有效数字的左侧永远不会有零更简单,这允许我们跳过表示最左边的 1 位并具有更高的精度。不是这种形式的数字被称为不正常的。)
让我们看看1e16。
> (integer-decode-float 1d16)
5000000000000000
1
1
这里我们有表示 (5000000000000000) * 2^1。请注意,尽管有效数字是一个很好的四舍五入数,但它不是 2 的幂;这是因为 1e16 不是 2 的幂。每次乘以 10,就是乘以 2 和 5;乘以 2 只是增加指数,但乘以 5 是“实际”乘法,这里我们乘以 5 16 次。
5000000000000000 = 10001110000110111100100110111111000001000000000000000 (base 2)
请注意,这是一个 53 位二进制数,因为双浮点数具有 53 位有效数。
但是理解这种情况的关键是指数是 1。(指数很小表明我们正在接近精度的极限。)这意味着浮点值是 2^1 = 2 倍这个有效数。
现在,当我们试图表示这个数字加 1 时会发生什么?好吧,我们需要以相同的比例表示 1。但是我们可以对这个数字做出的最小改变恰好是 2,因为有效数字的最低有效位的值为 2!
也就是说,如果我们增加有效位,使最小的变化,我们得到
5000000000000001 = 10001110000110111100100110111111000001000000000000001 (base 2)
当我们应用指数时,我们得到 2 * 5000000000000001 = 10000000000000002,这正是您观察到的值。您只能拥有 10000000000000000 或 10000000000000002,而 10000000000000001.1 更接近于后者。
(请注意,这里的问题甚至不是十进制数在二进制中不精确!这里没有二进制“重复小数”,有效数字的右端有很多 0 位 - 只是你的输入整齐地下降刚好超过最低位。)