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
- Lo zero ha due rappresentazioni: 00000000 (+0) e 10000000 (−0). Si spreca una parola codice: le 2ˡ parole rappresentano solo 2ˡ − 1 valori diversi.
- 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:
- Fai la somma normale dei due numeri su l bit.
- Se esce un riporto oltre l'ultimo bit (a sinistra), ignoralo.
- 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].