Salta al contenuto
Note per Studenti Esponenziazione veloce per quadrature successive

Esponenziazione veloce per quadrature successive

In questa pagina 7

Sia DD un dominio e ∘:D×D→D\circ : D \times D \to D un operatore binario associativo, (a∘b)∘c=a∘(b∘c)(a \circ b) \circ c = a \circ (b \circ c), con elemento neutro ee, cioè a∘e=e∘a=aa \circ e = e \circ a = a per ogni a∈Da \in D. Esempi: D=ND = \mathbb N con ∘=+\circ = + (e=0e = 0); matrici n×nn \times n con ∘=×\circ = \times (prodotto righe per colonne, e=Ine = I_n). L'operatore non deve essere commutativo.

Definizione (potenza). Per x∈Dx \in D e n∈Nn \in \mathbb N:

xn={en=0,x∘xn−1=xn−1∘xn>0.x^n = \begin{cases} e & n = 0, \\ x \circ x^{n-1} = x^{n-1} \circ x & n > 0. \end{cases}

Per n≥1n \ge 1, xn=x∘x∘⋯∘xx^n = x \circ x \circ \dots \circ x (nn fattori), senza parentesi per l'associatività.

L'uguaglianza x∘xn−1=xn−1∘xx \circ x^{n-1} = x^{n-1} \circ x vale per associatività anche per operatori non commutativi (come il prodotto di matrici). Il modello di costo assegna costo 11 a ogni applicazione di ∘\circ e costo 00 al resto. Si cerca un algoritmo efficiente per xnx^n.

Algoritmo basato sulla definizione

STUPID_POWER(x, n)
  if n = 0 then return e
  p <- x
  for i <- 1 to n - 1 do
    p <- x ∘ p
  return p

La definizione è ricorsiva, ma è una ricorsione di coda, eliminabile in un ciclo. TSP(n)=n−1=Θ(n)T_{SP}(n) = n - 1 = \Theta(n): lineare nell'esponente. Si vuole battere questo valore.

Proprietà di sottostruttura

Proprietà. Sia k=⌊n2⌋k = \lfloor \frac n2 \rfloor.

  • Se n=2kn = 2k è pari: xn=xk∘xkx^n = x^k \circ x^k.
  • Se n=2k+1n = 2k + 1 è dispari: xn=xk∘xk∘xx^n = x^k \circ x^k \circ x.

Dimostrazione. Per n=2kn = 2k: x2k=xk+k=xk∘xkx^{2k} = x^{k + k} = x^k \circ x^k, perché l'associatività permette di raggruppare i 2k2k fattori in due gruppi da kk. Per n=2k+1n = 2k + 1: x2k+1=xk+k+1=xk∘xk∘xx^{2k+1} = x^{k + k + 1} = x^k \circ x^k \circ x, con un fattore in più. Nessuna ipotesi su ∘\circ oltre l'associatività. ■\blacksquare

La proprietà lega xnx^n a x⌊n/2⌋x^{\lfloor n/2 \rfloor}: noto y=x⌊n/2⌋y = x^{\lfloor n/2 \rfloor}, bastano una applicazione di ∘\circ se nn è pari (xn=y∘yx^n = y \circ y) e due se è dispari (xn=y∘y∘xx^n = y \circ y \circ x). Per nn pari, a partire da xn/2x^{n/2} la definizione richiederebbe ancora n2\frac n2 applicazioni, qui ne basta una: si quadra il valore. Gli algoritmi di questo tipo sono detti di squaring.

Algoritmo ricorsivo POWER

POWER(x, n)
  if n = 0 then return e                { BASE }
  if n = 1 then return x
  k <- floor(n / 2)                     { DIVIDE: nessun lavoro }
  y <- POWER(x, k)                      { RECURSE }
  if EVEN(n) then return y ∘ y          { CONQUER }
  else return y ∘ y ∘ x

Il caso base n=1n = 1 sarebbe superfluo (si otterrebbe ricorsivamente), ma evita due applicazioni inutili di ∘\circ (con y=ey = e si farebbe e∘e∘xe \circ e \circ x). La correttezza discende da quella della proprietà di sottostruttura.

Analisi

Il conquer costa al più 22 (per nn dispari), il divide 00:

T(n)≤{0n=0,1,T ⁣(⌊n2⌋)+2n>1.T(n) \le \begin{cases} 0 & n = 0, 1, \\ T\!\left(\lfloor \frac n2 \rfloor\right) + 2 & n > 1. \end{cases}

Per i valori n=2t−1n = 2^t - 1 ogni istanza generata è dispari (⌊2t−12⌋=2t−1−1\lfloor \frac{2^t - 1}{2} \rfloor = 2^{t-1} - 1): il costo è 22 a ogni livello, quindi il limite 22 è raggiunto. La ricorrenza è del tipo del Master Theorem - enunciato, casi e applicazioniMaster Theorem per T(n) = aT(n/b) + w(n): si confronta w(n) con la funzione soglia n^(log_b a). Caso 1 (w minore di una potenza polinomiale): Theta(n^(log_b a)); caso 2 (w della stessa taglia): Theta(n^(log_b a) log n); caso 3 (w maggiore e regolare): Theta(w(n)). Prova completa dai livelli dell'albero, versione estesa (parti intere, n0 qualsiasi), esempi, e l'uso scorretto quando nessun caso si applica (w = n log n).Master Theorem - enunciato, casi e applicazioni → con a=1a = 1, b=2b = 2, w(n)=2w(n) = 2: la soglia è nlog⁡21=n0=1=Θ(w(n))n^{\log_2 1} = n^0 = 1 = \Theta(w(n)), caso 2, e T(n)=Θ(log⁡n)T(n) = \Theta(\log n). Il Master Theorem copre dunque anche soluzioni logaritmiche; la stessa ricorrenza è quella della ricerca binaria. Il risultato è un miglioramento esponenziale rispetto a STUPID_POWER.

Conto esatto. Sia k=⌊log⁡2n⌋k = \lfloor \log_2 n \rfloor e ν(n)\nu(n) il numero di bit a 11 della rappresentazione binaria di nn. Per n≥1n \ge 1:

TPOWER(n)=⌊log⁡2n⌋+ν(n)−1.T_{POWER}(n) = \lfloor \log_2 n \rfloor + \nu(n) - 1.

Dimostrazione per induzione su nn (vedi Dimostrazioni, induzione e invariantiTecniche di dimostrazione (esempio, controesempio, assurdo), induzione con casi base multipli, invarianti di ciclo (inizializzazione, conservazione, uso alla fine), schema generale per provare la correttezza; esempi svolti su arrayMax, sequenza di bit e numeri di Fibonacci.Dimostrazioni, induzione e invarianti →). Base: n=1n = 1 dà 0+1−1=00 + 1 - 1 = 0. Se n≥2n \ge 2 è pari, T(n)=T(n2)+1T(n) = T(\frac n2) + 1; poiché ⌊log⁡2n2⌋=⌊log⁡2n⌋−1\lfloor \log_2 \frac n2 \rfloor = \lfloor \log_2 n \rfloor - 1 e ν(n2)=ν(n)\nu(\frac n2) = \nu(n) (si toglie uno 00 finale), T(n)=(⌊log⁡2n⌋−1)+ν(n)−1+1=⌊log⁡2n⌋+ν(n)−1.T(n) = \bigl( \lfloor \log_2 n \rfloor - 1 \bigr) + \nu(n) - 1 + 1 = \lfloor \log_2 n \rfloor + \nu(n) - 1. Se n≥3n \ge 3 è dispari, T(n)=T(n−12)+2T(n) = T(\frac{n-1}{2}) + 2; ora ⌊log⁡2n−12⌋=⌊log⁡2n⌋−1\lfloor \log_2 \frac{n-1}{2} \rfloor = \lfloor \log_2 n \rfloor - 1 e ν(n−12)=ν(n)−1\nu(\frac{n-1}{2}) = \nu(n) - 1 (si toglie l'ultimo bit, che è 11), quindi T(n)=(⌊log⁡2n⌋−1)+(ν(n)−1)−1+2=⌊log⁡2n⌋+ν(n)−1.■T(n) = \bigl( \lfloor \log_2 n \rfloor - 1 \bigr) + \bigl( \nu(n) - 1 \bigr) - 1 + 2 = \lfloor \log_2 n \rfloor + \nu(n) - 1. \qquad \blacksquare

In parole: ⌊log⁡2n⌋\lfloor \log_2 n \rfloor quadrature (una per ogni livello) più ν(n)−1\nu(n) - 1 moltiplicazioni per xx (una per ogni bit a 11 tranne il primo). Il minimo su 2k≤n<2k+12^k \le n < 2^{k+1} è kk (nn potenza di 22) e il massimo 2k2k (n=2k+1−1n = 2^{k+1} - 1, tutti bit a 11). Per n=2tn = 2^t la formula generale (Albero della ricorrenza e formula generale per le ricorrenzeL'albero della ricorrenza ha la forma dell'albero delle chiamate dell'istanza peggiore e T(n) è la somma dei lavori dei nodi. Per la famiglia T(n) = s(n)T(f(n)) + w(n) con base T0 per n <= n0, contando i nodi per livello con le iterate di f e il livello f*(n,n0) si ottiene la formula chiusa T(n) = somma_l [prodotto_j s(f^(j)(n))] w(f^(l)(n)) + [prodotto s] T0, verificata per induzione e applicata a esempi (merge sort, Hanoi, ricorrenze con radice).Albero della ricorrenza e formula generale per le ricorrenze →) con s=1s = 1, f(n)=n2f(n) = \frac n2, w=1w = 1 dà T(n)=∑ℓ=0log⁡2n−11=log⁡2nT(n) = \sum_{\ell=0}^{\log_2 n - 1} 1 = \log_2 n.

Esempio (x13x^{13}). 13→6→3→113 \to 6 \to 3 \to 1. POWER(x,1) =x= x (nessuna operazione); POWER(x,3): y=xy = x, dispari, y∘y∘x=x3y \circ y \circ x = x^3 (22 operazioni); POWER(x,6): y=x3y = x^3, pari, y∘y=x6y \circ y = x^6 (11); POWER(x,13): y=x6y = x^6, dispari, y∘y∘x=x13y \circ y \circ x = x^{13} (22). Totale 5=⌊log⁡213⌋+ν(13)−1=3+3−15 = \lfloor \log_2 13 \rfloor + \nu(13) - 1 = 3 + 3 - 1, contro le 1212 di STUPID_POWER.

Osservazione sul costo. Il modello a costo unitario è ragionevole per somme e prodotti di interi o reali, ma non per operatori i cui risultati sono più grandi degli operandi (unione di insiemi, prodotto di polinomi, interi con tantissime cifre): lì l'analisi va rifatta con un modello di costo adeguato.

Algoritmi iterativi

I pacchetti di aritmetica non usano la ricorsione, per non pagarne i costi (nascosti dal modello). Si ottiene facilmente una versione iterativa con lo stesso numero di moltiplicazioni asintotico. Se n=bkbk−1…b0n = b_kb_{k-1}\dots b_0 in binario, con k=⌊log⁡2n⌋k = \lfloor \log_2 n \rfloor (⌊log⁡2n⌋+1\lfloor \log_2 n \rfloor + 1 bit), n=∑i=0kbi2in = \sum_{i=0}^{k} b_i 2^i e per l'associatività

xn=∘ki=0, bi=1x2i.x^n = \underset{i=0,\ b_i = 1}{\overset{k}{\circ}} x^{2^i}.

Si accumulano quindi le potenze x2ix^{2^i} con bi=1b_i = 1, e queste si ottengono iterativamente con x2i=x2i−1∘x2i−1x^{2^i} = x^{2^{i-1}} \circ x^{2^{i-1}}.

POWER2(x, n)
  if n = 0 then return e
  * n = b_k b_{k-1} ... b_0 *
  p <- e                         { accumula le potenze x^(2^i) con b_i = 1 }
  s <- x                         { a inizio iterazione i: s = x^(2^i) }
  for i <- 0 to k do
    if b_i = 1 then p <- p ∘ s
    s <- s ∘ s
  return p

Conto letterale: un quadrato s∘ss \circ s per ognuna delle k+1k + 1 iterazioni e un prodotto p∘sp \circ s per ognuno dei ν(n)\nu(n) bit a 11: TPOWER2(n)=k+1+ν(n)≤2(k+1)=2(⌊log⁡2n⌋+1)T_{POWER2}(n) = k + 1 + \nu(n) \le 2(k + 1) = 2(\lfloor \log_2 n \rfloor + 1) al caso peggiore, Θ(log⁡n)\Theta(\log n).

I bit non servono: si possono ottenere con il test di parità e la divisione intera, con una variabile mm inizializzata a nn (lo shift destro della rappresentazione di mm):

POWER3(x, n)
  p <- e;  s <- x;  m <- n
  for i <- 0 to k do
    if NOT EVEN(m) then p <- p ∘ s
    s <- s ∘ s
    m <- floor(m / 2)
  return p

POWER3 esegue le stesse applicazioni di operatore di POWER, in ordine bottom-up: è come se eseguisse solo le fasi di conquer, risparmiandosi tutta la generazione top-down dell'albero.

Esempio (x13x^{13}, 13=1101213 = 1101_2).

ii bib_i pp dopo il passo ss dopo il passo
0 1 e∘x=xe \circ x = x x2x^2
1 0 xx x4x^4
2 1 x∘x4=x5x \circ x^4 = x^5 x8x^8
3 1 x5∘x8=x13x^5 \circ x^8 = x^{13} x16x^{16} (inutile)

Una precisazione sul conteggio. Le dispense affermano che POWER2/POWER3 eseguono esattamente le stesse applicazioni di ∘\circ di POWER. Contando letteralmente il codice di sopra, POWER3 ne esegue k+1+ν(n)=TPOWER(n)+2k + 1 + \nu(n) = T_{POWER}(n) + 2 (per n=13n = 13: 77 contro 55), per due ragioni: la prima moltiplicazione p∘sp \circ s con p=ep = e non produce niente di nuovo, e l'ultimo quadrato s∘ss \circ s calcola una potenza che non si usa. Con le due ottimizzazioni (partire da p←sp \leftarrow s al primo bit a 11, non quadrare dopo l'ultimo bit) i conteggi coincidono esattamente. Il confronto TPOWER3=TPOWER+2T_{POWER3} = T_{POWER} + 2 è stato controllato con un programma per nn da 22 a 50005000.

Verifica con un programma

python
def power_rec(n):                       # numero di applicazioni di o in POWER
    if n <= 1: return 0
    return power_rec(n // 2) + (1 if n % 2 == 0 else 2)

# per n = 1..5000: power_rec(n) == n.bit_length() - 1 + bin(n).count("1") - 1

Per ogni nn da 11 a 50005000 vale TPOWER(n)=⌊log⁡2n⌋+ν(n)−1T_{POWER}(n) = \lfloor \log_2 n \rfloor + \nu(n) - 1, il massimo su [2k,2k+1)[2^k, 2^{k+1}) è 2k2k e il minimo kk.

Esempio con matrici: numeri di Fibonacci

Con ∘\circ il prodotto di matrici 2×22 \times 2 e M=(1110)M = \begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix} si ha Mn=(Fn+1FnFnFn−1)M^n = \begin{pmatrix} F_{n+1} & F_n \\ F_n & F_{n-1} \end{pmatrix} (induzione: Mn+1=MnMM^{n+1} = M^n M). Per n=13n = 13: M→M2→M3→M6→M13M \to M^2 \to M^3 \to M^6 \to M^{13} con POWER, e M13=(377233233144)M^{13} = \begin{pmatrix} 377 & 233 \\ 233 & 144 \end{pmatrix}, quindi F13=233F_{13} = 233. Basta quindi Θ(log⁡n)\Theta(\log n) prodotti di matrici 2×22 \times 2 per calcolare FnF_n (confronta con la ricorsione e la memoizzazione in Programmazione dinamica - Fibonacci, memoizzazione e schema del paradigmala programmazione dinamica (DP) evolve il divide and conquer: invece di risolvere di nuovo le stesse sottoistanze, le salva in una tabella. Fibonacci ricorsivo costa F_n - 1 addizioni (esponenziale), quello con tabella n - 1. Tre condizioni: sottostruttura, sottoistanze ripetute, spazio dei sottoproblemi ristretto. Bottom-up o memoizzazione (ricorsione + tabella globale). Per i problemi di ottimizzazione lo schema è: sottostruttura ottima, ricorrenza sui costi, informazione addizionale, calcolo della tabella, ricostruzione.Programmazione dinamica - Fibonacci, memoizzazione e schema del paradigma →). Attenzione al modello di costo: FnF_n ha Θ(n)\Theta(n) cifre binarie, quindi le operazioni su scalari non sono più a costo unitario per nn grande. Lo stesso vale per matrici n×nn \times n qualsiasi: calcolare AmA^m richiede Θ(log⁡m)\Theta(\log m) prodotti di matrici, ciascuno da 2n3−n22n^3 - n^2 operazioni scalari con la definizione (Prodotto di matrici - algoritmo iterativo e ricorsivo a blocchimodello di costo sulle matrici n x n (operazioni tra scalari, taglia n oppure N = n^2); somma in n^2 operazioni (ottima); prodotto righe per colonne iterativo con costo esatto 2n^3 - n^2; proprietà frattale del prodotto a blocchi dimostrata sugli indici; algoritmo ricorsivo RMUL con T(n) = 8T(n/2) + n^2, Theta(n^3) e soluzione esatta 2n^3 - n^2 per induzione e per srotolamento: fa le stesse operazioni dell'iterativo.Prodotto di matrici - algoritmo iterativo e ricorsivo a blocchi →) o meno con Algoritmo di Strassen e ibridazioneStrassen calcola il prodotto n x n con 7 chiamate ricorsive invece di 8, usando 10 somme/sottrazioni nel divide e 8 nel conquer: T(n) = 7T(n/2) + (9/2)n^2, Theta(n^(log2 7)) con soluzione esatta 7n^(log2 7) - 6n^2; la costante 7 è più che tripla di quella dell'iterativo (2) e Strassen batte l'iterativo solo da n = 655 (per le potenze di 2, da 1024). L'ibridazione cambia il caso base (iterativo per n <= n0): costo n^(log2 7)(2n0+5)/n0^(log2 7 - 2) - 6n^2, minimo per n0 = 8 con costante ~3.92.Algoritmo di Strassen e ibridazione →; per matrici con struttura (circolanti) il prodotto è più economico (Matrici circolanti e supercircolanti - algoritmi divide and conquerle matrici supercircolanti (quadranti alternati ricorsivi) hanno solo n valori distinti: somma in n operazioni, prodotto in 4n log2 n + n con il trucco (A1+A2)(B1+B2) e (A1-A2)(B1-B2) invece delle 4 chiamate (Theta(n^2)); gli autovalori sono la trasformata di Hadamard della prima riga (FHT, n log2 n) e il prodotto passa dalla base diagonalizzante; le matrici circolanti sono polinomi nella matrice di rotazione R, il loro prodotto è la convoluzione ciclica delle prime righe e si diagonalizzano con la matrice di Fourier: prodotto in O(n log n) con la FFT.Matrici circolanti e supercircolanti - algoritmi divide and conquer →).

Esercizi collegati

Domande d'esame

  1. Quante applicazioni dell'operatore esegue POWER(x, 31)? Risposta: 31=11111231 = 11111_2, ⌊log⁡231⌋=4\lfloor \log_2 31 \rfloor = 4, ν=5\nu = 5: 4+5−1=84 + 5 - 1 = 8 (caso peggiore, 2⋅42 \cdot 4; STUPID_POWER ne fa 3030). Traccia: 31→15→7→3→131 \to 15 \to 7 \to 3 \to 1, i quattro livelli dispari costano 22 ciascuno.
  2. Quale ricorrenza regola POWER e qual è la sua complessità? Traccia: T(n)≤T(⌊n2⌋)+2T(n) \le T(\lfloor \frac n2 \rfloor) + 2, a=1a = 1, b=2b = 2, w=2w = 2, soglia n0=1n^0 = 1, caso 2 del Master Theorem: Θ(log⁡n)\Theta(\log n); esatto ⌊log⁡2n⌋+ν(n)−1\lfloor \log_2 n \rfloor + \nu(n) - 1.
  3. Quali proprietà dell'operatore servono? Traccia: solo associatività (e l'elemento neutro per x0x^0); non serve la commutatività, quindi vale per le matrici.

Versione ripasso

  • Setting: ∘\circ associativo con neutro ee (anche non commutativo, per esempio il prodotto di matrici con e=Ine = I_n); x0=ex^0 = e, xn=x∘xn−1=xn−1∘xx^n = x \circ x^{n-1} = x^{n-1} \circ x. Costo == numero di applicazioni di ∘\circ.
  • STUPID_POWER: p←xp \leftarrow x, poi n−1n - 1 volte p←x∘pp \leftarrow x \circ p: T=n−1=Θ(n)T = n - 1 = \Theta(n).
  • Sottostruttura: con k=⌊n2⌋k = \lfloor \frac n2 \rfloor, xn=xk∘xkx^n = x^k \circ x^k (nn pari) e xn=xk∘xk∘xx^n = x^k \circ x^k \circ x (nn dispari). Dimostrazione: xk+kx^{k+k} e xk+k+1x^{k+k+1}, raggruppando per associatività. Da y=xky = x^k: 11 applicazione (pari) o 22 (dispari).
  • POWER: base n=0n = 0 (ee) e n=1n = 1 (xx, evita due applicazioni inutili); divide 00; y←y \leftarrow POWER(x,k)(x, k); conquer y∘yy \circ y oppure y∘y∘xy \circ y \circ x.
  • Ricorrenza: T(n)≤T(⌊n2⌋)+2T(n) \le T(\lfloor \frac n2 \rfloor) + 2, T(0)=T(1)=0T(0) = T(1) = 0. a=1a = 1, b=2b = 2, w=2w = 2, soglia n0=1n^0 = 1: caso 2, Θ(log⁡n)\Theta(\log n) (Master Theorem - enunciato, casi e applicazioniMaster Theorem per T(n) = aT(n/b) + w(n): si confronta w(n) con la funzione soglia n^(log_b a). Caso 1 (w minore di una potenza polinomiale): Theta(n^(log_b a)); caso 2 (w della stessa taglia): Theta(n^(log_b a) log n); caso 3 (w maggiore e regolare): Theta(w(n)). Prova completa dai livelli dell'albero, versione estesa (parti intere, n0 qualsiasi), esempi, e l'uso scorretto quando nessun caso si applica (w = n log n).Master Theorem - enunciato, casi e applicazioni →); è la ricorrenza della ricerca binaria. Il limite 22 per livello è raggiunto da n=2t−1n = 2^t - 1 (tutte istanze dispari). Per n=2tn = 2^t: T=log⁡2nT = \log_2 n (formula generale con s=1s = 1, w=1w = 1).
  • Esatto: T(n)=⌊log⁡2n⌋+ν(n)−1T(n) = \lfloor \log_2 n \rfloor + \nu(n) - 1, con ν(n)\nu(n) numero di bit a 11.
    • Induzione: base n=1n = 1 dà 00.
    • Pari: T(n2)+1T(\frac n2) + 1, con ⌊log⁡2n2⌋=⌊log⁡2n⌋−1\lfloor \log_2 \frac n2 \rfloor = \lfloor \log_2 n \rfloor - 1 e ν(n2)=ν(n)\nu(\frac n2) = \nu(n).
    • Dispari: T(n−12)+2T(\frac{n-1}{2}) + 2, con ν(n−12)=ν(n)−1\nu(\frac{n-1}{2}) = \nu(n) - 1.
    • Quindi: ⌊log⁡2n⌋\lfloor \log_2 n \rfloor quadrature e ν(n)−1\nu(n) - 1 moltiplicazioni per xx. Minimo kk (n=2kn = 2^k), massimo 2k2k (n=2k+1−1n = 2^{k+1} - 1).
    • Esempio x13x^{13}: 13→6→3→113 \to 6 \to 3 \to 1, 2+1+2=52 + 1 + 2 = 5 operazioni (contro 1212). Esempio x31x^{31}: 4+5−1=84 + 5 - 1 = 8.
  • Iterativo: con n=bk…b0n = b_k \dots b_0 in binario, xn=∘bi=1 x2ix^n = \circ_{b_i = 1}\, x^{2^i} e x2i=x2i−1∘x2i−1x^{2^i} = x^{2^{i-1}} \circ x^{2^{i-1}}.
    • POWER2: p←ep \leftarrow e, s←xs \leftarrow x; per i=0..ki = 0..k: se bi=1b_i = 1 allora p←p∘sp \leftarrow p \circ s; poi s←s∘ss \leftarrow s \circ s.
    • Costo letterale k+1+ν(n)≤2(⌊log⁡2n⌋+1)k + 1 + \nu(n) \le 2(\lfloor \log_2 n \rfloor + 1), Θ(log⁡n)\Theta(\log n).
    • POWER3: i bit si ottengono con EVEN(m)(m) e m←⌊m2⌋m \leftarrow \lfloor \frac m2 \rfloor, con m=nm = n all'inizio.
    • Esempio 13=1101213 = 1101_2: pp vale x,x,x5,x13x, x, x^5, x^{13} e ss vale x2,x4,x8,x16x^2, x^4, x^8, x^{16}.
    • Il codice letterale fa 22 applicazioni in più di POWER (e∘se \circ s al primo bit a 11 e l'ultimo quadrato inutile); con p←sp \leftarrow s al primo bit a 11 e senza l'ultimo quadrato coincidono.
  • Fibonacci: M=(1110)M = \begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix}, Mn=(Fn+1FnFnFn−1)M^n = \begin{pmatrix} F_{n+1} & F_n \\ F_n & F_{n-1} \end{pmatrix}, FnF_n con Θ(log⁡n)\Theta(\log n) prodotti 2×22 \times 2 (M13M^{13} dà F13=233F_{13} = 233), purché si accetti il costo unitario sugli scalari.
  • Modello di costo: il costo unitario vale per somme e prodotti di interi o reali, non per operatori che ingrandiscono i risultati (unione di insiemi, prodotto di polinomi, interi lunghi, i numeri di Fibonacci grandi): serve un modello adeguato.
  • Errori tipici: usare il costo unitario con operandi che crescono; omettere il caso base n=1n = 1; contare log⁡2n\log_2 n invece dei ⌊log⁡2n⌋+1\lfloor \log_2 n \rfloor + 1 bit; pensare che serva la commutatività (basta l'associatività).

Esercizi su questo argomento

Teoria collegata