定义
对于 n n n个整数 a 1 , a 2 , ⋯ , a n a_1,a_2,\cdots,a_n a1,a2,⋯,an,其中 n ≥ 2 n \ge 2 n≥2,如果整数d整除这n个整数中的每一个,那么d是这n个数的公因数。即 d ∣ a 1 , d ∣ a 2 , ⋯ , d ∣ a n d|a_1,d|a_2,\cdots,d|a_n d∣a1,d∣a2,⋯,d∣an
如果 a 1 , a 2 , ⋯ , a n a_1,a_2,\cdots,a_n a1,a2,⋯,an不全为0,那么其公因数中最大的一个,叫做这n个整数的最大公因数。一般记作 g c d ( a 1 , a 2 , ⋯ , a n ) = ( a 1 , a 2 , ⋯ , a n ) gcd(a_1,a_2,\cdots,a_n)=(a_1,a_2,\cdots,a_n) gcd(a1,a2,⋯,an)=(a1,a2,⋯,an)。若这n个数的最大公因数为1,则这n个数互素或者互质。
求解多个数的公因数,一般来说是先求两个数的公因数,得到的公因数再与其他数求公因数,直到求完所有数。
而求两个数的最大公因数,一般来说有两种,一种是更相减损术,另一种是辗转相除法。不妨设我们要求整数a、b的最大公因数 a > b > 0 a>b>0 a>b>0,下面分别介绍更相减损术和辗转相除法。
更相减损术
1、假设 d = a − b d=a-b d=a−b,如果 d = = b d==b d==b,则最大公因数是d;
2、否则,令 a = = m a x ( b , d ) , b = m i n ( b , d ) a==max(b,d),b=min(b,d) a==max(b,d),b=min(b,d),其中max是指其中最大的数,min是指最小的数。转到第一步,直到 d = = b d==b d==b。
显然,由于 a > b > 0 a>b>0 a>b>0,则每一次迭代,a会不断减小,同样b也会减小,并且,由于a、b均为整数,则每次至少减小1,所以算法一定会收敛。
证明:
假设 k ∣ a , k ∣ b k|a,k|b k∣a,k∣b,那么有 a = q 1 k , b = q 2 k a=q_1k, b=q_2k a=q1k,b=q2k,所以 d = ( q 1 − q 2 ) k d=(q_1-q_2)k d=(q1−q2)k,即 k ∣ d k|d k∣d;
同理如果 k ∣ d , k ∣ b k|d,k|b k∣d,k∣b,那么有 d = q 1 k , b = q 2 k d=q_1k, b=q_2k d=q1k,b=q2k,所以 a = ( q 1 + q 2 ) k a=(q_1+q_2)k a=(q1+q2)k,即 k ∣ a k|a k∣a;
也就是 k ∣ a , k ∣ b k|a,k|b k∣a,k∣b与 k ∣ d , k ∣ b k|d,k|b k∣d,k∣b等价; 所以 g c d ( a , b ) = g c d ( b , d ) gcd(a,b)=gcd(b,d) gcd(a,b)=gcd(b,d).
下面是一个用c++和gmp库实现的代码。
#include<iostream>
#include<gmpxx.h>
using namespace std;
int main(){
mpz_class a,b;
cout<<"Please input a:"<<endl;
cin>>a;
cout<<"Please input b:"<<endl;
cin>>b;
mpz_class d;
//ensure a>b;
if(a<b){
d=a;
a=b;
b=d;
}
if(a==0 or b==0){
cout<<"a or b can not be 0."<<endl;
return 0;
}
if(a==b){
cout<<"gcd(a,b)="<<a<<endl;
return 0;
}
d=a-b;
while(d!=b){
if(b>d){
a=b;
b=d;
}else{
a=d;
}
d=a-b;
}
cout<<"gcd(a,b)="<<d<<endl;
return 0;
}
假设文件名字为gcd1.cpp,使用如下命令编译
g++ gcd1.cpp -o gcd1 -lgmp -lgmpxx
辗转相除法
1、令r=a%b,即r是a除以b的余数,也就是说a=qb+r,其中q是整数, 0 ≤ r ≤ b 0 \le r \le b 0≤r≤b。
2、如果r==0,那么b是最大公因数,否则,令a=b,b=r,转到第1步。
由于r在不断减小,算法最终会收敛。
证明:
假设 k ∣ a , k ∣ b k|a,k|b k∣a,k∣b,那么有 a = q 1 k , b = q 2 k a=q_1k, b=q_2k a=q1k,b=q2k,所以 r = ( q 1 − q q 2 ) k r=(q_1-qq_2)k r=(q1−qq2)k,即 k ∣ r k|r k∣r;
同理如果 k ∣ r , k ∣ b k|r,k|b k∣r,k∣b,那么有 r = q 1 k , b = q 2 k r=q_1k, b=q_2k r=q1k,b=q2k,所以 a = ( q 1 + q q 2 ) k a=(q_1+qq_2)k a=(q1+qq2)k,即 k ∣ a k|a k∣a;
也就是 k ∣ a , k ∣ b k|a,k|b k∣a,k∣b与 k ∣ r , k ∣ b k|r,k|b k∣r,k∣b等价; 所以 g c d ( a , b ) = g c d ( b , r ) gcd(a,b)=gcd(b,r) gcd(a,b)=gcd(b,r).
代码如下
#include<iostream>
#include<gmpxx.h>
using namespace std;
int main(){
mpz_class a,b;
cout<<"Please input a:"<<endl;
cin>>a;
cout<<"Please input b:"<<endl;
cin>>b;
mpz_class r;
//ensure a>b;
if(a<b){
r=a;
a=b;
b=r;
}
if(a==0 or b==0){
cout<<"a or b can not be 0."<<endl;
return 0;
}
if(a==b){
cout<<"gcd(a,b)="<<a<<endl;
return 0;
}
r=a%b;
while(r!=0){
a=b;
b=r;
r=a%b;
}
cout<<"gcd(a,b)="<<b<<endl;
return 0;
}
gmp自带的gcd函数
gmp中实现了gcd函数,其用法如下
#include<iostream>
#include<gmpxx.h>
using namespace std;
int main(){
mpz_class a,b;
cout<<"Please input a:"<<endl;
cin>>a;
cout<<"Please input b:"<<endl;
cin>>b;
cout<<gcd(a,b)<<endl;
return 0;
}