Convertir de manera segura `float` a `double` sin pérdida de precisión.
Tengo el siguiente problema complicado, demostrado en jshell
11.0.12
y 17.0.1
aquí
jshell> 13.9f
$1 ==> 13.9
jshell> 13.9
$2 ==> 13.9
jshell> (double) 13.9f
$3 ==> 13.899999618530273
Lo mismo ocurre en una clase compilada simple en ambas versiones
strictfp public class Test {
public strictfp static void main(String[] args) {
System.out.format("%s%n", (double) 13.9f);
System.out.format("%s%n", 13.9f);
}
}
╰─➤ java Test
13.899999618530273
13.9
Aunque en 17 advierte que strictfp
ya no es necesario
warning: [strictfp] a partir de la versión 17, todas las expresiones de punto flotante se evalúan estrictamente y ‘strictfp’ no es necesario
El JLS dice esto en la sección 5.1.2
Una conversión primitiva de ampliación no pierde información sobre la magnitud general de un valor numérico en los siguientes casos, donde el valor numérico se conserva exactamente:
• de un tipo integral a otro tipo integral
• de byte, short o char a un tipo de punto flotante
• de int a double
• de float a double
En la versión 14 contenía lo siguiente después de la lista de viñetas
Una conversión primitiva de ampliación de float a double que no es strictfp puede perder información sobre la magnitud general del valor convertido.
¿Según mi comprensión, esto es un error en la implementación? La única forma confiable que he encontrado para realizar esta conversión es Double.parseDouble(Float.toString(13.9f))
.
davy.ai
Esto no es un error en la implementación, sino más bien el resultado de las limitaciones de la aritmética de punto flotante binaria. Los números de punto flotante se almacenan en formato binario, lo que puede causar errores de redondeo al convertir de decimal a binario y viceversa. Esto significa que a veces, al convertir un número de punto flotante de un tipo de datos a otro, se puede perder precisión.
En Java, las conversiones primitivas de ampliación suelen ser seguras si implican pasar de un tipo de datos menos preciso a uno más preciso. Sin embargo, en el caso de convertir un float a un double, la JLS especifica que si la conversión no se realiza en un contexto de
strictfp
, es posible perder información sobre la magnitud total del valor convertido.Por lo tanto, en el caso del ejemplo en
jshell
y en la clase compilada, el resultado de(double) 13.9f
puede no ser exacto debido a la pérdida de precisión involucrada en la conversión primitiva de ampliación.Para evitar este problema, se puede utilizar
Double.parseDouble(Float.toString(13.9f))
como una forma confiable de realizar la conversión de float a double sin perder precisión.