[libcxx-commits] [libcxx] [libc++] Implement std::gcd using the binary version (PR #77747)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed Apr 24 14:37:54 PDT 2024


================
@@ -50,9 +52,25 @@ struct __ct_abs<_Result, _Source, false> {
 };
 
 template <class _Tp>
-_LIBCPP_CONSTEXPR _LIBCPP_HIDDEN _Tp __gcd(_Tp __m, _Tp __n) {
+_LIBCPP_CONSTEXPR _LIBCPP_HIDDEN _Tp __gcd(_Tp __a, _Tp __b) {
   static_assert((!is_signed<_Tp>::value), "");
-  return __n == 0 ? __m : std::__gcd<_Tp>(__n, __m % __n);
+  if (__a == 0)
+    return __b;
+  if (__b == 0)
+    return __a;
+
+  int __az    = std::__countr_zero(__a);
+  int __bz    = std::__countr_zero(__b);
+  int __shift = std::min(__az, __bz);
+  __b >>= __bz;
+  while (__a != 0) {
+    __a >>= __az;
+    _Tp __absdiff = __a > __b ? __a - __b : __b - __a;
+    __b           = std::min(__a, __b);
+    __a           = __absdiff;
+    __az          = std::__countr_zero(__absdiff);
+  }
+  return __b << __shift;
----------------
AdvenamTacet wrote:

I would be happy, if that information is included:
```
If power of two divides both numbers, we can push it out.
- gcd( 2^x * a, 2^x * b) = 2^x * gcd(a, b)

If and only if exactly one number is even, we can divide that number by  that power. 
- if a, b are odd, then gcd(2^x * a, b) = gcd(a, b)

And standard gcd algorithm where instead of modulo, minus is used.
```

https://github.com/llvm/llvm-project/pull/77747


More information about the libcxx-commits mailing list