Reputation: 1642
So I recently started loving the language kotlin. Today, while comparing doubles, I came across the inevitable NaN
.
fun main(args: Array<String>) {
val nan = Double.NaN
println("1: " + (nan == nan))
println("2: " + (nan == (nan as Number)))
println("3: " + ((nan as Number) == nan))
}
N.B: (Double
is a subtype of Number
)
Running the above code yields:
1: false
2: true
3: true
I understand that comparing with NaN
in Java returns false
, so I would expect false
for all expressions.
How can this behavior be explained? What is the rationale behind it?
Upvotes: 17
Views: 9348
Reputation: 148149
That's because (2) and (3) are compiled to boxing a primitive and then Double.equals
check: on JVM, primitive double
can't be compared to a boxed one.
Double.equals
, in turn, checks equality by comparing doubleToLongBits(...)
of the two Double
s, and for the latter there's a guarantee that
If the argument is NaN, the result is
0x7ff8000000000000L
.
So, the bits returned for two NaN
are equal, and the rule NaN != NaN
is ignored here.
Also, as @miensol mentioned, there's another consequence of this equality check: +0
and -0
are equal according to ==
check and not to equals
check.
Equivalent code in Java would be:
double nan = Double.NaN;
System.out.println("1: " + (nan == nan)) //false
System.out.println("2: " + ((Double) nan).equals(((Number) nan)))
System.out.println("3: " + ((Number) nan).equals(nan));
The last two lines call Double.equals
, comparing doubleToLongBits(...)
.
Upvotes: 14
Reputation: 41678
The first comparison is equivalent to Java's:
double left = Double.NaN;
double right = Double.NaN;
boolean result = left == right;
And as you can read in this answer this is standarized and documented behavior.
The second & third comparison are equivalent to:
Double left = Double.valueOf(Double.NaN);
Number right = Double.valueOf(Double.NaN);
boolean result = left.equals(right);
Which uses Double.equals:
Note that in most cases, for two instances of
class Double
,d1
andd2
, the value ofd1.equals(d2)
is true if and only ifd1.doubleValue() == d2.doubleValue()
also has the value true. However, there are two exceptions:
If
d1
andd2
both representDouble.NaN
, then the equals method returnstrue
, even thoughDouble.NaN==Double.NaN
has the valuefalse
.If
d1
represents+0.0
whiled2
represents-0.0
, or vice versa, the equal test has the valuefalse
, even though+0.0==-0.0
has the valuetrue
.
Upvotes: 8