I was going with something that uses the Euclidean algorithm to calculate the GCD of two numbers. I, as usual, implemented a standard single-line liner, and it worked perfectly. It is used in an algorithm that calculates a series and calls gcd()
several times per element, as n
gets larger. I decided to see if I could do it better while retaining my memoirs, so here is what I tried:
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]; } };
I call the selected function through an instance of std::function
later. Interestingly, when, for example, n = 10000, the calculation is performed for 8 seconds on this computer, and with the version stored in memory it is close to the minute, all other things being equal.
Am I missing something obvious? I use key
as appropriate, so I don't need to specialize std::hash
for the hash map. The only thing I can think of is perhaps that the memoized version does not receive TCO and gcd()
, or that the call via std::function
slow for the functor (although I use it for both), or it is possible that I am set aside. Guru, show me the way.
Notes
I tried this on win32 and win64 with g ++ 4.7.0 and linux x86 with g ++ 4.6.1 and 4.7.1.
I also tried the version with std::map<std::pair<size_t, size_t>, size_t>
, which had comparable performance with the unmemoized version.