On the common measure of two magnitudes
De communi mensura duarum magnitudinum
Enuntiatio
Propositio III. Theorema. Datis duobus numeris non utrisque nullis, eorum maxima communis mensura per divisiones successivas invenitur.
Let two non-negative integers and be given, not both zero. I say that their greatest common divisor — the greatest integer dividing both without remainder — is found by the following reduction: while is not zero, replace the pair by the pair ; when becomes zero, the remaining first element is the sought divisor. The reduction always terminates, for the second magnitude strictly diminishes within the well-ordered naturals and cannot descend below zero. The number of reductions does not exceed a constant multiple of , whence the labour is logarithmic in the magnitudes.
Expressio
def gcd(a: int, b: int) -> int:
"""Greatest common divisor of a and b by Euclid's reduction.
Operates on the absolute values, so signs are immaterial.
By convention gcd(0, 0) == 0.
>>> gcd(48, 18)
6
>>> gcd(18, 48) # order is immaterial
6
>>> gcd(1071, 462)
21
>>> gcd(17, 13) # coprime magnitudes
1
>>> gcd(0, 5) # zero carries no constraint
5
>>> gcd(-48, 18) # signs are immaterial
6
"""
a, b = abs(a), abs(b)
while b != 0:
a, b = b, a % b # the reduction (a, b) -> (b, a mod b)
return a
# --- Demonstratio per exempla: concrete inline assertions ---
assert gcd(48, 18) == 6 # 48 = 2*18 + 12; 18 = 1*12 + 6; 12 = 2*6 + 0
assert gcd(18, 48) == 6 # symmetry under exchange
assert gcd(0, 0) == 0 # the conventional boundary case
assert gcd(0, 7) == 7 # gcd(0, n) = n
assert gcd(13, 17) == 1 # distinct primes are coprime
assert gcd(100, 100) == 100 # gcd(n, n) = n
assert gcd(1071, 462) == 21 # the classical worked example
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=False)
# Verification against the standard library over a wide range:
from math import gcd as _ref
for x in range(0, 200):
for y in range(0, 200):
assert gcd(x, y) == _ref(x, y), (x, y)
print("All assertions hold.")
Demonstratio
We treat , not both zero; signs are discharged at the outset by taking absolute values, since , and the case returns by convention. Two parts are required: that the reduction preserves the divisor sought (correctness), and that it must halt (termination). A third part bounds the labour.
Lemma (Preservation of common divisors). For , the pairs and have exactly the same set of common divisors; hence the same greatest common divisor.
Write the division with remainder , where and with . Let be any integer.
- Suppose and . Then divides any integer combination of and ; in particular . Thus divides both and .
- Conversely, suppose and . Then . Thus divides both and .
Therefore the common divisors of and of coincide as sets. Two equal sets of positive integers have the same greatest element, so
Loop invariant (Correctness). Let be the input pair (already made non-negative), and let denote the pair held after reductions. I claim the invariant
Base. At the pair is and the invariant is the identity .
Step. Suppose it holds after reductions and the loop performs one more, which requires . The new pair is . By the Lemma, , which by hypothesis equals . Hence the invariant survives the step.
When the loop halts it is because ; say this occurs at step , so . Then by the invariant the last equality because every integer divides , so the common divisors of are exactly the divisors of , the greatest of which is itself (and is only in the degenerate all-zero case). The returned value is therefore precisely .
Termination. Consider the second component as a measure . After the first reduction the second component is a remainder, and remainders satisfy . Hence for every step actually taken, The sequence is a strictly decreasing sequence of non-negative integers. By the well-ordering of the naturals, no such sequence is infinite: a strictly descending chain bounded below by has at most terms. Therefore reaches after finitely many reductions and the loop halts. There is no infinite regress; the construction is well-founded.
Scholium (the labour is logarithmic). A sharper bound shows the descent is fast. After two reductions the second component is at least halved: if , then either already, or , in which case the next quotient is exactly and . Thus in every case, so the second component loses at least one bit every two steps. The number of reductions is therefore , and (the tightest classical result) is largest precisely for consecutive Fibonacci numbers, where the quotients are all — which is why , lying near a Fibonacci ratio, takes its full complement of steps. The arithmetic operations being taken as unit cost, this is the complexity recorded above.
Both halves established and the bound exhibited, the proposition stands.
Q.E.D.