实现一个add方法完成两个大数相加

使用字符串模拟竖式加法,解决JavaScript中超出安全整数范围的大数相加问题

问题

在JavaScript中,当数字超过 Number.MAX_SAFE_INTEGER(2^53 - 1)时,会失去精度。例如:

console.log(9007199254740991 + 2); // 9007199254740992 (错误)

我们需要实现一个 add 方法,能够正确处理任意大的整数相加,返回准确的结果字符串。

解答

/**
 * 大数相加
 * @param {string} num1 - 第一个加数
 * @param {string} num2 - 第二个加数
 * @return {string} - 相加结果
 */
function add(num1, num2) {
  // 转换为字符串并去除空格
  num1 = String(num1).trim();
  num2 = String(num2).trim();
  
  // 获取两个数的长度
  let i = num1.length - 1;
  let j = num2.length - 1;
  
  // 进位标志
  let carry = 0;
  // 结果数组
  let result = [];
  
  // 从个位开始逐位相加
  while (i >= 0 || j >= 0 || carry > 0) {
    // 获取当前位的数字,如果已经遍历完则为0
    const digit1 = i >= 0 ? parseInt(num1[i]) : 0;
    const digit2 = j >= 0 ? parseInt(num2[j]) : 0;
    
    // 当前位相加(包括进位)
    const sum = digit1 + digit2 + carry;
    
    // 计算新的进位
    carry = Math.floor(sum / 10);
    
    // 当前位的结果
    result.unshift(sum % 10);
    
    // 移动指针
    i--;
    j--;
  }
  
  return result.join('');
}

使用示例

// 示例1:普通大数相加
console.log(add('123456789', '987654321')); 
// 输出: "1111111110"

// 示例2:超出安全整数范围
console.log(add('9007199254740991', '9007199254740991')); 
// 输出: "18014398509481982"

// 示例3:不同长度的数字
console.log(add('999', '1')); 
// 输出: "1000"

// 示例4:带有前导零的情况
console.log(add('00123', '00456')); 
// 输出: "579"

// 示例5:极大的数字
console.log(add(
  '123456789012345678901234567890',
  '987654321098765432109876543210'
)); 
// 输出: "1111111110111111111011111111100"

关键点

  • 字符串处理:将数字转换为字符串进行处理,避免精度丢失

  • 逆序遍历:从个位(字符串末尾)开始向高位遍历,模拟手工竖式加法

  • 进位处理:使用 carry 变量记录进位,每次相加后更新进位值

  • 补零对齐:当某个数字已遍历完时,用 0 补充,确保计算完整

  • 循环条件while (i >= 0 || j >= 0 || carry > 0) 确保处理完所有位和最后的进位

  • 结果构建:使用 unshift 将每位结果添加到数组开头,最后 join 成字符串

  • 时间复杂度:O(max(m, n)),其中 m 和 n 分别是两个数字的长度

  • 空间复杂度:O(max(m, n)),用于存储结果数组