检查java.lang.Double是否相等的高效方法

时间:2013-07-31 13:04:35

标签: java junit comparison double infinitest

检查双重值是否相同的最佳方法是什么。

我理解

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

所以可以假设这是最好的做法。

3 个答案:

答案 0 :(得分:4)

JUnit有一种方法用给定的delta检查Double的'相等':

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

请参阅this API documentation

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

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

答案 1 :(得分:1)

实际上,比较两个float / double值是否相等是一个错误的实践,因为浮点数会受到舍入错误的影响。 符号数学中相等的两个数字可能与计算机不同,具体取决于它们的计算方式。

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

答案 2 :(得分: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),因此它取决于平台。)

这里是基元类型的工作方式。

原始类型双

  

浮点类型为float和 double ,它们在概念上与IEEE标准中规定的单精度32位和双精度64位格式IEEE 754值和操作相关联。用于二进制浮点运算,ANSI / IEEE标准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);