Tale algoritmo si può trasformare facilmente in un algoritmo che testi

Teoria dei numeri
Lezione del giorno 15 maggio 2009
Algoritmi di fattorizzazione.
Sono algoritmi che, dato in input un naturale n>1, calcolano tutti i fattori primi di n: a tutt’oggi non
è stato trovato un algoritmo di fattorizzazione di complessità polinomiale.
Un algoritmo di fattorizzazione in genere cerca ottenere un obiettivo intermedio: decomporre
l’input n nel prodotto n=ab, dove a,b sono naturali (non necessariamente primi) tali che 1<a,b<n (se
a,b non esistono, si conclude che n è primo). Una volta trovati a,b l’algoritmo viene riapplicato
separatamente ad a,b per decomporli ulteriormente (se possibile): dopo un numero finito di ripetute
applicazioni dell’algoritmo, si perviene al calcolo dei fattori primi di n.
Ovviamente un algoritmo “ingenuo” di fattorizzazione consiste (come nel test ingenuo di primalità)
nel testare, per ogni naturale a con 2a n , se a è divisore di n, e in caso affermativo porre n= ab
(dove b=n/a): il numero dei test da effettuare è di ordine esponenziale O( 2 k) se k è la lunghezza
binaria di n (perché n<2k dunque n < 2 k).
Questo algoritmo trova un divisore a di n in tempi di calcolo ragionevoli solo se n ha un fattore
relativamente “piccolo”.
Illustriamo ora un algoritmo di fattorizzazione che invece è efficiente se n è prodotto di 2 divisori
relativamente “grandi” e “vicini fra loro”.
Algoritmo di fattorizzazione di Fermat.
Supponiamo l’input n dispari: non è una limitazione in un algoritmo di fattorizzazione perché se n è
pari, con successive divisioni per 2 si può fattorizzare n nella forma n=2km, con m dispari, e
sostituire m al posto di n come input.
L’algoritmo si basa sul seguente risultato, il quale dimostra che fattorizzare n nel prodotto di 2
numeri naturali equivale sostanzialmente a rappresentare n come differenza di 2 quadrati:
Teorema (Fermat).
Sia n un naturale dispari, e siano:
S = { (a,b)NxN / ab, n=ab }
T = { (r,s)ZxZ / r>s0, n=r2-s2 }
Allora la funzione f : S  T definita da f(a,b)=((a+b)/2,(a-b)/2) è biunivoca.
Dimostrazione:
Si verifica facilmente che f(a,b)T se (a,b)S.
Per dimostrare che f è biunivoca, basta costruire la funzione inversa: definiamo f-1 : T  S ponendo
f-1(r,s)=(r+s,r-s) (si verifica facilmente che f-1(r,s)S se (r,s)T).
Si verifica infine che le composizioni ff-1, f-1f sono le funzioni identiche di T ed S.
Come conseguenza del teorema precedente, è possibile implementare un algoritmo di
fattorizzazione: dato in input un intero dispari n>1, per trovare una fattorizzazione di n nel prodotto
di 2 numeri naturali a,b, basta trovare una coppia (r,s)T (quindi r,s interi, r>s0, tali che n=r2-s2) e
porre (a,b)=f-1(r,s)=(r+s,r-s).
Per trovare una coppia (r,s)T, possiamo fissare un intero r>0, e cercare un intero s0 tale che si
abbia r2-n=s2 : se r2-n =0 allora s=0, n=r2, a=b=r; se invece r2-n >0 si può usare il test già esaminato
in precedenza per verificare se il numero naturale r2-n è un quadrato perfetto di base naturale
opportuna s.
Dovendo essere r2-n=s20, si ha r n , dunque il valore minimo da fissare per r è r= n . (è il
cosiddetto ceiling di n , ossia il minimo intero  n ).
Per quanto riguarda il valore massimo di r, notiamo che al crescere di r, cresce il valore
corrispondente di a (se esiste) nella coppia (a,b): se r1>r, e se n=r2-s2=r12-s12 , allora s1>s, dunque
a=r+s<a1=r1+s1 . Poiché in una fattorizzazione non banale di n (dispari) il valore (teorico) massimo
di a è a=n/3 (con b=3), e ricordando che r=(a+b)/2, si ottiene che il valore massimo per r è la parte
intera di [(n/3)+3]/2=(n+9)/6.
Dunque, l’algoritmo di fattorizzazione di Fermat si può implementare nel modo seguente:
- input n intero dispari >1
- per r= n ,  n  +1,……, (n+9)/6 si testa se r2-n è un quadrato perfetto di base s0 e in
caso affermativo si esce con output “n=ab dove a=r+s, b=r-s”
- se nel ciclo precedente nessun test ha avuto esito positivo, si esce con output “n è primo”
Notiamo anche, come già premesso, che il test di Fermat trova un fattore non banale di n in tempi
ragionevoli se n è prodotto di 2 divisori a,b “abbastanza grandi” e “vicini fra loro” perché in tale
caso a,b  n , dunque r=(a+b)/2 n , ossia il valore r che nel ciclo permette di trovare la
fattorizzazione di n è “vicino” alla radice quadrata di n, e dunque (partendo dal valore iniziale
r= n ) tale valore viene trovato relativamente “presto”.
Esempio.
Se l’input é n=6077,  n =78, (n+9)/6=1014, il ciclo si dovrà eseguire per r=78, 79,…., 1014 e
si ha:
r=78  r2-n =7 (non quadrato)
r=79  r2-n =164 (non quadrato)
r=80  r2-n =323 (non quadrato)
r=81  r2-n =484 =222
ottenendo la fattorizzazione n=ab dove a=r+s=81+22=103, b=r-s=81-22=59.