Moltiplicazione in


10

Stavo guardando qui e ho notato che il miglior runtime per la moltiplicazione di due numeri -bit è O ( n log n 2 O ( log n ) , ma posso facilmente notare un algoritmo che gira in O ( n registro n ) .nO(nlogn2O(logn)O(nlogn)

Dopotutto, sappiamo come moltiplicare due polinomi dal grado in runtime O ( n log n ) . Ma moltiplicando polinomi è lo stesso di moltiplicare due n numeri -bits. Così abbiamo un algoritmo per moltiplicare due n numeri -bits a O ( n registriamo n ) . Ora l'unico problema che potrebbe verificarsi è il carry, ma in ogni fase possiamo risolverlo nel tempo O ( n ) , spostandoci semplicemente sul bit più a destra e sul suo vicino di sinistra, fino alla fine. Cioè, il nostro tempo di esecuzione deve rimanere O ( n log nnO(nlogn)nnO(nlogn)O(n) .O(nlogn)

Quindi ho fatto una nuova (e abbastanza ovvia) scoperta? O la pagina di Wikipedia non è aggiornata? O forse ho qualche errore?


In che modo "sappiamo" "moltiplicare due polinomi dal grado in runtime O ( n log n ) "?nO(nlogn)

Risposte:


8

Come già sottolineato da @DavidRicherby, la confusione sorge perché diverse misure di complessità si stanno confondendo. Ma lasciami elaborare un po '.

Di solito, quando si studiano algoritmi per la moltiplicazione polinomiale su anelli arbitrari, si è interessati al numero di operazioni aritmetiche nell'anello utilizzate da un algoritmo. In particolare, dati alcuni anello (commutativo, unitario) e due polinomi f , g R [ X ] di grado inferiore a n , l'algoritmo di Schönhage-Strassen necessita di moltiplicazioni O ( n log n log log n ) e aggiunte in R per calcolare f g R [ X ]Rf,gR[X]nO(nlognloglogn)RfgR[X]da, approssimativamente, adiacente -esimo radici primitive di unità di R per ottenere qualche grande anello D R e quindi, mediante la trasformata di Fourier su D , calcolando il prodotto D .nRDRDD

Se l'anello contiene un radice -esimo di unità, allora questo può essere accelerato a O ( n log n ) operazioni in R utilizzando Fast Fourier Transform direttamente sopra R . Più specificamente, su ZC , puoi farlo usando le operazioni dell'anello O ( n log n ) (ignorando il fatto che ciò richiederebbe un'aritmetica esatta sui numeri complessi).nO(nlogn)RRZCO(nlogn)

L'altra misura che può essere presa in considerazione è la complessità dei bit di un'operazione. E questo è ciò che ci interessa quando si moltiplicano due numeri interi di lunghezza bit . Qui, le operazioni primitive si stanno moltiplicando e aggiungendo due cifre (con carry). Quindi, quando si moltiplicano due polinomi su Z , in realtà è necessario tenere conto del fatto che i numeri che sorgono durante il calcolo non possono essere moltiplicati utilizzando un numero costante di operazioni primitive. Questo e il fatto che Z non abbia una n -esima radice primitiva di unità per n > 2 ti impedisce di applicare O ( n log n )nZZnn>2O(nlogn)algoritmo. Superare questo considerando con coefficienti dall'anello Z /2 n + 1 , dato che i coefficienti del polinomio prodotto non supererà questo vincolato. Lì (quando n è una potenza di due), hai (la classe di congruenza di) 2 come n -esima radice di unità, e chiamando ricorsivamente l'algoritmo per le moltiplicazioni dei coefficienti, puoi ottenere un totale di O ( n log n log log n ) operazioni primitive (cioè bit). Questo quindi passa alla moltiplicazione dei numeri interi.f,gZ/2n+1n2nO(nlognloglogn)

Per un esempio che evidenzi bene l'importanza della differenza tra operazioni ad anello e operazioni primitive, considera due metodi per valutare i polinomi: il metodo di Horner e il metodo di Estrin. Il metodo di Horner valuta un polinomio ad alcuni x Z sfruttando l'identità f ( x ) = ( ( f n x + f n - 1 ) x + + ) +f=i=0nfiXixZ mentre il metodo di Estrin divide f in due parti H = n / 2 i = 1 f n / 2 + i X i e L = n / 2 i = 0 f i X i cioè, H contiene i termini del grado > n / 2 e L i termini di gradon / 2 (assumere n

f(x)=((fnx+fn1)x++)+f0
f
H=i=1n/2fn/2+iXi
L=i=0n/2fiXi
H>n/2Ln/2n è un potere di due, per semplicità).

Quindi, possiamo calcolare usando f ( x ) = H ( x ) x n / 2 + L ( x ) e applicando l'algoritmo in modo ricorsivo.f(x)

f(x)=H(x)xn/2+L(x)

Il primo, usando addizioni e moltiplicazioni, si è dimostrato ottimale rispetto al numero di addizioni e moltiplicazioni (ovvero operazioni ad anello), il secondo ha bisogno di più (almeno n + log n ).nn+logn

n/2n/2Ω(n2)nO(n)O(nlogcn)=O~(n)c>0


9

nO(nlogn)nO(2lognnlogn)nO(nlogn)


5
Non penso che questo sia il problema. Se pensiamo numeri come polinomi i cui "x" è la base, ad esempio 2, quindi tipicamente si può moltiplicare gradi da zero polinomi (numeri più piccoli rispetto alla base) nel tempo costante. Immagino che il problema sia che l'algoritmo O (n * log n) utilizza FFT e all'interno dell'algoritmo FFT potrebbero emergere numeri asintoticamente più grandi.
jkff,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.