Reti Logiche - Aritmetica
Cerca per parola chiave 0/0

Aritmetica dei calcolatori

Naturali e interi, complemento alla radice, reti per somma, sottrazione, moltiplicazione e divisione

Le reti dell'aritmetica sono reti combinatorie con molti ingressi e molte uscite: nessuno le sintetizza con le mappe di Karnaugh. Il metodo è un altro, e vale in qualunque base: si parte dall'algoritmo che si usa a mano, lo si scompone in operazioni su una cifra, e si montano blocchi elementari (sommatori, multiplexer, comparatori). La parte delicata non è il circuito, ma il dimensionamento: su quante cifre sta ogni risultato, e quando il risultato non esiste.

Rappresentare i numeri naturali

La notazione posizionale

Un sistema posizionale ha una base β ≥ 2, β cifre (con valori da 0 a β − 1) e una legge che associa a una sequenza di cifre un numero naturale:

A ≡ (an−1 … a1 a0)β   ⟺   A = Σi=0n−1 ai · βi

Ogni cifra pesa in base alla sua posizione. Esempio in base sedici, con cifre 0…9, A…F: (1A2F)16 = 15 · 1 + 2 · 16 + 10 · 256 + 1 · 4096 = 6703. Quando scriviamo «54» indichiamo insieme il numero (un concetto) e una sua rappresentazione in base dieci: tenerli distinti aiuta, soprattutto con gli interi.

La divisione con resto e l'operatore modulo

Teorema della divisione con resto. Dati x ∈ ℤ e β ∈ ℕ, β > 0, esiste ed è unica la coppia q ∈ ℤ, r ∈ ℕ con 0 ≤ r < β tale che x = q · β + r. Si scrive q = ⌊x/β⌋ e r = |x|β.

L'unicità viene dal vincolo 0 ≤ r < β: per questo la divisione per un naturale approssima verso sinistra, anche per i negativi: ⌊−7/2⌋ = −4 con resto 1, non −3. Tre proprietà del modulo si usano di continuo:

  • |x + k · α|α = |x|α per ogni intero k;
  • |x ± y|α = ||x|α ± |y|α|α;
  • |x · y|α = ||x|α · |y|α|α.

Applicando il teorema ripetutamente (MOD & DIV) si trovano le cifre di A in base β: A = q1 · β + a0, q1 = q2 · β + a1, … fino a un quoziente nullo; i resti, letti dal basso, sono le cifre. Il teorema garantisce che la rappresentazione esiste ed è unica. Con le stesse proprietà si dimostrano i criteri di divisibilità, utili negli esercizi:

per un divisore di β

|A|γ = |a0|γ: in base dieci, per 2 e per 5 basta l'ultima cifra.

per un divisore di β − 1

A è multiplo di γ se e solo se lo è la somma delle cifre: il criterio del 3 in base dieci, e del 3 in base quattro.

per β + 1

Si guarda la somma delle cifre a segni alterni: il (poco noto) criterio dell'11 in base dieci.

Su quante cifre

Con n cifre in base β si scrivono βn combinazioni, quindi i naturali da 0 a βn − 1 (tutte le cifre a β − 1: 999…9 in base dieci). Per rappresentare A servono n = ⌈logβ(A + 1)⌉ cifre: 1000 in binario richiede ⌈log2 1001⌉ = 10 bit. È la domanda da farsi prima di qualunque rete: su quante cifre sta il risultato?

Reti per i numeri naturali

Cifre e codifiche

Una rete combinatoria vede variabili logiche, non cifre. In base 2 una cifra è una variabile; in un'altra base ogni cifra va codificata, di solito con il suo valore in binario (in base dieci è il BCD: 9 → 1001). Una rete «quadrato» in base dieci, con ingresso 1001 (9), deve dare 1000 0001 (81 in BCD), non 1010001 (81 in binario): la base in cui opera la rete è nel modo di interpretare le uscite. Per fortuna quasi tutte le operazioni si esprimono come relazioni tra cifre, indipendenti dalla base: le codifiche servono solo quando si sintetizzano le reti di una cifra.

Il complemento

Il complemento di A su n cifre in base β è A = βn − 1 − A: il numero che, sommato ad A, dà il massimo rappresentabile. Siccome βn − 1 ha tutte le cifre a β − 1, il complemento si fa cifra per cifra: ogni cifra ai diventa β − 1 − ai.

  • (1034)10 → (8965)10; ma su sei cifre (001034)10 → (998965)10: il complemento dipende dal numero di cifre;
  • (1034)5 → (3410)5;
  • in base 2 il complemento di una cifra è la NOT: il complemento di un numero è una barriera di invertitori.

Moltiplicare e dividere per una potenza della base

25 × 1000 non si calcola: si aggiungono tre zeri. 2562 / 100 ha quoziente 25 e resto 62 senza fare conti. Vale in ogni base:

  • moltiplicare per βk significa aggiungere k zeri in coda (shift a sinistra), su n + k cifre;
  • il quoziente della divisione per βk sono le n − k cifre più significative (shift a destra), il resto le k meno significative;
  • di conseguenza concatenare due numeri (X = Z · βk + Y) e spezzarne uno in due blocchi sono operazioni a costo nullo.

Le reti di shift sono solo fili: usare porte logiche per moltiplicare o dividere per βk è un errore. Anche l'estensione di campo dei naturali è a costo zero: per scrivere un naturale su più cifre si mettono zeri in testa (per gli interi sarà diverso).

Il sommatore

Dati X, Y su n cifre e un riporto entrante Cin ∈ {0, 1}, la somma vale al massimo 2βn − 1 < βn+1: sta sempre su n + 1 cifre, e l'ultima, il riporto uscente Cout, vale 0 o 1. Se Cout = 0 la somma sta su n cifre; se vale 1 no. Il Cin sembra una complicazione, ma è ciò che rende l'operazione modulare: una somma su n cifre si scompone in n somme su una cifra collegate dai riporti.

FAx0y0s0c1FAx1y1s1c2FAx2y2s2c3FAx3y3s3CinCout(riporto uscente)
Il montaggio ripple carry: si somma cifra per cifra dalla meno significativa, e il riporto uscente di ogni stadio entra nel successivo. Il riporto vale sempre 0 o 1, in qualunque base.

Il blocco su una cifra in base 2 è il full adder: tre ingressi, due uscite. La somma vale 1 quando gli ingressi a 1 sono in numero dispari (XOR a tre ingressi); il riporto vale 1 quando sono almeno due (cout = xy + x cin + y cin).

x0y0cin0pscoutsomma: XOR a tre ingressiriporto: forma SP

Se uno dei due addendi è sempre nullo il full adder si semplifica: si ottiene l'incrementatore (somma Cin a un numero), un circuito a un solo livello di logica. In Assembler inc %al e add $1, %al danno lo stesso risultato ma sono istruzioni diverse.

Dimensionare un sommatore. I due ingressi e l'uscita hanno lo stesso numero di cifre, sempre: nella ALU gli operandi stanno in registri di larghezza fissa. Se gli addendi hanno lunghezze diverse si estende il più corto; se la somma deve essere sempre rappresentabile si usa un sommatore a n + 1 cifre con ingressi estesi. La add dell'Assembler mette a 1 CF quando il risultato, come naturale, non sta nei bit degli operandi.

Il sottrattore e il comparatore

La differenza X − Y − bin può non essere un naturale. Si scrive come −bout · βn + D, con D su n cifre e il prestito uscente bout ∈ {0, 1}: se vale 1 la differenza è negativa. Sostituendo −Y = Y − βn + 1 si scopre che il sottrattore è un sommatore:

bout · βn + D = X + Y + bin

XnYNOTn+ +NOTbinCinNOTboutCoutD = X − Y − bin (modulo βⁿ)n
Il sottrattore è un sommatore: X − Y − bin si calcola come X + Y + bin, e il prestito uscente è il riporto uscente negato. bout = 1 vuol dire che la differenza non è un naturale (X < Y): ecco il comparatore.

Da qui il comparatore per naturali: A < B se e solo se A − B dà prestito (flag_min). Per l'uguaglianza si fa prima con una XOR per bit e una NOR (flag_eq): la rappresentazione è unica. Attenzione: guardare il prestito funziona solo per i naturali.

Il moltiplicatore

Con X, C su n cifre e Y su m, il risultato P = X · Y + C vale al più βm(βn − 1) e sta su n + m cifre. Il termine C serve, come il riporto, a scomporre: l'algoritmo delle elementari si riorganizza in modo da sommare due soli addendi alla volta. Esempio, 245 × 131:

passocalcolocifra del prodottonuovo C
y0 = 1245 · 1 + 0 = 245524
y1 = 3245 · 3 + 24 = 759975
y2 = 1245 · 1 + 75 = 320032
si concatena: 32 | 0 | 9 | 532095
MUL + ADDn × 1Xy0p0nCMUL + ADDn × 1Xy1p1nCMUL + ADDn × 1Xy2p20Ccifre altenP = (cifre alte, p2, p1, p0): un prodotto su n + 3 cifre
La moltiplicazione «delle elementari» riorganizzata: a ogni passo si moltiplica X per una cifra di Y e si somma il resto del passo precedente. La cifra meno significativa è già definitiva; le altre n diventano il C del passo dopo. Così si sommano sempre solo due addendi.

Il blocco n × 1 in base 2 è semplicissimo: moltiplicare per una cifra binaria vuol dire scegliere tra X e 0, cioè una barriera di AND, seguita da un sommatore.

XnANDyinCn+ +0n+1P = y_i · X + CCoutse y_i = 0: P = Cse y_i = 1: P = X + Cil multiplexer tra X e 0è una barriera di AND
Il blocco elementare della moltiplicazione in base 2: P = yi · X + C su n + 1 cifre. Moltiplicare per una cifra binaria significa scegliere tra X e 0: una AND per ogni bit.

In Assembler mul ha un solo operando: l'altro è implicito (AL, AX, EAX) e il risultato va su una destinazione doppia (AX, DX_AX, EDX_EAX). Spesso un moltiplicatore non serve affatto: per convertire due cifre BCD in binario, Y = 10 · x1 + x0 = 8x1 + 2x1 + x0. Gli shift sono fili, restano due somme: 2x1 + x0 ≤ 27 su 5 bit, poi 8x1 + (…) ≤ 99 su 7 bit, con gli ingressi di ciascun sommatore estesi alla sua larghezza.

Il divisore

Dividendo X su n + m cifre, divisore Y su m cifre: il resto sta su m cifre (è minore di Y), ma il quoziente, se Y = 1, può richiederne n + m. Si vuole il quoziente su n cifre, e questo è possibile solo se

X < βn · Y   ⟺   le m cifre più significative di X formano un numero minore di Y

Se la condizione è falsa (o Y = 0) la rete alza l'uscita no_div. L'algoritmo a mano: si prendono m + 1 cifre del dividendo, si calcola un quoziente parziale di una cifra e un resto, si concatena il resto con la cifra successiva, e così via. Esempio con β = 10, m = 2, n = 3: 01423 diviso 47 (fattibile: 01 < 47).

  1. 014 : 47 → quoziente 0, resto 14;
  2. 142 : 47 → quoziente 3, resto 1;
  3. 013 : 47 → quoziente 0, resto 13. Quindi Q = 030, R = 13 (verifica: 47 · 30 + 13 = 1423).

Il nucleo è quindi un divisore di m + 1 cifre per m cifre con quoziente su una cifra, e no_div si decide al primo stadio. In base 2 quel nucleo si riduce a un sottrattore e un multiplexer:

Xm+1Ym (+ uno 0 in testa)sottrattore + −boutNOTQ (1 cifra)X − Y01XR (m cifre)mse X < Y: Q = 0, R = Xse X ≥ Y: Q = 1, R = X − Y
Il nucleo della divisione in base 2: un dividendo di m + 1 cifre diviso un divisore di m cifre, con l'ipotesi X < 2Y. Il quoziente è una cifra sola: 1 se X ≥ Y. Lo dice il prestito del sottrattore, che sceglie anche il resto.

La div dell'Assembler vuole un dividendo su 2n bit, un divisore su n bit e un quoziente che stia su n bit, altrimenti genera un'eccezione: tocca al programmatore garantire X < 2n · Y, ad esempio estendendo gli operandi su un numero doppio di bit.

Esempio: ⌊7X/8⌋ senza moltiplicatori

Con X su n bit, Y = ⌊7X/8⌋ sta su n bit (non meno: con X = 7, Y = 6). Si scrive Y = ⌊(8X − X)/8⌋: 8X è uno shift (tre zeri in coda, n + 3 bit), la differenza si fa con un sottrattore a n + 3 bit (con X esteso), e la divisione per 8 butta via le tre cifre meno significative.

X − ⌊X/8⌋

Sembra più economico (sottrattore a n bit) ma è sbagliato: con X = 13 dà 13 − 1 = 12. I due risultati coincidono solo quando X è multiplo di 8.

⌊(8X − X)/8⌋

Con X = 13: (104 − 13) / 8 = 91 / 8 → 11, che è proprio ⌊7 · 13/8⌋. Le parti intere non si spostano dentro e fuori dalle somme.

Come si scoprono errori di questo tipo? Come con i programmi: si prova il circuito con qualche ingresso scelto con cura (casi limite, numeri non multipli), calcolando a mano le uscite. Non è una dimostrazione, ma un singolo caso che non torna basta a scoprire l'errore.

Rappresentare i numeri interi

Leggi di rappresentazione

I circuiti lavorano solo su cifre. Per gli interi si sceglie una legge biunivoca L che associa a ogni intero a (minuscolo) un naturale A (maiuscolo), rappresentato su n cifre: a ↔ A. Con βn combinazioni e β pari, l'intervallo più simmetrico possibile è

[ −βn/2 , βn/2 − 1 ]    (su 8 bit: da −128 a +127)

con un negativo in più. Le leggi usate in pratica:

a−128−127−10+1+127
traslazione (A = a + 128)000000000000000101111111100000001000000111111111
complemento alla radice100000001000000111111111000000000000000101111111
  • Traslazione: A = a + βn/2. È monotona (a < b ⟺ A < B); si usa nei convertitori A/D e D/A, dove si chiama binario bipolare, e per l'esponente dei numeri reali.
  • Complemento alla radice (CR): A = a se a ≥ 0, A = βn + a se a < 0. È la legge dei calcolatori, monotona solo tra numeri dello stesso segno.
  • Modulo e segno: una variabile di segno più il modulo. Non associa interi a naturali, e i circuiti che la usano sono più complessi.
-8-7-6-5-4-3-2-1012345670481215aAcomplemento alla radicetraslazionebase 2, n = 4 cifreinteri da −8 a +7In CR i negativi stannoin alto: A = 16 + a.La traslazione è una retta:A = a + 8, monotona.
Due leggi per rappresentare gli interi su 4 bit. La traslazione somma 8 a tutti ed è monotona. Il complemento alla radice lascia i non negativi dove sono e porta i negativi nella metà alta: la cifra più significativa dice il segno.

Le proprietà del complemento alla radice

  • Segno: a < 0 se e solo se la cifra più significativa è ≥ β/2. In base 2, se il bit più significativo è 1.
  • Legge inversa: a = A se an−1 < β/2, altrimenti a = −(A + 1). Esempi: (852)10 su 3 cifre ha MSD 8 ≥ 5, quindi a = −(147 + 1) = −148; (500)10 → −500; (1011)2 → −(0100 + 1) = −5; (1111)2 → −1.
  • Forma compatta: A = |a|βn. Ma solo se a è rappresentabile! Con β = 10, n = 3: |−953|1000 = 47, che è la rappresentazione di +47, non di −953 (che su tre cifre non esiste). Dimenticarlo è un errore grave.

Prova con il laboratorio: scegli la base e il numero di cifre, poi passa da un intero alla sua rappresentazione e viceversa. Il secondo modo mostra anche opposto, valore assoluto, estensione e riduzione.

Operazioni sugli interi in complemento alla radice

Un circuito esegue l'operazione O sugli interi se, ricevendo A ↔ a e B ↔ b, produce Z ↔ z con z = O(a, b). Il legame tra cifre e interi sta solo nella nostra testa: il bello del CR è che molti circuiti per naturali vanno bene anche così.

Valore assoluto e opposto

Dalla legge inversa: ABS(a) = A se an−1 < β/2, altrimenti A + 1. Il risultato è un naturale in [0, βn/2] e richiede n cifre (n − 1 non bastano, neanche in base 2). Esempi: (852)10 → 147 + 1 = 148; (1011)2 → 0100 + 1 = 5. In base 2 basta una barriera di XOR con il bit di segno e un incrementatore:

Anan−1n porte XORnINCcinB = ABS(a)na ≥ 0 (MSB = 0): XOR lascia A,INC non aggiunge niente → B = Aa < 0 (MSB = 1): XOR complementa,INC aggiunge 1 → B = Ā + 1
Valore assoluto in base 2. Un XOR con 1 è un invertitore, con 0 un filo: il bit di segno decide se complementare. Lo stesso bit entra come riporto nell'incrementatore. Il risultato sta su n bit (per −2n−1 serve proprio l'n-esimo).

Da qui il convertitore da CR a modulo e segno (sempre fattibile) e, con un multiplexer, quello inverso da MS a CR (che può andare in overflow). L'opposto si calcola come |A + 1|βn: complemento più incremento. Due casi da provare: con A = 10000000 si ottiene di nuovo 10000000, perché −128 non ha opposto su 8 bit (overflow, che in base 2 si riconosce perché ingresso e uscita sono entrambi negativi); con A = 00000000 l'incrementatore dà riporto, ed è per questo che serve il modulo. In Assembler neg calcola l'opposto e alza OF nel caso impossibile.

Estensione e riduzione di campo

Per scrivere lo stesso intero su n + 1 cifre non basta uno zero in testa: i negativi devono «salire» di βn(β − 1). Le n cifre basse restano uguali, e la nuova cifra vale 0 per i non negativi e β − 1 per i negativi. In base 2 si ripete il bit di segno: 1011 (−5) diventa 11011. L'estensione degli interi, a differenza dei naturali, richiede logica (in base 2 basta un filo). In Assembler la fanno cbw, cwd, cwde, cdq; per i naturali non c'è un'istruzione apposta: si mettono zeri.

Il problema inverso, la riduzione da n + 1 a n cifre, ha soluzione solo se il numero sta nell'intervallo più piccolo, cioè se

(an = 0 e an−1 < β/2)  oppure  (an = β − 1 e an−1 ≥ β/2)

e in quel caso si butta via la cifra più significativa. In base 10: 9852 (−148) si riduce a 852; 9352 (−648) no, perché −648 non sta in [−500, +499]. In base 2 la condizione è che le due cifre più significative siano uguali: il circuito di overflow è una XOR. Per ridurre di k cifre si controlla che i k + 1 bit più significativi siano tutti uguali (una AND e una OR a k + 1 ingressi, e una XOR tra le loro uscite).

Shift logici e aritmetici

Moltiplicare e dividere per βk si fa come per i naturali, quando si può cambiare il numero di cifre. Nei registri però i bit sono fissi, e le cose cambiano:

SHL / SAL (×2)1011001101100110primadopoCF = 1← 0SHR (÷2, naturali)1011001101011001primadopoCF = 10 entra a sinistraSAR (÷2, interi)1011001111011001primadopoCF = 1si ripete il bit di segnoPer moltiplicare per 2 serve una sola istruzione:il risultato è giusto se l'operando era riducibile.CF = 1: overflow per i naturali (MSB era 1)OF = 1: overflow per gli interi (due MSB diversi)
Moltiplicare per 2 è uguale per naturali e interi (cambia solo il flag che dice se il risultato è giusto); dividere per 2 no, perché prima bisogna estendere l'operando: con uno 0 i naturali (SHR), ripetendo il segno gli interi (SAR). Qui 10110011 vale 179 come naturale e −77 come intero: 179 / 2 = 89, ⌊−77 / 2⌋ = −39.
  • per 2: bisogna che l'operando sia riducibile (per i naturali MSB = 0, per gli interi due MSB uguali), poi si trasla a sinistra. La traslazione è la stessa: shl e sal sono la stessa istruzione macchina, che alza CF o OF e lascia al programmatore il flag giusto;
  • diviso 2: si estende di un bit (0 per i naturali, il segno per gli interi) e si prendono gli n bit alti. Servono due istruzioni diverse: shr e sar.

Somma, sottrazione e overflow

Quando s = a + b è rappresentabile su n cifre, per le proprietà del modulo:

S = |a + b|βn = ||a|βn + |b|βn|βn = |A + B|βn

La rappresentazione della somma è la somma delle rappresentazioni: non esiste un sommatore per interi, c'è il sommatore. È questa proprietà, da sola, a giustificare il complemento alla radice. Cambia solo come si capisce se il risultato è giusto: il riporto uscente non dice niente sugli interi. Con A = βn − 1 (cioè −1) e B = 1 si ha Cout = 1 ma la somma (0) è giusta; con A = B = βn/2 − 1 si ha Cout = 0 ma la somma di due positivi esce negativa.

Il metodo generale: si fa la somma su n + 1 cifre con gli addendi estesi (lì è sempre rappresentabile) e si controlla se il risultato è riducibile. In base 2 si arriva a una formula senza stadi in più: ow = cn ⊕ cn−1.

FAcifra n−1sommatorecifre n−2 … 0cn−1cn = CoutCinXORow (overflow, come interi)an−1 bn−1ow = cₙ ⊕ cₙ₋₁: l'overflow c'è quando ilriporto che entra nel bit di segno èdiverso da quello che ne esce
In base 2 il rilevatore di overflow è gratis: basta lo XOR dei riporti entrante e uscente dell'ultimo stadio. Il sommatore resta lo stesso; per i naturali si guarda Cout, per gli interi ow.
0000010001200103001140100501016011070111-81000-71001-61010-51011-41100-31101-21110-11111overflow+7 + 1 = −8riporto1111 + 1 = 0000Sommare 1 fa girare la ruotadi un passo in senso orario.Come naturali (0 … 15) il saltocritico è tra 1111 e 0000: CF.Come interi (−8 … +7) il saltocritico è tra 0111 e 1000: OF.Stessi bit, stesso circuito:cambia solo il flag da guardare.
L'aritmetica su n bit è un'aritmetica modulo 2n: le combinazioni stanno su una ruota. Per i naturali il risultato è sbagliato quando si attraversa il punto tra 1111 e 0000 (riporto), per gli interi quando si attraversa quello tra 0111 e 1000 (overflow).

La sottrazione è analoga: D = |A + B + 1|βn, cioè lo stesso sottrattore dei naturali, con l'overflow (in base 2) dato dallo XOR degli ultimi due prestiti. In Assembler c'è una sola add e una sola sub: alzano sia CF sia OF, e dopo l'istruzione il programmatore usa jc/jnc se sta lavorando con naturali, jo/jno se con interi.

Confrontare due interi

L'uguaglianza si testa come per i naturali. Per la minoranza si usa ancora un sottrattore, ma non si guarda il prestito: si guarda il segno della differenza, che per essere sempre rappresentabile va calcolata su n + 1 cifre, estendendo gli operandi. Esempio su 4 bit: −8 < 1, eppure 1000 − 0001 come naturali non dà prestito (8 − 1 = 7).

Moltiplicazione e divisione

Per moltiplicare e dividere conviene passare dai valori assoluti, riusare i circuiti dei naturali e sistemare il segno alla fine:

  • prodotto: ABS(p) = ABS(a) · ABS(b), il segno è lo XOR dei segni. Su n + m cifre non c'è mai overflow (|p| ≤ βn+m/4). Il moltiplicatore per interi non ha l'ingresso C;
  • divisione: tra interi il resto non è unico con il solo vincolo |r| < |b| (17 diviso −5 dà q = −3, r = 2 oppure q = −4, r = −3). Si aggiunge che il resto abbia il segno del dividendo: il quoziente è troncato verso lo zero. Allora ABS(a) = ABS(q) · ABS(b) + ABS(r) è una divisione tra naturali.

La fattibilità della divisione naturale tra i valori assoluti è necessaria ma non sufficiente: il quoziente, riportato in CR, può andare in overflow. Esempio in base 10 con n = 1, m = 2: −223 ÷ 28. La divisione naturale 223 ÷ 28 è fattibile (quoziente 7, una cifra), ma q = −7 non sta in [−5, +4]: non si può fare. Con −123 ÷ 28 invece ABS(q) = 4, ABS(r) = 11, quindi q = −4 ↔ Q = 6 e r = −11 ↔ R = 89. Il segnale no_idiv è l'OR di no_div e dell'overflow del convertitore MS → CR. Per questo in Assembler ci sono mul/imul e div/idiv distinte, mentre la somma è una sola.

Esercizi svolti

Il massimo di tre numeri

Testo. Rete che riceve a, b, c su n bit e produce il massimo; poi la stessa con interi in CR.

Tre comparatori calcolano xAB = (a < b), xBC = (b < c), xCA = (c < a); una piccola rete combinatoria ne ricava i due bit di comando di un multiplexer che sceglie tra A, B, C. La combinazione 111 è impossibile (un ciclo di minoranze non esiste) e con 000 i tre numeri sono uguali, quindi va bene qualunque scelta: sono entrambe non specificate, e la sintesi viene b0 = xAB, b1 = xBC · xCA. Per gli interi cambia solo il comparatore (segno della differenza estesa invece del prestito). Alternativa con meno logica: confrontare a e b, far passare il maggiore con un multiplexer a due vie, confrontarlo con c.

b = 7 − 5a senza moltiplicatori

Testo. a ↔ A in CR su 6 bit; produrre B ↔ b = 7 − 5a, senza moltiplicatori. Mostrare i valori per a = 14.

  1. Dimensionamento: −32 ≤ a ≤ 31, quindi −148 ≤ b ≤ 167: servono 9 bit (da −256 a +255).
  2. Riscrittura: b = (7 − a) − 4a = c − d. Il prodotto per 4 è uno shift di due posizioni.
  3. Circuito: C = 7 + A + 1 (con A esteso ripetendo il segno), D = 4A (due zeri in coda e segno esteso), B = C + D + 1: due sottrattori a 9 bit.
  4. Verifica con a = 14: A = 001110, C ↔ −7 = 111111001, D ↔ 56 = 000111000, B ↔ −63 = 111000001. E infatti 7 − 70 = −63.

Multiplo di 3 in base 4

Testo. A su 5 cifre in base 4: uscita 0 se A è multiplo di tre, 1 altrimenti.

Per il criterio visto (3 divide β − 1 = 3) basta sommare le cifre: ogni cifra sta su 2 bit, la somma di cinque cifre vale al più 15 e sta su 4 bit. Poi si divide per 3 con un divisore naturale e si guarda se il resto (2 bit) è nullo: z = OR dei bit del resto. Attenzione al dimensionamento del divisore: il quoziente arriva a 5 e richiede 3 bit, quindi il dividendo va esteso a 5 bit perché valga X < 23 · 3.

La tangente a una parabola

Testo. Interi a, b, c, x su n bit in CR; produrre il coefficiente angolare della tangente a y = ax2 + bx + c nel punto x, e poi sintetizzare i due bit meno significativi.

La derivata è m = 2ax + b: un moltiplicatore per interi (n × n → 2n bit), uno shift, un'estensione di b e un sommatore a 2n + 1 bit; c non serve. Per i bit bassi si ragiona sui fili: m0 = b0, perché l'altro addendo ha uno zero in coda; m1 = b1 ⊕ y0, dove y0 è il bit basso del prodotto ax, che vale 1 solo se entrambi sono dispari: m1 = b1 ⊕ a0x0. Il bit meno significativo dice la parità, qualunque sia il segno.

Buone norme per gli esercizi di aritmetica

  • Dimensiona prima di disegnare: per ogni filo, su quante cifre sta il valore nel caso peggiore? Scrivi il numero accanto a ogni bus.
  • Gli ingressi di un sommatore hanno sempre la stessa larghezza: estendi il più corto (zeri per i naturali, segno ripetuto per gli interi).
  • Moltiplicare o dividere per βk, concatenare, spezzare: sono fili. Mai porte logiche.
  • Prima di usare un moltiplicatore per una costante, scomponila in shift e somme o differenze: 10x = 8x + 2x, 7x = 8x − x.
  • Le parti intere non si distribuiscono: ⌊a − b⌋ ≠ a − ⌊b⌋ in generale. Applica la divisione alla fine.
  • Naturali o interi? Per i naturali conta Cout (o il prestito), per gli interi l'overflow; i confronti tra interi si fanno sul segno della differenza estesa.
  • |a|βn è la rappresentazione di a solo se a è rappresentabile su n cifre.
  • Per divisioni, controlla la fattibilità (no_div) e, per gli interi, anche l'overflow del quoziente.
  • Alla fine prova il circuito con due o tre valori scelti male di proposito (negativi, estremi dell'intervallo, non multipli).

Verifica