Java中比较Float浮点数或双精度浮点数Double的正确方法

培训教学 潘老师 8个月前 (09-09) 216 ℃ (0) 扫码查看

正确比较 float比较 double不仅仅是 Java 特有的问题。如今几乎所有编程语言中都可以观察到这一点。在计算机内存中,浮点数和双精度数使用IEEE 754标准格式存储。实际存储和转换如何工作,超出了本文的范围。

现在,只需了解在计算和转换过程中,这些数字可能会引入较小的舍入误差。这就是为什么不建议简单地依赖相等运算符 (==)来比较浮点数

让我们学习如何在 Java 中比较浮点值

1.比较double – 简单比较【不推荐】

首先看一下简单的比较方法,以了解使用==运算符比较double时出现了什么问题。在给定的程序中,我使用两种方法创建相同的浮点数(即1.1):

  • 将0.1累加11次。
  • 将0.1乘以11。

理论上,这两种操作都应该生成数字1.1。当我们比较这两种方法的结果时,它们应该匹配。

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");
}

程序输出:

f1 = 1.0999999999999999
f2 = 1.1
f1 and f2 are not equal

查看控制台中打印的两个值。f1计算为1.0999999999999999. 这正是四舍五入内部导致的问题。这就是为什么不建议使用运算'=='进行浮点数比较的原因

2.比较double – 基于阈值的比较【推荐】

现在我们知道了等号运算符的问题,让我们来解决它。在编程中,我们不能改变这些浮点数的存储或计算方式。因此,我们必须采用一种解决方案,其中我们同意确定两个值之间的差异,我们可以容忍并仍然将这些数字视为相等。这些值之间的同意差异称为阈值或epsilon。

因此,为了使用“基于阈值的浮点数比较”,我们可以使用Math.abs()方法计算两个数字之间的差异,然后将差异与阈值进行比较。这样做可以确保我们在比较浮点数时考虑到了精度差异。

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");
}

程序输出:

f1 = 1.0999999999999999
f2 = 1.1
f1 and f2 are equal using threshold

3.比较double – 使用BigDecimal比较【推荐】

在BigDecimal类中,您可以指定要使用的舍入模式和精确度限制。使用精确度限制,舍入误差大多可以解决。

最重要的一点是,BigDecimal数字是不可变的,即如果您创建了一个值为“1.23”的BigDecimal对象BD,那么该对象将始终是“1.23”,永远不会更改。此类提供了许多方法,可用于对其值进行数值操作。

您可以使用其compareTo()方法来比较两个BigDecimal数字。在比较时,它忽略了标度(小数点后的位数)。

a.compareTo(b);

方法返回:

-1:如果a<b

0 :如果 a == b

1 : 如果 a > b
永远不要使用equals()方法来比较BigDecimal实例。这是因为这个equals函数将比较它们的标度(scale)。如果标度不同,equals()会返回false,即使它们在数学上是相同的数字。

使用BigDecimal类的compareTo方法来比较double值:

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 类来解决原始问题:

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");
}

程序输出:

f1 = 1.1
f2 = 1.1
f1 and f2 are equal using BigDecimal

这就是java 中比较浮点数的全部内容。在评论部分分享您的想法。


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/teach/8950.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】