Vai al contenuto

Lezione 03 · Rappresentazione dei numeri relativi in binario

Cosa impari

  • quali numeri puoi rappresentare con l bit in binario puro;
  • quattro modi di rappresentare i numeri negativi: segno e modulo, complemento a uno, complemento a due, eccesso 2ˡ⁻¹;
  • a codificare e decodificare un numero in ciascuna rappresentazione, e a capire quando non è rappresentabile;
  • perché il complemento a due è il più usato: somma e sottrazione con un solo circuito;
  • a fare somme in complemento a due e a riconoscere l'overflow.

Nella lezione 02 hai convertito solo numeri positivi. Ma un calcolatore deve gestire anche temperature sotto zero, saldi in rosso, quote sotto il livello del mare. In memoria non c'è un simbolo "−": ci sono solo bit. Serve quindi una regola per decidere quali parole di bit rappresentano i numeri negativi.

In tutta la lezione l è il numero di bit a disposizione e la parola codice ha sempre esattamente l bit (si aggiungono zeri a sinistra se servono).

Binario puro: i numeri naturali

La rappresentazione vista finora si chiama binario puro. Con l bit hai 2ˡ parole codice e rappresenti i numeri naturali da 0 a 2ˡ − 1.

Intervallo: [0, 2ˡ − 1]

Parola (l = 2) Valore
00 0
01 1
10 2
11 3

Con l = 8 rappresenti i numeri da 0 a 255. Nessun numero negativo.

Perché tante rappresentazioni?

I numeri relativi sono gli interi positivi, negativi e lo zero. Esistono più modi di rappresentarli: segno e modulo, complemento a uno, complemento a due, eccesso. Ognuno nasce per rendere più semplici ed efficienti i circuiti che fanno i calcoli nel processore. Vediamoli uno alla volta.

Segno e modulo

È l'idea più naturale, simile a come scriviamo i numeri a mano:

  • il bit più a sinistra (MSB) è il segno: 0 per positivo, 1 per negativo;
  • gli altri l − 1 bit contengono il modulo (valore assoluto) in binario puro.

Intervallo: [−(2ˡ⁻¹ − 1), 2ˡ⁻¹ − 1]. Con l = 8: da −127 a +127.

Esempio svolto: ±73 su 8 bit

|73| = 73 = (1001001)₂, cioè 7 bit. Ne servono 7 per il modulo: va bene.

Numero Segno Modulo (7 bit) Parola
+73 0 1001001 01001001
−73 1 1001001 11001001
Parola (l = 3) Binario puro Segno e modulo
000 0 0
001 1 1
010 2 2
011 3 3
100 4 −0
101 5 −1
110 6 −2
111 7 −3

Un numero non è rappresentabile se il suo modulo non entra in l − 1 bit. Ad esempio su 6 bit l'intervallo è [−31, 31]: −33 non è rappresentabile.

Svantaggi

  1. Lo zero ha due rappresentazioni: 00000000 (+0) e 10000000 (−0). Si spreca una parola codice: le 2ˡ parole rappresentano solo 2ˡ − 1 valori diversi.
  2. La somma è complicata: bisogna prima guardare i segni.
    • Segni uguali: sommi i moduli e metti davanti il segno comune.
    • Segni diversi: sottrai il modulo minore dal maggiore e metti il segno del numero con modulo maggiore.

Esempio svolto: somme in segno e modulo con l = 5

(−9) + (−3): 11001 + 10011. Segni uguali: sommi i moduli 1001 + 0011 = 1100 e aggiungi il segno 1 → 11100 = −12.

(−4) + (+7): 10100 + 00111. Segni diversi: il modulo maggiore è 0111 (7). Calcoli 0111 − 0100 = 0011 e metti il segno di +7 → 00011 = +3.

Il complemento

Data una sequenza di k cifre che rappresenta il numero N in base b:

  • complemento alla base: Cb = bᵏ − N;
  • complemento alla base diminuita: Cd = Cb − 1 = (bᵏ − 1) − N.

In binario (b = 2) diventano:

Nome Formula Scorciatoia
Complemento a uno C1 C1 = (2ᵏ − 1) − N inverti tutti i bit (0 → 1, 1 → 0)
Complemento a due C2 C2 = 2ᵏ − N inverti tutti i bit e somma 1: C2 = C1 + 1

Esempi con k = 3 (quindi 2ᵏ = 8 = (1000)₂)

N C1: inverti i bit C2 = C1 + 1 Controllo: C2 = 1000 − N
001 110 111 1000 − 001 = 111
100 011 100 1000 − 100 = 100
111 000 001 1000 − 111 = 001

Complemento a uno

Per codificare X su l bit:

  • se X ≥ 0 lo scrivi in binario puro (il primo bit sarà 0);
  • se X < 0 scrivi |X| in binario puro su l bit e inverti tutti i bit. In formula: Y = 2ˡ − |X| − 1.

Intervallo: [−(2ˡ⁻¹ − 1), 2ˡ⁻¹ − 1], simmetrico, come segno e modulo. Il MSB indica ancora il segno: 0 positivo, 1 negativo.

Esempio svolto: −9 in complemento a uno su 8 bit

Passo Bit
9 in binario puro su 8 bit 00001001
Inverti tutti i bit 11110110

Con la formula: 2⁸ − 9 − 1 = 246 = (11110110)₂. Stesso risultato.

Parola (l = 4) C1 Parola C1
0000 0 1000 −7
0001 1 1001 −6
0010 2 1010 −5
0011 3 1011 −4
0100 4 1100 −3
0101 5 1101 −2
0110 6 1110 −1
0111 7 1111 −0

Anche qui lo zero ha due rappresentazioni (0000 e 1111) e questo complica somme e sottrazioni. Il vantaggio è che i negativi si ottengono in modo semplicissimo, invertendo i bit.

Dal complemento a uno al decimale (8 bit):

  • MSB = 0: numero positivo, normale conversione binario → decimale;
  • MSB = 1: numero negativo. Inverti tutti i bit e converti: ottieni il modulo. (Oppure con la formula: |N| = 2⁸ − 1 − valore della parola.)
Parola Segno Bit invertiti Valore
00000100 + – 4
00001001 + – 9
10000000 − 01111111 = 127 −127
10010010 − 01101101 = 109 −109
10101010 − 01010101 = 85 −85
11111111 − 00000000 = 0 −0

Complemento a due

È il metodo più diffuso nei calcolatori per i numeri interi con segno. Per codificare X su l bit:

  • se X ≥ 0 lo scrivi in binario puro (il primo bit sarà 0);
  • se X < 0 scrivi |X| in binario puro su l bit, inverti tutti i bit e somma 1. In formula: Y = 2ˡ − |X|.

Intervallo: [−2ˡ⁻¹, 2ˡ⁻¹ − 1]. Con l = 8: da −128 a +127. L'intervallo non è simmetrico: c'è un negativo in più.

Esempio svolto: −9 in complemento a due su 8 bit

Passo Bit
9 in binario puro su 8 bit 00001001
Inverti tutti i bit (C1) 11110110
Somma 1 + 1
Risultato 11110111

Con la formula: 2⁸ − 9 = 247 = (11110111)₂. Stesso risultato.

Esempio svolto: X = 10, 5, −5 su l = 4 bit

L'intervallo è [−8, 7].

  • X = 10: è fuori dall'intervallo, non rappresentabile.
  • X = 5: è positivo, binario puro → 0101.
  • X = −5: metodo 1, 2⁴ − 5 = 11 = 1011; metodo 2, 0101 → inverti 1010 → +1 → 1011.
Parola (l = 3) Binario puro Segno e modulo C1 C2
000 0 0 0 0
001 1 1 1 1
010 2 2 2 2
011 3 3 3 3
100 4 −0 −3 −4
101 5 −1 −2 −3
110 6 −2 −1 −2
111 7 −3 −0 −1

I vantaggi del complemento a due

  • Una sola rappresentazione dello zero: tutti i bit a 0. Nessuna parola sprecata.
  • Il MSB indica il segno.
  • Somma e sottrazione usano lo stesso circuito e non devono controllare i segni (lo vedi più sotto).

Dal complemento a due al decimale (8 bit). Se il MSB è 0 è una normale conversione. Se il MSB è 1 hai due metodi:

  • Metodo 1: il MSB ha peso negativo, −2⁷ = −128. Gli altri bit hanno il peso solito. Valore = −128 + c₆·2⁶ + … + c₀·2⁰.
  • Metodo 2: inverti tutti i bit, converti e somma 1: ottieni il modulo. Metti il segno meno.
Parola Metodo 1 (MSB = −128) Metodo 2 Valore
00000100 4 – 4
00001001 8 + 1 – 9
10000000 −128 −(01111111 + 1) = −(127 + 1) −128
10010010 −128 + 16 + 2 −(01101101 + 1) = −(109 + 1) −110
10101010 −128 + 32 + 8 + 2 −(01010101 + 1) = −(85 + 1) −86
11111111 −128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 −(00000000 + 1) −1

Confronta questa tabella con quella del complemento a uno: la stessa parola vale un'unità in meno (−86 invece di −85).

Rappresentazione per eccesso

Si sceglie un numero positivo k, detto eccesso (o bias). Per codificare X si scrive X + k in binario puro su l bit. Così i numeri da −k a 2ˡ − k − 1 vengono "spostati" su 0 … 2ˡ − 1.

Parola (l = 2) Binario puro Eccesso 1 Eccesso 2 Eccesso 3
00 0 −1 −2 −3
01 1 0 −1 −2
10 2 1 0 −1
11 3 2 1 0

Il caso più usato è k = 2ˡ⁻¹ (eccesso 128 su 8 bit, eccesso 64 su 7 bit, …):

  • Intervallo: [−2ˡ⁻¹, 2ˡ⁻¹ − 1], lo stesso del complemento a due. Con l = 8: da −128 a +127.
  • Una sola rappresentazione dello zero: 10000000 su 8 bit.
  • Su 8 bit i negativi vanno nelle parole 0 … 127, lo zero in 128, i positivi in 129 … 255.
  • Trucco: la parola in eccesso 2ˡ⁻¹ è uguale a quella in complemento a due con il primo bit invertito.

In eccesso il primo bit non è il segno

Qui un MSB uguale a 1 indica un numero positivo o zero, e 0 un numero negativo: il contrario delle altre rappresentazioni. Per sapere il segno devi decodificare il numero.

Esempio svolto: ±12 in eccesso 128 su 8 bit

X X + 128 Binario puro (8 bit) Controllo con il trucco
+12 140 10001100 C2(12) = 00001100 → inverti il primo bit → 10001100
−12 116 01110100 C2(−12) = 11110100 → inverti il primo bit → 01110100

Decodifica: converti la parola in binario puro e sottrai l'eccesso. Ad esempio 0110100 in eccesso 64 (7 bit): 52 − 64 = −12.

Confronto delle quattro rappresentazioni (8 bit)

N |N| in binario Segno e modulo Complemento a 1 Complemento a 2 Eccesso 128
−128 10000000 non esiste non esiste 10000000 00000000
−127 01111111 11111111 10000000 10000001 00000001
−100 01100100 11100100 10011011 10011100 00011100
−10 00001010 10001010 11110101 11110110 01110110
−1 00000001 10000001 11111110 11111111 01111111
0 00000000 00000000 e 10000000 00000000 e 11111111 00000000 10000000
1 00000001 00000001 00000001 00000001 10000001
10 00001010 00001010 00001010 00001010 10001010
100 01100100 01100100 01100100 01100100 11100100
127 01111111 01111111 01111111 01111111 11111111
128 10000000 non esiste non esiste non esiste non esiste
Rappresentazione Intervallo con l bit Con l = 8 Zeri
Binario puro [0, 2ˡ − 1] [0, 255] 1
Segno e modulo [−(2ˡ⁻¹ − 1), 2ˡ⁻¹ − 1] [−127, 127] 2
Complemento a uno [−(2ˡ⁻¹ − 1), 2ˡ⁻¹ − 1] [−127, 127] 2
Complemento a due [−2ˡ⁻¹, 2ˡ⁻¹ − 1] [−128, 127] 1
Eccesso 2ˡ⁻¹ [−2ˡ⁻¹, 2ˡ⁻¹ − 1] [−128, 127] 1

Verifica con Python (facoltativo). Scrivi un numero e il numero di bit: il programma mostra le quattro codifiche, oppure ti dice che il numero non è rappresentabile.

x = int(input('Numero intero (anche negativo): '))
l = int(input('Numero di bit: '))

# Valore (in binario puro) della parola codice in ogni rappresentazione
if x >= 0:
    sm = x
    c1 = x
    c2 = x
else:
    sm = 2 ** (l - 1) + (-x)    # bit di segno a 1 + modulo
    c1 = 2 ** l - (-x) - 1
    c2 = 2 ** l - (-x)
ecc = x + 2 ** (l - 1)

nomi = ['Segno e modulo', 'Complemento a 1', 'Complemento a 2', 'Eccesso ' + str(2 ** (l - 1))]
valori = [sm, c1, c2, ecc]
simmetrica = -(2 ** (l - 1) - 1) <= x <= 2 ** (l - 1) - 1
asimmetrica = -(2 ** (l - 1)) <= x <= 2 ** (l - 1) - 1
rappresentabile = [simmetrica, simmetrica, asimmetrica, asimmetrica]

for i in range(4):
    if rappresentabile[i]:
        n = valori[i]
        cifre = ''
        for j in range(l):          # esattamente l bit
            cifre = str(n % 2) + cifre
            n = n // 2
        print(f'{nomi[i]:17}: {cifre}')
    else:
        print(f'{nomi[i]:17}: non rappresentabile')

Prova con −9 su 8 bit, −128 su 8 bit e −33 su 6 bit.

Tool · Numeri relativi

Scrivi un numero e il numero di bit: ottieni la parola in tutte e quattro le rappresentazioni (più il binario puro), con l'intervallo e i passaggi. Nella scheda Da bit a decimale fai il percorso inverso, come nelle tabelle di decodifica.

Somme in complemento a due

Con il complemento a due (e con l'eccesso 2ˡ⁻¹) la sottrazione diventa una somma: X − Y = X + (−Y). Basta un unico algoritmo e un unico circuito: sommi le due parole bit per bit, come in binario puro, senza guardare i segni.

Regole:

  1. Fai la somma normale dei due numeri su l bit.
  2. Se esce un riporto oltre l'ultimo bit (a sinistra), ignoralo.
  3. Overflow: succede solo se i due operandi hanno lo stesso segno e il risultato ha segno diverso. Se gli operandi hanno segni diversi il risultato è sempre corretto.

Esempio svolto: 13 + (−20) su 8 bit

Bit Valore
00001101 13
+ 11101100 −20
= 11111001 −128 + 64 + 32 + 16 + 8 + 1 = −7

Nessun riporto finale, segni diversi: risultato corretto.

Esempi svolti su 4 bit (intervallo [−8, 7])

Operazione Somma dei bit Riporto finale Risultato su 4 bit Corretto?
4 + 2 0100 + 0010 = 0110 no 0110 = 6 sì
(−4) + (−2) 1100 + 1110 = 11010 sì, si ignora 1010 = −6 sì
4 + (−2) 0100 + 1110 = 10010 sì, si ignora 0010 = 2 sì
(−4) + 2 1100 + 0010 = 1110 no 1110 = −2 sì
6 + 3 0110 + 0011 = 1001 no 1001 = −7 no: overflow
(−6) + (−3) 1010 + 1101 = 10111 sì, si ignora 0111 = 7 no: overflow

Negli ultimi due casi gli operandi hanno lo stesso segno e il risultato ha segno opposto. Infatti 9 e −9 non stanno in [−8, 7].

Somme in eccesso 2ˡ⁻¹

In eccesso ogni parola contiene già l'eccesso: (X + 128) + (Y + 128) = (X + Y) + 256. Dopo la somma bisogna quindi sottrarre una volta l'eccesso (128 su 8 bit).

Esempio 13 + (−20): 10001101 (141) + 01101100 (108) = 11111001 (249). Poi 249 − 128 = 121 = 01111001, che in eccesso 128 vale 121 − 128 = −7.

Esempio 13 + 20: 10001101 (141) + 10010100 (148) = 289. Poi 289 − 128 = 161 = 10100001, che vale 161 − 128 = +33.

Tool · Somme in complemento a due

Prova gli esempi su 4 bit della tabella qui sopra: il tool mostra i riporti, ignora quello finale e ti dice se c'è overflow.

Errori frequenti negli esercizi

Errore Perché è sbagliato Come si corregge
Non controllare l'intervallo prima di codificare il numero può essere fuori portata calcola subito l'intervallo: 68 su 6 bit in C2 → [−32, 31], non rappresentabile
Invertire i bit senza prima arrivare a l bit gli zeri a sinistra mancanti diventano 1 mancanti scrivi |X| su l bit (es. 9 → 00001001), poi inverti
Dimenticare il +1 nel complemento a due ottieni il complemento a uno C2 = bit invertiti + 1
Invertire i bit anche dei numeri positivi i positivi non si complementano se X ≥ 0 usa il binario puro, in tutte le rappresentazioni
Decodificare 1xxxxxxx in C2 come se fosse segno e modulo sono due regole diverse in C2 il MSB vale −128 (o: inverti, converti, somma 1)
Leggere il primo bit come segno in eccesso in eccesso 1 = positivo, 0 = negativo decodifica sempre: valore − eccesso
Considerare il riporto finale un errore in C2 il riporto oltre l'ultimo bit si ignora l'overflow si riconosce dai segni, non dal riporto

Esercizi

Esercizio 1 · Le quattro codifiche. Rappresenta −25 su 8 bit in segno e modulo, complemento a uno, complemento a due ed eccesso 128.

Soluzione

Su 8 bit tutte e quattro le rappresentazioni arrivano almeno a −127: −25 è rappresentabile.

|25| = 16 + 8 + 1 = (11001)₂ → su 8 bit 00011001.

Rappresentazione Come Risultato
Segno e modulo segno 1 + modulo su 7 bit 0011001 10011001
Complemento a uno inverti 00011001 11100110
Complemento a due 11100110 + 1 11100111
Eccesso 128 −25 + 128 = 103 = 64 + 32 + 4 + 2 + 1 01100111

Controllo C2 con la formula: 256 − 25 = 231 = (11100111)₂. Controllo eccesso con il trucco: C2 con il primo bit invertito → 01100111.

Esercizio 2 · Una parola, cinque significati. Che numero rappresenta la parola 11100110 su 8 bit se letta in binario puro, segno e modulo, complemento a uno, complemento a due ed eccesso 128?

Soluzione
Rappresentazione Ragionamento Valore
Binario puro 128 + 64 + 32 + 4 + 2 230
Segno e modulo segno 1 (−), modulo 1100110 = 64 + 32 + 4 + 2 = 102 −102
Complemento a uno MSB 1: inverti → 00011001 = 25 −25
Complemento a due −128 + 64 + 32 + 4 + 2 −26
Eccesso 128 230 − 128 102

La stessa sequenza di bit ha significati diversi: senza sapere la rappresentazione usata non puoi dire che numero è.

Esercizio 3 · Somme in complemento a due (come allo scritto). Su 8 bit in complemento a due calcola (a) 45 + (−20) e (b) (−70) + (−60). Indica se il risultato è corretto o se c'è overflow.

Soluzione

(a) 45 = 00101101. −20: 20 = 00010100 → inverti 11101011 → +1 → 11101100.

Bit
00101101
+ 11101100
= 1 00011001

Il riporto finale si ignora: risultato 00011001 = 16 + 8 + 1 = 25. Operandi di segno diverso: risultato sempre corretto. Controllo: 45 − 20 = 25. ✓

(b) −70: 70 = 01000110 → inverti 10111001 → +1 → 10111010. −60: 60 = 00111100 → inverti 11000011 → +1 → 11000100.

Bit
10111010
+ 11000100
= 1 01111110

Ignorando il riporto resta 01111110 = +126. Gli operandi sono entrambi negativi ma il risultato è positivo: è un overflow. Infatti −70 − 60 = −130 è fuori dall'intervallo [−128, 127].

Verifica