Algoritmi e Strutture Dati
Autunno 02
Algoritmi per il Massimo Comun Divisore
Dip. Informatica ed Appl.
Prof. G. Persiano
Università di Salerno
In questi appunti presentiamo un algoritmo per il calcolo del massimo comun divisore di due interi. Il
problema del calcolo del massimo comun divisore è antichissimo e risale ad Euclide che propose un algoritmo
nelle proposizioni 1-3 del VII libro degli Elementi [1]. Euclide visse ad Alessandria intorno al 300 A.C. e quindi
il problema del massimo comun divisore è uno dei primi problemi algoritmici studiati e l’algoritmo di Euclide
è uno dei più antichi algoritmi noti.
Definizione 1 Siano a e b due interi. Diciamo che a divide b (in simboli a|b) se esiste un intero k tale
b = a · k.
Definizione 2 Siano a e b due interi non entrambi uguali a zero. Diciamo che un intero d è il massimo
comun divisore di a e b (in simboli d = (a, b)) se
1. d|a e d|b;
2. se d1 |a e d1 |b allora d1 |d;
3. d > 0.
È facile osservare che il massimo comun divisore di due interi esiste sempre ed è unico. Infatti se a = 0, allora
(a, b) = |b|. Se invece a, b 6= 0, consideriamo l’insieme p1 , · · · , ps dei primi che dividono a o b (o entrambi).
Allora esistono interi (positivi) α1 , . . . , αs e β1 , . . . , βs tali che
β1
αs
βs
1
a = ±pα
1 · · · ps e b = ±p1 · · · ps .
Quindi l’intero
min(α1 ,β1 )
d = p1
· · · psmin(αs ,βs )
è il massimo comun divisore di a e b.
La discussione precedente suggerisce un algoritmo per il calcolo del massimo comun divisore: fattorizzare
i due interi e moltiplicare i fattori primi comuni con il minimo esponente. L’algoritmo purtroppo richiede la
fattorizzazione dei due interi per cui non si conosce nessun algoritmo efficiente. Vogliamo invece un algoritmo
efficiente che calcoli (a, b) in un numero di passi polinomiale nella lunghezza della rappresentazione binaria di
a e b.
Un primo algoritmo.
Euclide [1] ci propone il seguente algoritmo.
EuclideMCDLento(a, b)
(a, b) ← (max(|a|, |b|), min(|a|, |b|));
while b > 0
(a, b) ← (max(b, a − b), min(b, a − b));
end
return a;
Ad esempio, se abbiamo a = 30 e b = 12, l’algoritmo EuclideMCDLento procede nel modo seguente:
(30, 12) = (18, 12) = (12, 6) = (6, 6) = (6, 0) = 6.
Correttezza.
La correttezza dell’algoritmo EuclideMCDLento può essere derivata dal seguente lemma.
Lemma 1 Siano a e b due interi non entrambi uguali a zero con a ≥ b.
1. (a, 0) = |a|;
2. (a, b) = (b, a − b).
Dim.:
Dimostrazione lasciata allo studente volenteroso.
Algoritmi per il Massimo Comun Divisore
2
Analisi. Osserviamo però che l’algoritmo EuclideMCDLento per valori di b molto piú piccoli di a impiega
tempo proporzionale ad a. Ad esempio, se b = 1 il ciclo while è eseguito esattamente a volte e quindi l’algoritmo
EuclideMCDLento impiega tempo esponenziale nella lunghezza dell’input (a ha lunghezza n = dlog(a + 1)e
mentre l’algoritmo impiega tempo proporzioanle ad a = O(2n )).
Versione efficiente dell’algoritmo di Euclide. L’algoritmo EuclideMCDLento può essere migliorato
osservando che ripetute sottrazioni dello stesso intero possono essere “collassate” in una sola operazione calcolando il resto della divisione di a per b (ovvero a mod b). Ad esempio, il calcolo di (715, 26) richiede successive
sottrazioni di 26 finquando non si ottiene (dopo 27 iterazioni) un intero minore di 26. Lo stesso risultato si
può ottenere in un solo passo calcolando 715 mod 26. Pertanto consideriamo il seguente algoritmo.
EuclideMCD(a, b)
(a, b) ← (max(a, b), min(a, b));
while b > 0
(a, b) ← (b, a mod b);
end
return a;
Analisi dell’algoritmo efficiente.
nel modo seguente.
EuclideMCDRec(a, b)
(a, b) ← (min(|a|, |b|), max(|a|, |b|));
if a = 0 then
return(b);
return EuclideMCDRec(b, a mod b);
Per analizzare l’algoritmo EuclideMCD, riscriviamo EuclideMCD
EuclideMCDMod(a, b)
(r−1 , r0 ) ← (max(a, b), min(a, b));
k = 0;
while rk > 0
k = k + 1;
rk = rk−2 mod rk−1 ;
end
return rk−1 ;
Lemma 2 Per ogni k tale che rk > 0, abbiamo che rk ≤ 12 rk−2 .
Dim.:
Consideriamo due casi.
1. rk−1 ≤ 12 rk−2 .
Poiché rk = rk−2 mod rk−1 abbiamo che rk < rk−1 e quindi rk < 12 rk−2 .
2. rk−1 > 21 rk−2 .
Poiché rk−1 = rk−3 mod rk−2 abbiamo che rk−1 < rk−2 < 2rk−1 e quindi rk = rk−2 mod rk−1 =
rk−2 − rk−1 ≤ 12 rk−2 .
Abbiamo quindi il seguente teorema.
Teorema 1 Il ciclo while dell’algoritmo EuclideMCDMod è eseguito al più 2 log(max a, b) volte, ove log x
denota il logaritmo in base 2 di x.
Bibliografia
[1] Euclide. Elementi. Disponibile all’URL http://aleph0.clarku.edu/ ˜ djoyce/java/elements/elements.html.
La versione aggiornata di questo documento si trova all’url http://www.dia.unisa.it/ ˜giuper/ASDI/note/gcd.pdf.