欧几里得算法(Euclidean Algorithm)
预备知识(不严谨定义)
整除:简单来说, \(a = nb\), 则有\(b|a\),读作b整除a
约数(divisor):上面整除的例子里,b就是a的约数,公约数就是多个数的共有约数,如2就是4、6、8的公约数
最大公约数(greast common divisor, 简称gcd):顾名思义,公约数里最大的一个,设\(gcd(a,b)=m\),则任取a、b的公约数c,有\(c <= m\),需要注意的是,最大公约数往往是整数,特殊的:
- 若\(b|a\), 则\(gcd(a, b)=b\)
- 任取整数\(n\),有\(gcd(0, n)=n\)
互素(relatively prime):两个数的最大公约数是1,那么我们就称这两个数的互素的
如果我们要求最大公约数,我们先来想一下最简单的思路。
假设\(a>b\),我们使用暴力求解的方式,从1开始,设置一个变量存储最大公约数值,每发现一个既能整除a又能整除b的数,将其置为最大公约数,直到遍历到b为止。粗一看,时间复杂度也并不很高,似乎也是可行的方法。但实际上,在实际的密码学程序中,需要大量的这类操作,并且操作的数往往是非常大的数,这时,这种方法就显得十分低效,而欧几里德方法就是为了能够高效的求取最大公约数。
欧几里德算法
首先我们来看,设
\[a = q*b+r \\d = gcd(a, b)
\]
那么\(r = a-q*b\),由于\(d|a、d|b\),则有\(d|(a-q*b)=r\),即d也是b和r的最大公约数,此外,又有\(b>r => b=q_1*r+r_1\)以此类推,就得到了我们的欧几里德算法。
算法描述为:
- 将输入置为\(a>b\)
- 令\(a=q*b+r\)
- 若\(r=0\),则\(gcd(a,b)=b\)
- 否则,令\(a := b, b := r\), 注意这里的:=是赋值操作,重复2
建议自己模拟一下,易于理解!
欧几里德算法的实现
# 加减法的实现对计算机的计算方式更友善
def gcd1(a, b):
a, b = max(a, b), min(a, b)
while a != b:
a, b = max(b, a-b), min(b, a-b)
return a
def gcd2(a, b):
a, b = max(a, b), min(a, b)
while a % b != 0:
a, b = b, a%b
return b
实用的欧几里德算法
上面只是欧几里德算法的直接实现,效率较低,不能满足实际环境的需要。
通常的生产代码中使用的最大公约数算法是一种称作binary GCD的算法,其算法描述如下,
openssl中使用的BN_gcd便使用了该算法