JavaScript 中的数字是 IEEE-754 双精度二进制浮点数,这是一种相当紧凑的格式(64 位),可提供快速计算和广泛的范围。它通过将数字存储为符号位、11 位指数和 52 位有效数来实现这一点(尽管通过聪明它实际上获得了 53 位精度)。它是二进制(以 2 为底)浮点数:有效数(加上一些巧妙之处)为我们提供了值,而指数为我们提供了数字的大小。
当然,只有这么多有效位,并不是每个数字都可以存储。这是数字 1,格式可以存储的下一个最大数字,1 + 2-52 ≈ 1.00000000000000022,然后是 1 + 2 × 2-52 ≈ 1.00000000000000044:
+-------------------------------------------------- -------------- 符号位
/ +-------+---------------------------------------- -------------- 指数
// | +-------------------------------------------------- +- 有效数字
// | / |
0 01111111111 000000000000000000000000000000000000000000000000000000
= 1
0 01111111111 00000000000000000000000000000000000000000000000000001
≈ 1.00000000000000022
0 01111111111 0000000000000000000000000000000000000000000000000010
≈ 1.00000000000000044
注意从 1.00000000000000022 到 1.00000000000000044 的跳跃;没有办法存储 1.0000000000000003。整数也可能发生这种情况:Number.MAX_SAFE_INTEGER (9,007,199,254,740,991) 是格式可以容纳的最大正整数值,其中i 和i + 1 都可以精确表示(spec)。 9,007,199,254,740,991 和 9,007,199,254,740,992 都可以表示,但是 next 整数 9,007,199,254,740,993 不能;我们可以在 9,007,199,254,740,992 之后表示的下一个整数是 9,007,199,254,740,994。以下是位模式,注意最右边(最低有效)位:
+-------------------------------------------------- -------------- 符号位
/ +-------+---------------------------------------- -------------- 指数
// | +-------------------------------------------------- +- 有效数字
// | / |
0 10000110011 111111111111111111111111111111111111111111111111111
= 9007199254740991 (Number.MAX_SAFE_INTEGER)
0 10000110100 00000000000000000000000000000000000000000000000000000
= 9007199254740992 (Number.MAX_SAFE_INTEGER + 1)
x xxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
9007199254740993 (Number.MAX_SAFE_INTEGER + 2) 无法存储
0 10000110100 00000000000000000000000000000000000000000000000000001
= 9007199254740994 (Number.MAX_SAFE_INTEGER + 3)
请记住,格式以 2 为底,使用该指数,最低有效位不再是小数;它的值为 2。它可以关闭 (9,007,199,254,740,992) 或开启 (9,007,199,254,740,994);所以在这一点上,即使在整数(整数)尺度上,我们也开始失去精度。这对我们的循环有影响!
在完成i = 9,007,199,254,740,992循环后,i++再次给我们...i = 9,007,199,254,740,992; i 没有变化,因为无法存储下一个整数并且计算最终会向下舍入。如果我们做i += 2,i 会改变,但i++ 不能改变它。所以我们达到了稳定状态:i 永远不会改变,循环永远不会终止。