Ich habe versucht, den Ganzzahl-Multiplikationsalgorithmus Schönhage-Strassen zu implementieren, bin aber im rekursiven Schritt auf einen Stolperstein gestoßen.
Ich habe einen Wert mit n Bits und möchte x 2 berechnen . Ich dachte ursprünglich, die Idee wäre, ein k sozu wählen,dass 4 k ≥ 2 n , x in 2 k Stücke mit jeweils 2 k - 1 Bit aufgeteilt wird, die SSA-Faltung anwenden, während modulo 2 2 k + 1 , ein Ring mit 2 k Bit, arbeitet Kapazität pro Wert, dann setzen Sie die Teile wieder zusammen. Die Ausgabe der Faltung hat jedoch etwas mehr als 2 n Bits (dh > 2 kBits pro Ausgabewert, was mehr als die Kapazität des Rings ist, da jeder Ausgabewert eine Summe mehrerer Produkte ist. Dies funktioniert also nicht. Ich musste einen zusätzlichen Faktor von 2 Polsterung hinzufügen.
Dieser zusätzliche Faktor 2 in der Polsterung ruiniert die Komplexität. Das macht meinen rekursiven Schritt zu teuer. Anstelle eines Algorithmus, ich erhalte ein F ( n ) = n lg n + √Algorithmus.
Ich habe ein paar Referenzen gelesen, die aus Wikipedia verlinkt sind, aber alle scheinen die Details zu beschönigen, wie dieses Problem gelöst wird. Zum Beispiel könnte ich den zusätzlichen Auffüllaufwand vermeiden, indem ich Modulo für ein p arbeite , das keine Potenz von 2 ist ... aber dann brechen die Dinge erst später ab, wenn ich nur Faktoren habe, die keine Potenz von 2 sind verbleibend und kann Cooley-Tukey nicht anwenden, ohne die Anzahl der Stücke zu verdoppeln. Außerdem darf p kein multiplikatives inverses Modulo 2 p + 1 haben . Es werden also immer noch erzwungene Faktoren von 2 eingeführt.
Wie wähle ich den Ring aus, der während des rekursiven Schritts verwendet werden soll, ohne die asymptotische Komplexität zu beeinträchtigen?
Oder in Pseudocodeform:
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);
...