Solving modular linear congruences for large numbers

后端 未结 2 1568
后悔当初
后悔当初 2021-01-24 23:05

I\'m looking for a better algorithm than one I found on stackoverflow to handle 4096 byte numbers, i\'m hitting a maximum recursion depth.

Code from stackoverlow post, i

2条回答
  •  独厮守ぢ
    2021-01-24 23:45

    Suppose that for some reason the linear congruence equations you'll be 'attacking' come up 'empty' (no solutions) often enough to be a design criteria for your algorithm.

    It turns out that you can use just (with any real overhead) the residue operations to answer that binary question -

    There exist solutions XOR There are no solutions

    This might have utility in cryptography; see also the abstract,

    Introduction of the Residue Number Arithmetic Logic Unit
    With Brief Computational Complexity Analysis

    Once you determine that a solution exist, you can use back substitution
    and the ALU to determine a solution.

    Also, you'll have calculated the gcd(a,m) and can construct the coefficients of Bézout's identity
    (if you need them).

    Following is python program that incorporates the above ideas; it calculates the minimal solution when it exists and prints out Bézout's identity.

    test_data = [ \
    (32,12,82), \
    (9,3,23), \
    (17,41,73), \
    (227,1,2011), \
    (25,15,29), \
    (2,22,71), \
    (7,10,21), \
    (124,58,900), \
    (46, 12, 240), \
    ]
    
    for lc in test_data:
        LC = lc
        back_sub_List = []
        while True:
            back_sub_List.append(LC)
            n_mod_a = LC[2] % LC[0]
            if n_mod_a == 0:
                break
            LC = (n_mod_a, -LC[1] % LC[0], LC[0])
        gcd_of_a0_n0 = LC[0]
        if LC[1] % LC[0] != 0:
            print(f"No solution          for {back_sub_List[0][0]}x = {back_sub_List[0][1]} (mod {back_sub_List[0][2]})")
        else:
            k = 0
            for LC in back_sub_List[::-1]: # solve with back substitution
                a,b,m = LC
                k = (b + k*m) // a         # optimize calculation since the remainder is zero?
            print(f"The minimal solution for {back_sub_List[0][0]}x = {back_sub_List[0][1]} (mod {back_sub_List[0][2]}) is equal to {k}")
        # get bezout
        S = [1,0]
        T = [0,1]
        for LC in back_sub_List:    
            a,b,n = LC
            q = n // a
            s = S[0] - q * S[1]
            S = [S[1], s]
            t = T[0] - q * T[1]
            T = [T[1], t]
        print(f"  Bézout's identity:     ({S[0]})({lc[2]}) + ({T[0]})({lc[0]}) = {gcd_of_a0_n0}")
    

    PROGRAM OUTPUT

    The minimal solution for 32x = 12 (mod 82) is equal to 26
      Bézout's identity:     (-7)(82) + (18)(32) = 2
    The minimal solution for 9x = 3 (mod 23) is equal to 8
      Bézout's identity:     (2)(23) + (-5)(9) = 1
    The minimal solution for 17x = 41 (mod 73) is equal to 11
      Bézout's identity:     (7)(73) + (-30)(17) = 1
    The minimal solution for 227x = 1 (mod 2011) is equal to 1320
      Bézout's identity:     (78)(2011) + (-691)(227) = 1
    The minimal solution for 25x = 15 (mod 29) is equal to 18
      Bézout's identity:     (-6)(29) + (7)(25) = 1
    The minimal solution for 2x = 22 (mod 71) is equal to 11
      Bézout's identity:     (1)(71) + (-35)(2) = 1
    No solution          for 7x = 10 (mod 21)
      Bézout's identity:     (0)(21) + (1)(7) = 7
    No solution          for 124x = 58 (mod 900)
      Bézout's identity:     (4)(900) + (-29)(124) = 4
    The minimal solution for 46x = 12 (mod 240) is equal to 42
      Bézout's identity:     (-9)(240) + (47)(46) = 2
    

提交回复
热议问题