私は、ユークリッドのアルゴリズムを使用して 2 つの数値の GCD を計算する何かをいじっていました。いつものように標準のワンライナーを実装しましたが、うまくいきました。シリーズを計算し、要素が大きくなるにつれてgcd()
要素ごとに数回呼び出すアルゴリズムで使用されます。n
メモ化することでもっとうまくできるかどうかを確認することにしたので、試したのは次のとおりです。
size_t const gcd(size_t const a, size_t const b) {
return b == 0 ? a : gcd(b, a % b);
}
struct memoized_gcd : private std::unordered_map<unsigned long long, size_t> {
size_t const operator()(size_t const a, size_t const b) {
unsigned long long const key = (static_cast<unsigned long long>(a) << 32) | b;
if (find(key) == end()) (*this)[key] = b == 0 ? a : (*this)(b, a % b);
return (*this)[key];
}
};
//std::function<size_t (size_t, size_t)> gcd_impl = gcd<size_t,size_t>;
std::function<size_t (size_t, size_t)> gcd_impl = memoized_gcd();
std::function
後でインスタンスを介して、選択した関数を呼び出します。興味深いことに、たとえば n = 10,000 の場合、このコンピューターでは計算が 8 秒で実行され、メモ化されたバージョンでは 1 分近くかかり、他のすべては同じです。
明らかな何かを見逃しましたか?ハッシュマップkey
に特化する必要がないように、手段として使用しています。std::hash
私が考えることができる唯一のことは、メモ化されたバージョンがTCOを取得せず、取得するgcd()
か、ファンクターの呼び出しstd::function
が遅いか(両方で使用しているにもかかわらず)、またはおそらく私が遅れていることです。教祖よ、道を示してください。
ノート
g++ 4.7.0 を使用した win32 と win64、および g++ 4.6.1 と 4.7.1 を使用した Linux x86 でこれを試しました。
std::map<std::pair<size_t, size_t>, size_t>
また、メモ化されていないバージョンと同等のパフォーマンスを持つバージョンも試しました。