Definition
The greatest common divisor is also called the Greatest Common Divisor and is commonly abbreviated as gcd.
A common divisor of a set of integers is a number that divides every integer in the set. is a common divisor of every set of integers.
The greatest common divisor of a set of integers is the largest of all its common divisors.
For integers that are not both , their greatest common divisor is denoted by , or simply when there is no ambiguity.
For integers that are not all , their greatest common divisor is denoted by , or simply when there is no ambiguity.
See number theory basics for properties of the greatest common divisor and least common multiple.
How do we find a greatest common divisor? We first consider two numbers.
Euclidean algorithm
Process
Given two numbers and , how can we find their greatest common divisor?
Without loss of generality, assume .
If divides , then is their greatest common divisor. Now consider the case where does not divide , namely with .
We can prove that as follows:
Proof
Let , so clearly . If and , then and .
The right-hand side shows that is an integer, so . Therefore every common divisor of is also a common divisor of .
The converse must also be proved.
Let and . As above, we obtain and .
The left-hand side is clearly an integer, so is also an integer, hence . Thus every common divisor of is also a common divisor of .
Since the two pairs have exactly the same common divisors, their greatest common divisors are equal.
Therefore
Since and the two numbers do not increase, we obtain a recursive method for finding the greatest common divisor of two numbers.
Implementation
C++
// Version 1
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
// Version 2
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
Java
// Version 1
public int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
// Version 2
public int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
Python
def gcd(a, b):
if b == 0:
return a
return gcd(b, a % b)
Return the value when the recursion reaches b == 0 (that is, when a % b == 0 in the previous step).
Based on the recursive method above, we can also write an iterative method:
C++
int gcd(int a, int b) {
while (b != 0) {
int tmp = a;
a = b;
b = tmp % b;
}
return a;
}
Java
public int gcd(int a, int b) {
while(b != 0) {
int tmp = a;
a = b;
b = tmp % b;
}
return a;
}
Python
def gcd(a, b):
while b != 0:
a, b = b, a % b
return a
All of the algorithms above are called the Euclidean algorithm.
In C++17, we can also use <numeric> and std::gcd from the std::lcm header to compute the greatest common divisor and least common multiple.
Note
On some compilers, C++14 provides std::__gcd(a,b) for computing the greatest common divisor, but it is only a private helper function for std::rotate.1 Using it may cause unexpected problems, so it is generally not recommended.
If two numbers and satisfy , they are said to be coprime.
Properties
How efficient is the Euclidean algorithm? We prove that when the input consists of two -bit binary integers, its time complexity is . (Equivalently, when and are assumed to have the same order of magnitude, the time complexity is .)
Proof
When computing , there are two cases:
-
, in which case ;
-
, in which case , and taking modulo at least halves . Thus this case occurs at most times.
The second case must occur after the first, so the first case occurs no more often than the second.
Consequently, at most recursive calls are needed.
In fact, applying the Euclidean algorithm to the greatest common divisor of two consecutive terms of the Fibonacci sequence makes the algorithm attain its worst-case complexity.
Subtractive Euclidean algorithm
Modulo operations on large integers have relatively high complexity, whereas addition and subtraction are cheaper. For large integers, we can use subtraction instead of multiplication and division to find the greatest common divisor.
Process
Given two numbers and , find .
Assume . If , then . Otherwise, for every such that and , we can prove that .
Therefore, all common divisors of and are common divisors of and , so .
Stein algorithm optimization
If , the subtractive algorithm reaches its worst case with its complexity.
Consider the following optimization: if and , then .
Otherwise, suppose (the case is analogous). Since the case has already been considered, . Therefore .
The optimized algorithm, known as Stein's algorithm, has time complexity .
Proof
If or , each recursive call at least halves one of .
Otherwise, , reducing the problem to the previous case.
The algorithm makes at most recursive calls.
Implementation
See big integer arithmetic for a big-integer template.
Big-integer arithmetic must implement subtraction, comparison, left shift, right shift (which may be replaced by multiplication and division by small integers), and the number of trailing zero bits (which can be computed by checking parity directly).
C++
Big gcd(Big a, Big b) {
if (a == 0) return b;
if (b == 0) return a;
// Count the powers of the common factor 2 in a and b; countr_zero gives the number of trailing zero bits
int atimes = countr_zero(a);
int btimes = countr_zero(b);
int mintimes = min(atimes, btimes);
a >>= atimes;
for (;;) {
// The common powers of 2 in a and b have been handled, so a cannot be even later
b >>= btimes;
// Ensure a<=b
if (a > b) swap(a, b);
b -= a;
if (b == 0) break;
btimes = countr_zero(b);
}
return a << mintimes;
}
The code above follows the C++17 std::gcd implementations in libstdc++ and MSVC. For unsigned int and unsigned long long, Stein's algorithm is faster than the Euclidean algorithm when countr_zero can be computed extremely quickly, but it may be slower otherwise.
About countr_zero
- GCC's built-in functions
__builtin_ctz(32-bit) and__builtin_ctzll(64-bit) can replacecountr_zeroin the code above. - Starting with C++20, the
<bit>header containsstd::countr_zero. - If non-standard-library functions are unavailable and C++20 cannot be used, the following is an implementation after preprocessing in the Word-RAM with multiplication model:
constexpr int loghash[64] = {0, 32, 48, 56, 60, 62, 63, 31, 47, 55, 59, 61, 30,
15, 39, 51, 57, 28, 46, 23, 43, 53, 58, 29, 14, 7,
35, 49, 24, 44, 54, 27, 45, 22, 11, 37, 50, 25, 12,
38, 19, 41, 52, 26, 13, 6, 3, 33, 16, 40, 20, 42,
21, 10, 5, 34, 17, 8, 36, 18, 9, 4, 2, 1};
int countr_zero(unsigned long long x) {
return loghash[(x & -x) * 0x9150D32D8EB9EFC0Ui64 >> 58];
}
For big-integer arithmetic, if the representation is similar to bitset, combining it with the implementation of countr_zero above gives time complexity O(n / w). If splitting by individual bits is inconvenient, the largest power of dividing the number must instead be found by brute force, and the complexity depends on the implementation. For example:
// A binary Big stored in little-endian order; every element must be enumerable
int countr_zero(Big a) {
int ans = 0;
for (auto x : a) {
if (x != 0) {
ans += 32; // Bit width of each element type
} else {
return ans + countr_zero(x);
}
}
return ans;
}
// Brute-force computation; if used, put it directly into gcd to reduce the constant factor
int countr_zero(Big a) {
int ans = 0;
while ((a & 1) == 0) {
a >>= 1;
++ans;
}
return ans;
}
For further discussion of the relative speed of gcd implementations, see Fastest way to compute the greatest common divisor.
Greatest common divisor of multiple numbers
How do we find the greatest common divisor of multiple numbers? The answer is clearly a divisor of every number, and therefore also a divisor of every adjacent pair. By induction, removing two numbers, computing their gcd, and putting the result back does not change the desired answer.
Least common multiple
Next we introduce how to compute the least common multiple (LCM).
Definition
A common multiple of a set of integers is a number divisible by every integer in the set. 0 is a common multiple of every set of integers.
The least common multiple of a set of integers is the smallest positive common multiple.
For integers , their least common multiple is denoted by , or simply when there is no ambiguity.
For integers , their least common multiple is denoted by , or simply when there is no ambiguity.
Two numbers
Let and .
For and , we find that their greatest common divisor is
and their least common multiple is
Since
we conclude that
To find the least common multiple of two numbers, first compute their greatest common divisor.
Multiple numbers
Once the of two numbers is known, their least common multiple can be computed in time. For multiple numbers, there is no need to compute a common gcd first: whenever the gcd of two numbers is computed in a sequence, put their least common multiple back into the sequence and continue with the remaining numbers.
Extended Euclidean algorithm
The extended Euclidean algorithm (EXGCD) is commonly used to find one solution to .
Process
Let
.
By the Euclidean identity, .
Thus .
Also, .
Therefore .
Comparing the coefficients of and , we obtain and .
Substitute recursively until , where the recursion returns with .
Implementation
C++
int Exgcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1;
y = 0;
return a;
}
int d = Exgcd(b, a % b, x, y);
int t = x;
x = y;
y = t - (a / b) * y;
return d;
}
Python
def Exgcd(a, b):
if b == 0:
return a, 1, 0
d, x, y = Exgcd(b, a % b)
return d, y, x - (a // b) * y
The function returns the ; and are computed along the way.
Range analysis
The equation has infinitely many solutions, and some obviously exceed the range of the long long type. Fortunately, if , the solution produced by the extended Euclidean algorithm always satisfies and . We prove this property below.
Proof
- When , , so the recursion terminates at the next level. We obtain , and clearly .
- When , assume . Since and , we have and ; this is at most . Therefore .
Writing the extended Euclidean algorithm iteratively
First, when , , , and , we clearly have:
which holds.
Given , let . Following the iterative gcd algorithm, one iteration can be written as:
Replace in the iteration by and by to obtain:
This gives the iterative extended Euclidean algorithm.
The iterative method avoids recursion, so it runs slightly faster than the recursive version.
int gcd(int a, int b, int& x, int& y) {
x = 1, y = 0;
int x1 = 0, y1 = 1, a1 = a, b1 = b;
while (b1) {
int q = a1 / b1;
tie(x, x1) = make_tuple(x1, x - q * x1);
tie(y, y1) = make_tuple(y1, y - q * y1);
tie(a1, b1) = make_tuple(b1, a1 - q * b1);
}
return a1;
}
If you inspect and , you will find that they have exactly the same values as in the iterative Euclidean algorithm. The identities and hold both before the while loop and after every iteration, so the algorithm necessarily computes the correctly.
Finally, is the required , and .
Matrix interpretation
For positive integers and , one Euclidean step, namely , can be represented by the matrix
Here, the floor symbol denotes the greatest integer not exceeding . Define the transformation .
The Euclidean algorithm repeatedly applies this transformation, giving
Let
Then
The condition is precisely the extended Euclidean algorithm. Multiplication by an identity matrix at the end does not change the result, suggesting that we can maintain a identity matrix from the start and write the following simpler iterative method:
int exgcd(int a, int b, int &x, int &y) {
int x1 = 1, x2 = 0, x3 = 0, x4 = 1;
while (b != 0) {
int c = a / b;
std::tie(x1, x2, x3, x4, a, b) =
std::make_tuple(x3, x4, x1 - x3 * c, x2 - x4 * c, b, a - b * c);
}
x = x1, y = x2;
return a;
}
This formulation is simpler than the recursive one.
Applications
- 10104 - Euclid Problem
- GYM - (http://codeforces.com/gym/100963) once upon a time
- UVa - 12775 - Gift Dilemma