1. Общ преглед
Най-просто казано, NaN е числова стойност на типа данни, която означава „не число“.
В този бърз урок ще обясним стойността на NaN в Java и различните операции, които могат да произведат или да включват тази стойност.
2. Какво е NaN ?
NaN обикновено показва резултата от невалидни операции. Например опит за разделяне на нула на нула е една такава операция.
Също така използваме NaN за непредставими стойности. Квадратният корен от -1 е един такъв случай, тъй като можем да опишем стойността ( i ) само в комплексни числа.
Стандартът IEEE за аритметика с плаваща запетая (IEEE 754) определя стойността на NaN . В Java типовете с плаваща запетая плават и удвояват този стандарт.
Java определя NaN константи от флоат и двойни типове като Float .NaN и Double.NaN :
„ Константа, съдържаща стойност без число (NaN) от тип double. Тя е еквивалентна на стойността, върната от Double.longBitsToDouble (0x7ff8000000000000L). "
и:
„Константа, съдържаща стойност без число (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 NaN = " + (NAN > NAN)); System.out.println("NaN < NaN = " + (NAN < NAN)); System.out.println("NaN != NaN = " + (NAN != NAN));
Нека да разгледаме резултата от изпълнението на горния код:
NaN == 1 = false NaN > 1 = false NaN NaN = false NaN < NaN = false NaN != NaN = true
Следователно не можем да проверяваме за NaN, като сравняваме с NaN, използвайки „==“ или „! =“. Всъщност рядко трябва да използваме оператори „==” или „! =” С флоат или двойни типове.
Вместо това можем да използваме израза „ 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
Докато правим операции, включващи флоат и двойни типове, трябва да сме наясно със стойностите на 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 на двойни или плаващи променливи от тип. Вместо това можем изрично да присвоим NaN на такива променливи, за да посочим липсващи или неизвестни стойности:
double maxValue = Double.NaN;
5. Заключение
В тази статия обсъдихме NaN и различните операции, свързани с него. Също така обсъдихме необходимостта от обработка на NaN, докато правим изчислявания с плаваща запетая в Java изрично.
Пълният изходен код може да бъде намерен в GitHub.