mirror of https://github.com/TheAlgorithms/C
feat: added extended Euclidean algorithm (#1238)
* chore: made it so math directory gets built * feat: added extended Euclidean algorithm * docs: added details qualifier Co-authored-by: David Leal <halfpacho@gmail.com> * docs: added param qualifiers to functions that needed them * docs: added details qualifier Co-authored-by: David Leal <halfpacho@gmail.com> * docs: small cleanup --------- Co-authored-by: David Leal <halfpacho@gmail.com>
This commit is contained in:
parent
e1fcdd2a04
commit
0a5f5c61f7
|
@ -0,0 +1,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;
|
||||
}
|
Loading…
Reference in New Issue