一、简介
两个整数的最大公约数是能够同时整除它们的最大的正整数。辗转相除法基于如下原理:两个整数的最大公约数等于其中较小的数和两数的相除余数的最大公约数。例如,252和105的最大公约数是21(252 = 21 × 12;105 = 21 × 5),因为252 ÷105 = 2......42,所以(105,42)是21。在这个过程中,较大的数缩小了,所以继续进行同样的计算可以不断缩小这两个数直至余数变为零。这时的除数就是所求的两个数的最大公约数。
由辗转相除法也可以推出,两数的最大公约数可以用两数的整数倍相加来表示,如21 = 5 × 105 + (?2) × 252。这个重要的等式叫做贝祖等式(又称“裴蜀定理”)。
设两数为a、b(a>b),求a和b最大公约数(a,b)的步骤如下:
用a除以b,得a÷b=q......r1(0≤r1)。
若r1=0,则(a,b)=b;
若r1≠0,则计算(b,r1),用b除以r1,得b÷r1=q......r2 (0≤r2).
若r2=0,则(a,b)==(b,r1)==r1,
若r2≠0,则计算(r1,r2),用r1除以r2,得r1÷r2=q......r3 (0≤r3)
……
如此下去,直到某个除法运算余数为0为止。这个除法运算的除数即为所求最大公约数。例如:a=25,b=15,a/b=1......10, b/10=1......5, 10/5=2.......0, 最后一个除法的除数为5,就是所求最大公约数(25, 15)。
代码一:
#include <stdio.h> unsigned gcd_rec( unsigned m,unsigned n ){ unsigned temp; if (m<n){ //m保存较大值,n保存较小值,不满足则交换二者的值 temp=m;m=n;n=temp; } if ( m%n == 0){ //如果余数为0则意味着n为m,n的最大公约数 return n; }else{ //否则需要使用较小的数n和两数的相除余数m%n继续求解 return gcd(n,m%n) ; } } int main( void ){ unsigned m,n; printf("请输入两个正整数:"); scanf("%u%u",&m,&n); printf("%u与%u的最大公约数为:%u\n",m,n,gcd ( m,n ) ); return 0; }
代码二:当然也可以不使用递归,使用迭代的方法进行计算,代码如下:
#include <stdio.h> void gcd_iter(unsigned m,unsigned n ){ int r; while(n!=0){ r=m%n; m=n; n=r; } printf("%d\n",u);
}
从这个代码中可以看出实际上并不必须使用u和v中的较小值进行下一次迭代除法,不过为尽快缩小计算规模选择较小的值更有好处。这里没有比较二者的值并选择其中较小值,不影响计算结果的正确性,而且代码更清晰,但是性能上有一些影响。
代码三:辗转相减求最大公约数
思想:最大公约数能整除i和j,则其一定也能整除i-j(if i>j)
void gcd(int m, int n){ while(m != n) { if(m > n) m -= n; else n -= m; } printf("%d\n",m); }
二、原理的证明
设两数为a、b(b<a),用gcd(a,b)表示a,b的最大公约数,r=a (mod b) 为a除以b以后的余数,k为a除以b的商,即a÷b=k.......r。辗转相除法即是要证明gcd(a,b)=gcd(b,r)。
第一步:令c=gcd(a,b),则设a=mc,b=nc(此时m与n互质)。
第二步:根据前提可知r =a-kb=mc-knc=(m-kn)c
第三步:根据第二步结果可知c也是r的因数
第四步:可以断定m-kn与n互质【假设他们不互质,二者存在非1的公约数d,使得m-kn = xd, n = yd。那么,m = xd + kyd = (x + ky)d,那么,a = mc = (x + ky)dc , b = nc = ydc,=> a,b的最大公约数为dc,而不是c,这与前面结论矛盾】
第五步:既然m - kn与n互质,且已知b=nc,r =(m-kn)c,则能得出b和r的最大公约数为c,即为c = gcd(r,b),又令c=gcd(a,b)进而gcd(a,b)=gcd(b,r)。
证毕。
三、最小公倍数
最小公倍数:数论中的一种概念,两个整数公有的倍数成为他们的公倍数,其中一个最小的公倍数是他们的最小公倍数。
最小公倍数=两整数的乘积÷两整数最大公约数:a * b / gcb(a,b)。