Entender os números mágicos do código
& 0xFF, >>> 24, | (1 << 3), 0o644 — depois dos níveis 11 a 15, fica evidente quais bits cada trecho pega ou liga.
Guide
O Curso de bases numéricas e bits é um tutorial interativo de 17 níveis que transforma o "binário" de conceito abstrato em interruptores que dá para tocar: você digita um número e as quatro notações (binária, octal, decimal e hexadecimal) mudam juntas; acende ou apaga um bit e o valor é atualizado na hora; faz dois números passarem por AND / OR / XOR / deslocamento e vê o resultado alinhado bit a bit; digita um decimal e acompanha a separação dele em sinal, expoente e mantissa, além de descobrir a qual decimal ele é exatamente igual em precisão dupla. Cada nível tem um objetivo concreto — converter um número, chegar a 200, escrever o complemento de dois de -5, calcular 5 << 3 — e o verificador responde na hora.
Atualizado em 2026-09-094 sources16 min read
O Curso de bases numéricas e bits é um tutorial interativo de 17 níveis que transforma o "binário" de conceito abstrato em interruptores que dá para tocar: você digita um número e as quatro notações (binária, octal, decimal e hexadecimal) mudam juntas; acende ou apaga um bit e o valor é atualizado na hora; faz dois números passarem por AND / OR / XOR / deslocamento e vê o resultado alinhado bit a bit; digita um decimal e acompanha a separação dele em sinal, expoente e mantissa, além de descobrir a qual decimal ele é exatamente igual em precisão dupla. Cada nível tem um objetivo concreto — converter um número, chegar a 200, escrever o complemento de dois de -5, calcular 5 << 3 — e o verificador responde na hora.
O curso é dividido em quatro blocos: conversão entre bases (binário ↔ decimal, potências de 2, por que hexadecimal e octal são "taquigrafia"); números com sinal (como o complemento de dois transforma subtração em soma e por que o estouro faz 127 + 1 virar -128); operações de bits (máscara com AND, ligar com OR, inverter com XOR, deslocar para multiplicar e dividir, e a aplicação direta disso nos bits de permissão 755 do Linux); e ponto flutuante (o layout dos campos do IEEE 754 e o motivo real de 0.1 + 0.2 !== 0.3).
São cerca de 45 minutos. O curso é para quem está começando a programar, para quem se prepara para entrevistas e para quem precisa consultar 0x1F, & 0xFF ou chmod 644 toda vez; não é preciso base de matemática, basta saber somar.
0x.?lesson=n leva direto a um nível.O curso em si está acima desta página: mude o valor, clique nos interruptores e preencha a resposta.
O nível 9, "Achar o complemento de dois", pede o complemento de dois de -5 em 8 bits:
No nível 16, "Campos do IEEE 754", ao digitar 0.15625 o painel mostra:
Valor absoluto 5 0 0 0 0 0 1 0 1
Inverter bits 1 1 1 1 1 0 1 0
Somar 1 1 1 1 1 1 0 1 1 ← resposta 11111011
Conferir sem sinal 251, com sinal 251 − 256 = −5 ✓0.15625 = 0.00101₂ = 1.01₂ × 2⁻³
Sinal 0
Expoente −3 + 127 = 124 = 01111100 ← resposta 124
Mantissa 01000000000000000000000 (o 1 inicial é implícito)
32 bits 0 01111100 01000000000000000000000 = 0x3E200000Qualquer base é uma "soma de valores posicionais". O decimal 203 = 2×100 + 0×10 + 3×1; o binário 1011 = 1×8 + 0×4 + 1×2 + 1×1 = 11. Da direita para a esquerda, os valores posicionais são 1, 2, 4, 8, 16, 32, 64, 128… Converter binário em decimal é somar os valores posicionais dos bits 1; converter decimal em binário é dividir por 2 anotando os restos, ou subtrair gananciosamente as potências de 2 da maior para a menor (os interruptores do nível 7 são justamente essa visualização).
difere de 1000 em apenas 2,4%, e por isso o KB passou a significar 1024 bytes no começo. Daí vem a confusão que existe até hoje: fabricantes de disco rotulam 1 GB como , o sistema operacional calcula com e um disco de 500 GB aparece com 465 GiB. A IEC criou por isso KiB, MiB e GiB (prefixos binários), adotados aos poucos pelo Linux e pelo macOS, enquanto o Windows continua mostrando GB mas calculando em GiB. Vale memorizar alguns números: , , , .
O binário é longo demais para ler. O hexadecimal (0–9 mais A–F) usa um símbolo para cada 4 bits, então um byte dá exatamente dois: 11111111 = FF, 10110110 = B6. A conversão não precisa passar pelo decimal — basta cortar o binário de 4 em 4 bits da direita para a esquerda e consultar cada grupo, que é o exercício do nível 5. O octal usa um símbolo para 3 bits e era usado por máquinas de 12, 24 e 36 bits; hoje sobrevive nas permissões do Linux (755) e no escape \012 do C. Os prefixos nos programas: 0x para hexadecimal, 0o para octal e 0b para binário.
Todo inteiro não negativo tem uma única forma binária, então um número de 8 bits pode funcionar como 8 interruptores independentes (bits de flag): flags = READ | WRITE, if (flags & EXEC). É assim que o font-weight do CSS, as permissões de arquivo do Unix e os campos de flag nos cabeçalhos de protocolo de rede são empacotados. No nível 7 você precisa chegar a 200 só clicando nos interruptores — da maior potência para a menor: 200 ≥ 128 liga, sobram 72 ≥ 64 liga, sobram 8 = 2³ liga, e dá 11001000.
Como guardar números negativos? A ideia intuitiva é reservar um bit para o sinal, mas assim existiriam dois zeros, "+0" e "−0", e o circuito de soma precisaria tratar cada caso. O complemento de dois (two's complement) funciona assim: se o bit mais significativo é 1, o valor é negativo e equivale ao valor sem sinal menos . Em 8 bits, 11111111 é 255 e também 255 − 256 = −1; 10000000 é −128. Para achar o complemento de dois de um número negativo: escreva o valor absoluto, inverta os bits e some um — −5 fica 00000101 → 11111010 → 11111011.
O encanto do complemento de dois é que a soma não precisa saber o sinal: −5 + 5 = 11111011 + 00000101 = 1 00000000, e depois de descartar o vai-um do 9º bit o resultado é exatamente 0. A subtração vira "somar o complemento" e a CPU precisa de um único somador. A faixa do complemento de dois em 8 bits vai de −128 a 127: há um negativo a mais do que positivos, porque o 0 ocupa um lugar do lado positivo.
A largura em bits é finita, e ao passar do limite o valor dá a volta. Em int8, 127 = 01111111; somando um, dá 10000000, que na leitura em complemento de dois é −128. É assim que o estouro de inteiro acontece em silêncio em C, Java e Go; em JavaScript, o Number comum é ponto flutuante e por isso não estoura, mas Int8Array, |0 e todas as operações de bits rodam em complemento de dois de 32 bits, e (2 ** 31) | 0 resulta em −2147483648. O famoso problema do ano 2038 é um contador de segundos com sinal de 32 bits que estoura para negativo em 2038-01-19 03:14:07 UTC; a "pontuação que fica negativa" e as "moedas que zeram" de jogos antigos são a mesma coisa.
As três operações lógicas bit a bit têm usos fixos:
| Operação | Regra | Uso consagrado |
|---|---|---|
AND & |
1 só quando os dois bits são 1 | Máscara: x & 0x0F pega os 4 bits de baixo; IP & máscara dá o endereço de rede; n & 1 testa paridade |
OR | |
1 quando qualquer um dos bits é 1 | Ligar: flags | READ ativa uma flag sem mexer nas outras |
XOR ^ |
1 só quando os bits diferem | Inverter / restaurar: x ^ m ^ m = x; cifra de uso único, soma de verificação, troca sem variável temporária |
"Desligar" um bit é a combinação de AND com NOT: flags & ~FLAG. As duas identidades do XOR, e , estão na raiz de todos os seus usos: a ^= b; b ^= a; a ^= b troca dois números, e para achar o único elemento que aparece um número ímpar de vezes em um vetor basta aplicar XOR em todos eles.
Deslocar n bits para a esquerda é multiplicar por (entram zeros nos bits de baixo) e deslocar n bits para a direita é dividir por arredondando para baixo. 5 << 3 = 101000 = 40. O deslocamento é a multiplicação e a divisão mais baratas que existem, e o uso mais comum é empacotar campos pequenos em um inteiro: (r << 16) | (g << 8) | b junta três valores de 0 a 255 em uma cor de 24 bits, e o caminho de volta (rgb >> 8) & 0xFF extrai o G. Atenção: existem dois deslocamentos à direita — o aritmético >> preserva o bit de sinal (um negativo continua negativo) e o lógico >>> preenche com 0. Em JavaScript os deslocamentos acontecem em 32 bits, 1 << 31 dá −2147483648 e 1 << 32 equivale a 1 << 0 = 1, porque a quantidade de bits é tratada como módulo 32.
As permissões de arquivo do Linux são 9 bits: dono, grupo e outros, com 3 bits cada, na ordem leitura r = 4, escrita w = 2 e execução x = 1. A soma de cada trio dá um dígito octal: rwxr-xr-x = 7, 5, 5 → 755; rw-r--r-- = 644. É a aplicação mais direta de valores posicionais e máscaras no dia a dia de quem administra sistemas: chmod u+x é um OR com 0o100, e chmod o-w é um AND com ~0o002. Ainda pode haver os bits 10 a 12 (setuid, setgid e sticky), e é por isso que às vezes aparece um quarto dígito, como 4755.
Um ponto flutuante é a notação científica em binário:
Precisão simples em 32 bits = 1 bit de sinal s + 8 bits de expoente e (viés 127) + 23 bits de mantissa f; precisão dupla em 64 bits = 1 + 11 (viés 1023) + 52. A mantissa guarda só a parte fracionária, porque o 1 da parte inteira é implícito — um bit de precisão de graça. O expoente é armazenado com viés para que comparar dois pontos flutuantes bit a bit seja monotônico como comparar inteiros. 0.15625 = = , o campo de expoente vale −3 + 127 = 124 = 01111100 e o campo de mantissa é 01 seguido de zeros.
Alguns códigos especiais: expoente todo 0 é número subnormal (valores muito próximos de 0 e o ±0); expoente todo 1 com mantissa toda 0 é ±∞; expoente todo 1 com mantissa diferente de 0 é NaN — é por isso que 0/0 é NaN enquanto 1/0 é Infinity, e também por isso que o NaN tem vários padrões de bits e ainda assim "não é igual a si mesmo".
Uma fração binária só representa exatamente somas de potências negativas de 2: 0,5; 0,25; 0,125… Já é uma dízima infinita em binário, , e a mantissa de 52 bits precisa arredondar. Então o 0.1 de precisão dupla é exatamente
um pouco maior que 0,1; o 0.2 também é um pouco maior; somando os dois e arredondando chega-se a 0,3000000000000000444…, enquanto o literal 0.3 mais próximo em precisão dupla é 0,29999999999999998889… — dois números binários diferentes, e por isso 0.1 + 0.2 === 0.3 é false. Não é um bug do JavaScript: qualquer linguagem que use IEEE 754 (Python, Java, C, Go) faz igual.
A saída depende do cenário: dinheiro pede inteiros em centavos ou uma biblioteca decimal (decimal, BigDecimal, Decimal.js); comparação pede uma margem de erro, Math.abs(a − b) < ε; exibição pede toFixed(2) só no último passo; contagem pede inteiros, e a precisão dupla representa exatamente todo inteiro dentro de , acima disso é hora de usar BigInt. A questão de múltipla escolha do último nível pergunta se o 0.1 armazenado é maior ou menor que o valor real, e a resposta é "maior" — basta olhar o 55511… a partir da 18ª casa da expansão exata.
BigInt não entram.Math.fround, meia precisão e bfloat16 ficam de fora.0x.10000000 é −128 e não −0, e −1 é tudo 1.>> é só dividir por 2": para números negativos o arredondamento é para baixo e não para zero: −5 >> 1 dá −3, enquanto Math.trunc(−5 / 2) dá −2.toFixed": toFixed só arredonda na exibição, e o erro das contas intermediárias já se acumulou; dinheiro deve começar em centavos inteiros.Int32Array e | 0 rodam em complemento de dois de 32 bits e estouram sim; e o Number perde precisão de inteiro acima de .& 0xFF, >>> 24, | (1 << 3), 0o644 — depois dos níveis 11 a 15, fica evidente quais bits cada trecho pega ou liga.
O estouro do nível 10 e o arredondamento do nível 17 explicam a maior parte desses bugs: no primeiro caso, use um tipo mais largo ou BigInt; no segundo, centavos inteiros ou uma biblioteca decimal.
Máscara de sub-rede é mascara com AND (nível 11): 192.168.1.37 & 255.255.255.0 = 192.168.1.0; e o significado de chmod 755 / 644 explica "por que o script não tem permissão de execução" (nível 15).
Complemento de dois, estouro, troca com XOR, multiplicação e divisão por deslocamento, campos do IEEE 754 e 0.1 + 0.2 estão entre as perguntas básicas mais frequentes, e cada nível funciona como um teste rápido.
Na maioria dos níveis zeros à esquerda podem ser omitidos (1011 e 00001011 valem); os níveis marcados como "complemento de dois de 8 bits" exigem exatamente 8 bits, porque a largura faz parte da resposta.
0x?Não fazem diferença: ff, FF e 0xFF são aceitos.
São duas leituras da mesma sequência de bits: sem sinal o bit mais significativo vale e com sinal ele vale . Em 8 bits, 11111111 é 255 sem sinal e −1 com sinal.
Ele expande a mantissa e o expoente da precisão dupla pela definição, chegando a um número racional, e faz a divisão longa para obter todos os dígitos decimais — não é uma aproximação, é a representação decimal exata daquele número binário.
No localStorage do navegador atual, sem envio para servidor; o link de "compartilhar este nível" carrega apenas o número do nível, não o progresso.
O curso roda inteiro no navegador: conversão entre bases, operações de bits, decomposição dos campos de ponto flutuante e expansão exata são cálculos de funções puras dentro da página, sem pedir nada a servidor; o progresso fica no localStorage do seu aparelho.
chmod — definição do modo simbólico e do modo octal: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/chmod.html(consultado em 2026-09-09)Atualizado em 2026-09-09
17 níveis: conversão binário/octal/hexadecimal, alternância de bits, complemento de dois e estouro, AND/OR/XOR/deslocamentos, bits de permissão chmod, decomposição do IEEE 754 e o mistério de 0,1 + 0,2
Esta ferramenta ainda não está totalmente traduzida; parte do conteúdo usa o idioma de origem ou um idioma de reserva.
ObjetivoO painel de valores mostra binário 1011. O que é isso em decimal?
O valor posicional de cada dígito é uma potência de 2: o mais à direita é 2⁰=1, então 2, 4, 8, 16… Adicione os pesos cujo bit é 1: 1011 = 8 + 0 + 2 + 1 = 11. Clicar em qualquer bit no painel atualiza o decimal imediatamente - uma maneira mais rápida de construir intuição do que memorizar regras.