应使用误差范围 epsilon 判断浮点数相等,而非 ==;因二进制无法精确表示十进制小数且存在舍入误差,如 0.1 + 0.2 != 0.3;epsilon 需依场景选择,如科学计算用 1e-6(float)或 1e-15(double),金融用 0.01,避免使用极小值或硬编码。

不能直接用 == 判断两个浮点数是否相等,因为 double 和 float 在二进制中无法精确表示大多数十进制小数(如 0.1、0.2),计算过程还会叠加舍入误差。例如 0.1 + 0.2 == 0.3 的结果是 false,实际值为 0.30000000000000004。解决办法是引入一个可接受的误差范围(epsilon),判断两数之差的绝对值是否小于它。
选对 epsilon 是关键
epsilon 不是固定常量,必须结合业务场景和数值量级来定:
- 一般科学计算或坐标比较:用
1e-6(float)或1e-15(double)较稳妥 - 金融金额(单位为“分”):用
1e-2或0.01更合理 - 避免用
Float.MIN_VALUE或Double.MIN_VALUE——它们太小(约1e-38/1e-308),几乎总导致判定失败 - 不建议硬写
0.0001这类字面量,应定义为private static final double EPS = 1e-9;,便于复用和统一调整
基础写法:Math.abs(a - b)
这是最常用、最直观的方式,适用于绝大多数条件判断和单元测试:
-
double a = 0.1 + 0.2;double b = 0.3;boolean equal = Math.abs(a - b) → <code>true - JUnit 的
assertEquals(double expected, double actual, double delta)就是基于此逻辑 - 注意:该方法只适用于数值量级相对稳定的情况(比如都在 0.001~1000 范围内)
应对极端量级:考虑相对误差
当数值可能极大(如 1e20)或极小(如 1e-20)时,单一绝对误差会失效:
-
1e20 + 1 == 1e20在double中恒成立,此时Math.abs(a-b) 总为 <code>true -
1e-20级别的数,1e-6又太大,失去区分能力 - 可改用相对误差公式:
Math.abs(a - b) - 更健壮的做法是组合使用:先判绝对差,再判相对差,任一满足即视为相等
高精度场景:用 BigDecimal 替代
如果业务要求**完全避免二进制误差**(如财务结算、审计校验),就不要用浮点类型做中间计算:
- 构造时必须用字符串:
new BigDecimal("0.1").add(new BigDecimal("0.2")),不能用new BigDecimal(0.1)(后者已带误差) - 比较用
compareTo():x.compareTo(y) == 0,安全且精确 - 代价是性能开销较大、代码略冗长,仅在必要时采用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











