在javascript中减去长数字

时间:2010-01-12 15:37:30

标签: javascript long-integer subtraction

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

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

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

6 个答案:

答案 0 :(得分:20)

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

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

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

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

答案 1 :(得分:3)

杰森已经发布了原因。对于解决方案,您可以在http://www-cs-students.stanford.edu/~tjw/jsbn/

获取Javascript BigInt库

答案 2 :(得分:2)

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+/, ''))


最好使用big-integer库来处理所有不同的测试用例。

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

答案 3 :(得分:0)

JavaScript documentation

中对此进行了解释
  

根据ECMAScript标准,只有一种数字类型:the double-precision 64-bit binary format IEEE 754 value[^M]\n -(2 53和{{1之间的数字}} -1) 2)。 整数没有特定的类型。

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

  

53 -1 252 = 4,503,599,627,370,496 2之间可表示的数字正是整数。对于下一个范围,从53 = 9,007,199,254,740,992 2 53 ,所有内容都会乘以{{1}因此,可表示的数字是偶数,等等。

(完全表示小于2 54 的所有整数。)

22大于52 1234567890123456789 1234567890123456799。在这种程度上,只有大约1%的整数使用双精度浮点格式精确存储。

这两个无法准确存储。它们都四舍五入到2

JavaScript documentation还解释了如何确定是否存储了整数:

  

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

答案 4 :(得分:0)

从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)

通过将n附加到整数常量10n的末尾或调用函数BigInt()来创建BigInt。它也与Number不同,因此1 + 1n将会失败。

您可以从MDN pages

了解更多信息

答案 5 :(得分:0)

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;
}