Fattorizzare i numeri interi Ci sono molti algoritmi efficienti per fattorizzare numeri interi e molti sono i testi dove è possibile trovare una completa trattazione sull'argomento, Qui vogliamo proporre dei sistemi (in parte abbastanza originali e forse relativamente veloci ma senza nessuna pretesa da parte nostra) per cercare di trovare i fattori di un numero intero con metodi algebrici e facilmente implementabili in un moderno calcolatore. L'idea è comunque quella di trovare dei limiti entro cui cercare con maggiori probabilità le soluzioni. Nella ricerca delle soluzioni prendiamo principalmente in esame solo valori interi positivi benché in linea di principio potremmo considerare anche i negativi dal momento che 9 = 3*3 = (-3)*(-3). Facendo girare tutti gli algoritmi in parallelo aumenta la probabilità di trovare soluzioni in tempi rapidi. Ogni algoritmo sarà implementato con una applicazione scritta in C/C++ o in PARI/Gp per la gestione dei grandi numeri 1
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Fattorizzare i numeri interi
Ci sono molti algoritmi efficienti per fattorizzare numeri interi e molti sono i testi dove è
possibile trovare una completa trattazione sull'argomento, Qui vogliamo proporre dei sistemi
(in parte abbastanza originali e forse relativamente veloci ma senza nessuna pretesa da parte
nostra) per cercare di trovare i fattori di un numero intero con metodi algebrici e facilmente
implementabili in un moderno calcolatore. L'idea è comunque quella di trovare dei limiti entro
cui cercare con maggiori probabilità le soluzioni. Nella ricerca delle soluzioni prendiamo
principalmente in esame solo valori interi positivi benché in linea di principio potremmo
considerare anche i negativi dal momento che 9 = 3*3 = (-3)*(-3). Facendo girare tutti gli
algoritmi in parallelo aumenta la probabilità di trovare soluzioni in tempi rapidi. Ogni algoritmo
sarà implementato con una applicazione scritta in C/C++ o in PARI/Gp per la gestione dei
grandi numeri
Considerazione preliminare (algoritmo 0)
Dato un numero p da fattorizzare di n cifre è facile provare che almeno un fattore deve essere
dell'ordine di
cioè deve avere almeno int(n/2) cifre con int(x) la parte la funzione parte
intera di x.
1
Se p = ab con a, b numeri primi allora entrambi i fattori sono entrambi maggiori di W cioè tali
per cui
a > W, b > W cioè S= a+b > W. In questo particolare caso possiamo porre anche
Considerare W ci è particolarmente utile quando trattiamo di grandi dimensioni
perché come vedremo meglio con gli altri algoritmi ci può aiutare a trovare dei limiti per i
int main(int argc, char *argv[]){long double x, p;long i = 0;int cifre;cout << "inserisci il numero di cifre del numero intero";cin >> cifre;cout <<" inserisci il numero da fattorizzare";cin >> p;x = pow(10, int(cifre/2)-1 );do{x = x + 1;i = i + 1;} while(int(p/x) != (p/x));cout << "un fattore e' " << x;cout <<" passi di elaborazione: " << i;cin >> "---------";return 0;}
2
LISTATO IN PARI/GP
{ algo2(cifre) = local(x, p);
p = nextprime(10^10)*nextprime(10^12);
x = 10^(floor(cifre/2)-1);
while(floor(p/x) != (p/x), x=x+1);
print(x);
print("-----");
print(p/x);
return (1);}
Primo algoritmo (AL-1) (variante della fattorizzazione alla Fermat)
(in generale non è detto che ci siano solo due fattori come nell'RSA ma il
procedimento di fattorizzazione può essere ripetuto per ognuno dei due fattori trovati finché
non si arriva a fattori che hanno decomposizione banale cioè che sono primi).
3
dove OR sta ad indicare che la relazione vale per una radice o per entrambe
tutti i numeri interi positivi (ove la ricerca può essere fatta in modo sequenziale
oppure random)
Attenzione: per P molto grande A(p) cioè il numero dei primi minori di P è
approssimativamente p/log(p)
LISTATI IN C++ E IN VISUAL BASIC .NET
Nei codici sorgenti in C++ che seguono ho usato l'espressione 'int(p/x)' per
semplicità tuttavia sarebbe meglio sostituirla con la più esatta sintatticamente
int main(int argc, char *argv[]){ long double x, p; long i, j; j = 0; cout << "inserisci il numero da fattorizzare "; cin >> p; for( i = int(sqrt(p)); i <= int(p/2); i++) { j = j +1; if(int(p/i) == (p/i)) { cout << "fattore: " << i << "\n"; cout << "passi: " << j << "\n"; } } cin >> "-----------------"
return 0;}
4
lo stesso algoritmo può essere implementato in Visual Basic .Net usando per la ricerca
dei fattori un generatore di numeri casuali: la ricerca si rileva molto più veloce:
Module Module1
Sub Main() Dim p As Decimal Dim generator As New Random Dim a As Decimal Dim i As Integer i = 0 Console.WriteLine("inserisci il numero da fattorizzare") p = Console.ReadLine() Do a = generator.Next(2, Int(Math.Sqrt(p))) i = i + 1 Loop While ((p / a) <> Int(p / a)) Console.Write("fattore: ") Console.Write(a) Console.Write("passi: ") Console.Write(i) Console.ReadLine() End Sub
Supponiamo di stare a considerare un tipico problema RSA quindi p ha solo due fattori ed s è
sicuramente un numero pari essendo la somma di due primi quindi di due numeri dispari.
Cerchiamo di velocizzare la ricerca dei fattori usando l’elemento W precedentemente
descritto.
mi porta a dover risolvere il seguente sistema:
7
mi porta a dover risolvere il seguente sistema:
unito alle soluzioni del sistema
Osservazione
1) equivale alla ben nota relazione
2) se allora (più avanti approfondiremo questo caso)
LISTATO IN C++
#include <stdio.h>#include <math.h>#include <iostream.h>int main(int argc, char *argv[]){ long double p, x, y, s; long i; cout << "inserisci il numero da fattorizzare "; cin >> p; s = 2* int(sqrt(p)); i = 0; do { x = (s + sqrt(pow(s,2)-4*p))/2; y = (s - sqrt(pow(s,2)-4*p))/2; s = s+1; i = i+1; }while((int(p/x) != (p/x)) || (int(p/y) != (p/y))) ; // si può mettere && (and) al posto di || (OR) ma una delle due cout << "un fattore e' " << x << "\n"; //soluzioni trovate potrebbe non essere intera cout << "un fattore e' " << y << "\n"; cout << "passi: " << i; cin >> "--------------------"; return 0;}
{algo1(p) = local( s, d, x, y);s = 2 * floor(sqrt(p));d = sqrt(abs(s^2-4*p));x = (s + d)/2;y = (s - d)/2;while (floor(p/x) != (p/x) && floor(p/y) != (p/y),s++;d = sqrt(abs(s^2-4*p));x = (s + d)/2;y = (s - d)/2);print(x);print("----");print(y);return (1);}
{algo1(p) = local(s, d, x, y);s = floor(sqrt(p));d = sqrt(abs(s^2-p));x = (s + d);y = (s - d);while (floor(p/x) != (p/x) && floor(p/y) != (p/y),s = s+1;d = sqrt(abs(s^2-p));x = (s + d);y = (s - d));print(x);print("----");print(y);return (1);}
9
{algo2b(p) = local(b, d, x, y);b = floor(sqrt(p));d = sqrt(abs(b^2-p));x = b + d;y = b - d;while (floor(p/x) != (p/x) && floor(p/y) != (p/y),b++ ;d = sqrt(abs(b^2-p));x = b + d;y = b - d);print(x);print("----");print(y); return (1);}
VARIANTE
a numero pari perché differenza di due numeri pari
Ciò porta all’equazione biquaratica
10
LISTATO IN C++
#include <stdio.h>#include <math.h>#include <iostream.h>int main(int argc, char *argv[]){ float a, x, y, p; long double i; cout << "inserisci il numero da fattorizzare "; cin >> p; a = 0; i = 0; do{ x = sqrt( (a+2*p+sqrt(pow(a,2)+4*a*p))/2); y = sqrt( (a+2*p-sqrt(pow(a,2)+4*a*p))/2); a = a+1; i = i+1; } while ((int(p/x) != (p/x)) || (int(p/y) != (p/y))) ; // si può mettere && (and) al posto di || (OR) ma una
cout << "fattore: " << x << "\n"; // delle due soluzioni trovate potrebbe non essere intera cout << "fattore: " << y << "\n"; cout << "passi: " <<i << "\n"; cin >> " -----"; return 0;}
int main(int argc, char *argv[]){ long double m, x, y, p; long i; cout << "inserisci il numero da fattorizzare "; cin >> p; m = 0; i = 0; do{ x = (m + sqrt(pow(m, 2) + 4*p))/2; y = (-m + sqrt(pow(m, 2) + 4*p))/2; m = m+1; i = i+1; } while ( (int(p/x) != (p/x)) || (int(p/y) != (p/y))); // si può mettere && (and) al posto di || (OR) ma una
cout << "fattore: " << x << "\n"; // delle due soluzioni trovate potrebbe non essere intera cout << "fattore: " << y << "\n"; cout << "passi: " <<i << "\n"; cin >> " -----";
, (possiamo considerare anche la soluzione negativa quella con
segno - , però poi occorre calcolare il suo valore assoluto)
Come nei casi precedenti
porta a:
unito alle soluzioni di
porta al sistema di condizioni
Wpbbx 2
allora
15
unito a
ciò porta a:
osservazione: se è un problema RSA allora quindi
con
LISTATO IN C++
#include <stdio.h>#include <math.h>#include <iostream.h>int main(int argc, char *argv[]){long double x, y, p;long a;long i = 0;cout<< "inserisci il numero da fattorizzare ";cin >> p;a = int(sqrt(p));a = a+1;do {x = a + sqrt(pow(a,2) -p);y = a - sqrt(pow(a,2) - p);a = a+1;i = i+1;} while( (int(p/x)!=(p/x)) ||(int(p/y) != p/y)) ; // si può mettere && (and) al posto di || (OR) ma una delle duecout << "fattore: " << x << "\n"; // soluzioni trovate potrebbe non essere interacout << "fattore: " << y << "\n";cout << "passaggi: " << i;cin >> "-------------"; return 0;}
int main(int argc, char *argv[]){long double x, y, p;long int i, a, c;a = 0;i = 0;cout << "inserisci numero ";cin >> p;do{ x = sqrt(p+a+sqrt(pow(a,2)+2*p*a)); y = sqrt(p+a-sqrt(pow(a,2)+2*p*a)); a = a+1; // qui è meglio mettere a = a+ 1/2 se non è un problema RSA; i = i +1;}while( (int(p/y) != (p/y)) || (int(p/x) != (p/x)) ) ; // si può mettere && (and) al posto di || (OR) macout << "fattore: " << x << "\n"; // una delle due soluzioni trovate potrebbe non essere intera cout << "fattore: " << y << "\n";cout << "passi: " << i;}
{ long double m, x, y, p; long i; cout << "inserisci il numero da fattorizzare "; cin >> p; x = int(pow(10, log10(p)/2))+1; y = int(pow(10, log10(p)/2))+1; do{ x = x-1; y = y+1; i = i+1; } while ( (int(p/x) != (p/x)) && (int(p/y) != (p/y)) );
Fattorizzazione per individuazione dell’intervallo migliore
Partendo dalla già nota relazione e ponendo y = x+a arriviamo a risolvere una
disequazione di secondo grado le cui soluzioni sono:
con
Nell’ipotesi invece che y = x-a ho che
con
Il problema è capire quale valore di a assegnare. Nei problemi RSA le radici non sono né troppo
vicine tra loro né troppo lontane quindi un buon valore per a potrebbe essere
Stesso discorso se partiamo da :
per y = x-a ottengo che per y = x+a
34
Teoria dei grandi numeri
Come è possibile gestire in un normale calcolatore numeri molto grandi, diciamo
numeri interi a 200 cifre ? Vediamo l'algoritmo con un esempio e poi generalizziamo con il
formalismo matematico
Supponiamo di voler calcolare 321*44 = 14124
sappiamo che ogni numero intero lo possiamo scrivere nella sua notazione polinomiale:
con X = 10
svolgiamo la moltiplicazione tra i polinomi e consideriamo che 12 mod 2 = 2 e che
12-(12 mod 10) = 10 (per i coefficienti del polinomio prodotto usiamo l'aritmetica
modulo 10 ovvero se abbiamo coefficienti maggiori o uguali a 10 cioè ad esempio 12
= 10 +2 scriviamo 12 = X+2 per poi continuare a semplificare e a ridurre modulo 10
finché tutti i coefficienti del polinomio sono in base 10)
tralasciano i passaggi abbiamo che cioè 14124 che è la soluzione
Il caso della somma è ancora più semplice perché
35
cioè 321 + 44 = 365 (anche per la somma se ce ne fosse
stato bisogno avremmo dovuto ridurre i coefficienti del polinomio in base l'aritmetica modulo
10)
Idem è il caso della differenza tra numeri
Questo ci permetterà di programmare un calcolatore per fargli compiere operazioni molto
complesse che un normale PC non riuscirebbe a fare. Infatti dall'algebra elementare esistono
formule che generalizzano la somma, la differenza la moltiplicazioni e la divisione tra polinomi
di qualunque grado
caso con la virgola:
12,6 +15,4 =
Il caso della divisione è un po',più complesso anche se in realtà una divisione non è altro che
una serie di sottrazioni come una moltiplicazione non è che una serie di somme
36
Ipotesi di Goldbach
La seguente trattazione non è la vera dimostrazione della congettura (la congettura
non è stata ancora dimostrata) ma solo il tentativo di fare alcuni ragionamenti
intorno alla congettura stessa.
LA CONGETTURA: Ogni numero pari maggiore di due è somma al più di due numeri
primi non necessariamente diversi tra loro
Primo tentativo di dimostrazione
Sia data la funzione Phi di eulero che mi dà il numero di primi con q minori di q.
E’ facile provare che
a) è sempre pari qualunque sia q
b) sse q è primo
PRIMO TANTATIVO DI DIMOSTRAZIONE (per induzione)
1) assumiamo che 2a = p+q vera, p, q primi
2) un numero pari è sempre la somma di due numeri pari
37
sse è primo; sse è primo. Allora
3)
4) vera
5) per induzione 2a = p+q per ogni a (ad ogni a cambieranno p, q)
SECONDO TENTATIVO DI DIMOSTRAZIONE (dimostrazione diretta)
Sia n = pq con p, q primi. Possiamo anche considerare n = 2pq perché
è sempre pari e perché MCD(p,q) = 1
pq+1-2k = p+q e dato che pq+1 è pari perché pq è dispri pq+1-2k è pari perché
differenza di numeri pari, quindi pq+1-2k è un generico numero pari che è somma di
due primi p, e q.
ora questo ci indica una strada per costruire numeri primi:
38
risolviamo il sistema
pq+1-2k = m p+q = m
dove m è un generico numero pari e p, q sono le incognite mentre k è un parametro
intero. Svolgendo i calcoli e le opportune sostituzioni abbiamo
a questo punto dovremmo essere in grado di sviluppare un applicativo tale che per
ogni numero pari m mi generi almeno due numeri p, q primi. Ciclando per tutti i pari avremo
tutti i numeri primi . In realtà ci si rende ben presto conto che con questo sistema si ottengono
non solo le coppie di primi ma anche le coppie di dispari la cui somma è m (si veda più in basso
l'impostazione geometrica del problema)
ecco l'applicativo in C++:
#include <stdio.h>#include <iostream.h>#include <math.h>int main(int argc, char *argv[]){long double p, q, m, k;long double v, w;int i, temp;cout << "inserisci un numero pari ";cin >> m;k = int((pow(m,2)-4*m+4)/8);do{
n = numero delle sedute di borsa da considerare = periodo di investimento
a = valore iniziale da investire
(termine ennesimo)
ad ogni seduta investirà il termine:
a cui impongo dei limiti fissati
Se penso che la tendenza si al rialzo una strategia prudente è 0<q<1 (se ci fossero delle
chiusure in "negativo" la perdita sarebbe limitata)
Se penso che la tendenza sia al ribasso una strategia prudente è q>1 (al primo "rimbalzo
tecnico" si recuperano tutte le perdite)
Nel caso delle progressioni aritmetiche:
50
il vero problema è come scegliere i parametri in modo da ottimizzare i guadagni e ridurre la
perdite supponendo di sapere la "tendenza del mercato". L'argomento merita un
approfondimento. Non tutti sono concordi con queste teorie ed esistono comunque pareri
discordi.
Il Lotto e la matematica
Non esistono teoria sicure sul gioco del lotto. Qui vogliamo presentare un semplice programma
in Visual Basic .Net per la generazione di numeri casuali per giocare al Lotto e tentare la
fortuna. Chi vende i numeri "fortunati" spesso altro non fa che usare sistemi come questo
(sistemi che non garantiscono in nessun caso vincite)- Il listato si può modificare per adattarlo
anche ad altri linguaggi di programmazione come il C/C++.
LISTATO IN VISUAL BASIC .NET
Module Module1 Sub Main() Dim generator As New Random Dim arr(30) As Integer Dim randomValue As Integer Dim ruota As String Dim i As Integer Console.WriteLine("inserisci la ruota") ruota = Console.ReadLine() Console.WriteLine(ruota) For i = 0 To 4 randomValue = generator.Next(1, 90) arr(i) = randomValue Console.Write(arr(i)) Console.Write("-") Next Console.ReadLine()
51
End SubEnd Module
52
Sommario
Fattorizzare i numeri interi...............................................................................................................................1
Primo algoritmo (AL-1) (variante della fattorizzazione alla Fermat).............................................................3
Secondo algoritmo (Al-2)..............................................................................................................................7
Terzo algoritmo (Al-3).................................................................................................................................12
Quarto algoritmo (Al-4)..............................................................................................................................15
Quinto algoritmo (Al-5)..............................................................................................................................18
Fattorizzazione con le disequazioni............................................................................................................22
Fattorizzazione con il teorema di Bezout....................................................................................................25
Fattorizzazione con i logaritmi....................................................................................................................26
Fattorizzazione con il metodo della bisezione............................................................................................28
L'approccio combinatorio - economico del problema................................................................................29
Fattorizzazione e ricerca operativa.............................................................................................................30
Fattorizzazione per differenza dei fattori...................................................................................................32
Fattorizzazione per individuazione dell’intervallo migliore.......................................................................34
Teoria dei grandi numeri................................................................................................................................35
Ipotesi di Goldbach.........................................................................................................................................37
Impostazione geometrica del problema.....................................................................................................43
Giocare in borsa con la matematica................................................................................................................46
I piani di accumulo del capitale......................................................................................................................49
Il Lotto e la matematica..................................................................................................................................51