NaN in Java

1. Panoramica

In poche parole, NaN è un valore del tipo di dati numerico che sta per "non un numero".

In questo rapido tutorial, spiegheremo il valore NaN in Java e le varie operazioni che possono produrre o coinvolgere questo valore.

2. Che cos'è NaN ?

NaN di solito indica il risultato di operazioni non valide. Ad esempio, il tentativo di dividere zero per zero è una di queste operazioni.

Usiamo anche NaN per valori non rappresentabili. La radice quadrata di -1 è uno di questi casi, poiché possiamo descrivere il valore ( i ) solo in numeri complessi.

Lo standard IEEE per l'aritmetica in virgola mobile (IEEE 754) definisce il valore NaN . In Java, i tipi a virgola mobile float e double implementano questo standard.

Java definisce le costanti NaN di entrambi i tipi float e double come Float .NaN e Double.NaN :

Una costante che contiene un valore Non numerico (NaN) di tipo double. È equivalente al valore restituito da Double.longBitsToDouble (0x7ff8000000000000L). "

e:

“Una costante che contiene un valore non numerico (NaN) di tipo float. È equivalente al valore restituito da Float.intBitsToFloat (0x7fc00000). "

Non abbiamo questo tipo di costanti per altri tipi di dati numerici in Java.

3. Confronti con NaN

Durante la scrittura di metodi in Java, dovremmo verificare che l'input sia valido e all'interno dell'intervallo previsto. Il valore NaN non è un input valido nella maggior parte dei casi. Pertanto, dovremmo verificare che il valore di input non sia un valore NaN e gestire questi valori di input in modo appropriato.

NaN non può essere confrontato con alcun valore di tipo floating. Ciò significa che otterremo false per tutte le operazioni di confronto che coinvolgono NaN (eccetto "! =" Per cui diventiamo true ).

Diventiamo vero per " x! = X" se e solo se 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)); 

Diamo un'occhiata al risultato dell'esecuzione del codice sopra:

NaN == 1 = false NaN > 1 = false NaN  NaN = false NaN < NaN = false NaN != NaN = true 

Quindi, non possiamo controllare NaN confrontandolo con NaN utilizzando "==" o "! =". In effetti, dovremmo usare raramente gli operatori "==" o "! =" Con i tipi float o double .

Invece, possiamo usare l'espressione " x! = x " . Questa espressione restituisce true solo per NAN.

Possiamo anche usare i metodi Float.isNaN e Double.isNaN per verificare questi valori . Questo è l'approccio preferito in quanto è più leggibile e comprensibile:

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))); 

Otterremo il seguente risultato quando eseguiremo questo codice:

1.0 is NaN = false 1.0 is NaN = false NaN is NaN = true NaN is NaN = true

4. Operazioni che producono NaN

Durante le operazioni che coinvolgono i tipi float e double , dobbiamo essere consapevoli dei valori NaN .

Alcuni metodi e operazioni a virgola mobile producono valori NaN invece di generare un'eccezione . Potrebbe essere necessario gestire tali risultati in modo esplicito.

Un caso comune che risulta in valori non numerici sono operazioni numeriche matematicamente indefinite :

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)); 

Questi esempi producono il seguente output:

ZERO / ZERO = NaN INFINITY - INFINITY = NaN INFINITY * ZERO = NaN 

Anche le operazioni numeriche che non hanno risultati in numeri reali producono NaN:

System.out.println("SQUARE ROOT OF -1 = " + Math.sqrt(-1)); System.out.println("LOG OF -1 = " + Math.log(-1)); 

Queste dichiarazioni risulteranno in:

SQUARE ROOT OF -1 = NaN LOG OF -1 = NaN 

Tutte le operazioni numeriche con NaN come operando producono NaN come risultato:

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)); 

E il risultato di quanto sopra è:

2 + NaN = NaN 2 - NaN = NaN 2 * NaN = NaN 2 / NaN = NaN 

Infine, non possiamo assegnare null a variabili di tipo double o float . Invece, possiamo assegnare esplicitamente NaN a tali variabili per indicare valori mancanti o sconosciuti:

double maxValue = Double.NaN;

5. conclusione

In questo articolo abbiamo discusso di NaN e delle varie operazioni che lo coinvolgono. Abbiamo anche discusso la necessità di gestire NaN durante l'esecuzione di calcoli in virgola mobile in Java in modo esplicito.

Il codice sorgente completo può essere trovato su GitHub.