8000 Iterative version of the Extended Euclid · cp-algorithms/cp-algorithms@4c378de · GitHub
[go: up one dir, main page]

Skip to content

Commit 4c378de

Browse files
committed
Iterative version of the Extended Euclid
See #532
1 parent 15d121a commit 4c378de

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

src/algebra/extended-euclid-algorithm.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,37 @@ The recursive function above returns the GCD and the values of coefficients to `
6969
7070
This implementation of extended Euclidean algorithm produces correct results for negative integers as well.
7171
72+
## Iterative version
73+
74+
It's also possible to write the Extended Euclidean algorithm in an iterative way.
75+
Because we it avoids recursion, the code will run a little bit faster than the recursive one.
76+
77+
```cpp extended_gcd_iter
78+
int gcd(int a, int b, int &x, int &y) {
79+
x = 1, y = 0;
80+
int x1 = 0, y1 = 1, a1 = a, b1 = b;
81+
while (b1) {
82+
int q = a1 / b1;
83+
tie(x, x1) = make_tuple(x1, x - q * x1);
84+
tie(y, y1) = make_tuple(y1, y - q * y1);
85+
tie(a1, b1) = make_tuple(b1, a1 - q * b1);
86+
}
87+
return a1;
88+
}
89+
```
90+
91+
If you look at the variable `a1` and `b1`, they taking exactly the same values as in the iterative version of the normal [Euclidean algorithm](algebra/euclid-algorithm.html).
92+
93+
To see why the algorithm work, you can check that the following invariants will at all time (before the while loop, and at the end of each iteration): $x \cdot a + y \cdot b = a_1$ and $x_1 \cdot a + y_1 \cdot b = b_1$.
94+
It's trivial to see, that these two equations are satisfied at the beginning.
95+
And you can check that the update in the loop iteration will still keep those equalities valid.
96+
97+
At the end we know that $a_1$ contains the GCD, so $x \cdot a + y \cdot b = g$.
98+
Which means that we have found the required coefficients.
99+
100+
You can even optimize the code more, and remove the variable $a_1$ and $b_1$ from the code, and just r 10000 euse $a$ and $b$.
101+
However if you do so, you loose the ability to argue about the invariants.
102+
72103
## Practice Problems
73104

74105
* [10104 - Euclid Problem](https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1045)

test/test_extended_gcd.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
#include <iostream>
22
#include <vector>
33
#include <cassert>
4+
#include <tuple>
45
using namespace std;
56

67
namespace e_maxx {
78
#include "extended_gcd.h"
89
}
910

11+
namespace e_maxx_iter {
12+
#include "extended_gcd_iter.h"
13+
}
14+
1015
namespace std {
1116
int gcd(int a, int b) {
1217
return b ? gcd(b, a % b) : a;
@@ -17,7 +22,7 @@ int main() {
1722
ios_base::sync_with_stdio(false);
1823
cin.tie(nullptr);
1924

20-
vector<int> numbers = {11, 30, 24, 32, 50, 23, 11, 40, 47, 15, 30, 31, 13, 19, 23, 37, 48, 29, 37, 22};
25+
vector<int> numbers = {11, 30, 24, 32, 50, 23, 11, 40, 47, 15, 30, 31, 0, 19, 23, 37, 48, 29, 37, 22};
2126
for (auto i = 0u; i + 1 < numbers.size(); i++) {
2227
int a = numbers[i];
2328
int b = numbers[i + 1];
@@ -26,5 +31,9 @@ int main() {
2631
int g = e_maxx::gcd(a, b, x, y);
2732
assert(g == std::gcd(a, b));
2833
assert(x * a + y * b == g);
34+
35+
g = e_maxx_iter::gcd(a, b, x, y);
36+
assert(g == std::gcd(a, b));
37+
assert(x * a + y * b == g);
2938
}
3039
}

0 commit comments

Comments
 (0)
0