Lezione del 13 marzo 2009
Osservazione: Se la funzione TimeA(n), che calcola il numero di operazioni elementari eseguite
dall’algoritmo A per un input di dimensione n (nel caso peggiore), viene calcolata in funzione
dell’input x (e non della sua dimensione n) e se essa risulta di ordine polinomiale O(xk), possiamo
notare che l’algoritmo A ha allora complessità esponenziale in n: infatti esisterà una costante C
tale che il numero di operazioni elementari eseguite dall’algoritmo A per un input x sia  Cxk, e
tenendo conto che x < 2n (essendo n la lunghezza binaria di x) si ricava:
TimeA(n)  C(2k)n
dunque TimeA(n) è di ordine esponenziale O(an) dove a=2k .
Complessità di alcuni algoritmi aritmetici.
a) Costruiamo un algoritmo A=Somma(x,y) per calcolare la somma x+y di due numeri naturali x,y
dati in input: supponiamo che, se n=L(x),m=L(y) sono le lunghezze binarie degli addendi, si abbia
nm.
L’algoritmo di somma si può eseguire con gli stessi metodi che si usano per sommare numeri
naturali rappresentati in base 10, utilizzando le operazioni elementari di somma sui singoli bits:
- si incolonna la rappresentazione binaria di y sotto quella di x, aggiungendo (se n>m) n-m bits=0
alla sinistra dei bits di y
- si inizializza il valore del riporto c=0
- procedendo da destra verso si sinistra si somma ogni bit di x con il bit dello stesso posto di y (con
l’operazione elementare BitSum di somma di bits), ottenendo ad ogni passo una delle cifre binarie
di x+y e un nuovo valore del riporto c
- se l’ultimo riporto è c=1 si aggiunge a sinistra un ulteriore bit=1 nel risultato x+y
- si esce con output x+y
Per esempio se x=(110011)2, y=(1101) allora:
110011+
001101
1000000
dunque il risultato della somma è x+y=(1000000)2.
Schematizzando l’algoritmo:
1) input x=(an-1an-2…..a1a0)2 , y=(bm-1bm-2…..b1b0)2 con n=L(x) m=L(y)
2) se n>m si pone bm=bm+1=…=bn-1=0
3) c=0
4) per i=0,1…,n-1 si calcola BitSum(ai,bi,c)=(t,c1) e si pone zi=t, c=c1
5) se c=1 si pone zn=1
6) si esce con output x+y=(znzn-1…..z1z0)2
In tale algoritmo si eseguono n operazioni elementari, dunque Time A(n)=O(n), e l’algoritmo ha
complessità polinomiale (lineare).
b) Costruiamo un algoritmo A=Diff(x,y) per calcolare la differenza x-y di due numeri naturali x,y
(con x>y) dati in input: se n=L(x),m=L(y) sono rispettivamente le lunghezze binarie, si avrà
certamente nm.
Si può ricondurre il caso a quello dell’algoritmo Somma(x,y) con il seguente ragionamento:
consideriamo il numero binario y1 ottenuto da y sostituendo ogni bit 0 con 1 e viceversa e poi
aggiungendo a sinistra (n-m) bits =1 (quindi y+y1 è un numero binario con n bits tutti=1 cioè
y+y1=2n-1).
Si ha dunque y+(y1+1)=2n (y1+1 è il cosiddetto “complemento a 2 di y”) da cui x-y=x+(y1+1)-2n.
Quindi per ottenere x-y basta sommare x con il complemento a 2 di y e poi sottrarre 2n al risultato
(il che equivale ad elidere l’ultimo bit =1 a sinistra): poiché nel calcolo di x+(y1+1) (addendi
lunghezza ≤n ) si esegue (vedere algoritmo Somma(x,y)) un numero n di operazioni elementari, si
conclude che TimeA(n)=O(n), e anche questo algoritmo ha complessità polinomiale (lineare).
c) Costruiamo un algoritmo A=Prod(x,y) per calcolare il prodotto x+y di due numeri naturali x,y
dati in input: supponiamo che, se n=L(x),m=L(y) sono le lunghezze binarie dei fattori, si abbia
nm.
L’algoritmo di prodotto si può eseguire con gli stessi metodi che si usano per moltiplicare numeri
naturali rappresentati in base 10, utilizzando le operazioni elementari di somma sui singoli bits.
Si costruiscono (al più) m righe (una riga in meno per ogni bit =0 in y) ognuna consistente nella
copia del numero binario y shiftato opportunamente verso sinistra di un certo numero di posti (il che
equivale ad aggiungere a destra dei bits =0) e si sommano tutte le righe (pensate come numeri
binari): per contare il numero di operazioni elementari, supponiamo di sommare le righe 2 alla volta
(la prima con la seconda, la terza con il risultato della somma della prima con la seconda etc.)
eseguendo in totale un numero ≤m-1 di somme fra numeri di lunghezza ≤n+m, e poiché ognuna di
tali somme corrisponde ad un numero ≤n+m di operazioni elementari di somma di bits, in totale il
numero di operazioni elementari nell’algoritmo è ≤(n+m)(m-1)<n2 ossia TimeA(n)=O(n2), e anche
questo algoritmo ha complessità polinomiale (quadratica).
Per esempio se x=(11011)2, y=(1011) allora:
11011x
1011
11011
110110
11011000
100101001
(si suppone di sommare la prima riga 11011 con la seconda 110110 e poi
sommare il risultato con la terza riga 11011000)
dunque il risultato del prodotto è xy=(100101001)2.
Tale algoritmo di prodotto non è il più efficiente: esiste un algoritmo più sofisticato che ha
complessità O(nlog(n)log(log(n))) “minore” di O(n2) (perché limn[nlog(n)log(log(n))]/n2=0).
Spesso, per i nostri scopi, ci limiteremo a costruire un algoritmo che risolva un problema senza
indagare se sia il più efficiente in termini di complessità.