最大公因数及其求解算法(GCD)

定义

对于 n n n个整数 a 1 , a 2 , ⋯   , a n a_1,a_2,\cdots,a_n a1,a2,,an,其中 n ≥ 2 n \ge 2 n2,如果整数d整除这n个整数中的每一个,那么d是这n个数的公因数。即 d ∣ a 1 , d ∣ a 2 , ⋯   , d ∣ a n d|a_1,d|a_2,\cdots,d|a_n da1,da2,,dan
如果 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=ab,如果 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 ka,kb,那么有 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=(q1q2)k,即 k ∣ d k|d kd
同理如果 k ∣ d , k ∣ b k|d,k|b kd,kb,那么有 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 ka;
也就是 k ∣ a , k ∣ b k|a,k|b ka,kb k ∣ d , k ∣ b k|d,k|b kd,kb等价; 所以 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 0rb
2、如果r==0,那么b是最大公因数,否则,令a=b,b=r,转到第1步。
由于r在不断减小,算法最终会收敛。

证明:
假设 k ∣ a , k ∣ b k|a,k|b ka,kb,那么有 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=(q1qq2)k,即 k ∣ r k|r kr
同理如果 k ∣ r , k ∣ b k|r,k|b kr,kb,那么有 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 ka;
也就是 k ∣ a , k ∣ b k|a,k|b ka,kb k ∣ r , k ∣ b k|r,k|b kr,kb等价; 所以 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;
}

猜你喜欢

转载自blog.csdn.net/watqw/article/details/123646247