valor resueltos representar que punto para numeros numero numericos normalizada metodos mantisa informatica flotante estandar ejercicios ejemplos coma floating-point comparison nan ieee-754 iec10967

floating-point - resueltos - que es coma flotante en informatica



¿Cuál es la razón para que todas las comparaciones devuelvan falso para los valores NaN de IEEE754? (13)

Del artículo de wikipedia sobre NaN , las siguientes prácticas pueden causar NaNs:

  • Todas las operaciones matemáticas> con un NaN como al menos un operando
  • Las divisiones 0/0, ∞ / ∞, ∞ / -∞, -∞ / ∞, y -∞ / -∞
  • Las multiplicaciones 0 × ∞ y 0 × -∞.
  • Las adiciones ∞ + (-∞), (-∞) + ∞ y sustracciones equivalentes.
  • Aplicar una función a argumentos fuera de su dominio, incluida 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) o el seno inverso. o coseno de un número que es menor que -1 o mayor que +1.

Dado que no hay manera de saber cuál de estas operaciones creó la NaN, no hay manera de compararlas que tenga sentido.

¿Por qué las comparaciones de los valores de NaN se comportan de manera diferente a todos los demás valores? Es decir, todas las comparaciones con los operadores ==, <=,> =, <,> donde uno o ambos valores es NaN devuelve falso, contrariamente al comportamiento de todos los demás valores.

Supongo que esto simplifica los cálculos numéricos de alguna manera, pero no pude encontrar una razón explícitamente establecida, ni siquiera en las Notas de clase sobre el estado de IEEE 754 de Kahan, que analiza en detalle otras decisiones de diseño.

Este comportamiento desviado está causando problemas al realizar un procesamiento de datos simple. Por ejemplo, al ordenar una lista de registros en algún campo de valor real en un programa C, necesito escribir un código adicional para manejar NaN como el elemento máximo, de lo contrario el algoritmo de clasificación podría confundirse.

Edit: las respuestas hasta el momento todos argumentan que no tiene sentido comparar NaNs.

Estoy de acuerdo, pero eso no significa que la respuesta correcta sea falsa, sino que sería un No booleano (NaB), que afortunadamente no existe.

Por lo tanto, la elección de devolver verdadero o falso para las comparaciones es arbitraria, y para el procesamiento general de datos sería ventajoso si obedeciera las leyes habituales (reflexividad de ==, tricotomía de <, ==,>) Que confían en estas leyes se confunden.

Así que estoy pidiendo alguna ventaja concreta de romper estas leyes, no solo el razonamiento filosófico.

Edit 2: Creo que entiendo ahora por qué hacer NaN máximo sería una mala idea, arruinaría el cálculo de los límites superiores.

NaN! = NaN puede ser conveniente para evitar detectar la convergencia en un bucle como

while (x != oldX) { oldX = x; x = better_approximation(x); }

que, sin embargo, debería escribirse comparando la diferencia absoluta con un límite pequeño. Entonces, en mi humilde opinión, este es un argumento relativamente débil para romper la reflexividad en NaN.


Fui miembro del comité IEEE-754, intentaré ayudar a aclarar un poco las cosas.

En primer lugar, los números de punto flotante no son números reales, y la aritmética de punto flotante no satisface los axiomas de la aritmética real. La tricotomía no es la única propiedad de la aritmética real que no se aplica a las flotaciones, ni siquiera la más importante. Por ejemplo:

  • La adición no es asociativa.
  • La ley distributiva no se cumple.
  • Hay números de coma flotante sin inversos.

Podría seguir. No es posible especificar un tipo aritmético de tamaño fijo que satisfaga todas las propiedades de la aritmética real que conocemos y amamos. El comité 754 tiene que decidir doblar o romper algunos de ellos. Esto está guiado por algunos principios bastante simples:

  1. Cuando podemos, igualamos el comportamiento de la aritmética real.
  2. Cuando no podemos, tratamos de hacer que las violaciones sean tan predecibles y tan fáciles de diagnosticar como sea posible.

Con respecto a su comentario "eso no significa que la respuesta correcta sea falsa", esto es incorrecto. El predicado (y < x) pregunta si y es menor que x . Si y es NaN, entonces no es menor que cualquier valor de coma flotante x , por lo que la respuesta es necesariamente falsa.

Mencioné que la tricotomía no es válida para los valores de punto flotante. Sin embargo, hay una propiedad similar que se mantiene. Cláusula 5.11, párrafo 2 de la norma 754-2008:

Son posibles cuatro relaciones mutuamente excluyentes: menor que, igual, mayor que y desordenado. El último caso surge cuando al menos un operando es NaN. Cada NaN se comparará desordenada con todo, incluyéndose a sí misma.

En lo que respecta a la escritura de código adicional para manejar NaNs, generalmente es posible (aunque no siempre fácil) estructurar su código de tal manera que los NaN se caigan adecuadamente, pero esto no siempre es así. Cuando no lo es, puede ser necesario algún código adicional, pero ese es un pequeño precio a pagar por la conveniencia que el cierre algebraico trajo a la aritmética de punto flotante.

Anexo: Muchos comentaristas han argumentado que sería más útil preservar la reflexividad de la igualdad y la tricotomía con el argumento de que adoptar NaN! = NaN no parece preservar ningún axioma familiar. Confieso que tengo cierta simpatía por este punto de vista, así que pensé que volvería a revisar esta respuesta y daría un poco más de contexto.

Mi entendimiento de hablar con Kahan es que NaN! = NaN se originó a partir de dos consideraciones pragmáticas:

  • Que x == y debe ser equivalente a x - y == 0 siempre que sea posible (más allá de ser un teorema de la aritmética real, esto hace que la implementación de la comparación del hardware sea más eficiente en el espacio, lo cual era de suma importancia en el momento en que se desarrolló el estándar: tenga en cuenta, sin embargo, que esto se viola para x = y = infinito, por lo que no es una buena razón por sí misma; podría haber sido razonablemente doblado a (x - y == 0) or (x and y are both NaN) ) .

  • Más importante aún, no había un predicado isnan( ) en el momento en que NaN se formalizó en la aritmética 8087; era necesario proporcionar a los programadores un medio conveniente y eficiente para detectar valores de NaN que no dependían de que los lenguajes de programación proporcionaran algo como isnan( ) que podría llevar muchos años. Citaré los propios escritos de Kahan sobre el tema:

Si no hubiera forma de deshacerse de los NaN, serían tan inútiles como los indefinidos en los CRAY; tan pronto como se encontró uno, el cálculo se detendría mejor en lugar de continuar por un tiempo indefinido hasta llegar a una conclusión indefinida. Es por eso que algunas operaciones sobre NaN deben entregar resultados que no sean de NaN. ¿Qué operaciones? ... Las excepciones son los predicados C "x == x" y "x! = X", que son respectivamente 1 y 0 para cada número infinito o finito x, pero se invierten si x no es un número (NaN); estos proporcionan la única distinción simple y excepcional entre NaN y números en idiomas que carecen de una palabra para NaN y un predicado IsNaN (x).

Tenga en cuenta que esta es también la lógica que descarta devolver algo así como un "No-A-booleano". Quizás este pragmatismo fuera de lugar, y el estándar debería haber requerido isnan( ) , pero eso hubiera hecho que el NaN fuera casi imposible de usar de manera eficiente y conveniente durante varios años mientras el mundo esperaba la adopción del lenguaje de programación. No estoy convencido de que hubiera sido una compensación razonable.

Para ser franco: el resultado de NaN == NaN no va a cambiar ahora. Mejor aprender a vivir con eso que quejarse en internet. Si quiere argumentar que también debería existir una relación de orden adecuada para contenedores, recomendaría que su lenguaje de programación favorito implemente el predicado de orden total estandarizado en IEEE-754 (2008). El hecho de que no se haya referido ya a la validez de la preocupación de Kahan que motivó la situación actual.


La respuesta simplificada es que un NaN no tiene un valor numérico, por lo que no hay nada que se pueda comparar con nada más.

Podría considerar probar y reemplazar sus NaN con + INF si desea que actúen como + INF.


NaN es una nueva instancia implícita (de un tipo especial de error de tiempo de ejecución). Eso significa NaN !== NaN por la misma razón que el new Error !== new Error ;

Y tenga en cuenta que dicha implicación también se ve fuera de los errores, por ejemplo, en el contexto de expresiones regulares significa /a/ !== /a/ que es solo la sintaxis de azúcar para el new RegExp(''a'') !== new RegExp(''a'')


No conozco la justificación del diseño, pero aquí hay un extracto del estándar IEEE 754-1985:

"Será posible comparar números de punto flotante en todos los formatos compatibles, incluso si los formatos de los operandos son diferentes. Las comparaciones son exactas y nunca se desbordan ni se desbordan. Son posibles cuatro relaciones mutuamente excluyentes: menor que, igual, mayor que y no ordenada El último caso surge cuando al menos un operando es NaN. Cada NaN se comparará desordenada con todo, incluso con él ".


Para lanzar en otra analogía. Si te entrego dos cajas y te digo que ninguna de ellas contiene una manzana, ¿me dirías que las cajas contienen la misma cosa?

NaN no contiene información sobre lo que es algo, solo lo que no es. Por lo tanto, nunca se puede decir que estos elementos sean iguales.


Para mí, la forma más fácil de explicarlo es:

Tengo algo y si no es una manzana, ¿entonces es una naranja?

No se puede comparar NaN con otra cosa (incluso a sí misma) porque no tiene un valor. También puede ser cualquier valor (excepto un número).

Tengo algo y si no es igual a un número, ¿entonces es una cadena?


Porque las matemáticas es el campo donde los números "simplemente existen". En informática, debe inicializar esos números y mantener su estado de acuerdo con sus necesidades. En esos viejos tiempos, la inicialización de la memoria funcionaba de la manera en que nunca podría confiar. Nunca podría permitirse pensar en esto "oh, eso se inicializaría con 0xCD todo el tiempo, mi algo no se romperá" .

Por lo tanto, necesita un disolvente adecuado que no se mezcle , que sea lo suficientemente pegajoso para no dejar que su algoritmo sea absorbido y roto. Los buenos algoritmos que involucran números funcionan principalmente con las relaciones, y esos si () se omitirán las relaciones.

Esto es solo la grasa que se puede poner en una nueva variable en la creación, en lugar de programar un infierno aleatorio desde la memoria de la computadora. Y su algoritmo sea lo que sea, no se romperá.

Luego, cuando descubres de repente que tu algoritmo está produciendo NaNs, es posible limpiarlo, examinando cada rama una por una. Una vez más, la regla "siempre falsa" está ayudando mucho en esto.


Respuesta muy corta:

Porque lo siguiente: nan / nan = 1 NO debe contener. De lo contrario, inf/inf sería 1.

(Por lo tanto, nan no puede ser igual a nan . En cuanto a > o < , si nan respetara cualquier relación de orden en un conjunto que satisfaga la propiedad arquimediana, tendríamos nuevamente nan / nan = 1 en el límite).


Se puede pensar en NaN como un estado / número indefinido. similar al concepto de 0/0 no definido o sqrt (-3) (en el sistema de números reales donde vive el punto flotante).

NaN se utiliza como una especie de marcador de posición para este estado indefinido. Hablando matemáticamente, indefinido no es igual a indefinido. Tampoco puede decir que un valor indefinido es mayor o menor que otro valor indefinido. Por lo tanto todas las comparaciones devuelven falso.

Este comportamiento también es ventajoso en los casos en los que se compara sqrt (-3) con sqrt (-2). Ambos devolverían NaN pero no son equivalentes a pesar de que devuelven el mismo valor. Por lo tanto, tener la igualdad siempre devuelve falso cuando se trata de NaN es el comportamiento deseado.


Si bien estoy de acuerdo en que las comparaciones de NaN con cualquier número real deben estar desordenadas, creo que hay una razón justa para comparar NaN consigo mismo. ¿Cómo, por ejemplo, uno descubre la diferencia entre la señalización de NaN y la de NaN silenciosa? Si consideramos las señales como un conjunto de valores booleanos (es decir, un vector de bits), podríamos preguntarnos si los vectores de bits son iguales o diferentes y ordenar los conjuntos en consecuencia. Por ejemplo, al descodificar un exponente máximo sesgado, si el significando se dejara desplazado para alinear el bit más significativo del significante en el bit más significativo del formato binario, un valor negativo sería un NaN silencioso y cualquier valor positivo Ser una señalización de NaN. Por supuesto, el cero está reservado para el infinito y la comparación no estaría ordenada. La alineación de MSB permitiría la comparación directa de señales incluso desde diferentes formatos binarios. Dos NaN con el mismo conjunto de señales serían equivalentes y darían significado a la igualdad.


Solo parece peculiar porque la mayoría de los entornos de programación que permiten NaN no permiten también la lógica de 3 valores. Si metes la lógica de 3 valores en la mezcla, se vuelve consistente:

  • (2.7 == 2.7) = verdadero
  • (2.7 == 2.6) = falso
  • (2.7 == NaN) = desconocido
  • (NaN == NaN) = desconocido

Incluso .NET no proporciona un bool? operator==(double v1, double v2) bool? operator==(double v1, double v2) operador, por lo que todavía está atascado con el resultado tonto (NaN == NaN) = false .


Supongo que NaN (No es un número) significa exactamente eso: este no es un número y, por lo tanto, compararlo no tiene sentido.

Es un poco como la aritmética en SQL con operandos null : todos resultan en null .

Las comparaciones para números de punto flotante comparan valores numéricos. Por lo tanto, no se pueden utilizar para valores no numéricos. Por lo tanto, NaN no puede compararse en un sentido numérico.