1.穷举法
穷举法就是将两个元素中较小的值进行遍历(从大往小去),只有有一个值能让两个元素取余为0,该值即为最大公约数。
java代码
int Gcd(int n,int m){
if(n<m){
int temp = n;
n=m;
m=temp;
}
for(int i=m;i>0;i–){
if(n%i==0&&m%i==0)
break;
}
return i;
}
穷举法的缺点:算法不稳定,假如是两个很大的素数,基本要遍历到天黑才能找到最大公约数1。
2.更相减损法(辗转相减法//我造的)
更相减损术,是出自《九章算术》的一种求最大公约数的算法,它原本是为约分而设计的,但它适用于任何需要求最大公约数的场合。
《九章算术》是中国古代的数学专著,其中的“更相减损术”可以用来求两个数的最大公约数,即“可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。”
翻译成现代语言如下:
第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
其中所说的“等数”,就是最大公约数。求“等数”的办法是“更相减损”法。所以更相减损法也叫等值算法。
例1、用更相减损术求98与63的最大公约数。
解:由于63不是偶数,把98和63以大数减小数,并辗转相减:
98-63=35
63-35=28
35-28=7
28-7=21
21-7=14
14-7=7
所以,98和63的最大公约数等于7。
这个过程可以简单的写为:
(98,63)=(35,63)=(35,28)=(7,28)=(7,21)=(7,14)=(7,7)=7.
例2、用更相减损术求260和104的最大公约数。
解:由于260和104均为偶数,首先用2约简得到130和52,再用2约简得到65和26。
此时65是奇数而26不是奇数,故把65和26辗转相减:
65-26=39
39-26=13
26-13=13
所以,260与104的最大公约数等于13乘以第一步中约掉的两个2,即13*2*2=52。
这个过程可以简单地写为:
(260,104)=(65,26)=(39,26)=(13,26)=(13,13)=13.[3]
c语言代码
#include<stdio.h>
int Gcd(int n,int m){
if(n-m==m)return m;
if(n%2==0&&m%2==0){
return 2*Gcd(n/2,m/2);
}else if(m>n-m){
Gcd(m,n-m);
}else{
Gcd(n-m,m);
}
}
这种方法的缺点:当两个数相差很大的时候,计算次数太多,欧几里得算法将其进行了改进。
3.辗转相除法(欧几里得算法)
我对辗转相除的理解就是:实现除数和余数有最大的约数
比如:377%319=58;
只要该数能被319和58约,就整除了。
算法步骤:
将除数和余数变成被除数和除数,不断相除,直到能除尽,最后的除数就是最大的余数,A%B=C —> B%C=D—> C%D=E,when E==0; OVER
例如 gcd(377,319);
第一步:377%319=58;
第二步:319%58=29;
第三步:58%29=0;
所以最大公约数为29;
c语言代码(写着写着就像java了)
//递归
int Gcd(int n,int m){
if(n<0||m<0)exit(0);
if(m==0) return n;
else if(m>n){
return Gcd(m,n);
}
else{
return Gcd(m,n%m);
}
}
//while循环(java)
int Gcd(int n,int m){
if(m<n){
int temp=m;
m=n;
n=temp;
}
while(n%m!=0){
n=m;
m=n%m;
}
retun m;
}
欧几里德算法是计算两个数最大公约数的传统算法,无论是理论,还是从效率上都是很好的。
但是他有一个致命的缺陷,这个缺陷只有在很大的素数时才会显现出来。
考虑现在的硬件平台,一般整数最多也就是64位, 对于这样的整数,计算两个数值就的模很简单的
对于字长为32位的平台,计算两个不超过32位的整数的模,只需要一个指令周期,而计算64位以下的整数模,也不
过几个周期而已。但是对更大的素数,这样的计算过程就不得不由用户来设计,为了计算两个超过64位的整数的模,
用户也许不得不采用类似于多位除法手算过程中的试商法,这个过程不但复杂,而且消耗了很多CPU时间。
对于现代密码算法,要求计算128位以上的素数的情况比比皆是,设计这样的程序迫切希望能够抛弃除法和取模
4.stein算法
Stein算法由J.Stein 1961年提出,这个方法也是计算两个数的最大公约数。
和欧几里德算法不同的是,Stein算法只有整数的移位和加减法,这对于程序设计者是一个福音。
为了说明Stein算法的正确性,首先必须注意到以下结论:
g_c_d( x,x ) = x , 也就是一个数和他自己的公约数是其自身。
g_c_d( x,y ) =2g_c_d( x/2,y/2 ),也就是最大公约数运算和倍乘运算可以交换,特殊的,当k=2时,说明两个偶数最大公约数比如能被2整除。
来研究一下最大公约数的性质,我们发现有 g_c_d( k*x,k*y ) = k*g_c_d( x,y ) 这么一个非常好的性质(证明我就省去了)。说他好是因为他非常符合我们化小的思想。我们试取 k=2 ,则有 g_c_d( 2x,2y ) = 2 * g_c_d( x,y )。这使我们很快联想到将两个偶数化小的方法。那么一奇一个偶以及两个奇数的情况我们如何化小呢?
先来看看一奇一偶的情况: 设有2x和y两个数,其中y为奇数。因为y的所有约数都是奇数,所以 a = g_c_d( 2x,y ) 是奇数。根据2x是个偶数不难联想到,a应该是x的约数。我们来证明一下:(2x)%a=0,设2x=n*a,因为a是奇数,2x是偶数,则必有n是偶数。又因为 x=(n/2)*a,所以 x%a=0,即a是x的约数。因为a也是y的约数,所以a是x和y的公约数,有 g_c_d( 2x,y ) <= g_c_d( x,y )。因为g_c_d( x,y )明显是2x和y的公约数,又有g_c_d( x,y ) <= g_c_d( 2x,y ),所以 g_c_d( 2x,y ) = g_c_d( x,y )。至此,我们得出了一奇一偶时化小的方法。
再来看看两个奇数的情况:设有两个奇数x和y,似乎x和y直接向小转化没有什么太好的办法,我们可以绕个道,把x和y向偶数靠拢去化小。不妨设x>y,我们注意到x+y和x-y是两个偶数,则有 g_c_d( x+y,x-y ) = 2 * g_c_d( (x+y)/2,(x-y)/2 ),那么 g_c_d( x,y ) 与 g_c_d( x+y,x-y ) 以及 g_c_d( (x+y)/2,(x-y)/2 ) 之间是不是有某种联系呢?为了方便我设 m=(x+y)/2 ,n=(x-y)/2 ,容易发现 m+n=x ,m-n=y 。设 a = g_c_d( m,n ),则 m%a=0,n%a=0 ,所以 (m+n)%a=0,(m-n)%a=0 ,即 x%a=0 ,y%a=0 ,所以a是x和y的公约数,有 g_c_d( m,n )<= g_c_d(x,y)。再设 b = g_c_d( x,y )肯定为奇数,则 x%b=0,y%b=0 ,所以 (x+y)%b=0 ,(x-y)%b=0 ,又因为x+y和x-y都是偶数,跟前面一奇一偶时证明a是x的约数的方法相同,有 ((x+y)/2)%b=0,((x-y)/2)%b=0 ,即 m%b=0 ,n%b=0 ,所以b是m和n的公约数,有 g_c_d( x,y ) <= g_c_d( m,n )。所以 g_c_d( x,y ) = g_c_d( m,n ) = g_c_d( (x+y)/2,(x-y)/2 )。
我们来整理一下,对两个正整数 x>y :
1.均为偶数 g_c_d( x,y ) =2g_c_d( x/2,y/2 );
2.均为奇数 g_c_d( x,y ) = g_c_d( (x+y)/2,(x-y)/2 );
2.x奇y偶 g_c_d( x,y ) = g_c_d( x,y/2 );
3.x偶y奇 g_c_d( x,y ) = g_c_d( x/2,y ) 或 g_c_d( x,y )=g_c_d( y,x/2 );
现在我们已经有了递归式,还需要再找出一个退化情况。注意到 g_c_d( x,x ) = x ,我们就用这个。
代码
int Gcd(int n,int m){
if(n<m){
int temp = n;
n=m;
m=temp;
}
if(m=0)return n;
if(n%2==0&&m%2==0){
return 2*Gcd(n/2,m/2);
}
if(n%2==0&&m%2!=0){
return Gcd(n/2,m);
}
if(n%2!=0&&m%2==0){
return Gcd(n,m/2);
}
return Gcd((n+m)/2,(n-m)/2);
}