检查双值是否相等的最有效方法是什么。
我知道
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));
}
所以人们可以认为这是最好的做法。
Double
是否与给定delta"相等"的方法:
Assert.assertEquals(0.00023d, 0.00029d, 0.0001d);
请参阅本API文档。
正如评论中所指出的,JUnit实际上很可能比手动比较给定的delta慢。JUnit首先执行Double.compare(expected, actual)
,然后(如果不相等)执行Math.abs(expected - actual) <= delta
。
希望这个答案对那些没有意识到JUnit实际上为不精确的Double
平等测试提供了一种方法的人仍然有用。
实际上,比较两个浮点/双精度值是否相等本身就是一种糟糕的做法,因为浮点数字会出现舍入误差。在符号数学中相等的两个数字可能与计算机不同,这取决于它们的计算方式。
最佳实践是您使用的第二个选项:Math.abs(a - b) < epsilon
我知道它可能比你想要的慢,但这是正确的方法。从应用程序的角度来看,逐位比较可能会导致两个数字被认为是不同的,即使它们是相同的(如果你手工计算,它们会相等,但由于舍入误差,它们逐位不同)。
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.
然后检查是否与CCD_ 11相等。(doubleToLongBits
内部调用public static native long doubleToRawLongBits(double value)
,因此它依赖于平台)。
这里是原始类型的工作方式。
原始类型双
浮点类型为float和double,它们在概念上与IEEE二进制浮点运算标准ANSI/IEEE标准754-1985(IEEE,纽约)中规定的单精度32位和双精度64位格式IEEE 754值和运算相关联JLS-4.2.3
浮点数上的运算符的行为符合IEEE 754的规定(余数运算符除外(§15.17.3))。JLS-4.2.4
因此,最快的方法是使用基元类型,并可能根据所需的准确性执行"delta检查"。如果使用Double提供的方法无法做到这一点。
不应该使用JUnit断言方法,因为它执行更多的检查,所以最好做一些事情,比如:
boolean eq = Double.valueOf(5.0d).equals(Double.valueOf(2.0d));
Assert.assertTrue(eq);