tipos - ¿Por qué Java implícitamente(sin conversión) convierte un `long` en un` float`?
tipos de variables en java netbeans (4)
Cada vez que creo que entiendo sobre conversión y conversión, encuentro otro comportamiento extraño.
long l = 123456789L;
float f = l;
System.out.println(f); // outputs 1.23456792E8
Dado que un long
tiene una profundidad de bit mayor que un float
, esperaría que se requiera un molde explícito para que se pueda compilar. Y no es sorprendente que veamos que hemos perdido precisión en el resultado.
¿Por qué no se requiere un yeso aquí?
Aunque tienes razón en que una larga usa más bits internamente que una coma flotante, el lenguaje Java funciona en una ruta de ensanchamiento:
byte -> corto -> int -> largo -> flotante -> doble
Para convertir de izquierda a derecha (una conversión de ampliación), no es necesario el envío (por lo que está permitido el tiempo de flotación). Para convertir de derecha a izquierda (una conversión de estrechamiento) es necesario un lanzamiento explícito.
En algún lugar oí esto. Float puede almacenar en forma exponencial como lo escribimos. ''23500000000'' se almacena como ''2.35e10''. Así que, el flotador tiene espacio para ocupar el rango de valores de largo. El almacenamiento en forma exponencial es también el motivo de la pérdida de precisión.
La Especificación del lenguaje Java, Capítulo 5: Conversión y promoción aborda este problema:
5.1.2 Ampliación de conversión primitiva
Las siguientes 19 conversiones específicas sobre tipos primitivos se llaman conversiones primitivas de ensanchamiento:
- byte a corto, int, largo, flotante o doble
- corto a int, largo, flotante o doble
- char a int, long, float o double
- int a long, float o double
- largo para flotar o doble
- flotar para duplicar
Las conversiones primitivas ampliadas no pierden información sobre la magnitud general de un valor numérico.
...
La conversión de un valor int o un valor largo en float, o de un valor largo en double, puede dar como resultado la pérdida de precisión, es decir, el resultado puede perder algunos de los bits menos significativos del valor. En este caso, el valor del punto flotante resultante será una versión redondeada correctamente del valor entero
Para decirlo de otra manera, el JLS distingue entre una pérdida de magnitud y una pérdida de precisión .
int
to byte
por ejemplo, es una pérdida (potencial) de magnitud porque no puede almacenar 500 en un byte
.
long
para float
es una pérdida potencial de precisión, pero no de magnitud, porque el rango de valores para los flotadores es mayor que el de los largos.
Entonces la regla es:
- Pérdida de magnitud: requiere conversión explícita;
- Pérdida de precisión: no se requiere conversión.
¿Sutil? Por supuesto. Pero espero que eso lo aclare.
Se podría pedir la misma pregunta de long
para double
: ambas conversiones pueden perder información.
La Sección 5.1.2 de la Especificación de Lenguaje Java dice:
Las conversiones primitivas ampliadas no pierden información sobre la magnitud general de un valor numérico. De hecho, las conversiones que se amplían de un tipo integral a otro tipo integral no pierden ninguna información; el valor numérico se conserva exactamente. Las conversiones que se amplían de float a double en las expresiones strictfp también conservan el valor numérico exactamente; sin embargo, dichas conversiones que no son strictfp pueden perder información sobre la magnitud general del valor convertido.
La conversión de un valor int o un valor largo en float, o de un valor largo en double, puede dar como resultado la pérdida de precisión, es decir, el resultado puede perder algunos de los bits menos significativos del valor. En este caso, el valor del punto flotante resultante será una versión redondeada correctamente del valor entero, utilizando el modo IEEE 754 redondeado a más cercano (§4.2.4).
En otras palabras, aunque pueda perder información, sabe que el valor seguirá estando en el rango general del tipo de destino.
La elección ciertamente podría haberse hecho para exigir que todas las conversiones implícitas no pierdan ninguna información, por lo que int
y long
para float
habría sido explícito y long
para double
habría sido explícito. ( int
al double
está bien, un double
tiene la precisión suficiente para representar con precisión todos los valores int
).
En algunos casos eso hubiera sido útil, en algunos casos no. El diseño del lenguaje se trata de compromiso; no puedes ganarlos a todos. No estoy seguro de qué decisión habría tomado ...