Duplo vs. BigDecimal?

Eu tenho que calcular algumas variables ​​de ponto flutuante e meu colega me sugere usar BigDecimal vez de double pois será mais preciso. Mas eu quero saber o que é e como aproveitar ao máximo o BigDecimal ?

   

Um BigDecimal é uma maneira exata de representar números. Um Double tem uma certa precisão. Trabalhar com duplas de várias magnitudes (digamos, d1=1000.0 e d2=0.001 ) poderia resultar na queda total de 0.001 quando sumdo como a diferença de magnitude é tão grande. Com BigDecimal isso não aconteceria.

A desvantagem do BigDecimal é que ele é mais lento, e é um pouco mais difícil programar algoritmos dessa maneira (devido a + - * e / não sobrecarregados).

Se você está lidando com dinheiro, ou precisão é uma obrigação, use BigDecimal . Caso contrário, as Doubles tendem a ser boas o suficiente.

Eu recomendo ler o javadoc do BigDecimal como eles explicam as coisas melhor do que eu faço aqui 🙂

Meu inglês não é bom, então vou escrever um exemplo simples aqui.

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

Saída do programa:

 0.009999999999999998 0.01 

Alguém ainda quer usar o dobro? 😉

Existem duas diferenças principais do dobro:

  • Precisão arbitrária, similarmente ao BigInteger, eles podem conter um número de precisão e tamanho arbitrários
  • Base 10 em vez de Base 2, um BigDecimal é n * 10 ^ scale onde n é um número inteiro assinado grande arbitrário e escala pode ser considerada como o número de dígitos para mover o ponto decimal para a esquerda ou para a direita

A razão pela qual você deve usar o BigDecimal para cálculos monetários não é que ele possa representar qualquer número, mas que pode representar todos os números que podem ser representados na noção decimal e que incluem virtualmente todos os números no mundo monetário (você nunca transfere 1/3 $ para alguém).

Se você quiser anotar um valor como 1/7 como valor decimal,

 1/7 = 0.142857142857142857142857142857142857142857... 

com uma sequência infinita de 142857. Mas como você só pode escrever um número finito de dígitos, inevitavelmente introduzirá um erro de arredondamento (ou truncamento).

Infelizmente, números como 1/10 ou 1/100 expressos como números binários com uma parte fracionária também têm um número infinito de binários decimais .

 1/10 = binary 0.000110011001100110... 

Os duplos armazenam os valores como números binários e, portanto, podem introduzir um erro apenas convertendo um número decimal em um número binário, sem fazer nenhuma aritmética.

Números decimais (como BigDecimal ), por outro lado, armazenam cada dígito decimal como está. Isto significa que um tipo decimal não é mais preciso do que um ponto flutuante binário ou um tipo de ponto fixo em um sentido geral (por exemplo, não pode armazenar 1/7 sem perda de precisão), mas é mais preciso para números dados com um número finito de dígitos decimais, como é frequentemente o caso para cálculos de dinheiro.

O BigDecimal do Java tem a vantagem adicional de poder ter um número arbitrário (mas finito) de dígitos em ambos os lados do ponto decimal, limitado apenas pela memory disponível.

BigDecimal é a biblioteca numérica de precisão arbitrária da Oracle. BigDecimal faz parte da linguagem Java e é útil para uma variedade de aplicações que vão desde o financeiro ao científico (que é onde tipo de am).

Não há nada de errado em usar duplas para certos cálculos. Suponha, no entanto, que você quisesse calcular Math.Pi * Math.Pi / 6, ou seja, o valor da function Riemann Zeta para um argumento real de dois (um projeto no qual estou trabalhando atualmente). A divisão de ponto flutuante apresenta um problema doloroso de erro de arredondamento.

O BigDecimal, por outro lado, inclui muitas opções para calcular expressões com precisão arbitrária. Os methods adicionar, multiplicar e dividir, conforme descrito na documentação do Oracle abaixo, “ocupam o lugar” de +, * e / no BigDecimal Java World:

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

O método compareTo é especialmente útil em loops while e for.

Tenha cuidado, no entanto, no uso de construtores para BigDecimal. O construtor de string é muito útil em muitos casos. Por exemplo, o código

BigDecimal onethird = new BigDecimal (“0.33333333333”);

utiliza uma representação de string de 1/3 para representar esse número de repetição infinita em um grau especificado de precisão. O erro de arredondamento é mais provável em algum lugar tão profundo dentro da JVM que os erros de arredondamento não afetarão a maioria de seus cálculos práticos. Eu tenho, por experiência pessoal, visto arredondar para cima, no entanto. O método setScale é importante nesses aspectos, como pode ser visto na documentação do Oracle.

 package j2ee.java.math; /** * Generated from IDL definition of "valuetype "BigDecimal"" * TomORB IDL compiler v1.0 */ public abstract class BigDecimal extends j2ee.java.lang.Number implements org.omg.CORBA.portable.StreamableValue, j2ee.java.lang.Comparable { private String[] _truncatable_ids = {"RMI:java.math.BigDecimal:11F6D308F5398BBD:54C71557F981284F"}; protected int scale_; protected j2ee.java.math.BigInteger intVal; /* constants */ int ROUND_UP = 0; int ROUND_DOWN = 1; int ROUND_CEILING = 2; int ROUND_FLOOR = 3; int ROUND_HALF_UP = 4; int ROUND_HALF_DOWN = 5; int ROUND_HALF_EVEN = 6; int ROUND_UNNECESSARY = 7; public abstract int _hashCode(); public abstract int scale(); public abstract int signum(); public abstract boolean _equals(org.omg.CORBA.Any arg0); public abstract java.lang.String _toString(); public abstract j2ee.java.math.BigDecimal abs(); public abstract j2ee.java.math.BigDecimal negate(); public abstract j2ee.java.math.BigDecimal movePointLeft(int arg0); public abstract j2ee.java.math.BigDecimal movePointRight(int arg0); public abstract j2ee.java.math.BigDecimal setScale(int arg0); public abstract j2ee.java.math.BigDecimal setScale(int arg0, int arg1); public abstract j2ee.java.math.BigDecimal valueOf(long arg0); public abstract j2ee.java.math.BigDecimal valueOf(long arg0, int arg1); public abstract int compareTo(j2ee.java.math.BigDecimal arg0); public abstract j2ee.java.math.BigInteger toBigInteger(); public abstract j2ee.java.math.BigInteger unscaledValue(); public abstract j2ee.javax.rmi.CORBA.ClassDesc classU0024(java.lang.String arg0); public abstract j2ee.java.math.BigDecimal add(j2ee.java.math.BigDecimal arg0); public abstract j2ee.java.math.BigDecimal max(j2ee.java.math.BigDecimal arg0); public abstract j2ee.java.math.BigDecimal min(j2ee.java.math.BigDecimal arg0); public abstract j2ee.java.math.BigDecimal multiply(j2ee.java.math.BigDecimal arg0); public abstract j2ee.java.math.BigDecimal subtract(j2ee.java.math.BigDecimal arg0); public abstract j2ee.java.math.BigDecimal divide(j2ee.java.math.BigDecimal arg0, int arg1); public abstract j2ee.java.math.BigDecimal divide(j2ee.java.math.BigDecimal arg0, int arg1, int arg2); public void _write (org.omg.CORBA.portable.OutputStream os) { super._write( os ); os.write_long(scale_); ((org.omg.CORBA_2_3.portable.OutputStream)os).write_value( new java.lang.String("intVal") ); } public void _read (final org.omg.CORBA.portable.InputStream os) { super._read( os ); scale_=os.read_long(); intVal=(j2ee.java.math.BigInteger)((org.omg.CORBA_2_3.portable.InputStream)os).read_value ( "RMI:java.math.BigInteger:E2F79B6E7A470003:8CFC9F1FA93BFB1D".toString() ); } public String[] _truncatable_ids() { return _truncatable_ids; } public org.omg.CORBA.TypeCode _type() { return j2ee.java.math.BigDecimalHelper.type(); } } 

Tipos numéricos primitivos são úteis para armazenar valores únicos na memory. Mas quando se trata de cálculo usando tipos double e float, há um problema com o arredondamento. Isso acontece porque a representação da memory não é mapeada exatamente para o valor. Por exemplo, um valor duplo deve ter 64 bits, mas o Java não usa todos os 64 bits. Ele armazena apenas o que considera as partes importantes do número. Assim, você pode chegar aos valores incorretos ao adicionar valores juntos do tipo float ou double. Pode ser este vídeo https://youtu.be/EXxUSz9x7BM vai explicar mais