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

IT 文章2年前 (2023)发布 小编
0 0 0

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

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

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

ad

程序员导航

优网导航旗下整合全网优质开发资源,一站式IT编程学习与工具大全网站

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. 这正是四舍五入内部导致的问题。这就是为什么不建议使用运算'=='进行浮点数比较的原因

ad

AI 工具导航

优网导航旗下AI工具导航,精选全球千款优质 AI 工具集

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数字。在比较时,它忽略了标度(小数点后的位数)。

ad

免费在线工具导航

优网导航旗下整合全网优质免费、免注册的在线工具导航大全

a.compareTo(b);

方法返回:

-1:如果a<b

0 :如果 a == b

1 : 如果 a > b

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

使用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 中比较浮点数的全部内容。在评论部分分享您的想法。

© 版权声明

相关文章

暂无评论

暂无评论...