Сравнение 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(...)
двух 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);
использует двойной.равно:
обратите внимание, что в большинстве случаев, для двух экземпляров
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
.