P207: Determine the greatest common divisor of two positive integer numbers

求最大公约数。

最大公因数

最大公因数(英语:highest common factor,hcf)也称最大公约数(英语:greatest common divisor,gcd)是数学词𢑥,指能够整除多个整数的最大正整数。而多个整数不能都为零。例如8和12的最大公因数为4。 整数序列的最大公因数可以记为。 求两个整数最大公因数主要的方法:

  • 穷举法:分别列出两整数的所有因数,并找出最大公因数。
  • 质因数分解:分别列出两数的质因数分解式,并计算共同项的乘积。
  • 短除法:两数除以其共同质因数,直到两数互质时,所有除数的乘积即为最大公因数。
  • 辗转相除法:两数相除,取余数重复进行相除,直到余数为0时,直到余数为0时,前一个除数即为最大公因数。wiki-hcf

照例先写测试用例:

from python99.arithmetic.p207 import gcd def test_gcd(): assert gcd(36, 63) == 9

「辗转相除法」是一个简单有效的求最大公约数的方法。

辗转相除法

在数学中,辗转相除法,又称欧几里得算法(英语:Euclidean algorithm),是求最大公因数的算法。辗转相除法首次出现于欧几里得的《几何原本》(第VII卷,命题i和ii)中,而在中国则可以追溯至东汉出现的《九章算术》。wiki-division

计算过程

辗转相除法是一种递回算法,每一步计算的输出值就是下一步计算时的输入值。设k表示步骤数(从0开始计数),算法的计算过程如下。

每一步的输入是都是前两次计算的非负余数。因为每一步计算出的余数都在不断减小,所以,小于。在第k步中,算法计算出满足以下等式的商和余数

其中。也就是要不断减去直到比小。

为求简明,以下只说明如何求两个非负整数a和b的最大公约数(负数的情况是简单的)。在第一步计算时(k = 0),设分别等于a和b,第2步(此时k = 1)时计算(即b)和(第一步计算产生的余数)相除产生的商和余数,以此类推。整个算法可以用如下等式表示:

如果有,算法的第一步实际上会把两个数字交换,因为这时a除以b所得的商会等于0,余数则等于a。然后,算法的第二步便是把b除以a,再计算所得之商和余数。所以,对于总有,即运算的每一步中得出的余数一定小于上一步计算的余数。 由于每一步的余数都在减小并且不为负数,必然存在第N步时等于0,使算法终止,就是a和b的最大公因数。其中N不可能无穷大,因为在和0之间只有有限个自然数。wiki-division

完整的代码实现:

# Determine the greatest common divisor of two positive integer numbers # Use Euclid's algorithm def gcd(a, b): return euclid(max(a, b), min(a, b)) def euclid(a, b): # expect a > b r0 = a % b if r0 ==0: return b r1 = b % r0 if r1 == 0: return r0 else: return euclid(r0, r1)

辗转相除法(euclid(a,b))是一个递归算法。其接受两个整数a和b,且a>b(所以需要在外层按大小排列好两个整数),求出余数r0r1r0 = a % b, r1 = b % r0

  • r0为0则b为最大公约数;
  • r1为0则r0为最大公约数;
  • r0r1皆不为0则r0, r1的最大公约数即是a, b的最大公约数,问题被简化为求r0, r1的最大公约数。

举个例子,输入整数36和63,求最大公约数:

  1. 63大于36,以63为a以36为b,求得r0为27,r1为9。r0r1皆不为0,所以求27和9的最大公约数。
  2. 27为a,9为b,求得r0为0则b 9为最大公约数。

参考文献

wiki-hcf. https://zh.wikipedia.org/wiki/最大公因数
wiki-division. https://zh.wikipedia.org/wiki/辗转相除法

results matching ""

    No results matching ""