JavaScript原生Number类型的安全整数范围是-(2^53-1)到2^53-1,超出这个范围的整数运算会出现精度丢失,比如直接执行9999999999999999 + 1可能得到不符合预期的结果。因此处理大数运算时,通常将数字转为字符串,模拟人工计算的过程逐位处理,避免精度问题。

大数运算的核心思路
大数运算的本质是模拟我们手动列竖式计算的过程,核心处理点包括:
- 将数字转为字符串,从最低位(字符串末尾)开始逐位处理
- 处理进位、借位逻辑,对应不同运算的规则
- 处理前导零,避免结果出现多余的零开头
- 处理正负号,分情况处理同号、异号的运算逻辑
大数加法实现
大数加法的逻辑和手动加法一致,从末位开始相加,满十进一,最后反转结果并去除前导零。
function bigNumberAdd(a, b) {
// 处理输入为数字的情况,转为字符串
a = String(a);
b = String(b);
let i = a.length - 1;
let j = b.length - 1;
let carry = 0; // 进位值
let result = [];
// 从最低位开始逐位相加
while (i >= 0 || j >= 0 || carry > 0) {
const numA = i >= 0 ? parseInt(a[i]) : 0;
const numB = j >= 0 ? parseInt(b[j]) : 0;
const sum = numA + numB + carry;
result.push(sum % 10);
carry = Math.floor(sum / 10);
i--;
j--;
}
// 反转结果并转为字符串,去除前导零
let res = result.reverse().join('');
res = res.replace(/^0+/, '') || '0';
return res;
}
// 测试示例
console.log(bigNumberAdd('9999999999999999', '1')); // 输出10000000000000000
console.log(bigNumberAdd('123456789', '987654321')); // 输出1111111110大数减法实现
大数减法需要先判断两个数的大小,用大的减小的,再根据原始符号调整结果的正负,处理借位逻辑。
function bigNumberSubtract(a, b) {
a = String(a);
b = String(b);
// 判断a是否大于等于b,用于确定结果正负
const isANotSmaller = (a, b) => {
if (a.length !== b.length) return a.length > b.length;
return a >= b;
};
let isNegative = false;
if (!isANotSmaller(a, b)) {
// 交换a和b,标记结果为负
[a, b] = [b, a];
isNegative = true;
}
let i = a.length - 1;
let j = b.length - 1;
let borrow = 0; // 借位值
let result = [];
while (i >= 0 || j >= 0) {
const numA = i >= 0 ? parseInt(a[i]) : 0;
const numB = j >= 0 ? parseInt(b[j]) : 0;
let diff = numA - borrow - numB;
if (diff < 0) {
diff += 10;
borrow = 1;
} else {
borrow = 0;
}
result.push(diff);
i--;
j--;
}
// 反转结果,去除前导零
let res = result.reverse().join('').replace(/^0+/, '') || '0';
return isNegative ? '-' + res : res;
}
// 测试示例
console.log(bigNumberSubtract('10000000000000000', '9999999999999999')); // 输出1
console.log(bigNumberSubtract('123456', '654321')); // 输出-530865大数乘法实现
大数乘法模拟竖式乘法,用一个数的每一位去乘另一个数的每一位,结果按位置累加,最后处理进位。
function bigNumberMultiply(a, b) {
a = String(a);
b = String(b);
const lenA = a.length;
const lenB = b.length;
// 结果最多有lenA + lenB位,初始化全0数组
const result = new Array(lenA + lenB).fill(0);
// 从最低位开始逐位相乘
for (let i = lenA - 1; i >= 0; i--) {
for (let j = lenB - 1; j >= 0; j--) {
const product = parseInt(a[i]) * parseInt(b[j]);
// 乘积放在对应位置,位置是i+j+1
const pos = i + j + 1;
const sum = product + result[pos];
result[pos] = sum % 10;
result[pos - 1] += Math.floor(sum / 10);
}
}
// 去除前导零,转为字符串
let res = result.join('').replace(/^0+/, '') || '0';
return res;
}
// 测试示例
console.log(bigNumberMultiply('123456', '654321')); // 输出80779853376
console.log(bigNumberMultiply('9999', '9999')); // 输出99980001大数除法实现
大数除法采用试商法,模拟手动除法的过程,逐位取被除数,计算当前位能商几,更新余数继续计算。
function bigNumberDivide(dividend, divisor) {
dividend = String(dividend);
divisor = String(divisor);
if (divisor === '0') throw new Error('除数不能为0');
if (dividend === '0') return '0';
let result = [];
let remainder = ''; // 当前余数
for (let i = 0; i < dividend.length; i++) {
// 拼接当前位的数字到余数
remainder += dividend[i];
remainder = remainder.replace(/^0+/, '') || '0';
// 试商,从9到0找最大的能乘的数不超过余数
let count = 0;
while (bigNumberSubtract(remainder, bigNumberMultiply(divisor, count)) >= 0) {
count++;
}
count--; // 上一个满足条件的数
result.push(count > 0 ? count : 0);
// 更新余数
remainder = bigNumberSubtract(remainder, bigNumberMultiply(divisor, count));
}
// 去除结果前导零
let res = result.join('').replace(/^0+/, '') || '0';
return res;
}
// 测试示例
console.log(bigNumberDivide('80779853376', '654321')); // 输出123456
console.log(bigNumberDivide('10000000000000000', '9999999999999999')); // 输出1实现注意事项
以上实现是基础的字符串大数运算逻辑,实际使用中还可以做更多优化:
- 可以支持正负号处理,在加减法里扩展符号逻辑
- 乘法可以优化为更高效的算法,比如Karatsuba算法提升大位数相乘的性能
- 除法可以优化试商逻辑,避免重复调用乘法和减法,提升计算效率
- 如果涉及小数运算,需要额外处理小数点的位置,统一转为整数计算后再调整小数点
如果需要生产环境使用,也可以直接使用成熟的大数库,比如BigInt(ES2020引入的原生大整数类型),或者第三方库如bignumber.js,这些库已经处理了各种边界情况,可靠性更高。
下面是使用BigInt实现大数运算的示例,原生BigInt可以直接处理大整数,不需要手动实现运算逻辑:
// BigInt类型的大数运算,需要在数字后加n标识 const a = 9999999999999999n; const b = 1n; console.log(a + b); // 输出10000000000000000n console.log(a * b); // 输出9999999999999999n // 注意BigInt和Number不能直接混合运算,需要统一类型
JavaScript大数运算字符串处理进制转换高精度计算修改时间:2026-05-29 22:42:07