Ho cercato di implementare l'algoritmo di moltiplicazione di interi Schönhage-Strassen, ma ho colpito un ostacolo nel passaggio ricorsivo.
Ho un valore con bit e voglio calcolare x ^ 2 \ pmod {2 ^ n + 1} . Inizialmente pensavo che l'idea fosse quella di scegliere un k tale che 4 ^ k \ geq 2n , dividere x in 2 ^ k pezzi ciascuno con 2 ^ {k-1} bit, applicare la convoluzione di SSA mentre si lavora modulo 2 ^ {2 ^ k} +1 , un anello con 2 ^ k bit di capacità per valore, quindi rimettere insieme i pezzi. Tuttavia, l'output della convoluzione ha poco più di 2n bit (ovvero > 2 ^ knbit per valore di uscita, che è superiore alla capacità dell'anello, poiché ciascun valore di uscita è una somma di più prodotti), quindi non funziona. Ho dovuto aggiungere un ulteriore fattore di 2 di imbottitura.
Quel fattore aggiuntivo di 2 nell'imbottitura rovina la complessità. Rende il mio passaggio ricorsivo troppo costoso. Invece di un algoritmo , finisco con un algoritmo .
Ho letto alcuni riferimenti collegati da Wikipedia, ma tutti sembrano sorvolare i dettagli di come questo problema è stato risolto. Ad esempio, potrei evitare il sovraccarico di imbottitura extra lavorando modulo per una che non è una potenza di 2 ... ma poi le cose si rompono più tardi, quando ho solo non-power- di 2 fattori rimanenti e non è possibile applicare Cooley-Tukey senza raddoppiare il numero di pezzi. Inoltre, potrebbe non avere un modulo moltiplicativo inverso . Quindi ci sono ancora fattori forzati per l'introduzione di 2.
Come scelgo l'anello da usare durante la fase ricorsiva, senza soffiare sulla complessità asintotica?
Oppure, in forma di pseudo codice:
multiply_in_ring(a, b, n):
...
// vvv vvv //
// vvv HOW DOES THIS PART WORK? vvv //
// vvv vvv //
let inner_ring = convolution_ring_for_values_of_size(n);
// ^^^ ^^^ //
// ^^^ HOW DOES THIS PART WORK? ^^^ //
// ^^^ ^^^ //
let input_bits_per_piece = ceil(n / inner_ring.order);
let piecesA = a.splitIntoNPiecesOfSize(inner_ring.order, input_bits_per_piece);
let piecesB = b.splitIntoNPiecesOfSize(inner_ring.order, input_bits_per_piece);
let piecesC = inner_ring.negacyclic_convolution(piecesA, piecesB);
...