NaN en Java

1. Vue d'ensemble

En termes simples, NaN est une valeur de type de données numérique qui signifie «pas un nombre».

Dans ce rapide tutoriel, nous expliquerons la valeur NaN en Java et les différentes opérations qui peuvent produire ou impliquer cette valeur.

2. Qu'est-ce que NaN ?

NaN indique généralement le résultat d'opérations non valides. Par exemple, tenter de diviser zéro par zéro est l'une de ces opérations.

Nous utilisons également NaN pour les valeurs non représentables. La racine carrée de -1 est un tel cas, car nous ne pouvons décrire la valeur ( i ) que dans des nombres complexes.

La norme IEEE pour l'arithmétique à virgule flottante (IEEE 754) définit la valeur NaN . En Java, les types à virgule flottante float et double implémentent cette norme.

Java définit les constantes NaN des types float et double comme Float .NaN et Double.NaN :

« Une constante contenant une valeur Not-a-Number (NaN) de type double. Il équivaut à la valeur renvoyée par Double.longBitsToDouble (0x7ff8000000000000L). »

et:

«Une constante contenant une valeur Not-a-Number (NaN) de type float. Il équivaut à la valeur renvoyée par Float.intBitsToFloat (0x7fc00000). »

Nous n'avons pas ce type de constantes pour les autres types de données numériques en Java.

3. Comparaisons avec NaN

Lors de l'écriture de méthodes en Java, nous devons vérifier que l'entrée est valide et dans la plage attendue. La valeur NaN n'est pas une entrée valide dans la plupart des cas. Par conséquent, nous devons vérifier que la valeur d'entrée n'est pas une valeur NaN et gérer ces valeurs d'entrée de manière appropriée.

NaN ne peut être comparé à aucune valeur de type flottant. Cela signifie que nous obtiendrons false pour toutes les opérations de comparaison impliquant NaN (sauf «! =» Pour lequel nous obtenons true ).

On devient vrai pour « x! = X» si et seulement si x est 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)); 

Jetons un coup d'œil au résultat de l'exécution du code ci-dessus:

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

Par conséquent, nous ne pouvons pas vérifier NaN en comparant avec NaN en utilisant «==» ou «! =». En fait, nous devrions rarement utiliser les opérateurs «==» ou «! =» Avec des types float ou double .

Au lieu de cela, nous pouvons utiliser l'expression « x! = x » . Cette expression renvoie vrai uniquement pour NAN.

Nous pouvons également utiliser les méthodes Float.isNaN et Double.isNaN pour vérifier ces valeurs . C'est l'approche préférée car elle est plus lisible et compréhensible:

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

Nous obtiendrons le résultat suivant lors de l'exécution de ce code:

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

4. Opérations produisant du NaN

Lors des opérations impliquant des types float et double , nous devons être conscients des valeurs NaN .

Certaines méthodes et opérations à virgule flottante produisent des valeurs NaN au lieu de lever une exception. Nous pouvons avoir besoin de traiter ces résultats de manière explicite.

Les opérations numériques mathématiquement indéfinies sont un cas courant résultant en des valeurs non numériques :

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

Ces exemples donnent le résultat suivant:

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

Les opérations numériques qui n'ont pas de résultats en nombres réels produisent également NaN:

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

Ces déclarations entraîneront:

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

Toutes les opérations numériques avec NaN comme opérande produisent NaN comme résultat:

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

Et le résultat de ce qui précède est:

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

Enfin, nous ne pouvons pas affecter null aux variables de type double ou float . Au lieu de cela, nous pouvons explicitement attribuer NaN à ces variables pour indiquer des valeurs manquantes ou inconnues:

double maxValue = Double.NaN;

5. Conclusion

Dans cet article, nous avons discuté de NaN et des différentes opérations qui le concernent. Nous avons également discuté de la nécessité de gérer NaN tout en effectuant des calculs en virgule flottante en Java de manière explicite.

Le code source complet est disponible à l'adresse over sur GitHub.