每日智识
柔彩主题三 · 更轻盈的阅读体验

Java浮点精度问题的那些坑,你踩过几个?

发布时间:2025-12-16 15:33:11 阅读:2 次

在超市收银系统里,明明标价9.99元的商品,结账时却显示9.990000000000001元。顾客一脸疑惑,收银员也摸不着头脑。这种情况背后,很可能就是Java中的浮点精度问题在作怪。

为什么0.1 + 0.2 不等于 0.3?

写过Java的人都可能见过这样的代码:

double a = 0.1;
double b = 0.2;
System.out.println(a + b); // 输出:0.30000000000000004

这并不是Java的bug,而是IEEE 754标准下二进制浮点数的固有局限。十进制中的0.1,在二进制中是无限循环小数,就像1/3在十进制中是0.333...一样,计算机只能截断存储,造成精度丢失。

什么时候该警惕浮点数?

涉及金额计算、科学计数、比较判断等场景,浮点数的微小误差可能被放大。比如用double存账户余额,经过几次加减后,原本应为0的余额可能变成-0.000000000000001,导致逻辑判断出错。

再比如下面这段代码:

double price = 1.0 - 0.9;
if (price == 0.1) {
    System.out.println("相等");
} else {
    System.out.println("不相等"); // 实际输出这个
}

直接用==比较两个double值,几乎总会踩坑。

正确的姿势:BigDecimal出场

处理需要精确计算的场景,应该用java.math.BigDecimal。它能以字符串形式精确表示数值,避免二进制转换带来的误差。

import java.math.BigDecimal;

BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
BigDecimal sum = a.add(b);
System.out.println(sum); // 输出:0.3

注意构造时要用字符串,而不是new BigDecimal(0.1),否则传入的已经是失真的double值,从源头就错了。

日常开发的小建议

如果必须用double,比较时应使用误差范围(delta):

double result = 0.1 + 0.2;
if (Math.abs(result - 0.3) < 1e-10) {
    System.out.println("可以认为相等");
}

另外,像float这种单精度类型,误差更大,除非对内存特别敏感,否则不如直接用double或更稳妥的BigDecimal

浮点精度问题看似冷门,实则潜伏在每个涉及数值运算的角落。理解它的原理,才能在关键时刻避开那些“莫名其妙”的bug。