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
BigDecimal
para Precisão: Ideal para cálculos financeiros ou monetários onde a exatidão decimal é crucial. - Use
BigInteger
para 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
.