欧几里得算法

参考:
https://zh.wikipedia.org/wiki/%E8%BC%BE%E8%BD%89%E7%9B%B8%E9%99%A4%E6%B3%95

序:
欧几里得算法又称辗转相除法, 用来求最大公约数的算法,之前学过,但仅仅是学过公式,并不知道有什么用,最近看RSA的公钥私钥生成原理,发现数学真实神奇,借此机会,深入了解一下。

  • 算法介绍:
    两个整数的最大公约数是能够同时整除它们的最大的正整数。假设两个整数a,b, 且 a > b, 根据辗转相除法迭代, 每次用 a mod b 的余数 替换b, 用b 替换a, 迭代知道 b == 0, 返回 a的值。
    推导演示:
大的那个数 小的那个数 余数
a b r0 = a%b q0
b r0 r1 = b% r0 q1
r0 r1 r2 = r0 % r1 q2
... ... ... ...
rN-4 rN-3 rN-2 = rN-4 % rN-3 qN-2
rN-3 rN-2 rN-1 = rN-3 % rN-2 qN-1
rN-2 rN-1 rN = rN-2 % rN-1 qN
rN-1 rN == 0 rN-1 = 1 * rN-1 - 0 * rN 0

得到的最大公约数就是rN-1

  • 证明:
    分为两步, 第一步证明rN-1 能够被 a, b整除, 第二步证明最大公约数g <= rN-1
    • 第一步基于我们表格的推导很容易:
      rN-2 = qN * rN-1 + rN = qN * rN-1
      rN-3 = qN-1 * rN-2 + rN-1 = qN-1 * qN * rN-1 + rN-1 = ( qN-1 * qN + 1) * rN-1
      ........
      r0 = q2 * r1 + r2
      b =q1 * r0 + r1
      a= q0 * b + r0
      所以 rN-3 也是可以被rN-1整除的
      以此类推, a, b 均能被rN-1 整除

    • 第二步证明rN-1是最大的:
      假设a, b的最大公约数是g, 即有:
      r0 = a%b = a - q0 * b =
      (m - q0 * n) * g
      即有a%b 的余数也是最大公约数g的倍数, 同理 rN - 1 也是最大公约数g的倍数, 即:g <= rN-1

得证

python 代码:

def gcd(a, b):
    if b == 0:
        return a
    return gcd(b, a % b)
  • 贝祖等式:
    贝祖等式说明,两个数ab的最大公约数g可以表示为ab的线性和。
    也就是说,存在整数st使g = sa + tb。注意是正数哦。
    由辗转相除法逆推:
    g = rN-1 = rN-3 - qN-1 * rN-2
    rN-2 = rN-4 - qN-2 * rN-3
    rN-3 = rN-5 - qN-3 * rN-4
    ......
    r2 = r0 - q2 * r1
    r1 = b - q1 * r0
    r0 = a - q0 * b
    b = 0 * a + 1 * b
    a = 1 * a + 0 * b
    递推可证明贝祖等式成立。
    即找到rN-3,rN-2的乘积形式的表达, 乘数都是整数,sN-1,
    tN-1一定也是整数
    • 证明:
      找到贝祖等式的s 和 t的值,利用上面的证明过程用数学归纳法递推:
      假设 rj = sj * a + tj * b 对于 j <= k-1 均成立
      rk = rk-2 - qk * rk-1
      rk-2 = sk-2 * a + tk-2 * b
      rk-1 = sk-1 * a + tk-1 * b
      则:
      rk = sk-2 * a + tk-2 * b - qk* (sk-1 * a + tk-1 * b) = (sk-2 - qk*sk-1) * a + (tk-2 - qk * tk-1) * b
      即:
      sk = sk-2 -qk * sk-1
      tk = tk-2 -qk * tk-1
      .....
      算法开始时:
      s0 = 1, t0 = -q0
      s-1 = 0, q-1 = 1
      s-2 = 1, q-2 = 0
  • 扩展欧几里得算法
    扩展欧几里得算法即找到贝祖等式的s 和 t的值,
    sk = sk-2 - qk * sk-1
    tk = tk-2 - qk * tk-1
    • python代码:
def ex_gcd(a, b):
    s0 = 1
    t0 = 0
    s1 = 0
    t1 = 1
    m, n = a, b
    while b != 0:
        a, b, q = b, a % b, a // b
        s0, s1 = s1, s0 - q * s1
        t0, t1 = t1, t0 - q * t1
        print "%d = %d * %d + %d * %d" % (a, s0, m, t0, n)
        print "%d = %d * %d + %d * %d" % (b, s1, m, t1, n)
    return s0, t0, a

结果:

30 = 0 * 47 + 1 * 30
17 = 1 * 47 + -1 * 30
17 = 1 * 47 + -1 * 30
13 = -1 * 47 + 2 * 30
13 = -1 * 47 + 2 * 30
4 = 2 * 47 + -3 * 30
4 = 2 * 47 + -3 * 30
1 = -7 * 47 + 11 * 30
1 = -7 * 47 + 11 * 30
0 = 30 * 47 + -47 * 30
(-7, 11, 1)

维基上的算法:
https://zh.wikipedia.org/wiki/%E6%89%A9%E5%B1%95%E6%AC%A7%E5%87%A0%E9%87%8C%E5%BE%97%E7%AE%97%E6%B3%95
这个明显比我自己推导写的代码要简洁多了,这个代码思想和上面的递推公式是反的, 是从先找到最大公约数, 有等式 g = 1 * s N-1 + 0 * sN开始往回推, 而上面的逻辑是从a, b开始顺序推,一边找最大公约数, 一边解二元一次方程:
逆推公式:
sN = 1, tN = 0
g = 1 * r N-1 + 0 * rN = sN * r N-1 + tN * rN
rN = 1 * rN-2 - qN * rN- 1 = sN-1* rN-2 +tN-1 * rN- 1
有 g = (1 - qN) * r N-1 + 1* rN-2 = (sN - )
rN-1 = 1 * rN-3 - qN-1 * rN- 2
对应的s,t :
sN = 1, tN = 0
sN-1 = 1,

sk - 2 = sk + qk * sk-1
tk - 2 = tk + qk * tk-1

s-2 = 1
s-1 = t -2 = 0
s0 = s-2 - qk * s-1 = s-2 - qk * t -2
不妨设t -3 = 1
上面的式子变为:
s0 = t -3 - qk * t -2 = t -1 = 1
利用数据归纳法可以证明

  • sk = t k-1
  • tk = tk-2 - qk * tk-1 = sk -1 - qk * tk-1

你可能感兴趣的:(欧几里得算法)