Próbowałem zaimplementować algorytm mnożenia liczb całkowitych Schönhage-Strassen, ale natknąłem się na przeszkodę w kroku rekurencyjnym.
I mają wartość o bitów i Aby obliczyć . Początkowo myślałem, że pomysł takiego, że , podziel na kawałki każdy za pomocą bitów, zastosuj splot SSA podczas pracy modulo , pierścień z bitami pojemności na wartość, a następnie złóż kawałki z powrotem. Jednak wyjście splotu ma nieco więcej niż bitów (tj.bitów na wartość wyjściową, która jest większa niż pojemność pierścienia, ponieważ każda wartość wyjściowa jest sumą kilku produktów), więc to nie działa. Musiałem dodać dodatkowy współczynnik 2 wypełnień.
Ten dodatkowy współczynnik 2 w wypełnieniu psuje złożoność. To sprawia, że mój krok rekurencyjny jest zbyt drogi. Zamiast algorytmu kończę z algorytmem F (n) = n \ lg n + \ sqrt {n} F (4 \ sqrt {n}) = \ Theta (n \ lg ^ 2 n) .
Przeczytałem kilka odnośników z wikipedii, ale wszystkie wydają się rozmyślać o szczegółach rozwiązania tego problemu. Na przykład, mógłbym uniknąć dodatkowego narzutu, pracując modulo dla który nie jest potęgą 2 ... ale potem wszystko się psuje później, kiedy mam tylko brak mocy z 2 pozostałych czynników i nie można zastosować Cooleya-Tukeya bez podwojenia liczby elementów. Ponadto może nie mieć multiplikatywnego odwrotnego modułu . Wciąż wprowadzane są czynniki wymuszone 2.
Jak wybrać pierścień do użycia podczas etapu rekurencyjnego, nie powodując asymptotycznej złożoności?
Lub w formie pseudokodu:
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);
...