WADDINGTONS Cada Questão Revela um Novo Jeito de Aprender

Problemas Com Numeros Decimais

Problemas Com Numeros Decimais
Neste artigo
  1. Quando números decimais não somam
  2. As opções que realmente funcionam
  3. O que não adianta tentar
  4. Um caso que quase quebrou meu sistema

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. 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. 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.

Problemas Com Números Decimais 5 Ano – SRYSF
Problemas Com Números Decimais 5 Ano – SRYSF

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.

6-02 Operações com Números Decimais. Problemas e Exercícios. > aMath
6-02 Operações com Números Decimais. Problemas e Exercícios. > aMath
Review the 6 essential operations with decimal numbers.
Review the 6 essential operations with decimal numbers.

Artigos Relacionados