计算a、b两个整数的最大公约数。
1. 欧几里得算法(辗转相除法):
辗转相除法, 又名欧几里得算法(Euclidean algorithm),是求最大公约数的一种方法。它的具体做法是:用较大数除以较小数,再用出现的余数(第一余数)去除除数,再用出现的余数(第二余数)去除第一余数,如此反复,直到最后余数是0为止。如果是求两个数的最大公约数,那么最后的除数就是这两个数的最大公约数。
2. 更相减损法:
第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
3. Stein算法:
辗转相除法是计算两个数最大公约数的传统算法,无论从理论还是从实际效率上都是很好的。但是却有一个致命的缺陷,这个缺陷在素数比较小的时候一般是感觉不到的,只有在大素数时才会显现出来:一般实际应用中的整数很少会超过64位(当然已经允许128位了),对于这样的整数,计算两个数之间的模是很简单的。对于字长为32位的平台,计算两个不超过32位的整数的模,只需要一个指令周期,而计算64位以下的整数模,也不过几个周期而已。但是对于更大的素数,这样的计算过程就不得不由用户来设计,为了计算两个超过64位的整数的模,用户也许不得不采用类似于多位数除法手算过程中的试商法,这个过程不但复杂,而且消耗了很多CPU时间。对于现代密码算法,要求计算128位以上的素数的情况比比皆是,比如说RSA加密算法至少要求500bit密钥长度,设计这样的程序迫切希望能够抛弃除法和取模。
Stein算法很好的解决了辗转相除法中的这个缺陷,Stein算法只有整数的移位和加减法。下面就来说一下Stein算法的原理:
1. 若a和b都是偶数,则记录下公约数2,然后都除2(即右移1位);
2. 若其中一个数是偶数,则偶数除2,因为此时2不可能是这两个数的公约数了
3. 若两个都是奇数,则a = |a-b|,b = min(a,b),因为若d是a和b的公约数,那么d也是|a-b|和min(a,b)的公约数。
Stein算法比辗转相除法更加快速,简易。它与每一次进行更相减损法得到的结果似乎存在着微妙的联系,通过下面的比较,可以发现两种算法之间的联系。
4. 扩展欧几里得算法:
拓展欧几里得算法是欧几里得算法的扩展。除了计算a、b两个整数的最大公约数,此算法还能找到整数x、y(其中一个很可能是负数)。通常谈到最大公因子时, 我们都会提到一个非常基本的事实(详见注1):若设a,b是整数,则存在整数x,y,使得ax+by=gcd(a,b)。有两个数a,b,对它们进行辗转相除法,可得它们的最大公约数——这是众所周知的。然后,收集辗转相除法中产生的式子,倒回去,可以得到ax+by=gcd(a,b)的整数解。
拓展欧几里得算法证明:转自:https://blog.csdn.net/lincifer/article/details/49391175
#模拟矩阵表示
def gcd(x, y):
u0, v0 = 1, 0
u1, v1 = 0, 1
while y:
q = x // y
u0, u1 = u1, u0 - q * u1
v0, v1 = v1, v0 - q * v1
x, y = y, x % y #gcd(x, y) = gcd(y, x%y)
return x, u0, v0
#print(gcd(2*3*7*9*11, 6*12*13))
print(gcd(30, 47))
#递归
def ext_euclid(a, b):
if b == 0:
return 1, 0, a
else:
# q = gcd(a, b) = gcd(b, a%b) 欧几里得算法
x, y, q = ext_euclid(b, a % b)
x, y = y, (x - (a // b) * y)
return x, y, q
print(ext_euclid(47,30))
附录:
贝祖定理/裴蜀定理:
裴蜀定理说明了对任何整数 a、b和它们的最大公约数 d ,关于未知数 x 和 y 的线性丢番图方程(称为裴蜀等式)。其中丢番图方程又名不定方程、整系数多项式方程,是变量仅容许是整数的多项式等式;番图问题有数条等式,其数目比未知数的数目少;丢番图问题要求找出对所有等式都成立的整数组合。对丢番图问题的数学研究称为丢番图分析。
其中,d|a意为d整除a(a可以被d整除),⌊a/s⌋意为(a/s)向下取整。
原作者最后一行应更正为d | (ax1+by1)。
引自:https://blog.csdn.net/discreeter/article/details/69833579