J'étudiais juste les questions de l'OCPJP et j'ai trouvé cet étrange code:
public static void main(String a[]) {
System.out.println(Double.NaN==Double.NaN);
System.out.println(Double.NaN!=Double.NaN);
}
Quand j'ai exécuté le code, j'ai eu:
false
true
Comment la sortie false
lorsque nous comparons deux éléments qui se ressemblent? Que signifie NaN
?
NaN signifie "pas un nombre".
La troisième édition de la spécification du langage Java (JLS) dit :
Une opération qui déborde génère un infini signé, une opération qui déborde génère une valeur dénormalisée ou un zéro signé et une opération qui n’a pas de résultat mathématiquement défini produit NaN. En conséquence, 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é. Par conséquent, une opération de comparaison numérique impliquant un ou deux NaNs renvoie
false
et toute comparaison!=
impliquant NaN renvoietrue
, y comprisx!=x
lorsquex
est NaN.
NaN n'est par définition égal à aucun nombre, y compris NaN. Cela fait partie de la norme IEEE 754 et est implémenté par la CPU/FPU. La JVM n’a pas à ajouter de logique à prendre en charge.
http://en.wikipedia.org/wiki/NaN
Une comparaison avec un NaN renvoie toujours un résultat non ordonné, même en comparant avec lui-même. ... Les prédicats d'égalité et d'inégalité ne signalant pas, x = x retournant false peut être utilisé pour tester si x est un NaN silencieux.
Java traite tous les NaN comme des NaN silencieux.
Pourquoi cette logique
NaN
signifie Not a Number
. Qu'est-ce qui n'est pas un nombre? 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 constater dans la documentation de longBitsToDouble
:
Si l'argument est une valeur comprise entre
0x7ff0000000000001L
et0x7fffffffffffffffL
ou dans la plage0xfff0000000000001L
à0xffffffffffffffffL
, le résultat est uneNaN
.
De plus, NaN
est traité logiquement à l'intérieur de 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
is a été testé comme 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 valeursdouble
(y comprisDouble.POSITIVE_INFINITY
).
Double.compare(Double.NaN, Double.NaN);
Double.NaN.compareTo(Double.NaN);
Ou equals
:
Si
this
etargument
représentent tous deuxDouble.NaN
, alors la méthodeequals
renvoietrue
, même siDouble.NaN==Double.NaN
a la valeurfalse
.
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 vaut 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 de type
double
(NaN) non notée Cela équivaut à la valeur renvoyée parDouble.longBitsToDouble(0x7ff8000000000000L)
.
Fait intéressant, la source de Double
définit NaN
ainsi:
public static final double NaN = 0.0d / 0.0;
Le comportement spécial que vous décrivez est câblé dans la machine virtuelle Java.
NaN est une valeur spéciale qui indique "pas un nombre"; il résulte de certaines opérations arithmétiques non valides, telles que sqrt(-1)
, et possède la propriété (parfois gênante) qui NaN != NaN
.
selon, La norme IEEE pour l’arithmétique en virgule flottante pour les nombres à double précision,
Représentation standard à virgule flottante double précision IEEE nécessite un mot de 64 bits, qui peut être représenté par un numéro numéroté de 0 à 63, de gauche à droite
où,
S: Sign – 1 bit
E: Exponent – 11 bits
F: Fraction – 52 bits
Si
E=2047
(tous lesE
sont1
) et queF
est différent de zéro, alorsV=NaN
("Pas un nombre")
Ce qui signifie,
Si tous les bits E
sont à 1 et s'il existe un bit différent de zéro dans F
, le nombre est NaN
.
par conséquent, entre autres, tous les nombres 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 d'opérations dont le résultat n'est pas représentable par un nombre. L'opération la plus connue est 0/0, dont le résultat n'est pas connu.
Pour cette raison, NaN n'est égal à rien (y compris les autres valeurs non numériques). Pour plus d’informations, consultez la page wikipedia: http://en.wikipedia.org/wiki/NaN
Selon ce lien , il a des situations diverses et difficiles à retenir. C'est comme ça que je me souviens et les distingue. NaN
signifie "mathématiquement indéfini", par exemple: "le résultat de 0 divisé par 0 est indéfini" et comme il est indéfini, la comparaison avec indéfini est bien sûr indéfinie ". En outre, cela fonctionne plus comme des prémisses mathématiques. D'autre part, l'infini positif et négatif est prédéfini et définitif, par exemple, "l'infini positif positif ou négatif est mathématiquement bien défini".