JavaScript浮点数相减精度问题:为何计算结果不符合预期?
为什么JavaScript中3.0减2.6会得到0.3999999999999999而非0.4?
这个问题是JavaScript浮点数精度的经典陷阱,我来帮你理清楚前因后果:
核心原因:浮点数的二进制存储限制
首先得明确:大部分十进制小数无法被二进制浮点数精确表示。比如0.1、0.6这类数,在二进制里是无限循环的小数,就像十进制里的1/3=0.3333...一样。当你把2.6存入JS的Number类型时,实际存储的是一个非常接近2.6但存在微小误差的近似值。
而你代码里的toFixed(1)又额外加了一层坑:toFixed()返回的是字符串,不是数字!虽然JS会在减法时自动把字符串转成数字,但这个转换过程依然逃不过浮点数的精度问题。
那为什么discount_amt=2.5时结果正常?因为2.5是2 + 1/2,对应的二进制是10.1,可以被精确存储,所以3.0-2.5=0.5的计算完全精确。
解决方法
针对你的场景,有几个简单有效的方案:
1. 先计算,后格式化
不要在计算前用toFixed()处理数值,先完成所有运算,最后再用toFixed()格式化输出结果:
var total = parseFloat('3'); var discount_amt = parseFloat('2.6'); total = total - discount_amt; console.log(total.toFixed(1)); // 输出 "0.4"
2. 转整数计算,避免浮点数误差
把所有小数乘以10(或10的n次方,n是你需要保留的小数位数)转成整数,计算完成后再转回去:
var total = parseFloat('3') * 10; var discount_amt = parseFloat('2.6') * 10; total = (total - discount_amt) / 10; console.log(total); // 输出 0.4
3. 用精度阈值判断近似相等(如果需要比较结果)
如果你的场景需要判断计算结果是否等于某个值,可以用Number.EPSILON(JS中表示两个可表示浮点数之间的最小差值)来做近似判断:
var result = 3.0 - 2.6; if (Math.abs(result - 0.4) < Number.EPSILON) { console.log("结果近似等于0.4"); }
内容的提问来源于stack exchange,提问作者Bhautik




