最大公约数——辗转相除法

辗转相除法基于如下原理:两个整数的最大公约数等于其中较小的数和两数的差的最大公约数,这是一个递归过程。

辗转相除法更像辗转相减法,因为辗转一次可能要减好几次,就变成了除法(取余操作)。

执行过程

假设要求自然数a、b的最大公约数,商依次为q0, q1, ..., qn, 余数依次为r1, r2, ..., rn,则执行过程如下:

a = q0 * b + r0;

b = q1 * r0 + r1;

r0 = q2 * r1 + r2;

r1 = q3 * r2 + r3;

...

rn-3 = qn-1 * rn-2 + rn-1;

rn-2 = qn * rn-1 + rn;

如果rn = 0; 则rn-1即为a、b的最大公约数。

证明

辗转相除法的正确性可以通过两步来证明。首先,算法的最终结果rn−1同时整除a和b。因为它是一个公约数,所以必然小于或者等于最大公约数g。然后,任何a和b的公约数都能整除rn−1。所以g一定小于或等于rn−1。两个不等式只在rn−1 = g是同时成立。具体证明如下:

1、证明rn-1是a和b的一个公约数,即rn-1能够a和b。

  因为rn-2 = qn * rn-1 + rn、rn = 0,所以

    rn-2 = qn * rn-1;

  因为rn−1能够整除rn−2,所以也能够整除rn-3:

    rn-3 = qn-1 * rn-2 + rn-1 = qn-1 * (qn * rn-1) + rn-1 = (qn-1 * qn  + 1) * rn-1;

  同理可证rn−1可以整除所有之前步骤的余数,包括a和b,即rn−1是a和b的一个公约数,rn−1 ≤ g。

2、证明任何整除a和b的自然数g(也就是a和b的公约数)都能整除rn-1:

  根据定义,a和b可以写成g的倍数:a = mg、b = ng,其中m和n是自然数。

  因为r0 = a − q0 * b = mg − q0 * ng = (m − q0 * n)g,所以g整除r0。

  同理可证g整除每个余数r1, r2, …, rn-1

  综上所述,g = GCD(a, b) = GCD(b, r0) = GCD(r0, r1) = … = GCD(rn−2, rn−1) = rn−1

C语言实现

int function(int a, int b) {
    if(a == 0)
        return b;
    if(b == 0)
        return a;
    return function(b, a % b);
}

实际上,最大公约数对浮点数也是适用的:

#define feq(a, b) (fabs(a - b) < 1E-4)
double fgcd(double a, double b){
     if (feq(a, 0))
         return b;
     if (feq(b, 0))
         return a;
     return fgcd(b, fmod(a, b));
}

 

posted @ 2014-04-12 11:41  Shanks-香克斯  阅读(1347)  评论(0编辑  收藏  举报