2つの2進数の乗算にはn^2の時間がかかりますが、数値の2乗はどういうわけかより効率的に行うことができます。(nはビット数です)どうしてそれができるでしょうか?
それとも不可能ですか?これは狂気です!
2つの2進数の乗算にはn^2の時間がかかりますが、数値の2乗はどういうわけかより効率的に行うことができます。(nはビット数です)どうしてそれができるでしょうか?
それとも不可能ですか?これは狂気です!
O(N^2) よりも効率的に 2 つの数値を乗算するアルゴリズムが存在します (カラツバ、ポラード、シェーンハーゲ シュトラッセンなどを参照)。
「2 つの任意の N ビット数を乗算する」と「任意の N ビット数を 2 乗する」という 2 つの問題は、同じ複雑さを持ちます。
我々は持っています
4*x*y = (x+y)^2 - (x-y)^2
したがって、N ビット整数の 2 乗に O(f(N)) 時間がかかる場合、2 つの任意の N ビット整数の積も O(f(N)) で取得できます。(つまり、2x N ビット合計、2x N ビット平方、1x 2N ビット合計、および 1x 2N ビット シフト)
そして明らかに私たちは持っています
x^2 = x * x
したがって、2 つの N ビット整数の乗算に O(f(N)) かかる場合、N ビット整数の 2 乗は O(f(N)) で実行できます。
積 (平方に対して) を計算するアルゴリズムは、同じ漸近コストで平方 (積に対して) を計算するアルゴリズムを提供します。
他の回答で述べたように、高速乗算に使用されるアルゴリズムは、二乗の場合に単純化できます。ゲインは、f(N) 自体ではなく、f(N) の前の定数になります。
n桁の数値を二乗する方が、2つのランダムなn桁の数値を乗算するよりも高速な場合があります。グーグル私はこの記事を見つけました。それは任意精度の算術についてですが、それはあなたの求めていることに関連しているかもしれません。その中で著者はこれを言います:
大きな整数、つまりX ^ 2 =(xn-1、xn-2、...、x1、x0)^ 2を二乗する場合、xi*xjおよびxj*xiの形式の多くの外積項は同等です。それらを2倍にするには、1回だけ計算してから、左にシフトする必要があります。n桁の二乗演算は、(n ^ 2 + n)/2個の単精度乗算のみを使用して実行されます。
他の人が指摘したように、二乗は、任意の数値間の通常の乗算よりも約 1.5 倍または 2 倍高速です。計算上の利点はどこから来るのですか? 対称性です。の二乗を計算して、1011
悪用できるパターンを見つけてみましょう。u0:u3
最上位から最下位までの数のビットを表します。
1011 // u3 * u0 : u3 * u1 : u3 * u2 : u3 * u3
1011 // u2 * u0 : u2 * u1 : u2 * u2 : u2 * u3
0000 // u1 * u0 : u1 * u1 : u1 * u2 : u1 * u3
1011 // u0 * u0 : u0 * u1 : u0 * u2 : u0 * u3
ui * ui
の要素を考慮して対角線を形成し、それらを無視すると、 の要素が 2 回繰り返されi=0, 1, ..., 4
ていることがわかります。ui * uj
i ≠ j
したがって、対角線より下の要素の積和を計算し、それを左シフトして 2 倍にするだけです。最後に対角要素を追加します。これで、2 倍の速度アップがどこから来たのかがわかります。実際には、対角線と余分な操作により、速度は約 1.5 倍になります。
二乗によるべき乗について言及している可能性があると思います。この手法は乗算には使用されませんが、n が大きくなる可能性がある x^n の累乗に使用されます。x 自体を N 回乗算するのではなく、N の 2 進数表現にマッピングできる一連の 2 乗および加算演算を実行します。乗算演算の数 (大きな数の加算よりもコストがかかります) は、N からlog(N) は、素朴なべき乗アルゴリズムに関するものです。
数値に 2 のべき乗を掛けることを意味しますか? 結果は単純なビット シフトで計算できるため、これは通常、任意の 2 つの乱数を乗算するよりも高速です。ただし、最新のマイクロプロセッサは、これらのタイプの計算に多くのブルート フォース シリコンを使用しており、ほとんどの演算は古いマイクロプロセッサに比べて目がくらむほどの速度で実行されることに注意してください。
私はそれを持ってます!
2 * 2
よりも高価です
2 << 1
(1 つのケースでしか機能しないことに注意してください。)
乗算を展開したいとします(a+b)×(c+d)
。これは、4 つの個別の乗算に分割されますa×c + a×d + b×c + b×d
。
しかし、 を展開したい場合は(a+b)²
、3 つの乗算 (および 2 倍) だけが必要ですa² + 2ab + b²
。
(2 つの乗算自体が平方であることに注意してください。)
願わくば、これが、通常の乗算よりも 2 乗を実行する場合に可能なスピードアップのいくつかについての洞察を与え始めることを願っています。
まず第一に素晴らしい質問です!このような質問がもっとあればいいのにと思います。
したがって、私が思いついた方法は、算術複雑さのみの一般的な乗算の O(n log n) であることがわかりました。任意の数 X を次のように表すことができます。
X = x_{n-1} 2^{n-1} + ... + x_1 2^1 + x_0 2^0
Y = y_{m-1} 2^{m-1} + ... + y_1 2^1 + y_0 2^0
どこ
x_i, y_i \in {0,1}
それから
XY = sum _ {k=0} ^ m+n r_k 2^k
どこ
r_k = sum _ {i=0} ^ k x_i y_{k-i}
これは、(n + m) log( n + m) 時間で各 k の r_k の値を見つけるための FFT の単純なアプリケーションです。
次に、各 r_k について、オーバーフローの大きさを判断し、それに応じて合計する必要があります。数値を二乗する場合、これは O(n log n)算術演算を意味します。
Schönhage-Strassen アルゴリズムを使用して r_k 値をより効率的に合計し、O(n log n log log n) ビット操作の範囲を取得できます。
あなたの質問に対する正確な回答は、すでに Eric Bainville によって投稿されています。
ただし、整数の乗算にははるかに優れた境界が存在するため、数値の 2 乗では O(n^2) よりもはるかに優れた境界を取得できます。
マシンのワード サイズが固定長であり、2 乗する数値がメモリ内にあると仮定すると、2 乗演算はメモリから 1 回の読み込みで済むため、高速になる可能性があります。
任意の長さの整数の場合、乗算は通常 O(N²) ですが、大きな整数の場合はこれを減らすアルゴリズムがあります。
aをbで乗算する単純な O(N²) アプローチを想定する場合、 aの各ビットに対して、bをシフトし、そのビットが 1 の場合はアキュムレータに追加する必要があります。a のビットごとに、 3N 回のシフトと追加が必要です。
ご了承ください
( x - y )² = x² - 2 xy + y²
したがって
x² = ( x - y )² + 2 xy - y²
各yが x よりも大きくない最大の 2 のべき乗である場合、これにより、下の 2 乗、2 つのシフト、および 2 つの加算が得られます。各反復でNが減少すると、効率が向上する可能性があります (対称性は、長方形ではなく三角形の各点を訪問することを意味します) が、それでも O(N²) です。
利用する別のより良い対称性があるかもしれません。
2 進数 A を持っている場合、それは (熱心な読者に証明を残します) として (2^n + B) として表すことができます。これは 2^2n + 2^(n+1)B + B として 2 乗できます。 ^2. 次に、B がゼロに等しくなるような点まで展開を繰り返すことができます。私はあまり詳しく見ていませんが、直感的には、2 乗関数を汎用の乗算よりもアルゴリズムのステップを少なくすることができるはずだと感じています。
2 nの平方根は 2 n / 2または 2 n >> 1であるため、数値が 2 の累乗である場合、累乗がわかればすべてが完全に単純になります。乗算はさらに簡単です: 2 4 * 2 8は 2 4+8です。あなたが行ったこの声明には意味がありません。
あなたの発言は完全に間違っていると思います
2 つの 2 進数の乗算には n^2 の時間がかかります
2 つの 32 ビット数の乗算には、正確に 1 クロック サイクルかかります。64 ビット プロセッサでは、2 つの 64 ビット数を乗算するには、正確に 1 クロック サイクルかかると想定します。32 ビット プロセッサが 1 クロック サイクルで 2 つの 64 ビット数を乗算できることは、私にとって驚くべきことではありません。
yet squaring a number can be done more efficiently somehow.
数を 2 乗することは、その数をそれ自体で乗算するだけなので、単純な乗算にすぎません。CPUには「二乗」演算はありません。
「二乗」と「2 のべき乗」を混同している可能性があります。2 の乗算は、すべてのビットを 1 桁分「左」にシフトすることで実装できます。4 を掛けると、すべてのビットが 2 桁分「左」にシフトします。8で、3ポジション。しかし、このトリックは 2 の累乗にしか適用できません。