This question already has an answer here:
I am reading Effective java by Joshua Bloch and in Item 8: Obey the general contract when overriding equals, this statement is written
for float fields, use the Float.compare method; and for double fields, use Double.compare. The special treatment of float and double fields is made necessary by the existence of Float.NaN, -0.0f and the analogous double constants;
Can someone explain me with example why we can't use ==
for float or double comparison
There are two reasons to compare floating-point objects:
The
==
operator provides mathematical comparisons. It returns false forNaN == NaN
and true for-0.f == +0.f
The
compare
andcompareTo
routines provide object comparisons. When comparing a NaN to itself, they indicate that it is the same (by returning zero). When comparing-0.f
to+0.f
, they indicate they are different (by returning non-zero).From apidoc,
Float.compare
:Float.compareTo
:Consider the following code:
The ouput is not correct, since something that is not a number, is simply not a number, and should be treated as equal from number comparison point of view. It is also clear that
0=-0
.Let's see what
Float.compare
does:Float.floatToIntBits
:From JLS 15.20.1. Numerical Comparison Operators <, <=, >, and >=
For strict comparisons where operands are positive zero and negative zero the result will be wrong.
From JLS 15.21.1. Numerical Equality Operators == and !=:
For equality comparisons where both operands are NaN the result will be wrong.
Since total ordering (
=
,<
,>
,<=
,>=
) is used by many important algorithms (see all the classes that implement the Comparable interface) it is better to use the compare method because it will yield more consistent behavior.The consequence of the total ordering in the context of the IEEE-754 standard is the difference between the positive and negative zero.
For instance, if you use the equality operator instead of the compare method, and have some collection of values and your code logic makes some decisions based on the ordering of the elements, and you somehow start getting a surplus of NaN values they'll all be treated as different values instead as the same values.
That may likely produce error in the behavior of the program proportional to the amount/rate of NaN values. And if you have a lot of positive and negative zeroes, that's just one pair to affect your logic with error.
Float uses IEEE-754 32 bit format and Double uses IEEE-754 64 bit format.
float
(anddouble
) have some special bit sequences that are reserved for special meanings that are not "numbers":0xff800000
0x7f800000
0x7fc00000
Each of these returns
0
(meaning they are "the same") when compared to itself usingFloat.compare()
, but the following comparisons using==
differ from this forFloat.NaN
:So when comparing
float
values, to be consistent for all values, including the specialFloat.NaN
value,Float.compare()
is the best option.The same applies to
double
.