Open Genzhen opened 3 years ago
每日一题会在下午四点在交流群集中讨论,五点小程序中更新答案 欢迎大家在下方发表自己的优质见解 二维码加载失败可点击 小程序二维码
每日一题会在下午四点在交流群集中讨论,五点小程序中更新答案 欢迎大家在下方发表自己的优质见解
因为 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进行运算
扫描下方二维码,收藏关注,及时获取答案以及详细解析,同时可解锁800+道前端面试题。
一、JavaScript Number 的精度丢失问题
因为 JavaScript 的 Number 类型是遵循 IEEE 754 规范表示的,这就意味着 JavaScript 能精确表示的数字是有限的,JavaScript 可以精确到个位的最大整数是 9007199254740992,也就是 2 的 53 次方,超过这个范围就会精度丢失,造成 JavaScript 无法判断大小,从而会出现下面的现象:
在淘宝早期的订单系统中把订单号当作数字处理,后来随着订单号暴增,已经超过了 9007199254740992,最终的解法是把订单号改成字符串处理。
二、解决方案
1)实现方式一
参考网上常用的一中方案是将 Number 转为 String,然后将 String 转为 Array,并且注意补齐较短的数组,将他们的长度标称一样再一一相加得到一个新数组,再讲和组成的新数组转为数字就可以了。
2)实现方式二
也可以引用第三方库 bignumber.js,原理也是把所有数字当作字符串,重新实现了计算逻辑,缺点是性能比原生的差很多。