¿Por qué Double.NaN == Double.NaN devuelve falso?

Estaba estudiando preguntas de OCPJP y encontré este código extraño:

public static void main(String a[]) { System.out.println(Double.NaN==Double.NaN); System.out.println(Double.NaN!=Double.NaN); } 

Cuando ejecuté el código, obtuve:

 false true 

¿Cómo es false el resultado cuando estamos comparando dos cosas que tienen el mismo aspecto? ¿Qué significa NaN ?

NaN significa “No es un número”.

Especificación del lenguaje Java (JLS) tercera edición dice :

Una operación que se desborda produce un infinito con signo, una operación que subdesborda produce un valor desnormalizado o un cero firmado, y una operación que no tiene un resultado matemáticamente definido produce NaN. Todas las operaciones numéricas con NaN como operando producen NaN como resultado. Como ya se ha descrito, NaN no está ordenado, por lo que una operación de comparación numérica que involucre uno o dos NaNs devuelve false y cualquier comparación != involucre a NaN devuelve true , incluyendo x!=x cuando x es NaN.

NaN por definición no es igual a ningún número, incluido NaN. Esto es parte del estándar IEEE 754 e implementado por la CPU / FPU. No es algo a lo que la JVM tiene que agregarle ninguna lógica para ser compatible.

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

Una comparación con un NaN siempre devuelve un resultado desordenado incluso cuando se compara consigo mismo. … Los predicados de igualdad y desigualdad no son de señalización, por lo que x = x return false se puede usar para probar si x es un NaN silencioso.

Java trata a todos los NaN como NaN silencioso.

Por qué esa lógica

NaN significa Not a Number . ¿Qué no es un número? Cualquier cosa. Puedes tener cualquier cosa en un lado y cualquier cosa en el otro lado, por lo que nada garantiza que ambos sean iguales. NaN se calcula con Double.longBitsToDouble(0x7ff8000000000000L) y como puede ver en la documentación de longBitsToDouble :

Si el argumento tiene algún valor en el rango 0x7ff0000000000001L través de 0x7fffffffffffffffL o en el rango de 0xfff0000000000001L a 0xffffffffffffffffL , el resultado es un NaN .

Además, NaN se trata lógicamente dentro de la API.


Documentación

 /** * A constant holding a Not-a-Number (NaN) value of type * {@code double}. It is equivalent to the value returned by * {@code Double.longBitsToDouble(0x7ff8000000000000L)}. */ public static final double NaN = 0.0d / 0.0; 

Por cierto, NaN se prueba como su muestra de código:

 /** * Returns {@code true} if the specified number is a * Not-a-Number (NaN) value, {@code false} otherwise. * * @param v the value to be tested. * @return {@code true} if the value of the argument is NaN; * {@code false} otherwise. */ static public boolean isNaN(double v) { return (v != v); } 

Solución

Lo que puedes hacer es usar compare / compare :

Double.NaN es considerado por este método como igual a él y mayor que todos los demás valores double (incluido Double.POSITIVE_INFINITY ).

 Double.compare(Double.NaN, Double.NaN); Double.NaN.compareTo(Double.NaN); 

O, equals :

Si this argument y ambos representan Double.NaN , el método equals devuelve true , aunque Double.NaN==Double.NaN tiene el valor false .

 Double.NaN.equals(Double.NaN); 

Puede que no sea una respuesta directa a la pregunta. Pero si quiere verificar si algo es igual a Double.NaN debería usar esto:

 double d = Double.NaN Double.isNaN(d); 

Esto devolverá true

El javadoc para Double.NaN lo dice todo:

Una constante que contiene un valor Not-a-Number (NaN) de tipo double . Es equivalente al valor devuelto por Double.longBitsToDouble(0x7ff8000000000000L) .

Curiosamente, la fuente de Double define NaN así:

 public static final double NaN = 0.0d / 0.0; 

El comportamiento especial que describes está conectado a la JVM.

NaN es un valor especial que denota “no un número”; es el resultado de ciertas operaciones aritméticas inválidas, como sqrt(-1) , y tiene la propiedad (a veces molesta) que NaN != NaN .

según, el estándar IEEE para aritmética de coma flotante para números de precisión doble,

La representación estándar de coma flotante de doble precisión IEEE requiere una palabra de 64 bits, que se puede representar como numerada de 0 a 63, de izquierda a derecha

enter image description here dónde,

 S: Sign – 1 bit E: Exponent – 11 bits F: Fraction – 52 bits 

Si E=2047 (todas las E son 1 ) y F es distinto de cero, entonces V=NaN (“No es un número”)

Lo que significa,

Si todos los bits E son 1, y si hay un bit distinto de cero en F entonces el número es NaN .

por lo tanto, entre otros, todos los siguientes números son NaN ,

 0 11111111 0000000000000000010000000000000000000000000000000000 = NaN 1 11111111 0000010000000000010001000000000000001000000000000000 = NaN 1 11111111 0000010000011000010001000000000000001000000000000000 = NaN 

En particular, no puedes probar

 if (x == Double.NaN) 

para verificar si un resultado particular es igual a Double.NaN , porque todos los valores de “no un número” se consideran distintos. Sin embargo, puede usar el método Double.isNaN :

 if (Double.isNaN(x)) // check whether x is "not a number" 

Ningún número representa el resultado de las operaciones cuyo resultado no es representable con un número. La operación más famosa es 0/0, cuyo resultado no se conoce.

Por esta razón, NaN no es igual a nada (incluidos otros valores que no son números). Para obtener más información, simplemente consulte la página de wikipedia: http://en.wikipedia.org/wiki/NaN

Según este enlace , tiene varias situaciones y es difícil de recordar. Así es como los recuerdo y los distingo. NaN significa “matemáticamente indefinido”, por ejemplo: “el resultado de 0 dividido por 0 no está definido” y porque no está definido, por lo que “la comparación relacionada con indefinido no está definida”. Además, funciona más como premisas matemáticas. Por otro lado, tanto el infinito positivo como el negativo están predefinidos y son definitivos, por ejemplo “infinito positivo o negativo grande está bien definido matemáticamente”.

    Intereting Posts