Skip to content

Commit bc0b1d3

Browse files
authored
Added Modular Inverse (keon#721)
1 parent 7370b8d commit bc0b1d3

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ If you want to uninstall algorithms, it is as simple as:
210210
- [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py)
211211
- [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py)
212212
- [modular_exponential](algorithms/maths/modular_exponential.py)
213+
- [modular_inverse](algorithms/maths/modular_inverse.py)
213214
- [next_bigger](algorithms/maths/next_bigger.py)
214215
- [next_perfect_square](algorithms/maths/next_perfect_square.py)
215216
- [nth_digit](algorithms/maths/nth_digit.py)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# extended_gcd(a, b) modified from
2+
# https://github.com/keon/algorithms/blob/master/algorithms/maths/extended_gcd.py
3+
4+
def extended_gcd(a: int, b: int) -> [int, int, int]:
5+
"""Extended GCD algorithm.
6+
Return s, t, g
7+
such that a * s + b * t = GCD(a, b)
8+
and s and t are co-prime.
9+
"""
10+
11+
old_s, s = 1, 0
12+
old_t, t = 0, 1
13+
old_r, r = a, b
14+
15+
while r != 0:
16+
quotient = old_r // r
17+
18+
old_r, r = r, old_r - quotient * r
19+
old_s, s = s, old_s - quotient * s
20+
old_t, t = t, old_t - quotient * t
21+
22+
return old_s, old_t, old_r
23+
24+
25+
def modular_inverse(a: int, m: int) -> int:
26+
"""
27+
Returns x such that a * x = 1 (mod m)
28+
a and m must be coprime
29+
"""
30+
31+
s, t, g = extended_gcd(a, m)
32+
if g != 1:
33+
raise ValueError("a and m must be coprime")
34+
return s % m

tests/test_maths.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
gcd, lcm, trailing_zero, gcd_bit,
99
gen_strobogrammatic, strobogrammatic_in_range,
1010
is_strobogrammatic, is_strobogrammatic2,
11+
modular_inverse,
1112
modular_exponential,
1213
find_next_square, find_next_square2,
1314
prime_check,
@@ -166,6 +167,21 @@ def test_is_strobogrammatic2(self):
166167
self.assertFalse(is_strobogrammatic2("14"))
167168

168169

170+
class TestModularInverse(unittest.TestCase):
171+
"""[summary]
172+
Test for the file modular_Exponential.py
173+
174+
Arguments:
175+
unittest {[type]} -- [description]
176+
"""
177+
178+
def test_modular_inverse(self):
179+
# checks if x * x_inv == 1 (mod m)
180+
self.assertEqual(1, 2 * modular_inverse.modular_inverse(2, 19) % 19)
181+
self.assertEqual(1, 53 * modular_inverse.modular_inverse(53, 91) % 91)
182+
self.assertEqual(1, 2 * modular_inverse.modular_inverse(2, 1000000007) % 1000000007)
183+
self.assertRaises(ValueError, modular_inverse.modular_inverse, 2, 20)
184+
169185
class TestModularExponential(unittest.TestCase):
170186
"""[summary]
171187
Test for the file modular_Exponential.py

0 commit comments

Comments
 (0)