arnaucube
arnaucube/mathPublic Self-hosted repository
math/number-theory.sage
number-theory.sageRaw
  1# Chinese Remainder Theorem
  2def crt(a_i, m_i):
  3    if len(a_i)!=len(m_i):
  4        raise Exception("error, a_i and m_i must be of the same length")
  5
  6    M=1
  7    for i in range(len(m_i)):
  8        M = M * m_i[i]
  9
 10    x = 0
 11    for i in range(len(a_i)):
 12        M_i = M/m_i[i]
 13        y_i = Integer(mod(M_i^-1, m_i[i]))
 14        x = x + a_i[i] * M_i * y_i
 15    return mod(x, M)
 16
 17# gcd, using Binary Euclidean algorithm
 18def gcd(a, b):
 19    g=1
 20    # random_elementove powers of two from the gcd
 21    while mod(a, 2)==0 and mod(b, 2)==0:
 22        a=a/2
 23        b=b/2
 24        g=2*g
 25    # at least one of a and b is now odd
 26    while a!=0:
 27        while mod(a, 2)==0:
 28            a=a/2
 29        while mod(b, 2)==0:
 30            b=b/2
 31        # now both a and b are odd
 32        if a>=b:
 33            a = (a-b)/2
 34        else:
 35            b = (b-a)/2
 36
 37    return g*b
 38
 39def gcd_recursive(a, b):
 40    if mod(a, b)==0:
 41        return b
 42    return gcd_recursive(b, mod(a,b))
 43
 44
 45# Extended Euclidean algorithm
 46# Inputs: a, b
 47# Outputs: r, x, y, such that r = gcd(a, b) = x*a + y*b
 48def egcd(a, b):
 49    s=0
 50    s_=1
 51    t=1
 52    t_=0
 53    r=b
 54    r_=a
 55    while r!=0:
 56        q = r_ // r
 57        (r_,r) = (r,r_ - q*r)
 58        (s_,s) = (s,s_ - q*s)
 59        (t_,t) = (t,t_ - q*t)
 60    
 61    d = r_
 62    x = s_
 63    y = t_
 64    
 65    return d, x, y
 66
 67def egcd_recursive(a, b):
 68    if b==0:
 69        return a, 1, 0
 70
 71    g, x, y = egcd_recursive(b, a%b)
 72    return g, y, x - (a//b) * y
 73
 74# Inverse modulo N, using the Extended Euclidean algorithm
 75def inv_mod(a, N):
 76    g, x, y = egcd(a, N)
 77    if g != 1:
 78        raise Exception("inv_mod err, g!=1")
 79    return mod(x, N)
 80
 81# Tests
 82
 83#####
 84# Chinese Remainder Theorem tests
 85a_i = [5, 3, 10]
 86m_i = [7, 11, 13]
 87assert crt(a_i, m_i) == 894
 88
 89a_i = [3, 8]
 90m_i = [13, 17]
 91assert crt(a_i, m_i) == 42
 92
 93
 94#####
 95# gcd, using Binary Euclidean algorithm tests
 96assert gcd(21, 12) == 3
 97assert gcd(1_426_668_559_730, 810_653_094_756) == 1_417_082
 98
 99assert gcd_recursive(21, 12) == 3
100
101#####
102# Extended Euclidean algorithm tests
103assert egcd(7, 19) == (1, -8, 3)
104assert egcd_recursive(7, 19) == (1, -8, 3)
105
106#####
107# Inverse modulo N tests
108assert inv_mod(7, 19) == 11