Conversor IEEE 754 — Decimal para Bits de Ponto Flutuante (32/64 bits)
Converta nos dois sentidos entre números decimais e padrões de bits IEEE 754 (precisão simples de 32 bits ou dupla de 64 bits). Sinal, expoente e mantissa em cores diferenciadas facilitam identificar NaN, infinito e números subnormais.
O exemplo clássico: por que 0.1 + 0.2 não dá 0.3
No JavaScript, `0.1 + 0.2` resulta em `0.30000000000000004`, não `0.3`. Observar os padrões de bits em precisão dupla explica o motivo.
| Valor | Hexadecimal em precisão dupla (64 bits) | Binário em precisão dupla (64 bits) |
|---|---|---|
| 0.1 | 0x3FB999999999999A | 0011111110111001100110011001100110011001100110011001100110011010 |
| 0.2 | 0x3FC999999999999A | 0011111111001001100110011001100110011001100110011001100110011010 |
| 0.3 | 0x3FD3333333333333 | 0011111111010011001100110011001100110011001100110011001100110011 |
| 0.1 + 0.2 | 0x3FD3333333333334 | 0011111111010011001100110011001100110011001100110011001100110100 |
0.1, 0.2 e 0.3 são todas frações infinitamente periódicas em binário, então nenhuma delas cabe exatamente na mantissa de 52 bits e cada uma é arredondada. Como os erros de arredondamento de 0.1 e 0.2 não chegam a se cancelar, a soma acaba ficando apenas um bit diferente do padrão exato de 0.3 (0x3FD3333333333334). Tente inserir esses valores no conversor acima e compare você mesmo os bits finais.
O que é o IEEE 754? Vendo números de ponto flutuante como bits
Quando um computador armazena um número decimal, ele não guarda os dígitos que você digitou: empacota o valor em uma quantidade fixa de bits seguindo o padrão IEEE 754, divididos em sinal, expoente e mantissa. Esta ferramenta mostra exatamente quais bits são armazenados para qualquer valor que você digitar, tanto em precisão simples (32 bits) quanto em precisão dupla (64 bits), e também funciona ao contrário: cole um padrão hexadecimal ou binário bruto e descubra a que valor decimal ele corresponde.
A programação do dia a dia raramente exige pensar nessa camada, mas é exatamente ela que explica por que `0.1 + 0.2` não dá `0.3`, por que inteiros muito grandes perdem precisão ao serem guardados como float, e por que NaN e infinito se comportam desse jeito em comparações. Ver o sinal, o expoente e a mantissa detalhados para um valor real transforma essas regras abstratas em algo concreto para apontar.
Como usar esta ferramenta
- Escolha uma direção e uma precisão Selecione "Decimal → Padrão de bits" ou "Padrão de bits → Decimal" e, em seguida, precisão simples (32 bits) ou dupla (64 bits).
- Digite um valor Na entrada decimal, digite qualquer número ou "NaN"/"Infinity"/"-Infinity". Na entrada em bits, use uma string hexadecimal com prefixo `0x` ou uma string binária com o número de dígitos correspondente à precisão escolhida.
- Leia a divisão entre sinal, expoente e mantissa A sequência de bits colorida e uma tabela detalhada mostram o expoente bruto, o expoente após remover o viés e a representação hexadecimal completa.
- Confira o rótulo de classificação A ferramenta classifica automaticamente o resultado como zero, subnormal, normal, infinito ou NaN, junto com uma breve explicação do que essa classificação significa.
- Experimente os predefinidos e os casos extremos Use os botões de 0,1/0,2/0,3, ±0, ±Infinity e NaN, ou teste valores negativos e números extremamente grandes ou pequenos para ver como são codificados.
Dicas para aproveitar melhor
- Converta 0.1, 0.2 e 0.3 para bits em precisão dupla e compare com o resultado de 0.1+0.2 (0.30000000000000004) — dá para perceber visualmente que só o último bit é diferente.
- Digitar "-0" no campo decimal produz um padrão de bits com apenas o bit de sinal ativado (diferente de "+0"). Como números, 0 === -0, mas as representações em bits são distintas.
- Quando o campo do expoente é todo zero, uma mantissa igual a zero significa zero, e uma mantissa diferente de zero significa um número subnormal — uma representação especial usada para alcançar valores extremamente próximos de zero à custa da precisão.
- Alternar entre precisão simples (32 bits) e dupla (64 bits) para o mesmo valor, como 0.1, mostra como o erro de arredondamento é maior na precisão simples.
- Para decodificar um padrão de bits de volta a um valor decimal, digite uma string hexadecimal com o prefixo `0x`, ou uma string binária com exatamente tantos dígitos quanto a precisão selecionada (o prefixo `0b` é opcional).
Onde esta ferramenta ajuda
Disciplinas de ciência da computação
Os livros descrevem a estrutura do ponto flutuante de forma abstrata; aqui dá para conferir isso com números reais enquanto se estuda ou se prepara um relatório de laboratório.
Depurar bugs de precisão numérica
Descubra por que um cálculo específico fica levemente diferente do esperado, digitando o valor suspeito e examinando seu padrão de bits exato, sem escrever código.
Programação embarcada e de baixo nível
Decodifique um valor de ponto flutuante em hexadecimal visto em um dump de memória ou registrador de volta para um número decimal legível.
Preparação para entrevistas técnicas
Treine respostas para perguntas como "qual a diferença entre precisão simples e dupla no nível dos bits" usando um exemplo concreto em vez de decoreba.
Explicar "0.1 + 0.2 ≠ 0.3" para alguém
Mostre os padrões de bits reais lado a lado em vez de apenas afirmar que o arredondamento do ponto flutuante é a causa.
Glossário
- IEEE 754
- O padrão internacional que define como os computadores representam números de ponto flutuante. Publicado em 1985, é seguido pelo tipo float/double de praticamente todas as linguagens de programação.
- Bit de sinal
- O único bit que indica se um valor é positivo (0) ou negativo (1). É independente do expoente e da mantissa, por isso "+0" e "-0" existem como padrões de bits distintos.
- Expoente
- Os bits que codificam a escala (magnitude) do valor: 8 bits em precisão simples, 11 em precisão dupla, armazenados com um viés somado.
- Mantissa (significando)
- Os bits que codificam os dígitos significativos do valor: 23 bits em precisão simples, 52 em precisão dupla, normalmente interpretados com um 1 implícito no início.
- Viés
- Um deslocamento fixo (127 em precisão simples, 1023 em dupla) somado ao expoente para que ele possa ser armazenado e comparado como um simples inteiro sem sinal.
- Número subnormal
- Um padrão de bits com o expoente todo zero e a mantissa diferente de zero. Ao omitir o 1 implícito, ele permite representar valores mais próximos de zero do que um número normal, à custa da precisão.
- NaN (não é um número)
- Um padrão de bits com o expoente todo um e a mantissa diferente de zero, produzido por operações indefinidas como 0/0 ou ∞-∞.
- Infinito
- Um padrão de bits com o expoente todo um e a mantissa toda zero, que costuma surgir quando um cálculo ultrapassa o intervalo representável.
Perguntas frequentes
Curiosidade — Como o IEEE 754 se tornou uma língua comum
Antes de 1985, cada fabricante de computadores usava sua própria representação de ponto flutuante. IBM, DEC, Cray e outros podiam calcular o mesmo valor, digamos "0.1", e obter comportamentos de arredondamento e intervalos representáveis sutilmente diferentes, de modo que portar um programa numérico de uma máquina para outra costumava produzir resultados ligeiramente diferentes. Para resolver esse caos, um grupo de trabalho liderado por William Kahan, da UC Berkeley — que também havia trabalhado no projeto do coprocessador numérico Intel 8087 —, impulsionou a criação de um padrão para toda a indústria, publicado em 1985 como IEEE 754.
A ideia central do IEEE 754 é dividir um número finito de bits (32 ou 64) em três papéis — sinal, expoente e mantissa — para aproximar o conjunto infinito dos números reais. O expoente cuida da escala (quão grande ou pequeno é um número), enquanto a mantissa cuida da precisão (quantos dígitos significativos ela tem), permitindo que um número fixo de bits cubra com flexibilidade tanto magnitudes muito pequenas quanto muito grandes. O expoente é armazenado somando-se um viés (127 na precisão simples, 1023 na dupla), de modo que comparar dois padrões de bits como simples inteiros sem sinal já basta para determinar qual valor é maior, evitando a complexidade extra de uma representação com sinal como o complemento de dois.
Somente frações cujo denominador é uma potência de dois (1/2, 1/4, 3/8 etc.) podem ser representadas exatamente em binário. O valor decimal 0.1 é a fração 1/10 e, como 10 não é uma potência de dois, ele se torna a fração binária infinitamente periódica 0.0001100110011... Com apenas um número finito de bits de mantissa disponíveis, é preciso truncar e arredondar em algum ponto — esta é a razão fundamental pela qual um computador não consegue representar 0.1 exatamente. É também por isso que sistemas contábeis que precisam de aritmética decimal exata costumam evitar números de ponto flutuante em favor da aritmética com inteiros ou de um tipo decimal dedicado (como BCD).
O IEEE 754 foi revisado depois em 2008 e 2019, adicionando precisão meia (16 bits), precisão quádrupla (128 bits) e formatos de ponto flutuante decimal, mas a divisão central em sinal, expoente e mantissa, junto com seus modos de arredondamento, permanece inalterada desde a edição original de 1985. Como praticamente todos os tipos float/double das linguagens de programação seguem esse padrão, a pergunta "por que 0.1 + 0.2 não é igual a 0.3?" aparece essencialmente da mesma forma, não importa qual linguagem você use.