バイナリ GCD アルゴリズムが非常に遅いのはなぜですか?
概要
http://en.wikipedia.org/wiki/Binary_GCD_algorithm
Wikipedia によると、Euclid のアルゴリズムよりもわずかに高速であるとされています (それほどではありませんが、少なくとも同等のパフォーマンスが得られると期待していました)。私の場合、それは一桁遅いです。理由を理解するのを手伝っていただけますか?
Rubyで実装してみました。最初に再帰的ソリューションを使用しました
def gcd_recursive(u, v)
return u|v if u==0 or v==0
if u.even?
if v.even?
return gcd(u>>1, v>>1)<<1
else
return gcd(u>>1, v) if v.odd?
end
elsif u.odd? and v.even?
return gcd(u, v>>1)
else
if u < v
u, v = v, u
end
return gcd((u-v)>>1, v)
end
end
それはあまりうまく機能しなかったので、ループにするとどのくらい速くなるかを確認したかったのです
def gcd(u, v)
return u|v if u==0 or v==0
shift=0
while ((u|v)&1)==0 do
u=u >> 1;
v=v >> 1;
shift += 1
end
while ((u&1) == 0) do
u=u >> 1
end
begin
while ((v & 1) == 0) do
v=v >> 1
end
if u < v
v -= u
else
diff = u - v
u = v
v = diff
end
end while v != 0
u<<shift
end
これらはベンチマーク結果です
user system total real
std 0.300000 0.000000 0.300000 ( 0.313091)
rbn 0.850000 0.000000 0.850000 ( 0.872319)
bin 2.730000 0.000000 2.730000 ( 2.782937)
rec 3.070000 0.000000 3.070000 ( 3.136301)
std はネイティブの Ruby 1.9.3 C 実装です。
rbn は基本的に同じもの (Euclid のアルゴリズム) ですが、Ruby で書かれています。
bin は上記のループ コードです。
rec は再帰バージョンです。
編集: matz の Ruby 1.9.3 でベンチマークを実行しました。 Rubinius で同じテストを実行してみました。結果は次のとおりです。これも紛らわしいですね…
rbn 1.268079 0.024001 1.292080 ( 1.585107)
bin 1.300082 0.000000 1.300082 ( 1.775378)
rec 1.396087 0.000000 1.396087 ( 2.348785)
解決策
これは単なる推測ですが、次の 2 つの理由が重なっているのではないかと考えています。