Techioz Blog

バイナリ 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 つの理由が重なっているのではないかと考えています。