浮点数精度问题:0.1 + 0.2
解释 JavaScript 浮点数精度丢失的原因及解决方案
问题
为什么 0.1 + 0.2 !== 0.3?如何解决?
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false
解答
原因
JavaScript 使用 IEEE 754 双精度浮点数标准存储数字。十进制的 0.1 和 0.2 转换为二进制时是无限循环小数,存储时会被截断,导致精度丢失。
// 0.1 的二进制表示(无限循环)
// 0.0001100110011001100110011001100110011001100110011001101...
// 实际存储的值
console.log(0.1.toPrecision(20)); // "0.10000000000000000555"
console.log(0.2.toPrecision(20)); // "0.20000000000000001110"
解决方案
1. 使用 toFixed 转换
function add(a, b) {
return parseFloat((a + b).toFixed(10));
}
console.log(add(0.1, 0.2)); // 0.3
console.log(add(0.1, 0.2) === 0.3); // true
2. 转为整数计算
function add(a, b) {
// 获取小数位数
const precision = Math.max(
(a.toString().split('.')[1] || '').length,
(b.toString().split('.')[1] || '').length
);
const multiplier = Math.pow(10, precision);
// 转整数计算后再除回来
return (Math.round(a * multiplier) + Math.round(b * multiplier)) / multiplier;
}
console.log(add(0.1, 0.2)); // 0.3
3. 使用 Number.EPSILON 比较
function isEqual(a, b) {
// Number.EPSILON 是 JavaScript 最小精度值
return Math.abs(a - b) < Number.EPSILON;
}
console.log(isEqual(0.1 + 0.2, 0.3)); // true
4. 使用第三方库
// 使用 decimal.js
import Decimal from 'decimal.js';
const result = new Decimal(0.1).plus(0.2);
console.log(result.toNumber()); // 0.3
// 使用 big.js
import Big from 'big.js';
const sum = new Big(0.1).plus(0.2);
console.log(sum.toNumber()); // 0.3
关键点
- JavaScript 使用 IEEE 754 双精度浮点数,64 位存储(1 符号位 + 11 指数位 + 52 尾数位)
- 0.1 和 0.2 转二进制是无限循环小数,存储时被截断导致精度丢失
- 简单场景用
toFixed或转整数计算 - 精度要求高的场景(如金融计算)使用 decimal.js 或 big.js
- 比较浮点数相等时使用
Number.EPSILON作为误差范围
目录