【问题标题】:Subtracting long numbers in javascript在javascript中减去长数字
【发布时间】:2011-01-04 05:46:14
【问题描述】:

为什么 q == 0 在以下脚本中?

<script>
  var start = 1234567890123456789;
  var end =   1234567890123456799;
  var q = end - start;
  alert(q);
</script>

我认为结果应该是 10。这两个数字相减的正确方法是什么?

【问题讨论】:

    标签: javascript long-integer subtraction


    【解决方案1】:

    因为 JavaScript 中的数字是浮点数。它们的精度有限。

    当 JavaScript 看到一个很长的数字时,它会将它四舍五入到它可以表示为 64 位浮点数的最接近的数字。在您的脚本中,startend 被四舍五入为相同的值。

    alert(1234567890123456789);   // says: 1234567890123456800
    alert(1234567890123456799);   // says: 1234567890123456800
    

    没有内置方法可以对大整数进行精确算术,但您可以使用 this one 等 BigInteger 库。

    【讨论】:

      【解决方案2】:

      Jason 已经发布了原因。如需解决方案,您可以在 http://www-cs-students.stanford.edu/~tjw/jsbn/ 获取 Javascript BigInt 库

      【讨论】:

      • @MicahelBray 您应该将以上内容作为对 Jasons 回答的评论发布。
      【解决方案3】:

      JavaScript documentation中有解释:

      根据 ECMAScript 标准,只有一种数字类型:the double-precision 64-bit binary format IEEE 754 value-(253-1)253 之间的数字支持>-1)。 整数没有特定的类型。

      关于double precision floating point format 的维基百科页面解释:

      252= 4,503,599,627,370,496253= 9,007,199,254,740,992 之间的可表示数字正是整数。对于下一个范围,从253254,一切都乘以 2,所以可表示的数字是偶数等。

      (所有小于252 的整数都被精确表示。)

      12345678901234567891234567890123456799 大于 260= 1152921504606846976。在这个数量级上,只有大约 1% 的整数使用双精度浮点格式精确存储。

      这两个不能准确存储。它们都四舍五入为1234567890123456800


      JavaScript documentation 还解释了如何判断一个整数是否准确存储:

      [...] 从 ECMAScript 6 开始,您还可以使用 Number.isSafeInteger() 以及 Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER 检查数字是否在双精度浮点数范围内。超出此范围,JavaScript 中的整数不再安全,将是该值的双精度浮点近似值。

      【讨论】:

        【解决方案4】:

        const subtract = (a, b) => [a, b].map(n => [...n].reverse()).reduce((a, b) => a.reduce((r, d, i) => {
            let s = d - (b[i] || 0)
            if (s < 0) {
                s += 10
                a[i + 1]--
            }
            return '' + s + r
        }, '').replace(/^0+/, ''))


        最好对这些事情使用大整数库,以便处理所有不同的测试用例。

        这只是您可以使用的一般情况....

        【讨论】:

          【解决方案5】:

          自 2020 年 1 月起,BigInt 数据类型将添加到 Javascript。该提案目前位于Stage 4可以精确计算大于 2^53-1 (Number.MAX_SAFE_INTEGER) 的数字。

          BigInt 已在 Chrome、Node、Firefox 中发布,并且正在 Safari 中进行。 Read more here

          var start = BigInt('1234567890123456789');
          var end = BigInt('1234567890123456799');
          var q = end - start;
          alert(q)

          BigInt 是通过将 n 附加到整数文字的末尾 — 10n — 或调用函数 BigInt() 来创建的。它也与 Number 不同,所以 1 + 1n 会失败。

          您可以从MDN pages 阅读更多相关信息

          【讨论】:

            【解决方案6】:
            function add(x, y) {
                //*********************************************************************//
                // This function adds or subtracts two extremely large decimal numbers //
                // Inputs x and y should be numbers, i.e. commas are removed already   //
                // Use this function to remove commas and convert to number:           //
                // x = parseFloat(strNumber.replaceAll(",","").trim());                //
                // Inputs x and y can be both positive, or both negative,              //
                // or a combination (i.e. one positive and one negative in any         //
                // position whether as x or as y) which means subtraction              //
                //*********************************************************************//
            
                var temp, borrow=false, bothNeg=false, oneNeg=false, neg=false;
                if (x < 0 && y < 0) { bothNeg = true; x = -x; y = -y; } 
                else if (x < 0 || y < 0) {
                    oneNeg = true;
                    if (Math.abs(x) == Math.abs(y)) { x = 0; y = 0; }
                    else if (x < 0 && Math.abs(x) > Math.abs(y)) { neg = true; x = -x; y = -y; }
                    else if (x < 0 && Math.abs(x) < Math.abs(y)) { temp = y; y = x; x = temp; }
                    else if (y < 0 && Math.abs(x) < Math.abs(y)) { neg = true; temp = y; y = -x; x = -temp; }
                }
                x = parseInt(x*1000000000/10).toString();
                y = parseInt(y*1000000000/10).toString();
                var lenx=x.length, leny=y.length, len=(lenx>leny)?lenx:leny, sum="", div=0, x1, y1, rem;
                for (var i = 0; i < len; i++) {
                    x1 = (i >= lenx) ? 0 : parseInt(x[lenx-i-1]);
                    y1 = (i >= leny) ? 0 : parseInt(y[leny-i-1]);
                    y1 = (isNaN(y1)) ? 0 : y1;
                    if (oneNeg) y1 = -y1;
                    if (borrow) x1 = x1 - 1;
                    if (y < 0 && x1 > 0 && Math.abs(x1) >= Math.abs(y1)) { borrow=false; div=0; }
                    if (y < 0 && y1 <= 0 && (x1 < 0 || Math.abs(x1) < Math.abs(y1))) { borrow=true; rem=(x1+y1+div+10)%10; div=10; }
                    else { rem=(x1+y1+div)%10; div=Math.floor((x1+y1+div)/10); }
                    sum = Math.abs(rem).toString() + sum;
                }
                if (div > 0) sum = div.toString() + sum;
                sum = parseFloat(sum*10/1000000000);
                if (bothNeg || neg) sum = -sum;
                return sum;
            }
            

            【讨论】:

              猜你喜欢
              • 2014-08-17
              • 1970-01-01
              • 1970-01-01
              • 2018-10-24
              • 2014-10-01
              • 1970-01-01
              • 1970-01-01
              • 2013-07-08
              • 1970-01-01
              相关资源
              最近更新 更多