我正在玩弄一些使用欧几里得算法来计算两个数字的 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 秒,而使用记忆的版本接近一分钟,其他一切都相同。
我错过了什么明显的东西吗?我将key
其用作权宜之计,因此我不需要专门std::hash
研究哈希图。我唯一能想到的可能是 memoized 版本没有获得 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>
未记忆版本具有可比性能的版本。