3

检查双精度值是否相等的最有效方法是什么。

我明白那个

double a = 0.00023d;
double b = 0.00029d;

boolean eq = (a == b);

是缓慢的。

所以我正在使用

double epsilon = 0.00000001d;
eq = Math.abs(a - b) < epsilon;

问题是Infinitest抱怨测试花费了太多时间。这没什么大不了的(顶部 1 秒),但这让我很好奇。

附加信息

a是硬编码的,因为它是预期值,b由下式计算

  // fyi: current = int, max = int
  public double getStatus()
  {
    double value = 0.0;
    if (current != 0 && max != 0)
      value = ((double) current) / max;
    return value;
  }

更新

java.lang.Double 就是这样做的

public boolean equals(Object obj) {
return (obj instanceof Double)
       && (doubleToLongBits(((Double)obj).value) ==
          doubleToLongBits(value));
}

因此可以假设这是最佳实践。

4

3 回答 3

6

JUnit 有一种方法可以Double用给定的 delta 检查“相等”:

Assert.assertEquals(0.00023d, 0.00029d, 0.0001d);

请参阅此 API 文档

正如评论中所指出的,JUnit 实际上很可能比手动与给定的增量进行比较要慢。JUnit 首先执行 aDouble.compare(expected, actual)后跟(如果不等于) a Math.abs(expected - actual) <= delta

希望这个答案对于那些不知道 JUnit 实际上提供了一种不精确Double相等测试的方法的人仍然有用。

于 2013-07-31T13:08:36.967 回答
2

实际上,比较两个浮点/双精度值本身是一种不好的做法,因为浮点数存在舍入误差。两个在符号数学中相等的数字可能与计算机不同,这取决于它们的计算方式。

最佳做法是您使用的第二个选项:Math.abs(a - b) < epsilon.
我知道它可能比您想要的要慢,但这是正确的方法。从应用程序的角度来看,按位比较可能会导致两个数字被视为不同,即使它们相同(如果您手动计算它们,它们将相等,但由于舍入误差,它们按位不同) .

于 2013-08-06T13:21:33.937 回答
0

java.lang.Double

如问题java.lang.Double.equals()调用所示public static long doubleToLongBits(double value)

/**
 * Returns a representation of the specified floating-point value
 * according to the IEEE 754 floating-point "double
 * format" bit layout.

然后检查是否与==. (doubleToLongBits内部调用public static native long doubleToRawLongBits(double value),所以它依赖于平台)。

这里原始类型的工作方式。

原始类型 double

浮点类型是 float 和double,它们在概念上与 IEEE 二进制浮点算术标准、ANSI/IEEE 中指定的单精度 32 位和双精度 64 位格式 IEEE 754 值和运算相关联标准 754-1985(IEEE,纽约)。JLS-4.2.3


浮点数运算符的行为符合 IEEE 754 的规定(余数运算符除外(第 15.17.3 节))。 JLS-4.2.4


因此,最快的方法是使用原始类型并可能根据所需的准确性执行“增量检查”。如果使用 Double 提供的方法无法做到这一点。

一个人不应该使用 JUnit 断言方法,因为它执行更多的检查,一个人会更好地做某事,比如:

boolean eq = Double.valueOf(5.0d).equals(Double.valueOf(2.0d));
Assert.assertTrue(eq);
于 2013-08-06T13:07:59.133 回答