两种最大公约数的算法

来源:互联网 发布:古代日本人身高 知乎 编辑:程序博客网 时间:2024/04/28 12:35

1. 欧几里德算法

欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数。其计算原理依赖于下面的定理:

定理:g(a,b) = g(b,a mod b)

证明:a可以表示成a = kb + r,则r = a mod b
假设d是a,b的一个公约数,则有
d|a, d|b,而r = a - kb,因此d|r
因此d是(b,a mod b)的公约数

假设d 是(b,a mod b)的公约数,则
d | b , d |r ,但是a = kb +r
因此d也是(a,b)的公约数

因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证。

2. Stein算法
欧几里德算法是计算两个数最大公约数的传统算法,他无论从理论还是从效率上都是很好的。但是他有一个致命的缺陷,这个缺陷只有在大素数时才会显现出来。

考虑现在的硬件平台,一般整数最多也就是64位,对于这样的整数,计算两个数之间的模是很简单的。对于字长为32位的平台,计算两个不超过32位的整数的 模,只需要一个指令周期,而计算64位以下的整数模,也不过几个周期而已。但是对于更大的素数,这样的计算过程就不得不由用户来设计,为了计算两个超过 64位的整数的模,用户也许不得不采用类似于多位数除法手算过程中的试商法,这个过程不但复杂,而且消耗了很多CPU时间。对于现代密码算法,要求计算 128位以上的素数的情况比比皆是,设计这样的程序迫切希望能够抛弃除法和取模。

Stein算法由J. Stein 1961年提出,这个方法也是计算两个数的最大公约数。和欧几里德算法算法不同的是,Stein算法只有整数的移位和加减法,这对于程序设计者是一个福音。

为了说明Stein算法的正确性,首先必须注意到以下结论:

g(a,a) = a,也就是一个数和他自身的公约数是其自身
g(ka,kb) = k g(a,b),也就是最大公约数运算和倍乘运算可以交换,特殊的,当k=2时,说明两个偶数的最大公约数必然能被2整除。

现在算法的完整实现代码如下(C++)

 

/******************************************************************* 

   文件名: G.cpp
   摘要: 求最大公约数,欧几里德算法与Stein算法的实现
   开发平台: Win Xp SP2
   编译环境: CL.exe 8.0 (in Visual Studio 2005 SDK)
   作者: 88250
   完成日期: 2007-1-21    版本: 1.0
   Blog: 
http://DL88250.ynutx.net
   E-mail: DL88250@gmail.com
   QQ: 845765 or 316281008
                                        
 ******************************************************************
*/ 

#include 
<iostream>

using namespace std;

int Euclid(int a,int b) 

        
if (0 == a) 
    {
        
return b;
    }
        
if (0 == b)       
    {
        
return a;
    }
        
if (a > b) 
    {
        
int t = a;
        a 
= b;
        b 
= t;
    }
          
        
for (int c = a % b; c > 0; c = a % b) 
        { 
        a 
= b;
        b 
= c;
    } 
    
return b; 
}

int Stein(int a, int b)
{
    
int aa[255= {0};
    
int ba[255= {0};
    
int ca[255= {0};
    aa[
0= a;
    ba[
0= b;
    ca[
0= 1;
    
for (int i = 0; i < 255; i++)
    {
        
if (0 == aa[i])
        {
            
return ba[i];
        }
        
if (0 == ba[i])
        {
            
return aa[i];
        }
        
if ((0 == (aa[i] & 1)) && (0 == (ba[i] & 1)))
        {
// 都是偶数
            aa[i+1= aa[i] >> 1;
            ba[i
+1]    = ba[i] >> 1;
            ca[i
+1= ca[i] << 1;
        }    
        
if ((0 == (aa[i] & 1)) && (1 == (ba[i] & 1)))
        {
// an是偶数,bn不是
            aa[i+1= aa[i] >> 1;
            ba[i
+1]    = ba[i];
            ca[i
+1= ca[i];
        }
        
if ((0 == (ba[i] & 1)) && (1 == (aa[i] & 1)))
        {
// bn是偶数,an不是
            ba[i+1= ba[i] >> 1;
            aa[i
+1]    = aa[i];
            ca[i
+1= ca[i];
        }
        
if ((1 == (ba[i] & 1)) && (1 == (aa[i] & 1)))
        {
// 都不是偶数
            aa[i+1= abs(ba[i] - aa[i]);
            ba[i
+1]    = aa[i] < ba[i] ? aa[i]:ba[i];
            ca[i
+1= ca[i];
        }
    }
}

int main(int argc, char *argv[])
{
    cout 
<< Euclid(5025<< endl;
    cout 
<< Stein(5025<< endl;

        
return 0;
}

 

c
原创粉丝点击