2010-08-05 22 views
182

Tengo que calcular algunas variables de coma flotante y mi colega me sugiere usar BigDecimal en lugar de double ya que será más preciso. Pero quiero saber de qué se trata y cómo aprovechar al máximo BigDecimal?Doble contra BigDecimal?

+0

Echa un vistazo a este; http://stackoverflow.com/questions/322749/retain-precision-with-doubles-in-java –

Respuesta

275

A BigDecimal es una forma exacta de representar números. A Double tiene una cierta precisión. Trabajar con dobles de varias magnitudes (digamos d1=1000.0 y d2=0.001) puede ocasionar que el 0.001 se pierda al sumar cuando la diferencia de magnitud es tan grande. Con BigDecimal esto no sucedería.

La desventaja de BigDecimal es que es más lento, y es un poco más difícil de algoritmos del programa de esa manera (debido a +-* y / no se sobrecargue).

Si está tratando con dinero, o la precisión es imprescindible, use BigDecimal. De lo contrario, Doubles tienden a ser lo suficientemente buenos.

Yo te recomiendo leer el javadoc de BigDecimal ya que explican las cosas mejor que yo aquí :)

+0

Sí, estoy calculando el precio de stock, así que creo que BigDecimal es útil en este caso. –

+5

@Truong Ha: cuando trabaje con los precios, quiere usar BigDecimal. Y si los almacena en la base de datos, quiere algo similar. – extraneon

+63

Decir que "BigDecimal es una forma exacta de representar números" es engañoso. 1/3 y 1/7 no pueden expresarse exactamente en un sistema numérico de base 10 (BigDecimal) o en un sistema numérico de base 2 (flotante o doble). 1/3 podría expresarse exactamente en base 3, base 6, base 9, base 12, etc. y 1/7 podría expresarse exactamente en base 7, base 14, base 21, etc.Las ventajas de BigDecimal son que es una precisión arbitraria y que los humanos están acostumbrados a los errores de redondeo que obtienes en la base 10. –

32

Hay dos diferencias principales: de doble

  • precisión arbitraria, de manera similar a lo que pueden BigInteger contiene número de precisión arbitraria y tamaño
  • Base 10 en lugar de la Base 2, un BigDecimal es una escala n * 10^donde n es un número entero grande y la escala puede considerarse como el número de dígitos para mover el punto decimal o derecha

La razón por la que debe usar BigDecimal para cálculos monetarios no es que pueda representar ningún número, sino que puede representar todos los números que se pueden representar en noción decimal y que incluyen prácticamente todos los números en el mundo monetario (nunca transfiera 1/3 $ a alguien).

+0

Esta respuesta realmente explica la diferencia y la razón de usar BigDecimal sobre el doble. Las preocupaciones sobre el rendimiento son secundarias. – Vortex

5

BigDecimal es la biblioteca numérica de precisión arbitraria de Oracle. BigDecimal es parte del lenguaje Java y es útil para una variedad de aplicaciones que van desde la financiera a la científica (que es donde tipo de am).

No hay nada malo con el uso de dobles para ciertos cálculos. Supongamos, sin embargo, que desea calcular Math.Pi * Math.Pi/6, es decir, el valor de la función Riemann Zeta para un argumento real de dos (un proyecto en el que estoy trabajando actualmente). La división de coma flotante te presenta un doloroso problema de error de redondeo.

BigDecimal, por otro lado, incluye muchas opciones para calcular expresiones con precisión arbitraria. El complemento, multiplicar y dividir los métodos como se describe en la documentación de Oracle a continuación "tomar el lugar" de +, *, y/en BigDecimal Java Mundial:

http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html

El método compareTo es especialmente útil en tiempo y para bucles.

Tenga cuidado, sin embargo, en su uso de constructores para BigDecimal. El constructor de cadenas es muy útil en muchos casos. Por ejemplo, el código

BigDecimal onethird = new BigDecimal ("0.33333333333 ");

utiliza una representación de cadena de 1/3 para representar ese número infinitamente repetitivo con un grado específico de precisión. El error de redondeo es más probable en algún lugar tan profundo dentro de la JVM que los errores de redondeo no perturbará la mayoría de sus cálculos prácticos. Sin embargo, según mi experiencia personal, el método setScale es importante en estos aspectos, como se puede ver en la documentación de Oracle.

+0

BigDecimal es * parte * de * biblioteca numérica de precisión arbitraria * Java *. 'In-house' no tiene sentido en este contexto, especialmente porque fue escrito por IBM. – EJP

+0

@EJP: revisé la clase BigDecimal y descubrí que solo una parte de ella está escrita por IBM. Comentario de copyright debajo: '/ * * Porciones Copyright IBM Corporation, 2001. Todos los derechos reservados. */' – realPK

-7

Primitive numeric Los tipos son útiles para almacenar valores individuales en la memoria, pero cuando se trata de cálculos utilizando tipos dobles y flotantes, hay un problema con el redondeo. Esto sucede porque la representación de la memoria no se corresponde exactamente con el valor. Por ejemplo, un valor doble es se supone que toma 64 bits, pero Java no utiliza todos los 64 bits. Solo almacena lo que cree que son las partes importantes del número. Por lo tanto, puede llegar a los valores incorrectos al agregar valores del tipo flotante o doble. Puede ser este video https://youtu.be/EXxUSz9x7BM explicará más

+3

¿Eres el autor de ese video? Si no lo eres, has elegido una de las peores explicaciones para copiar y pegar textualmente como respuesta. Si es así, debería dedicar más tiempo a investigar cómo funciona el "doble" antes de hacer videos. –

+0

Soy el autor. ¿Qué crees que es correcto con la respuesta? –

+3

"Java no usa los 64 bits. Solo almacena lo que cree que son las partes importantes del número ". No tiene sentido. Java siempre usa 64 bits, y almacena valores en el formato IEEE 754 binary64, no lo que cree que es importante. –

91

Mi inglés no es bueno, así que simplemente voy a escribir un ejemplo simple aquí.

double a = 0.02; 
    double b = 0.03; 
    double c = b - a; 
    System.out.println(c); 

    BigDecimal _a = new BigDecimal("0.02"); 
    BigDecimal _b = new BigDecimal("0.03"); 
    BigDecimal _c = _b.subtract(_a); 
    System.out.println(_c); 

La salida del programa:

0.009999999999999998 
0.01 

Alguien aún desea utilizar el doble? ;)

+9

I [seguramente] (http://stackoverflow.com/q/42871564/581205). – maaartinus

+2

no puedo creer que esta respuesta obtuviera más de 50 votos. inicializar un nuevo BigDecimal ("0.02") significa que está configurando su escala en 2 decimales, por lo que BigDecimal redondeará el resultado por usted. También puede redondear el doble y obtener 0.01 fácilmente de lo que esperaba. – eldjon

+2

@eldjon Eso no es cierto. Mira este ejemplo: BigDecimal two = new BigDecimal ("2"); BigDecimal eight = new BigDecimal ("8"); System.out.println (two.divide (eight)); Esto imprime 0.25. – Lurr

7

Si desea escribir un valor como 1/7 como valor decimal se obtiene

1/7 = 0.142857142857142857142857142857142857142857... 

con una secuencia infinita de 142857. Sin embargo, ya que sólo se puede escribir un número finito de dígitos que inevitablemente introducirá un error de redondeo (o truncamiento).

Lamentablemente, los números como 1/10 o 1/100 expresados ​​como números binarios con una parte fraccionaria también tienen un número infinito de decimales binarios.

almacenar valores
1/10 = binary 0.000110011001100110... 

dobla como números binarios y, por tanto, podría introducir un error exclusivamente mediante la conversión de un número decimal en un número binario, sin siquiera hacer cualquier aritmética.

Los números decimales (como BigDecimal), por otro lado, almacenan cada dígito decimal como está. Esto significa que un tipo decimal no es más preciso que un punto flotante binario o un tipo de punto fijo en un sentido general (por ejemplo, no puede almacenar 1/7 sin pérdida de precisión), pero es más preciso para números dados con un número finito de dígitos decimales, como suele ser el caso para los cálculos de dinero.

La BigDecimal de Java tiene la ventaja adicional de que puede tener un número arbitrario (pero finito) de dígitos en ambos lados del punto decimal, limitado solo por la memoria disponible.

Cuestiones relacionadas