实现大数计算(如BigInt)的核心在于模拟手工运算过程,通过字符串或数组逐位处理进位。以下是五种实现方式的详细解析及优化建议:
核心思路- 数据结构:将大数转为字符串或数组,避免直接数值计算。
- 逐位运算:从最低位(字符串末尾)开始相加,处理进位。
- 进位处理:每步计算当前位结果和进位值,最终处理最高位进位。
方式一:基础字符串补零法const add = (num1, num2) => { const len = Math.max(num1.length, num2.length); num1 = num1.padStart(len, '0'); // 补零对齐 num2 = num2.padStart(len, '0'); let flag = 0, result = '', temp; for (let i = len - 1; i >= 0; i--) { temp = flag + parseInt(num1[i]) + parseInt(num2[i]); result = (temp % 10) + result; // 当前位结果 flag = Math.floor(temp / 10); // 进位 } return flag ? '1' + result : result; // 处理最高位进位};特点:
- 简单直观,通过补零对齐长度。
- 缺点:频繁调用padStart可能影响性能。
方式二:原生BigInt(非手写)let n1 = BigInt('111111111111111111111111111111111111111');let n2 = 222222222222222222222222222222222222222n;console.log(n1 + n2); // 直接运算注意:
- 仅适用于现代JavaScript环境(ES2020+)。
- 非手写实现,但作为对比参考。
方式三:动态数组处理var addStrings = function(num1, num2) { const arr1 = num1.split(''); const arr2 = num2.split(''); let res = '', flag = 0; while (arr1.length || arr2.length || flag) { const a = arr1.length ? +arr1.pop() : 0; const b = arr2.length ? +arr2.pop() : 0; const s = a + b + flag; res = (s % 10) + res; flag = Math.floor(s / 10); } return res;};优化点:
- 使用数组的pop()动态缩短长度,减少索引操作。
- 适用场景:适合需要频繁修改输入数据的场景。
方式四:TypeScript实现(类型安全)function addStrings(num1: string, num2: string): string { let i = num1.length - 1, j = num2.length - 1, add = 0; const ans: number[] = []; while (i >= 0 || j >= 0 || add !== 0) { const x = i >= 0 ? parseInt(num1.charAt(i)) : 0; const y = j >= 0 ? parseInt(num2.charAt(j)) : 0; const r = x + y + add; ans.unshift(r % 10); // 直接插入头部,避免反转 add = Math.floor(r / 10); i--; j--; } return ans.join('');};特点:
- 使用unshift直接构建结果,避免最后反转数组。
- 缺点:unshift在大量数据时性能较差(需移动元素)。
方式五:高效进位处理var addStrings = function(num1, num2) { let aLen = num1.length - 1, bLen = num2.length - 1; let remainder = 0, result = []; while (aLen >= 0 || bLen >= 0 || remainder !== 0) { const a = aLen >= 0 ? num1.charCodeAt(aLen) - '0'.charCodeAt(0) : 0; const b = bLen >= 0 ? num2.charCodeAt(bLen) - '0'.charCodeAt(0) : 0; const temp = a + b + remainder; result.push(temp % 10); remainder = Math.floor(temp / 10); aLen--; bLen--; } return result.reverse().join('');};优化点:
- 使用charCodeAt替代parseInt,提升字符转换速度。
- 关键改进:通过remainder !== 0确保最后进位被处理。
性能对比与建议- 字符处理速度:charCodeAt > parseInt > split/pop。
- 内存效率:避免频繁操作数组头部(如unshift)。
- 推荐实现:方式五或方式三,平衡了可读性与性能。
扩展:减法/乘法实现思路- 减法:类似加法,但需处理借位(当前位不足时向高位借1)。
- 乘法:通过逐位相乘 + 错位相加(模拟竖式乘法)。
通过以上方法,可以高效实现大数运算,突破JavaScript原生数值类型的限制。实际应用中可根据场景选择字符串或数组操作,并注意字符转换的优化。