zoukankan      html  css  js  c++  java
  • Python 最大公约数的欧几里得算法及Stein算法

    greatest common divisor(最大公约数)

    1.欧几里得算法

    欧几里德算法又称辗转相除法,用于计算两个正整数a,b的最大公约数。

    其计算原理依赖于下面的定理:
    两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数。
    最大公约数(greatest common divisor)缩写为gcd。
    gcd(a,b) = gcd(b,a mod b) (不妨设a>b 且r=a mod b ,r不为0),以此辗转相除得到最终结果。
     
    证明:
    a可以表示成a = kb + r(a,b,k,r皆为正整数,且r<b),则r = a mod b
    假设d是a,b的一个公约数,记作d|a,d|b,即a和b都可以被d整除。
    而r = a - kb,两边同时除以d,r/d=a/d-kb/d=m,等式左边可知m为整数,因此d|r
    因此d也是b,a mod b的公约数
    因此(a,b)和(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证。
     
    代码实现:
    C++:
    int gcd(int a,int b){
        if (a < b)
            std::swap(a, b);
        return b == 0 ? a : gcd(b, a % b);        
    }

    Python:

    函数内递归

    1 def gcd(a, b):
    2     if a < b:
    3         a, b = b, a
    4     while b != 0:
    5         a,b = b,a%b
    6     return a

    函数递归:

    1 def gcd(a, b):
    2     if b == 0:
    3         return a
    4     return gcd(b, a % b)

    2.Stein算法:

    欧几里德算法是计算两个数最大公约数的传统算法,无论从理论还是从实际效率上都是很好的。但是却有一个致命的缺陷,这个缺陷在素数比较小的时候一般是感觉不到的,只有在大素数时才会显现出来。
    一般实际应用中的整数很少会超过64位(当然现在已经允许128位了),对于这样的整数,计算两个数之间的模是很简单的。对于字长为32位的平台,计算两个不超过32位的整数的模,只需要一个指令周期,而计算64位以下的整数模,也不过几个周期而已。但是对于更大的素数,这样的计算过程就不得不由用户来设计,为了计算两个超过64位的整数的模,用户也许不得不采用类似于多位数除法手算过程中的试商法,这个过程不但复杂,而且消耗了很多CPU时间。对于现代密码算法,要求计算128位以上的素数的情况比比皆是,设计这样的程序迫切希望能够抛弃除法和取模。
     
    证明:
    由J. Stein 1961年提出的Stein算法很好的解决了欧几里德算法中的这个缺陷,Stein算法只有整数的移位和加减法,为了说明Stein算法的正确性,首先必须注意到以下结论:
    gcd(a,a)=a,也就是一个数和其自身的公约数仍是其自身。
    gcd(ka,kb)=k gcd(a,b),也就是最大公约数运算和倍乘运算可以交换。特殊地,当k=2时,说明两个偶数的最大公约数必然能被2整除。
    当k与b互为质数,gcd(ka,b)=gcd(a,b),也就是约掉两个数中只有其中一个含有的因子不影响最大公约数。特殊地,当k=2时,说明计算一个偶数和一个奇数的最大公约数时,可以先将偶数除以2。
     
    代码实现:
    Python:
     1 def gcd_Stein(a, b):  
     2     if a < b:
     3         a, b = b, a
     4     if (0 == b):
     5         return a
     6     if a % 2 == 0 and b % 2 == 0:
     7         return 2 * gcd_Stein(a/2, b/2)
     8     if a % 2 == 0:
     9         return gcd_Stein(a / 2, b)
    10     if b % 2 == 0:
    11         return gcd_Stein(a, b / 2)
    12     
    13     return gcd_Stein((a + b) / 2, (a - b) / 2) 
     
     
     
  • 相关阅读:
    PHP+MYSQL单例模式的滑铁卢
    碰到一个安装SQl2008 Express Edition出错的怪异情况
    用虚拟并口解决向USB条码打印机发送ZPL指令的解决方案
    让excanvas支持动态创建的canvas标签(附演示文件)
    sql 检索语句
    c++ string 类基本用法样例
    Sqlite c/c++ api 学习
    最常见的20种VC++编译错误信息
    C#动态调用C++编写的DLL函数
    C++中将BYTE转16进制字符串
  • 原文地址:https://www.cnblogs.com/Dragon5/p/6401596.html
Copyright © 2011-2022 走看看