2012-06-13 18 views
14
int i = 0, j = 0; 
double nan1 = (double)0/0; 
double nan2 = (double)0/0; 
double nan3 = (double)i/j; 
System.out.println(Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits(nan2)); 
System.out.println(Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits((double)0/0)); 
System.out.println(Double.doubleToRawLongBits(nan3) == Double.doubleToRawLongBits(nan2)); 

de salida:Confusión sobre NaN en Java

true 
true 
false 

favor me ayude cómo se produjo la salida de true dos primeros y false para la última. Por favor dígame qué es el trabajo real del método Double.doubleToRawLongBits().

+0

Se están produciendo dos 'NaN's diferentes. Uno es '0x7ff8000000000000' y el otro es' 0xfff8000000000000'. El hardware parece dar '0xfff8000000000000' para' 0/0'. Pero la propagación constante del compilador usa '0x7ff8000000000000' en su lugar. A menos que haya pasado por alto algo, esto parece un error para mí. – Mysticial

+0

¿Qué sucede si habilita 'strictfp' para el método? – Joey

+5

Además: »En los formatos de almacenamiento de coma flotante conformes con el estándar IEEE 754, los NaN se identifican mediante patrones de bits predefinidos específicos exclusivos de los NaN. El bit de signo no importa. «([Wikipedia] (http://en.wikipedia.org/wiki/NaN#Encoding)) – Joey

Respuesta

3

Por favor, intente ejecutar código siguiente para ver los valores:

public class Test 
{ 
    public static void main(String[] args){ 
     int i = 0, j = 0; 
     double nan1 = (double)0/0; 
     double nan2 = (double)0/0; 
     double nan3 = (double)i/j; 
     System.out.println(Double.doubleToRawLongBits(nan1) + " == "+ Double.doubleToRawLongBits(nan2) + " is " + 
      (Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits(nan2))); 
     System.out.println(Double.doubleToRawLongBits(nan1) + " == "+ Double.doubleToRawLongBits((double)0/0) + " is " + 
      (Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits((double)0/0))); 
     System.out.println(Double.doubleToRawLongBits(nan3) + " == "+ Double.doubleToRawLongBits(nan2) + " is " + 
      (Double.doubleToRawLongBits(nan3) == Double.doubleToRawLongBits(nan2))); 
    } 
} 

en mi Mac, Produce salida siguiente:

9221120237041090560 == 9221120237041090560 is true 
9221120237041090560 == 9221120237041090560 is true 
-2251799813685248 == 9221120237041090560 is false 

este escollo se documenta en el Javadoc para la doubleToRawLongBits method:

Si el argumento es NaN, el resultado es el largo entero que representa el valor real NaN. A diferencia del método doubleToLongBits, doubleToRawLongBits no contrae todos los patrones de bits que codifican un NaN a un único valor NaN "canónico".

+2

¿Responde esto a la pregunta? – Mysticial

+0

El código es el mismo que en la pregunta tan bastante superfluo; pero al seguir el enlace a los documentos * no * responde la pregunta, aunque con una indirección. Edité la parte relevante como una cita. Pero diría que todo lo anterior es solo basura que no tiene nada que ver con una respuesta. – Joey

+0

No creo que esto resuelva mi confusión sobre el problema. –

1

Creo que Java sigue a IEEE 754. En este caso NaN tiene más de una posible representación de bits. Las dos representaciones en su caso difieren en el bit "signo". El valor del bit de signo parece no estar definido por el estándar y generalmente se ignora. Entonces ambos valores son correctos. Ver http://en.wikipedia.org/wiki/NaN

0

La razón es porque cuando se divide una variable doble 0 por 0 se devuelve NaN, por lo que el método tampoco tienen una única representación canónica en binario, por lo que puede devolver el binario de NaN como 7F F8 00 00 00 00 00 00 o F8 FF 00 00 00 00 00 00.

a pesar de que técnicamente representan lo mismo, que es NaN, su diferente en representación binaria.

2

El estándar IEEE 754 permite diferentes patrones de bits para NaN. Para los propósitos de cálculo y de comparación todos ellos deben funcionar de la misma (es decir NaN no compara igual a sí mismo, no se ordena y cada cálculo que implica NaN es NaN sí mismo). Con doubleToRawLongBits obtienes el patrón de bits exacto utilizado. Esto también se detalla en el JLS:

En su mayor parte, la plataforma Java trata a valores NaN de un tipo dado como aunque colapsado en un solo valor canónica (y por lo tanto esta especificación nor- Mally se refiere a una NaN arbitrario como si fuera un valor canónico). Sin embargo, la versión 1.3 la plataforma Java métodos introducidos permiten al programador para distinguir entre valores NaN: los métodos y Float.floatToRawIntBitsDouble.double- ToRawLongBits. El lector interesado se refiere a las especificaciones para las clases Float y Double para obtener más información.

En el caso de que el bit de signo es diferente, en este caso me puedo dirigir a Wikipedia, que resume esta manera concisa:

En IEEE 754 formatos de almacenamiento de punto flotante que sigan los estándares, se identifican NaNs mediante patrones de bits predefinidos específicos únicos para NaN. El bit de signo no importa.

Ambos valores son NaN, solo usan diferentes bits para representar eso. Algo que es permitido por IEEE 754 y en este caso probablemente proviene del compilador que sustituye Double.NaN por un cálculo constante que resulta en NaN mientras que el hardware real da un resultado diferente, como sospechaba Mysticial en un comentario a la pregunta ya.

+0

Joey es el compilador que elige diferentes patrones de bits aleatoriamente para los valores NaN. Si no, entonces ¿por qué el mismo patrón para nan1 y nan2 pero un patrón diferente para nan3? –