「保姆级教程」JavaScript 大数相加终极指南:手写算法 + BigInt 实战

199 阅读4分钟

在日常开发中,尤其是处理金融数据、用户资产、区块链交易、科学计算等场景时,我们可能会碰到一个老大难问题——大整数精度丢失

如果你曾好奇:

  • 为什么 0.1 + 0.2 !== 0.3
  • JavaScript 明明是动态语言,为什么连个大数都算不准?
  • 如何在不借助外部库的前提下,准确计算超大整数的加法?
  • BigInt 到底怎么用,和 Number 有什么坑?

那这篇文章,就是为你准备的「保姆级」解决方案!

我们将带你从原理到实践,手把手实现一个支持任意长度整数加法的算法,并全面掌握 ES6 新增的 BigInt 类型,一站式吃透 JavaScript 中的大数处理。


一、JavaScript 的数字精度问题

JavaScript 只有一种数字类型:Number,它是基于 IEEE 754 的双精度浮点数,能精确表示的整数范围是:

console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991

超出这个范围,JS 就会“看不清楚”这个数字,甚至会把两个不同的数当成一样的。

console.log(9007199254740991 + 1); // ✅ 9007199254740992
console.log(9007199254740991 + 2); // ❌ 还是 9007199254740992

另外,浮点数误差问题也很有名:

console.log(0.1 + 0.2); // 0.30000000000000004

这是因为 0.1 和 0.2 在二进制中是无限循环小数,JS 存不精确,只能“尽量接近”。

所以 JS 在处理大数字或者浮点运算时,是不怎么靠谱的。那怎么办?


二、方案一:手写大整数加法(字符串模拟)

这种方法思路很简单,把两个超大整数当成字符串,一个个字符加过去,手动处理进位。

比如你要加:

123456789123456789
+
987654321987654321

用 JS 自带的 Number 肯定不行,只能模拟“人脑竖式加法”。

实现代码:

function addLargeNumbers(num1, num2) {
  let result = '';
  let carry = 0;
  let i = num1.length - 1;
  let j = num2.length - 1;

  while (i >= 0 || j >= 0 || carry > 0) {
    const digit1 = i >= 0 ? parseInt(num1[i]) : 0;
    const digit2 = j >= 0 ? parseInt(num2[j]) : 0;
    const sum = digit1 + digit2 + carry;

    result = (sum % 10) + result;
    carry = Math.floor(sum / 10);
    
    i--;
    j--;
  }

  return result;
}

测试一下:

console.log(addLargeNumbers("123456789123456789", "987654321987654321"));
// 输出:1111111111111111110

这个算法很朴素,但在不支持 BigInt 的环境里,它就是最稳的方式。


三、方案二:用 BigInt 正面对抗大数

从 ES2020 开始,JS 引入了一个新类型:BigInt,它可以表示任意长度的整数,完美解决精度丢失的问题。

创建 BigInt 的方式:

const a = 123456789012345678901234567890n; // 字面量加 n
const b = BigInt("123456789012345678901234567890"); // 使用构造函数

console.log(typeof a); // 'bigint'

注意两个坑:

  1. 不能和 Number 混着算
console.log(1n + 1); // ❌ 会报错
console.log(1n + BigInt(1)); // ✅
  1. 不能处理小数

BigInt 是整数类型,小数直接会被砍掉:

console.log(BigInt(3.14)); // 3n

所以如果你是要做“钱的计算”,比如精确到小数点后两位,BigInt 其实不合适,推荐用 decimal.jsbignumber.js 之类的库。


四、总结对比

特性手写算法(字符串)BigInt
精度✅ 任意长度✅ 任意长度
是否原生❌ 手动处理✅ 内置
是否支持小数
与 Number 兼容性✅ 自由转换❌ 需手动转换
浏览器兼容性✅ 兼容老浏览器❌ 仅现代浏览器

五、实际应用场景推荐

  • 面试算法题 / 练习基础:推荐手写字符串加法,能加深你对 JS 的基本功理解;
  • 业务代码开发:如果环境支持 ES2020,直接用 BigInt,代码更简洁,性能也好;
  • 金额、精确浮点计算:建议用第三方库,比如 decimal.js,别自己手写。

最后碎碎念

JavaScript 一直被称为“玩具语言”,但其实只要你愿意深入一点,就能写出很严谨的代码。大整数处理就是个典型例子:你可以用最基本的字符串操作解决问题,也可以靠新特性直接搞定。

希望这篇文章对你有帮助。如果你有更优雅的解法或者其他语言里的实现思路,也欢迎留言交流。