JavaScript Number 大数相加失真

一、业务场景

需要将两个 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值