你以为的0.1 + 0.2,其实不是0.3
在浏览器控制台里输入 0.1 + 0.2,回车后你看到的可能是 0.30000000000000004。这个结果看起来离谱,但其实是JavaScript里最常见的浮点数精度丢失现象。
很多刚接触前端开发的人遇到这种问题都会愣住,尤其是做金额计算时,比如用户买了两件0.1元的商品,系统却显示总价是0.30000000000000004元,这显然没法跟用户解释。
为什么会这样?
根本原因在于计算机用二进制存储数字,而像0.1这样的小数在二进制中是无限循环的——就像1/3在十进制中是0.333…一样。JavaScript使用IEEE 754标准的双精度浮点数格式,只能近似表示这些值,于是就出现了微小误差。
再来看几个典型的例子:
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.2 + 0.7); // 0.8999999999999999
console.log(0.3 - 0.2); // 0.09999999999999998
这些都不是bug,而是几乎所有基于IEEE 754标准的语言都会面临的问题,包括Java、Python、C++等。
实际场景中的坑
假设你在做一个购物车功能,用户加购了三件0.1元的贴纸,你想判断总价是否满0.3元来决定是否免运费。代码可能是这样的:
const price = 0.1;
const total = price * 3;
if (total === 0.3) {
console.log('免运费');
} else {
console.log('还需支付0.01元免运费');
}
结果用户明明凑够了,却还是被提示要多付钱。这就是因为 price * 3 实际上是 0.30000000000000004,不等于0.3。
怎么避免这类问题?
最简单的方法是别直接比较浮点数是否相等。可以用一个极小的数(叫“误差范围”或“epsilon”)来判断两个数是否“足够接近”:
function isEqual(a, b) {
return Math.abs(a - b) < Number.EPSILON * 100;
}
console.log(isEqual(0.1 + 0.2, 0.3)); // true
另一种常见做法是把金额转换成“分”来计算。比如0.1元变成10分,全程用整数运算,最后再除以100转回元。这样彻底避开小数问题。
// 以分为单位计算
const priceInCents = 10; // 0.1元 = 10分
const totalInCents = priceInCents * 3; // 30分
const totalInYuan = totalInCents / 100; // 0.3元
// 这样就不会出错
如果你经常处理高精度计算,也可以考虑使用专门的库,比如 decimal.js 或 big.js,它们能提供任意精度的数学运算支持。
别让小数毁了你的逻辑
浮点数精度问题看似不起眼,但在金融、计费、动画帧率控制等场景下可能引发严重后果。下次当你发现某个数值判断莫名其妙失败时,不妨检查一下是不是掉进了浮点数的坑里。
打开浏览器控制台试试就知道,这些问题每天都在发生。理解它,才能绕开它。