私はSchönhage–Strassen整数乗算アルゴリズムを実装しようとしましたが、再帰的なステップで障害にぶつかりました。
Iは、値有するとビットを、私は計算したい。私はもともとアイデアが選ぶことだと思ったように4 ^ K \ GEQ 2N、分割XにK ^ 2と各片2 ^ {K-1}ビットモジュロ作業中に、SSAの畳み込みを適用する2 ^ {2 ^ kは} +1、値ごとに2 ^ kビットの容量を持つリング。次に、ピースを元に戻します。ただし、たたみ込みの出力には2nビットより少し多い(つまり、> 2 ^ kK 4 、K ≥ 2 N X 2 、K 2 、K - 1 2 2 K + 1 2 K 2 N > 2 K出力値あたりのビット数。これは、各出力値がいくつかの積の合計であるため、リングの容量よりも大きいため、これは機能しません。私は2倍のパディングを追加する必要がありました。
パディングのその2の余分な要素は、複雑さを台無しにします。それは私の再帰的なステップを高すぎます。アルゴリズムの代わりに、アルゴリズム。
私はウィキペディアからリンクされているいくつかの参考文献を読みましたが、それらはすべて、この問題がどのように解決されるかについての詳細に光沢がないようです。たとえば、2の累乗ではないpに対してを法として処理することにより、余分なパディングオーバーヘッドを回避できますが、非累乗のみの場合、後でうまくいきません。 of-2要素が残り、ピースの数を2倍にしないとCooley-Tukeyを適用できません。また、pは2 ^ p + 1を法とする乗法逆行列を持たない場合があります。したがって、導入されている2の強制要因はまだあります。
漸近的な複雑さを吹き飛ばすことなく、再帰的なステップで使用するリングを選択するにはどうすればよいですか?
または、擬似コード形式で:
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);
...