js Number类型采用的是64-bits的双精度标准。超过2^53就回精度缺失;
大数相加
就像做正常加法计算一样,个位与个位相加,超过十进一
最后一位相加,注意进位和位数补齐,还有循环或递归结束条件
add (num1, num2) {
let maxLen = Math.max(num1.length, num2.length); // 取最大长度 并在字符串头部补0
num1 = num1.padStart(maxLen, '0');
num2 = num2.padStart(maxLen, '0');
let carry = 0; // 进位
let sum = 0; // 临时的和
let res = ''; // 结果
for (let i = maxLen - 1; i >= 0; i--) { // 倒着循环
sum = parseInt(num1[i]) + parseInt(num2[i]) + carry; // 求当前位数的和 +进位
carry = Math.floor(sum / 10); // 进位
res = sum % 10 + res; // 求余拼接
}
if (carry === 1) { // 如果最后相加有进位
res = '1' + sum;
}
return res;
}
https://zhuanlan.zhihu.com/p/72179476
较为优雅的方法,使用while循环、使用pop弹出最后一位数,两个按位取反符~~处理位数不够时产生的undefined
add (num1, num2) {
let arr1 = num1.split('');
let arr2 = num2.split('');
let carry = 0; // 进位
let res = '';
while (arr1.length || arr2.length || carry) { // 循环直到两个数组都没值,且没有进位
carry += ~~arr1.pop() + ~~arr2.pop(); // ~按位取反 取负数并-1,可以解决undefined不被转化成0的问题
res = (carry % 10) + res; // 取余数进行字符串拼接
carry = carry > 9; // 是否有进位,避免最后相加为10 没进位少循环一次
}
return res;
}
另一个思路,js的精度是2的53次方,16位数,截取前16位按正常运算,超出部分计算后拼接
参考
https://blog.csdn.net/wutengteng0401/article/details/100170133
https://zhuanlan.zhihu.com/p/72179476
https://www.cnblogs.com/mengff/p/12859381.html
https://www.jianshu.com/p/c373943f0e9e
大数乘法
multiplication (num1, num2) {
if (Number.isNaN(num1) || Number.isNaN(num2)) { // 判断传入的是数字
return '';
}
let len1 = num1.length,
len2 = num2.length,
res = [];
for (let i = len1 - 1; i >= 0; i--) { // 倒着循环 秒啊,i代表被乘数角标
for (let j = len2 - 1; j >= 0; j--) {
let index1 = i + j, // 第一次循环时取十位数角标
index2 = i + j + 1; // 第一次循环时的个位数角标
// let mul = num1[i] * num2[j] + (res[index2] || 0); // 可以使用两个按位取反符处理undefined ~~
let mul = num1[i] * num2[j] + ~~res[index2]; // 求积,每次加上最后一位的值
res[index1] = Math.floor(mul / 10) + ~~res[index1]; // 例:就像十位取除以十之后的数并加上进位
res[index2] = mul % 10; // 最后一位取余数
}
}
return res.join('').replace(/^0+/, ''); // join转字符串后正则替换第一位的0
}
https://segmentfault.com/a/1190000015979292?utm_source=tag-newest