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

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

запуск вышеуказанного кода дает:

1: false
2: true
3: true

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

как можно объяснить такое поведение? В чем заключается его обоснование?

2 ответов


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

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

если аргумент 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);

использует двойной.равно:

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

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

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