From 0ce40710ca76ad5e34e16cfc1a76290c136514f7 Mon Sep 17 00:00:00 2001 From: Rohith Date: Thu, 11 Dec 2025 16:41:42 +0530 Subject: [PATCH 1/5] add improved binary_exponentiation --- math/binary_exponent.cpp | 120 ++++++++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 41 deletions(-) diff --git a/math/binary_exponent.cpp b/math/binary_exponent.cpp index 05e6f33f7ae..6b85b6ad5d7 100644 --- a/math/binary_exponent.cpp +++ b/math/binary_exponent.cpp @@ -2,70 +2,108 @@ * @file * @brief C++ Program to find Binary Exponent Iteratively and Recursively. * - * Calculate \f$a^b\f$ in \f$O(\log(b))\f$ by converting \f$b\f$ to a + * Calculate a^b in O(log(b)) by converting b to a * binary number. Binary exponentiation is also known as exponentiation by * squaring. * @note This is a far better approach compared to naive method which - * provide \f$O(b)\f$ operations. + * provide O(b) operations. * * Example: - *
10 in base 2 is 1010. - * \f{eqnarray*}{ - * 2^{10_d} &=& 2^{1010_b} = 2^8 * 2^2\\ - * 2^1 &=& 2\\ - * 2^2 &=& (2^1)^2 = 2^2 = 4\\ - * 2^4 &=& (2^2)^2 = 4^2 = 16\\ - * 2^8 &=& (2^4)^2 = 16^2 = 256\\ + * 10 in base 2 is 1010. + * {eqnarray*}{ + * 2^{10_d} = 2^{1010_b} = 2^8 * 2^2\\ + * 2^1 = 2\\ + * 2^2 = (2^1)^2 = 2^2 = 4\\ṇ + * 2^4 = (2^2)^2 = 4^2 = 16\\ + * 2^8 = (2^4)^2 = 16^2 = 256\\ * \f} - * Hence to calculate 2^10 we only need to multiply \f$2^8\f$ and \f$2^2\f$ - * skipping \f$2^1\f$ and \f$2^4\f$. + * Hence to calculate 2^10 we only need to multiply 2^8 and 2^2 + * skipping 2^1 and 2^4. */ #include +using namespace std; -/// Recursive function to calculate exponent in \f$O(\log(n))\f$ using binary +/// Recursive function to calculate exponent in O(log(n)) using binary /// exponent. -int binExpo(int a, int b) { - if (b == 0) { +// Use long long for avoiding overflow. +long long binary_exponent_recursive(long long base, long long exponent) { + if (exponent == 0) { return 1; } - int res = binExpo(a, b / 2); - if (b % 2) { - return res * res * a; + long long half = binary_exponent_recursive(base, exponent / 2); + if (exponent % 2) { + return half * half * base; } else { - return res * res; + return half * half; } } /// Iterative function to calculate exponent in \f$O(\log(n))\f$ using binary /// exponent. -int binExpo_alt(int a, int b) { - int res = 1; - while (b > 0) { - if (b % 2) { - res = res * a; +/// Use long long for avoiding Overflow +long long binary_exponent_iterative(long long base, long long exponent) { + long long res = 1; + while (exponent > 0) { + if (exponent % 2) { + res *= base; } - a = a * a; - b /= 2; + base = base * base; + exponent >>= 1; } return res; } -/// Main function -int main() { - int a, b; - /// Give two numbers a, b - std::cin >> a >> b; - if (a == 0 && b == 0) { - std::cout << "Math error" << std::endl; - } else if (b < 0) { - std::cout << "Exponent must be positive !!" << std::endl; - } else { - int resRecurse = binExpo(a, b); - /// int resIterate = binExpo_alt(a, b); +//@brief Self-test examples for verifying +void test() { + // Test 0 + long long expected0 = 1024; + cout << "Test 0" << endl; + cout << "Input: base = 2 and exponent = 10" << endl; + cout << "Expected: " << expected0 << endl; + cout << "Recursive: " << binary_exponent_recursive(2, 10) << endl; + cout << "Iterative: " << binary_exponent_iterative(2, 10) << endl; + cout << endl; - /// Result of a^b (where '^' denotes exponentiation) - std::cout << resRecurse << std::endl; - /// std::cout << resIterate << std::endl; - } + // Test 1 + long long expected1 = 2187; + cout << "Test 1" << endl; + cout << "Input: base = 3 and exponent = 7" << endl; + cout << "Expected: " << expected1 << endl; + cout << "Recursive: " << binary_exponent_recursive(3, 7) << endl; + cout << "Iterative: " << binary_exponent_iterative(3, 7) << endl; + cout << endl; + + // Test 2 + long long expected2 = 16777216; + cout << "Test 2" << endl; + cout << "Input: base = 4 and exponent = 12" << endl; + cout << "Expected: " << expected2 << endl; + cout << "Recursive: " << binary_exponent_recursive(4, 12) << endl; + cout << "Iterative: " << binary_exponent_iterative(4, 12) << endl; + cout << endl; + + // Test 3 + long long expected3 = 30517578125; + cout << "Test 3" << endl; + cout << "Input: base = 5 and exponent = 15" << endl; + cout << "Expected: " << expected3 << endl; + cout << "Recursive: " << binary_exponent_recursive(5, 15) << endl; + cout << "Iterative: " << binary_exponent_iterative(5, 15) << endl; + cout << endl; + + // Test 4 + long long expected4 = 3656158440062976; + cout << "Test 4" << endl; + cout << "Input: base = 6 and exponent = 20" << endl; + cout << "Expected: " << expected4 << endl; + cout << "Recursive: " << binary_exponent_recursive(6, 20) << endl; + cout << "Iterative: " << binary_exponent_iterative(6, 20) << endl; + cout << endl; } + +/// Main function +int main() { + test(); // run self-test examples + return 0; +} \ No newline at end of file From 73de14fe678df446cd2d3cd68c95ec0c382397a3 Mon Sep 17 00:00:00 2001 From: Rohith Date: Thu, 11 Dec 2025 16:43:53 +0530 Subject: [PATCH 2/5] feat: add improved binary_exponentiation --- math/binary_exponent.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/math/binary_exponent.cpp b/math/binary_exponent.cpp index 6b85b6ad5d7..893968a5ad9 100644 --- a/math/binary_exponent.cpp +++ b/math/binary_exponent.cpp @@ -103,6 +103,7 @@ void test() { } /// Main function +// returns 0 in case of no error. int main() { test(); // run self-test examples return 0; From da43ec4236862542874fdee0fd370500053b628a Mon Sep 17 00:00:00 2001 From: Rohith Date: Thu, 11 Dec 2025 18:16:38 +0530 Subject: [PATCH 3/5] feat: add improved binary_exponentiation --- math/binary_exponent.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/math/binary_exponent.cpp b/math/binary_exponent.cpp index 893968a5ad9..c3f4a7c84d6 100644 --- a/math/binary_exponent.cpp +++ b/math/binary_exponent.cpp @@ -2,23 +2,27 @@ * @file * @brief C++ Program to find Binary Exponent Iteratively and Recursively. * - * Calculate a^b in O(log(b)) by converting b to a + * Calculate \f$a^b\f$ in \f$O(\log(b))\f$ by converting \f$b\f$ to a * binary number. Binary exponentiation is also known as exponentiation by * squaring. - * @note This is a far better approach compared to naive method which - * provide O(b) operations. + * + * @note This is a far better approach compared to the naive method which + * provides \f$O(b)\f$ operations. * * Example: + * * 10 in base 2 is 1010. - * {eqnarray*}{ - * 2^{10_d} = 2^{1010_b} = 2^8 * 2^2\\ - * 2^1 = 2\\ - * 2^2 = (2^1)^2 = 2^2 = 4\\ṇ - * 2^4 = (2^2)^2 = 4^2 = 16\\ - * 2^8 = (2^4)^2 = 16^2 = 256\\ + * + * \f{eqnarray*}{ + * 2^{10_d} &=& 2^{1010_b} = 2^8 \cdot 2^2 \\ + * 2^1 &=& 2 \\ + * 2^2 &=& (2^1)^2 = 4 \\ + * 2^4 &=& (2^2)^2 = 16 \\ + * 2^8 &=& (2^4)^2 = 256 \\ * \f} - * Hence to calculate 2^10 we only need to multiply 2^8 and 2^2 - * skipping 2^1 and 2^4. + * + * Hence to calculate \f$2^{10}\f$, we only need to multiply \f$2^8\f$ and + * \f$2^2\f$, skipping \f$2^1\f$ and \f$2^4\f$. */ #include From e8276231fb3a4a008a6f29d564fbb6ac32f77ea4 Mon Sep 17 00:00:00 2001 From: Rohith Date: Thu, 11 Dec 2025 19:10:33 +0530 Subject: [PATCH 4/5] Major rework to improve code quality and add automation checks --- math/extended_euclid_algorithm.cpp | 172 +++++++++++++++++------------ 1 file changed, 100 insertions(+), 72 deletions(-) diff --git a/math/extended_euclid_algorithm.cpp b/math/extended_euclid_algorithm.cpp index cc2eacac8e3..2ca38bad176 100644 --- a/math/extended_euclid_algorithm.cpp +++ b/math/extended_euclid_algorithm.cpp @@ -1,97 +1,125 @@ /** * @file - * @brief GCD using [extended Euclid's algorithm] + * @brief GCD using extended Euclid's algorithm * (https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm) * - * Finding coefficients of a and b ie x and y in Bézout's identity - * \f[\text{gcd}(a, b) = a \times x + b \times y \f] - * This is also used in finding Modular - * multiplicative inverse of a number. (A * B)%M == 1 Here B is the MMI of A for - * given M, so extendedEuclid (A, M) gives B. + * Finding coefficients x and y for Bézout's identity: + * \f[ + * \gcd(a, b) = a \times x + b \times y + * \f] + * + * This algorithm is also used to compute the Modular Multiplicative Inverse + * (MMI). If (A × B) % M == 1, then B is MMI(A, M), and + * extended_euclid_recursive(A, M) provides B. */ -#include // for swap function + #include -#include +using namespace std; /** - * function to update the coefficients per iteration - * \f[r_0,\,r = r,\, r_0 - \text{quotient}\times r\f] + * @brief Recursive Extended Euclid Algorithm + * + * Computes gcd(a, b) along with coefficients x and y such that: + * \f[ + * a \times x + b \times y = \gcd(a, b) + * \f] * - * @param[in,out] r signed or unsigned - * @param[in,out] r0 signed or unsigned - * @param[in] quotient unsigned + * @param[in] a first number + * @param[in] b second number + * @param[out] gcd greatest common divisor + * @param[out] x coefficient of a + * @param[out] y coefficient of b */ -template -inline void update_step(T *r, T *r0, const T2 quotient) { - T temp = *r; - *r = *r0 - (quotient * temp); - *r0 = temp; +void extended_euclid_recursive(long long a, long long b, long long& gcd, + long long& x, long long& y) { + if (b == 0) { + gcd = a; + x = 1; + y = 0; + return; + } + + long long x1, y1; + extended_euclid_recursive(b, a % b, gcd, x1, y1); + + x = y1; + y = x1 - (a / b) * y1; } /** - * Implementation using iterative algorithm from - * [Wikipedia](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Pseudocode) + * @brief Iterative Extended Euclid Algorithm * - * @param[in] A unsigned - * @param[in] B unsigned - * @param[out] GCD unsigned - * @param[out] x signed - * @param[out] y signed + * Equivalent to the recursive version but performed iteratively. */ -template -void extendedEuclid_1(T1 A, T1 B, T1 *GCD, T2 *x, T2 *y) { - if (B > A) - std::swap(A, B); // Ensure that A >= B - - T2 s = 0, s0 = 1; - T2 t = 1, t0 = 0; - T1 r = B, r0 = A; - - while (r != 0) { - T1 quotient = r0 / r; - update_step(&r, &r0, quotient); - update_step(&s, &s0, quotient); - update_step(&t, &t0, quotient); +void extended_euclid_iterative(long long a, long long b, long long& gcd, + long long& x, long long& y) { + long long x0 = 1, y0 = 0, x1 = 0, y1 = 1; + + while (b != 0) { + long long q = a / b, temp = b; + b = a - q * b; + a = temp; + + temp = x1; + x1 = x0 - q * x1; + x0 = temp; + + temp = y1; + y1 = y0 - q * y1; + y0 = temp; } - *GCD = r0; - *x = s0; - *y = t0; + + gcd = a; + x = x0; + y = y0; } /** - * Implementation using recursive algorithm - * - * @param[in] A unsigned - * @param[in] B unsigned - * @param[out] GCD unsigned - * @param[in,out] x signed - * @param[in,out] y signed + * @brief Self-test examples in your preferred style */ -template -void extendedEuclid(T A, T B, T *GCD, T2 *x, T2 *y) { - if (B > A) - std::swap(A, B); // Ensure that A >= B - - if (B == 0) { - *GCD = A; - *x = 1; - *y = 0; - } else { - extendedEuclid(B, A % B, GCD, x, y); - T2 temp = *x; - *x = *y; - *y = temp - (A / B) * (*y); - } +void test() { + // Test 0 + long long gcd0, x0, y0; + cout << "Test 0" << endl; + cout << "Input: a = 30 and b = 20" << endl; + + extended_euclid_recursive(30, 20, gcd0, x0, y0); + cout << "Recursive => gcd: " << gcd0 << " x: " << x0 << " y: " << y0 + << endl; + + extended_euclid_iterative(30, 20, gcd0, x0, y0); + cout << "Iterative => gcd: " << gcd0 << " x: " << x0 << " y: " << y0 + << endl; + + // Test 1 + long long gcd1, x1, y1; + cout << "Test 1" << endl; + cout << "Input: a = 101 and b = 23" << endl; + + extended_euclid_recursive(101, 23, gcd1, x1, y1); + cout << "Recursive => gcd: " << gcd1 << " x: " << x1 << " y: " << y1 + << endl; + + extended_euclid_iterative(101, 23, gcd1, x1, y1); + cout << "Iterative => gcd: " << gcd1 << " x: " << x1 << " y: " << y1 + << endl; + + // Test 2 + long long gcd2, x2, y2; + cout << "Test 2" << endl; + cout << "Input: a = 55 and b = 34" << endl; + + extended_euclid_recursive(55, 34, gcd2, x2, y2); + cout << "Recursive => gcd: " << gcd2 << " x: " << x2 << " y: " << y2 + << endl; + + extended_euclid_iterative(55, 34, gcd2, x2, y2); + cout << "Iterative => gcd: " << gcd2 << " x: " << x2 << " y: " << y2 + << endl; } /// Main function int main() { - uint32_t a, b, gcd; - int32_t x, y; - std::cin >> a >> b; - extendedEuclid(a, b, &gcd, &x, &y); - std::cout << gcd << " " << x << " " << y << std::endl; - extendedEuclid_1(a, b, &gcd, &x, &y); - std::cout << gcd << " " << x << " " << y << std::endl; + test(); // run self-test examples return 0; -} +} \ No newline at end of file From c9656b47bb5049bf095c67c4b4550cb4be6496cd Mon Sep 17 00:00:00 2001 From: Rohith Date: Thu, 11 Dec 2025 19:16:42 +0530 Subject: [PATCH 5/5] feat: add improved binary_exponentiation --- math/extended_euclid_algorithm.cpp | 42 +++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/math/extended_euclid_algorithm.cpp b/math/extended_euclid_algorithm.cpp index 2ca38bad176..b7aca0a1912 100644 --- a/math/extended_euclid_algorithm.cpp +++ b/math/extended_euclid_algorithm.cpp @@ -19,11 +19,25 @@ using namespace std; /** * @brief Recursive Extended Euclid Algorithm * - * Computes gcd(a, b) along with coefficients x and y such that: + * This method recursively applies the idea that: * \f[ - * a \times x + b \times y = \gcd(a, b) + * \gcd(a, b) = \gcd(b,\, a \bmod b) * \f] * + * Each recursive step reduces the problem size by replacing (a, b) + * with (b, a % b). Once b becomes 0, the algorithm has reached the base + * case, where gcd = a and the Bézout coefficients (x, y) are known. + * + * On returning from recursion, the coefficients are updated in reverse + * order using: + * \f[ + * x = y_1,\qquad + * y = x_1 - \left\lfloor \frac{a}{b} \right\rfloor \cdot y_1 + * \f] + * + * This back-substitution step reconstructs the Bézout identity + * for the original pair (a, b). + * * @param[in] a first number * @param[in] b second number * @param[out] gcd greatest common divisor @@ -49,7 +63,29 @@ void extended_euclid_recursive(long long a, long long b, long long& gcd, /** * @brief Iterative Extended Euclid Algorithm * - * Equivalent to the recursive version but performed iteratively. + * This version performs the same transformations as the recursive method + * but unfolds the process into a loop. It repeatedly updates (a, b) + * using the identity: + * \f[ + * (a, b) \rightarrow (b,\; a - \lfloor a/b \rfloor \cdot b) + * \f] + * + * Alongside (a, b), it maintains two pairs of coefficients (x0, y0) and + * (x1, y1) which evolve according to the same quotient used during each + * division step. Once b becomes zero, the surviving values (x0, y0) + * form the Bézout coefficients: + * \f[ + * a \times x_0 + b_{\text{original}} \times y_0 = \gcd(a, b) + * \f] + * + * This approach avoids recursion and makes the sequence of updates + * easier to trace step-by-step. + * + * @param[in] a first number + * @param[in] b second number + * @param[out] gcd greatest common divisor + * @param[out] x coefficient of a + * @param[out] y coefficient of b */ void extended_euclid_iterative(long long a, long long b, long long& gcd, long long& x, long long& y) {