2012-07-16 17 views
5

Duplicar posibles:
Retain precision with Doubles in javade Java de doble precisión con la constante multiplicación/división

¿Conoce la diferencia entre estas dos operaciones en Java.

final double m1 = 11d/1e9; // gives 1.1e-8 
final double m2 = 11d * 1e-9; // gives 1.1000000000000001e-8 

Veo en el bytecode generado que el resultado precompilado de m2 ya no es lo que esperaba.
En la salida de javap -verbose -c puedo ver el siguiente valor:

const #3 = double 1.1E-8d; 
[...] 
const #6 = double 1.1000000000000001E-8d; 

Cuando uso M1 o M2 en otras expresiones, que no tienen el mismo resultado.

Cuando intento lo mismo en C, m1 y m2 es estrictamente 1.1E-8

Creo que mi problema es en la forma de Java maneja doble cómputo de precisión pero no puedo explicarme lo que extraño.

Respuesta

1

El la diferencia que tienes es que 1e9 es exactamente representable y 1e-9 que no es exactamente representable. Un pequeño error de representación da como resultado un error aritmético que puede ver.

System.out.println(new BigDecimal(1e9)); 
System.out.println(new BigDecimal(1e-9)); 

impresiones

1000000000 
1.0000000000000000622815914577798564188970686927859787829220294952392578125E-9 

La diferencia no es si usted ha usado * o /, sino que ha utilizado un número entero en un caso y una fracción en la otra.

System.out.println(11 * 1e9); 
System.out.println(11 * 1e-9); 

impresiones

1.1E10 
1.1000000000000001E-8 
+0

Ok esa es la explicación para Java, pero ahora ¿por qué cuando ejecuto el mismo código en C tengo toda la precisión que necesitaba? – Joker

+0

El compilador de C optimizará el código * mucho * más que 'javac'. Esto puede significar que podría traducir '/ 1e-9' a' * 1e9' porque a) es más rápido yb) más preciso.El compilador de Java realiza muy pocas optimizaciones, esto se deja al JIT, lo que también significa que el código optimizado y no optimizado debe hacer lo mismo; de lo contrario, vería un cambio en el comportamiento mientras se ejecuta el programa. La conversión de un 'doble' a una cadena es diferente en C y Java también, pero es menos probable que sea la causa de la diferencia. En ambos casos, usan la misma FPU. –

+1

También el compilador de C podría hacer uso de los cómputos/cómputos de punto flotante de 80 bits que tiene su computadora. Esto depende de la plataforma y solo está disponible en procesadores x86/x64. Java se comportará igual en todas las plataformas, por lo que solo usará coma flotante de 64 bits, incluso si el punto flotante de 80 bits está disponible. –

3

No hay diferencia entre Java y C, ambos respetan el estándar de coma flotante IEEE. La única diferencia puede ser la forma de imprimirlo. El número exacto 1.1e-8 no es representable como double. La diferencia en el rendimiento puede atribuirse a los detalles sobre cómo se acumuló el error de representación y a qué redondeo se utiliza para imprimir el resultado.

+0

sí, pero se divide 1 a 10^9 – Pooya

+0

Creo que la diferencia es sólo en la cantidad de error se acumula, en donde la segunda línea a pocos pasos por encima del umbral que se imprime. –

0

Si utiliza BigDecimal de la siguiente manera:

BigDecimal a=new BigDecimal(1e-9); 
BigDecimal b=new BigDecimal(11); 
System.out.println(a.multiply(b).toString()); 

verá que su número es

1.10000000000000006850975060355784206078677556206457666121423244476318359375E-8 

JVM redondea el número y la cambia a:

1.1000000000000001e-8 
Cuestiones relacionadas