JavaScript数学运算精度问题及解决方案
一、问题根源
-
IEEE 754双精度浮点数标准限制
JavaScript使用64位二进制存储数值,无法精确表示部分十进制小数。例如:
0. 1 10 = 0. 0001100110011 ‾ 2 0.1_{10} = 0.\overline{0001100110011}_2 0.110=0.00011001100112
这种二进制无限循环会导致截断误差,例如:0.1 + 0.2 === 0.3; // false
-
数值范围与精度矛盾
双精度浮点数的有效数字仅 52 52 52位,当数值超过 2 53 2^{53} 253时,整数运算也会出现误差。
二、解决方案
1. 简单精度修正
-
四舍五入法
通过toFixed(n)
限制小数位数(自动四舍五入):(0.1 + 0.2).toFixed(2); // "0.30"
注意:
toFixed()
返回字符串类型,需再转换为数值。 -
误差容忍比较
使用Number.EPSILON
(最小精度单位)判断浮点数相等:Math.abs(0.3 - (0.1 + 0.2)) < Number.EPSILON; // true
2. 整数放大法
将小数转换为整数运算,避免二进制转换误差:
// 计算 0.1 + 0.2(放大10倍)
const result = (1 + 2) / 10; // 0.3
适用于已知小数位数的场景。
3. 第三方高精度库
库名称 | 特点 | 示例代码 |
---|---|---|
Big.js | 轻量级,基础运算 | new Big(0.1).plus(0.2).toString() → “0.3” |
Decimal.js | 支持三角函数等复杂运算 | Decimal.add(0.1, 0.2).toNumber() → 0.3 |
Math.js | 提供表达式解析功能 | math.evaluate('0.1 + 0.2') → 0.3 |
4. 自定义函数处理
如引用[1]的Arithmetic
函数处理计算,FormatByAccuracy
控制显示精度。
三、应用场景建议
- 财务计算:必须使用
Big.js
或Decimal.js
- 工程计算:可结合放大倍数法与误差容忍比较
- 数据展示:
toFixed()
或FormatByAccuracy
格式化