W Javie „NaN” oznacza „Not a Number”. Nie jest to typ wyjątku, raczej zaskakująco, typ danych NaN jest również liczbą. Ale często, gdy początkujący programiści dostają go nieumyślnie, używają go dalej w swoich obliczeniach. W związku z tym niekompatybilne typy danych w Javie, gdy są używane razem, mogą powodować zgłaszany błąd. Powszechnie uważa się również, że java.lang.ArithmeticException: / by zerojest uważany za taki sam jak NaN. Jednak Java traktuje je oba inaczej. Wystarczająco zastanawiające? Aby uzyskać kompleksowe zrozumienie, przeanalizujemy, w jaki sposób różnią się one od siebie. Pod koniec tego artykułu dowiesz się o możliwych operacjach generujących nie liczbę (nan) i kilku prostych sposobach radzenia sobie z tym.

Co to jest NaN?

Czym więc jest NaN? „NaN”, jak wielu z was się domyśliło, jest używane do reprezentowania „Not a Number” w Javie. Jest to specjalna wartość zmiennoprzecinkowa do oznaczania przepełnień i błędów. Jest generowany, gdy liczba zmiennoprzecinkowa jest dzielona przez zero lub gdy obliczany jest pierwiastek kwadratowy z liczby ujemnej. NaN w Javie - 1Na przykład spójrz na poniższy fragment.

public class NaN
{
    public static void main(String[]args)
    {
        System.out.println(0.0 / 0.0);	  //zero divided by zero
        System.out.println(Math.sqrt(-1)); //take sqrt of negative number
        System.out.println(10.0 % 0);      //taking mod by zero	
    }
}
Wyjście

NaN                                                                                                                                           
NaN                                                                                                                                           
NaN
W powyższym fragmencie można zaobserwować, że NaN powstaje w wyniku 3 prostych operacji:
  • Dzielenie float / doublezera przez zero.
  • Biorąc pod pierwiastek z liczby ujemnej (Math.sqrt(-x)). W matematyce pierwiastek kwadratowy z liczby ujemnej daje liczbę urojoną . Ten przypadek jest rozwiązywany przez zwrócenie NaN w Javie.
  • Biorąc mod liczby z zerem, zwróci resztę po podzieleniu wartości przez zero. Dlatego NaN jest zwracane.

Czym NaN różni się od dodatniej i ujemnej nieskończoności?

Zgodnie ze specyfikacją IEEE 754 istnieją trzy specjalne wartości zmiennoprzecinkowe i podwójne do obsługi przypadków granicznych:
  • Pozytywna nieskończoność
  • Ujemna nieskończoność
  • NaN
Wynikiem dzielenia liczby dodatniej przez 0 jest dodatnia nieskończoność. Podobnie ujemna nieskończoność daje wynik dzielenia liczby ujemnej przez zero. Należy pamiętać, że wszystkie wartości zmiennoprzecinkowe mają również zastosowanie do typu danych double. Ograniczona precyzja pływaków jest czasami niewystarczająca. Jednak zobaczymy, jak NaN działa zarówno dla float, jak i double w dalszej części.

Czym jest metoda NaN()?

isNaN()jest jedną z podstawowych metod w Javie, aby sprawdzić, czy jest to wartość NaN, czy nie. Jak omówiliśmy powyżej trzy przypadki, nadszedł czas, aby przetestować, w jaki sposób metoda isNaN() rozróżnia wartości +infinity , -infinity i NaN.

public class isNaN
{ public static void main(String[]args)
  { 
    Double posInfinity = +2.0 / 0.0;
    Double negInfinity = -3.5 / 0.0;
    Double nanVal = 50 % 0.0;


    System.out.println ("+" + posInfinity + ".IsNaN() = " + posInfinity.isNaN());
    System.out.println ( negInfinity + ".IsNaN() = " + negInfinity.isNaN());
    System.out.println ( nanVal +  ".IsNaN() = " + nanVal.isNaN());
  }
}
Wyjście

+Infinity.IsNaN() = false                                                                                                                       
-Infinity.IsNaN() = false                                                                                                                       
NaN.IsNaN() = true

Jak porównać wartości NaN?

Każda wartość NaN jest uważana za odrębną. Oznacza to, że żaden pojedynczy NaN nie jest równy żadnemu innemu NaN. Zgodnie z tą zasadą, jeśli porównasz jedną wartość z drugą, wynik jest zawsze ujemny. Ponieważ NaN jest nieuporządkowany, więc porównanie numeryczne obejmujące nawet pojedynczy NaN zwraca wartość false. Java udostępnia Float.NaN i Double.NaN dla pól stałych w obu klasach w celu przeprowadzenia porównań. Możemy je rozróżnić w dwóch oddzielnych scenariuszach:
  • Prawda: Tylko w przypadku równości (!=)
  • Fałsz: dla wszystkich operandów porównania (==, <=, >=, <, >)
Oto działający przykład dla was:

public class ComparingNaN
{ public static void main(String[] args)                                                                                                     
  {
    // Comparing NaN values for Float constants
    System.out.println (Float.NaN != Float.NaN); // true
    System.out.println (Float.NaN == Float.NaN); // false
    System.out.println (Float.NaN < Float.NaN);  // false
    System.out.println (Float.NaN > Float.NaN);  // false
    System.out.println (Float.NaN <= Float.NaN); // false
    System.out.println (Float.NaN >= Float.NaN); // false

    // Comparing NaN values for Float constants
    System.out.println (Double.NaN != Double.NaN); // true
    System.out.println (Double.NaN == Double.NaN); // false
    System.out.println (Double.NaN < Double.NaN);  // false
    System.out.println (Double.NaN > Double.NaN);  // false
    System.out.println (Double.NaN <= Double.NaN); // false
    System.out.println (Double.NaN >= Double.NaN); // false
  }
}

Jak wygenerować wartości NaN?

Zanim zakończymy, spójrzmy na kilka typowych przykładów uzyskania Not a Number (nan).

public class GenerateNaNValues {  
  static final float ZERO = 0;
  public static void main (String[]args)
  {
    System.out.println("ZERO / ZERO = " + (ZERO / ZERO));
    System.out.println("+INFINITY - INFINITY = " + 
    (Float.POSITIVE_INFINITY + Float.NEGATIVE_INFINITY));
    System.out.println("-INFINITY * ZERO = " + (Float.NEGATIVE_INFINITY * ZERO));
    System.out.println("+INFINITY * ZERO = " + (Float.POSITIVE_INFINITY * ZERO));
    System.out.println("log10(-10) = " +  Math.log(-10));
    System.out.println("√-10 = " + Math.sqrt(-10));
    System.out.println("NaN + 10 = " + (Float.NaN + 10));
    System.out.println("NaN - 10 = " + (Float.NaN - 10));
    System.out.println("NaN * 10 = " + (Float.NaN * 10));
    System.out.println("NaN / 10 = " + (Float.NaN / 10));
    System.out.println("NaN + NaN = " + (Float.NaN + Float.NaN));
    System.out.println("NaN - NaN = " + (Float.NaN - Float.NaN));
    System.out.println("NaN * NaN = " + (Float.NaN * Float.NaN));
    System.out.println("NaN / NaN = " + (Float.NaN / Float.NaN));
  }
}
Wyjście:

ZERO / ZERO = NaN                                                                                                                               
+INFINITY - INFINITY = NaN                                                                                                                      
-INFINITY * ZERO = NaN                                                                                                                          
+INFINITY * ZERO = NaN                                                                                                                          
log10(-10) = NaN                                                                                                                                
√-10 = NaN                                                                                                                                      
NaN + 10 = NaN                                                                                                                                    
NaN - 10 = NaN                                                                                                                                  
NaN * 10 = NaN                                                                                                                                  
NaN / 10 = NaN                                                                                                                                  
NaN + NaN = NaN                                                                                                                                 
NaN - NaN = NaN                                                                                                                                 
NaN * NaN = NaN                                                                                                                                 
NaN / NaN = NaN

Wniosek

Po przyjrzeniu się licznym operacjom prowadzącym do produkcji NaN, musisz być już z tym zaznajomiony. Na początku może cię to zdziwić, ale nie ma w tym nic skomplikowanego. Rozwijając mały nawyk sprawdzania, czy wartość nie jest NaN w obliczeniach podwójnych/zmiennoprzecinkowych, można zaoszczędzić wielu kłopotów. Nawet jeśli na początku o tym zapomnisz, wszystko jest w porządku. Zawsze możesz zapoznać się z tym artykułem w celu rozwiązania drobnych problemów. Tworzenie kompilowalnego, bezbłędnego kodu za jednym razem jest efektem wieloletniego doświadczenia. Ubrudźmy więc sobie ręce kodem i zbudujmy coś wspaniałego!