FE-Interview
FE-Interview copied to clipboard
Day323:大数计算如何实现
每日一题会在下午四点在交流群集中讨论,五点小程序中更新答案 欢迎大家在下方发表自己的优质见解
二维码加载失败可点击 小程序二维码
扫描下方二维码,收藏关注,及时获取答案以及详细解析,同时可解锁800+道前端面试题。
一、JavaScript Number 的精度丢失问题
因为 JavaScript 的 Number 类型是遵循 IEEE 754 规范表示的,这就意味着 JavaScript 能精确表示的数字是有限的,JavaScript 可以精确到个位的最大整数是 9007199254740992,也就是 2 的 53 次方,超过这个范围就会精度丢失,造成 JavaScript 无法判断大小,从而会出现下面的现象:
Math.pow(2, 53); // 9007199254740992
Math.pow(2, 53) === Math.pow(2, 53) + 1; // true
9007199254740992 === 9007199254740992 + 1; // true

在淘宝早期的订单系统中把订单号当作数字处理,后来随着订单号暴增,已经超过了 9007199254740992,最终的解法是把订单号改成字符串处理。
二、解决方案
1)实现方式一
参考网上常用的一中方案是将 Number 转为 String,然后将 String 转为 Array,并且注意补齐较短的数组,将他们的长度标称一样再一一相加得到一个新数组,再讲和组成的新数组转为数字就可以了。
function sumString(a, b) {
a = "0" + a;
b = "0" + b; //加'0'首先是为了转为字符串,而且两个数相加后可能需要进位,这样保证了和的长度就是a、b中长的那个字符的长度
var arrA = a.split(""), //将字符串转为数组
arrB = b.split(""),
res = [], //相加结果组成的数组
temp = "", //相同位数相加的值
carry = 0, //同位数相加结果大于等于10时为1,否则为0
distance = a.length - b.length, //计算两个数字字符串的长度差
len = distance > 0 ? a.length : b.length; //和的长度
// 在长度小的那个值前加distance个0,保证两个数相加之前长度是想等的
if (distance > 0) {
for (let i = 0; i < distance; i++) {
arrB.unShift("0");
}
} else {
for (let i = 0; i < distance; i++) {
arrA.unShift("0");
}
}
// 现在得到了两个长度一致的数组,需要做的就是把他们想通位数的值相加,大于等于10的要进一
// 最终得到一个和组成的数组,将数组转为字符串,去掉前面多余的0就得到了最终的和
for (let i = len - 1; i >= 0; i--) {
temp = Number(arrA[i]) + Number(arrB[i]) + carry;
if (temp >= 10) {
carry = 1;
res.unshift((temp + "")[1]);
} else {
carry = 0;
res.unshift(temp);
}
}
res = res.join("").replace(/^0/, "");
console.log(res);
}
2)实现方式二
也可以引用第三方库 bignumber.js,原理也是把所有数字当作字符串,重新实现了计算逻辑,缺点是性能比原生的差很多。
用BigInt进行运算