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.
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.
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).
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);
Related
What is the accuracy of the equality test if the below datatypes are cast to Double (the .equals() test) or to double (the == test)?
Long
long
Integer
int
If the equality test is only accurate within a range of possible Long, long, Integer or int values, what is the precise range over which this accuracy holds?
For example;
Long longTest = Long.MAX_VALUE;
Long longTest2 = Long.MAX_VALUE;
double doubleTest = (double) longTest;
double doubleTest2 = (double) longTest2;
if(doubleTest == doubleTest2) //Is this accurate?
return true;
Think about it as follows:
Both double and long occupy 64 bits storage. For float and int, it is 32.
Because there are some bits spent on the exponent, you will always be in danger of loosing precision when casting a long to a double or an int to a float.
The only save thing is int -> double.
Anyway, as to your example: the double cannot hold the Long.MAX_VALUE with absolute precision, for the reason stated above. It will be an approximation. However, the approxiamtion should be the same every time, hence your example should return true.
Although it would have been possible for the creators of Java to have defined == overloads for all combinations of numeric types so that only things with the same numeric value would compare equal [implying, for example, that there would be no float value which compares equal to 16777217], or to have forbidden the use of == on any combination of types where that operator wouldn't behave as an equivalence relation, they did neither of those those things. Instead, they decided that it should be possible to compare operands with any combination of primitive types, whether or not that is meaningful, and such comparisons should use the same implicit conversions as exist in any other context (a decision I really dislike, btw).
Consequently, a comparison between e.g. a long and a float will be performed by performing an approximate conversion to float and comparing that, without regard for whether any precision was lost in the conversion. A comparison between float and double will be done by performing an exact conversion to double and comparing that. This leads to 16777216.0f == 16777217, and 16777217 == 16777217.0, but 167772176.0f != 16777217.0. There are times when one may want to know whether the float is the best float representation of the other value, and times one may want to know whether it's an exact representation, but the type ranking in Java is inconsistent with regard to which question the == operator answers.
Several cases...
If both types are wrappers, equals is always precise - but do mind that equals is type sensitive (e.g. Integer.equals(Long) always yields false, regardless of value). Otherwise...
If one type is a wrapper and the other is primitive, the wrapper will be unboxed and the comparison is done using == semantics the same as both types were primitives from the start.
Equality for primitives (==) is precise for any integer type (byte, short, int, long) - the smaller type will be cast to the larger type, then compared. For char, its cast to the larger type but unsigned.
Equality with one operand a floating point type (float, double) the other type is cast to the floating point type and there is potentially precision lost in that case. Float can represent any integer value that has <= 24 significant bits precisely, double has 53 bits of relevant precision (its determined by the number of mantissa bits in the type, see IEEE754 for dirty details).
So basically, float == (int) N is only precise when (approx.) abs(N) <= (1 << 23), and double = (long) N when abs(N) <= (1 << 52). If there are more significant bits in the integer type, the lowermost bits are lost when the type is cast to float/resp. double. Since double has more mantissa bits than int can have significant bits, comparisions between double and int are precise in that regard.
I'm porting a Java app to C# that makes use of
double x;
if (x == null) blah blah
doubles in .Net aren't nullable so this needs to be changed. No big deal.
It is poor practice to test floating point numbers for equality. So if I initialize a variable
double d = double.MaxValue;
and later want to test it
if (d == double.MaxValue) blah blah
is this valid? Am I guaranteed that the test will always return true, assuming d has not been given a new value?
Double in Java is nullable, since it's a class and therefore a reference type, which boxes a double. You should use Nullable<double> or double? in C# (both are technically the same). Nullable<T> is a generic "box wrapper" for .NET value types.
There's nothing wrong with checking floating point values against some constant that you assigned before.
The smelly part about floats and equality comparison is trying to compare computed values or a computed value and a constant - that will likely fail due to rounding errors.
What is an elegant, readable and non-verbose way of comparing two floating point value for exact equality?
As simple as it may sound, its a wicked problem. The == operator doesn't get the job done for NaN and also has special treatment for zero:
(+0.0 == -0.0) -> true
Double.NaN == Double.NaN -> false
But I want to determine if two values are exactly the same (but I do not care for different NaN patterns, so any NaN == any other NaN -> true).
I can do this with this ugly Monster piece of code:
Double.doubleToLongBits(a) == Double.doubleToLongBits(b)
Is there a better way to write this (and make the intent obvious)?
You can use
Double.compare(a, b) == 0
From the javadoc for compareTo
Double.NaN is considered by this method to be equal to itself and greater than all other double values (including Double.POSITIVE_INFINITY).
0.0d is considered by this method to be greater than -0.0d.
What you've got is already the best way of doing it, I'd say. It makes it clear that you're interested in the bitwise representation of the value. You happen to be converting those bits to long as a convenient 64-bit type which doesn't have any funky behaviour.
If you don't want it appearing frequently in your codebase, just add a method to wrap it:
public static boolean bitwiseEqualsWithCanonicalNaN(double x, double y) {
return Double.doubleToLongBits(x) == Double.doubleToLongBits(y);
}
Note that as per your question, this does not differentiate between different NaN values. If you wanted to do this at a later date, you'd need to use Double.toRawLongBits.
The code review tool I use complains with the below when I start comparing two float values using equality operator. What is the correct way and how to do it? Is there a helper function (commons-*) out there which I can reuse?
Description
Cannot compare floating-point values using the equals (==) operator
Explanation
Comparing floating-point values by using either the equality (==) or inequality (!=) operators is not always accurate because of rounding errors.
Recommendation
Compare the two float values to see if they are close in value.
float a;
float b;
if(a==b)
{
..
}
IBM has a recommendation for comparing two floats, using division rather than subtraction - this makes it easier to select an epsilon that works for all ranges of input.
if (abs(a/b - 1) < epsilon)
As for the value of epsilon, I would use 5.96e-08 as given in this Wikipedia table, or perhaps 2x that value.
It wants you to compare them to within the amount of accuracy you need. For example if you require that the first 4 decimal digits of your floats are equal, then you would use:
if(-0.00001 <= a-b && a-b <= 0.00001)
{
..
}
Or:
if(Math.abs(a-b) < 0.00001){ ... }
Where you add the desired precision to the difference of the two numbers and compare it to twice the desired precision.
Whatever you think is more readable. I prefer the first one myself as it clearly shows the precision you are allowing on both sides.
a = 5.43421 and b = 5.434205 will pass the comparison
private static final float EPSILON = <very small positive number>;
if (Math.abs(a-b) < EPSILON)
...
As floating point offers you variable but uncontrollable precision (that is, you can't set the precision other than when you choose between using double and float), you have to pick your own fixed precision for comparisons.
Note that this isn't a true equivalence operator any more, as it isn't transitive. You can easily get a equals b and b equals c but a not equals c.
Edit: also note that if a is negative and b is a very large positive number, the subtraction can overflow and the result will be negative infinity, but the test will still work, as the absolute value of negative infinity is positive infinity, which will be bigger than EPSILON.
Use commons-lang
org.apache.commons.lang.math.NumberUtils#compare
Also commons-math (in your situation more appropriate solution):
http://commons.apache.org/math/apidocs/org/apache/commons/math/util/MathUtils.html#equals(double, double)
The float type is an approximate value - there's an exponent portion and a value portion with finite accuracy.
For example:
System.out.println((0.6 / 0.2) == 3); // false
The risk is that a tiny rounding error can make a comparison false, when mathematically it should be true.
The workaround is to compare floats allowing a minor difference to still be "equal":
static float e = 0.00000000000001f;
if (Math.abs(a - b) < e)
Apache commons-math to the rescue: MathUtils.(double x, double y, int maxUlps)
Returns true if both arguments are equal or within the range of allowed error (inclusive). Two float numbers are considered equal if there are (maxUlps - 1) (or fewer) floating point numbers between them, i.e. two adjacent floating point numbers are considered equal.
Here's the actual code form the Commons Math implementation:
private static final int SGN_MASK_FLOAT = 0x80000000;
public static boolean equals(float x, float y, int maxUlps) {
int xInt = Float.floatToIntBits(x);
int yInt = Float.floatToIntBits(y);
if (xInt < 0)
xInt = SGN_MASK_FLOAT - xInt;
if (yInt < 0)
yInt = SGN_MASK_FLOAT - yInt;
final boolean isEqual = Math.abs(xInt - yInt) <= maxUlps;
return isEqual && !Float.isNaN(x) && !Float.isNaN(y);
}
This gives you the number of floats that can be represented between your two values at the current scale, which should work better than an absolute epsilon.
I took a stab at this based on the way java implements == for doubles. It converts to the IEEE 754 long integer form first and then does a bitwise compare. Double also provides the static doubleToLongBits() to get the integer form. Using bit fiddling you can 'round' the mantissa of the double by adding 1/2 (one bit) and truncating.
In keeping with supercat's observation, the function first tries a simple == comparison and only rounds if that fails. Here is what I came up with some (hopefully) helpful comments.
I did some limited testing, but can't say I've tried all edge cases. Also, I did not test performance. It shouldn't be too bad.
I just realized that this is essentially the same solution as the one offered by Dmitri. Perhaps a bit more concise.
static public boolean nearlyEqual(double lhs, double rhs){
// This rounds to the 6th mantissa bit from the end. So the numbers must have the same sign and exponent and the mantissas (as integers)
// need to be within 32 of each other (bottom 5 bits of 52 bits can be different).
// To allow 'n' bits of difference create an additive value of 1<<(n-1) and a mask of 0xffffffffffffffffL<<n
// e.g. 4 bits are: additive: 0x10L = 0x1L << 4 and mask: 0xffffffffffffffe0L = 0xffffffffffffffffL << 5
//int bitsToIgnore = 5;
//long additive = 1L << (bitsToIgnore - 1);
//long mask = ~0x0L << bitsToIgnore;
//return ((Double.doubleToLongBits(lhs)+additive) & mask) == ((Double.doubleToLongBits(rhs)+additive) & mask);
return lhs==rhs?true:((Double.doubleToLongBits(lhs)+0x10L) & 0xffffffffffffffe0L) == ((Double.doubleToLongBits(rhs)+0x10L) & 0xffffffffffffffe0L);
}
The following modification handles the change in sign case where the value is on either side of 0.
return lhs==rhs?true:((Double.doubleToLongBits(lhs)+0x10L) & 0x7fffffffffffffe0L) == ((Double.doubleToLongBits(rhs)+0x10L) & 0x7fffffffffffffe0L);
There are many cases where one wants to regard two floating-point numbers as equal only if they are absolutely equivalent, and a "delta" comparison would be wrong. For example, if f is a pure function), and one knows that q=f(x) and y===x, then one should know that q=f(y) without having to compute it. Unfortunately the == has two defects in this regard.
If one value is positive zero and the other is negative zero, they will compare as equal even though they are not necessarily equivalent. For example if f(d)=1/d, a=0 and b=-1*a, then a==b but f(a)!=f(b).
If either value is a NaN, the comparison will always yield false even if one value was assigned directly from the other.
Although there are many cases where checking floating-point numbers for exact equivalence is right and proper, I'm not sure about any cases where the actual behavior of == should be considered preferable. Arguably, all tests for equivalence should be done via a function that actually tests equivalence (e.g. by comparing bitwise forms).
First, a few things to note:
The "Standard" way to do this is to choose an constant epsilon, but constant epsilons do not work correctly for all number ranges.
If you want to use a constant epsilon sqrt(EPSILON) the square root of the epsilon from float.h is a generally considered a good value. (this comes from an infamous "orange book" who's name escapes me at the moment).
Floating point division is going to be slow, so you probably want to avoid it for comparisons even if it behaves like picking an epsilon that is custom made for the numbers' magnitudes.
What do you really want to do? something like this:
Compare how many representable floating point numbers the values differ by.
This code comes from this really great article by Bruce Dawson. The article has been since updated here. The main difference is the old article breaks the strict-aliasing rule. (casting floating pointers to int pointer, dereferencing, writing, casting back). While the C/C++ purist will quickly point out the flaw, in practice this works, and I consider the code more readable. However, the new article uses unions and C/C++ gets to keep its dignity. For brevity I give the code that breaks strict aliasing below.
// Usable AlmostEqual function
bool AlmostEqual2sComplement(float A, float B, int maxUlps)
{
// Make sure maxUlps is non-negative and small enough that the
// default NAN won't compare as equal to anything.
assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);
int aInt = *(int*)&A;
// Make aInt lexicographically ordered as a twos-complement int
if (aInt < 0)
aInt = 0x80000000 - aInt;
// Make bInt lexicographically ordered as a twos-complement int
int bInt = *(int*)&B;
if (bInt < 0)
bInt = 0x80000000 - bInt;
int intDiff = abs(aInt - bInt);
if (intDiff <= maxUlps)
return true;
return false;
}
The basic idea in the code above is to first notice that given the IEEE 754 floating point format, {sign-bit, biased-exponent, mantissa}, that the numbers are lexicographically ordered if interpreted as signed magnitude ints. That is the sign bit becomes the sign bit, the and the exponent always completely outranks the mantissa in defining magnitude of the float and because it comes first in determining the magnitude of the number interpreted as an int.
So, we interpret the bit representation of the floating point number as a signed-magnitude int. We then convert the signed-magnitude ints to a two's complement ints by subtracting them from 0x80000000 if the number is negative. Then we just compare the two values as we would any signed two's complement ints, and seeing how many values they differ by. If this amount is less than the threshold you choose for how many representable floats the values may differ by and still be considered equal, then you say that they are "equal." Note that this method correctly lets "equal" numbers differ by larger values for larger magnitude floats, and by smaller values for smaller magnitude floats.
Is it safe if I use comparision like this (a is int, b and c is float/double):
a == b
b == c
It may hear ridiculous, but in my old programing language, sometimes 1 + 2 == 3 is false (because left side returns 2.99999999999...). And, what about this:
Math.sqrt(b) == Math.sqrt(c)
b / 3 == 10 / 3 //In case b = 10, does it return true?
In general, no it is not safe due to the fact that so many decimal numbers cannot be precisely represented as float or double values. The often stated solution is test if the difference between the numbers is less than some "small" value (often denoted by a greek 'epsilon' character in the maths literature).
However - you need to be a bit careful how you do the test. For instance, if you write:
if (Math.abs(a - b) < 0.000001) {
System.err.println("equal");
}
where a and b are supposed to be "the same", you are testing the absolute error. If you do this, you can get into trouble if a and b are (say_ 1,999,999.99 and 2,000,000.00 respectively. The difference between these two numbers is less than the smallest representable value at that scale for a float, and yet it is much bigger than our chosen epsilon.
Arguably, a better approach is to use the relative error; e.g. coded (defensively) as
if (a == b ||
Math.abs(a - b) / Math.max(Math.abs(a), Math.abs(b)) < 0.000001) {
System.err.println("close enough to be equal");
}
But even this is not the complete answer, because it does not take account of the way that certain calculations cause the errors to build up to unmanageable proportions. Take a look at this Wikipedia link for more details.
The bottom line is that dealing with errors in floating point calculations is a lot more difficult than it appears at first glance.
The other point to note is (as others have explained) integer arithmetic behaves very differently to floating point arithmetic in a couple of respects:
integer division will truncate if the result is not integral
integer addition subtraction and multiplication will overflow.
Both of these happen without any warning, either at compile time or at runtime.
You do need to exercise some care.
1.0 + 2.0 == 3.0
is true because integers are exactly representable.
Math.sqrt(b) == Math.sqrt(c)
if b == c.
b / 3.0 == 10.0 / 3.0
if b == 10.0 which is what I think you meant.
The last two examples compare two different instances of the same calculation. When you have different calculations with non representable numbers then exact equality testing fails.
If you are testing the results of a calculation that is subject to floating point approximation then equality testing should be done up to a tolerance.
Do you have any specific real world examples? I think you will find that it is rare to want to test equality with floating point.
b / 3 != 10 / 3 - if b is a floating point variable like b = 10.0f, so b / 3 is 3.3333, while 10 / 3 is integer division, so is equal to 3.
If b == c, then Math.sqrt(b) == Math.sqrt(c) - this is because the sqrt function returns double anyways.
In general, you shouldn't be comparing doubles/floats for equation, because they are floating point numbers so you might get errors. You almost always want to compare them with a given precision, i.e.:
b - c < 0.000001
The safest way to compare a float/double with something else is actually to use see if their difference is a small number.
e.g.
Math.abs(a - b) < EPS
where EPS can be something like 0.0000001.
In this way you make sure that precision errors do not affect your results.
== comparison is not particularly safe for doubles/floats in basically any language. An epsilon comparison method (where you check that the difference between two floats is reasonably small) is your best bet.
For:
Math.sqrt(b) == Math.sqrt(c)
I'm not sure why you wouldn't just compare b and c, but an epsilon comparison would work here too.
For:
b / 3 == 10 / 3
Since 10/3 = 3 because of integer division, this will not necessarily give the results you're looking for. You could use 10.0 / 3, though i'm still not sure why you wouldn't just compare b and 10 (using the epsilon comparison method in either case).
Float wrapper class's compare method can be used to compare two float values.
Float.compare(float1,float2)==0
It will compare integer bits corresponding to each float object.
In java you can compare a float with another float,and a double with another double.And you will get true when comparing a double with a float when their precision is equal
b is float and 10 is integer then if you compare both with your this critearia then it will give false because...
b = flaot (meance ans 3.33333333333333333333333)
10 is integer so that make sence.
If you want a more complete explanation, here there is a good one: http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html (but it is a little bit long)