四种算法求最大公因数
题目分析:
本次实验内容为使用以下几种算法1:辗转相除法函数嵌套调用2:辗转相除法函数递归调用3:穷举法(利用数学定义4:更相减损法5:Stein算法函数非递归调用6:Stein算法函数递归调用;求出随机生成的几十组数据(两个一组)的最大公因数,并且显示出每种算法的运行时间,观察做以比较看看哪个算法在计算相同组数据时生成它们的最大公因数速率快。
1.辗转相除法
辗转相除法(又名欧几里德法)C语言中用于计算两个正整数a,b的最大公约数和最小公倍数,实质它依赖于下面的定理:
a b=0
gcd(a,b)=
gcd (b,a mod b) b!=0
根据这一定理可以采用函数嵌套调用和递归调用形式进行求两个数的最大公约数和最小公倍数,现分别叙述如下:
①函数嵌套调用
其算法过程为: 前提:设两数为a,b设其中a 做被除数,b做除数,temp为余数
1、大数放a中、小数放b中;
2、求a/b的余数;
3、若temp=0则b为最大公约数;
4、如果temp!=0则把b的值给a、temp的值给a;
5、返回第二步。
(1)算法基本流程图如下
(2)测试代码
2.穷举法(利用数学定义)
穷举法(也叫枚举法)穷举法求两个正整数的最大公约数的解题步骤:从两个数中较小数开始由大到小列举,直到找到公约数立即中断列举,得到的公约数便是最大公约数 。
定义:对两个正整数a,b如果能在区间[a,0]或[b,0]内能找到一个整数temp能同时被a和b所整除,则temp即为最大公约数。
(1)算法流程图如下
(2)测试代码如下:
3. 更相减损法
更相减损术,是出自《九章算术》的一种求最大公约数的算法,它原本是为约分而设计的,但它适用于任何需要求最大公约数的场合。《九章算术》是中国古代的数学专著,其中的“更相减损术”可以用来求两个数的最大公约数,即“可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。”
翻译成现代语言如下:
第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
其中所说的“等数”,就是最大公约数。求“等数”的办法是“更相减损”法。所以更相减损法也叫等值算法。
(1)算法基本流程图如下:
(2)测试源代码及:
4.Stein算法
Stein算法由J. Stein 1961年提出,这个方法也是计算两个数的最大公约数。来研究一下最大公约数的性质,发现有 gcd( kx,ky ) = kgcd( x,y ) 这么一个非常好的性质。试取 k=2,则有 gcd( 2x,2y ) = 2 * gcd( x,y )。很快联想到将两个偶数化小的方法。那么一奇一个偶以及两个奇数的情况如何化小呢?
先来看看一奇一偶的情况: 设有2x和y两个数,其中y为奇数。因为y的所有约数都是奇数,所以 a = gcd( 2x,y ) 是奇数。根据2x是个偶数不难联想到,a应该是x的约数。我们来证明一下:(2x)%a=0,设2x=na,因为a是奇数,2x是偶数,则必有n是偶数。又因为 x=(n/2)*a,所以 x%a=0,即a是x的约数。因为a也是y的约数,所以a是x和y的公约数,有 gcd( 2x,y ) <= gcd( x,y )。因为gcd( x,y )明显是2x和y的公约数,又有gcd( x,y ) <= gcd( 2x,y ),所以 gcd( 2x,y ) = gcd( x,y )。至此,我们得出了一奇一偶时化小的方法。
再来看看两个奇数的情况:设有两个奇数x和y,不妨设x>y,注意到x+y和x-y是两个偶数,则有 gcd( x+y,x-y ) = 2 * gcd( (x+y)/2,(x-y)/2 ),那么 gcd( x,y ) 与 gcd( x+y,x-y ) 以及 gcd( (x+y)/2,(x-y)/2 ) 之间是不是有某种联系呢?为了方便设 m=(x+y)/2 ,n=(x-y)/2 ,容易发现 m+n=x ,m-n=y 。设 a = gcd( 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的公约数,有 gcd( m,n )<= gcd(x,y)。再设 b = gcd( 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的公约数,有 gcd( x,y ) <= gcd( m,n )。所以 gcd( x,y ) = gcd( m,n ) = gcd( (x+y)/2,(x-y)/2 )。
整理一下,对两个正整数 x>y :
1.均为偶数 gcd( x,y ) =2gcd( x/2,y/2 );
2.均为奇数 gcd( x,y ) = gcd( (x+y)/2,(x-y)/2 );
2.x奇y偶 gcd( x,y ) = gcd( x,y/2 );
3.x偶y奇 gcd( x,y ) = gcd( x/2,y ) 或 gcd( x,y )=gcd( y,x/2 )
(1)算法基本流程图展示
(2)测试源代码
最后附上程序源代码
#include “stdio.h” /输入输出类头文件/
#include"math.h"
#include"stdlib.h"
#include"time.h"
#include"Windows.h"
const int N = 10;
/*1.辗转相除法
①函数嵌套调用
其算法过程为:?前提:设两数为a,b设其中a 做被除数,b做除数,temp为余数
1、大数放a中、小数放b中;
2、求a/b的余数;
3、若temp=0则b为最大公约数;
4、如果temp!=0则把b的值给a、temp的值给a;
5、返回第二步;
/
int divisor(int a, int b) /自定义函数求两数的最大公约数/
{
int temp; /定义整型变量/
if (a通过比较求出两个数中的最大值和最小值/
{
temp = a; a = b; b = temp;
} /设置中间变量进行两数交换/
while (b != 0) /通过循环求两数的余数,直到余数为0/
{
temp = a%b;
a = b; /变量数值交换/
b = temp;
}
return (a); /返回最大公约数到调用函数处/
}
//#include “stdio.h”
//int main()
//{
// int m, n, t1, t2; /定义整型变量/
// printf(“please input two integer number:”); /提示输入两个整数/
// scanf("%d%d", &m, &n); /通过终端输入两个数/
// t1 = divisor(m, n); /自定义主调函数/
// t2 = multiple(m, n); /自定义主调函数/
// printf(“The higest common divisor is %d\n”, t1); /输出最大公约数/
// printf(“The lowest common multiple is %d\n”, t2); /输出最小公倍数/
// return 0;
//}
/②函数递归调用/
int gcd(int a, int b)
{
if (a%b == 0)
return b;
else
return gcd(b, a%b);
}
//#include “stdio.h”
//int main()
//{
// int m, n, t1;
// printf(“please input two integer number:”);
// scanf("%d%d", &m, &n);
// t1 = gcd(m, n);
// printf(“The highest common divisor is %d\n”, t1);/最大公约数/
// return 0;
//}
/2.穷举法(利用数学定义)
穷举法(也叫枚举法)穷举法求两个正整数的最大公约数的解题步骤:
从两个数中较小数开始由大到小列举,直到找到公约数立即中断列举,得到的公约数便是最大公约数?。
对两个正整数a,b如果能在区间[a,0]或[b,0]内能找到一个整数temp能同时被a和b所整除,则temp即为最大公约数。/
int divisor1(int a, int b) /自定义函数求两数的最大公约数/
{
int temp; /定义义整型变量/
temp = (a>b) ? b : a; /采种条件运算表达式求出两个数中的最小值/
while (temp>0)
{
if (a%temp == 0 && b%temp == 0) /只要找到一个数能同时被a,b所整除,则中止循环/
break;
temp–; /如不满足if条件则变量自减,直到能被a,b所整除/
}
return (temp); /返回满足条件的数到主调函数处/
}
//#include “stdio.h”
//int main()
//{
// int m, n, t1;
// printf(“please input two integer number:”);
// scanf("%d%d", &m, &n);
// t1 = divisor(m, n);
// printf(“The higest common divisor is %d\n”, t1);
// return 0;
//}
/
3.更相减损法
更相减损术,是出自《九章算术》的一种求最大公约数的算法,它原本是为约分而设计的,但它适用于任何需要求最大公约数的场合。《九章算术》是中国古代的数学专著,其中的“更相减损术”可以用来求两个数的最大公约数,即“可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。”
翻译成现代语言如下:
第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
其中所说的“等数”,就是最大公约数。求“等数”的办法是“更相减损”法。所以更相减损法也叫等值算法
*/
int gcd1(int m, int n)
{
int i = 0, temp=0, x=1;
while (m % 2 == 0 && n % 2 == 0) //判断m和n能被多少个2整除
{
m /= 2;
n /= 2;
i += 1;
}
if (m
temp = m;
m = n;
n = temp;
}
while (x)
{
x = m - n;
m = (n>x) ? n : x;
n = (n
break;
}
if (i == 0)
return n;
else
return (int)pow(2.0, i)n;
}
//更相减损法
//#include
//#include"math.h"
//int main()
//{
// int m, n, t2;
// printf(“please input two integer number:”);
// scanf("%d%d", &m, &n);
// t2 = gcd( m,n);
// printf(“The higest common divisor is %d\n”, t2);
// return 0;
//}
/
Stein算法
①函数非递归调用
*/
int Stein(unsigned int x, unsigned int y)
{
int factor = 0;
int temp;
if (x
temp = x;
x= y;
y= temp;
}
if (0 == y)
{
return 0;
}
while (x!= y)
{
if (x & 0x1)
{
if (y & 0x1)
{
y = (x - y ) >> 1;
x -= y;
}
else
{
y >>= 1;
}
}
else
{
if (y & 0x1)
{
x >>= 1;
if (x
temp = x;
x = y;
y = temp;
}
}
else
{
x >>= 1;
y >>= 1;
++factor;
}
}
}
return (x << factor );
}
//Stein算法
//①函数非递归调用
//#include
//int main()
//{
// int m, n, t2;
// printf(“please input two integer number:”);
// scanf("%d%d", &m, &n);
// t2 = Stein(m, n);
// printf(“The higest common divisor is %d\n”, t2);
// return 0;
//}
//②函数递归调用
int gcd2(int u, int v)
{
if (u == 0) return v;
if (v == 0) return u;
// look for factors of 2
if (~u & 1) // u is even
{
if (v & 1) // v is odd
return gcd(u >> 1, v);
else // both u and v are even
return gcd(u >> 1, v >> 1) << 1;
}
if (~v & 1) // u is odd, v is even
return gcd(u, v >> 1);
// reduce larger argument
if (u > v)
return gcd((u - v) >> 1, v);
return gcd((v - u) >> 1, u);
}
//②函数递归调用
//#include
//int main()
//{
// int m, n, t2;
// printf(“please input two integer number:”);
// scanf("%d%d", &m, &n);
// t2 = gcd(m, n);
// printf(“The higest common divisor is %d\n”, t2);
// return 0;
//}
int main()
{
int Random[N][2];
for (int j = 0; j < 2;j++)
for (int i = 0; i < N; i++)
{
Random[i][j] = 0;
}
srand((unsigned)time(NULL));
for (int j = 0; j < 2; j++)
for (int i = 0; i < N; i++)
{
Random[i][j] = (rand()%99+1);
}
for (int i = 0; i<2; i++)
{
for (int j = 0; j
}