Magia dos números: por que 0.1 + 0.2 não é igual a 0.3?
Olá, futuro guru do JavaScript! Se você já tentou somar 0.1 e 0.2 no console do navegador, provavelmente teve um choque cultural:
console.log(0.1 + 0.2); // Exibe: 0.30000000000000004Sim, o JavaScript não enlouqueceu. Este é um problema padrão da aritmética de ponto flutuante (IEEE 754). Os computadores simplesmente não conseguem representar perfeitamente 0.1 em binário — é como tentar escrever 1/3 em decimal. O resultado é uma fração infinita.
E então surge a clássica pergunta no Stack Overflow, que acumulou milhares de visualizações: «How to round to at most 2 decimal places, if necessary». Como exibir o número de forma elegante, sem a cauda de «0000000004»? Como arredondar para duas casas, mas apenas quando necessário?
Neste artigo, vamos analisar um tutorial passo a passo que resolverá o problema de uma vez por todas. Você aprenderá por que toFixed() às vezes mente, como funciona o Math.round() e qual método escolher para uma loja online, calculadora ou apenas para exibir um preço bonito.
Problema: «Quero 2 casas, mas não mais!»
Imagine que você está programando um carrinho de compras. O preço do produto é 10.00. Você quer mostrar 10, e não 10.00. Mas se o preço for 10.456, você quer mostrar 10.46. A lógica é simples: arredondamos para duas casas, mas descartamos os zeros extras.
O método padrão toFixed(2) faz o seguinte:
const price = 10;console.log(price.toFixed(2)); // "10.00" — mas precisamos de "10"
const price2 = 10.456;console.log(price2.toFixed(2)); // "10.46" — aqui está okProblema: toFixed() sempre retorna uma string e sempre adiciona zeros. Isso não é adequado.
Um segundo detalhe — toFixed() pode arredondar de forma estranha devido ao mesmo ponto flutuante:
console.log((1.005).toFixed(2)); // "1.00" — mas deveria ser "1.01"!Bingo! É por isso que a pergunta no Stack Overflow é tão popular. Vamos analisar as soluções.
Solução nº1: Arredondamento matemático (Math.round)
A maneira mais confiável é multiplicar o número por 100, arredondar e dividir de volta. Funciona assim:
function roundToTwo(num) { return Math.round(num * 100) / 100;}
console.log(roundToTwo(10.456)); // 10.46console.log(roundToTwo(10)); // 10console.log(roundToTwo(1.005)); // 1 — ops, problema novamenteViu? 1.005 * 100 = 100.49999999999999 (devido ao IEEE 754). Math.round arredonda isso para baixo, resultando em 100, dividimos por 100 = 1. Não é bom.
Conclusão: O método é bom para casos simples, mas não para cálculos financeiros. Para exemplos didáticos, serve.
Solução nº2: Number.EPSILON — o salvador da precisão
Para vencer o erro de ponto flutuante, podemos adicionar um pequeno delta — Number.EPSILON. Esta é a menor diferença entre dois números que o JavaScript consegue distinguir (aproximadamente 2.2e-16).
function roundToTwo(num) { return Math.round((num + Number.EPSILON) * 100) / 100;}
console.log(roundToTwo(1.005)); // 1.01 — funciona!console.log(roundToTwo(10.456)); // 10.46console.log(roundToTwo(10)); // 10Por que isso funciona? Empurramos o número um pouco para cima, para que 100.4999... se transforme em 100.5... e arredonde corretamente.
Importante: Este método não é ideal para todos os casos extremos, mas para 99% das tarefas é uma excelente solução. É exatamente o que costumam recomendar no Stack Overflow.
Solução nº3: toFixed() + Number() — um truque esperto
Outra maneira popular é usar toFixed(2) e depois converter a string de volta para número com Number() ou o operador unário +. Os zeros extras são removidos automaticamente.