Schönhage – Strassen tamsayı çarpma algoritmasını uygulamaya çalışıyorum, ancak yinelemeli adımda bir tökezleyen bloğa çarptı.
Benim bir değerim var ile bit ve hesaplamak istiyorum . Başlangıçta fikir almaya olduğunu düşündüm k öyle ki 4 ^ k \ geq 2n , split x içine k ^ 2 ile her adet 2 ^ {k-1} bit modül çalışırken, SSA en konvolüsyonunu uygulamak 2 ^ {2 ^ k} +1 , değer başına 2 ^ k bit kapasiteli bir halka , daha sonra parçaları tekrar bir araya getirin. Bununla birlikte, evrişim çıkışı 2n bitten biraz daha fazladır (yani > 2 ^ kHer çıkış değerinin birkaç ürünün toplamı olması nedeniyle halkanın kapasitesinden daha fazla olan çıkış değeri başına bit sayısı), bu işe yaramaz. Ben 2 dolgu ekstra bir faktör eklemek zorunda kaldı.
Dolgudaki 2 ekstra faktör karmaşıklığı bozar. Yinelemeli adımımı çok pahalı yapıyor. Bunun yerine, bir algoritması, bir sona bir algoritması ile.
Vikipedi ile bağlantılı birkaç referans okudum, ancak hepsi bu sorunun nasıl çözüldüğüne dair ayrıntılar üzerinde parlak görünüyor. Örneğin, 2 gücü olmayan bir p için modulo 2 ^ {p 2 ^ k} + 1 çalıştırarak ekstra dolgu yükünü önleyebilirim ... ama sonra sadece güç olmayan- -2 faktör kaldı ve parça sayısını iki katına çıkarmadan Cooley-Tukey'i uygulayamaz. Ayrıca, p çarpımsal bir ters modülo 2 ^ p + l'e sahip olmayabilir . Yani hala zorla kabul edilen 2 faktör var.
Asimptotik karmaşıklığı üflemeden özyinelemeli adımda kullanılacak halkayı nasıl seçerim?
Veya sözde kod biçiminde:
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);
...