Сравнение 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.