【问题标题】:How javascript treat large integers (more than 52 bits)?javascript 如何处理大整数(超过 52 位)?
【发布时间】:2019-02-20 17:24:00
【问题描述】:

考虑这段代码(节点 v5.0.0)

const a = Math.pow(2, 53)
const b = Math.pow(2, 53) + 1
const c = Math.pow(2, 53) + 2

console.log(a === b) // true
console.log(a === c) // false

为什么a === b 是真的?

javascript 可以处理的最大整数值是多少?

我正在实现高达 2^64 的随机整数生成器。有什么我应该注意的陷阱吗?

【问题讨论】:

  • 抱歉,已经修复了。
  • a 和 b 是同一个数,同一个数是相同的,或者相等的。
  • 为什么需要这么大的整数?你能制作两个 32 字符的数字并将它们连接成一个字符串吗?
  • 我对以 10 为底的浮点数做了一个简单的模拟(注意:您的计算机使用以 2 为底的浮点数!):jsfiddle.net/unhLemoa 如您所见,如果您将尾数向上移动到尽可能高的位置,您可以获得像123456789100000000 这样的大数字,但您实际上不能将该数字加一;您可以创建的最接近的较高数字是123456789200000000

标签: javascript node.js integer


【解决方案1】:

回答你的第二个问题,这是 JavaScript 中的最大 安全整数

console.log( Number.MAX_SAFE_INTEGER );

其余的都写在MDN:

MAX_SAFE_INTEGER 常量的值为9007199254740991。这 这个数字背后的原因是 JavaScript 使用双精度 IEEE 754 中指定的浮点格式数字,并且只能 安全地表示 -(2 ** 53 - 1)2 ** 53 - 1 之间的数字。

在这种情况下,安全是指表示整数的能力 准确并正确地比较它们。例如, Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2会 计算为true,这在数学上是不正确的。看 Number.isSafeInteger() 了解更多信息。

【讨论】:

    【解决方案2】:

    .:: JavaScript 只支持 53 位整数 ::.

    JavaScript 中的所有数字都是浮点数,这意味着整数始终表示为

    sign × mantissa × 2exponent
    

    尾数有 53 位。您可以使用指数来获得更高的整数,但它们将不再是连续的。例如,您通常需要将尾数乘以 2(指数 1)才能到达第 54 位。

    但是,如果乘以 2,则只能表示每隔一个整数:

    Math.pow(2, 53)      // 54 bits 9007199254740992
    Math.pow(2, 53) + 1  // 9007199254740992
    Math.pow(2, 53) + 2  //9007199254740994
    Math.pow(2, 53) + 3  //9007199254740996
    Math.pow(2, 53) + 4  //9007199254740996
    

    加法过程中的舍入效应使奇数增量(+1 对 +3)的事情变得不可预测。实际的表示有点复杂,但这个解释应该可以帮助你理解基本问题。

    您可以安全地使用strint 库对字符串中的大整数进行编码并对它们执行算术运算。

    Here是全文。

    【讨论】:

      【解决方案3】:

      javascript 如何处理大整数?

      JS 没有整数。 JS 数字是 64 位浮点数。它们存储为尾数和指数。

      精度由尾数给出,大小由指数给出。

      如果您的数字需要比尾数中存储的精度更高的精度,则最低有效位将被截断。

      9007199254740992; // 9007199254740992
      (9007199254740992).toString(2);
      // "100000000000000000000000000000000000000000000000000000"
      //  \        \                    ...                   /\
      //   1        10                                      53  54
      // The 54-th is not stored, but is not a problem because it's 0
      
      9007199254740993; // 9007199254740992
      (9007199254740993).toString(2);
      // "100000000000000000000000000000000000000000000000000000"
      //  \        \                    ...                   /\
      //   1        10                                      53  54
      // The 54-th bit should be 1, but the mantissa only has 53 bits!
      
      9007199254740994; // 9007199254740994
      (9007199254740994).toString(2);
      // "100000000000000000000000000000000000000000000000000010"
      //  \        \                    ...                   /\
      //   1        10                                      53  54
      // The 54-th is not stored, but is not a problem because it's 0
      

      然后,您可以存储所有这些整数:

      -9007199254740992, -9007199254740991, ..., 9007199254740991, 9007199254740992
      

      第二个叫做minimum safe integer

      Number.MIN_SAFE_INTEGER的值是最小整数n这样 n 和 n - 1 都可以精确地表示为 Number 值。

      Number.MIN_SAFE_INTEGER 的值为 -9007199254740991 (−(253−1)).

      倒数第二个叫做maximum safe integer

      Number.MAX_SAFE_INTEGER的值是最大整数n这样 n 和 n + 1 都可以精确地表示为 Number 值。

      Number.MAX_SAFE_INTEGER 的值为 9007199254740991 (253-1).

      【讨论】:

        【解决方案4】:

        Number.MAX_VALUE 会告诉你 JS 实现中可表示的最大浮点值。答案可能是:1.7976931348623157e+308。但这并不意味着可以精确表示高达 10^308 的每个整数。正如您的示例代码所示,超过 2^53 只能表示偶数,并且随着您在数轴上走得更远,差距会变得更大。

        如果您需要大于 2^53 的精确整数,您可能需要使用 bignum 包,它允许任意大的整数(在可用内存范围内)。我碰巧知道的两个包是:

        BigInt by Leemon

        Crunch

        【讨论】:

          【解决方案5】:

          为了补充这里的其他答案,值得一提的是BigInt 存在。这允许 JavaScript 处理任意大的整数。

          在您的号码上使用n 后缀,并使用2n ** 53n + 2n 等常规运算符。重要的是要指出 BigInt 不是 Number,但您可以通过显式转换与 Number 进行范围有限的互操作。

          Node.js REPL 中的一些示例:

          > 999999999999999999999999999999n + 1n 10000000000000000000000000000000n > 2n ** 53n 9007199254740992n > 2n ** 53n + 1n 9007199254740993n > 2n ** 53n == 2n ** 53n + 1n 错误的 > 1n 类型 '大神' > 3 * 4n TypeError:不能混合 BigInt 和其他类型,使用显式转换 > BigInt(3) * 4n 12n > 3 * 数量(4n) 12 > 数字(2n ** 53n)== 数字(2n ** 53n + 1n) 真的

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-03-31
            • 2022-08-17
            • 2017-10-02
            • 2012-05-27
            相关资源
            最近更新 更多