1. Обзор
Проще говоря, NaN
— это числовое значение типа данных, которое означает «не число».
В этом кратком руководстве мы объясним значение NaN
в Java и различные операции, которые могут создавать или использовать это значение.
2. Что такое NaN
?
NaN
обычно указывает на результат недопустимых операций. Например, попытка разделить ноль на ноль является одной из таких операций.
Мы также используем NaN
для непредставимых значений. Квадратный корень из -1 является одним из таких случаев, поскольку мы можем описать значение ( i
) только комплексными числами.
Стандарт IEEE для арифметики с плавающей запятой (IEEE 754) определяет значение NaN
. В Java этот стандарт реализуют типы с плавающей запятой float
и double .
Java определяет константы NaN для типов
float
и double
как Float
.NaN и Double.NaN
:
“ Константа, содержащая значение Not-a-Number (NaN) типа double. Это эквивалентно значению, возвращаемому Double.longBitsToDouble(0x7ff8000000000000L)».
а также:
«Константа, содержащая значение Not-a-Number (NaN) типа float. Это эквивалентно значению, возвращаемому Float.intBitsToFloat(0x7fc00000)».
У нас нет такого типа констант для других числовых типов данных в Java.
3. Сравнение с NaN
При написании методов на Java мы должны проверять, что ввод действителен и находится в ожидаемом диапазоне. Значение NaN
не является допустимым входом в большинстве случаев. Поэтому мы должны убедиться, что входное значение не является значением NaN
, и соответствующим образом обработать эти входные значения.
NaN
нельзя сравнивать ни с каким значением плавающего типа. Это означает, что мы получим false
для всех операций сравнения, включающих NaN
(кроме «!=», для которого мы получаем true
).
Мы получаем истину
для « x != x»
тогда и только тогда , когда x
равно NaN:
System.out.println("NaN == 1 = " + (NAN == 1));
System.out.println("NaN > 1 = " + (NAN > 1));
System.out.println("NaN < 1 = " + (NAN < 1));
System.out.println("NaN != 1 = " + (NAN != 1));
System.out.println("NaN == NaN = " + (NAN == NAN));
System.out.println("NaN > NaN = " + (NAN > NAN));
System.out.println("NaN < NaN = " + (NAN < NAN));
System.out.println("NaN != NaN = " + (NAN != NAN));
Давайте посмотрим на результат выполнения кода выше:
NaN == 1 = false
NaN > 1 = false
NaN < 1 = false
NaN != 1 = true
NaN == NaN = false
NaN > NaN = false
NaN < NaN = false
NaN != NaN = true
Следовательно, мы не можем проверить наличие NaN
, сравнивая с NaN
с помощью «==» или «!=». На самом деле нам следует редко использовать операторы «==» или «!=» с типами float
или double .
Вместо этого мы можем использовать выражение « x !
= х» .
Это выражение возвращает true только для NAN.
Мы также можем использовать методы Float.isNaN
и Double.isNaN
для проверки этих значений .
Это предпочтительный подход, поскольку он более читаем и понятен:
double x = 1;
System.out.println(x + " is NaN = " + (x != x));
System.out.println(x + " is NaN = " + (Double.isNaN(x)));
x = Double.NaN;
System.out.println(x + " is NaN = " + (x != x));
System.out.println(x + " is NaN = " + (Double.isNaN(x)));
При запуске этого кода мы получим следующий результат:
1.0 is NaN = false
1.0 is NaN = false
NaN is NaN = true
NaN is NaN = true
4. Операции, производящие NaN
При выполнении операций с типами float
и double
нам нужно знать о значениях NaN
.
Некоторые методы и операции с плавающей запятой производят значения NaN
вместо создания исключения.
Нам может понадобиться явно обрабатывать такие результаты.
Распространенным случаем, приводящим к нечисловым значениям, являются математически неопределенные числовые операции :
double ZERO = 0;
System.out.println("ZERO / ZERO = " + (ZERO / ZERO));
System.out.println("INFINITY - INFINITY = " +
(Double.POSITIVE_INFINITY - Double.POSITIVE_INFINITY));
System.out.println("INFINITY * ZERO = " + (Double.POSITIVE_INFINITY * ZERO));
Эти примеры приводят к следующему результату:
ZERO / ZERO = NaN
INFINITY - INFINITY = NaN
INFINITY * ZERO = NaN
Числовые операции, которые не дают результатов в действительных числах, также производят NaN:
System.out.println("SQUARE ROOT OF -1 = " + Math.sqrt(-1));
System.out.println("LOG OF -1 = " + Math.log(-1));
Эти заявления приведут к:
SQUARE ROOT OF -1 = NaN
LOG OF -1 = NaN
Все числовые операции с NaN
в качестве операнда дают в результате NaN
:
System.out.println("2 + NaN = " + (2 + Double.NaN));
System.out.println("2 - NaN = " + (2 - Double.NaN));
System.out.println("2 * NaN = " + (2 * Double.NaN));
System.out.println("2 / NaN = " + (2 / Double.NaN));
И результат вышеизложенного:
2 + NaN = NaN
2 - NaN = NaN
2 * NaN = NaN
2 / NaN = NaN
Наконец, мы не можем присвоить null переменным
типа double
или float .
Вместо этого мы можем явно присвоить NaN
таким переменным, чтобы указать отсутствующие или неизвестные значения:
double maxValue = Double.NaN;
5. Вывод
В этой статье мы обсудили NaN
и различные связанные с ним операции. Мы также обсудили необходимость обработки NaN
при явном выполнении вычислений с плавающей запятой в Java.
Полный исходный код можно найти на GitHub .