为啥 Number.MAX_SAFE_INTEGER 是 9,007,199,254,740,991 而不是 9,007,199,254,740,992?

Posted

技术标签:

【中文标题】为啥 Number.MAX_SAFE_INTEGER 是 9,007,199,254,740,991 而不是 9,007,199,254,740,992?【英文标题】:Why is Number.MAX_SAFE_INTEGER 9,007,199,254,740,991 and not 9,007,199,254,740,992?为什么 Number.MAX_SAFE_INTEGER 是 9,007,199,254,740,991 而不是 9,007,199,254,740,992? 【发布时间】:2014-12-10 09:37:44 【问题描述】:

ECMAScript 6 的 Number.MAX_SAFE_INTEGER 应该代表 javascript 在浮点精度问题出现之前可以存储的最大数值。但是,要求添加到此值的数字 1 也必须可以表示为 Number

Number.MAX_SAFE_INTEGER

注意Number.MAX_SAFE_INTEGER 的值是n 的最大整数,因此nn + 1 都可以精确地表示为Number 值。

Number.MAX_SAFE_INTEGER 的值为9007199254740991 (2^53−1)

——ECMAScript Language Specification

Chrome、Firefox、Opera 和 IE11 的 JavaScript 控制台都可以安全地执行数字 9,007,199,254,740,992 的计算。一些测试:

// Valid
Math.pow(2, 53)                         // 9007199254740992
9007199254740991 + 1                    // 9007199254740992
9007199254740992 - 1                    // 9007199254740991
9007199254740992 / 2                    // 4503599627370496
4503599627370496 * 2                    // 9007199254740992
parseInt('20000000000000', 16)          // 9007199254740992
parseInt('80000000000', 32)             // 9007199254740992
9007199254740992 - 9007199254740992     // 0
9007199254740992 == 9007199254740991    // false
9007199254740992 == 9007199254740992    // true

// Erroneous
9007199254740992 + 1                    // 9007199254740992
9007199254740993 + ""                   // "9007199254740992"
9007199254740992 == 9007199254740993    // true

为什么要求n + 1 也必须可以表示为Number?为什么失败会使值不安全

【问题讨论】:

可能是因为2^53 - 1 是最后一个可以准确表示的值 - 2^53 将给出与2^53 + 1 相同的值(“被盗”来自leanpub.com/understandinges6/read#leanpub-auto-numbers) 数字从0开始..也许是这个原因。 【参考方案1】:

我之所以这么说是因为Math.pow(2, 53) 是最大的可直接表示的整数,但它的 不安全 因为它也是第一个表示的值也是另一个值的近似值:

900719925474099<b><em>2</em></b> == 900719925474099<b><em>3</em></b> // true

对比Math.pow(2, 53) - 1

900719925474099<b><em>1</em></b> == 900719925474099<b><em>3</em></b> // false

【讨论】:

我猜99007199254740992 通过代理是不安全的,当您知道这绝对是您想要使用的值时,不一定是不安全的数字。【参考方案2】:

唯一靠近另一个数字的数字 当与它的下一个数字相比时显示为真

9007199254740992 == 9007199254740993
true
9007199254740993 == 9007199254740994
false
9007199254740991 == 9007199254740992
false
9007199254740997 == 9007199254740998
false

【讨论】:

您的“假”结果都跨越了 2 的倍数边界,奇数是较低的。如果你比较一个偶数和下一个更大的数,比如2^53 + 42^53 + 5,你会发现它们在 IEEE754 双精度中是相等的。【参考方案3】:

我对这个问题也有同样的担忧。 说安全范围是-2^53~2^53(包括边界值),而 说安全范围是-2^53+1~2^53-1

终于在https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger找到了正确的解释

它说,“安全”的意思是:

    可以精确地表示为 IEEE-754 双精度数,并且 其 IEEE-754 表示不能是对任何其他整数进行四舍五入以适应 IEEE-754 表示的结果。

所以2^53 不是安全整数,因为: 它可以在 IEEE-754 中精确表示,但整数 2^53 + 1 不能在 IEEE-754 中直接表示,而是在四舍五入和四舍五入下舍入到 2^53

【讨论】:

以上是关于为啥 Number.MAX_SAFE_INTEGER 是 9,007,199,254,740,991 而不是 9,007,199,254,740,992?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?

为啥 CAP 定理中的 RDBMS 分区不能容忍,为啥它可用?