辗转相除法基于如下原理:两个整数的最大公约数等于其中较小的数和两数的差的最大公约数,这是一个递归过程。
辗转相除法更像辗转相减法,因为辗转一次可能要减好几次,就变成了除法(取余操作)。
执行过程
假设要求自然数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)); }
原文:http://www.cnblogs.com/redhead/p/3660228.html