Home > Tecnologia > Informática > Arquitectura de Computadores > Números inteiros negativos em binário

Números inteiros negativos em binário

Como representar números inteiros negativos em binário

Na nossa numeração decimal, estamos habituados a ver o sinal “-” quando temos números negativos. Isto é, para além de termos os 10 algarismos, de 0 a 9, ainda podemos usar o símbolo “-” para indicar que o número é negativo.

Nos computadores só temos mesmo zeros e uns e não há como representar directamente o símbolo “-”. Como poderemos, então, tratar números negativos?

Imagine-se que queremos construir uma calculadora em binário. Para já, temos que ter em conta o número de bits que temos disponíveis na nossa “calculadora”. Comecemos por considerar que temos 8 bits. Neste caso, teremos 28 = 256 combinações, as quais podemos numerar de 0000 0000 a 1111 1111 em binário, ou seja, de 0 a 255 em decimal. E, já agora, de 00h a FFh (hexadecimal) – só para relembrar.

A solução é dedicarmos um bit para identificar se um número é positivo ou negativo e chama-se a esse bit, bit de sinal. Este é situado no MSB (Most Significant Bit) do nosso número binário. Ao usarmos um bit de sinal, restam-nos 7 bits para representar valores, agora positivos e negativos. Para cada parte, ficamos com 27 = 128 combinações.

Existem várias formas de codificar números positivos e números negativos. Neste tópico vou apenas referir a mais usada: O complemento para dois.

No complemento para 2, quando o número é positivo, o bit de sinal (no MSB) fica a 0. Assim, temos os números positivos a variar entre 0000 0000 a 0111 1111 em binário, ou seja, de 0 a 127. E aqui estão as 128 combinações “não negativas”, pois inclui-se o zero. Para representar um número negativo, o bit de sinal fica a 1. Neste caso, podemos ver os números negativos a variar entre 1000 0000 e 1111 1111. Qual a variação em decimal? Irei adiantar que será de -128 a -1 (tendo 128 combinações negativas).

Como chegamos ao valor negativo? Usando a regra de complemento para 2, fazemos:

  • Invertemos os bits todos (a este passo também se chama complemento para 1)
  • Somamos +1

Vejamos:

  • 1000 0000 → (invertendo os bits) 0111 1111 → somando +1 = 1000 0000 (2) = 128 (10)
  • 1111 1111 → (invertendo os bits) 0000 0000 → somando +1 = 0000 0001 (2) = 1 (10)

Como temos o bit de sinal a 1, os resultados serão -128 e -1, respectivamente.

Vejamos um exemplo. Converta-se o seguinte número binário para decimal com bit de sinal:

1101 0011 (2)

Para facilitar, usemos uma tabela para aplicar o complemento para 2:

11010011
00101100
+1
00101101

Aplicou-se então uma inversão de bits e somou-se mais 1. Ficámos com o valor 0010 1101 que em decimal é:

1 × 25 + 1 × 23 + 1 × 22 + 1 × 20 = 32 + 8 + 4 + 1 = 45

Ou seja: 1101 0011 (2) = -45 (10)

NOTA: Só usamos a regra do complemento para 2 quando o bit de sinal é 1!



Vejamos a seguinte tabela e compare-se os valores em decimal com e sem sinal:

Número binárioDecimal com sinal
(complemento para 2)
Decimal sem sinal
0000 000000
0000 000111
.........
0111 1110126126
0111 1111127127
1000 0000-128128
1000 0001-127129
1000 0010-126130
.........
1111 1100-4252
1111 1101-3253
1111 1110-2254
1111 1111-1255

Uma grande vantagem do complemento para 2 é a sua aplicabilidade directa em operações de adição e subtracção, entre outras, como iremos ver.

Por exemplo, se tivermos em binário 0000 0000, ou seja zero em decimal, e subtraírmos 1, sabemos que depois dos “empresta 1”1, o nosso número binário ficará 1111 1111, ou seja -1. Ao contrário, ao somarmos 1 a 1111 1111, depois de todos os”e lá vai 1″1, ficamos com 0000 0000, ou seja 0.

Vejamos a seguinte operação de adição: 65 + (-45) em binário.

Teremos:

01000001
+11010011
100010000

Temos um “bit” extra, que é o carrier (bit de transporte), a 1 e que será ignorado. O carrier é um sinalizador (flag) do processador e está presente na tabela apenas para lembrar que, no fim de uma operação, se ainda faltar um “e lá vai 1”, este fica activo, como acontece neste caso. Assim, temos o número binário 0001 0100 que é 20 em decimal. Repare-se que a operação é directa quando aplicamos o complemento para 2, o que é uma enorme vantagem! Observe-se, também, que o bit de sinal do primeiro membro é 0, pois é um número positivo, e o do segundo membro é 1, pois é um número negativo. O bit de sinal do resultado é 0 pois o resultado é positivo!

Concluindo: 65 + (-45) = 20 em decimal.

Vejamos ainda outro exemplo:

-127 + 15 (o valor -127 está na tabela mais acima e vale 1000 0001)

10000001
+00001111
110010000

Mais uma vez, apenas foi colocado o carrier para lembrar que este bit existe no processador. Aqui é totalmente desprezável, serve apenas como mera indicação. Repare mais uma vez nos bits de sinal. No resultado temos este a 1 o que indica que o resultado é negativo. Aplique-se então o complemento para 2 para determinar o resultado.

1001 0000 → (invertendo os bits) 0110 1111 → +1 = 0111 0000 (2) = 112 (10)

Ou seja: -127 + 15 = -112 em decimal.



Noções de overflow e underflow:

Imagine-se agora que queremos fazer a soma: 96 + 48:

01100000
+00110000
10010000

Repare-se que temos dois números positivos e o resultado surge como negativo. Se estivéssemos a operar sem sinal, o resultado até estaria certo pois 96 + 48 = 144, mas estamos a trabalhar com sinal! Logo, alguma coisa está errada! De facto, se fossemos aplicar a regra do complemento para 2 verificávamos que:

1001 0000 → (invertendo os bits) 0110 0000 → +1 = 0110 0001(2) = 97(10)

Ou seja, seria dizer que 96 + 48 = -97! O que está totalmente errado!

Lembre-se que o limite positivo, neste caso, é 127 e a soma ultrapassa este valor! 144 é maior que 127! Estamos, então, perante um caso de OVERFLOW. Quer isto dizer que, ultrapassámos o limite positivo!

Este caso também aconteceria se estivéssemos a implementar um contador binário de passo 1 (vai somando 1 em 1). Quando este chegasse a 0111 1111 em binário (127 em decimal) passaria para 1000 0000 em binário (-128 em decimal) e diríamos que ocorreu também um overflow.

Considere-se agora que queremos efectuar a seguinte operação: -112 + (-32)

Aproveitamos este exemplo para ver como obtemos a representação de -32 usando o processo inverso do complemento para 2:

32 (10) = 0010 0000 (2) → -1 = 0001 1111 → (invertendo os bits) 1110 0000

10010000
+11100000
101110000

Repare-se que, o facto de termos ambos os membros com sinal negativo e o resultado da soma ser positivo, indica logo que algo está errado! De facto -112 – 32 seria -144, mas o que sai fora do limite negativo de -128. E se pegarmos no resultado, concluímos que -112 + (-32) ≠ 112! Existe por isso um UNDERFLOW! Ultrapassámos o limite negativo!

O mesmo acontece se estivéssemos a implementar um contador binário de passo -1 (vai decrescendo de 1 em 1). Quando chegássemos a 1000 0000 em binário (-128 em decimal) passaria para 0111 1111 em binário (127 em decimal) e diríamos também que ocorreu um underflow.

Mas como podemos testar estes casos?

Existem condições básicas para verificar se ultrapassámos limites positivos ou negativos:

  • Se a soma de dois membros positivos (bits de sinal a 0) der um resultado negativo (bit de sinal a 1) estamos perante um overflow!
  • Se a soma de dois membros negativos (bits de sinal a 1) der um resultado positivo (bit de sinal a 0) estamos perante um underflow!

Já na subtracção também é possível verificar estes erros, mas com regras diferentes. Vejamos um exemplo equivalente ao do overflow:

96 + 48 = 96 – (-48)

Mais uma vez, determine-se (-48) pelo processo inverso do complemento para 2:

48 (10) = 0011 0000 (2) → -1 = 0010 1111 → (invertendo os bits) 1101 0000

Vejamos os cálculos:

01100000
-11010000
110010000

Repare-se que voltamos a ter: 96 – (-48) ≠ -97

Daqui surge a regra:

  • Se a subtracção de um membro positivo (bit de sinal a 0) com um número negativo (bit de sinal a 1) – e que equivale a uma soma de membros positivos – der um resultado negativo (bit de sinal a 1) então estamos perante um overflow!

No caso equivale a um underflow:

-112 + (-32) = -112 – 32

10010000
-00100000
001110000

Voltamos a ter o resultado 112 positivo! O que está errado!

Daqui surge a regra:

  • Se a subtracção de um membro negativo (bit de sinal a 1) com um membro positivo (bit de sinal a 0) – e que equivale a somar um número negativo com outro número negativo – der um resultado positivo (bit de sinal a 0) então estamos perante um underflow!

Já agora, quando trabalhamos com código do processador (código máquina ou assembly), podemos verificar também o caso genérico de overflow através de um bit no registo de sinalizadores (flags), implementado pelos processadores. Oportunamente, iremos ver exemplos disso.

Próximo artigo 

Este artigo foi escrito com a antiga grafia.

Notas:

  1. Leia o artigo “Operações aritméticas em binário” para mais informações sobre a adição e subtracção em números binários.

About Carlos Santos

Frequência em mestrado de Engenharia Electrotécnica e de Computadores. Programador freelancer: Websites, Aplicações Web (JAVA e PHP), J2SE/J2EE, C/C++ e Android. Explicador e formador em informática, matemática e electrotecnia. Formação presencial ou remota através de Skype e Team Viewer. Interesses: Música, áudio, vídeo, ciência, astronomia e mitologia.

2 comments

  1. Maria Antônia

    Oi tudo bem? Você poderia me dizer qual conversão abaixo é correta?
    0xA0 / para decimal: -96 / binário: 10100000/ complemento de dois de -96 em decimal: 96

    Ou

    0xA0 / para decimal: 160/ binário: 10100000/ complemento de dois de 160 em decimal: 96

    0x00 / binario 0000 0000/ decimal 0 / complemento de dois 1 0000 0000 em decimal 255

    • Olá!
      Antes demais é mais fácil passar para binário e repare que o bit de sinal está a 1, o que indica que o número é negativo. Complementando o número binário fica 01011111, somando 1 fica 01100000 o que dá 64 + 32 = 96. Logo o resultado é -96! 🙂

Leave a Reply

Your email address will not be published and it is optional.