IEEE 双精度格式 2^53 或 2^54 中可表示的最大安全整数是多少?

Is the maximum safe integer representable in IEEE double format 2^53 or 2^54?

我在多个 post 中看到可以用 IEEE 双精度格式表示的最大安全整数是 2^53

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER

但是有一个 post 说它是 2^54

Range within which all integers can be represented (including boundaries) 2^54 as an upper bound -2^54 as a lower bound

这个答案是错误的还是我遗漏了什么?

编辑:

以上post现在似乎已更正。

But there is this one post which says it's 2^54:

Range within which all integers can be represented (including boundaries) 2^54 as an upper bound -2^54 as a lower bound

这个答案是错误的还是我遗漏了什么?

你没有遗漏什么。 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 的倍数] 等)

为了完整性:格式可以(准确地)表示 很多 更大的整数,只是在那个数量级,它不能表示 all,因为格式使用基值(尾数)和指数,当你达到 2^53 时,指数只能表示偶数(2 的倍数)。稍后指数再次翻转,只能表示 4 的倍数,等等

让我们想象一下。 IEEE-754 相当复杂,但让我们举一个简化的例子( 不是 IEEE-754)只是为了解释的目的。假设我们有四位存储指数和八位存储尾数,假设我们只存储整数。这意味着指数 = 1,我们可以存储 0 到 255 之间的值:

CONCEPTUAL, *NOT* IEEE-754!

Exponent (binary)    Mantissa (binary)   Result Value (decimal)
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 的倍数来牺牲范围的精度。现在我们只能按两位计数:

CONCEPTUAL, *NOT* IEEE-754!

Exponent (binary)    Mantissa (binary)   Result Value (decimal)
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 的评论所解释的那样,值本身仍然是精确的,但是做算术的时候就是四舍五入的时候。