Почему 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, слева направо
где,
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