日常知识通
柔彩主题三 · 更轻盈的阅读体验

Java浮点精度问题:为什么0.1 + 0.2不等于0.3?

发布时间:2025-12-16 15:32:29 阅读:276 次

你有没有在写Java程序时遇到过这样的奇怪现象:明明是0.1加0.2,结果打印出来却不是0.3?

比如这段代码:

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

看起来像是程序出错了,其实这是Java中浮点数精度的典型表现。根本原因在于计算机底层用二进制表示小数时的局限性。

为什么0.1在二进制里“表达不清”?

我们日常用十进制,0.1很清楚。但计算机用的是二进制,而像0.1这样的小数,在二进制中是无限循环的——就像1/3在十进制中是0.333…一样。

也就是说,0.1在二进制里是0.0001100110011…一直循环下去。计算机只能存储有限位数,于是就做了截断或近似处理,这就带来了微小的误差。

float和double都逃不过这个问题

Java里的float和double都遵循IEEE 754标准,用固定位数存储浮点数。double有64位,比float(32位)更精确,但依然无法完全避免这种精度丢失。

举个生活中的例子:就像你用一把最小刻度是毫米的尺子去量0.1毫米的厚度,怎么量都不准,因为工具本身的精度不够。

什么时候需要特别注意?

如果你在做金融计算、订单金额、税率计算这类对精度要求高的场景,直接用double可能会出问题。比如算一笔9.99元的商品打9折,理论上应该是8.991,四舍五入为8.99,但如果浮点误差导致变成8.992,最后多收了用户一分钱,长期积累可能引发纠纷。

解决方案:用BigDecimal

对于高精度需求,Java提供了BigDecimal类,它可以精确表示小数,不会受二进制转换影响。

import java.math.BigDecimal;

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

注意:构造BigDecimal时要用字符串,而不是double。如果写成new BigDecimal(0.1),0.1本身已经是近似值了,传进去就带着误差。

日常开发的小建议

在大多数情况下,比如游戏得分、物理模拟、图形处理,用double完全没问题,那点误差可以忽略。但只要涉及钱、合同、报表这些对数字敏感的场景,就得切换到BigDecimal。

另外,比较两个浮点数是否相等时,别用==,而是判断它们的差值是否在一个极小范围内:

double a = 0.1 + 0.2;
double b = 0.3;
if (Math.abs(a - b) < 1e-10) {
    System.out.println("视为相等");
}

这样能有效避开精度陷阱。