Precisão Numérica em Java - BigInteger e BigDecimal
Os tipos numéricos primitivos do Java, como long e double, são eficientes, mas possuem limitações. O tipo long tem um tamanho máximo, e o double pode introduzir erros de precisão em cálculos decimais. Para cenários que exigem exatidão absoluta ou números de tamanho ilimitado, o Java oferece duas classes essenciais no pacote java.math: BigDecimal e BigInteger.
As Limitações dos Tipos Primitivos
O uso de double ou float em cálculos financeiros é desaconselhado devido à sua incapacidade de representar muitos valores decimais de forma exata. Isso pode levar a erros de arredondamento. Por exemplo, a operação 2.0 - 1.1 resulta em 0.8999999999999999 em vez de 0.9.
Da mesma forma, o tipo long possui um valor máximo e não consegue armazenar números inteiros arbitrariamente grandes, como os necessários em criptografia ou certos cálculos matemáticos.
BigDecimal: Cálculos com Precisão Decimal
A classe BigDecimal foi projetada para eliminar os erros de arredondamento, garantindo que os cálculos decimais sejam 100% precisos.
Objetos BigDecimal são imutáveis: uma vez criados, seu valor não pode ser alterado. Qualquer operação aritmética (como add ou subtract) não modifica o objeto original, mas sim retorna um novo objeto com o resultado. Por isso, as operações devem ser feitas com métodos, e não com operadores como + ou -.
Para garantir a máxima precisão, o ideal é criar objetos BigDecimal a partir de uma String.
import java.math.BigDecimal;
public class Program {
public static void main(String[] args) {
// Criar a partir de String para garantir precisão
BigDecimal a = new BigDecimal("2.0");
BigDecimal b = new BigDecimal("1.1");
// Correto: reatribuir o novo objeto retornado por subtract()
BigDecimal result = a.subtract(b);
System.out.println(result); // Exibe exatamente 0.9
}
}BigInteger: Cálculos com Inteiros Grandes
Quando é necessário trabalhar com números inteiros que ultrapassam o limite de long, BigInteger é a solução. Ele pode armazenar números de tamanho virtualmente ilimitado. Assim como BigDecimal, BigInteger é imutável e suas operações são realizadas por meio de métodos.
import java.math.BigInteger;
public class Program {
public static void main(String[] args) {
BigInteger a = new BigInteger("9223372036854775807"); // Limite máximo de long
BigInteger b = new BigInteger("2");
// Correto: chamar o método e atribuir o novo objeto resultante
BigInteger result = a.multiply(b);
System.out.println(result); // 18446744073709551614
}
}Resumo
- Use
BigDecimalpara Precisão: Ideal para cálculos financeiros ou monetários onde a exatidão decimal é crucial. - Use
BigIntegerpara Tamanho: Ideal para números inteiros que podem exceder o valor máximo delong. - Imutabilidade: As operações não alteram o objeto. Elas retornam um novo objeto com o resultado, que deve ser atribuído a uma variável.
- Construtor
String: ParaBigDecimal, crie objetos a partir deString(new BigDecimal("0.1")) para evitar a herança de imprecisões do tipodouble.