不同的GCD算法


分类: C语言程序 28人阅读 评论(0) 收藏 举报

早在公元前300年左右,欧几里得就在他的著作《几何原本》中给出了高效的解法——辗转相除法。辗转相除法使用到的原理很聪明也很简单,假设用f(x, y)表示x,y的最大公约数,取k = x/y,b = x%y,则x = ky + b,如果一个数能够同时整除x和y,则必能同时整除b和y;而能够同时整除b和y的数也必能同时整除x和y,即x和y的公约数与b和y的公约数是相同的,其最大公约数也是相同的,则有f(x, y)= f(y, x % y)(y > 0),如此便可把原问题转化为求两个更小数的最大公约数,直到其中一个数为0,剩下的另外一个数就是两者最大的公约数。

证明如下:
我们只需证明gcd(a,b)gcd(b,a%b)可以互相整除即可。
对于gcd(a,b),它是a和b的线性组合中的最小正元素,gcd(b,a%b) 是b与a%b的一个线性组合,而a%b是a与b的一个线性组合,因而gcd(b,a%b)是一个a与b的线性组合,因为a,b都能被gcd(a,b)整除,因而任何一个a与b的线性组合都能被gcd(a,b)整除,所以gcd(b,a%b)能被gcd(a,b)整除。反之亦然。
(摘自百度百科)
这都是网上比较正式比较权威的解释,直接就拿来用了。
下面是我写的一段代码,还有注释中是三种摘自网络上别人的不同解法。人家的代码简直精简到一塌糊涂。~~~~(>_<)~~~~ 
#include<stdio.h>   /*欧几里得算法(辗转相除法)求最大公约数。*/
int gcd(int m,int n);

int main (void){
	int m,n;
	printf("请输入m和n的数值(都为正整数),将为你求出两个数的最大公约数:\n");
	scanf("%d %d",&m,&n);
	printf("%d\n",gcd(m,n));
	return 0;
}


int gcd(int m,int n){                               //我的递归法
	if(n==0)
		return m;
	return gcd(n,m%n);
}

int gcd(int a,int b)           //精简版递归法
{  
    return (b>0)?gcd(b,a%b):a;  
}  


/*int gcd(int a,int b)           //位运算法。这个代码害怕不害怕。。
{  
    while(b^=a^=b^=a%=b);  
    return a;  
}  */

话说看到位运算法的时候真被吓到了。。确实非常精炼!
下面把这句提取出来,小小的分析一下。
while(b^=a^=b^=a%=b);  

因为两个数字进行三次异或运算可以交换数值。

所以其实可以写为:
while(b>0){
a=a%b;         -->求出余数赋给a;
b=b^a;          -->通过亦或运算,b的值变为其他值
a=a^b;          -->a的值变为原b的值
b=b^a;          -->b的值变为原a的值 
}
return  a;
这样,当b为0的时候,a就是最大公约数,然后返回这个值即可:

还有一种方法叫二进制gcd法                                                         


posted @ 2014-11-17 21:17  lazypark  阅读(301)  评论(0编辑  收藏  举报