lgwebdream / FE-Interview

🔥🔥🔥 前端面试,独有前端面试题详解,前端面试刷题必备,1000+前端面试真题,Html、Css、JavaScript、Vue、React、Node、TypeScript、Webpack、算法、网络与安全、浏览器
https://lgwebdream.github.io/FE-Interview/
Other
6.76k stars 897 forks source link

Day323:大数计算如何实现 #1149

Open Genzhen opened 3 years ago

Genzhen commented 3 years ago

每日一题会在下午四点在交流群集中讨论,五点小程序中更新答案 欢迎大家在下方发表自己的优质见解

二维码加载失败可点击 小程序二维码

扫描下方二维码,收藏关注,及时获取答案以及详细解析,同时可解锁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

numbermax

在淘宝早期的订单系统中把订单号当作数字处理,后来随着订单号暴增,已经超过了 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,原理也是把所有数字当作字符串,重新实现了计算逻辑,缺点是性能比原生的差很多。

836334258 commented 1 year ago

用BigInt进行运算