但是有一篇帖子说它是 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 使用这种形式的双精度,因此很容易看出这一点:
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^53, 2^53 + 2, 2^53 + 4, ... 也就是说,此时它只能存储 2 的倍数。(然后之后,它只能按四[4的倍数]计数,然后只能按八[8的倍数]等)
为了完整性:格式可以(准确地)表示很多更大的整数,只是在那个量级上,它不能表示所有,因为格式使用基值(尾数)和指数,当达到 2^53 时,指数只能表示偶数(2 的倍数)。后来指数再次翻转,只能表示 4 的倍数,等等。
让我们想象一下。 IEEE-754 相当复杂,但我们举一个简化的例子(不是 IEEE-754)只是为了解释。假设我们有 4 位存储指数和 8 位存储尾数,假设我们只存储整数。这意味着当指数 = 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 在 double 中发生的情况。但是我们不能表示 257,因为在那个量级上,我们只能处理 2 的倍数。这就是 2^53 + 1 在双精度中发生的情况,我们无法表示它。我们可以表示 2^53 + 2。