在 Java 中,直接使用 == 比较浮点数(float/double)可能会因精度损失导致错误结果。这是因为浮点数采用 IEEE 754 标准,无法精确表示所有十进制小数(如 0.1)。其根源在于计算机中使用的是二进制表示浮点数,导致许多十进制小数无法精确存储和计算。以下是安全比较浮点数的常用方法:
1. 允许误差法(推荐)
- 使用一个极小的误差值(epsilon)判断两数差值是否在可接受范围内:
float a = 1.0f - 0.9f;
float b = 0.1f;
float epsilon = 1e-6f; // 根据精度需求调整
// 比较是否近似相等
boolean isEqual = Math.abs(a - b) < epsilon; // true
- 优点:灵活控制精度,解决大部分比较场景。
- 适用场景:一般计算、条件判断。
2. BigDecimal 法(高精度场景)
- 使用
BigDecimal精确表示小数,并通过compareTo()比较:
BigDecimal x = new BigDecimal("1.0").subtract(new BigDecimal("0.9"));
BigDecimal y = new BigDecimal("0.1");
boolean isEqual = x.compareTo(y) == 0; // true
- 注意:务必用字符串构造
BigDecimal,避免二进制精度损失。 - 适用场景:金融计算、要求绝对精确的比较。
3. Double.compare() / Float.compare()
- Java 标准库提供的比较方法:
double d1 = 0.1 + 0.2;
double d2 = 0.3;
boolean isEqual = Double.compare(d1, d2) == 0;
System.out.println(isEqual);
运行结果:

- 局限性:内部仍基于二进制表示比较,可能仍需结合误差范围使用。
- 适用场景:需要符合
Comparator接口的排序等场景。
关键注意事项:
-
永远避免
==直接比较:System.out.println(0.1 + 0.2 == 0.3);以上代码运行后打印结果为:false,得到的结果并非是我们所期望的。

-
Epsilon 的选择:
-
根据实际精度需求调整
epsilon(如1e-5、1e-10)。 -
对于极小或极大值,可改用相对误差比较:
boolean isEqual = Math.abs(a - b) < epsilon * Math.max(Math.abs(a), Math.abs(b));
-
-
特殊值处理:
NaN(非数字):NaN == NaN总为false,需用Float.isNaN()检测。- 无穷大:
Double.POSITIVE_INFINITY可互相比较。
总结选择建议:
在大多数浮点数比较的需求中,可能都需要进行精确比较,但也不排除一些允许有误差的场景,因此需要我们根据不同场景进行选择,以下表格进行了简单的总结,供大家参考。
| 场景 | 推荐方法 |
|---|---|
| 常规浮点数比较 | 允许误差法(Math.abs(a-b)<ε) |
| 金融计算/高精度要求 | BigDecimal + 字符串构造 |
| 集合排序/实现Comparator | Float.compare() / Double.compare() |
示例代码整合:
public class FloatComparison {
public static void main(String[] args) {
// 允许误差法
float a = 1.0f - 0.9f;
float b = 0.1f;
boolean approxEqual = Math.abs(a - b) < 1e-6; // true
// BigDecimal 法
BigDecimal x = new BigDecimal("1.0").subtract(new BigDecimal("0.9"));
BigDecimal y = new BigDecimal("0.1");
boolean exactEqual = x.compareTo(y) == 0; // true
System.out.println("近似比较: " + approxEqual);
System.out.println("精确比较: " + exactEqual);
}
}
10万+

被折叠的 条评论
为什么被折叠?



