es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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)).

Tags:  , ,

Answer

  1. Avatar for 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.

Comments are closed.