Ridicarea la putere este o operație binecunoscută, formulă uzuală fiind: An=n∏i=1A=A×A×…×A⏟de n ori
Un algoritm care implementează această metodă va avea complexitate liniară, O(n):
int Putere(int A , int n) { int P = 1 ; for(int i = 1 ; i <= n ; i ++) P = P * A; return P; }
Descriere
O metodă mai bună este cea numită exponențierea rapidă , sau ridicarea la putere în timp logaritmic, complexitatea sa fiind O(log2n). Ea se bazează pe următoarea formulă:
An={1, dacă n=0A⋅An−1, dacă n – impar(An2)2, dacă n – par
Exemplu
Să calculăm 225:
- 225=2⋅224, deoarece
25
este impar - 224=(212)2, deoarece
24
este par - 212=(26)2, deoarece
12
este par - 26=(23)2, deoarece
6
este par - 23=2⋅22, deoarece
3
este impar - 22=(21)2, deoarece
2
este par - 21=2⋅20, deoarece
1
este impar - 20=1
Atunci în ordine inversă:
- 21=2⋅1=2
- 22=22=4
- 23=2⋅4=8
- 26=82=64
- 212=642=4096
- 224=40962=16777216
- 225=2⋅16777216=33554432
Constatăm că numărul înmulțirilor efectuate este mult mai mic decât în cazul primei metode.
Implementare recursivă
Implementarea recursivă este directă:
int Putere(int A , int n) { if(n == 0) return 1; if(n % 2 == 1) return A * Putere(A , n - 1); int P = Putere(A , n / 2); return P * P; }
Implementare iterativă
Să considerăm A25. Să-l scriem pe 25 ca sumă de puteri ale lui 2 (orice număr natural poate fi scris ca sumă de puteri ale lui 2 într-un singur mod): 25=1+8+16.
Atunci A25=A1+8+16=A1⋅A8⋅A16=(A1)1⏟=A1⋅(A2)0⏟=1⋅(A4)0⏟=1⋅(A8)1⏟=A8⋅(A16)1⏟=A16. Observăm că exponenții 0 și 1 sunt cifrele reprezentării în baza 2 a lui 25.
Se figurează următoarea idee, pentru a determina A
n
:
- vom determina un produs
P
, format din factori de formaA
1
,A
2
,A
4
,A
8
, … - determinăm cifrele reprezentării în baza
2
a luin
, începând cu cea mai nesemnificativă:- dacă cifra curentă este
1
, înmulțim peA
laP
,P = P * A;
- înmulțim pe
A
cu el însuși,A = A * A;
, obținând următoarea putere din șirul de mai sus
- dacă cifra curentă este
Implementare C++:
int Putere(int A , int n) { int P = 1; while(n) { if(n % 2 == 1) P = P * A; A = A * A; n /= 2; } return P; }
altă variantă, care folosește operațiile pe biți:
int Putere(int A , int n) { int P = 1; for(int k = 1 ; k <= n ; k <<= 1) { if((n & k)) P *= A; A = A * A; } return P; }
Observații
- ridicarea la putere rapidă poate fi folosită și pentru:
- operații modulo (determinarea restului împărțirii rezultatului la o valoare dată)
- numere mari
- ridicarea la putere a matricelor
- ridicarea la putere a polinoamelor
Probleme ataşate
Nr. | Problema | Clasa | Dificultate | Operații I/O |
---|---|---|---|---|
1 | #2398 - Moka | 9 | dificilă | fișiere |
2 | #2404 - Test | 9 | ușoară | fișiere |