Double.NaN - comment fonctionne cette fonction contre-intuitif?
Question
Je suis tombé sur la définition de .NET de double.NaN
dans le code suivant:
public const double NaN = (double)0.0 / (double)0.0;
Ceci est fait de la même dans PositiveInfinity
et NegativeInfinity
.
double.IsNaN
(avec suppression de quelques #pragmas et les commentaires) est défini comme:
[Pure]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static bool IsNaN(double d)
{
if (d != d)
{
return true;
}
else
{
return false;
}
}
Ceci est très contre-intuitif pour moi.
Pourquoi est-NaN définie comme la division par zéro? Comment est 0.0 / 0.0
représenté « dans les coulisses »? Comment la division peut par 0 être possible double
, et pourquoi NaN != NaN
?
La solution
réponse assez simple ici. NET Framework a mis en œuvre la norme à virgule flottante spécifiée par la norme IEEE (System.Double
est conforme à la norme IEC 60559: 1989 ( IEEE 754) de série binaire arithmétique à virgule flottante.) . En effet, l'arithmétique en virgule flottante a fait travailler dans de nombreux systèmes, et non pas seulement x86 / 64 architectures, en suivant les conventions ce qui garantit qu'il y aura moins de problèmes de compatibilité (par exemple le code portage d'un DSP dans un processeur x86).
En ce qui concerne le d! = D, ceci est une optimisation des performances. Fondamentalement, cette instruction repose sur une instruction matérielle qui peut très rapidement déterminer si deux nombres à virgule flottante double sont égaux. En vertu de la norme, NAN! = NAN et est donc le meilleur moyen de test. Essayer de trouver une référence pour vous.
Autres conseils
Pourquoi est-NaN définie comme division par zéro? Comment la division peut par 0 soit possible en double, et pourquoi NaN ! = NaN?
Tous ces sont mandatés par le IEEE 754 standard, ce qui à peu près tout le confort moderne mettre en œuvre des CPU.
Comment est 0,0 / 0,0 représentés « dans les coulisses »?
En ayant un exposant avec tous les bits mis à 1 et une mantisse d'au moins un bit mis à 1. On notera que cela signifie qu'il y a un grand nombre de différentes configurations de bits qui représentent tous NaN - mais, comme mentionné ci-dessus, même si les motifs de bits sont identiques, ils doivent être considérés comme différents (c.-à-faux == doit retourner).
De C # Spec:
14.9.2 opérateurs de comparaison à virgule flottante Les opérateurs de comparaison en virgule flottante sont prédéfinies:
opérateur booléen == (x float, float y); opérateur booléen == (double x, double y);
bool operator = (x float, float y!); bool operator = (double x, double y)!
opérateur booléen <(x flotteur, le flotteur y); opérateur booléen <(double x, double y);
opérateur booléen> (x float, float y); opérateur booléen> (double x, double y);
opérateur booléen <= (x float, float y); opérateur booléen <= de (double x, double y);
opérateur booléen> = (x float, float y); opérateur booléen> = (double x, double y);Les opérateurs comparent les opérandes selon les règles de la norme IEC 60559: Si l'un des opérandes est NaN, le résultat est faux pour tous les opérateurs, à l'exception! =, Dont le résultat est vrai. Pour tout deux opérandes, x! = Y produit toujours le même résultat que! (X = = y). Cependant, quand un ou les deux opérandes sont NaN, le <,>, <= et> = opérateurs ne produisent pas les mêmes résultats que la négation logique de l'opérateur inverse. [Exemple: Si l'un de x et y est NaN, alors x
= Y) est vrai. Exemple d'extrémité]
En ce qui concerne la façon dont NaN est représenté dans les coulisses, le wikipedia article sur l'IEEE spec a quelques exemples.