Сравнение NaN в Котлине

Поэтому я недавно начал любить язык kotlin. Сегодня, сравнивая двойники, я столкнулся с неизбежным 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)) } 

NB: ( Double – это подтип Number )

Выполнение приведенного выше кода дает:

 1: false 2: true 3: true 

Я понимаю, что сравнение с NaN в Java возвращает false , поэтому я ожидал бы false для всех выражений.

Как объяснить это поведение? В чем причина этого?

Это потому, что (2) и (3) скомпилированы для бокса примитива, а затем проверка Double.equals : на JVM примитивный double нельзя сравнивать с коробкой.

Double.equals , в свою очередь, проверяет равенство, сравнивая doubleToLongBits(...) двух Double s, а для последнего есть гарантия, что

Если аргументом является NaN, результат равен 0x7ff8000000000000L .

Итак, биты, возвращаемые для двух NaN , равны, а правило NaN != NaN здесь игнорируется.

Кроме того, как упоминал @miensol , есть еще одно следствие этой проверки равенства: +0 и -0 равны в соответствии с проверкой == а не equals проверке.

Эквивалентным кодом в Java будет:

 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)); 

Последние две строки вызывают Double.equals , сравнивая doubleToLongBits(...) .

Первое сравнение эквивалентно Java:

 double left = Double.NaN; double right = Double.NaN; boolean result = left == right; 

И, как вы можете прочитать в этом ответе, это стандартизованное и документированное поведение.

Второе и третье сравнение эквивалентны:

 Double left = Double.valueOf(Double.NaN); Number right = Double.valueOf(Double.NaN); boolean result = left.equals(right); 

Что использует Double.equals :

Обратите внимание, что в большинстве случаев для двух экземпляров class Double , d1 и d2 значение d1.equals(d2) истинно тогда и только тогда, когда d1.doubleValue() == d2.doubleValue() также имеет значение true. Однако есть два исключения:

  • Если d1 и d2 оба представляют Double.NaN , то метод equals возвращает true , хотя Double.NaN==Double.NaN имеет значение false .

  • Если d1 представляет +0.0 тогда как d2 представляет -0.0 , или наоборот, равный тест имеет значение false , хотя значение +0.0==-0.0 имеет значение true .

Intereting Posts