GCD (Euclidean Algorithm)
Compute the greatest common divisor by repeatedly replacing (a, b) with (b, a mod b); the extended form also finds x, y with ax + by = gcd.
Overview
The greatest common divisor gcd(a, b) is the largest integer dividing both. Euclid's algorithm computes it with the identity gcd(a, b) = gcd(b, a mod b) and base case gcd(a, 0) = a. For gcd(252, 105): 252 mod 105 = 42, 105 mod 42 = 21, 42 mod 21 = 0, so the answer is 21.
The extended Euclidean algorithm tracks how each remainder is a combination of the original inputs, yielding integers x, y with a·x + b·y = gcd(a, b) (Bezout's identity). This is how Modular Inverse is computed when the modulus is not prime, and how linear Diophantine equations ax + by = c are solved (solvable iff gcd | c).
The number of steps is O(log min(a, b)); the worst case is consecutive Fibonacci numbers. Every mainstream library ships it (math.gcd, std::gcd, BigInteger.gcd), but interviews expect you to write it and to know the extended version.
Intuition
A mental model before the formal terms.
Tile a 252 × 105 rectangle with the largest square possible. Cut off as many 105 × 105 squares as fit (two), leaving a 105 × 42 strip. Repeat on the strip: two 42 × 42 squares leave 42 × 21; two 21 × 21 squares leave nothing. The last square that tiles exactly, 21, is the gcd. Each step shrinks the problem to the leftover strip, which is what a mod b computes.
How it works
- While
b != 0: set(a, b) = (b, a mod b). Whenbreaches 0,ais the gcd. - Extended: maintain two pairs
(old_r, r) = (a, b),(old_s, s) = (1, 0),(old_t, t) = (0, 1)such thatold_r = a·old_s + b·old_tandr = a·s + b·tat all times. - Each step computes
q = old_r div rand updates every pair as(old, cur) = (cur, old - q·cur). The invariant is preserved because it is linear. - When
rbecomes 0,old_ris the gcd and(old_s, old_t)are the Bezout coefficients. - Binary GCD (Stein) replaces divisions with shifts and subtractions: factor out common 2s, then repeatedly subtract the smaller odd number from the larger.
Why it works
Any common divisor d of a and b divides a - q·b = a mod b, and any common divisor of b and a mod b divides a = q·b + (a mod b). So the pair (a, b) and the pair (b, a mod b) have exactly the same common divisors, hence the same greatest one.
Termination and speed: after two steps the larger value at least halves (a mod b < a / 2 whenever b ≤ a), so the number of steps is at most 2·log2(a). Lamé's theorem sharpens this to about log_φ(min(a, b)) steps, attained by Fibonacci inputs.
Extended: the coefficients are correct because each remainder is computed as an integer combination of the previous two, and the initial values are trivially combinations of a and b.
Recognition
How to tell a problem wants this.
- "Greatest common divisor", "can these be measured with a common unit", "reduce a fraction", "simplify a ratio".
- Any LCM (Least Common Multiple) question, since
lcm = a / gcd · b. - Modular inverses when the modulus is composite, or solving
ax + by = cin integers. - Detecting whether a step size
kvisits every position in a cycle of lengthn(yes iffgcd(k, n) = 1).
Interactive visualization
Play, step, change the input. ← → and space work too.
| a | b | q = a div b | r = a mod b |
|---|---|---|---|
| 252 | 105 | · | · |
1(s0, s1), (t0, t1) = (1, 0), (0, 1) # a = s0·A + t0·B, b = s1·A + t1·B2while b != 0:3 q = a div b; r = a mod b4 a, b = b, r5 s0, s1 = s1, s0 - q·s1; t0, t1 = t1, t0 - q·t16return a # gcd; and s0·A + t0·B == gcdPseudocode
1gcd(a, b):2 while b != 0:3 a, b = b, a mod b4 return a5ext_gcd(a, b):6 if b == 0: return (a, 1, 0)7 g, x1, y1 = ext_gcd(b, a mod b)8 return (g, y1, x1 - (a div b) * y1)Implementations
1from typing import Tuple2 3 41 · Iterative Euclidean algorithm5def gcd(a: int, b: int) -> int:6 """math.gcd does this in C; shown for the algorithm. Exact for any size."""7 a, b = abs(a), abs(b)8 while b:9 a, b = b, a % b # (a, b) -> (b, a mod b) shrinks b every step10 return a # gcd(a, 0) == a11 12 132 · Extended Euclid: g = ax + by14def ext_gcd(a: int, b: int) -> Tuple[int, int, int]:15 """Return (g, x, y) with a*x + b*y == g == gcd(a, b)."""16 if b == 0:17 return a, 1, 018 g, x1, y1 = ext_gcd(b, a % b)19 return g, y1, x1 - (a // b) * y1 # floor // matches Python's floor %20 21 223 · Demo23if __name__ == "__main__":24 import math25 assert gcd(48, 18) == 6 == math.gcd(48, 18)26 assert gcd(-48, 18) == 627 assert gcd(0, 7) == 728 g, x, y = ext_gcd(240, 46)29 assert g == 2 and 240 * x + 46 * y == g- The tuple assignment
a, b = b, a % bperforms the Euclid step atomically — no temporary needed. - Python
%returns a result with the divisor's sign (floor semantics); afterabsnormalization the loop only sees non-negatives anyway. ext_gcduses floor division//with floor%— consistent, so the Bezout identity holds for negative inputs too.- Arbitrary-precision ints mean no overflow anywhere;
math.gcdis the C-speed stdlib version.
Each op costs O(digits) on huge ints.
math.gcd(any number of args since 3.9) always returns a non-negative int — prefer it in real code.- Python's floor
%differs from C++/JS truncation:-7 % 3is2in Python,-1in C++/JS. Euclid works with either, as long as////matches. - Recursion in
ext_gcdis depth O(log), nowhere near the default 1000-frame limit.
- Re-implementing gcd in a hot loop instead of calling
math.gcd. - Porting C code with
int(a / b)— true division then truncation disagrees with Python's floor%on negatives. - Assuming
%behaves like C: sign conventions differ.
- Stdlib: C++17
std::gcd, Pythonmath.gcd; JS/TS have none — always hand-rolled. - Division/remainder signs: C++ and JS truncate toward zero (
-7 % 3 == -1); Python floors (-7 % 3 == 2). Extended Euclid must pair the matching quotient:a / b(C++),Math.trunc(a / b)(JS/TS),a // b(Python). - Range: C++
long longto 2^63; JS/TSnumberexact to 2^53, then BigInt (separate code path); Python unbounded. - Edge case:
llabs(INT64_MIN)overflows in C++; Python and BigInt have no such value.
Complexity
Worst case is consecutive Fibonacci numbers. Recursive form uses O(log) stack. Extended version has the same bound with constant extra work per step.
Compare growth rates in the Complexity Explorer →When to use — and when not to
- Reducing fractions, computing LCM (Least Common Multiple), checking coprimality.
- Modular inverse modulo a composite
m(extended Euclid) — see Modular Inverse. - Solving linear Diophantine equations and Chinese Remainder Theorem reconstruction.
- GCD of an array or of a sliding range (combine with Sparse Table or Segment Tree since gcd is associative and idempotent).
- Never write trial division over
1..min(a, b)— that isO(min(a, b))versusO(log). - Floating-point inputs: gcd is defined on integers; convert exact rationals first.
- When only powers of two are involved,
a & -aand shifts are cheaper — see Power-of-Two Tricks.
Alternatives
Common mistakes
- Swapping arguments incorrectly in the recursive form (
gcd(a % b, b)instead ofgcd(b, a % b)) — still correct but doubles the steps. - Negative inputs:
%in C++, Java, JavaScript and Go keeps the sign of the dividend, so take absolute values first or normalize the result. - Extended Euclid: returning
(x1 - (a / b) * y1)with integer division that truncates toward zero on negatives — fine as long as remainders are computed with the same division; do not mixfloorand truncation. - JavaScript:
a % bon values above2^53loses precision; useBigInt. - Assuming
gcd(0, 0) = 0is an error; by convention it is 0, andgcd(x, 0) = |x|.
Interview patterns
- GCD of strings:
"ABCABC","ABC"have a common divisor string iffs + t == t + s, of lengthgcd(len(s), len(t)). - Rotate an array in place by
kusinggcd(n, k)cycles. - Count pairs
(i, j)withgcd(a[i], a[j]) = 1via inclusion-exclusion over divisors — see Combinatorics. - Water jug problem:
zis reachable iffz ≤ x + yandgcd(x, y)dividesz.