Eu tenho tentado implementar o algoritmo de multiplicação de números inteiros Schönhage-Strassen, mas atingi um obstáculo na etapa recursiva.
Eu tenho um valor com bits e quero calcular x ^ 2 \ pmod {2 ^ n + 1} . Eu originalmente pensei que a idéia era escolher um k tal que 4 ^ k \ geq 2n , dividir x em 2 ^ k pedaços cada um com 2 ^ {k-1} bits, aplicar a convolução da SSA enquanto trabalhava no módulo 2 ^ {2 ^ k} +1 , um anel com 2 ^ k bits de capacidade por valor e, em seguida, reinstale as peças. No entanto, a saída da convolução tem um pouco mais de 2n bits (ou seja, > 2 ^ kn x 2kbits por valor de saída, que é mais do que a capacidade do anel, devido a cada valor de saída ser uma soma de vários produtos) para que isso não funcione. Eu tive que adicionar um fator extra de 2 de preenchimento.
Esse fator extra de 2 no preenchimento arruina a complexidade. Isso torna meu passo recursivo muito caro. Em vez de um , acabo com um algoritmo .
Li algumas referências vinculadas da wikipedia, mas todas parecem encobrir os detalhes de como esse problema foi resolvido. Por exemplo, eu poderia evitar a sobrecarga do preenchimento extra trabalhando no módulo para um que não é uma potência de 2 ... mas depois as coisas quebram mais tarde, quando eu tenho apenas de-2 fatores restantes e não pode aplicar o Cooley-Tukey sem dobrar o número de peças. Além disso, pode não ter um módulo inverso multiplicativo . Portanto, ainda há fatores forçados de 2 sendo introduzidos.
Como escolho o anel para usar durante a etapa recursiva, sem soprar a complexidade assintótica?
Ou, na forma de pseudo-código:
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);
...