我在多篇文章中看到,以 IEEE 双精度格式表示的最大安全整数是 253:
但是有一篇文章说它是 254:
https://stackoverflow.com/a/12445693
所有整数可以表示的范围(包括边界)
- 254 作为上限
- -254 作为下限
这个答案是错误的还是我遗漏了什么?
以上帖子现在似乎已更正。
但是有一篇文章说它是 2^54:https://stackoverflow.com/a/12445693
所有整数可以表示的范围(包括边界) 2^54 为上限 -2^54 为下限
这个答案是错误的还是我遗漏了什么?
你没有错过什么。 IEEE 754 双精度二进制浮点(“double”)无法表示的第一个整数是 2^53 + 1,这完全在声明的 -2^54..2^54 范围内。这可能是一个错字,因为可以表示 -2^53..2^53(含)范围内的所有整数。从 2^53 开始,只能表示 2 的倍数(因此 2^53 + 2 可以,但 2^53 + 1 不行)。由于 JavaScript 使用这种形式的 double,因此很容易看到它的实际效果:
const x = 2**53;
const y = x + 1;
console.log(x.toLocaleString()); // 9,007,199,254,740,992
console.log(y.toLocaleString()); // 9,007,199,254,740,992 -- the same
console.log(x === y); // true
const z = x + 2;
console.log(z.toLocaleString()); // 9,007,199,254,740,994
对于双精度数,2^53 - 1 是最后一个所谓的“安全”整数,其中“安全”被定义为“你可以向它加 1 并得到下一个整数”。 (事实上,JavaScript 甚至有一个值 2^53 - 1 的常量:
Number.MAX_SAFE_INTEGER
。)加 1 时得到的下一个整数(当然)是 2^53 - 第一个整数,格式为无法再处理每个不同的整数。从 2^53 开始,double 只能以 2 为单位进行计数:2^53, 2^53 + 2, 2^53 + 4, ... 也就是说,此时它只能存储 2 的倍数。(然后后来,它只能按四数[4的倍数],然后只能按八[8的倍数],等等)
为了完整性:该格式可以(准确地)表示很多更大的整数,只是在这个数量级上,它不能表示全部,因为该格式使用基值(尾数)和指数,并且当达到 2^53 时,指数只能表示偶数(2 的倍数)。之后指数再次翻转,只能表示 4 的倍数,等等
让我们想象一下这一点。 IEEE-754 相当复杂,但为了解释目的,我们举一个简化的例子(不是 IEEE-754)。假设我们有四位来存储指数,八位来存储尾数,并且假设我们只存储整数。这意味着指数 = 1 时,我们可以存储 0 到 255 之间的值:
概念性,*不是* IEEE-754! 指数(二进制) 尾数(二进制) 结果值(十进制) 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 1 0 2 ... 0 0 0 1 1 1 1 1 1 1 1 0 254 0 0 0 1 1 1 1 1 1 1 1 1 255
我们的尾数已达到极限,因此我们通过使用指数 = 2 并使尾数为 2 的倍数来牺牲范围的精度。现在我们只能以两位数来计数:
概念性,*不是* IEEE-754! 指数(二进制) 尾数(二进制) 结果值(十进制) 0 0 0 2 0 0 0 0 0 0 0 1 2 0 0 0 2 0 0 0 0 0 0 1 0 4 ... 0 0 0 2 0 1 1 1 1 1 1 1 254 0 0 0 2 1 0 0 0 0 0 0 0 256 0 0 0 2 1 0 0 0 0 0 0 1 258 ... 0 0 0 2 1 1 1 1 1 1 1 0 508 0 0 0 2 1 1 1 1 1 1 1 1 510
请注意,我们可以精确地表示值 256,即使它超出了尾数本身可以处理的范围 (0-255),因为使用指数,我们采用尾数值 (128) 并将其加倍得到 256。这正是双精度数中的 2^53 所发生的情况。但我们无法表示 257,因为在这个量级上我们只能处理 2 的倍数。这就是双精度数中的 2^53 + 1 所发生的情况,我们无法表示它。不过我们可以表示 2^53 + 2。
以 IEEE-754 双精度格式表示的最大安全整数为 2^53 - 1。如果您尝试存储大于此值,则不再安全。虽然可以存储更大的整数,但如果您想确保它保持安全,我建议不要这样做,因为它们在 2^53 - 1 以上会变得不精确。编辑:正如 Eric 的评论所解释的,这些值本身仍然是精确的,但是做算术时是四舍五入的时候。