
javascript 中 `0.1 + 0.2 !== 0.3` 是因二进制浮点表示无法精确存储十进制小数,临时乘除 10 仅对特例“碰巧有效”,真正可靠的方法是结合整数运算与显式舍入。
在 JavaScript 中,所有数字均以 IEEE 754 双精度浮点格式存储。由于 0.1 和 0.2 在二进制中是无限循环小数(如 0.1₁₀ = 0.0001100110011…₂),它们必须被截断近似,导致计算时产生微小误差——因此 0.1 + 0.2 得到的是 0.30000000000000004,而非数学上的精确 0.3。
有人尝试通过“放大→整数运算→缩小”来规避该问题,例如:
let y = (0.2 * 10 + 0.1 * 10) / 10; // 结果为 0.3(看似正确)
这之所以“看起来有效”,并非因为乘以 10 具有普适性,而是巧合:0.2 * 10 和 0.1 * 10 的浮点结果(2.0 和 1.0)恰好能被精确表示为双精度数,加法后仍为精确整数 3.0,再除以 10 时也未引入新误差。但这一逻辑极其脆弱——例如 0.3 + 0.6 用同样方法会失败:
console.log((0.3 * 10 + 0.6 * 10) / 10); // 0.8999999999999999 ❌
原因在于 0.3 * 10 实际为 3.0000000000000004,0.6 * 10 为 6.000000000000001,相加后舍入误差叠加,再除以 10 无法恢复理想值。
立即学习“Java免费学习笔记(深入)”;
✅ 正确做法是:先用 Math.round() 显式舍入到目标精度的整数,再缩放回小数:
// 统一保留 1 位小数的加法
function addFixed(a, b, decimals = 1) {
const factor = 10 ** decimals;
return (Math.round(a * factor) + Math.round(b * factor)) / factor;
}
console.log(addFixed(0.2, 0.1)); // 0.3 ✅
console.log(addFixed(0.3, 0.6)); // 0.9 ✅
console.log(addFixed(1.005, 2.005, 2)); // 3.01 ✅(避免 1.005 + 2.005 = 3.0099999999999998)⚠️ 注意事项:
- 不要依赖 parseFloat((a + b).toFixed(n)) 处理链式运算,toFixed() 返回字符串且中间步骤仍存在浮点误差;
- 对金融计算等高精度场景,应使用专用库(如 decimal.js 或 big.js),避免手工缩放;
- Math.round() 方案适用于简单、固定精度的场景(如金额显示、UI 展示),但不替代任意精度算术。
总结:浮点误差的本质是表示局限,而非计算错误。乘以 10 “奏效”只是偶然,而 Math.round() + 缩放才是可控、可复现、可推广的实践方案。










