企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 在 Java 中比较浮点数或双精度数的正确方法 > 原文: [https://howtodoinjava.com/java/basics/correctly-compare-float-double/](https://howtodoinjava.com/java/basics/correctly-compare-float-double/) 正确地**比较浮点**或**比较双**不仅是 Java 特定的问题。 当今几乎所有编程语言都可以观察到它。 使用 [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) 标准格式存储浮点数和双精度数。 实际的存储和转换如何工作,不在本文的讨论范围之内。 现在,只需了解在计算和转换期间,可以在这些数字中引入*较小的舍入误差*。 这就是为什么不建议仅依赖相等运算符(`==`)**比较浮点数**的原因。 让我们学习**如何比较 Java** 中的浮点值。 ```java Table of Contents 1\. Simple comparison [Not recommended] 2\. Threshold based comparison [Recommended] 3\. Compare with BigDecimal [Recommended] ``` ## 1\. 双精度比较 -- 简单比较(不推荐) 首先看一下简单比较,以了解用`==`运算符比较`double`到底有什么问题。 在给定的程序中,我使用两种方法创建相同的浮点数(即`1.1`): 1. 添加`.1` 11 次。 2. 将`.1`乘以 11。 理论上,两个操作都应产生数字`1.1`。 当我们比较这两种方法的结果时,它应该匹配。 ```java private static void simpleFloatsComparison() { //Method 1 double f1 = .0; for (int i = 1; i <= 11; i++) { f1 += .1; } //Method 2 double f2 = .1 * 11; System.out.println("f1 = " + f1); System.out.println("f2 = " + f2); if (f1 == f2) System.out.println("f1 and f2 are equal\n"); else System.out.println("f1 and f2 are not equal\n"); } ``` 程序输出。 ```java f1 = 1.0999999999999999 f2 = 1.1 f1 and f2 are not equal ``` 查看控制台中打印的两个值。 将`f1`计算为`1.0999999999999999`。 其舍入问题恰恰是内部引起的。 因此,不建议将**浮点数用`'=='`运算符进行比较**。 ## 2\. 双精度比较 -- 基于阈值的比较[推荐] 现在,当我们知道相等运算符的问题时,让我们解决它。 使用编程,我们无法更改存储或计算这些浮点数的方式。 因此,我们必须采用一种解决方案,在该解决方案中,我们同意确定两个可以容忍的值的差异,并且仍然认为数字相等。 该商定的值差被称为**阈值**或`ε`。 因此,现在要使用“基于阈值的**浮点比较**”,我们可以使用`Math.abs()`方法计算两个数字之间的差并将其与阈值进行比较。 ```java private static void thresholdBasedFloatsComparison() { final double THRESHOLD = .0001; //Method 1 double f1 = .0; for (int i = 1; i <= 11; i++) { f1 += .1; } //Method 2 double f2 = .1 * 11; System.out.println("f1 = " + f1); System.out.println("f2 = " + f2); if (Math.abs(f1 - f2) < THRESHOLD) System.out.println("f1 and f2 are equal using threshold\n"); else System.out.println("f1 and f2 are not equal using threshold\n"); } ``` 程序输出: ```java f1 = 1.0999999999999999 f2 = 1.1 f1 and f2 are equal using threshold ``` ## 3\. 比较`double`与`BigDecimal`(推荐) 在[`BigDecimal`](https://docs.oracle.com/javase/10/docs/api/java/math/BigDecimal.html)类中,可以指定要使用的**舍入模式**和**精确度**。 使用精确的精度限制,可以解决舍入误差。 最好的部分是`BigDecimal`数字是[不可变的](https://howtodoinjava.com/java/basics/how-to-make-a-java-class-immutable/),即,如果创建具有`"1.23"`值的`BigDecimal`,则该对象将保持`"1.23"`且不能更改。 此类提供了许多方法,可用于对其值进行数值运算。 您可以使用`compareTo()`方法与`BigDecimal`数字进行比较。 比较时会忽略比例。 > **`a.compareTo(b);`** > > 方法返回: > > -1 – 如果是`a < b` > > 0 – 如果`a == b` > > 1 – 如果是`a > b` 切勿使用`equals()`方法比较`BigDecimal`实例。这是因为此`equals`函数将比较比例。 如果比例不同,即使在数学上相同,`equals()`也将返回`false`。 Java 程序将`BigDecimal`类与`double`进行比较。 ```java private static void testBdEquality() { BigDecimal a = new BigDecimal("2.00"); BigDecimal b = new BigDecimal("2.0"); System.out.println(a.equals(b)); // false System.out.println(a.compareTo(b) == 0); // true } ``` 现在,为了验证,让我们使用`BigDecimal`类解决原始问题。 ```java private static void bigDecimalComparison() { //Method 1 BigDecimal f1 = new BigDecimal("0.0"); BigDecimal pointOne = new BigDecimal("0.1"); for (int i = 1; i <= 11; i++) { f1 = f1.add(pointOne); } //Method 2 BigDecimal f2 = new BigDecimal("0.1"); BigDecimal eleven = new BigDecimal("11"); f2 = f2.multiply(eleven); System.out.println("f1 = " + f1); System.out.println("f2 = " + f2); if (f1.compareTo(f2) == 0) System.out.println("f1 and f2 are equal using BigDecimal\n"); else System.out.println("f1 and f2 are not equal using BigDecimal\n"); } ``` 程序输出: ```java f1 = 1.1 f2 = 1.1 f1 and f2 are equal using BigDecimal ``` 这就是**比较 Java** 中的浮点数的全部。 在评论部分分享您的想法。 学习愉快!