Problemas Com Numeros Decimais - Problemas Com Numeros Decimais - GITEDU
Problemas Com Numeros Decimais - GITEDU

Por que seus cálculos com decimais estão dando errado

Eu passei anos lidando com esse problema específico e posso garantir que a maioria das pessoas não entende o que está acontecendo nos bastidores. Quando você soma 0,1 mais 0,2 no JavaScript e o resultado é 0,30000000000000004, isso não é um bug. É o comportamento esperado de um sistema que usa a representação binária padrão do IEEE 754 para números de ponto flutuante. O cerne da questão é que computadores armazenam tudo em binário, e muitos números decimais que parecem simples não têm representação exata nessa base. O número 0,1 em decimal vira uma fração periódica infinita em binário, igual a como 1/3 vira 0,333... no sistema decimal. O computador arredonda. E esse arredondamento se acumula.

Entendendo os problemas com numeros decimais na prática

Eu me lembro de uma vez em que construí um sistema de faturamento para uma clínica médica. A conta era simples: multiplicar o valor do procedimento pelo número de sessões e aplicar um desconto progressivo. O código funcionava nos testes unitários. Na produção, depois de cem transações processadas, o relatório mensal estava R$ 3,47 desativado. Três reais e quarenta e sete centavos sumidos sem explicação aparente. O problema não estava em nenhuma fórmula específica. Estava na forma como cada operação intermediária introduzia erros de arredondamento binário que se propagavam. O valor do procedimento era 47,90. Em binário float, isso já era 47,8999999999999985789145284819... Cada multiplicação e divisão alimentava essa imprecisão. Eu levei duas semanas inteiros para isolar a causa raiz.

O que funcionou foi mudar completamente a abordagem. Ao invés de trabalhar com valores decimais diretamente, converti tudo para centavos (inteiros) desde o início. O 47,90 virou 4790. Todas as operações foram feitas com inteiros. Só na etapa final, na hora de exibir o valor para o usuário, eu dividia por 100. O relatório bateu certinho no primeiro rodapé subsequente.

As principais armadilhas que todo desenvolvedor encontra

A primeira armadilha é achar que comparar floats com == funciona. Isso raramente funciona. Quando você precisa verificar se dois valores numéricos são iguais, sempre use uma tolerância. O padrão da indústria é comparar a diferença absoluta contra um epsilon. No JavaScript, algo como Math.abs(a - b)

1e-10 resolve a maioria dos casos. Em Python, existe a função math.isclose() que já faz isso de forma configurável. A segunda armadilha é usar tipos de ponto flutuante para valores monetários. Isso é um erro clássico que vejo recorrentemente. Bancos, fintechs, plataformas de e-commerce — todos usam representação decimal fixa. O Java tem BigDecimal. O Ctem decimal. O Python tem decimal.Decimal. O PostgreSQL tem NUMERIC. Use a ferramenta certa para o trabalho certo. Float serve para medidas físicas, simulações, gráficos. Não serve para dinheiro.

A terceira armadilha é a formatação. Mesmo quando o cálculo está correto, exibir o resultado pode enganar. Um valor como 19,90 pode ser exibido como 19,8999999999999985 se você não usar formatação adequada. A maioria das linguagens tem funções de formatação que redondeiam corretamente para exibição, mas é preciso chamar explicitamente. printf("%.2f", valor) no C, format(valor, ".2f") no Python, Number.toFixed(2) no JavaScript. Cada linguagem tem seu jeito, mas o princípio é o mesmo.

Quando o método dos inteiros não é suficiente

O truque de converter para centavos funciona bem para dinheiro com casas decimais fixas. Mas nem sempre é viável. Existem cenários onde a precisão necessária varia dinamicamente. Juros compostos com taxas não inteiras, conversões cambiais com muitas casas decimais, cálculos científicos que envolvem grandezas em ordens de magnitude diferentes. Nesses casos, a solução correta é usar bibliotecas de aritmética decimal de precisão arbitrária. No JavaScript, a biblioteca decimal.js ou big.js são amplamente usadas. No Python, o módulo decimal nativo é mais do que suficiente. No Ruby, o BigDecimal da biblioteca padrão. Essas bibliotecas implementam a representação decimal diretamente, eliminando o problema da conversão binária.

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

Eu tive um projeto em que precisei calcular parcelas de um empréstimo com taxa de juros de 1,327% ao mês. O valor do financiamento era R$ 12.450,00. Usando float, cada parcela tinha um centavo de diferença em relação ao calculado manualmente. Somando vinte e quatro parcelas, o erro acumulava para quase cinquenta centavos. Mudar para BigDecimal resolveu, mas o código ficou significativamente mais verboso. Operações que eram uma linha viravam três ou quatro. Isso é o custo real de usar precisão decimal corretamente.

O que geralmente dá errado e como evitar

Uma coisa que todo mundo esquece é o problema da ordem das operações. Multiplicação e divisão não são comutativas no mundo dos floats quando há arredondamento envolvido. Calcular (a * b) / c pode dar um resultado diferente de (a / c) * b. Em finanças, isso importa porque o arredondamento é aplicado em momentos diferentes. A regra prática é: faça o arredondamento o mais tarde possível e use a mesma ordem de operações em todas as partes do sistema. Outro problema frequente é a confusão entre arredondamento e truncamento. Algunas linguagens arredondam para o inteiro mais próximo. Outras truncam na direção do zero. Isso parece detalhe, mas em cálculos de comissões ou impostos faz diferença. Sempre verifique qual comportamento a função que você está usando adota. Em Python, int(2,7) retorna 2. round(2,7) retorna 3. Em JavaScript, Math.trunc(2,7) retorna 2, mas Math.round(2,7) também retorna 3. As regras de arredondamento em meade dos valores exatos variam entre Math.round, Math.floor e Math.ceil, e escolher a errada gera discrepâncias sutis.

Uma limitação importante que poucos mencionam: mesmo com BigDecimal ou Decimal, há operações que inevitavelmente produzem resultados infinitos em decimal. Divisão de 1 por 3, por exemplo. Nessas situações, você precisa definir explicitamente a precisão e a estratégia de arredondamento. Caso contrário, a biblioteca vai lançar uma exceção ou usar um comportamento padrão que pode não ser o que você espera. Configure isso no início do seu sistema e mantenha consistente.

Resumo dos passos para resolver problemas com numeros decimais

Primeiro, identifique onde o problema está. Se for dinheiro, verifique se você está usando float em algum ponto do fluxo. Se for medida ou cálculo científico, verifique se a precisão do tipo escolhido é suficiente para a faixa de valores que você está manipulando. Segundo, aplique a correção adequada. Para valores monetários, use inteiros (centavos) ou BigDecimal. Para cálculos gerais com necessidade de precisão decimal, use bibliotecas especializadas. Nunca confie em comparações diretas de floats.

Terceiro, teste com casos de borda. valores pequenos somados a valores grandes, muitas operações encadeadas, divisões que geram dízimas periódicas. Um conjunto mínimo de testes de borda leva cerca de vinte minutos para escrever e evita horas de depuração posterior. Se você precisa de uma referência rápida, a biblioteca decimal.js para JavaScript pode ser baixada diretamente do repositório no GitHub. A documentação cobre os casos mais comuns de uso e inclui exemplos de migração de código que usa números nativos. No ecossistema Python, não há nada para baixar — o módulo decimal já vem instalado com a linguagem padrão.