Euclidean algorithm


The Euclidean algorithm is an efficient algorithm that finds the greatest common divisor of two integers, without knowledge of their prime factorizations. It is one of the oldest algorithms still in use today, based on the following theorem:

For any two positive integers \(a\) and \(b\): $$\gcd(a, b) = \gcd(a \bmod b, b)$$

This theorem turns out to be a consequence of the remainder \(a \bmod b\) being a linear combination of \(a\) and \(b\), as any factor that divides \(a\) and \(b\) must also divide their linear combination \(a \bmod b.\) So, \(a\) and \(b\) end up sharing the same set of common factors as \(a \bmod b\) and \(b\), including the same greatest common divisor.

Remember, the order of the inputs does not matter for the \(\gcd\) function: \(\gcd(a, b) = \gcd(b, a).\) So do not focus on the order here. Basically, what this theorem is saying is that the greatest common divisor of two positive integers stays the same even if one of the integers has the other integer subtracted from it a certain number of times (which is essentially the effect of the \(\bmod\) operation).

The result of \(a \bmod b\) will always be \(a\) if \(a < b\), which is not very useful if our goal is to make the greatest common divisor easier to compute. The part of this theorem that is actually useful to the Euclidean algorithm is when \(a \geq b\), which means \(a \bmod b\) will decrease in size, becoming smaller than \(b\), since, as you know, \(a \bmod b\) can only return an integer in the set \(\set{0, ... b-1}.\) This process brings \(a\) progressively closer to the greatest common divisor, as you'll see below:

algorithm euclid is
input: two integers, a and b, where a ≥ b
output: their greatest common divisor (gcd)

while b ≠ 0
t ← b
b ← a mod b
a ← t
return a

The larger integer a gets continually replaced until the smaller integer b is able to divide it and a mod b = 0, at which point a holds the greatest common divisor. Let's watch this algorithm step-by-step:

a b a mod b
1071 462 147
462 147 21
147 21 0
21 0

Here is exactly how the algorithm uses the theorem mentioned earlier:

$$\gcd(1071, 462) = \gcd(1071 \bmod 462, 462) = \gcd(147, 462)$$ $$=\gcd(462, 147) = \gcd(462 \bmod 147, 147) = \gcd(21, 147)$$ $$=\gcd(147, 21) = \gcd(147 \bmod 21, 21) = \gcd(0, 21) = 21$$

Quite effective! And especially useful for large integers, whose prime factorizations would take way too long to compute.

Contents

Extended version


The extended Euclidean algorithm not only returns the greatest common divisor of two integers \(a\) and \(b\), but also the integer coefficients \(x\) and \(y\) such that \(ax + by = \gcd(a, b).\)

To briefly explain how it does this, it recognizes that the equation that defines integer division, \(a = (a \text{ div } b) \times b + (a \bmod b)\), can always be rearranged as \((a \bmod b) = a - (a \text{ div } b) \times b\) to express \(a \bmod b\) as a linear combination of \(a\) and \(b.\) This equation is then updated as a and b update each iteration until a mod b = 0, at which point the loop finishes. During the second-to-last iteration of the loop, a mod b stores the value of the greatest common divisor for the originally input a and b, which is why we maintain "previous" variables, so that in the end, we can access those second-to-last values. Here's the extended algorithm:

algorithm extended_euclid is
input: two integers, a and b, where a ≥ b
output: their greatest common divisor (gcd) and x and y such that ax + by = gcd(a, b)

previous_x ← 1
x ← 0
previous_y ← 0
y ← 1

while b ≠ 0
temp_x ← x
x ← previous_x - a div b * x
previous_x ← temp_x

temp_y ← y
y ← previous_y - a div b * y
previous_y ← temp_y

t ← b
b ← a mod b
a ← t
return a, previous_x, previous_y

Let's walk through this algorithm for the inputs a = 1071 and b = 462:

We'll be keeping an eye on how this equation changes with each iteration: $$(a \bmod b) = a - (a \text{ div } b) \times b$$ During the first iteration of the loop, we generate the following equation with the values of a and b: $$(1071 \bmod 462) = 1071 - (1071 \text{ div } 462) \times 462$$ $$147 = 1071 - 2 \times 462$$ a and b are updated at the end of the first iteration. Then, in the second iteration we have: $$(462 \bmod 147) = 462 - (462 \text{ div } 147) \times 147$$ $$21 = 462 - 3 \times 147$$ a and b are updated again at the end of the second iteration. Then, in the third iteration we have: $$(147 \bmod 21) = 147 - (147 \text{ div } 21) \times 21$$ $$0 = 147 - 7 \times 21$$ a and b are updated again at the end of the third iteration, but since b is now 0, there are no further iterations. The greatest common divisor was found by the algorithm to be \(21.\) Now, how can we represent \(21\) in the form \(ax + by\), specifically \(1071 \times x + 462 \times y\)? The answer lies in the equations we generated as we were walking through the algorithm: $$0 = 147 - 7 \times 21$$ $$21 = 462 - 3 \times 147$$ $$147 = 1071 - 2 \times 462$$ Only the equations from the second-to-last iteration and earlier are useful: $$21 = 462 - 3 \times 147$$ $$147 = 1071 - 2 \times 462$$ The greatest common divisor is \(21\), already represented as a linear combination in one of the equations. Let's substitute the equation from the iteration preceding it so that we can get to the original terms \(1071\) and \(462\) (if there were more iterations preceding it, we'd have to substitute each of their equations, but in this case, there is just one previous iteration): $$21 = 462 - 3 \times (1071 - 2 \times 462)$$ By substituting \(147\), we now have \(21\) written as a linear combination of \(1071\) and \(462\): $$21 = 462 - 3 \times (1071 - 2 \times 462)$$ $$21 = 462 - 3 \times 1071 + 6 \times 462$$ $$21 = - 3 \times 1071 + 7 \times 462$$ Thus, the integer coefficients \(x\) and \(y\) we are looking for are \(-3\) and \(7.\)

All we had to do was keep records of these \(a \bmod b\) equations from each iteration. That is the entirety of the Euclidean algorithm's extension. The integer coefficients \(x\) and \(y\) such that \(ax + by = \gcd(a, b)\) are a byproduct of computing \(\gcd(a, b)\) with the Euclidean algorithm. In other words, \(x\) and \(y\) were always present, we just had to write a bit more code to pay attention to how they update with \(a\) and \(b.\) Overall, this extension allows us to get more out of the algorithm than we normally would for very little additional computing cost, which is really nice!

Logic & Proofs
IntegerRational numberInequalityReal numberTheoremProofStatementProof by exhaustionUniversal generalizationCounterexampleExistence proofExistential instantiationAxiomLogicTruthPropositionCompound propositionLogical operationLogical equivalenceTautologyContradictionLogic lawPredicateDomainQuantifierArgumentRule of inferenceLogical proofDirect proofProof by contrapositiveIrrational numberProof by contradictionProof by casesSummationDisjunctive normal form
Set Theory
SetElementEmpty setUniversal setSubsetPower setCartesian productStringBinary stringEmpty stringSet operationSet identitySet proof
Functions
FunctionFloor functionCeiling functionInverse function
Algorithms
AlgorithmPseudocodeCommandAsymptotic notationTime complexityAtomic operationBrute-force algorithm
Relations
RelationReflexive relationSymmetric relationTransitive relationRelation compositionEquivalence relationEquivalence class
Number Theory
Integer divisionLinear combinationDivision algorithmModular arithmeticPrime factorizationGreatest common divisorLeast common multiplePrimality testFactoring algorithmEuclid's theoremPrime number theoremEuclidean algorithm
Induction
Proof by inductionFibonacci sequenceProof by strong inductionWell-ordering principleSequenceFactorialRecursive definition
Combinatorics
Rule of productRule of sumBijection rulePermutationCombinationComplement ruleExperimentOutcomeSample spaceEventProbabilityProbability distributionUniform distributionMultisetSixfold wayInclusion-exclusion principlePigeonhole principle
Graph Theory
GraphWalkSubgraphRegular graphComplete graphEmpty graphCycle graphHypercube graphBipartite graphComponentEulerian circuitEulerian trailHamiltonian cycleHamiltonian pathTreeHuffman treeSubstringForestPath graphStarSpanning treeWeighted graphMinimum spanning treeGreedy algorithmPrim's algorithm
Recursion
RecursionRecursive algorithmCorrectness proofDivide-and-conquer algorithmSorting algorithmMerge sort