Skip to content

Commit c6bd27c

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

File tree

1 file changed

+8
-13
lines changed

1 file changed

+8
-13
lines changed

libcxx/include/__numeric/gcd_lcm.h

Lines changed: 8 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,16 @@ 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+
int __shift = std::__countr_zero(__a | __b);
80+
__a >>= std::__countr_zero(__a);
8481
do {
85-
_Tp __diff = __a - __b;
86-
if (__a > __b) {
87-
__a = __b;
88-
__b = __diff;
82+
_Tp __t = __b >> std::__countr_zero(__b);
83+
if (__a > __t) {
84+
__b = __a - __t;
85+
__a = __t;
8986
} else {
90-
__b = __b - __a;
87+
__b = __t - __a;
9188
}
92-
if (__diff != 0)
93-
__b >>= std::__countr_zero(__diff);
9489
} while (__b != 0);
9590
return __a << __shift;
9691
}

0 commit comments

Comments
 (0)