java - ¿Por qué Double.NaN== Double.NaN devuelve falso?
floating-point scjp (9)
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 porDouble.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.
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 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
.
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.
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 devuelvetrue
, incluyendox!=x
cuandox
es NaN.
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
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
Según este link , 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".
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
dónde,
S: Sign – 1 bit
E: Exponent – 11 bits
F: Fraction – 52 bits
Si
E=2047
(todas lasE
son1
) yF
es distinto de cero, entoncesV=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"
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 de0x7fffffffffffffffL
o en el rango de0xfff0000000000001L
a0xffffffffffffffffL
, el resultado es unNaN
.
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 valoresdouble
(incluidoDouble.POSITIVE_INFINITY
).
Double.compare(Double.NaN, Double.NaN);
Double.NaN.compareTo(Double.NaN);
O, equals
:
Si
this
argument
y ambos representanDouble.NaN
, el métodoequals
devuelvetrue
, aunqueDouble.NaN==Double.NaN
tiene el valorfalse
.
Double.NaN.equals(Double.NaN);