Skip to content

Commit f7ff3cd

Browse files
[libc++] Fix sub-overflow in std::gcd implementation (llvm#117984)
Fix llvm#117249
1 parent da24c02 commit f7ff3cd

File tree

2 files changed

+11
-24
lines changed

2 files changed

+11
-24
lines changed

libcxx/include/__numeric/gcd_lcm.h

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ 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+
// Using Binary GCD algorithm https://en.wikipedia.org/wiki/Binary_GCD_algorithm, based on an implementation
59+
// from https://lemire.me/blog/2024/04/13/greatest-common-divisor-the-extended-euclidean-algorithm-and-speed/
5960
//
6061
// If power of two divides both numbers, we can push it out.
6162
// - gcd( 2^x * a, 2^x * b) = 2^x * gcd(a, b)
@@ -76,21 +77,17 @@ constexpr _LIBCPP_HIDDEN _Tp __gcd(_Tp __a, _Tp __b) {
7677
if (__a == 0)
7778
return __b;
7879

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;
80+
_Tp __c = __a | __b;
81+
int __shift = std::__countr_zero(__c);
82+
__a >>= std::__countr_zero(__a);
8483
do {
85-
_Tp __diff = __a - __b;
86-
if (__a > __b) {
87-
__a = __b;
88-
__b = __diff;
84+
_Tp __t = __b >> std::__countr_zero(__b);
85+
if (__a > __t) {
86+
__b = __a - __t;
87+
__a = __t;
8988
} else {
90-
__b = __b - __a;
89+
__b = __t - __a;
9190
}
92-
if (__diff != 0)
93-
__b >>= std::__countr_zero(__diff);
9491
} while (__b != 0);
9592
return __a << __shift;
9693
}

libcxx/test/std/numerics/numeric.ops/numeric.ops.gcd/gcd.pass.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,7 @@ constexpr struct {
2727
int x;
2828
int y;
2929
int expect;
30-
} Cases[] = {
31-
{0, 0, 0},
32-
{1, 0, 1},
33-
{0, 1, 1},
34-
{1, 1, 1},
35-
{2, 3, 1},
36-
{2, 4, 2},
37-
{36, 17, 1},
38-
{36, 18, 18}
39-
};
40-
30+
} Cases[] = {{0, 0, 0}, {1, 0, 1}, {0, 1, 1}, {1, 1, 1}, {2, 3, 1}, {2, 4, 2}, {11, 9, 1}, {36, 17, 1}, {36, 18, 18}};
4131

4232
template <typename Input1, typename Input2, typename Output>
4333
constexpr bool test0(int in1, int in2, int out)

0 commit comments

Comments
 (0)