Por que 0,1 + 0,2 não dá 0,3

O padrão IEEE 754 escreve um número como sinal, expoente e mantissa, na base dois: valor = (−1)^sinal × 1,mantissa × 2^(expoente − viés). A precisão simples tem 8 bits de expoente e 23 de mantissa, a dupla 11 e 52. É o formato de quase todos os processadores e de todas as linguagens de programação.

Na base dois só as frações cujo denominador é potência de 2 têm escrita finita. 0,5 e 0,25 sim, 0,1 não: em binário é 0,000110011001100… periódico e precisa ser cortado. O valor armazenado é o mais próximo disponível, que num float é 0,100000001490116…, e ao somar valores já aproximados os erros se acumulam.

Por isso decimais em ponto flutuante não se comparam com ==, mas verificando se a diferença é pequena, e dinheiro se conta em centavos inteiros ou com tipos decimais. Valores especiais completam o formato: zero com sinal, infinitos, NaN e os subnormais, que preenchem o vão perto do zero.

Erros comuns

  • Comparar dois floats com ==: 0.1 + 0.2 == 0.3 é falso em quase todas as linguagens.
  • Usar floats para valores em dinheiro: os arredondamentos se somam. Melhor centavos inteiros ou um tipo decimal.
  • Achar que um float de 32 bits tem 32 bits de precisão: a mantissa tem 24, cerca de 7 dígitos decimais; um double tem cerca de 16.

Perguntas frequentes

Quantos dígitos decimais têm um float e um double?

Um float de 32 bits garante cerca de 7 dígitos decimais significativos, um double de 64 bits cerca de 15 a 16. Além disso, os dígitos que você vê refletem a aproximação binária.

O que são números subnormais?

São os valores menores que o mínimo normal: o expoente é todo zero e a mantissa perde o 1 implícito. Eles permitem chegar perto do zero aos poucos, com menos precisão.

Por que existem +0 e −0?

Porque o sinal é um bit separado. Os dois zeros são iguais na comparação, mas 1/+0 dá +∞ e 1/−0 dá −∞: guardam o lado pelo qual se chegou ao zero.

Como funciona este cálculo

Valor = (−1)^s × 1,f × 2^(e − viés) para os números normais, com viés 127 na precisão simples e 1023 na dupla; para os subnormais (e = 0) o valor é (−1)^s × 0,f × 2^(1 − viés). Expoente todo em 1 com mantissa nula é ±∞, com mantissa não nula é NaN. O valor exato é calculado em decimal sem arredondamentos: todo float é m × 2^k, e para k negativo isso é m × 5^(−k) ÷ 10^(−k).