DEV Community

Java Efetivo (livro)
Java Efetivo (livro)

Posted on

Item 60: Evite o float e o double caso sejam necessárias respostas exatas

Problema com float e double:

  • Projetados para cálculos científicos e matemáticos, executam aritmética binária de ponto flutuante.
  • Não são adequados para cálculos monetários ou situações que exigem respostas exatas.
  • Não conseguem representar com precisão potências negativas de dez, como 0.1, o que leva a erros.

Exemplo 1:
Cálculo incorreto ao subtrair valores em dólares:

System.out.println(1.03 - 0.42);  // Resultado: 0.6100000000000001

Enter fullscreen mode Exit fullscreen mode

Exemplo 2:
Erro ao comprar nove itens de 10 centavos cada:

System.out.println(1.00 - 9 * 0.10);  // Resultado: 0.09999999999999998

Enter fullscreen mode Exit fullscreen mode

Mesmo arredondando, os erros persistem.
Problema com cálculos progressivos, como ao comprar doces a preços incrementais de 0.10 a 1.00.

Exemplo 3:
Erro ao comprar doces até não ter mais dinheiro:

double funds = 1.00;
for (double price = 0.10; funds >= price; price += 0.10) {
    funds -= price;
}
System.out.println(funds);  // Resultado: 0.3999999999999999

Enter fullscreen mode Exit fullscreen mode

Solução 1: Usar BigDecimal

  • Ideal para cálculos financeiros e situações em que precisão é fundamental.
  • Evitar o uso do construtor double de BigDecimal, preferindo o construtor String.

Exemplo com BigDecimal:

BigDecimal funds = new BigDecimal("1.00");
BigDecimal price = new BigDecimal("0.10");
int itemsBought = 0;

while (funds.compareTo(price) >= 0) {
    funds = funds.subtract(price);
    price = price.add(new BigDecimal("0.10"));
    itemsBought++;
}
System.out.println(itemsBought + " items bought. Money left: " + funds);  
// Resultado: 4 items bought. Money left: 0.00

Enter fullscreen mode Exit fullscreen mode

O cálculo agora é preciso.

Desvantagens de BigDecimal:

  • Menos conveniente de usar do que os tipos primitivos.
  • Mais lento, especialmente para grandes volumes de operações.

Solução 2: Usar int ou long

  • Para evitar os problemas de precisão, faça cálculos em centavos, usando int ou long em vez de dólares com double.

Exemplo com int (em centavos):

int funds = 100;  // 1.00 dólar = 100 centavos
int price = 10;   // 0.10 dólar = 10 centavos
int itemsBought = 0;

while (funds >= price) {
    funds -= price;
    price += 10;
    itemsBought++;
}
System.out.println(itemsBought + " items bought. Money left: " + funds);  
// Resultado: 4 items bought. Money left: 0

Enter fullscreen mode Exit fullscreen mode

O cálculo é rápido e preciso.

Conclusão:

  • Não use float ou double para cálculos que exigem precisão exata.
  • Use BigDecimal para cálculos monetários ou situações que exigem precisão decimal.
  • Use int ou long para cálculos financeiros que não envolvam grandes números, fazendo os cálculos em centavos.

Escolhas:

  • Para até 9 dígitos, use int.
  • Para até 18 dígitos, use long.
  • Para quantidades maiores, use BigDecimal.
  • Este resumo mostra que, dependendo do contexto, a escolha entre BigDecimal, int ou long pode otimizar tanto a precisão quanto o desempenho.

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay