Skip to content

Commit 1f04c92

Browse files
[libc++] Fix sub-overflow in std::gcd implementation
Fix #117249
1 parent 2fe947b commit 1f04c92

File tree

1 file changed

+9
-13
lines changed

1 file changed

+9
-13
lines changed

libcxx/include/__numeric/gcd_lcm.h

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ template <class _Tp>
5555
constexpr _LIBCPP_HIDDEN _Tp __gcd(_Tp __a, _Tp __b) {
5656
static_assert(!is_signed<_Tp>::value, "");
5757

58-
// From: https://lemire.me/blog/2013/12/26/fastest-way-to-compute-the-greatest-common-divisor
58+
// From: https://lemire.me/blog/2024/04/13/greatest-common-divisor-the-extended-euclidean-algorithm-and-speed/
5959
//
6060
// If power of two divides both numbers, we can push it out.
6161
// - gcd( 2^x * a, 2^x * b) = 2^x * gcd(a, b)
@@ -76,21 +76,17 @@ constexpr _LIBCPP_HIDDEN _Tp __gcd(_Tp __a, _Tp __b) {
7676
if (__a == 0)
7777
return __b;
7878

79-
int __az = std::__countr_zero(__a);
80-
int __bz = std::__countr_zero(__b);
81-
int __shift = std::min(__az, __bz);
82-
__a >>= __az;
83-
__b >>= __bz;
79+
_Tp __c = __a | __b;
80+
int __shift = std::__countr_zero(__c);
81+
__a >>= std::__countr_zero(__a);
8482
do {
85-
_Tp __diff = __a - __b;
86-
if (__a > __b) {
87-
__a = __b;
88-
__b = __diff;
83+
_Tp __t = __b >> std::__countr_zero(__b);
84+
if (__a > __t) {
85+
__b = __a - __t;
86+
__a = __t;
8987
} else {
90-
__b = __b - __a;
88+
__b = __t - __a;
9189
}
92-
if (__diff != 0)
93-
__b >>= std::__countr_zero(__diff);
9490
} while (__b != 0);
9591
return __a << __shift;
9692
}

0 commit comments

Comments
 (0)