JavaScript Number 大数相加失真

文章讨论了在JavaScript中两个大整数相加时遇到的精度问题,由于Number类型对大整数处理的限制,直接相加可能导致错误结果。解决方案包括使用BigInt内置对象以及自定义字符串相加算法,确保能够正确处理大于Number.MAX_SAFE_INTEGER的整数。

一、业务场景

需要将两个 id 数值相加,得到联合主键,或者将两个正整数相加,求和。

二、遇到的问题

刚开始直接使用Number(id1) + Number(id2),得到的数据不正确。

function numberAdd(id1, id1) {
    return Number(id1) + Number(id2);
}
console.log(numberAdd('111111111111111111', '1'));
// 得到错误的结果:111111111111111100。无法正确求和得到111111111111111112。

三、原因

因为 Javascript 的数字存储使用了 IEEE 754 中规定的双精度浮点数数据类型,而这一数据类型能够安全存储 -(2^53 - 1) 到 2^53 - 1 之间的数值(包含边界值)。

Number.MAX_SAFE_INTEGER 常量表示在 JavaScript 中最大的安全整数,是一个值为 9007199254740991 的常量。

例如:

Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 // 会得到true

四、解决办法

1、使用 BigInt

BigInt 是一种内置对象,它提供了一种方法来表示大于 2^53 - 1 的整数。

可以用在一个整数字面量后面加 n 的方式定义一个 BigInt ,如:10n;或者调用函数 BigInt()并传递一个整数值或字符串值。

注意:不能和任何 Number 实例混合运算,两者必须转换成同一种类型。

警告:当使用 BigInt 时,带小数的运算会被取整。

const rounded = 5n / 2n; // 得到2n, 而不是2.5n

大数相加

function bigIntAdd(id1, id2) {
    return String(BigInt(id1) + BigInt(id2));
}
console.log(bigIntAdd('111111111111111111', '1')); // 得到正确结果:111111111111111112

2、字符串相加算法

BigInt是在ES2020中引入的新特性。还可以自己实现大数相加的算法。

function addStrings (str1, str2) {
    let maxLength = Math.max(str1.length, str2.length); // 获取两个数字的最大长度
    str1 = str1.padStart(maxLength, 0); // 用0补齐长度,让它们两个长度相同
    str2 = str2.padStart(maxLength, 0);

    let temp = 0; // 每个位置相加之和
    let flag = 0; // 进位:相加之和如果大于等于10,则需要进位
    let result = ""; // 最终结果返回值

    for(let i = maxLength-1; i >= 0; i--) {
      temp = parseInt(str1[i]) + parseInt(str2[i]) + flag; // 获取当前位置的相加之和:字符串1 + 字符串2 + 进位数字
      flag = Math.floor(temp/10); // 获取下一个进位
      result = temp % 10 + result; // 拼接结果字符串
    }
    if(flag === 1) { // 如果遍历完成后,flag还剩1,说明两数相加之后多了一位,类似于:95 + 10 = 105
      result = "1" + result;
    }
    return result;
};
console.log(addStrings('111111111111111111', '1')); // 得到正确结果:111111111111111112

### JavaScript大数相加的实现方法 在JavaScript中,由于`Number.MAX_SAFE_INTEGER`的限制(其值为2^53-1,即9007199254740991),超出该范围的数值计算可能会导致精度丢失。为了实现高精度的大数相加,可以采用字符串操作的方式进行手动计算[^2]。 以下是基于字符串处理的大数相加算法实现: #### 算法思路 1. 将输入的两个大数以字符串形式表示。 2. 确定两个字符串的长度,并对较短的字符串在其头部补零,使两者长度一致。 3. 从字符串的末尾开始逐位相加,同时考虑进位问题。 4. 如果最终仍有进位,则将其添加到结果的最高位。 5. 返回计算结果作为字符串。 #### 实现代码 以下是一个完整的JavaScript大数相加函数实现: ```javascript function bigSum(a, b) { let str = ""; // 存储结果 let length = Math.max(a.length, b.length); // 取较长字符串的长度 a = a.padStart(length, "0"); // 补零对齐 b = b.padStart(length, "0"); let carry = 0; // 进位标志 let result; for (let i = length - 1; i >= 0; i--) { let n = parseInt(a[i], 10) + parseInt(b[i], 10) + carry; // 当前位相加并加上进位 result = n % 10; // 当前位的结果 carry = Math.floor(n / 10); // 更新进位 str = result + str; // 构建结果字符串 } if (carry) { str = carry + str; // 如果最后还有进位,追加到结果前 } return str; } // 测试示例 console.log(bigSum("2342341234124123", "7856564389786944")); // 输出: "10198905623911067" ``` 上述代码通过字符串操作实现了大数相加的功能,能够正确处理超出`Number.MAX_SAFE_INTEGER`范围的数值[^3]。 #### 注意事项 - 在实际应用中,确保输入的数字是以字符串形式传递的,以避免因直接使用`Number`类型而导致的精度问题。 - 如果需要处理更复杂的大数运算(如乘法、除法等),可以参考类似的字符串操作逻辑或引入第三方库(如`BigInt`或`decimal.js`)[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值