Salta al contenuto
Note per Studenti Numeri con segno, complemento a 2, sottrazione e overflow

Numeri con segno, complemento a 2, sottrazione e overflow

In questa pagina 7

Il sommatore (Sommatori binari - half adder, full adder e ripple carryHalf adder (2 ingressi): $S=X\oplus Y$, $C=XY$. Full adder (3 ingressi, con riporto in ingresso $Z$): $S=X\oplus Y\oplus Z$, $C=XY+XZ+YZ=G+PZ$ con $P=X\oplus Y$, $G=XY$; si realizza con due half adder e una OR. Il ripple carry adder a $n$ bit concatena $n$ full adder: il riporto "ondeggia" dal LSB al MSB, quindi il ritardo cresce linearmente con $n$. È un circuito iterativo (gerarchico e regolare). Il moltiplicatore a 2 bit usa 4 AND e 2 half adder.Sommatori binari - half adder, full adder e ripple carry →) lavora su numeri senza segno. Come rappresentare i numeri negativi, in modo che lo stesso circuito faccia somme e sottrazioni? La risposta è il complemento a 2. (Un'altra trattazione è in Rappresentazione dei numeri interi con segnoInteri con segno su n bit: modulo e segno, complemento a 1, complemento a 2 ed eccesso K; intervalli rappresentabili, calcolo dell'opposto, estensione del segno.Rappresentazione dei numeri interi con segno → e Aritmetica binariaSomma e sottrazione in binario, overflow per senza segno (riporto) e per complemento a 2 (segni), flag del processore, moltiplicazione per somme e scorrimenti, algoritmo di Booth, divisione, shift logici e aritmetici.Aritmetica binaria →.)

Sottrazione di numeri senza segno

Si sottrae NN da MM (entrambi su nn bit) bit per bit con i prestiti (Basi di numerazione e conversioni - binario, ottale ed esadecimaleUn numero in base $r$ vale $\sum a_i r^i$ (cifre $a_i\in{0,\dots,r-1}$). Conversioni: base $r\to$ decimale con la somma pesata; decimale $\to$ base $r$ per divisioni successive (parte intera, resti letti dal basso) e moltiplicazioni successive (parte frazionaria, parti intere lette dall'alto); binario $\leftrightarrow$ ottale/esadecimale a gruppi di 3/4 bit. Somma, differenza e prodotto binari seguono le regole decimali con cifre 0 e 1; la differenza ha prestiti, il prodotto somma prodotti parziali traslati.Basi di numerazione e conversioni - binario, ottale ed esadecimale →).

  • Se M≥NM\ge N: nessun prestito in uscita dal bit più significativo, e il risultato è corretto.
  • Se M<NM<N: c'è un prestito in uscita e il risultato è M−N+2nM-N+2^n, sbagliato. Il valore assoluto corretto è 2n2^n meno il risultato ottenuto (il suo complemento a 2), e il segno è negativo.

Esempio (n=8n=8): 01100100−1001011001100100-10010110 (100−150100-150). Il risultato a 8 bit è 1100111011001110 (206=100−150+256206=100-150+256), con prestito in uscita 11 (M<NM<N). Valore assoluto: 256−206=50=00110010256-206=50=00110010. Risultato corretto: −001100102=−50-00110010_2=-50.

Altro esempio con M≥NM\ge N: 10011011−0100111010011011-01001110 (155−78155-78) =01001101=01001101 (7777), nessun prestito.

Complementi

Dato NN su nn bit:

  • complemento a 1: (2n−1)−N(2^n-1)-N, cioè il complemento di ogni bit (si scambiano 0 e 1);
  • complemento a 2: 2n−N2^n-N, cioè complemento a 1 più 1.
NN complemento a 1 complemento a 2
10110011011001 01001100100110 01001110100111
00011110001111 11100001110000 11100011110001
101100101100 010011010011 010100010100

Il complemento del complemento restituisce NN. Per 00 il complemento a 2 su nn bit è ancora 00 (si scarta il riporto).

Sottrazione con il complemento a 2. Poiché M−N=M+(2n−N)−2nM-N=M+(2^n-N)-2^n, si somma a MM il complemento a 2 di NN e si toglie 2n2^n:

  • se M≥NM\ge N la somma produce un riporto in uscita (il termine 2n2^n), che si scarta: resta M−NM-N;
  • se M<NM<N non c'è riporto in uscita e la somma vale 2n−(N−M)2^n-(N-M), il complemento a 2 della differenza: per ottenere il modulo si ripete il complemento a 2, e si mette il segno meno.

In questo modo la stessa addizione serve per sommare e sottrarre; con i numeri in complemento a 2 (sotto) l'ultimo passaggio sparisce.

Rappresentare numeri con segno

Si vedono due rappresentazioni a nn bit.

Segno e modulo. Si antepone un bit di segno: 00 per positivi (e zero), 11 per negativi. Un numero e il suo opposto differiscono solo per il bit di segno. Con 4 bit: da −7-7 a +7+7, ma lo zero ha due rappresentazioni (00000000 e 10001000). Le operazioni trattano segno e modulo separatamente, quindi la sottrazione richiede una correzione di segno.

Complemento a 2. I positivi sono come in senza segno (00 seguito dal modulo); un negativo −N-N si rappresenta con il complemento a 2 di NN, cioè 2n−N2^n-N. L'MSB è 00 per tutti i positivi e 11 per tutti i negativi. Con 4 bit:

bit senza segno segno e modulo complemento a 2
0000 0 +0+0 0
0111 7 7 7
1000 8 −0-0 −8-8
1001 9 −1-1 −7-7
1010 10 −2-2 −6-6
1011 11 −3-3 −5-5
1100 12 −4-4 −4-4
1101 13 −5-5 −3-3
1110 14 −6-6 −2-2
1111 15 −7-7 −1-1

In complemento a 2 c'è un solo zero e l'intervallo è asimmetrico: da −2n−1-2^{n-1} a 2n−1−12^{n-1}-1 (con 8 bit da −128-128 a 127127; −(−128)-(-128) non è rappresentabile). Il valore si legge dando all'MSB il peso −2n−1-2^{n-1}: 11110011=−128+64+32+16+2+1=−1311110011=-128+64+32+16+2+1=-13.

Esempi a 8 bit: +9=00001001+9=00001001; −9-9: segno e modulo 1000100110001001, complemento a 2 1111011111110111 (=256−9=256-9: si inverte 00001001→1111011000001001\to11110110 e si somma 1). −13-13: segno e modulo 1000110110001101, complemento a 2 1111001111110011. Il numero −3-3 a 8 bit in complemento a 2 è 1111110111111101. Estensione del segno: per aumentare i bit di un numero in complemento a 2 si replica l'MSB (1101→111111011101\to11111101 resta −3-3).

I calcolatori usano il complemento a 2 perché somma e sottrazione condividono lo stesso hardware.

Somma e sottrazione con segno in complemento a 2

Somma: si sommano i numeri inclusi i bit di segno e si scarta il riporto in uscita dal bit di segno. Il risultato è in complemento a 2. Esempi a 8 bit:

operazione operandi risultato valore
+6+13+6+13 00000110+0000110100000110+00001101 0001001100010011 +19+19
−6+13-6+13 11111010+0000110111111010+00001101 0000011100000111 +7+7
+6−13+6-13 00000110+1111001100000110+11110011 1111100111111001 −7-7
−6−13-6-13 11111010+1111001111111010+11110011 1110110111101101 −19-19

Sottrazione: A−B=A+(−B)A-B=A+(-B), cioè si somma ad AA il complemento a 2 di BB: A−B=A+B‾+1A-B=A+\overline B+1 (complemento a 1 di BB più 1). Esempio: +7−(−12)+7-(-12): −12=11110100-12=11110100, il suo complemento a 2 è 0000110000001100 (+12+12), e 00000111+00001100=00010011=+1900000111+00001100=00010011=+19 ✓.

Circuito addizionatore-sottrattore

Con un solo circuito si fanno entrambe le operazioni: si introduce un segnale SS (0 = somma, 1 = sottrazione). Ogni bit BiB_i passa per una porta XOR con SS: se S=0S=0 passa BiB_i, se S=1S=1 passa Bi‾\overline{B_i} (complemento a 1). Lo stesso segnale SS è il riporto in ingresso del primo full adder, e fornisce il "+1". Il sommatore calcola quindi A+BA+B (con S=0S=0) oppure A+B‾+1=A−BA+\overline B+1=A-B (con S=1S=1). Per n=4n=4: quattro XOR, quattro full adder in cascata.

Overflow

L'overflow (straripamento) si ha quando il risultato non sta nei bit disponibili: per esempio 1000+1000=100001000+1000=10000 con numeri a 4 bit. È un problema in ogni sistema con un numero di bit fissato; il sistema deve poterlo rilevare.

Numeri senza segno.

  • Nella somma c'è overflow se il riporto in uscita dal bit più significativo vale 1.
  • Nella sottrazione non può esserci overflow (il risultato non supera il minuendo); il riporto in uscita dell'addizionatore-sottrattore vale C=1C=1 se M≥NM\ge N (risultato corretto) e C=0C=0 se M<NM<N (risultato da correggere con complemento e segno meno). Equivalente al "prestito" invertito.

Numeri con segno (complemento a 2). Somma e sottrazione di operandi di segno diverso non hanno mai overflow (il modulo non cresce). Si ha overflow solo se i due addendi (per la sottrazione: AA e −B-B) hanno lo stesso segno e il risultato ha segno opposto. In termini di riporti: c'è overflow se il riporto che entra nel bit di segno è diverso dal riporto che esce dal bit di segno: V=Cin, MSB⊕Cout, MSB.V=C_{in,\,MSB}\oplus C_{out,\,MSB}. Perché: se i due positivi sommano oltre 2n−1−12^{n-1}-1, il riporto entra nel bit di segno (che diventa 1) ma non esce; se i due negativi scendono sotto −2n−1-2^{n-1}, il riporto non entra ma esce. Con V=1V=1 il risultato è errato.

Esempi a 8 bit (intervallo −128…127-128\dots127):

  • 70+8070+80: 01000110+01010000=1001011001000110+01010000=10010110; riporto in ingresso al segno 11, in uscita 00 ⇒\Rightarrow V=1V=1: 150150 non sta, il risultato è letto come −106-106.
  • (−70)+(−80)(-70)+(-80): 10111010+10110000=(1) 0110101010111010+10110000=(1)\,01101010; riporto in ingresso 00, in uscita 11 ⇒\Rightarrow V=1V=1: −150-150 non sta, letto come +106+106.
  • 100+27=127100+27=127: 01100100+00011011=0111111101100100+00011011=01111111, riporti 00 e 00 ⇒V=0\Rightarrow V=0 (al limite, ma corretto).
  • (−100)+(−28)=−128(-100)+(-28)=-128: 10011100+11100100=(1) 1000000010011100+11100100=(1)\,10000000, riporti 11 e 11 ⇒V=0\Rightarrow V=0 (corretto).

Esercizi di riferimento (numeri in complemento a 2, MSB = segno):

  • (a) 110001+011101110001+011101 (6 bit: −15+29-15+29): somma 001110001110, riporto in ingresso al segno 11, in uscita 11 ⇒\Rightarrow nessun overflow; risultato +14+14 ✓.
  • (b) 0110111+01011110110111+0101111 (7 bit: +55+47+55+47): somma 11001101100110; riporto in ingresso al segno 11, in uscita 00 ⇒\Rightarrow overflow (102>63102>63).
  • (c) 00000111−1111010000000111-11110100 (+7−(−12)+7-(-12)): 00000111+00001100=0001001100000111+00001100=00010011 ⇒\Rightarrow nessun overflow, +19+19.
  • (d) 0110111−01011110110111-0101111 (+55−47+55-47, 7 bit): complemento a 2 del sottraendo 10100011010001; 0110111+1010001=(1) 00010000110111+1010001=(1)\,0001000; riporti 11 e 11 ⇒\Rightarrow nessun overflow; +8+8 (il riporto in uscita si scarta).

VHDL

Con il package numeric_std il tipo signed rappresenta numeri in complemento a 2:

vhdl
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity add_signed is
  port ( a, b : in  std_logic_vector(7 downto 0);
         s    : out std_logic_vector(7 downto 0);
         v    : out std_logic );                    -- overflow
end add_signed;

architecture beh of add_signed is
  signal sum : std_logic_vector(7 downto 0);
begin
  sum <= std_logic_vector(signed(a) + signed(b));
  s   <= sum;
  v   <= (a(7) xnor b(7)) and (a(7) xor sum(7));    -- stesso segno in ingresso, segno diverso in uscita
end beh;

Il package fa interpretare i vettori come numeri con segno; con un package come std_logic_unsigned gli stessi vettori sarebbero senza segno (Introduzione al VHDL - entity, architecture, tipi e livelli di descrizioneVHDL è un linguaggio di descrizione dell'hardware (HDL), non di programmazione: le dichiarazioni sono concorrenti e descrivono blocchi di circuito; serve per documentare, simulare e sintetizzare. Un blocco ha una entity (nome e porte in/out) e almeno una architecture (cosa c'è dentro: structural con component e port map, dataflow con equazioni booleane, behavioral con comportamento). Tipi: std_logic (da 1164: '0','1','X','Z','U','-',...), std_logic_vector, bit, boolean, integer. Signal per i collegamenti interni, constant per i valori fissi.Introduzione al VHDL - entity, architecture, tipi e livelli di descrizione →).

Errori comuni

  • Dire che in complemento a 2 il riporto in uscita indica overflow: per i numeri con segno conta il confronto tra il riporto entrante e quello uscente dal bit di segno.
  • Calcolare il complemento a 2 invertendo i bit senza sommare 1.
  • Credere che −(−2n−1)-(-2^{n-1}) sia rappresentabile: l'intervallo è asimmetrico.
  • Usare l'estensione con zeri (anziché replicare il segno) su un numero negativo.
  • Scrivere −13-13 a 8 bit come 1000110110001101 (è segno e modulo): in complemento a 2 è 1111001111110011.
  • Segno del risultato nella sottrazione senza segno: se c'è prestito va corretto con complemento e segno meno.

Versione ripasso

Esercizi su questo argomento

Teoria collegata