aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/include/std/numeric
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/include/std/numeric')
-rw-r--r--libstdc++-v3/include/std/numeric34
1 files changed, 30 insertions, 4 deletions
diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric
index bd70a52..2de6aaf 100644
--- a/libstdc++-v3/include/std/numeric
+++ b/libstdc++-v3/include/std/numeric
@@ -76,6 +76,7 @@
#if __cplusplus >= 201402L
#include <type_traits>
+#include <bit>
namespace std _GLIBCXX_VISIBILITY(default)
{
@@ -97,15 +98,40 @@ namespace __detail
template<typename _Up> void __absu(bool) = delete;
- // GCD implementation
+ // GCD implementation, using Stein's algorithm
template<typename _Tp>
constexpr _Tp
__gcd(_Tp __m, _Tp __n)
{
static_assert(is_unsigned<_Tp>::value, "type must be unsigned");
- return __m == 0 ? __n
- : __n == 0 ? __m
- : __detail::__gcd(__n, _Tp(__m % __n));
+
+ if (__m == 0)
+ return __n;
+ if (__n == 0)
+ return __m;
+
+ const int __i = std::__countr_zero(__m);
+ __m >>= __i;
+ const int __j = std::__countr_zero(__n);
+ __n >>= __j;
+ const int __k = __i < __j ? __i : __j; // min(i, j)
+
+ while (true)
+ {
+ if (__m > __n)
+ {
+ _Tp __tmp = __m;
+ __m = __n;
+ __n = __tmp;
+ }
+
+ __n -= __m;
+
+ if (__n == 0)
+ return __m << __k;
+
+ __n >>= std::__countr_zero(__n);
+ }
}
// LCM implementation