浮点数为啥算着算着就不准了
写代码的时候你可能遇到过这种情况:明明是0.1加0.2,结果打印出来却是0.30000000000000004。看着就离谱,但其实这背后不是程序出bug,而是浮点数的“老毛病”——精度丢失。
计算机用二进制存小数,根本存不准
我们人类习惯用十进制,比如0.1、0.5都清清楚楚。但计算机底层用的是二进制,很多简单的十进制小数,在二进制里其实是无限循环的。
就像1/3在十进制里是0.333...一样,0.1在二进制中也是个除不尽的数:0.0001100110011...一直循环。计算机不可能存无限位,只能截断,这就带来了误差。
IEEE 754标准是怎么存浮点数的
现在的编程语言基本都用IEEE 754标准来表示浮点数。它把一个数拆成三部分:符号位、指数位、尾数位。比如JavaScript里的数字就是双精度浮点数,总共64位,尾数部分只有52位用来存有效数字。
也就是说,哪怕你输入的是0.1,系统也会先把它转成最接近的二进制近似值再存起来。这个过程本身就带了点“失真”。
例子一看就明白
拿最常见的例子来说:
console.log(0.1 + 0.2); // 输出:0.30000000000000004
看着奇怪,其实每一步都在按规则走。0.1和0.2各自被转成二进制近似值,相加后再转回十进制,自然就跟预期有点偏差。
不只是JavaScript,几乎所有语言都有这个问题
别以为这是JavaScript不靠谱,Python、Java、C++都逃不开。不信你看Python:
print(0.1 + 0.2) # 输出:0.30000000000000004
一样的结果。因为问题不在语言,而在底层的浮点数表示方式。
什么时候特别容易踩坑
做金融计算的时候最要命。比如你算一笔账,加来加去最后发现差了几分钱,查半天发现是浮点数累积误差搞的鬼。
还有做循环判断时也得小心:
for (let i = 0; i < 1.0; i += 0.1) {
console.log(i);
}
你以为会跑10次?实际上可能跑11次,因为i累加过程中慢慢“漂”过了1.0。
怎么避开这个坑
如果是钱相关的计算,别用浮点数。常见的做法是:金额统一用“分”来存整数,显示时再除以100转成“元”。这样全程都是整数运算,没精度问题。
或者用专门的库,比如JavaScript里的 BigInt 配合缩放,或者用 decimal.js 这类高精度库。
做比较的时候也别直接用 == 判断两个浮点数是否相等,最好设定一个极小的容差值(比如1e-10),差得比这个还小就算相等。