Problemas Com Numeros Decimais - 6-02 Operações com Números Decimais. Problemas e Exercícios.
6-02 Operações com Números Decimais. Problemas e Exercícios.

Quando números decimais não somam

Isso é uma das coisas que todo programador encontra e quase ninguém se prepara para isso na faculdade. Você escreve um código simples, soma dois valores com vírgula e o resultado vem com aqueles seis dígitos depois do ponto que não fazem sentido nenhum. A primeira reação é sempre da própria calculadora, quando na verdade a calculadora está certa e o bug tá em outro lugar.

problemas com numeros decimais no dia a dia

O problema começa porque computadores não representam números decimais da forma como nós escrevemos. Eles usam binário, e frações como 0,1 ou 0,7 simplesmente não têm representação exata nessa base. O resultado é que operações como 0,1 mais 0,2 podem devolver algo como 0,30000000000000004. Parece absurdo, mas é a realidade da representação IEEE 754. Eu já passei uma tarde inteira debugando um sistema de cobrança onde o valor final do cliente vinha cinqüenta centavos abaixo do esperado. A planilha batia perfeito. O relatório batia perfeito. Só o valor cobrado no banco que estava errado. O rastreamento mostrou que, ao longo de vinte linhas com arredondamentos parciais, o erro acumulado chegava a esse meio real. A solução não foi mágica alguma: parei de arredondar durante os cálculos intermediários e só arredondava na exibição final.

Agora, existe mais de um jeito de lidar com isso, e escolher o errado é fácil se você não souber o que cada abordagem entrega.

As opções que realmente funcionam

A primeira tentação é usar Math.round() ou função semelhante em cada operação. Isso resolve para exibição, mas cria outro problema: se você precisa fazer cálculos encadeados, arredondar no meio da cadeia propaga erro para tudo que vem depois. O correto é manter precisão total nos cálculos internos e arredondar apenas no momento da saída. Se você trabalha com JavaScript e o problema é simples, uma opção prática é multiplicar, calcular e dividir. Para somar valores monetários, multiplique tudo por cem, trabalhe com inteiros, e divida por cem no final. É uma solução caseira, funciona para casos pequenos, mas quebra quando os valores crescem além do limite seguro do tipo inteiro do JavaScript, que é dois ponto cinquenta e três quintilhões. Acima disso, você perde precisão de novo.

👉 Clique no botão abaixo para saber mais sobre o assunto!

Para situações onde dinheiro é envolvido de verdade, a recomendação padrão é usar bibliotecas de decimal fixo. No ecossistema JavaScript, bignumber.js e decimal.js são os mais usados. Eles implementam aritmética decimal com precisão configurável, então 0,1 mais 0,2 dá exatamente 0,3. A desvantagem é que todo número que entra no sistema precisa passar por uma conversão. Se você deixar passar um float nativo, a contaminação já aconteceu antes mesmo da biblioteca agir. No Python a coisa é um pouco mais direta porque existe o módulo decimal embutido. Ele permite configurar contextos com precisão arbitrária e ainda oferece arredondamento com políticas claras, como ROUND_HALF_UP que a maioria dos sistemas financeiros exige. A desvantagem é que ele é significativamente mais lento que float nativo, algo em torno de dez a vinte vezes. Se você está processando milhões de linhas, esse overhead aparece.

Em Java, a classe BigDecimal resolve o problema, mas ela tem uma armadilha clássica. Se você criar um BigDecimal passando um double, o construtor vai capturar exatamente a representação binária imperfeita, não o valor decimal que você esperava. Sempre use o construtor que recebe string. É um detalhe que faz todo mundo errar na primeira vez.

O que não adianta tentar

Arredondar com toFixed() em JavaScript parece solução, mas na prática só esconde o erro. A função retorna uma string, e se você converter essa string de volta para número para continuar calculando, o float volta a morar no seu código. Use toFixed apenas para exibir, nunca para calcular. Também não adianta confiar em comparação direta de floats. Expressões como if (valor === 0,1) + 0,2) são uma receita para bugs silenciosos. A prática correta é comparar com uma tolerância, usando uma diferença absoluta menor que um epsilon, ou usar funções específicas de igualdade decimal quando a biblioteca permitir.

Um caso que quase quebrou meu sistema

Tive um bug específico envolvendo taxa de câmbio. O sistema calculava o valor em reais multiplicando dólares por uma cotação armazenada como float. A cotação vinha de uma API externa com dez casas decimais. O cálculo estava certo nos testes unitários porque usávamos valores fixos. Na produção, com valores altos de transação, o erro de arredondamento se repetia em cada operação e o relatóriofinanceiro fechava com diferença de real e meio. A correção foi migrar a cotação para decimal com precisão configurada e só aplicar o arredondamento na hora de registrar o lançamento contábil. Se você precisa de uma referência rápida, o módulo decimal do Python já vem instalado. Não precisa baixar nada. Para JavaScript, o decimal.js pode ser puxado via npm com install decimal.js. Para Java, BigDecimal também é parte padrão do JDK.

O essencial é entender que o problema com números decimais não é defeito do seu código, é limite da representação binária. Uma vez que você aceita isso, a escolha da ferramenta certa deixa de ser adivinhação e passa a ser decisão técnica baseada no que o sistema realmente precisa.