These are probably going to end up in C++17 as well.
This is a straight addition; no changes to existing code.
Differential D21343
Implement `lcm` and `gcd` from library fundamentals V2 mclow.lists on Jun 14 2016, 2:04 PM. Authored by
Details
These are probably going to end up in C++17 as well. This is a straight addition; no changes to existing code.
Diff Detail Event TimelineComment Actions I created a top-level gcd which did nothing but make everything unsigned and do the abs once, and then called a __gcd specialized for unsigned and only one kind of unsigned, and got measurably faster results (about 10%). template<class _Tp> constexpr std::enable_if_t<is_unsigned<_Tp>{}, _Tp> _LIBCPP_INLINE_VISIBILITY __gcd(_Tp __m, _Tp __n) { return __n == 0 ? __m : __gcd(__n, __m % __n); } template<class _Tp, class _Up> constexpr common_type_t<_Tp,_Up> _LIBCPP_INLINE_VISIBILITY gcd(_Tp __m, _Up __n) { static_assert((is_integral<_Tp>::value && is_integral<_Up>::value), "Arguments to gcd must be integer types"); using _Rp = common_type_t<_Tp,_Up>; using _Wp = make_unsigned_t<_Rp>; return static_cast<_Rp>(__gcd(static_cast<_Wp>(__abs<_Tp>()(__m)), static_cast<_Wp>(__abs<_Up>()(__n)))); } Here is the test driver I used: #include <chrono> #include <iostream> int main() { std::uint64_t x = 0; auto t0 = std::chrono::steady_clock::now(); for (auto i = 1'999'990'000; i <= 2'000'000'000; ++i) { for (auto j = 1'999'990'000; j <= 2'000'000'000; ++j) { x += gcd(i, j); } } auto t1 = std::chrono::steady_clock::now(); std::cout << std::chrono::duration<double>(t1-t0).count() << '\n'; return x; } I also tried the traditional iterative solution (as opposed to recursive) and was surprised that it was not faster. I then tried "binary" gcd (https://en.wikipedia.org/wiki/Binary_GCD_algorithm) and was again surprised it wasn't faster. Both of these alternatives were in the ball park though, and it could be that they might measure faster over other domains. The binary variant used __m >>= std::__ctz(__m); instead of a while loop to remove factors of 2 (in two places).
Comment Actions Gosh darn it Howard. Your like 10 minutes ahead of me. Here is a constexpr gcd test.
Comment Actions Updated based on comments here and elsewhere.
Also, add an assertion to detect overflow in lcm. I have not yet incorporated Eric's constexpr tests. Comment Actions Updated with Eric's constexpr tests. |
This should be _LIBCPP_BEGIN_NAMESPACE_LFTS.