def test_ext_gcd(self): self.assertEqual(ext_gcd(5, 7), (3, -2, 1)) self.assertEqual(ext_gcd(12, 10), (1, -1, 2)) self.assertEqual(ext_gcd(12, -18), (-1, -1, 6)) self.assertEqual(ext_gcd(-3, -1), (0, -1, 1)) for i in xrange(20): x = random.randint(10, 100) y = random.randint(10, 100) (a, b, d) = ext_gcd(x, y) self.assertEqual(a*x + b*y, d)
def linear_congruence(a, b, n): """Returns a list of the solutions x to the congruence a*x = b (mod n). Input: * a: int * b: int * n: int (n > 1) Returns: * solutions: list Raises: * ValueError: if n <= 1. Examples: >>> linear_congruence(10, 6, 12) [3, 9] >>> linear_congruence(12, 9, 15) [2, 7, 12] >>> linear_congruence(10, 3, 12) [] >>> linear_congruence(10, 3, 0) Traceback (most recent call last): ... ValueError: linear_congruence: Must have n >= 2. Details: The linear congruence a*x = b (mod n) has a solution if and only if d = gcd(a, n) divides b. This function uses a straightforward application of this theorem. See Theorem 3.7 from "Elementary Number Theory" By Jones and Jones for details. """ if n < 2: raise ValueError("linear_congruence: Must have n >= 2.") (u, v, d) = ext_gcd(a, n) # The congruence has a solution if and only if gcd(a, n) | b. if b % d != 0: return [] # x0 is our particular solution. # There will be exactly d incongruent solutions modulo n. x0 = b * u // d solutions = [(x0 + k * n // d) % n for k in xrange(d)] solutions.sort() return solutions
def linear_congruence(a, b, n): """Returns a list of the solutions x to the congruence a*x = b (mod n). Input: * a: int * b: int * n: int (n > 1) Returns: * solutions: list Raises: * ValueError: if n <= 1. Examples: >>> linear_congruence(10, 6, 12) [3, 9] >>> linear_congruence(12, 9, 15) [2, 7, 12] >>> linear_congruence(10, 3, 12) [] >>> linear_congruence(10, 3, 0) Traceback (most recent call last): ... ValueError: linear_congruence: Must have n >= 2. Details: The linear congruence a*x = b (mod n) has a solution if and only if d = gcd(a, n) divides b. This function uses a straightforward application of this theorem. See Theorem 3.7 from "Elementary Number Theory" By Jones and Jones for details. """ if n < 2: raise ValueError("linear_congruence: Must have n >= 2.") (u, v, d) = ext_gcd(a, n) # The congruence has a solution if and only if gcd(a, n) | b. if b % d != 0: return [] # x0 is our particular solution. # There will be exactly d incongruent solutions modulo n. x0 = b*u//d solutions = [(x0 + k*n//d) % n for k in xrange(d)] solutions.sort() return solutions