一、簡介
兩個整數的最大公約數是能夠同時整除它們的最大的正整數。輾轉相除法基於如下原理:兩個整數的最大公約數等於其中較小的數和兩數的相除余數的最大公約數。例如,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)。
