Binary GCD returns gcd(a, b) after at most 1 + lg(ab) passes and O(n^2) bit operations full
This proof shows: correctness, termination, time.worst, bit_operations.worst.
We use the pseudocode BINARY-GCD of the page. The inputs a0,b0 are any integers, and g=gcd(a0,b0), with gcd(x,0)=∣x∣ and gcd(0,0)=0. For x>0, tz(x) is the exponent of 2 in x, so x=2tz(x)u with u odd.
Lemma 1 (three gcd rules). Let u,v≥1 be integers.
- If u is odd, then gcd(u,2sv)=gcd(u,v) for each s≥0.
- gcd(u,v)=gcd(u,v−u).
- If k=min(tz(u),tz(v)), then gcd(u,v)=2kgcd(u/2tz(u),v/2tz(v)).
Proof. (1) A common divisor of u and v divides 2sv. Conversely, let d divide u and 2sv. Since u is odd, d is odd, so gcd(d,2s)=1, and d∣2sv gives d∣v by Gauss's lemma. So the two pairs have the same common divisors. (2) d divides u and v if and only if it divides u and v−u. (3) Write u=2su′ and v=2tv′ with u′,v′ odd, s≤t say, so k=s. Then gcd(u,v)=2sgcd(u′,2t−sv′), because gcd(cx,cy)=cgcd(x,y) for c≥1, and gcd(u′,2t−sv′)=gcd(u′,v′) by rule 1. □
Theorem 1 (correctness). BINARY-GCD(a0,b0) stops and returns g.
Proof. After line L1, a=∣a0∣, b=∣b0∣, and gcd(a,b)=g. If a=0, line L2 returns b=g; if b=0, line L3 returns a=g. Otherwise a,b≥1. Line L4 sets k=tz(aorb), which is min(tz(a),tz(b)), since the lowest 1 digit of aorb is the lower of the lowest 1 digits of a and b. Let a1=a/2tz(a) and b1=b/2tz(b). By Lemma 1 (3), g=2kgcd(a1,b1)=2kgcd(a1,b), the last step by rule 1. Line L5 sets a=a1. We use this invariant at the start of each pass of the loop L6 to L10:
(I) a is odd, b≥1, and 2kgcd(a,b)=g.
Initialization. Shown above.
Maintenance. Line L7 makes b odd; by rule 1, gcd(a,b) does not change. Line L8 swaps if needed, so now a≤b and both are odd. Line L9 sets b←b−a≥0, and rule 2 keeps the gcd. If b≥1 after line L9, the loop goes on and (I) holds: a is odd and b≥1.
Exit. The loop exits at line L10 when b−a=0, so a=b and gcd(a,b)=a. Then g=2ka, which line L11 returns. Termination follows from Theorem 2. ■
Theorem 2 (number of passes). If a0b0=0, the loop runs at most 1+lg(∣a0∣⋅∣b0∣) times. If the inputs have at most n binary digits, this is at most 2n+1.
Proof. For pass i, let Pi=a⋅b right after line L8 of that pass. At that moment a≤b, both odd. If the pass does not exit, line L9 makes b−a, which is even and at least 2, and line L7 of the next pass divides it by at least 2. So the next pass starts its line L8 with the pair a and (b−a)/2s, s≥1, in some order, and
Pi+1≤a⋅2b−a<2ab=2Pi. Let the loop run t passes. Then 1≤Pt<P1/2t−1 when t≥2, so 2t−1<P1. Lines L5 and L7 only divide, so P1≤∣a0∣⋅∣b0∣. This gives t<1+lg(∣a0∣∣b0∣) for t≥2, and the bound holds for t=1 too. Since ∣a0∣,∣b0∣<2n, t≤2n+1. ■
Tightness. On (2n−1,1) the loop runs exactly n times: the pair is (1,2j−1), line L9 gives 2j−2, and line L7 gives 2j−1−1. So the number of passes is Θ(n) in the worst case.
Theorem 3 (time and bit operations). On the word RAM with a constant-time count of trailing zeros, BINARY-GCD uses O(n) word operations. On inputs of at most n binary digits, it uses O(n2) bit operations.
Proof. Each pass does a constant number of shifts, comparisons, subtractions and trailing zero counts, so the word bound follows from Theorem 2. In the bit model, each of these operations on numbers of at most n digits costs O(n) bit operations: a shift by s places costs O(n), and tz by a scan from the low end costs O(1+tz(x)). Lines L1 to L5 and L11 cost O(n), and there are O(n) passes of O(n) each, so the total is O(n2). If tz is computed by testing one digit at a time, the total count of digits shifted out over the whole run is at most lg∣a0∣+lg∣b0∣≤2n, since each shift by one place halves a value that stays at least 1; this does not change the bounds. ■