-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathextended_gcd.cpp
113 lines (98 loc) · 2.78 KB
/
extended_gcd.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
The extended Euclidean algorithm is an extension to the Euclidean algorithm,
which computes, besides the greatest common divisor of integers a and b, the
coefficients of Bézout's identity, that is integers x and y such that
a * x + b * y = gcd(a,b).
https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
*/
// return gcd(a ,b)
// recursive version
int extended_gcd(int a, int b, int &x, int &y) {
// basic case
if (0 == b) {
x = 1;
y = 0;
return a;
}
// recursive
int r = extended_gcd(b, a % b, x, y);
int t = y;
y = x - (a / b) * y;
x = t;
return r;
}
// The standard Euclidean algorithm (non-recursive)
int extended_gcd(int a, int b, int &x, int &y) {
x = 1;
y = 0;
if (0 == b) return a;
int new_x = 0;
int new_y = 1;
int new_r = b;
int r = a;
int quotient, tmp;
while (new_r) {
quotient = r / new_r;
tmp = r;
r = new_r;
new_r = tmp - quotient * new_r;
tmp = x;
x = new_x;
new_x = tmp - quotient * new_x;
tmp = y;
y = new_y;
new_y = tmp - quotient * new_y;
}
return r;
}
// Applications
/*
1. Computing modular inverse
If a and n are relatively prime, there exist integers x and y such that
a * x + n * y = 1, and such integers may be found using the Euclidean
algorithm. Considering this equation modulo n, it follows that a * x = 1; i.e.,
x = a^(-1)(mod n).
*/
int modular_inverse(int a, int n) {
int x, y;
int r = extended_gcd(a, n, x, y);
if (r > 1) {
printf("a is not invertible\n");
return -1;
}
// If a and b are both positive, we have
// |x| < b / gcd(a, b) and |y| < a / gcd(a, b)
return x < 0 ? x + n : x;
}
/*
2. Solving a linear Diophantine equation ax + by = c,
for a, b and c are known, solve x and y.
*/
bool linear_Diophantine_equation(int a, int b, int &x, int &y) {
int d = extended_gcd(a, b, x, y);
if (c % d) return false;
int k = c / d;
x *= k;
y *= k; // get one of the solutions
return true;
}
/*
3. Solving a linear congruence equation a * x = b (mod n).
It is solvable iff the congruence b = 0 (mod d) with
d = gcd(a, n) is solvable.
In that case, if we find x0 that satisfies this congruence,
then all the solutions can be formed from {x0 + k * n / d | k ∈ Z},
where d = gcd(a, n). There are exactly d solutions in the complete
residue system modulo n, namely {0, 1, ..., n - 1}.
*/
bool linear_congruence_equation(int a, int b, int n) {
int x, y;
int d = extended_gcd(a, n, x, y);
if (b % d) // no solutions
return false;
int x0 = x * (b / d) % n; // particular solution
for (int i = 1; i < d; ++i) {
printf("%d\n", (x0 + i * (n / d)) % n);
}
return true;
}