Я намагався реалізувати алгоритм множення цілих чисел Шенгаге-Страссена, але потрапив на камеру спотикання на етапі рекурсивності.
Я маю цінність з біт, і я хочу обчислити . Спочатку я вважав, що ідея полягає в тому, щоб вибрати , щоб 4 ^ k \ geq 2n , розділили х на 2 ^ k шматки, кожен з 2 ^ {k-1} бітами, застосувавши згортку SSA під час роботи модуля 2 ^ {2 ^ k} +1 , кільце ємністю 2 ^ k на значення, а потім складіть шматки назад. Тим не менш, вихід згортки має трохи більше 2n біт (тобто > 2 ^ k біт на вихідне значення, що перевищує ємність кільця, оскільки кожне вихідне значення є сумою декількох продуктів), тому це не працює . Мені довелося додати додатковий коефіцієнт 2 прокладки.
Цей додатковий коефіцієнт 2 у прокладці руйнує складність. Це робить мій рекурсивний крок занадто дорогим. Замість алгоритму , я закінчую з алгоритмом .
Я прочитав кілька посилань, пов’язаних із вікіпедії, але всі вони, здається, змальовують деталі того, як вирішується це питання. Наприклад, я міг би уникнути додаткових накладних накладних витрат, працюючи за модулем для що не є потужністю 2 ... але потім речі просто ламаються пізніше, коли у мене є лише неенерго- Залишилося 2 чинника, і не можна застосувати Cooley-Tukey, не подвоївши кількість штук. Також може не мати мультипликативного зворотного модуля . Отже, все ще вводяться примусові фактори 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);
...