Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Genzhen opened this issue Jun 17, 2021 · 1 comment
Open

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

Genzhen opened this issue Jun 17, 2021 · 1 comment
Labels
JavaScript teach_tag

Comments

@Genzhen
Copy link
Collaborator

Genzhen commented Jun 17, 2021

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

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

扫描下方二维码,收藏关注,及时获取答案以及详细解析,同时可解锁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,原理也是把所有数字当作字符串,重新实现了计算逻辑,缺点是性能比原生的差很多。

@Genzhen Genzhen added the JavaScript teach_tag label Jun 17, 2021
@836334258
Copy link

用BigInt进行运算

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
JavaScript teach_tag
Projects
None yet
Development

No branches or pull requests

2 participants