在日常开发中,尤其是处理金融数据、用户资产、区块链交易、科学计算等场景时,我们可能会碰到一个老大难问题——大整数精度丢失。
如果你曾好奇:
- 为什么
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'
注意两个坑:
- 不能和 Number 混着算
console.log(1n + 1); // ❌ 会报错
console.log(1n + BigInt(1)); // ✅
- 不能处理小数
BigInt 是整数类型,小数直接会被砍掉:
console.log(BigInt(3.14)); // 3n
所以如果你是要做“钱的计算”,比如精确到小数点后两位,BigInt 其实不合适,推荐用 decimal.js 或 bignumber.js 之类的库。
四、总结对比
| 特性 | 手写算法(字符串) | BigInt |
|---|---|---|
| 精度 | ✅ 任意长度 | ✅ 任意长度 |
| 是否原生 | ❌ 手动处理 | ✅ 内置 |
| 是否支持小数 | ❌ | ❌ |
| 与 Number 兼容性 | ✅ 自由转换 | ❌ 需手动转换 |
| 浏览器兼容性 | ✅ 兼容老浏览器 | ❌ 仅现代浏览器 |
五、实际应用场景推荐
- 面试算法题 / 练习基础:推荐手写字符串加法,能加深你对 JS 的基本功理解;
- 业务代码开发:如果环境支持 ES2020,直接用
BigInt,代码更简洁,性能也好; - 金额、精确浮点计算:建议用第三方库,比如
decimal.js,别自己手写。
最后碎碎念
JavaScript 一直被称为“玩具语言”,但其实只要你愿意深入一点,就能写出很严谨的代码。大整数处理就是个典型例子:你可以用最基本的字符串操作解决问题,也可以靠新特性直接搞定。
希望这篇文章对你有帮助。如果你有更优雅的解法或者其他语言里的实现思路,也欢迎留言交流。