¿Por qué typeof NaN devuelve 'número'?

166

Solo por curiosidad.

No parece muy lógico que typeof NaNsea ​​número. Solo como NaN === NaNo NaN == NaNdevolviendo falso, por cierto. ¿Es esta una de las peculiaridades de javascript, o habría una razón para esto?

Editar: gracias por sus respuestas. Sin embargo, no es una cosa fácil tener la cabeza puesta. Leyendo respuestas y la wiki entendí más, pero aún así, una oración como

Una comparación con un NaN siempre devuelve un resultado desordenado, incluso cuando se compara con sí mismo. Los predicados de comparación son señalización o no señalización, las versiones de señalización señalan una excepción no válida para tales comparaciones. Los predicados de igualdad y desigualdad no son señalización, por lo que x = x devuelve falso se puede utilizar para probar si x es un NaN silencioso.

solo mantiene mi cabeza girando. Si alguien puede traducir esto en lenguaje legible para humanos (en lugar de, digamos, matemático), estaría agradecido.

KooiInc
fuente
17
+1: "NaN es un número pero no es un número. Hum ... ¡¿qué ?!"
antes
11
Para más diversión; (NaN! == NaN) == verdadero
Alex K.
1
Aún más divertido (pero comprensible, isNaN devuelve un valor booleano): isNaN (parseInt ('nodice')) === isNaN (parseInt ('someOtherNaN')) === true;
KooiInc
1
Si usa jQuery, prefiero isNumericverificar el tipo: $.isNumeric(NaN); devuelve falso, donde como $.type(NaN);, devuelve el número. api.jquery.com/jQuery.isNumeric
Justin
3
Como matemático profesional, debo decir que la oración tiene poco en común con el lenguaje preciso de las matemáticas.
Dmitri Zaitsev

Respuestas:

53

Significa no un número. No es una peculiaridad de javascript, sino un principio informático común.

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

Hay tres tipos de operaciones que devuelven NaN:

Operaciones con un NaN como al menos un operando

Formas indeterminadas

  • Las divisiones 0/0, ∞ / ∞, ∞ / −∞, −∞ / ∞ y −∞ / −∞
  • Las multiplicaciones 0 × ∞ y 0 × −∞
  • El poder 1 ^ ∞
  • Las adiciones ∞ + (−∞), (−∞) + ∞ y sustracciones equivalentes.

Operaciones reales con resultados complejos:

  • La raíz cuadrada de un número negativo
  • El logaritmo de un número negativo.
  • La tangente de un múltiplo impar de 90 grados (o π / 2 radianes)
  • El seno o coseno inverso de un número que es menor que -1 o mayor que +1.

Todos estos valores pueden no ser iguales. Una prueba simple para un NaN es probar que value == valuees falso.

Charles Beattie
fuente
46
Una prueba aún más simple esisNaN(value)
Alsciende
44
Sin embargo, @Alsciende no es equivalente. isNaN(undefined)vuelve true, pero undefined == undefinedtambién es cierto. Lo mismo ocurre con todos los demás tipos que no son números, excepto null.
Andy
77
En otras palabras, value !== valuees probablemente la forma más corta de probar si valuees realmente NaN.
Andy
1
Parece que tienes razón, @Andy. Ahora que es una peculiaridad.
Alsciende
2
La frase "estos valores pueden no ser los mismos" no tiene significado, porque esos valores no existen.
Dmitri Zaitsev
103

Bueno, NaNsigue siendo un tipo numérico , a pesar del hecho de que en realidad significa Not-A-Number :-)

NaN solo significa que el valor específico no se puede representar dentro de las limitaciones del tipo numérico (aunque eso podría decirse de todos los números que deben redondearse para ajustarse, pero NaN es un caso especial).

Un específico NaNno se considera igual a otro NaNporque pueden ser valores diferentes. Sin embargo, NaNsigue siendo un tipo de número, al igual que 2718 o 31415.


En cuanto a su pregunta actualizada para explicar en términos simples:

Una comparación con un NaN siempre devuelve un resultado desordenado, incluso cuando se compara con sí mismo. Los predicados de comparación son señalización o no señalización, las versiones de señalización señalan una excepción no válida para tales comparaciones. Los predicados de igualdad y desigualdad no son señalización, por lo que x = x devuelve falso se puede utilizar para probar si x es un NaN silencioso.

Todo esto significa es (desglosado en partes):

Una comparación con un NaN siempre devuelve un resultado desordenado, incluso cuando se compara con sí mismo.

Básicamente, a NaNno es igual a ningún otro número, incluido otro NaN, e incluso a sí mismo .

Los predicados de comparación son señalización o no señalización, las versiones de señalización señalan una excepción no válida para tales comparaciones.

Intentar realizar operaciones de comparación (menor que, mayor que, y así sucesivamente) entre un NaNnúmero y otro puede provocar una excepción (señalización) o simplemente obtener un resultado falso (no señalización o silencio).

Los predicados de igualdad y desigualdad no son señalización, por lo que x = x devuelve falso se puede utilizar para probar si x es un NaN silencioso.

Las pruebas de igualdad (igual a, no igual a) nunca son una señal, por lo que su uso no causará una excepción. Si tiene un número regular x, x == xsiempre será cierto. Si xes a NaN, x == xsiempre será falso. Le está dando una manera de detectar NaNfácilmente (en silencio).

paxdiablo
fuente
1
buena explicación, aunque no estoy de acuerdo en las últimas dos oraciones: una mejor manera de verificar si x es un NaN está utilizando la función isNaN ()
Carlos Barcelona
@DominicRodger así es como lo pienso: typeof a === 'number'significa "a se almacena internamente como un flotador IEEE 754"
Andy
¿Por qué Infinity === Infinityregresa truesi un Infinitypuede ser producido por diferentes valores: 1.0 / 0.0 o 2.0 / 0.0?
Hashem Qolami
1
@Hashem, muy probablemente porque se consideran el mismo infinito. Tratando la división como una resta repetida, no importa si comienza en dos o uno, es el mismo número de pasos necesarios para alcanzar (o, más exactamente, no alcanzar) cero. Entiendo que los gurús de las matemáticas tienen diferentes clases de infinito, pero (1) sospecho 1/0y estoy 2/0en la misma clase y (2) solo hay una clase de infinito en IEEE754 (aparte de, +/-por supuesto).
paxdiablo
1
No conozco ninguna forma de definir estos "números reales" excepcionales de manera significativa. En matemáticas, el registro y la raíz de los negativos solo pueden obtenerse mediante la extensión de reales a números complejos, donde evalúan valores múltiples y 0/0no se definen de manera significativa, aparte de decir que su "valor" es todo el conjunto de números E incluso si se definieron, Math.log(-1) == Math.log(-1)aún se evalúa false. Por lo tanto, no solo no hay "números reales", NaNsino que incluso si los hubiera, no se usaron para la comparación.
Dmitri Zaitsev
20

El estándar ECMAScript (JavaScript) especifica que Numbersson flotantes IEEE 754 , que incluyen NaNcomo un posible valor.

ECMA 262 5e Sección 4.3.19 : Valor numérico

valor primitivo correspondiente a un formato IEEE 754 de formato binario de 64 bits de doble precisión.

ECMA 262 5e Sección 4.3.23 : NaN

Valor numérico que es un valor IEEE 754 "No es un número".

IEEE 754 en Wikipedia

El estándar IEEE para aritmética de punto flotante es un estándar técnico establecido por el Instituto de Ingenieros Eléctricos y Electrónicos y el estándar más utilizado para el cálculo de punto flotante [...]

El estándar define

  • formatos aritméticos : conjuntos de datos de punto flotante binario y decimal, que consisten en números finitos (incluidos ceros con signo y números subnormales), infinitos y valores especiales "no un número" (NaN)

[...]

Jeremy Banks
fuente
8

typeof NaNregresa 'number'porque:

  • La especificación ECMAScript dice que el tipo de número incluye NaN:

    4.3.20 Tipo de número

    conjunto de todos los valores numéricos posibles, incluidos los valores especiales de "No es un número" (NaN), infinito positivo e infinito negativo

  • Entonces typeofvuelve en consecuencia:

    11.4.3 El tipo de operador

    La producción UnaryExpression : typeof UnaryExpression se evalúa de la siguiente manera:

    1. Sea val el resultado de evaluar UnaryExpression .
    2. Si Tipo ( val ) es Referencia , entonces
      1. Si IsUnresolvableReference ( val ) es verdadero , devuelve "undefined".
      2. Deje que val sea GetValue ( val ).
    3. Devolver una cadena determinada por Type ( val ) de acuerdo con la Tabla 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".            |
    ------------------------------------------------------------------

Este comportamiento está de acuerdo con el estándar IEEE para aritmética de punto flotante (IEEE 754) :

4.3.19 Valor numérico

valor primitivo correspondiente a un formato IEEE 754 de formato binario de doble precisión de 64 bits

4.3.23 NaN

valor de número que es un valor IEEE 754 "No es un número"

8.5 El tipo de número

El tipo de número tiene exactamente 18437736874454810627 (es decir, 2 53 −2 64 +3) valores, que representan los valores IEEE 754 de formato de doble precisión de 64 bits como se especifica en el estándar IEEE para aritmética de punto flotante binario, excepto que 9007199254740990 ( es decir, 2 53 −2) valores distintos de "No es un número" del Estándar IEEE están representados en ECMAScript como un único valor especial de NaN . (Tenga en cuenta que el valor NaN es producido por la expresión del programa NaN).

Oriol
fuente
5

NaN es un valor de coma flotante válido ( http://en.wikipedia.org/wiki/NaN )

y NaN === NaN es falso porque no son necesariamente el mismo no número

Charles Ma
fuente
1
Lo siento, pero tengo que decir que no es una buena manera de pensarlo. "no necesariamente el mismo no número" no significa que siempre sean diferentes y compararlos debería dar falso. Es mejor no cuantificar NaN y solo pensarlo como una rareza en nuestra base de conocimiento.
Dave
1
Entonces, ¿por qué todos los Infinitys de alguna manera son idénticos? ¿Alguna idea?
Hashem Qolami
5

NaN != NaNporque no son necesarios el MISMO no número. Por lo tanto, tiene mucho sentido ... También por qué los flotadores tienen +0.00 y -0.00 que no son lo mismo. El redondeo puede hacer que en realidad no sean cero.

En cuanto a typeof, eso depende del idioma. Y la mayoría de los idiomas dirán que NaN es flotante, doble o número dependiendo de cómo lo clasifiquen ... No conozco ningún idioma que diga que este es un tipo desconocido o nulo.

Cine
fuente
1
ehr, considere: var x = parseInt ('no dice'), y = x; ¿Ahora diría que ambos NaN son exactamente iguales? Pero no, x === y devuelve falso también.
KooiInc
sí, pero no puedes estar SEGURO, y por lo tanto no son lo mismo. Es la misma lógica que la lógica NULLable en la base de datos. Aunque muchas personas piensan en ellos como lo mismo que los punteros nulos de otros lenguajes de programación, de hecho tienen una semántica totalmente diferente. Son "DESCONOCIDOS" y, por lo tanto, un valor NULO en comparación con otro siempre es falso. Hacer cálculos con un valor NULL termina con el resultado NULL. Intente verlo desde la perspectiva del valor que se llama DESCONOCIDO en su lugar
Cine
Como es de tipo number, NaNes primitivo y, por lo tanto, está determinado únicamente por su valor.
Dmitri Zaitsev
4

NaNsignifica No es un número . Es un valor de tipos de datos numéricos (generalmente tipos de punto flotante, pero no siempre) que representa el resultado de una operación no válida, como dividir por cero.

Aunque sus nombres dicen que no es un número, el tipo de datos utilizado para contenerlo es un tipo numérico. Entonces, en JavaScript, NaNvolverá a solicitar el tipo de datos de number(como alert(typeof(NaN))lo demuestra claramente).

Joachim Sauer
fuente
En realidad, la división entre cero se evalúa como InfinitynoNaN
Dmitri Zaitsev
2

Javascript usa NaN para representar cualquier cosa que encuentre que no pueda ser representada de otra manera por sus especificaciones. No significa que no sea un número. Es la forma más fácil de describir el encuentro. NaN significa que él o un objeto que se refiere a él no podría ser representado de otra manera por javascript. A todos los efectos prácticos, es "desconocido". Siendo 'desconocido' no puede decirte qué es ni siquiera si es en sí mismo. Ni siquiera es el objeto al que está asignado. Solo puede decirte lo que no es, y la nada o la nada solo pueden describirse matemáticamente en un lenguaje de programación. Como las matemáticas son números, JavaScript representa la nada como NaN. Eso no significa que no sea un número. Significa que no podemos leerlo de otra manera que tenga sentido. Por eso puede ' t incluso igual a sí mismo. Porque no lo hace.

Louis
fuente
2

Un mejor nombre para NaN, describiendo su significado de manera más precisa y menos confusa, sería una excepción numérica . Realmente es otro tipo de objeto de excepción disfrazado de tipo primitivo (por el diseño del lenguaje), donde al mismo tiempo no se trata como primitivo en su falsa auto-comparación. De ahí la confusión. Y mientras el lenguaje "no decida" elegir entre un objeto de excepción apropiado y un número primitivo , la confusión se mantendrá.

La infame no igualdad de NaNsí mismo, ambos ==y ===es una manifestación del diseño confuso que obliga a este objeto de excepción a ser un tipo primitivo. Esto rompe el principio fundamental de que una primitiva está determinada únicamente por su valor . Si NaNse prefiere ser visto como una excepción (de los cuales puede haber diferentes tipos), entonces no debe "venderse" como primitivo. Y si se quiere ser primitivo, ese principio debe mantenerse. Mientras esté roto, como lo hemos hecho en JavaScript, y realmente no podemos decidir entre los dos, la confusión que conduce a una carga cognitiva innecesaria para todos los involucrados seguirá siendo. Lo cual, sin embargo, es realmente fácil de solucionar simplemente haciendo la elección entre los dos:

  • haga NaNun objeto de excepción especial que contenga la información útil sobre cómo surgió la excepción, en lugar de desechar esa información como lo que está implementado actualmente, lo que lleva a un código más difícil de depurar;
  • o hacer NaNuna entidad del tipo primitivo number(que podría llamarse menos confusamente "numérico"), en cuyo caso debería ser igual a sí mismo y no puede contener ninguna otra información; esta última es claramente una elección inferior.

La ventaja sólo es concebible de forzar NaNal numbertipo es ser capaz de tirar de nuevo en cualquier expresión numérica. Lo que, sin embargo, lo convierte en una opción frágil, porque el resultado de cualquier expresión numérica que contenga NaNserá NaN, o dará lugar a resultados impredecibles, como NaN < 0evaluar a false, es decir, regresar en booleanlugar de mantener la excepción.

E incluso si "las cosas son como son", nada nos impide hacer esa distinción clara para nosotros mismos, para ayudar a que nuestro código sea más predecible y más fácil de depurar. En la práctica, eso significa identificar esas excepciones y tratarlas como excepciones. Lo cual, desafortunadamente, significa más código, pero con suerte será mitigado por herramientas como TypeScript de Flowtype.

Y luego tenemos la distinción de señalizaciónNaN desordenada silenciosa vs ruidosa . Lo que realmente se trata de cómo se manejan las excepciones, no las excepciones en sí mismas, y nada diferente de otras excepciones.

Del mismo modo, Infinityy +Infinityson elementos de tipo numérico que surgen en la extensión de la línea real pero no son números reales. Matemáticamente, se pueden representar mediante secuencias de números reales que convergen a cualquiera +o -Infinity.

Dmitri Zaitsev
fuente
1

Esto es simplemente porque NaNes una propiedad del objeto Number en JS, no tiene nada que ver con que sea un número.

Nullw0rm
fuente
Como cualquier otro objeto, Number puede tener cualquier tipo de propiedad. Number.fu = "bar"; alert(typeof Number.fu);
Alsciende
NaNno es el valor almacenado Number.NaN, sea lo que sea. NaNes un valor primitivo de tipo Número. Y además, el valor de Number.NaNes NaN, pero eso no está relacionado.
Oriol
1

La mejor manera de pensar en NAN es que no es un número conocido . Es por eso que NAN! = NAN porque cada valor NAN representa un número único desconocido. Las NAN son necesarias porque los números de coma flotante tienen un rango limitado de valores. En algunos casos, el redondeo se produce cuando se pierden los bits más bajos, lo que conduce a lo que parece ser una tontería como 1.0 / 11 * 11! = 1.0. Los valores realmente grandes que son mayores son NAN con infinito como un ejemplo perfecto.

Dado que solo tenemos diez dedos, cualquier intento de mostrar valores mayores que 10 es imposible, lo que significa que tales valores deben ser NAN porque hemos perdido el verdadero valor de este valor mayor que 10. Lo mismo se aplica a los valores de coma flotante, donde el valor excede los límites de lo que puede mantenerse en un flotador.

mP.
fuente
El infinito no está representado por un NaN. Intentar representar un número fuera del rango se redondearía hacia abajo (a max / -inf) o hacia arriba (a min / + inf).
OrangeDog
1

Porque NaN es un tipo de datos numéricos.

BenM
fuente
1

NaNes un número desde un punto de vista de tipo, pero no es un número normal como 1, 2 o 329131. El nombre "No es un número" se refiere al hecho de que el valor representado es especial y se trata del dominio de especificaciones de formato IEEE, no dominio de lenguaje javascript.

6502
fuente
1

Si usa jQuery, prefiero isNumericverificar el tipo:

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

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

Justin
fuente
Gracias hombre. He tenido problemas con isNumberdel utilpaquete de imprenta. Bien, que todavía usamos jQueryen nuestro proyecto, así que usé su sugerencia en su lugar.
Ashok MA
Para el rec, isNumberfrom utilde mecanografiado también devuelve truepara NaN.
Ashok MA
0

Javascript tiene solo un tipo de datos numéricos, que es el flotante estándar de doble precisión de 64 bits. Todo es un doble. NaN es un valor especial de doble, pero no obstante es doble.

Todo lo que parseInthace es "convertir" su cadena en un tipo de datos numéricos, por lo que el resultado es siempre "número"; solo si la cadena original no se podía analizar, su valor será NaN.

Kerrek SB
fuente
0

NaN sigue siendo un tipo numérico, pero representa un valor que no podría representar un número válido.

Matthew Abbott
fuente
0

Podríamos argumentar que NaN es un objeto de caso especial. En este caso, el objeto de NaN representa un número que no tiene sentido matemático. Hay otros objetos de casos especiales en matemáticas como INFINITE, etc.

Todavía puede hacer algunos cálculos con él, pero eso generará comportamientos extraños.

Más información aquí: http://www.concentric.net/~ttwang/tech/javafloat.htm (basado en java, no javascript)

Pedro Loureiro
fuente
0

Tienes que amar Javascript. Tiene algunas pequeñas peculiaridades interesantes.

http://wtfjs.com/page/13

La mayoría de esas peculiaridades se pueden explicar si se detiene para resolverlas de manera lógica, o si sabe un poco sobre teoría de números, pero aún así pueden atraparlo si no las conoce.

Por cierto, recomiendo leer el resto de http://wtfjs.com/ - ¡hay muchas peculiaridades más interesantes que esta!

Spudley
fuente
0

El valor NaN es realmente el Número. Por lo tanto, cuando pregunte si es un número, dirá que sí. Hizo lo correcto al usar la llamada isNaN ().

Para información, NaN también puede ser devuelto por operaciones en Números que no están definidos como divisiones por cero o raíz cuadrada de un número negativo.

Robar
fuente
¿En qué sentido es "el valor"? NaN == Number.NaNevalúa a false!
Dmitri Zaitsev
@DmitriZaitsev ¿Has leído el hilo? ¿Y has probado if (parseInt ("nan") == Number.NaN)? Prueba también! = Y mira lo que te dice.
Rob
Lo siento, olvidé el NaN==NaNser estúpido false, debe haber sido un sádico que inventó eso para hacer sufrir a todos.
Dmitri Zaitsev
0

Un ejemplo

Imagina que estamos convirtiendo una cadena en un número:

Number("string"); // returns NaN

¡Cambiamos el tipo de datos a número pero su valor no es un número!

Amir Fo
fuente
Parece que has perdido el punto de la pregunta. NaNes del tipo de número . La pregunta es por qué.
Quentin
@Quentin expliqué en la última línea.
Amir Fo
-1

Es un valor especial de tipo de número como POSITIVE_INFINITY

¿Por qué? Por diseño

RiaD
fuente