-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
Copy patheuclidean_algorithm_extended.c
154 lines (135 loc) · 3.81 KB
/
euclidean_algorithm_extended.c
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/**
* @{
* @file
* @brief Program to perform the [extended Euclidean
* algorithm](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm)
*
* @details The extended Euclidean algorithm, on top of finding the GCD (greatest common
* divisor) of two integers a and b, also finds the values x and y such that
* ax+by = gcd(a, b)
*/
#include <assert.h> /// for tests
#include <stdio.h> /// for IO
#include <stdlib.h> /// for div function and corresponding div_t struct
/**
* @brief a structure holding the values resulting from the extended Euclidean
* algorithm
*/
typedef struct euclidean_result
{
int gcd; ///< the greatest common divisor calculated with the Euclidean
///< algorithm
int x, y; ///< the values x and y such that ax + by = gcd(a, b)
} euclidean_result_t;
/**
* @brief gives queue-like behavior to an array of two ints, pushing an element
* onto the end and pushing one off the front
*
* @param arr an array of ints acting as a queue
* @param newval the value being pushed into arr
*
* @returns void
*/
static inline void xy_push(int arr[2], int newval)
{
arr[1] = arr[0];
arr[0] = newval;
}
/**
* @brief calculates the value of x or y and push those into the small 'queues'
*
* @details Both x and y are found by taking their value from 2 iterations ago minus the
* product of their value from 1 iteration ago and the most recent quotient.
*
* @param quotient the quotient from the latest iteration of the Euclidean
* algorithm
* @param prev the 'queue' holding the values of the two previous iterations
*
* @returns void
*/
static inline void calculate_next_xy(int quotient, int prev[2])
{
int next = prev[1] - (prev[0] * quotient);
xy_push(prev, next);
}
/**
* @brief performs the extended Euclidean algorithm on integer inputs a and b
*
* @param a first integer input
* @param b second integer input
*
* @returns euclidean_result_t containing the gcd, and values x and y such that
* ax + by = gcd
*/
euclidean_result_t extended_euclidean_algorithm(int a, int b)
{
int previous_remainder = 1;
int previous_x_values[2] = {0, 1};
int previous_y_values[2] = {1, 0};
div_t div_result;
euclidean_result_t result;
/* swap values of a and b */
if (abs(a) < abs(b))
{
a ^= b;
b ^= a;
a ^= b;
}
div_result.rem = b;
while (div_result.rem > 0)
{
div_result = div(a, b);
previous_remainder = b;
a = b;
b = div_result.rem;
calculate_next_xy(div_result.quot, previous_x_values);
calculate_next_xy(div_result.quot, previous_y_values);
}
result.gcd = previous_remainder;
result.x = previous_x_values[1];
result.y = previous_y_values[1];
return result;
}
/** @} */
/**
* @brief perform one single check on the result of the algorithm with provided
* parameters and expected output
*
* @param a first paramater for Euclidean algorithm
* @param b second parameter for Euclidean algorithm
* @param gcd expected value of result.gcd
* @param x expected value of result.x
* @param y expected value of result.y
*
* @returns void
*/
static inline void single_test(int a, int b, int gcd, int x, int y)
{
euclidean_result_t result;
result = extended_euclidean_algorithm(a, b);
assert(result.gcd == gcd);
assert(result.x == x);
assert(result.y == y);
}
/**
* @brief Perform tests on known results
* @returns void
*/
static void test()
{
single_test(40, 27, 1, -2, 3);
single_test(71, 41, 1, -15, 26);
single_test(48, 18, 6, -1, 3);
single_test(99, 303, 3, -16, 49);
single_test(14005, 3507, 1, -305, 1218);
printf("All tests have successfully passed!\n");
}
/**
* @brief Main Function
* @returns 0 upon successful program exit
*/
int main()
{
test(); // run self-test implementations
return 0;
}