Pourquoi NaN n'est pas égale à NaN? [dupliquer]

cette question a déjà une réponse ici:

la norme pertinente de L'IEEE définit une constante numérique NaN (et non un nombre) et prescrit que NaN doit comparer comme n'étant pas égale à m'. Pourquoi est-ce?

toutes les langues que je connais appliquent cette règle. Mais il provoque souvent des problèmes importants, par exemple un comportement inattendu quand NaN est stocké dans un conteneur, quand NaN est dans les données qui sont triées, etc. Sans compter que la grande majorité des programmeurs s'attendent à ce que n'importe quel objet soit égal à lui-même (avant qu'ils ne connaissent NaN), donc les surprendre ajoute aux bogues et à la confusion.

les normes IEEE sont bien pensées dehors, donc je suis sûr qu'il y a une bonne raison pour laquelle comparer NaN comme égal à lui-même serait mauvais. Je ne peux pas comprendre ce que c'est.

89
demandé sur Turn 2012-04-05 22:43:01

6 réponses

Les accepté de réponse est de 100% sans question MAL . Pas à moitié faux ou même légèrement faux. Je crains que cette question ne soit source de confusion et de confusion pour les programmeurs pendant longtemps encore lorsque cette question apparaîtra dans searches.

NaN est conçu pour se propager à travers tous les calculs, les infectant comme un virus, donc si quelque part dans vos calculs profonds et complexes que vous avez frappé sur une NaN, vous ne bulle pas une réponse apparemment raisonnable. Autrement par identité NaN / NaN devrait égaler 1, avec toutes les autres conséquences comme (NaN / NaN)==1, (NaN*1)==NaN, etc. Si vous imaginez que vos calculs ont mal tourné quelque part (l'arrondissement a produit un zéro dénominateur, donnant NaN), etc alors vous pourriez obtenir des résultats tout à fait incorrects (ou pire: subtilement incorrects) de vos calculs sans aucun indicateur évident quant à la raison.

il y a aussi de très bonnes raisons pour NaNs dans les calculs lorsque l'on sonde la valeur d'un fonction mathématique; l'un des exemples donnés dans le document référencé est de trouver les zéros() d'une fonction f(). Il est tout à fait possible que dans le processus de sonder la fonction avec des valeurs de guess que vous sonderez un où la fonction f() ne donne pas de résultat sensible. Cela permet à zeros () de voir la NaN et de continuer son travail.

l'alternative à La NaN est de déclencher une exception dès qu'une opération illégale est détectée (également appelé un signal ou d'un piège). Outre les énormes pénalités de performance que vous pourriez rencontrer, à l'époque il n'y avait aucune garantie que les CPU le supporteraient en matériel ou le langage OS/le supporterait en logiciel; chacun était son propre flocon de neige unique dans la manipulation de flottant-point. IEEE a décidé de le traiter explicitement dans le Logiciel comme les valeurs NaN afin qu'il soit portable à travers n'importe quel OS ou langage de programmation. Corriger virgule flottante algorithmes sont généralement correcte dans tous les virgule flottante implémentations , que ce soit un noeud.JS ou COBOL (hah).

en théorie, vous n'avez pas besoin de définir des directives spécifiques #pragma, de mettre des drapeaux de compilateurs fous, de saisir les exceptions correctes, ou d'installer des gestionnaires de signaux spéciaux pour que ce qui semble être l'algorithme identique fonctionne correctement. Malheureusement, certains concepteurs de langage et rédacteurs de compilateurs ont été vraiment occupés à défaire cette fonctionnalité au mieux de leurs capacités.

s'il vous Plaît lire quelques-uns des information sur l'histoire de IEEE 754 floating point. Aussi cette réponse à une question similaire où un membre du Comité a répondu: Quelle est la raison pour toutes les comparaisons retournant false pour IEEE754 Nan valeurs?

"Une Entrevue avec le Vieil Homme de virgule Flottante"

"Histoire de virgule Flottante IEEE Format"

What chaque informaticien devrait connaître l'arithmétique à virgule flottante

129
répondu russbishop 2017-05-23 12:34:41

eh Bien, log(-1) donne NaN , et acos(2) donne aussi NaN . Ça veut dire que log(-1) == acos(2) ? Clairement pas. Il est donc parfaitement logique que NaN ne soit pas égal à lui-même.

revisitant ceci presque deux ans plus tard, voici une fonction de comparaison "NaN-safe":

function compare(a,b) {
    return a == b || (isNaN(a) && isNaN(b));
}
88
répondu Niet the Dark Absol 2014-05-15 08:42:35

ma première réponse (il y a 4 ans) critique la décision du point de vue moderne sans comprendre le contexte dans lequel la décision a été prise. En tant que tel, il ne répond pas à la question.

la bonne réponse est donnée ici :

NaN != NaN provient de deux considérations pragmatiques:

[...] Il n'y avait pas de isnan( ) prédit à l'époque que NaN a été formalisé dans le 8087 arithmétique; il était nécessaire de fournir les programmeurs avec un moyen pratique et efficace de détecter Nan valeurs qui ne dépendaient pas de langages de programmation fournir quelque chose comme isnan( ) qui pourrait prendre de nombreuses années

cette approche présentait un inconvénient: elle rendait NaN moins utile dans de nombreuses situations sans rapport avec le calcul numérique. Par exemple, beaucoup plus tard, quand les gens voulaient utilisez NaN pour représenter les valeurs manquantes et les mettre dans des conteneurs à base de hash, ils ne pouvaient pas le faire.

si le Comité avait prévu des cas d'utilisation future et les avait jugés suffisamment importants, ils auraient pu opter pour le plus verbeux !(x<x & x>x) au lieu de x!=x comme critère pour NaN . Cependant, leur objectif était plus pragmatique et plus étroit: fournir la meilleure solution pour un calcul numérique, et en tant que tel, ils ne voyaient aucun problème avec leur approche.

= = =

réponse originale:

je suis désolé, bien que j'apprécie la pensée qui est entrée dans la réponse la plus votée, Je ne suis pas d'accord avec elle. NaN ne signifie pas "non défini" - voir http://www.cs.berkeley.edu / ~wkahan/ieee754status / IEEE754.PDF , page 7 (rechercher le mot"undefined"). Comme le confirme ce document, la NaN est un concept bien défini.

de plus, l'approche de L'IEEE devait suivre la règles mathématiques régulières autant que possible, et quand ils ne pouvaient pas, suivre la règle de "la moindre surprise" - voir https://stackoverflow.com/a/1573715/336527 . Tout objet mathématique est égal à lui-même, de sorte que les règles mathématiques impliquent que NaN == NaN devrait être vrai. Je ne vois aucune raison valable et puissante de s'écarter d'un principe mathématique aussi important (sans parler des règles moins importantes de la trichotomie de la comparaison, etc.).).

en conséquence, ma conclusion est la suivante.

les membres du comité de L'IEEE n'ont pas réfléchi très clairement et ont fait une erreur. Puisque très peu de gens ont compris l'approche du comité de L'IEEE, ou se sont souciés de ce que dit exactement la norme au sujet de NaN (à savoir: le traitement de la plupart des compilateurs de NaN viole la norme de l'IEEE de toute façon), personne n'a soulevé une alarme. Par conséquent, cette erreur est maintenant intégrée dans la norme. Il est peu probable qu'elle soit corrigée, car une telle correction briserait un beaucoup de code existant.

Edit: Voici un post à partir d'un très instructive discussion. Note: pour obtenir une vue non biaisée, vous devez lire tout le thread, car Guido a une vue différente de celle d'autres développeurs du noyau. Cependant, Guido ne s'intéresse pas personnellement à ce sujet, et suit largement la recommandation de Tim Peters. Si Quelqu'un a les arguments de Tim Peters en faveur de NaN != NaN , s'il vous plaît les ajouter dans les commentaires; ils ont une bonne chance de changer mon opinion.

26
répondu max 2017-05-23 12:26:10

une belle propriété est: si x == x retourne false, puis x est NaN.

(on peut utiliser cette propriété pour vérifier si x est NaN ou pas.)

7
répondu asf107 2012-04-05 18:47:27

essayez ceci:

var a = 'asdf';
var b = null;

var intA = parseInt(a);
var intB = parseInt(b);

console.log(intA); //logs NaN
console.log(intB); //logs NaN
console.log(intA==intB);// logs false

si intA = = intB était vrai, cela pourrait vous conduire à conclure que a==b, ce qui n'est clairement pas le cas.

une autre façon de le regarder est que NaN vous donne juste des informations sur ce que quelque chose N'est pas, pas ce que c'est. Par exemple, si je dis "une pomme n'est pas un gorille" et "une orange n'est pas un gorille', voulez-vous conclure qu '"une pomme" =='orange'?

6
répondu Mike C 2013-04-02 12:43:06

en fait, il existe un concept en mathématiques connu sous le nom de valeurs "d'unité". Ces valeurs sont des extensions qui sont soigneusement construites pour réconcilier les problèmes périphériques dans un système. Par exemple, vous pouvez penser à l'anneau à l'infini dans le plan complexe comme étant un point ou d'un ensemble de points, et certaines anciennement prétentieux problèmes disparaissent. Il y a d'autres exemples de ce qui concerne les cardinalités des jeux où vous pouvez démontrer que vous pouvez choisir la structure du continuum de infinities tant que| P(A) | > | A / et que rien ne casse.

avertissement: Je ne travaille qu'avec mon vague souvenir de mes quelques mises en garde intéressantes au cours de mes études de mathématiques. Je m'excuse si j'ai fait un travail lamentable en représentant les concepts auxquels j'ai fait allusion ci-dessus.

Si vous voulez croire que NaN est un solitaire valeur, alors vous êtes probablement va être malheureuse avec certains des résultats comme l'opérateur d'égalité ne fonctionne pas comme vous le souhaitez/voulez. Toutefois, si vous choisissez de croyez que NaN est plus d'un continuum de la "méchanceté" représenté par un espace solitaire, alors vous êtes parfaitement heureux avec le comportement de l'opérateur d'égalité. En d'autres termes, vous perdez de vue le poisson que vous avez pris dans la mer mais vous attrapez un autre qui ressemble à la même chose, mais est tout aussi malodorant.

2
répondu Garth Pickell 2013-03-19 18:54:26