Sam
Oct 05 2020 at 15:14 GMT
With Euclid's algorithm, we can find the greatest common divisor (GCD) of two integers and . It can be proven that the GCD is the smallest positive integer linear combination of and . Thus, we can write the GCD as a linear combination of and :
The extended Euclidean algorithm allows to find not only the GCD, but also the values of the coefficients and .
I would like some explanations of how this algorithm works.
Carl
Oct 05 2020 at 17:47 GMT
The idea of the extended Euclidean algorithm is to keep track of how each encountered remainder can be written as a linear combination of and . This way, once we reach the last non-zero remainder, which corresponds to the GCD, we know how to express it as a linear combination of and .
Let's find the GCD of 221 and 91 using the extended Euclidean algorithm.
According to the Division theorem, we can write 221 as 91 times the quotient plus the remainder:
Thus, .
We can express this first remainder (39) as a linear combination of 221 and 91 by rearranging the terms:
Let's continue with the algorithm:
By the Division theorem:
So, .
Let's express 13 as a linear combination of 221 and 91:
Let's continue:
By the Division theorem:
Thus, we reached a zero remainder: .
Thus, the GCD of 221 and 91 is 13, and we know how to express 13 as a linear combination of 221 and 91:
That is, and are two possible coefficients in a linear combination of 221 and 91 that makes up the GCD.
Let's now see how to implement a function extendedGCD in C++ that computes both the GCD and the coefficients and using the extended Euclidean algorithm.
First we need a way to express the return value of such a function. It consists of 3 items:
One way to express this is using a struct that has 3 fields. Since this struct represents the value of a linear combination along with the coefficients and , let's call it LinearCombination and define it as follows:
struct LinearCombination {
int value;
int s;
int t;
};So, the GCD of the previous example would correspond to:
LinearCombination gcd = {13, -2, 5};We now have a way to express the GCD and the coefficients, so the signature of the extendedGCD function will be:
LinearCombination extendedGCD(int a, int b);Let's think about how the extendedGCD function would work.
We start with and , which trivially are linear combinations of and :
We compute the remainder using the Division theorem:
Since is equal to the difference between linear combinations of and , is also a linear combination of and .
Next, we recursively compute . Thus, becomes the new and becomes the new .
Since and are initially linear combinations of and , and the remainder that we compute is also a linear combination of and , it follows that and are always linear combinations of and :
Knowing this, we can determine how to compute the coefficients and for the remainder :
Thus, the coefficients for the remainder are and .
We keep doing this until we reach a zero-remainder, that is, until becomes 0. When that happens, we simply return , which is the last non-zero remainder, and thus it corresponds to the GCD.
Let's look at the implementation:
struct LinearCombination {
int value; // the value of sa + tb
int s; // the coefficient s in sa + tb
int t; // the coefficient t in sa + tb
};
LinearCombination extendedGCDRec(LinearCombination x, LinearCombination y) {
if (y.value == 0) {
return x;
}
int q = x.value / y.value;
int s = x.s - q * y.s;
int t = x.t - q * y.t;
LinearCombination r = {x.value - q * y.value, s, t};
return extendedGCDRec(y, r);
}
LinearCombination extendedGCD(int a, int b) {
if (a == 0 && b == 0) {
return LinearCombination({-1, 0, 0});
}
if (a == 0) {
return LinearCombination({b, 0, 1});
}
LinearCombination x = {a, 1, 0};
LinearCombination y = {b, 0, 1};
return extendedGCDRec(x, y);
}In extendedGCD, we first check whether both a and b are zero. If that's the case, the GCD is undefined, so we return a linear combination with the sentinel value -1 to indicate that.
Then, we check whether a is zero. If that's the case, the GCD is simply b with s = 0 and t = 1.
Otherwise, we express the initial values of x and y as a linear combinations of a and b, and call extendedGCDRec, which is the recursive function that does all the work.
In extendedGCDRec, we check if y is zero. If that's the case, we found the GCD, which is x.
Otherwise, we compute the remainder and its coefficients s and t.
Then, we call the function recursively with y becoming the new x and r becoming the new y.
We keep doing this until we reach a zero-remainder, in which case the condition y == 0 will be true and we return the last non-zero remainder x.