J'ai essayé d'implémenter l'algorithme de multiplication de Schönhage – Strassen, mais j'ai rencontré une pierre d'achoppement à l'étape récursive.
J'ai une valeur avec n bits et je veux calculer . Je pensais à l'origine que l'idée était de choisir un tel que , diviser en morceaux chacun avec bits, appliquer la convolution de SSA tout en travaillant modulo , un anneau avec bits de capacité par valeur, puis remontez les morceaux. Cependant, la sortie de la convolution a un peu plus de bits (c'est-à-direbits par valeur de sortie, ce qui est supérieur à la capacité de l'anneau, car chaque valeur de sortie étant une somme de plusieurs produits), cela ne fonctionne donc pas. J'ai dû ajouter un facteur supplémentaire de 2 de rembourrage.
Ce facteur supplémentaire de 2 dans le rembourrage ruine la complexité. Cela rend mon étape récursive trop chère. Au lieu d'un algorithme , je me retrouve avec un algorithme .
J'ai lu quelques références liées à partir de wikipedia, mais elles semblent toutes masquer les détails de la façon dont ce problème est résolu. Par exemple, je pourrais éviter la surcharge de remplissage supplémentaire en travaillant modulo pour un qui n'est pas une puissance de 2 ... mais alors les choses se cassent plus tard, quand je n'ai que de la non-puissance- de-2 facteurs restants et ne peuvent pas appliquer Cooley-Tukey sans doubler le nombre de pièces. De plus, peut ne pas avoir un modulo inverse multiplicatif . Il y a donc toujours des facteurs forcés de 2 introduits.
Comment choisir la bague à utiliser lors de l'étape récursive, sans souffler la complexité asymptotique?
Ou, sous forme de pseudo code:
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);
...