it-swarm.com.ru

Почему 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?

148
Maverick

NaN означает «не число».

Третье издание спецификации языка Java (JLS) гласит :

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

134
Adrian Mitev

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

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

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

Ява рассматривает весь NaN как тихий NaN.

60
Peter Lawrey

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

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

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

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


Документация

/** 
 * 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;

Кстати, NaNis протестирован как пример кода:

/**
 * 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);
48
falsarella

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

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

Это вернет true

11
JREN

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

Константа, содержащая значение Not-a-Number (NaN) типа double. Это эквивалентно значению, возвращенному функцией Double.longBitsToDouble(0x7ff8000000000000L).

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

public static final double NaN = 0.0d / 0.0;

Особое поведение, которое вы описываете, встроено в JVM.

6
Bohemian

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

3
Fred Foo

согласно, стандарт 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"
3
Sufiyan Ghori

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

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

2
Matteo

Согласно этой ссылке , он имеет различные ситуации и трудно запомнить. Вот как я их помню и различаю. NaN означает «математически не определено», например: «результат 0, деленный на 0, не определен», и поскольку он не определен, то «сравнение, связанное с неопределенным, конечно, не определено». Кроме того, это больше похоже на математические предпосылки. С другой стороны, как положительная, так и отрицательная бесконечность предопределены и окончательны, например, «положительное или отрицательное бесконечно большое хорошо определено математически». 

0
Tiina