2012-03-28 28 views
10

Mi compañero de trabajo hizo este experimento:doble substracción tema precisión

public class DoubleDemo { 

     public static void main(String[] args) { 
      double a = 1.435; 
      double b = 1.43; 
      double c = a - b; 
      System.out.println(c); 
     } 
} 

Para esta operación de primer grado que esperaba este resultado:

0.005 

Pero inesperadamente la salida fue:

0.0050000000000001155 

¿Por qué el doble falla en una operación tan simple? Y si el doble no es el tipo de datos para este trabajo, ¿qué debería usar?

+0

Gracias por compartir su experimento. +1 – kasavbere

+0

Estoy seguro de que este es un duplicado de –

+0

posible duplicado de [Conservar la precisión con Dobles en java] (http://stackoverflow.com/questions/322749/retain-precision-with-doubles-in-java) –

Respuesta

17

double se almacena internamente como una fracción en binario - como 1/4 + 1/8 + 1/16 + ...

El valor 0.005 - o el valor 1.435 - no puede ser almacenado como una fracción exacta en binario, por lo double no puede almacenar la exacta valor 0.005, y el valor restado no es del todo exacto.

Si te preocupa la aritmética decimal precisa, usa BigDecimal.

También puede encontrar this article de lectura útil.

+0

+ 1 Usa BigDecimal o redondea tu resultado. –

2

doble y flotante son no exactamente números reales.

¡Hay un número infinito de números reales en cualquier rango, pero solo un número finito de bits para representarlos! por esta razón, se esperan errores de redondeo para el doble y flotantes.

El número que obtiene es el número más cercano posible que se puede representar mediante el doble en la representación en coma flotante.

Para obtener más información, es posible que desee leer this article [advertencia: podría ser de alto nivel].

Es posible que desee utilizar BigDecimal para obtener exactamente un número decimal [pero nuevamente encontrará errores de redondeo cuando intente obtener 1/3].

1

double y float aritmética nunca serán exactamente correctas debido al redondeo que ocurre "debajo del capó".

Esencialmente, los dobles y los flotantes pueden tener una cantidad infinita de decimales, pero en la memoria deben estar representados por una cantidad real de bits. Entonces, cuando haces esta aritmética decimal, se produce un procedimiento de redondeo y, a menudo, se reduce en una cantidad muy pequeña si tomas en cuenta todos los decimales.

Como se sugirió anteriormente, si necesita valores completamente exactos, entonces use BigDecimal, que almacena sus valores de manera diferente. Here's the API

+0

No es exacto decir que "nunca" serán exactamente correctos. Sería correcto decir que nunca serán exactamente correctos cuando representen algo más que fracciones cuyo denominador no sea un poder de dos. – supercat

-1
//just try to make a quick example to make b to have the same precision as a has, by using BigDecimal 

private double getDesiredPrecision(Double a, Double b){ 
    String[] splitter = a.toString().split("\\."); 
    splitter[0].length(); // Before Decimal Count 
    int numDecimals = splitter[1].length(); //After Decimal Count 

    BigDecimal bBigDecimal = new BigDecimal(b); 
    bBigDecimal = bBigDecimal.setScale(numDecimals,BigDecimal.ROUND_HALF_EVEN); 

    return bBigDecimal.doubleValue(); 
} 
+0

Eso no responde la pregunta. –

+0

bueno, tienes razón. Solo intenta hacer un pequeño ejemplo en BigDecimal. Ya hay personas respondiendo la pregunta. No es necesario ser repetitivo. – madmaximshen

+0

En SO, las respuestas son para proporcionar una respuesta completa y autónoma. Si sientes que falta algo en otra respuesta, deja un comentario una vez que tengas suficiente reputación. Si cree que puede escribir una mejor respuesta * completa *, hágalo. No publiques "medias respuestas" como esta. –

Cuestiones relacionadas