0.1 + 0.2 !== 0.3 是因IEEE 754浮点数精度限制,0.1等小数在二进制中无限循环,导致存储误差;解决方案包括使用 number.EPSILON 比较、转整数运算、toFixed() 转换、引入 decimal.js 等高精度库,或设计上避免浮点运算。

javaScript中的数字精度问题是一个常见但容易被忽视的陷阱,尤其是在处理浮点数运算时。比如执行 0.1 + 0.2 === 0.3,结果却是 false,这让很多开发者感到困惑。这并非bug,而是由javascript采用的IEEE 754双精度浮点数标准导致的。
为什么会出现精度问题?
JavaScript中所有数字都以64位浮点数形式存储,这意味着小数在二进制中可能无法精确表示。例如:
- 0.1 在二进制中是无限循环小数(类似十进制中的1/3)
- 因此计算机只能近似存储,造成微小误差
- 这些误差在加减乘除中会累积,最终影响比较和计算结果
示例:
console.log(0.1 + 0.2); // 输出 0.30000000000000004
立即学习“Java免费学习笔记(深入)”;
console.log(0.1 + 0.2 === 0.3); // false
常见的解决方案
1. 使用 Number.EPSILON 进行安全比较
由于浮点数存在误差,直接用 === 判断相等不可靠。可以借助 Number.EPSILON 定义一个可接受的“误差范围”。
建议做法:
function numbersCloseEnough(a, b) { return Math.abs(a - b) < Number.EPSILON; } // 使用 numbersCloseEnough(0.1 + 0.2, 0.3); // true
2. 转换为整数运算(适用于货币等场景)
将小数乘以10的幂次,转为整数计算后再还原。
例如:
const a = 0.1 * 100; // 10 const b = 0.2 * 100; // 20 const result = (a + b) / 100; // 0.3
这种做法适合处理价格、金额等对精度要求高的场景。
3. 使用 toFixed() 和 parseFloat()
toFixed() 可将数字保留指定位数并返回字符串,再用 parseFloat() 转回数字。
示例:
const result = parseFloat((0.1 + 0.2).toFixed(1)); console.log(result); // 0.3
注意:toFixed 返回的是字符串,需转换;且只适合展示,不适合连续计算。
4. 引入第三方库(如 decimal.js、big.js)
对于复杂或高频的高精度计算,推荐使用专门的数学库。
以 decimal.js 为例:
const Decimal = require('decimal.js'); let a = new Decimal(0.1); let b = new Decimal(0.2); console.log(a.plus(b).equals(0.3)); // true
这类库提供任意精度的十进制运算,避免了原生浮点数的问题。
5. 避免不必要的浮点运算
- 金额单位用“分”而不是“元”
- 比例用整数百分比或千分比
- 时间用毫秒而非秒的小数
基本上就这些。虽然JavaScript的数字精度问题是语言层面的限制,但通过合理的方法完全可以规避。关键是理解原理,在合适场景选择合适方案。不复杂,但容易忽略。