Isso é feito para que a adição não precise ter nenhuma lógica especial para lidar com números negativos. Confira o artigo na Wikipedia .
Digamos que você tenha dois números, 2 e -1. Na sua maneira "intuitiva" de representar números, eles seriam 0010
e 1001
, respectivamente (estou usando 4 bits de tamanho). No caminho do complemento dos dois , eles são 0010
e 1111
. Agora, digamos que eu queira adicioná-los.
A adição do complemento de dois é muito simples. Você adiciona números normalmente e qualquer bit de transporte no final é descartado. Então, eles são adicionados da seguinte forma:
0010
+ 1111
=10001
= 0001 (discard the carry)
0001
é 1, que é o resultado esperado de "2 + (- 1)".
Mas no seu método "intuitivo", adicionar é mais complicado:
0010
+ 1001
= 1011
Qual é -3, certo? A adição simples não funciona neste caso. Você precisa observar que um dos números é negativo e, se esse for o caso, use um algoritmo diferente.
Para esse método de armazenamento "intuitivo", a subtração é uma operação diferente da adição, exigindo verificações adicionais dos números antes que eles possam ser adicionados. Como você deseja que as operações mais básicas (adição, subtração, etc.) sejam o mais rápido possível, é necessário armazenar números de uma maneira que permita usar os algoritmos mais simples possíveis.
Além disso, no método de armazenamento "intuitivo", existem dois zeros:
0000 "zero"
1000 "negative zero"
Que são intuitivamente o mesmo número, mas têm dois valores diferentes quando armazenados. Todo aplicativo precisará executar etapas extras para garantir que valores diferentes de zero também não sejam negativos.
Há outro bônus em armazenar entradas dessa maneira, e é nesse momento que você precisa estender a largura do registro em que o valor está sendo armazenado. Com o complemento two, armazenar um número de 4 bits em um registro de 8 bits é uma questão de repetir sua bit mais significativo:
0001 (one, in four bits)
00000001 (one, in eight bits)
1110 (negative two, in four bits)
11111110 (negative two, in eight bits)
É apenas uma questão de olhar para o pedaço de sinal da palavra menor e repeti-lo até preencher a largura da palavra maior.
Com seu método, você precisaria limpar o bit existente, que é uma operação extra além do preenchimento:
0001 (one, in four bits)
00000001 (one, in eight bits)
1010 (negative two, in four bits)
10000010 (negative two, in eight bits)
Você ainda precisa definir os 4 bits extras nos dois casos, mas no caso "intuitivo", também é necessário limpar o quinto bit. É um pequeno passo extra em uma das operações mais fundamentais e comuns presentes em todos os aplicativos.