mirror of
https://github.com/TheAlgorithms/C
synced 2024-11-21 21:11:57 +03:00
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
154
math/euclidean_algorithm_extended.c
Normal file
154
math/euclidean_algorithm_extended.c
Normal file
@ -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
Block a user