为什么Number.MAX_SAFE_INTEGER是9007199254740991而不是9007199254740992?

在 JavaScript 中,Number.MAX_SAFE_INTEGER 是一个常量,它代表了能够以精确方式表示的最大整数。然而,这个值为什么是 9,007,199,254,740,991 而不是 9,007,199,254,740,992 呢?本文将深入探讨这个问题,并提供一些学习和指导意义。

IEEE 754 标准

要理解 Number.MAX_SAFE_INTEGER 的值为什么是 9,007,199,254,740,991,首先需要了解 IEEE 754 标准。这是一种二进制浮点数算术标准,用于表示数字、特殊值(如 NaN 和 Infinity)以及执行基本算术运算。JavaScript 使用 IEEE 754 标准来表示数字,其中包括整数和浮点数。

IEEE 754 标准在存储数字时使用了固定的比特位数。对于 JavaScript,使用 64 位存储数字,其中 1 位表示符号,11 位表示指数,剩下的 52 位表示尾数。因此,JavaScript 可以表示的最大整数是:

---- - - - ---------------------

安全整数范围

由于使用了固定的比特位数,JavaScript 的整数有一个安全范围,即能够以精确方式表示的最小值和最大值。这个范围称为“安全整数范围”。

在 JavaScript 中,可以使用 Number.MIN_SAFE_INTEGER 和 Number.MAX_SAFE_INTEGER 来表示安全整数范围的下限和上限。它们的值分别为:

----------------------- - -----------------
----------------------- - ----------------

因此,如果要进行计算并确保得到准确的结果,则应始终在安全整数范围内操作整数。

解释为什么Number.MAX_SAFE_INTEGER是9007199254740991

现在我们知道了 IEEE 754 标准和安全整数范围,我们可以回答本文的主要问题:为什么 Number.MAX_SAFE_INTEGER 是 9,007,199,254,740,991 而不是 9,007,199,254,740,992?

简单来说,这是由于数字使用了 64 位存储,并且其中一位用于符号(正负),而另外 11 位用于指数。指数部分需要包含一个偏移量,因为它可以表示正、零和负数。这意味着如果将所有 11 位都设置为 1,则会获得最大的非特殊值,而不是最大的整数。

换句话说,如果将指数部分全部设置为 1,则会将尾数部分减半。这是因为指数的最后一位被用来表示是否存在一个隐含的 1,而如果指数部分全部为 1,则没有“空间”可以存储这个隐含的 1。

因此,实际上只有 52 位用于存储尾数,这意味着最大的整数是:

---- - - - ---------------------

任何比这个数字更大的整数都将无法以精确方式表示。

示例代码

以下是一个示例代码,演示了 Number.MAX_SAFE_INTEGER 和安全整数范围的使用:

----- ---------- - ------------------------
----- ---------- - ------------------------

---------------- ---- -------- ---------------- -- ------ ---- -------- ----------------
---------------- ---- -------

- ----------------------------------------------------------- --------
---------------------------------------------------------------------------------------