¿Por qué NaN no es igual a NaN? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

El estándar IEEE relevante define una constante numérica NaN (no un número) y prescribe que NaN debe compararse como no igual a sí mismo. ¿Por qué es eso?

Todos los idiomas que conozco implementar esta regla. Pero a menudo causa problemas significativos, por ejemplo, un comportamiento inesperado cuando NaN se almacena en un contenedor, cuando NaN está en los datos que se están ordenando, etc. Sin mencionar que la gran mayoría de los programadores esperan que cualquier objeto sea igual a sí mismo (antes de que aprendan sobre NaN), por lo que sorprenderlos se suma a los errores y la confusión.

Los estándares IEEE están bien pensados, por lo que estoy seguro de que hay una buena razón por la que comparar NaN como igual a sí mismo sería malo. Yo sólo no sé qué es.

Author: Turn, 2012-04-05

6 answers

La respuesta aceptada es 100% sin duda INCORRECTA. No a mitad de camino o incluso ligeramente mal. Me temo que este problema va a confundir y engañar a los programadores durante mucho tiempo cuando esta pregunta aparezca en las búsquedas.

NaN está diseñado para propagarse a través de todos los cálculos, infectándolos como un virus, por lo que si en algún lugar de sus cálculos profundos y complejos encuentra a una NaN, no genera una respuesta aparentemente sensata. De lo contrario por identidad NaN / NaN debe ser igual a 1, junto con todas las otras consecuencias como la (NaN/NaN)==1, (NaN*1)==NaN, etc. Si imaginas que tus cálculos salieron mal en algún lugar (el redondeo produjo un denominador cero, produciendo NaN), etc, entonces podrías obtener resultados tremendamente incorrectos (o peor: sutilmente incorrectos) de tus cálculos sin un indicador obvio de por qué.

También hay muy buenas razones para NaNs en los cálculos cuando se sondea el valor de una función matemática; uno de los ejemplos dados en el documento vinculado es encontrar los ceros de una función f(). Es completamente posible que en el proceso de sondeo de la función con valores de conjetura que sondeará uno donde la función f () no produce ningún resultado sensible. Esto permite a zeros () ver la NaN y continuar su trabajo.

La alternativa a NaN es activar una excepción tan pronto como se encuentre una operación ilegal (también llamada señal o trampa). Además de las enormes penalizaciones de rendimiento que podría encontrar, en ese momento no había garantizar que las CPU lo soportarían en hardware o que el sistema operativo/lenguaje lo soportaría en software; cada uno era su propio copo de nieve único en el manejo del punto flotante. IEEE decidió manejarlo explícitamente en el software como los valores NaN para que fuera portable a través de cualquier sistema operativo o lenguaje de programación. Los algoritmos de coma flotante correctos generalmente son correctos en todas las implementaciones de coma flotante, ya sea en node.js o COBOL (hah).

En teoría, no tienes que establecer directivas específicas #pragma, establecer indicadores de compilador locos, capturar las excepciones correctas, o instalar controladores de señal especiales para hacer que lo que parece ser el algoritmo idéntico realmente funcione correctamente. Desafortunadamente, algunos diseñadores de lenguaje y escritores de compiladores han estado muy ocupados deshaciendo esta característica al máximo de sus habilidades.

Por favor, lea algo de la información sobre la historia de la coma flotante IEEE 754. También esta respuesta a una pregunta similar cuando un miembro del comité responded: ¿Cuál es la razón para que todas las comparaciones devuelvan valores falsos para IEEE754 NaN?

"Una Entrevista con el Viejo Hombre de Punto Flotante"

"Historia del Formato de Coma Flotante IEEE"

Lo que todo científico de la computación debe saber sobre la aritmética de coma flotante

 129
Author: russbishop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:41

Bien, log(-1) da NaN, y acos(2) también da NaN. ¿Eso significa que log(-1) == acos(2)? Claramente no. Por lo tanto, tiene perfecto sentido que NaN no es igual a sí mismo.

Volviendo a esto casi dos años después, aquí hay una función de comparación "NaN-safe":

function compare(a,b) {
    return a == b || (isNaN(a) && isNaN(b));
}
 88
Author: Niet the Dark Absol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-15 08:42:35

Mi respuesta original (de hace 4 años) critica la decisión desde la perspectiva moderna sin entender el contexto en el que se tomó la decisión. Como tal, no responde a la pregunta.

La respuesta correcta se da aquí :

NaN != NaN se originó a partir de dos consideraciones pragmáticas:

[...] No había predicado isnan( ) en el momento en que NaN se formalizó en la aritmética 8087; era necesario proporcionar programadores con un medio conveniente y eficiente de detectar valores NaN que no dependían de lenguajes de programación que proporcionaran algo como isnan( ) que podría tomar muchos años

Había una desventaja en ese enfoque: hacía que la NaN fuera menos útil en muchas situaciones no relacionadas con la computación numérica. Por ejemplo, mucho más tarde, cuando la gente quiso usar NaN para representar los valores faltantes y ponerlos en contenedores basados en hash, no pudieron hacerlo.

Si el comité previó casos de uso futuros, y los consideró lo suficientemente importantes, podrían haber ido para el más detallado !(x<x & x>x) en lugar de x!=x como una prueba para NaN. Sin embargo, su enfoque era más pragmático y estrecho: proporcionar la mejor solución para un cálculo numérico, y como tal no vieron ningún problema con su enfoque.

===

Respuesta original:

Lo siento, por mucho que aprecio el pensamiento que se introdujo en la respuesta votada por arriba, no estoy de acuerdo con ella. NaN no significa " indefinido" - véase http://www.cs.berkeley.edu / ~wkahan / ieee754status / IEEE754.PDF , página 7 (busca la palabra "undefined"). Como confirma ese documento, NaN es un concepto bien definido.

Además, el enfoque de IEEE era seguir las reglas matemáticas regulares tanto como fuera posible, y cuando no podían, seguir la regla de "menos sorpresa" - ver https://stackoverflow.com/a/1573715/336527 . Cualquier objeto matemático es igual a sí mismo, por lo que las reglas de las matemáticas implicarían que NaN = = NaN debe ser Verdad. No veo ninguna razón válida y poderosa para desviarme de un principio matemático tan importante (por no mencionar las reglas menos importantes de la tricotomía de comparación, etc.).).

Como resultado, mi conclusión es la siguiente.

Los miembros del comité IEEE no pensaron esto muy claramente, y cometieron un error. Dado que muy pocas personas entendieron el enfoque del comité IEEE, o se preocuparon por lo que dice exactamente el estándar sobre NaN (a saber: el tratamiento de la mayoría de los compiladores de NaN viola el estándar IEEE de todos modos), nadie dio la alarma. Por lo tanto, este error ahora está incrustado en el estándar. Es poco probable que se corrija, ya que tal arreglo rompería una gran cantidad de código existente.

Editar: Aquí hay un post de una discusión muy informativa. Nota: para obtener una vista imparcial tienes que leer todo el hilo, ya que Guido tiene una visión diferente a la de otros desarrolladores principales. Sin embargo, Guido no está personalmente interesado en este tema, y en gran medida sigue la recomendación de Tim Peters. Si alguien tiene argumentos de Tim Peters a favor de NaN != NaN, por favor agréguelos en los comentarios; tienen una buena oportunidad de cambiar mi opinión.

 26
Author: max,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:10

Una buena propiedad es: si x == x devuelve false, entonces x es NaN.

(se puede usar esta propiedad para comprobar si x es NaN o no.)

 7
Author: asf107,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-05 18:47:27

Prueba esto:

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 fuera cierto, eso podría llevar a concluir que a = = b, lo cual claramente no es.

Otra forma de verlo es que NaN solo te da información sobre lo que algo NO ES, no lo que es. Por ejemplo, si yo digo 'una manzana no es un gorila' y 'una naranja no es un gorila', podría llegar a la conclusión de que 'apple'=='naranja'?

 6
Author: Mike C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-02 12:43:06

En realidad, hay un concepto en matemáticas conocido como valores de "unidad". Estos valores son extensiones que se construyen cuidadosamente para reconciliar problemas periféricos en un sistema. Por ejemplo, se puede pensar en el anillo en el infinito en el plano complejo como un punto o un conjunto de puntos, y algunos problemas antes pretenciosos desaparecen. Hay otros ejemplos de esto con respecto a cardinalidades de conjuntos donde se puede demostrar que se puede elegir la estructura del continuum de infinidades para siempre que |P (A)| > |A| y nada se rompa.

DESCARGO DE RESPONSABILIDAD: Solo estoy trabajando con mi vaga memoria de mis algunas advertencias interesantes durante mis estudios de matemáticas. Me disculpo si hice un trabajo lamentable de representar los conceptos a los que aludí anteriormente.

Si desea creer que NaN es un valor solitario, entonces probablemente no estará satisfecho con algunos de los resultados, como el operador de igualdad que no funciona de la manera que espera/desea. Sin embargo, si usted decide creer que NaN es más de un continuum de" maldad " representado por un marcador de posición solitario, entonces estás perfectamente feliz con el comportamiento del operador de igualdad. En otras palabras, pierdes de vista el pez que pescaste en el mar, pero atrapas otro que se ve igual, pero es igual de maloliente.

 2
Author: Garth Pickell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-19 18:54:26