问题
What is the most performant way to check double values for equality.
I understand that
double a = 0.00023d;
double b = 0.00029d;
boolean eq = (a == b);
is slow.
So I'm using
double epsilon = 0.00000001d;
eq = Math.abs(a - b) < epsilon;
The problem is that Infinitest
is complaning about tests taking too much time. It's not a big deal (1 sec top), but it made me curious.
Additional info
a
is hard coded since it's the expected value, b
is computed by
// fyi: current = int, max = int
public double getStatus()
{
double value = 0.0;
if (current != 0 && max != 0)
value = ((double) current) / max;
return value;
}
Update
java.lang.Double does it that way
public boolean equals(Object obj) {
return (obj instanceof Double)
&& (doubleToLongBits(((Double)obj).value) ==
doubleToLongBits(value));
}
so one could assume that is the best practice.
回答1:
JUnit has a method of checking a Double
for 'equality' with a given delta:
Assert.assertEquals(0.00023d, 0.00029d, 0.0001d);
See this API documentation.
As noted in the comments, JUnit actually most likely is slower than comparing manually with a given delta. JUnit first does a Double.compare(expected, actual)
followed (if not equal) by a Math.abs(expected - actual) <= delta
.
Hopefully this answer still is useful for people not aware that JUnit actually provides a way for inexact Double
equality testing.
回答2:
Actually, comparing two float/double values for equality is a bad practice in itself, because floating point numbers suffer from rounding errors. Two numbers which would be equal in symbolic maths may be different to the computer, depending on how they are computed.
The best practice is the second option you used: Math.abs(a - b) < epsilon
.
I understand it may be slower than you'd like, but it's the right way to do it. Bitwise comparison may result in two numbers being considered as different even though they're the same, from the point of view of the application (they would be equal if you had computed them by hand, but they are bitwise different due to rounding errors).
回答3:
java.lang.Double
As shown in the question java.lang.Double.equals()
calls public static long doubleToLongBits(double value)
, which
/**
* Returns a representation of the specified floating-point value
* according to the IEEE 754 floating-point "double
* format" bit layout.
and then checks for equality with ==
.
(doubleToLongBits
internally calls public static native long doubleToRawLongBits(double value)
, so it is platform dependent).
Here the way the primitive type works.
primitive type double
The floating-point types are float and double, which are conceptually associated with the single-precision 32-bit and double-precision 64-bit format IEEE 754 values and operations as specified in IEEE Standard for Binary Floating-Point Arithmetic, ANSI/IEEE Standard 754-1985 (IEEE, New York).JLS-4.2.3
Operators on floating-point numbers behave as specified by IEEE 754 (with the exception of the remainder operator (§15.17.3)). JLS-4.2.4
So the fastest way would be using primitive types and possibly performing a 'delta check' depending on the needed accuracy. If that's not possible using the methods provided by Double.
One should not use the JUnit assert method, since it performs more checks, one would be better off doing sth like:
boolean eq = Double.valueOf(5.0d).equals(Double.valueOf(2.0d));
Assert.assertTrue(eq);
来源:https://stackoverflow.com/questions/17971226/performant-way-to-check-java-lang-double-for-equality