Путаница на NaN в Java
int i = 0, j = 0;
double nan1 = (double)0/0;
double nan2 = (double)0/0;
double nan3 = (double)i/j;
System.out.println(Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits(nan2));
System.out.println(Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits((double)0/0));
System.out.println(Double.doubleToRawLongBits(nan3) == Double.doubleToRawLongBits(nan2));
выход:
true
true
false
Пожалуйста, помогите мне, как результат пришел true
для первых двух и false
для последнего. Скажите, пожалуйста, что такое фактическая работа метода Double.doubleToRawLongBits().
Ответы
Ответ 1
Попробуйте запустить следующий код, чтобы увидеть значения:
public class Test
{
public static void main(String[] args){
int i = 0, j = 0;
double nan1 = (double)0/0;
double nan2 = (double)0/0;
double nan3 = (double)i/j;
System.out.println(Double.doubleToRawLongBits(nan1) + " == "+ Double.doubleToRawLongBits(nan2) + " is " +
(Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits(nan2)));
System.out.println(Double.doubleToRawLongBits(nan1) + " == "+ Double.doubleToRawLongBits((double)0/0) + " is " +
(Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits((double)0/0)));
System.out.println(Double.doubleToRawLongBits(nan3) + " == "+ Double.doubleToRawLongBits(nan2) + " is " +
(Double.doubleToRawLongBits(nan3) == Double.doubleToRawLongBits(nan2)));
}
}
На моем Mac он производит следующий вывод:
9221120237041090560 == 9221120237041090560 is true
9221120237041090560 == 9221120237041090560 is true
-2251799813685248 == 9221120237041090560 is false
Эта ошибка описана в Javadoc для метода doubleToRawLongBits:
Если аргументом является NaN, результатом является длинное целое число, представляющее фактическое значение NaN. В отличие от метода doubleToLongBits, doubleToRawLongBits не сворачивает все битовые шаблоны, кодирующие NaN, в одно "каноническое" значение NaN.
Ответ 2
Стандарт IEEE 754 позволяет использовать различные шаблоны бит для NaN
. Для целей расчета и сравнения они должны работать одинаково (т.е. NaN
сравнивается не равным себе, не упорядочивается, и каждое вычисление с участием NaN
есть NaN
). С помощью doubleToRawLongBits
вы получите точный шаблон бит. Это также подробно описано в JLS:
По большей части платформа Java рассматривает значения NaN данного типа как хотя и рухнуло в единое каноническое значение (и, следовательно, эта спецификация, mally относится к произвольному NaN, как к каноническому значению). Однако версия 1.3 платформа Java представила методы, позволяющие программисту различать между значениями NaN: методами Float.floatToRawIntBits
и Double.double-
ToRawLongBits
. Заинтересованный читатель относится к спецификациям для классов Float
и Double
для получения дополнительной информации.
В вашем случае бит знака отличается, в этом случае я могу направить вас на Wikipedia, в котором кратко сказано это:
В стандартах IEEE 754, соответствующих форматам хранения с плавающей запятой, NaN определяются конкретными заранее определенными битовыми шаблонами, уникальными для NaN. Знак бит не имеет значения.
Оба значения NaN
, они просто используют разные биты для представления этого. Что-то, что позволяет IEEE 754, и в этом случае, вероятно, связано с компилятором, подставляющим Double.NaN
для постоянного вычисления, которое приводит к NaN
, в то время как фактическое оборудование дает другой результат, как подозревается Mystical в комментарии к вопросу уже.
Ответ 3
Я думаю, что Java следует за IEEE 754. В этом случае NaN имеет более одного возможного представления битов. Два представления в вашем случае отличаются бит "знака". Значение знакового бита, по-видимому, не определяется стандартом и обычно игнорируется. Поэтому оба значения верны. См. http://en.wikipedia.org/wiki/NaN
Ответ 4
Причина в том, что когда вы делите двойную переменную 0 на 0, она возвращает NaN, поэтому метод не имеет одного канонического представления в двоичном формате, поэтому он может возвращать двоичный файл NaN как 7F F8 00 00 00 00 00 или FF F8 00 00 00 00 00 00.
Хотя технически они представляют одно и то же, что является NaN, оно отличается от двоичного представления.