Aritmética binária e complemento de dois

Visualize os pesos binários, explore representações com sinal e acompanhe os cálculos por coluna.

A carregar a simulação interativa...

Um único somador também subtrai 🖖

Nos computadores modernos, os inteiros negativos são representados usando o Complemento para Dois. O bit mais significativo (MSB) age como um peso negativo: para um inteiro de 8 bits, o bit 7 representa -128 em vez de +128. A subtração torna-se idêntica à adição: a CPU calcula A - B como A + (~B + 1), eliminando hardware de subtração separado e permitindo que a ALU use os mesmos circuitos somadores para ambas as operações.

Binário é apenas valor posicional na base 2 🖖

Nos números do dia a dia, cada coluna vale dez vezes a da direita; em binário o fator é simplesmente 2. Os bits carregam (da direita para a esquerda) os pesos 1, 2, 4, 8, 16, 32, … Ler um número binário é somar os pesos onde há um 1: 1011 é 8 + 0 + 2 + 1 = 11. O mostrador de pesos de bits da ferramenta deixa você alternar cada bit e acompanhar o total acumulado, que é o segredo por trás de cada conversão aqui.

Sua CPU multiplica como um camponês russo 🖖

A multiplicação longa mostrada aqui — dobrar A e somá-lo onde B tem um bit 1 — é exatamente a "multiplicação do camponês russo", um método que já aparece em papiros egípcios de mais de 3000 anos. Divide-se um número pela metade (descartando os restos) e dobra-se o outro; depois somam-se os valores dobrados onde o número reduzido é ímpar. Dividir pela metade e checar a paridade é literalmente ler dígitos binários, então um antigo escriba e uma ALU moderna executam o mesmo algoritmo.

OITO BITS, QUATRO SIGNIFICADOS — QUAL CODIFICAÇÃO ESTÁ A LER?

Em que codificação binária você está?

Um byte não dá pista alguma sobre como deve ser lido. O padrão 11010110 é 214, ou −42, ou −41, ou −86, dependendo apenas de uma convenção combinada de antemão — e os bits em si não conseguem dizer qual. Escolha errado e tudo o que vem depois está errado, enquanto tudo o que vem depois continua a parecer certo. Por isso a primeira pergunta nunca é qual o resultado, mas quanto pesa o bit mais alto. As quatro codificações abaixo respondem a isso de quatro maneiras; os dois últimos casos mostram por que uma delas conquistou o hardware.

Sem sinal — cada coluna soma w₇ = +128 → 0…255
Complemento de dois — o bit mais alto lhe deve 128 w₇ = −128 → −128…127
Complemento de um — trocar o sinal invertendo cada bit w₇ = −127, 0 = ±0
Sinal e magnitude — o bit que não é um número w₇ = ±, 0 = ±0
Subtração sem subtrator a − b = a + (¬b + 1)
Multiplicar deslocando e somando a × b = ∑ (a ≪ i)

01

Sem sinal — cada coluna soma

O que você sabe: Os oito pesos são potências positivas de dois, de 1 a 128. Nada codifica um sinal, portanto nada pode ser negativo: o intervalo vai de 0 a 255 e os 256 padrões estão todos em uso.

Como ler: w₇ = +128 → 0…255

Exemplo resolvido: 85 + 11 → 01010101 + 00001011 = 01100000 = 96, com os transportes a subir das colunas baixas. Force mais e 214 + 100 dá 58 em oito bits — os verdadeiros 314 menos 256, com o 1 que falta pendurado no transporte de saída.

Abrir este caso: Soma sem sinal
Sem sinal — cada coluna soma. Todos os pesos positivos: as oito colunas apenas somam, de 0 a 255. Os oito pesos são potências positivas de dois, de 1 a 128. Nada codifica um sinal, portanto nada pode ser negativo: o intervalo vai de 0 a 255 e os 256 padrões estão todos em uso.
Todos os pesos positivos: as oito colunas apenas somam, de 0 a 255.

02

Complemento de dois — o bit mais alto lhe deve 128

O que você sabe: Sete pesos positivos e um negativo: o bit 7 vale −128 em vez de +128. Nada mais muda, e o intervalo desloca-se para −128 até 127.

Como ler: w₇ = −128 → −128…127

Exemplo resolvido: 11010110 decompõe-se em −128 + 64 + 16 + 4 + 2 = −42. Some 10 (00001010) com adição comum por colunas e obtém 11100000 = −128 + 64 + 32 = −32. Esses mesmos oito bits valem 214 no modo sem sinal.

Abrir este caso: Complemento de dois
Complemento de dois — o bit mais alto lhe deve 128. O bit 7 pesa −128, portanto 11010110 é −42 — os bits a que o modo sem sinal chama 214. Sete pesos positivos e um negativo: o bit 7 vale −128 em vez de +128. Nada mais muda, e o intervalo desloca-se para −128 até 127.
O bit 7 pesa −128, portanto 11010110 é −42 — os bits a que o modo sem sinal chama 214.

03

Complemento de um — trocar o sinal invertendo cada bit

O que você sabe: O bit 7 pesa −127. Um número negativo é o inverso bit a bit da sua magnitude, portanto −42 é 11010101 e não 11010110, e o intervalo é simétrico: −127 a 127.

Como ler: w₇ = −127, 0 = ±0

Exemplo resolvido: −42 é 11010101, o inverso de 00101010. Somando 10 chega-se a 11011111 = −127 + 64 + 16 + 8 + 4 + 2 + 1 = −32, e isso só está certo aqui porque nada saiu pelo topo. Tente em vez disso −42 + 50: a soma simples lê-se 7, um a menos, e o transporte de saída tem de voltar a entrar por baixo para chegar a 8.

Abrir este caso: Complemento de um
Complemento de um — trocar o sinal invertendo cada bit. −42 é apenas 42 invertido, e 11111111 é um segundo zero, negativo. O bit 7 pesa −127. Um número negativo é o inverso bit a bit da sua magnitude, portanto −42 é 11010101 e não 11010110, e o intervalo é simétrico: −127 a 127.
−42 é apenas 42 invertido, e 11111111 é um segundo zero, negativo.

04

Sinal e magnitude — o bit que não é um número

O que você sabe: O bit 7 é uma bandeira pura, sem peso nenhum: 0 significa positivo, 1 significa negativo, e os sete bits baixos guardam uma magnitude comum de 0 a 127.

Como ler: w₇ = ±, 0 = ±0

Exemplo resolvido: −42 é 10101010: o bit de sinal levantado e depois 42 na forma 0101010. É assim que as pessoas escrevem números, e é a única das quatro codificações em que entregar ambos os operandos a um somador comum está simplesmente errado — 10101010 + 00001010 sai como 10110100, que se lê −52 e não −32.

Abrir este caso: Sinal e magnitude
Sinal e magnitude — o bit que não é um número. O bit de sinal não carrega peso — e um somador comum devolve −52 em vez de −32. O bit 7 é uma bandeira pura, sem peso nenhum: 0 significa positivo, 1 significa negativo, e os sete bits baixos guardam uma magnitude comum de 0 a 127.
O bit de sinal não carrega peso — e um somador comum devolve −52 em vez de −32.

05

Subtração sem subtrator

O que você sabe: Complemento de dois com a operação em subtração. O hardware não possui circuito de subtração: troca o sinal do segundo operando e soma.

Como ler: a − b = a + (¬b + 1)

Exemplo resolvido: 42 − 58 → inverta 00111010 para 11000101, some 1 e obtenha 11000110, que é −58. Agora some-lhe 00101010: 11110000, e isso lê-se −128 + 64 + 32 + 16 = −16.

Abrir este caso: Subtrair somando
Subtração sem subtrator. Inverta, some um, depois some: 42 + (−58) aterra em −16. Complemento de dois com a operação em subtração. O hardware não possui circuito de subtração: troca o sinal do segundo operando e soma.
Inverta, some um, depois some: 42 + (−58) aterra em −16.

06

Multiplicar deslocando e somando

O que você sabe: Modo sem sinal com a operação em multiplicação. Todo bit 1 do segundo operando contribui com uma cópia do primeiro, deslocada à esquerda pela posição desse bit.

Como ler: a × b = ∑ (a ≪ i)

Exemplo resolvido: 13 × 5 → o 5 é 00000101, portanto os bits 0 e 2 estão levantados. Isso contribui com 13 sem deslocamento (00001101 = 13) mais 13 deslocado duas casas (00110100 = 52), e 13 + 52 = 65 = 01000001.

Abrir este caso: Deslocar e somar
Multiplicar deslocando e somando. O 5 tem os bits 0 e 2 levantados, portanto 13 e 52 são as únicas linhas que contam. Modo sem sinal com a operação em multiplicação. Todo bit 1 do segundo operando contribui com uma cópia do primeiro, deslocada à esquerda pela posição desse bit.
O 5 tem os bits 0 e 2 levantados, portanto 13 e 52 são as únicas linhas que contam.

Problema resolvido na íntegra

  1. Dois indicadores de overflow separados para 42 convertido em oito bits 6 passos

    Converta 42 para oito bits de duas formas diferentes e, em seguida, descubra por que razão um CPU possui duas flags de overflow distintas quando tem apenas um somador.

    1. A notação posicional é uma soma de potências, pelo que a via direta consiste em determinar quais as potências de dois que estão presentes. Três delas, e o padrão de bits surge de imediato.

    2. A via mecânica dá a mesma resposta sem qualquer pesquisa. Divida por dois repetidamente e os restos são os bits, o menos significativo primeiro — leia a coluna de baixo para cima.

    3. A negação em complemento para dois é inverter e depois incrementar, e o resultado é igual a 256 − 42. Esse é todo o truque: aritmética módulo 256, com a metade superior reclassificada como negativa.

    4. Agora as flags. O transporte de saída é uma propriedade da posição do bit mais significativo; o overflow é uma divergência entre o transporte de entrada no bit de sinal e o transporte de saída do mesmo.

    5. Considere um par em que as duas flags divergem. Nenhum transporte sai do byte, pelo que a aritmética sem sinal está correta, mas o bit de sinal inverteu-se — a resposta com sinal está errada em 256.

    6. Inverta a situação com um par que gera transporte mas não overflow, e o argumento a favor de duas flags fica concluído.

    Resposta

    Porque os mesmos bits significam dois números diferentes, e apenas o programador sabe de qual se trata. 0110 0100 + 0011 0010 = 1001 0110 não produz transporte de saída do bit 7, pelo que C = 0 e uma leitura sem sinal de 100 + 50 = 150 é perfeitamente correta. Leia o mesmo resultado em complemento para dois e este é −106, o que não faz sentido, e V = 1 indica isso mesmo. Some 200 + 100 em vez disso e as flags invertem-se: C = 1, V = 0. O somador não sabe nem quer saber — calcula uma soma e ativa ambos os alarmes, e a instrução que o compilador escolhe a seguir decide qual deles é um erro. É por isso que C e C++ deixam o overflow com sinal indefinido e definem o wraparound sem sinal: o hardware distingue-os, e a linguagem optou por expor essa diferença.

Referências (1)

Problemas de exemplo

  • Soma sem sinal - 85 + 11 em binário, com o transporte a propagar-se pelas colunas.
  • Complemento de dois - Complemento de dois: 11010110 lê-se −42, e −42 + 10 = −32.
  • Complemento de um - Complemento de um: o bit mais alto pesa −127, então −42 é 11010101.
  • Sinal e magnitude - Sinal e magnitude: o bit mais alto é puro sinal, então −42 é 10101010.
  • Subtrair somando - 42 − 58 = −16, ilustrando como a subtração se faz somando, graças ao peso negativo do bit mais alto.
  • Deslocar e somar - 13 × 5 = 65 por multiplicação binária de deslocar e somar.