web-dev-qa-db-ja.com

2つの乱数を乗算するよりも数値を2乗する方が速いのはなぜですか?

2つの2進数の乗算にはn ^ 2時間かかりますが、数値の2乗は何らかの方法でより効率的に実行できます。 (nはビット数です)どうしてそうなるのでしょうか?

それとも不可能ですか?これは狂気です!

32
Jess
  1. 2つの数値を乗算するためにO(N ^ 2)よりも効率的なアルゴリズムが存在します(Karatsuba、Pollard、Schönhage–Strassenなどを参照)

  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))で実行できます。

積を計算する(または平方を表す)アルゴリズムは、同じ漸近コストで平方を計算する(積を表す)アルゴリズムを提供します。

他の回答で述べたように、高速乗算に使用されるアルゴリズムは、2乗の場合に簡略化できます。ゲインは、f(N)自体ではなく、f(N)の前の定数になります。

67
Eric Bainville

N桁の数を二乗することは、2つのランダムなn桁の数を乗算するよりも速い場合があります。私が見つけたグーグル この記事 。それは任意精度の算術についてですが、それはあなたの求めていることに関連しているかもしれません。その中で著者はこれを言います:

大きな整数、つまりX ^ 2 =(xn-1、xn-2、...、x1、x0)^ 2を二乗する場合、xi * xjおよびxj * xiの形式の多くの外積項は同等です。それらを2倍にするには、一度だけ計算してから左シフトする必要があります。 n桁の二乗演算は、(n ^ 2 + n)/ 2個の単精度乗算のみを使用して実行されます。

14

他の人が指摘しているように、二乗は任意の数の間の通常の乗算​​よりも約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の要素i=0, 1, ..., 4が対角線を形成し、それらを無視すると考えると、ui * ujの要素i ≠ jが2回繰り返されていることがわかります。

したがって、必要なのは、対角線より下の要素の積和を計算し、左シフトで2倍にすることだけです。最後に対角要素を追加します。これで、2倍のスピードアップがどこから来ているのかがわかります。実際には、対角線と余分な操作のために、スピードアップは約1.5倍です。

7
gkb0986

二乗による指数化 を参照していると思います。この手法は、乗算には使用されませんが、x ^ nの累乗に使用されます。ここで、nは大きくなる可能性があります。 x倍自体をN回乗算するのではなく、Nのバイナリ表現にマップできる一連の2乗および加算演算を実行します。乗算演算の数(多数の加算よりもコストがかかる)がNからに削減されます。素朴なべき乗アルゴリズムに関するlog(N)。

6
Jim Lewis

数値に2の累乗を掛けることを意味しますか?結果は単純なビットシフトで計算できるため、これは通常、任意の2つの乱数を乗算するよりも高速です。ただし、最新のマイクロプロセッサはこれらのタイプの計算に多くのブルートフォースシリコンを使用しており、ほとんどの演算は古いマイクロプロセッサと比較して目がくらむほどの速度で実行されることに注意してください。

4
Mike Thompson

私はそれを持ってます!

2 * 2

よりも高価です

2 << 1

(注意点は1つのケースでのみ機能します。)

3
fbrereto

乗算を拡張したいとします(a+b)×(c+d)。それは4つの個別の乗算に分割されます:a×c + a×d + b×c + b×d

しかし、拡張したい場合は(a+b)²の場合、3回の乗算(および2倍)のみが必要です。a² + 2ab + b²

(2つの乗算はそれ自体が正方形であることに注意してください。)

うまくいけば、これは通常の乗算​​で正方形を実行するときに可能なスピードアップのいくつかへの洞察を与え始めるだけです。

3
mwfearnley

まず第一に素晴らしい質問です!このような質問がもっとあったらいいのにと思います。

したがって、私が思いついた方法は、算術の複雑さのみにおける一般的な乗算のための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について、オーバーフローの大きさを決定し、それに応じて合計する必要があります。数値を2乗する場合、これはO(n log n)算術演算を意味します。

Schönhage–Strassenアルゴリズムを使用して、r_k値をより効率的に合計し、O(n log n log log n)ビット演算の範囲を取得できます。

あなたの質問に対する正確な答えは、EricBainvilleによってすでに投稿されています。

ただし、整数を乗算するためのより良い境界が存在するという理由だけで、数値を2乗するためにcanはO(n ^ 2)よりもはるかに良い境界を得ることができます!

1
ldog

マシンのワードサイズに固定長を想定し、2乗する数がメモリ内にある場合、2乗操作にはメモリからのロードが1回だけ必要なので、より高速になる可能性があります。

任意の長さの整数の場合、乗算は通常O(N²)ですが、大きな整数の場合はこれを減らすアルゴリズムがあります。

abを掛ける単純なO(N²)アプローチを想定した場合)、次にaの各ビットについて、bをシフトする必要があります。そのビットが1の場合は、アキュムレータに追加します。 aのビットごとに、3Nのシフトと追加が必要です。

ご了承ください

( x - y )² = x² - 2 xy + y²

したがって、

x² = ( x - y )² + 2 xy - y²

yがx以下の2の最大の累乗である場合、これにより、より低い正方形、2つのシフト、および2つの加算が減少します。 [〜#〜] n [〜#〜]は反復ごとに減少するため、効率が向上する可能性があります(対称性は各ポイントにアクセスすることを意味します)長方形ではなく三角形)ですが、それでもO(N²)です。

利用する別のより良い対称性があるかもしれません。

0
Pete Kirkham

数値のNビット乗算で問題を解決したい

AビットはA(n-1)A(n-2)........ A(1)A(0)です。

BビットはB(n-1)B(n-2)........ B(1)B(0)です。

数Aの二乗の場合、生成される一意の乗算ビットはA(0)-> A(0).... A(n-1)A(1)-> A(1).... A( n-1)など、合計操作は次のようになります。

OP = n + n-1 + n-2 ....... + 1したがって、OP = n ^ 2 + n/2;したがって、漸近表記はO(n ^ 2)になります。

aとBの乗算では、n ^ 2の一意の乗算が生成されるため、漸近表記はO(n ^ 2)になります。

0
Navjot Bansal

a ^ 2(a + b)*(a + b)+ b ^ 2例: 66 ^ 2 =(66 + 6)(66-6)+ 6 ^ 2 = 72 * 60 + 36 = 4356

a ^ nの場合は、べき乗則を使用します

66 ^ 4 = 4356 ^ 2

0
Sean Ashley