GCD & the Sieve of Eratosthenes

Reducing fractions, syncing repeating schedules, factoring numbers, hashing with primes: two ancient Greek algorithms still do this work in every contest and in a lot of production code.

intermediate⏱ 12 min read
01

Learn

The idea, the mechanics and the cost.

01Euclid's algorithm

The greatest common divisor gcd(a, b) is the largest number dividing both. Trying every candidate is slow. Euclid noticed that any common divisor of a and b also divides a mod b, because a mod b = a − q·b. So

gcd(a, b) = gcd(b, a mod b), and gcd(a, 0) = a.

For 84 and 60: (84, 60) → (60, 24) → (24, 12) → (12, 0), so the answer is 12 after three divisions. In code it is one line: while (b) { t = a % b; a = b; b = t; }.

Once you have gcd, the least common multiple follows: lcm(a, b) = a / gcd(a, b) * b. Divide first, so the intermediate value does not overflow.

(84, 60)84 = 1·60 + 24(60, 24)60 = 2·24 + 12(24, 12)24 = 2·12 + 0(12, 0)gcd = 12gcd(a, b) = gcd(b, a mod b)

02Why Euclid is so fast

After two steps the larger number at least halves. If b ≤ a/2, then a mod b < b ≤ a/2. If b > a/2, then a mod b = a − b < a/2. Either way the pair shrinks fast, so Euclid takes O(log min(a, b)) steps: about 90 divisions even for 64-bit numbers.

Primality has a similar shortcut. To test whether n is prime you only need to try divisors up to √n, because divisors come in pairs d · (n/d), and one of the pair is always ≤ √n. That gives an O(√n) test, fine for one number up to about 10^12.

But if you need all primes up to n, testing each number separately costs O(n√n). The sieve does much better.

divisor pairs of 36≤ √36 = 6≥ 611 · 36 = 363622 · 18 = 361833 · 12 = 361244 · 9 = 36966 · 6 = 366every pair has one divisor ≤ √n, so checking up to √n is enough

03The Sieve of Eratosthenes

Write 2..n and mark them all "maybe prime". Walk p upward. If p is still unmarked, it is prime, because no smaller prime divides it. Then cross out its multiples. Two details make it fast:

  • start crossing at p²: smaller multiples like 2p and 3p were already crossed by 2 and 3
  • stop when p² > n: every composite ≤ n has a prime factor ≤ √n, so everything left is prime

for p in 2..: if p*p > n break; if is[p]: for m = p*p; m <= n; m += p: is[m] = false

The total work is n/2 + n/3 + n/5 + … over primes, which is O(n log log n): practically linear. A sieve up to 10^7 runs in well under a second and needs one byte (or one bit) per number.

12345678910111213141516171819202122232425262728293031323334353637383940primecrossed by:235cross multiples of p starting at p²
Each composite is coloured by the first prime that crossed it out. Only 2, 3 and 5 are needed for n = 40, since 7² = 49 > 40.

04Beyond the basic sieve

A small upgrade makes the sieve far more useful. Instead of a boolean, store spf[m], the smallest prime factor, the first time m is crossed out. Then you can factor any m ≤ n in O(log m): divide by spf[m] repeatedly.

Typical uses:

  • counting divisors of many numbers (factor, then multiply exponents + 1)
  • checking coprimality: gcd(a, b) == 1
  • fractions in lowest terms: divide both parts by their gcd

Pitfalls: 1 is neither prime nor composite, so mark it explicitly. Allocate n + 1 entries. When n is large, compute p * p in 64-bit to avoid overflow.

Cost at a glance

gcd (Euclid)O(log min(a,b))
Primality test by trial divisionO(√n)
Sieve: all primes up to nO(n log log n)
Factor m with an spf sieveO(log m)

Remember

  1. gcd(a, b) = gcd(b, a mod b) until b is 0; it needs only O(log) steps, and lcm = a / gcd · b.
  2. Divisors come in pairs around √n, so primality checks and sieving can stop at √n.
  3. The sieve crosses multiples from p² upward and finds all primes up to n in O(n log log n).
02

Play

Step through the algorithm, then try it on your own input.

👀 What to watch: First watch (a, b) shrink to (gcd, 0). Then in the sieve, notice that each new prime starts crossing at p², and that the run stops long before n.

Interactive visualizerfocus here, then space ← →
✎ Your inputn: 10–100. a, b: 1–100000, or leave both empty to run only the sieve.

Euclid's algorithm

aba mod b
8460·

Sieve of Eratosthenes, 2..60

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
primejust crossed outcomposite (crossed out)not decided yetcurrent p
gcd(84, 60): any common divisor of a and b also divides a mod b, so we may replace (a, b) by (b, a mod b) without changing the answer.

Pseudocode

 1 gcd(a, b): while b != 0: 2   (a, b) = (b, a mod b) 3   return a 4 is_prime[2..n] = true 5 for p = 2; p * p <= n; p++: 6   if is_prime[p]:                 // p is prime 7     for m = p*p; m <= n; m += p: is_prime[m] = false 8 every number still marked true is prime
1 / 1
03

Check

Three questions. Pick an answer to see why.

Q1

Euclid on (48, 18): which pair comes right after (48, 18)?

Q2

Sieving up to n = 100, what is the last p whose multiples we cross out?

Q3

Why does the sieve start crossing the multiples of p at p² instead of 2p?

04

Practice

Real problems to lock it in, easiest first.