Skip to content

Commit 5f708bc

Browse files
williamfisetclaude
andcommitted
Refactor ExtendedEuclideanAlgorithm and ModularInverse: add docs, clean up
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a1306d8 commit 5f708bc

File tree

3 files changed

+66
-43
lines changed

3 files changed

+66
-43
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ $ java -cp classes com.williamfiset.algorithms.search.BinarySearch
242242
- [[UNTESTED] Chinese remainder theorem](src/main/java/com/williamfiset/algorithms/math/ChineseRemainderTheorem.java)
243243
- [Prime number sieve (sieve of Eratosthenes)](src/main/java/com/williamfiset/algorithms/math/SieveOfEratosthenes.java) **- O(nlog(log(n)))**
244244
- [Prime number sieve (sieve of Eratosthenes, compressed)](src/main/java/com/williamfiset/algorithms/math/CompressedPrimeSieve.java) **- O(nlog(log(n)))**
245-
- [Totient function (phi function, relatively prime number count)](src/main/java/com/williamfiset/algorithms/math/EulerTotientFunction.java) **- O(n<sup>1/4</sup>)**
245+
- [Totient function (phi function, relatively prime number count)](src/main/java/com/williamfiset/algorithms/math/EulerTotientFunction.java) **- O(√n)**
246246
- [Totient function using sieve (phi function, relatively prime number count)](src/main/java/com/williamfiset/algorithms/math/EulerTotientFunctionWithSieve.java) **- O(nlog(log(n)))**
247247
- [Extended euclidean algorithm](src/main/java/com/williamfiset/algorithms/math/ExtendedEuclideanAlgorithm.java) **- ~O(log(a + b))**
248248
- [Greatest Common Divisor (GCD)](src/main/java/com/williamfiset/algorithms/math/Gcd.java) **- ~O(log(a + b))**
Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,39 @@
1-
/** Time Complexity ~O(log(a + b)) */
1+
/**
2+
* Extended Euclidean Algorithm. Given two integers a and b, computes gcd(a, b) and finds integers x
3+
* and y such that ax + by = gcd(a, b). Useful for finding modular inverses and solving linear
4+
* Diophantine equations.
5+
*
6+
* <p>Time: ~O(log(a + b))
7+
*
8+
* @author William Fiset, william.alexandre.fiset@gmail.com
9+
*/
210
package com.williamfiset.algorithms.math;
311

412
public class ExtendedEuclideanAlgorithm {
513

6-
// This function performs the extended euclidean algorithm on two numbers a and b.
7-
// The function returns the gcd(a,b) as well as the numbers x and y such
8-
// that ax + by = gcd(a,b). This calculation is important in number theory
9-
// and can be used for several things such as finding modular inverses and
10-
// solutions to linear Diophantine equations.
14+
/**
15+
* Performs the extended Euclidean algorithm on a and b.
16+
*
17+
* @return an array [gcd(a, b), x, y] such that ax + by = gcd(a, b).
18+
*/
1119
public static long[] egcd(long a, long b) {
12-
if (b == 0) return new long[] {a, 1, 0};
13-
else {
14-
long[] ret = egcd(b, a % b);
15-
long tmp = ret[1] - ret[2] * (a / b);
16-
ret[1] = ret[2];
17-
ret[2] = tmp;
18-
return ret;
19-
}
20+
if (b == 0)
21+
return new long[] {a, 1, 0};
22+
long[] ret = egcd(b, a % b);
23+
long tmp = ret[1] - ret[2] * (a / b);
24+
ret[1] = ret[2];
25+
ret[2] = tmp;
26+
return ret;
27+
}
28+
29+
public static void main(String[] args) {
30+
// egcd(35, 15) = [5, 1, -2] because gcd(35,15)=5 and 35*1 + 15*(-2) = 5.
31+
long[] result = egcd(35, 15);
32+
System.out.printf("gcd(%d, %d) = %d, x = %d, y = %d\n", 35, 15, result[0], result[1], result[2]);
33+
34+
// Finding modular inverse: 7^(-1) mod 11 = 8 because 7*8 mod 11 = 1.
35+
long[] inv = egcd(7, 11);
36+
long modInverse = ((inv[1] % 11) + 11) % 11;
37+
System.out.printf("7^(-1) mod 11 = %d\n", modInverse);
2038
}
2139
}
Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,51 @@
1-
/** Time Complexity ~O(log(a + b)) */
1+
/**
2+
* Computes the modular inverse of a number using the Extended Euclidean Algorithm.
3+
*
4+
* <p>The modular inverse of 'a' mod 'm' is a value x such that a*x ≡ 1 (mod m). It exists if and
5+
* only if gcd(a, m) = 1 (i.e. a and m are coprime).
6+
*
7+
* <p>Time: ~O(log(a + m))
8+
*
9+
* @author William Fiset, william.alexandre.fiset@gmail.com
10+
*/
211
package com.williamfiset.algorithms.math;
312

413
public class ModularInverse {
514

6-
// This function performs the extended euclidean algorithm on two numbers a and b.
7-
// The function returns the gcd(a,b) as well as the numbers x and y such
8-
// that ax + by = gcd(a,b). This calculation is important in number theory
9-
// and can be used for several things such as finding modular inverses and
10-
// solutions to linear Diophantine equations.
15+
/**
16+
* Returns the modular inverse of 'a' mod 'm', or null if it does not exist.
17+
*
18+
* @param a the value to invert.
19+
* @param m the modulus (must be positive).
20+
* @return the modular inverse, or null if gcd(a, m) != 1.
21+
* @throws ArithmeticException if m is not positive.
22+
*/
23+
public static Long modInv(long a, long m) {
24+
if (m <= 0)
25+
throw new ArithmeticException("mod must be > 0");
26+
a = ((a % m) + m) % m;
27+
long[] v = egcd(a, m);
28+
if (v[0] != 1)
29+
return null;
30+
return ((v[1] % m) + m) % m;
31+
}
32+
33+
// Returns [gcd(a, b), x, y] such that ax + by = gcd(a, b).
1134
private static long[] egcd(long a, long b) {
12-
if (b == 0) return new long[] {a, 1L, 0L};
35+
if (b == 0)
36+
return new long[] {a, 1, 0};
1337
long[] v = egcd(b, a % b);
1438
long tmp = v[1] - v[2] * (a / b);
1539
v[1] = v[2];
1640
v[2] = tmp;
1741
return v;
1842
}
1943

20-
// Returns the modular inverse of 'a' mod 'm' if it exists.
21-
// Make sure m > 0 and 'a' & 'm' are relatively prime.
22-
public static Long modInv(long a, long m) {
23-
24-
if (m <= 0) throw new ArithmeticException("mod must be > 0");
25-
26-
// Avoid a being negative
27-
a = ((a % m) + m) % m;
28-
29-
long[] v = egcd(a, m);
30-
long gcd = v[0];
31-
long x = v[1];
32-
33-
if (gcd != 1) return null;
34-
return ((x + m) % m) % m;
35-
}
36-
3744
public static void main(String[] args) {
38-
39-
// Prints 3 since 2*3 mod 5 = 1
45+
// 2*3 mod 5 = 1, so modInv(2, 5) = 3.
4046
System.out.println(modInv(2, 5));
4147

42-
// Prints null because there is no
43-
// modular inverse such that 4*x mod 18 = 1
48+
// gcd(4, 18) != 1, so no inverse exists.
4449
System.out.println(modInv(4, 18));
4550
}
4651
}

0 commit comments

Comments
 (0)