-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathSource.cpp
More file actions
140 lines (121 loc) · 3.98 KB
/
Copy pathSource.cpp
File metadata and controls
140 lines (121 loc) · 3.98 KB
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <stdio.h>
#include <algorithm>
#include <array>
//=================================================================================
unsigned int ExtendedEuclidianAlgorithm (int smaller, int larger, int &s, int &t)
{
// make sure A <= B before starting
bool swapped = false;
if (larger < smaller)
{
swapped = true;
std::swap(smaller, larger);
}
// set up our storage for the loop. We only need the last two values so will
// just use a 2 entry circular buffer for each data item
std::array<int, 2> remainders = { larger, smaller };
std::array<int, 2> ss = { 1, 0 };
std::array<int, 2> ts = { 0, 1 };
int indexNeg2 = 0;
int indexNeg1 = 1;
// loop
while (1)
{
// calculate our new quotient and remainder
int newQuotient = remainders[indexNeg2] / remainders[indexNeg1];
int newRemainder = remainders[indexNeg2] - newQuotient * remainders[indexNeg1];
// if our remainder is zero we are done.
if (newRemainder == 0)
{
// return our s and t values as well as the quotient as the GCD
s = ss[indexNeg1];
t = ts[indexNeg1];
if (swapped)
std::swap(s, t);
return remainders[indexNeg1];
}
// calculate this round's s and t
int newS = ss[indexNeg2] - newQuotient * ss[indexNeg1];
int newT = ts[indexNeg2] - newQuotient * ts[indexNeg1];
// store our values for the next iteration
remainders[indexNeg2] = newRemainder;
ss[indexNeg2] = newS;
ts[indexNeg2] = newT;
// move to the next iteration
std::swap(indexNeg1, indexNeg2);
}
}
//=================================================================================
void WaitForEnter ()
{
printf("\nPress Enter to quit");
fflush(stdin);
getchar();
}
//=================================================================================
int main(int argc, char **argv)
{
// get user input
int a, m, n;
printf("Given a, m and n, solves for X.\n(a * X) %% m = n\n\n");
printf("a = ");
scanf("%i", &a);
printf("m = ");
scanf("%i", &m);
printf("n = ");
scanf("%i", &n);
// show details of what they entered
printf("\n(%i * X) mod %i = %i\n", a, m, n);
// Attempt brute force
printf("\nBrute Force Testing X from 0 to %i:\n", (m-1));
for (int i = 0; i < m; ++i) {
if ((a*i) % m == n)
{
printf(" X = %i\n", i);
printf(" %i mod %i = %i\n", a*i, m, (a*i) % m);
break;
}
else if (i == (m - 1))
{
printf(" No solution!\n");
}
}
// Attempt inverse via Extended Euclidean Algorithm
printf("\nExtended Euclidean Algorithm:\n");
int s, t;
int GCD = ExtendedEuclidianAlgorithm(a, m, s, t);
// report failure if we couldn't do inverse
if (GCD != 1)
{
printf(" Values are not co-prime, cannot invert! GCD = %i\n", GCD);
}
// Else report details of inverse and show that it worked
else
{
printf(" Inverse = %i\n", t);
printf(" X = Inverse * n = %i\n", t*n);
printf(" %i mod %i = %i\n", a*t*n, m, (a*t*n) % m);
}
WaitForEnter();
return 0;
}
/*
TODO:
* blog post
* then chinese remainder theorem, which uses this!
Blog:
* Note that this post is a prerequisite for a future post
* talk about brute force and extended euclidian algorithm both5
* show a simple working run
* 7,9,2
* show a large number run
* 7, 1000001, 538
* show a run where inverse and then multiply is not the smallest value
* 5,7,3
* show something that works via brute force but isn't invertible. Like they aren't coprime but you want the mod to equal two anyways so doesnt matter.
* a,m,n = 8, 6, 4
LINKS:
* http://blog.demofox.org/2015/01/24/programmatically-calculating-gcd-and-lcm/
* https://en.wikipedia.org/wiki/Modular_multiplicative_inverse
* https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
*/