2012-05-07 14 views
5

hay algo que me desconcierta y no encontré mucha información sobre las especificaciones de VM. Es un poco oscuro y estaría bien si alguien pudiera explicarme.Lanzando un doble a otro tipo numérico

Estas pocas líneas de código .....

double myTest = Double.MAX_VALUE; 

System.out.println("1. float: " + (float)myTest); 
System.out.println("2. int: " + (int)myTest); 
System.out.println("3. short: " + (short)myTest); 
System.out.println("4. byte: " + (byte)myTest); 

..... producir este resultado:

  1. float: Infinity
  2. int: 2147483647
  3. corta: -1
  4. byte: -1

byte, short y int son 8, 16, 32 bit con complemento a dos. float y double son 32 y 64 bit IEEE 754 (see here).

Según mi entender, el valor máximo de double implica que todos los bits de la mantis (52 bits) se cambian a 1. Por lo tanto, no es (muy) sorprendente que un lanzamiento a corto o a byte devuelva -1, es decir todos los bits se cambian a 1. Parece que el elenco mantiene la 'cola' del double para que encaje en 8 bit byte o 16 bit short.

Lo que me sorprende es el elenco int y, en menor medida, el elenco a float. ¿Cómo es posible obtener "2. int: 2147483647" que es 0x7FFFFFFF, el valor máximo mientras que es corto y el byte 3. y 4. son -1?

El elenco de float también es extraño. Si se conservaron los 32 bits en la 'cola' de myTest, ¿no debería generar un NaN?

Respuesta

4

JLS detalla las reglas en la sección 5.1.3 Narrowing Primitive Conversion. Las reglas dependen del tipo de objetivo.

float:

Una conversión primitiva estrechamiento de doble a flotar se rige por las reglas de redondeo IEEE 754 (§4.2.4). Esta conversión puede perder precisión, pero también perder rango, lo que da como resultado un cero flotante de un doble distinto de cero y un infinito flotante de un doble finito. Un NaN doble se convierte en un NaN flotante y un doble infinito se convierte en el infinito flotante con la misma firma.

int y long:

uno de los siguientes dos casos se deben cumplir:

  • ...
  • El valor debe ser demasiado grande (un valor positivo de gran magnitud o infinito positivo), y el resultado del primer paso es el mayor valor representable de tipo int o largo.

byte, char y short:

Si el tipo de destino es byte, char o short, la conversión es de dos pasos. Primero, el double se convierte a long como se explicó anteriormente. A continuación, el long se convierte en el último tipo como sigue:

Una conversión estrechamiento de un entero con signo a un tipo integral T simplemente descarta todos, pero los bits de orden n más bajas, donde n es el número de bits usado para representar tipo T. Además de una posible pérdida de información sobre la magnitud del valor numérico, esto puede hacer que el signo del valor resultante difiera del signo del valor de entrada.

+0

Gracias esto es muy interesante. Así que una vez que el doble se convierte en un int ("con el mayor valor representable" en mi ejemplo), se convierte en un byte o un corto con una filosofía diferente ("descarta todos menos los n bits de orden más bajo"). – Jerome

+0

@ Jerome: Bastante (excepto que creo que el tipo intermedio es 'largo', pero no afecta el resultado). – NPE

+0

Vale la pena señalar que aunque emitir 'double' para' flotar' puede hacer que algunos valores distintos se vuelvan indistinguibles, eso es un problema menor comparado con el hecho de que fundir 'float' en' double' puede hacer que las cosas que se deben considerar indistinguibles en vez ser ordenado * incorrectamente *. Por ejemplo, dado 'float f = 16777217; double d = 16777216.0000001; ', que es más grande - 'f' o' d'? ¿Qué tal 'float ff = 1E38f * 10f; doble dd = 1e300; '? En cuanto a 'ff' y' dd' como "indistinguible" no sería genial, pero decir 'ff> dd' es incorrecto en cientos de órdenes de magnitud. – supercat

Cuestiones relacionadas