Pourquoi Double.NaN == Double.NaN renvoie false?

Je ne faisais qu’étudier les questions de l’OCPJP et j’ai trouvé ce code étrange:

public static void main(Ssortingng a[]) { System.out.println(Double.NaN==Double.NaN); System.out.println(Double.NaN!=Double.NaN); } 

Quand j’ai couru le code, j’ai eu:

 false true 

Comment la sortie est-elle false quand on compare deux choses qui se ressemblent? Que signifie NaN ?

NaN signifie “Pas un numéro”.

La troisième édition de Java Language Specification (JLS) dit :

Une opération qui déborde produit une infinité signée, une opération qui déborde produit une valeur dénormalisée ou un zéro signé, et une opération sans résultat mathématiquement défini produit NaN. Toutes les opérations numériques avec NaN en tant qu’opérande produisent NaN. Comme cela a déjà été décrit, NaN n’est pas ordonné, donc une opération de comparaison numérique impliquant un ou deux NaN renvoie false et toute comparaison != Impliquant NaN renvoie true , y compris x!=x lorsque x est NaN.

NaN est par définition différent de tout nombre, y compris NaN. Cela fait partie de la norme IEEE 754 et est implémenté par le CPU / FPU. La JVM n’a pas à append de logique à la prise en charge.

http://en.wikipedia.org/wiki/NaN

Une comparaison avec un NaN renvoie toujours un résultat non ordonné même lorsque l’on compare avec lui-même. … Les prédicats d’égalité et d’inégalité ne signalent pas, donc x = x retournant false peut être utilisé pour tester si x est un NaN silencieux.

Java traite tout NaN comme un NaN silencieux.

Pourquoi cette logique

NaN signifie Not a Number . Qu’est-ce qu’un numéro? N’importe quoi. Vous pouvez avoir n’importe quoi dans un côté et n’importe quoi dans l’autre côté, donc rien ne garantit que les deux sont égaux. NaN est calculé avec Double.longBitsToDouble(0x7ff8000000000000L) et comme vous pouvez le voir dans la documentation de longBitsToDouble :

Si l’argument est une valeur dans la plage 0x7ff0000000000001L à 0x7fffffffffffffffL ou dans la plage 0xfff0000000000001L à 0xffffffffffffffffL , le résultat est un NaN .

De plus, NaN est traité logiquement dans l’API.


Documentation

 /** * A constant holding a Not-a-Number (NaN) value of type * {@code double}. It is equivalent to the value returned by * {@code Double.longBitsToDouble(0x7ff8000000000000L)}. */ public static final double NaN = 0.0d / 0.0; 

Au fait, NaN est testé comme votre exemple de code:

 /** * Returns {@code true} if the specified number is a * Not-a-Number (NaN) value, {@code false} otherwise. * * @param v the value to be tested. * @return {@code true} if the value of the argument is NaN; * {@code false} otherwise. */ static public boolean isNaN(double v) { return (v != v); } 

Solution

Ce que vous pouvez faire est d’utiliser compare / compareTo :

Double.NaN est considéré par cette méthode comme étant égal à lui-même et supérieur à toutes les autres valeurs double (y compris Double.POSITIVE_INFINITY ).

 Double.compare(Double.NaN, Double.NaN); Double.NaN.compareTo(Double.NaN); 

Ou, equals :

Si this et l’ argument représentent tous les deux Double.NaN , alors la méthode equals renvoie true , même si Double.NaN==Double.NaN a la valeur false .

 Double.NaN.equals(Double.NaN); 

Ce n’est peut-être pas une réponse directe à la question. Mais si vous voulez vérifier si quelque chose est égal à Double.NaN vous devriez utiliser ceci:

 double d = Double.NaN Double.isNaN(d); 

Cela retournera true

Le javadoc pour Double.NaN dit tout:

Une constante contenant une valeur Non-Number-Number (NaN) de type double . Il est équivalent à la valeur renvoyée par Double.longBitsToDouble(0x7ff8000000000000L) .

Fait intéressant, la source de Double définit NaN :

 public static final double NaN = 0.0d / 0.0; 

Le comportement spécial que vous décrivez est câblé dans la JVM.

NaN est une valeur spéciale qui dénote “pas un nombre”; c’est le résultat de certaines opérations arithmétiques invalides, telles que sqrt(-1) , et a la propriété (parfois agaçante) que NaN != NaN .

selon la norme IEEE pour l’arithmétique à virgule flottante pour les nombres à double précision,

La représentation standard à virgule flottante à double précision IEEE requirejs un mot de 64 bits, qui peut être représenté par un numéro de 0 à 63, de gauche à droite

entrer la description de l'image ici où,

 S: Sign – 1 bit E: Exponent – 11 bits F: Fraction – 52 bits 

Si E=2047 (tous les E sont 1 ) et F non nul, alors V=NaN (“Pas un nombre”)

Ce qui signifie,

Si tous les bits E sont 1 et s’il y a un bit non nul dans F le nombre est NaN .

par conséquent, entre autres, tous les numéros suivants sont NaN ,

 0 11111111 0000000000000000010000000000000000000000000000000000 = NaN 1 11111111 0000010000000000010001000000000000001000000000000000 = NaN 1 11111111 0000010000011000010001000000000000001000000000000000 = NaN 

En particulier, vous ne pouvez pas tester

 if (x == Double.NaN) 

vérifier si un résultat particulier est égal à Double.NaN , car toutes les valeurs «pas un nombre» sont considérées comme distinctes. Cependant, vous pouvez utiliser la méthode Double.isNaN :

 if (Double.isNaN(x)) // check whether x is "not a number" 

Pas un nombre représente le résultat des opérations dont le résultat n’est pas représentable avec un nombre. L’opération la plus célèbre est 0/0, dont le résultat n’est pas connu.

Pour cette raison, NaN n’est égal à rien (y compris d’autres valeurs non-nombre). Pour plus d’informations, consultez la page Wikipedia: http://en.wikipedia.org/wiki/NaN

Selon ce lien , il a différentes situations et difficile à retenir. C’est comme ça que je me souviens et que je les distingue. NaN signifie “mathématiquement indéfini” par exemple: “le résultat de 0 divisé par 0 est indéfini” et comme il n’est pas défini, “la comparaison avec undefined est bien sûr indéfinie”. De plus, cela fonctionne plus comme des prémisses mathématiques. Par contre, les infinis positifs et négatifs sont prédéfinis et définitifs, par exemple “le grand infini positif ou négatif est bien défini mathématiquement”.