Почему Double.NaN == Double.NaN возвращает false?

Я просто изучал вопросы OCPJP, и я нашел этот странный код:

public static void main(String a[]) {
    System.out.println(Double.NaN==Double.NaN);
    System.out.println(Double.NaN!=Double.NaN);
}

Когда я запустил код, я получил:

false
true

Как вывод false, когда мы сравниваем две вещи, которые выглядят одинаково друг с другом? Что означает NaN?

Ответ 1

NaN означает "Не номер".

Третье издание Java Language Specification (JLS) гласит:

Операция, которая переполняет, создает подписанную бесконечность, операция, которая выполняется под потоком, создает денормализованное значение или подписанный нуль, а операция, которая не имеет математически определенного результата, дает NaN. В результате числовые операции с NaN в качестве операнда дают NaN. Как уже было описано, NaN неупорядочен, поэтому операция числового сравнения с участием одного или двух NaN возвращает false и любое сравнение !=, включающее NaN, возвращает true, включая x!=x, когда x является NaN.

Ответ 2

NaN по определению не равно любому числу, включая NaN. Это часть стандарта IEEE 754 и реализуется CPU/FPU. Это не то, что JVM должно добавить любую логику для поддержки.

http://en.wikipedia.org/wiki/NaN

Сравнение с NaN всегда возвращает неупорядоченный результат даже при сравнении с самим собой.... Предикаты равенства и неравенства не сигнализируют, так что x = x возвращение false может быть использовано для проверки, является ли x тихим NaN.

Java рассматривает все NaN как спокойные NaN.

Ответ 3

Почему эта логика

NaN означает Not a Number. Что не число? Что-нибудь. Вы можете иметь что-нибудь в одной стороне и что-нибудь в другой стороне, поэтому ничто не гарантирует, что оба они равны. NaN вычисляется с помощью Double.longBitsToDouble(0x7ff8000000000000L) и, как вы можете видеть в документации longBitsToDouble:

Если аргументом является любое значение в диапазоне 0x7ff0000000000001L через 0x7fffffffffffffffL или в диапазоне 0xfff0000000000001L через 0xffffffffffffffffL, результат равен NaN.

Кроме того, NaN логически обрабатывается внутри API.


Documentation

/** 
 * A constant holding a Not-a-Number (NaN) value of type
 * {@code double}. It is equivalent to the value returned by
 * {@code Double.longBitsToDouble(0x7ff8000000000000L)}.
 */
public static final double NaN = 0.0d / 0.0;

Кстати, NaN тестируется как образец кода:

/**
 * Returns {@code true} if the specified number is a
 * Not-a-Number (NaN) value, {@code false} otherwise.
 *
 * @param   v   the value to be tested.
 * @return  {@code true} if the value of the argument is NaN;
 *          {@code false} otherwise.
 */
static public boolean isNaN(double v) {
    return (v != v);
}

Решение

Что вы можете сделать, это использовать compare/compareTo:

Double.NaN считается этим методом равным себе и больше всех других значений double (включая Double.POSITIVE_INFINITY).

Double.compare(Double.NaN, Double.NaN);
Double.NaN.compareTo(Double.NaN);

Или, equals:

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

Double.NaN.equals(Double.NaN);

Ответ 4

javadoc для Double.NaN говорит все:

Постоянная, содержащая значение типа "не-номер" (NaN) типа double. Это эквивалентно значению, возвращаемому Double.longBitsToDouble(0x7ff8000000000000L).

Интересно, что источник для double определяет NaN таким образом:

public static final double NaN = 0.0d / 0.0;

Специальное поведение, которое вы описываете, жестко подключено к JVM.

Ответ 5

Это может быть не прямой ответ на вопрос. Но если вы хотите проверить, соответствует ли значение Double.NaN, вы должны использовать это:

double d = Double.NaN
Double.isNaN(d);

Это вернет true

Ответ 6

NaN - особое значение, обозначающее "не число"; это результат некоторых недействительных арифметических операций, таких как sqrt(-1), и имеет (иногда раздражающее) свойство NaN != NaN.

Ответ 7

Стандарт IEEE для арифметики с плавающей запятой для чисел с двойной точностью,

Стандартное представление с плавающей точкой с двойной точностью IEEE требует 64-битного слова, которое может быть представлено как пронумерованное от 0 до 63, слева направо

enter image description here где,

S: Sign – 1 bit
E: Exponent – 11 bits
F: Fraction – 52 bits 

Если E=2047 (все E являются 1), а F отличен от нуля, тогда V=NaN ( "Не число" )

Это означает, что

Если все биты E равны 1, и если в F есть ненулевой бит, то это число NaN.

поэтому, среди прочих, все следующие числа NaN,

0 11111111 0000000000000000010000000000000000000000000000000000 = NaN
1 11111111 0000010000000000010001000000000000001000000000000000 = NaN
1 11111111 0000010000011000010001000000000000001000000000000000 = NaN

В частности, вы не можете протестировать

if (x == Double.NaN) 

чтобы проверить, равен ли конкретный результат Double.NaN, потому что все значения "не числа" считаются отличными. Однако вы можете использовать метод Double.isNaN:

if (Double.isNaN(x)) // check whether x is "not a number"

Ответ 8

Не число представляет результат операций, результат которых не представляется числом с номером. Самая известная операция - 0/0, результат которой неизвестен.

По этой причине NaN не равно ничему (включая другие значения, отличные от числа). Для получения дополнительной информации просто просмотрите страницу wikipedia: http://en.wikipedia.org/wiki/NaN