Representações binárias de inteiros negativos

Este é um guia rápido para aprender como funciona a representação de inteiros negativos em computadores. Independentemente da convenção, inteiros positivos sempre têm a mesma representação. O que muda entre as convenções é a representação dos negativos.

Neste post listarei três tipos de representações. Em todas elas, utiliza-se o bit mais significativo (Most Significant Bit - MSB) para determinar o sinal. Se for 1, é negativo, se for 0, é positivo.

Sinal e Magnitude

Esta é simples. Para transformar um número positivo num negativo, basta trocar o sinal, através do MSB. Ou seja, se 00000010 é +2, 10000010 é -2.

O problema desta representação é que ela não é eficiente na hora de realizar cálculos aritméticos. Então antes de enviar um número negativo para a unidade aritmética, os processadores que utilizavam essa representação convertiam para outra representação (complemento a um, por exemplo), e quando liam o resultado, convertiam de volta para o "Sinal e Magnitude" antes de gravar no registrador.

Outro problema é a dupla representação do zero. Há o zero 0000000 e o zero negativo 10000000. Graças a isto, a operação de comparação com zero seria formada por duas operações na prática.

Num inteiro sem sinal, oito bits podem representar 256 valores (0 a 255). Já num inteiro com sinal, utilizando a representação Sinal e Magnitude, perderíamos 1 bit para o sinal e teríamos 7 bits para a magnitude. Ou seja, 0 a 127 com MSB 0 (0 a +127), e 0 a 127 com MSB 1 (-0 a -127). Continuamos com 256 valores, mas dois representam a mesma coisa (0 e -0), então na prática, podemos representar apenas 255 valores, quando estamos trabalhando com inteiros com sinal, usando Sinal e Magnitude.

Complemento a Um

Na representação Complemento a Um, em vez de trocar apenas o MSB, precisamos também inverter todos os outros bits, se o número for negativo.

Repetindo o exemplo do 2 em um inteiro de 8 bits, aqui estão os seus valores utilizando Complemento a Um:
+2: 00000010
-2: 11111101

Perceba que agora podemos utilizar estes valores para realizar cálculos aritméticos e obtermos resultados válidos, diferentemente da representação com Sinal e Magnitude.

Se somarmos -2 com 2, obteremos 11111111, que significa -0. Ou seja, assim como a representação anterior, Complemento a Um também possui duas representações para o zero (00000000 e 11111111). E  para corrigir este problema, "inventaram" a representação Complemento a Dois, explicada a seguir.

Complemento a Dois

Esta representação é semelhante a Complemento a Um, com a diferença que possui mais um passo para tornar um número positivo em negativo.

Além de setar o MSB como 1 e inverter o restante dos dígitos, somamos 1 a este valor.

Ou seja, o passo-a-passo para transformar o dois positivo em dois negativo é:

Valor inicial: 00000010 (Dois positivo)
  1. Trocar MSB: 10000010
  2. Inverter bits após MSB: 11111101
  3. Somar um: 11111110
Nesta representação, as operações aritméticas também são preservadas, assim como no Complemento a Um. Se somarmos -2 com +2, obtemos:

+2: 00000010
-2: 11111110
-------------
   100000000

Resultado:
    00000000

Como você percebeu, o resultado verdadeiro precisaria de nove bits. Como isto ultrapassa o espaço que tínhamos para representar o inteiro, ele zera, assim como um hodômetro quando ultrapassa seu limite. Ele começa a contar do zero novamente. Isto é conhecido como overflow de inteiro, e apesar de parecer uma limitação, é usado a todo momento para realizar subtração de inteiros.

Na tabela abaixo, fazemos uma comparação da representação dos inteiros negativos, considerando uma máquina hipotética que utiliza 5 bits para guardar um inteiro:


Assimetria do Complemento a Dois

Preste atenção na diferença entre o Complemento a Um e Complemento a Dois na tabela. Veja que é como se fosse a mesma coluna, só que a da direita (Compl. a Dois) está deslocada uma linha para cima. Há dois efeitos para este deslocamento, um é a eliminação da dupla representação do zero, e outro ainda não havia sido mencionado, que é a assimetria de valores possíveis para o Complemento a Dois.

Pela tabela acima, a representação de Complemento a Dois parece desperdiçar o valor binário 10000. Ele está presente na coluna do Complemento a Um, mas não na do Complemento a Dois.

Isto acontece apenas na tabela. Na realidade, o Complemento a Dois não desperdiça nenhum valor binário. O 10000 no exemplo hipotético de inteiros de 5 bits corresponderia ao valor -16, que não seria possível de representar nem com o Sinal e Magnitude, nem com o Complemento a Um.

Ou seja, com 5 bits utilizando Complemento a Dois, poderíamos representar de -16 a -1 (10000 a 11111) e de 0 a 15 (00000 a 01111), totalizando 32 valores. Nas outras representações, só são representados 31 valores, já que temos dois reservados para o zero.