Skip to content

Commit a845a60

Browse files
committed
Revisit Euclidean algorithm article
1 parent 6468f06 commit a845a60

File tree

2 files changed

+41
-70
lines changed

2 files changed

+41
-70
lines changed

src/algebra/euclid-algorithm.md

Lines changed: 39 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,100 @@
1-
<!--?title The Euclidean algorithm for finding greatest common divisor -->
2-
3-
# The Euclidean algorithm for finding greatest common divisor
4-
5-
Given two non-negative integers $a$ and $b$, find their greatest common divisor, i.e. the largest number which is a divisor of both $a$ and $b$. It's commonly denoted by $gcd$.
6-
7-
$$gcd(a, b) = \max_ {k = 1 \ldots \infty \ : \ k \mid a \ \& \ k \mid b} k$$
1+
<!--?title Euclidean algorithm for computing the greatest common divisor -->
2+
# Euclidean algorithm for computing the greatest common divisor
83

4+
Given two non-negative integers $a$ and $b$, we have to find their **GCD** (greatest common divisor), i.e. the largest number which is a divisor of both $a$ and $b$.
5+
It's commonly denoted by $\gcd(a, b)$. Mathematically it is defined as:
6+
$$\gcd(a, b) = \max_ {k = 1 \dots \infty ~ : ~ k \mid a ~ \wedge k ~ \mid b} k.$$
97
(here the symbol "$\mid$" denotes divisibility, i.e. "$k \mid a$" means "$k$ divides $a$")
108

11-
When one of the numbers is zero, while the other is non-zero, their greatest common divisor, by definition, is the second number. When both numbers are zero, their greatest common divisor is undefined (it can be any arbitrarily large number), but we can define it to be zero. So we have a simple rule: if one of the numbers is zero, the greatest common divisor is the other number.
9+
When one of the numbers is zero, while the other is non-zero, their greatest common divisor, by definition, is the second number. When both numbers are zero, their greatest common divisor is undefined (it can be any arbitrarily large number), but we can define it to be zero. Which gives us a simple rule: if one of the numbers is zero, the greatest common divisor is the other number.
1210

13-
The Euclidean algorithm, discussed below, allows to find the greatest common divisor of two numbers $a$ and $b$ in $O(\log min(a, b))$.
11+
The Euclidean algorithm, discussed below, allows to find the greatest common divisor of two numbers $a$ and $b$ in $O(\log \min(a, b))$.
1412

15-
The algorithm was first described in Euclid's "Elements" (circa 300 BC), but it is possible that the algorithm has earlier origins.
13+
The algorithm was first described in Euclid's "Elements" (circa 300 BC), but it is possible that the algorithm has even earlier origins.
1614

1715
## Algorithm
1816

1917
The algorithm is extremely simple:
2018

21-
$$gcd(a, b) = \begin{cases}a,&\text{if }b = 0 \\\\ gcd(b, a\mod b),&\text{otherwise}\end{cases}$$
19+
$$\gcd(a, b) = \begin{cases}a,&\text{if }b = 0 \\\\ \gcd(b, a \bmod b),&\text{otherwise.}\end{cases}$$
2220

2321
## Implementation
2422

2523
```cpp
2624
int gcd (int a, int b) {
27-
if (b == 0)
28-
return a;
29-
else
30-
return gcd (b, a % b);
25+
if (b == 0)
26+
return a;
27+
else
28+
return gcd (b, a % b);
3129
}
3230
```
3331
34-
Using the ternary operator in C++, we can write a shorter implementation:
32+
Using the ternary operator in C++, we can write it as a one-liner.
3533
3634
```cpp
3735
int gcd (int a, int b) {
38-
return b ? gcd (b, a % b) : a;
36+
return b ? gcd (b, a % b) : a;
3937
}
4038
```
4139

42-
Finally, here is a non-recursive implementation:
40+
And finally, here is a non-recursive implementation:
4341

4442
```cpp
4543
int gcd (int a, int b) {
46-
while (b) {
47-
a %= b;
48-
swap(a, b);
49-
}
50-
return a;
44+
while (b) {
45+
a %= b;
46+
swap(a, b);
47+
}
48+
return a;
5149
}
5250
```
5351
5452
## Correctness Proof
5553
56-
First, notce that at each iteration of the Euclidean algorithm the second argument strictly decreases, therefore (since the arguments are always non-negative) the algorithm will always terminate.
54+
First, notice that in each iteration of the Euclidean algorithm the second argument strictly decreases, therefore (since the arguments are always non-negative) the algorithm will always terminate.
5755
58-
For the proof of correctness, we need to show that $gcd(a, b) = gcd(b, a \mod b)$ for all $a \geq 0$, $b > 0$.
56+
For the proof of correctness, we need to show that $\gcd(a, b) = \gcd(b, a \bmod b)$ for all $a \geq 0$, $b > 0$.
5957
6058
We will show that the value on the left side of the equation divides the value on the right side and vice versa. Obviously, this would mean that the left and right sides are equal, which will prove Euclid's algorithm.
6159
62-
Let $d = gcd(a, b)$. Then by definition $d\mid a$ and $d\mid b$.
63-
64-
Now let's represent the remainder from dividing $a$ by $b$ as follows:
65-
66-
$$
67-
a \mod b = a - b \cdot \Bigl\lfloor\dfrac{a}{b}\Bigr\rfloor
68-
$$
69-
70-
But then, it follows:
71-
72-
$$
73-
d \mid (a \mod b)
74-
$$
60+
Let $d = \gcd(a, b)$. Then by definition $d\mid a$ and $d\mid b$.
7561
76-
So, recalling that $d \mid b$, we obtain the system:
62+
Now let's represent the remainder of the division of $a$ by $b$ as follows:
63+
$$a \bmod b = a - b \cdot \Bigl\lfloor\dfrac{a}{b}\Bigr\rfloor$$
7764
78-
$$
79-
\begin{cases}d \mid b,\cr d \mid (a \mod b)\cr\end{cases}
80-
$$
65+
From this it follows that $d \mid (a \bmod b)$, which means we have the system of divisiblities:
66+
$$\begin{cases}d \mid b,\\\\ d \mid (a \mod b)\end{cases}$$
8167
82-
Now we use the fact that for any three numbers $p$, $q$, $r$, if $p\mid q$ and $p\mid r$ then $p\mid gcd(q, r)$, In our case, we get:
83-
84-
$$
85-
d \mid gcd(b, a \mod b)
86-
$$
87-
88-
Substituting $d$ with its definition ($gcd(a, b)$) we get:
89-
90-
$$
91-
gcd(a, b) \mid gcd(b, a \mod b)
92-
$$
68+
Now we use the fact that for any three numbers $p$, $q$, $r$, if $p\mid q$ and $p\mid r$ then $p\mid \gcd(q, r)$. In our case, we get:
69+
$$d = \gcd(a, b) \mid \gcd(b, a \mod b)$$
9370
9471
Thus we have shown that the left side of the original equation divides the right. The second half of the proof is similar.
9572
9673
## Time Complexity
9774
98-
The running time of the algorithm is estimated by Lame's theorem, which establishes a surprising connection between the Euclidean algorithm and the Fibonacci sequence:
75+
The running time of the algorithm is estimated by Lamé's theorem, which establishes a surprising connection between the Euclidean algorithm and the Fibonacci sequence:
9976
10077
If $a > b \geq 1$ and $b < F_n$ for some $n$, the Euclidean algorithm performs at most $n-2$ recursive calls.
10178
10279
Moreover, it is possible to show that the upper bound of this theorem is optimal. When $a = F_n$ and $b = F_{n-1}$, $gcd(a, b)$ will perform exactly $n-2$ recursive calls. In other words, consecutive Fibonacci numbers are the worst case input for Euclid's algorithm.
10380
104-
Given that Fibonacci numbers grow exponentially (as a constant raised to $n$th power), we get that the Euclidean algorithm works in $O(\log min(a, b))$ multiplication operations.
105-
106-
## LCM (least common multiple)
81+
Given that Fibonacci numbers grow exponentially, we get that the Euclidean algorithm works in $O(\log \min(a, b))$.
10782
108-
Calculating least common multiple (commonly denoted LCM) is reduced to calculating $gcd$ with the following simple formula:
83+
## Least common multiple
10984
110-
$$
111-
lcm(a, b) = \dfrac{a \cdot b}{gcd(a, b)}
112-
$$
85+
Calculating the least common multiple (commonly denoted **LCM**) can be reduced to calculating the GCD with the following simple formula:
86+
$$\text{lcm}(a, b) = \frac{a \cdot b}{\gcd(a, b)}$$
11387
11488
Thus, LCM can be calculated using the Euclidean algorithm with the same time complexity:
11589
90+
A possible implementation, that cleverly avoids integer overflows by first dividing $a$ with the GCD, is given here:
91+
11692
```cpp
11793
int lcm (int a, int b) {
118-
return a / gcd (a, b) * b;
94+
return a / gcd(a, b) * b;
11995
}
12096
```
121-
(here it is advantageous to first divide by $gcd$ and then multiply by $b$ to avoid overflow in some cases)
122-
123-
## Literature
124-
125-
- Thomas Cormen, Charles Leiserson, Ronald Rivest, Clifford Stein. Algorithms: Construction and analysis [2005]
12697

12798
## Practice Problems
12899

129-
- [GCD and LCM [easy]](https://www.codechef.com/problems/FLOW016)
100+
- [Codechef - GCD and LCM](https://www.codechef.com/problems/FLOW016)

src/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ especially popular in field of competitive programming.*
99
## Articles
1010

1111
### Algebra
12-
- [Euler's Totient Function](./algebra/phi-function.html)
12+
- [Euler's totient function](./algebra/phi-function.html)
1313
- [Number of divisors / sum of divisors](./algebra/divisors.html)
14-
- [Euclidean algorithm for finding the GCD (greatest common divisor)](./algebra/euclid-algorithm.html)
14+
- [Euclidean algorithm for computing the greatest common divisor](./algebra/euclid-algorithm.html)
1515
- [Sieve of Eratosthenes](./algebra/sieve-of-eratosthenes.html)
1616
- [Extended Euclidean Algorithm](./algebra/extended-euclid-algorithm.html)
1717
- [Binary Exponentiation](./algebra/binary-exp.html)

0 commit comments

Comments
 (0)