等間隔の3つを見つけることに関する最近のパズルブログの投稿で、私はO(n lg n)時間内にそれを行うと主張するトップアンサーを持つstackoverflowの質問に導かれました。興味深い部分は、解が多項式の2乗を伴い、O(n lg n)時間でそれを行う方法を説明する論文を参照することです。
現在、多項式の乗算は、数値の乗算と実質的に同じです。唯一の本当の違いは、キャリーがないことです。しかし...キャリーはO(n lg n)時間で行うこともできます。例えば:
var value = 100; // = 0b1100100
var inputBitCount = value.BitCount(); // 7 (because 2^7 > 100 >= 2^6)
var n = inputBitCount * 2; // 14
var lgn = n.BitCount(); // 4 (because 2^4 > 14 => 2^3)
var c = lgn + 1; //5; enough space for 2n carries without overflowing
// do apparently O(n log n) polynomial multiplication
var p = ToPolynomialWhereBitsAreCoefficients(value); // x^6 + x^5 + x^2
var p2 = SquarePolynomialInNLogNUsingFFT(p); // x^12 + 2x^11 + 2x^10 + x^8 + 2x^7 + x^4
var s = CoefficientsOfPolynomial(p2); // [0,0,0,0,1,0,0,2,1,0,2,2,1]
// note: s takes O(n lg n) space to store (each value requires at most c-1 bits)
// propagate carries in O(n c) = O(n lg n) time
for (var i = 0; i < n; i++)
for (var j = 1; j < c; j++)
if (s[i].Bit(j))
s[i + j].IncrementInPlace();
// extract bits of result (in little endian order)
var r = new bool[n];
for (var i = 0; i < n; i++)
r[i] = s[i].Bit(0);
// r encodes 0b10011100010000 = 10000
だから私の質問はこれです:ここで間違いはどこですか?O(n lg n)での数値の乗算は、コンピューターサイエンスの巨大な未解決の問題であり、この単純な答えは本当に疑わしいです。
- 持ち運びは間違っていますか、それともO(n lg n)ではありませんか?キャリーを追跡するには、値ごとにlg n + 1ビットで十分であり、アルゴリズムが非常に単純であるため、間違っていた場合は驚くでしょう。個々の増分にはO(lg n)時間かかることがありますが、x増分の総コストはO(x)であることに注意してください。
- 論文の多項式乗算アルゴリズムは間違っていますか、または違反している条件がありますか?この論文では、数論的変換ではなく高速フーリエ変換を使用していますが、これは問題になる可能性があります。
- 賢い人の多くは、シェーンハーゲ–ストラッセンアルゴリズムの明らかなバリエーションを40年間見逃していませんか?これははるかに少ないようです。
効率的な多項式乗算を除いて、実際にこれを実装するコードを作成しました(数論変換はまだ十分に理解されていません)。ランダムテストはアルゴリズムが正しいことを確認しているように見えるため、問題は時間の複雑さの分析にある可能性があります。
この例を手作業で行いました。算術ミスをしました。ごめんなさい。ただし、実際にアルゴリズムを実装してテストし、正しい結果を得ました。
—
クレイグギドニー
x^10 + 2x^8
か?x ^ 10は1回のみ(x ^ 5 * x ^ 5)、x ^ 8は2回(x ^ 6 * x ^ 2 + x ^ 2 * x ^ 6)