JavaScript 中精度问题以及解决方案
JavaScript 中的精度问题源于其遵循 IEEE 754 双精度浮点数标准,导致某些小数无法精确表示(如 0.1 + 0.2 !== 0.3)。以下是问题分析及解决方案:
问题原因
-
二进制浮点数的固有缺陷
十进制小数(如0.1)在二进制中是无限循环的,存储时会被截断,引发精度丢失。 -
安全整数范围限制
JavaScript 的Number类型仅在[-2^53 +1, 2^53 -1]范围内能精确表示整数。
解决方案
1. 整数运算(避免浮点数)
将小数转换为整数(如“分”代替“元”),计算后再转回小数。注意数值范围,超出安全整数时使用 BigInt。
// 示例:金额转为分计算
function toCents(value) {
return Math.round(value * 100);
}
const total = (toCents(0.1) + toCents(0.2)) / 100; // 0.3
// 大整数使用 BigInt
const a = BigInt(Math.round(0.1 * 100)); // 10n
const b = BigInt(Math.round(0.2 * 100)); // 20n
const sum = Number(a + b) / 100; // 0.3
2. 使用高精度计算库
- decimal.js:精确十进制浮点运算。
- big.js:轻量库,适合货币计算。
// 使用 decimal.js
import Decimal from "decimal.js";
const sum = new Decimal(0.1).plus(0.2).toString(); // "0.3"
3. 控制显示精度(toFixed 或 toPrecision)
用于最终展示,避免中间计算使用(可能导致误差累积)。
console.log((0.1 + 0.2).toFixed(2)); // "0.30"(字符串)
4. 比较时容忍误差范围
使用 Number.EPSILON 或自定义阈值。
// 默认容忍误差
function areEqual(a, b, epsilon = 1e-10) {
return Math.abs(a - b) < epsilon;
}
// 动态阈值(针对不同数量级)
function dynamicAreEqual(a, b) {
return Math.abs(a - b) < Number.EPSILON * Math.max(Math.abs(a), Math.abs(b));
}
5. 自定义高精度计算函数
处理加减乘除,通过放大为整数计算。
// 加法示例
function add(num1, num2) {
const factor = 10 ** Math.max(getDecimals(num1), getDecimals(num2));
return (num1 * factor + num2 * factor) / factor;
}
// 获取小数位数
function getDecimals(num) {
const str = num.toString();
return (str.split('.')[1] || '').length;
}
console.log(add(0.1, 0.2)); // 0.3
总结
| 场景 | 推荐方案 |
|---|---|
| 简单计算且范围可控 | 整数运算或放大为整数计算 |
| 复杂金融计算 | 使用 decimal.js 或 big.js |
| 结果展示 | toFixed 或 toPrecision |
| 比较浮点数 | 误差范围判断 |
根据实际需求选择方案,复杂场景推荐优先使用成熟的第三方库。

浙公网安备 33010602011771号