Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing NaN in Kotlin

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?

like image 591
AplusKminus Avatar asked Jun 17 '16 14:06

AplusKminus


People also ask

How do you compare Double NaN?

Use the IsNaN method to determine whether a value is not a number. The Equality operator considers two NaN values to be unequal to one another. In general, Double operators cannot be used to compare Double. NaN with other Double values, although comparison methods (such as Equals and CompareTo) can.

What is NaN in Kotlin?

A constant holding the "not a number" value of Double.

How do you compare objects in Kotlin?

In Kotlin, == is the default way to compare two objects: it compares their values by calling equals under the hood. Thus, if equals is overridden in your class, you can safely compare its instances using ==. For reference comparison, you can use the === operator, which works exactly the same as == in Java.

How do I compare two classes in Kotlin?

Referential equality ('===') === operator is used to compare the reference of two variable or object. It will only be true if both the objects or variables pointing to the same object. The negated counterpart of === in Kotlin is !== which is used to compare if both the values are not equal to each other.


1 Answers

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 Doubles, 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(...).

like image 194
hotkey Avatar answered Sep 24 '22 23:09

hotkey