Pourquoi typeof NaN renvoie-t-il 'nombre'?

166

Juste par curiosité.

Il ne semble pas très logique que ce typeof NaNsoit le nombre. Juste comme NaN === NaNou NaN == NaNretournant faux, au fait. Est-ce l'une des particularités de javascript, ou y aurait-il une raison à cela?

Edit: merci pour vos réponses. Ce n'est cependant pas une chose facile à faire. En lisant les réponses et le wiki, j'ai mieux compris, mais quand même, une phrase comme

Une comparaison avec un NaN renvoie toujours un résultat non ordonné même en comparant avec lui-même. Les prédicats de comparaison sont soit de signalisation soit non de signalisation, les versions de signalisation signalent une exception invalide pour de telles comparaisons. Les prédicats d'égalité et d'inégalité ne sont pas de signalisation, donc x = x retournant false peut être utilisé pour tester si x est un NaN silencieux.

garde juste ma tête qui tourne. Si quelqu'un peut traduire cela dans un langage lisible par l'homme (par opposition à, disons, un mathématicien), je serais reconnaissant.

KooiInc
la source
17
+1: "NaN est un nombre mais n'est pas un nombre. Hum ... quoi?!"
ereOn
11
Pour plus de plaisir; (NaN! == NaN) == true
Alex K.
1
Encore plus amusant (mais compréhensible à y penser, isNaN renvoie un booléen): isNaN (parseInt ('nodice')) === isNaN (parseInt ('someOtherNaN')) === true;
KooiInc
1
Si vous utilisez jQuery, je préfère isNumericplutôt vérifier le type: $.isNumeric(NaN); renvoie false, où as $.type(NaN);, renvoie number. api.jquery.com/jQuery.isNumeric
Justin
3
En tant que mathématicien professionnel, je dois dire que cette phrase n'a pas grand-chose à voir avec le langage précis des mathématiques.
Dmitri Zaitsev

Réponses:

53

Cela signifie pas un nombre. Ce n'est pas une particularité de javascript mais un principe informatique commun.

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

Il existe trois types d'opérations qui renvoient NaN:

Opérations avec un NaN comme au moins un opérande

Formes indéterminées

  • Les divisions 0/0, ∞ / ∞, ∞ / −∞, −∞ / ∞ et −∞ / −∞
  • Les multiplications 0 × ∞ et 0 × −∞
  • La puissance 1 ^ ∞
  • Les additions ∞ + (−∞), (−∞) + ∞ et soustractions équivalentes.

Des opérations réelles avec des résultats complexes:

  • La racine carrée d'un nombre négatif
  • Le logarithme d'un nombre négatif
  • La tangente d'un multiple impair de 90 degrés (ou π / 2 radians)
  • Le sinus ou cosinus inverse d'un nombre inférieur à -1 ou supérieur à +1.

Toutes ces valeurs peuvent ne pas être les mêmes. Un test simple pour un NaN est de tester value == valueest faux.

Charles Beattie
la source
46
Un test encore plus simple estisNaN(value)
Alsciende
4
@Alsciende ce n'est pas équivalent cependant. isNaN(undefined)renvoie true, mais undefined == undefinedest également vrai. Il en va de même pour tous les autres types non numériques sauf null.
Andy
7
En d'autres termes, value !== valuec'est probablement le moyen le plus court de tester si valuec'est vraiment NaN.
Andy
1
On dirait que tu as raison, @Andy. Voilà une particularité.
Alsciende
2
L'expression «ces valeurs peuvent ne pas être les mêmes» n'a pas de sens, car ces valeurs n'existent pas.
Dmitri Zaitsev
103

Eh bien, NaNc'est toujours un type numérique , malgré le fait qu'il signifie en fait Not-A-Number :-)

NaNsignifie simplement que la valeur spécifique ne peut pas être représentée dans les limites du type numérique (bien que cela puisse être dit pour tous les nombres qui doivent être arrondis pour s'adapter, mais NaNc'est un cas particulier).

Un spécifique NaNn'est pas considéré comme égal à un autre NaNcar il peut s'agir de valeurs différentes. Cependant, NaNc'est toujours un type de nombre, tout comme 2718 ou 31415.


Quant à votre question mise à jour à expliquer en termes simples:

Une comparaison avec un NaN renvoie toujours un résultat non ordonné même en comparant avec lui-même. Les prédicats de comparaison sont soit de signalisation soit non de signalisation, les versions de signalisation signalent une exception invalide pour de telles comparaisons. Les prédicats d'égalité et d'inégalité ne sont pas de signalisation, donc x = x retournant false peut être utilisé pour tester si x est un NaN silencieux.

Tout cela signifie (décomposé en parties):

Une comparaison avec un NaN renvoie toujours un résultat non ordonné même en comparant avec lui-même.

Fondamentalement, a NaNn'est égal à aucun autre nombre, y compris un autre NaN, et même lui- même inclus .

Les prédicats de comparaison sont soit de signalisation soit non de signalisation, les versions de signalisation signalent une exception invalide pour de telles comparaisons.

Tenter d'effectuer des opérations de comparaison (inférieure à, supérieure à, etc.) entre un NaNnombre et un autre nombre peut soit entraîner la levée d'une exception (signalisation), soit simplement devenir fausse (sans signalisation ou silencieuse).

Les prédicats d'égalité et d'inégalité ne sont pas de signalisation, donc x = x retournant false peut être utilisé pour tester si x est un NaN silencieux.

Les tests d'égalité (égal à, différent de) ne signalent jamais, donc leur utilisation ne provoquera pas d'exception. Si vous avez un numéro régulier x, ce x == xsera toujours vrai. Si xest a NaN, alors x == xsera toujours faux. Cela vous donne un moyen de détecter NaNfacilement (tranquillement).

paxdiablo
la source
1
bonne explication, même si je ne suis pas d'accord dans les deux dernières phrases: une meilleure façon de vérifier si x est un NaN utilise la fonction isNaN ()
Carlos Barcelona
@DominicRodger voici ce que j'en pense: typeof a === 'number'signifie "a est stocké en interne en tant que flottant IEEE 754"
Andy
Pourquoi Infinity === Infinityretourne- t-il truesi un Infinitypeut être produit par différentes valeurs: 1.0 / 0.0 ou 2.0 / 0.0?
Hashem Qolami
1
@Hashem, probablement parce qu'ils sont considérés comme le même infini. Traiter la division comme une soustraction répétée, cela ne fait aucune différence que vous commenciez à deux ou à un, c'est le même nombre d'étapes nécessaires pour atteindre (ou, plus précisément, ne pas atteindre) zéro. Je comprends que les gourous des mathématiques ont différentes classes d'infini mais (1) je soupçonne 1/0et je me 2/0trouve dans la même classe et (2) il n'y a qu'une seule classe d'infini dans IEEE754 (autre que +/-bien sûr).
paxdiablo
1
Je ne connais aucun moyen de définir ces «chiffres réels» exceptionnels de manière significative. En mathématiques, le log et la racine des négatifs ne peuvent être obtenus qu'au moyen de l'extension des réels à des nombres complexes, où ils s'évaluent en plusieurs valeurs et 0/0ne sont pas définis de manière significative, à part dire que sa "valeur" est l'ensemble complet de nombres. Et même s'ils ont été définis, Math.log(-1) == Math.log(-1)évalue toujours false. Donc, non seulement il n'y a pas de "nombres réels" autres que NaNmais même s'il y en avait, ils n'ont pas été utilisés pour la comparaison.
Dmitri Zaitsev
20

La norme ECMAScript (JavaScript) spécifie qu'il Numberss'agit de flottants IEEE 754 , qui incluent NaNcomme valeur possible.

ECMA 262 5e Section 4.3.19 : Valeur numérique

valeur primitive correspondant à une valeur IEEE 754 au format binaire 64 bits double précision.

ECMA 262 5e Section 4.3.23 : NaN

Valeur numérique qui est une valeur IEEE 754 «Not-a-Number».

IEEE 754 sur Wikipedia

La norme IEEE pour l'arithmétique en virgule flottante est une norme technique établie par l'Institut des ingénieurs électriciens et électroniciens et la norme la plus largement utilisée pour le calcul en virgule flottante [...]

La norme définit

  • formats arithmétiques : ensembles de données à virgule flottante binaires et décimales, constitués de nombres finis (y compris les zéros signés et les nombres inférieurs à la normale), les infinis et les valeurs spéciales «pas un nombre» (NaN)

[...]

Jeremy Banks
la source
8

typeof NaNretourne 'number'parce que:

  • La spécification ECMAScript indique que le type Number inclut NaN:

    4.3.20 Type de numéro

    ensemble de toutes les valeurs numériques possibles, y compris les valeurs spéciales «Not-a-Number» (NaN), l'infini positif et l'infini négatif

  • Donc typeofretourne en conséquence:

    11.4.3 Le type d'opérateur

    La production UnaryExpression : typeof UnaryExpression est évaluée comme suit:

    1. Soit val le résultat de l'évaluation de UnaryExpression .
    2. Si Type ( val ) est Reference , alors
      1. Si IsUnresolvableReference ( val ) est vrai , retournez "undefined".
      2. Laissez val être GetValue ( val ).
    3. Renvoyer une chaîne déterminée par type ( val ) selon le Tableau 20.

                    Table 20 — typeof Operator Results
    ==================================================================
    |        Type of val         |              Result               |
    ==================================================================
    | Undefined                  | "undefined"                       |
    |----------------------------------------------------------------|
    | Null                       | "object"                          |
    |----------------------------------------------------------------|
    | Boolean                    | "boolean"                         |
    |----------------------------------------------------------------|
    | Number                     | "number"                          |
    |----------------------------------------------------------------|
    | String                     | "string"                          |
    |----------------------------------------------------------------|
    | Object (native and does    | "object"                          |
    | not implement [[Call]])    |                                   |
    |----------------------------------------------------------------|
    | Object (native or host and | "function"                        |
    | does implement [[Call]])   |                                   |
    |----------------------------------------------------------------|
    | Object (host and does not  | Implementation-defined except may |
    | implement [[Call]])        | not be "undefined", "boolean",    |
    |                            | "number", or "string".            |
    ------------------------------------------------------------------

Ce comportement est conforme à la norme IEEE pour l'arithmétique à virgule flottante (IEEE 754) :

4.3.19 Valeur numérique

valeur primitive correspondant à une valeur IEEE 754 au format binaire 64 bits double précision

4.3.23 NaN

valeur numérique qui est une valeur IEEE 754 «Not-a-Number»

8.5 Le type de nombre

Le type Number a exactement 18437736874454810627 (c'est-à-dire 2 53 -2 64 +3) valeurs, représentant les valeurs IEEE 754 au format 64 bits double précision comme spécifié dans la norme IEEE pour l'arithmétique binaire à virgule flottante, sauf que le 9007199254740990 ( c'est-à-dire 2 53 -2) les valeurs distinctes «Not-a-Number» de la norme IEEE sont représentées dans ECMAScript comme une valeur NaN spéciale unique . (Notez que la valeur NaN est produite par l'expression de programme NaN.)

Oriol
la source
5

NaN est une valeur à virgule flottante valide ( http://en.wikipedia.org/wiki/NaN )

et NaN === NaN est faux car ils ne sont pas nécessairement le même non-nombre

Charles Ma
la source
1
Désolé, mais je dois dire que ce n'est pas une bonne façon d'y penser. «pas nécessairement le même non-nombre» ne signifie pas qu'ils sont toujours différents et les comparer devrait donner faux. Il est préférable de ne pas quantifier NaN et de le considérer comme une bizarrerie dans notre base de connaissances.
Dave
1
Alors pourquoi tous Infinitysont en quelque sorte identiques? Des pensées?
Hashem Qolami
5

NaN != NaNcar ils ne sont pas nécessairement le même non-nombre. Cela a donc beaucoup de sens ... Aussi pourquoi les flottants ont à la fois +0,00 et -0,00 qui ne sont pas les mêmes. L'arrondi peut faire qu'ils ne sont en fait pas nuls.

Quant au typeof, cela dépend de la langue. Et la plupart des langages diront que NaN est un flottant, un double ou un nombre selon la façon dont ils le classent ... Je ne connais aucun langage qui dira que c'est un type inconnu ou nul.

Ciné
la source
1
ehr, considérez: var x = parseInt ('no dice'), y = x; Maintenant, je dirais que les deux NaN sont exactement les mêmes? Mais non, x === y renvoie également false.
KooiInc
oui, mais vous ne pouvez pas être SÛR, et donc ils ne sont pas les mêmes. C'est la même logique que la logique NULLable dans la base de données. Bien que beaucoup de gens les considèrent comme identiques aux pointeurs nuls d'autres langages de programmation, ils ont en fait une sémantique totalement différente. Ils sont "INCONNU" et donc une valeur NULL par rapport à une autre est toujours fausse. Faire des calculs sur une valeur NULL aboutit au résultat NULL. Essayez plutôt de le voir du point de vue de la valeur appelée INCONNU
Ciné
Comme étant de type number, NaNest primitif, et donc uniquement déterminé par sa valeur.
Dmitri Zaitsev
4

NaNsignifie Pas un nombre . Il s'agit d'une valeur de types de données numériques (généralement des types à virgule flottante, mais pas toujours) qui représente le résultat d'une opération non valide telle que la division par zéro.

Bien que ses noms indiquent qu'il ne s'agit pas d'un nombre, le type de données utilisé pour le contenir est un type numérique. Donc, en JavaScript, demander le type de données de NaNretournera number(comme alert(typeof(NaN))le montre clairement).

Joachim Sauer
la source
En fait, diviser par zéro est évalué comme InfinitynonNaN
Dmitri Zaitsev
2

Javascript utilise NaN pour représenter tout ce qu'il rencontre qui ne peut pas être représenté autrement par ses spécifications. Cela ne veut pas dire que ce n'est pas un nombre. C'est simplement la manière la plus simple de décrire la rencontre. NaN signifie que lui ou un objet qui y fait référence ne peut pas être représenté d'une autre manière par javascript. À toutes fins pratiques, il est «inconnu». Étant «inconnu», il ne peut pas vous dire ce qu'il est ni même s'il est lui-même. Ce n'est même pas l'objet auquel il est assigné. Il ne peut que vous dire ce qu'il n'est pas, et le non-né ou le néant ne peut être décrit que mathématiquement dans un langage de programmation. Puisque les mathématiques concernent les nombres, javascript représente le néant sous forme de NaN. Cela ne veut pas dire que ce n'est pas un nombre. Cela signifie que nous ne pouvons pas le lire d'une autre manière qui ait du sens. C'est pourquoi ça peut ' t même égal. Parce que non.

Louis
la source
2

Un meilleur nom pour NaN, décrivant sa signification plus précisément et avec moins de confusion, serait une exception numérique . C'est en réalité un autre type d'objet d'exception déguisé en type primitif (par la conception du langage), où en même temps il n'est pas traité comme primitif dans sa fausse auto-comparaison. D'où la confusion. Et tant que la langue "ne se fera pas la volonté" de choisir entre un objet d'exception approprié et un chiffre primitif , la confusion restera.

La tristement célèbre non-égalité de NaNlui-même, à la fois ==et ===est une manifestation de la conception déroutante forçant cet objet d'exception à être un type primitif. Cela brise le principe fondamental selon lequel une primitive est uniquement déterminée par sa valeur . Si l' NaNon préfère être considéré comme une exception (dont il peut y avoir différents types), alors il ne doit pas être «vendu» comme primitif. Et si on veut qu'il soit primitif, ce principe doit tenir. Tant qu'il est cassé, comme nous l'avons dans JavaScript, et que nous ne pouvons pas vraiment décider entre les deux, la confusion menant à une charge cognitive inutile pour toutes les personnes impliquées restera. Ce qui, cependant, est vraiment facile à corriger en faisant simplement le choix entre les deux:

  • soit créer NaNun objet d'exception spécial contenant les informations utiles sur la façon dont l'exception est survenue, au lieu de jeter ces informations comme ce qui est actuellement implémenté, conduisant à un code plus difficile à déboguer;
  • ou créer NaNune entité de type primitif number(qui pourrait être moins confuse appelée "numérique"), auquel cas elle devrait être égale à elle-même et ne peut contenir aucune autre information; ce dernier est clairement un choix inférieur.

Le seul avantage concevable de forcer NaNdans le numbertype est de pouvoir le renvoyer dans n'importe quelle expression numérique. Ce qui, cependant, rend le choix fragile, car le résultat de toute expression numérique contenant NaNsera soit NaN, soit conduira à des résultats imprévisibles tels que l' NaN < 0évaluation false, c'est- à -dire le retour booleanau lieu de conserver l'exception.

Et même si «les choses sont telles qu'elles sont», rien ne nous empêche de faire cette distinction claire pour nous-mêmes, pour aider à rendre notre code plus prévisible et plus facile à déboguer. En pratique, cela signifie identifier ces exceptions et les traiter comme des exceptions. Ce qui, malheureusement, signifie plus de code mais, espérons-le, sera atténué par des outils tels que TypeScript de Flowtype.

Et puis nous avons la distinction de signalisationNaN désordonnée calme vs bruyante aka . Ce qui concerne vraiment la façon dont les exceptions sont gérées, pas les exceptions elles-mêmes, et rien de différent des autres exceptions.

De même, Infinityet +Infinitysont des éléments de type numérique apparaissant dans l' extension de la ligne réelle mais ce ne sont pas des nombres réels. Mathématiquement, ils peuvent être représentés par des séquences de nombres réels convergeant vers l'un +ou l' autre -Infinity.

Dmitri Zaitsev
la source
1

C'est simplement parce que NaNc'est une propriété de l'objet Number dans JS, cela n'a rien à voir avec le fait qu'il s'agit d'un nombre.

Nullw0rm
la source
Comme tout autre objet, Number peut avoir n'importe quel type de propriété. Number.fu = "bar"; alert(typeof Number.fu);
Alsciende
NaNn'est pas la valeur stockée Number.NaN, quelle qu'elle soit. NaNest une valeur primitive de type Number. Et en plus, la valeur de Number.NaNest NaN, mais ce n'est pas lié.
Oriol
1

La meilleure façon de penser à NAN est que ce n'est pas un nombre connu . C'est pourquoi NAN! = NAN parce que chaque valeur NAN représente un numéro inconnu unique. Les NAN sont nécessaires car les nombres à virgule flottante ont une plage de valeurs limitée. Dans certains cas, l'arrondi se produit lorsque les bits inférieurs sont perdus, ce qui conduit à ce qui semble être un non-sens comme 1.0 / 11 * 11! = 1.0. Les valeurs vraiment grandes qui sont plus grandes sont les NAN, l'infini étant un parfait exemple.

Étant donné que nous n'avons que dix doigts, toute tentative d'afficher des valeurs supérieures à 10 est impossible, ce qui signifie que de telles valeurs doivent être des NAN car nous avons perdu la vraie valeur de cette valeur supérieure à 10. Il en va de même pour les valeurs à virgule flottante, où la valeur dépasse les limites de ce qui peut être contenu dans un flottant.

mP.
la source
L'infini n'est pas représenté par un NaN. Tenter de représenter un nombre en dehors de la plage serait arrondi vers le bas (à max / -inf) ou vers le haut (à min / + inf).
OrangeDog
1

Parce que NaN est un type de données numérique.

BenM
la source
1

NaNest un nombre du point de vue du type, mais n'est pas un nombre normal comme 1, 2 ou 329131. Le nom "Not A Number" fait référence au fait que la valeur représentée est spéciale et concerne le domaine de spécification du format IEEE, pas domaine de langage javascript.

6502
la source
1

Si vous utilisez jQuery, je préfère isNumericsur vérifier le type:

console.log($.isNumeric(NaN));  // returns false
console.log($.type(NaN));       // returns number

http://api.jquery.com/jQuery.isNumeric/

Justin
la source
Merci mec. J'ai eu des problèmes avec isNumberdu utilpaquet dactylographiées. Bien que nous utilisons toujours jQuerydans notre projet, nous avons donc utilisé votre suggestion à la place.
Ashok MA
Pour le rec, isNumberfrom utilof typescript renvoie également truepour NaN.
Ashok MA
0

Javascript n'a qu'un seul type de données numérique, qui est le flottant standard 64 bits à double précision. Tout est double. NaN est une valeur spéciale de double, mais c'est néanmoins un double.

Tout ce que cela parseIntfait est de «convertir» votre chaîne en un type de données numérique, de sorte que le résultat est toujours «nombre»; seulement si la chaîne d'origine n'était pas analysable, sa valeur sera NaN.

Kerrek SB
la source
0

NaN est toujours un type numérique, mais il représente une valeur qui ne peut pas représenter un nombre valide.

Matthew Abbott
la source
0

Nous pourrions affirmer que NaN est un objet de cas particulier. Dans ce cas, l'objet de NaN représente un nombre qui n'a aucun sens mathématique. Il existe d'autres objets de cas spéciaux en mathématiques comme INFINITE et ainsi de suite.

Vous pouvez toujours faire des calculs avec, mais cela entraînera des comportements étranges.

Plus d'informations ici: http://www.concentric.net/~ttwang/tech/javafloat.htm (basé sur java, pas javascript)

Pedro Loureiro
la source
0

Vous devez aimer Javascript. Il a quelques petites bizarreries intéressantes.

http://wtfjs.com/page/13

La plupart de ces bizarreries peuvent être expliquées si vous vous arrêtez pour les résoudre logiquement, ou si vous connaissez un peu la théorie des nombres, mais elles peuvent néanmoins vous surprendre si vous ne les connaissez pas.

En passant, je recommande de lire le reste de http://wtfjs.com/ - il y a beaucoup plus de bizarreries intéressantes que celle-ci!

Spudley
la source
0

La valeur NaN est vraiment le Number.NaN donc quand vous demandez si c'est un nombre, il dira oui. Vous avez fait la bonne chose en utilisant l'appel isNaN ().

Pour information, NaN peut également être retourné par des opérations sur des nombres qui ne sont pas définis comme des divisions par zéro ou la racine carrée d'un nombre négatif.

Rob
la source
Dans quel sens est-ce "la valeur"? NaN == Number.NaNévalue à false!
Dmitri Zaitsev
@DmitriZaitsev Avez-vous lu le fil de discussion? Et avez-vous essayé if (parseInt ("nan") == Number.NaN)? Essayez également! = Et voyez ce qu'il vous dit.
Rob
Désolé, j'ai oublié l' NaN==NaNêtre stupide false, ça doit être un sadique qui a inventé ça pour faire souffrir tout le monde.
Dmitri Zaitsev
0

Un exemple

Imaginez que nous convertissons une chaîne en nombre:

Number("string"); // returns NaN

Nous avons changé le type de données en nombre mais sa valeur n'est pas un nombre!

Amir Fo
la source
Vous semblez avoir manqué le point de la question. NaNest du type numérique . La question est de savoir pourquoi.
Quentin
@Quentin j'ai expliqué à la dernière ligne.
Amir Fo
-1

Il s'agit d'une valeur spéciale de type Number comme POSITIVE_INFINITY

Pourquoi? Intentionnellement

RiaD
la source