1. 程式人生 > >[Python3 練習] 008 歐幾裏德算法

[Python3 練習] 008 歐幾裏德算法

余數 greate 情況 方法 tro 原來 要求 iso clas

題目:寫個“歐幾裏德算法”的小程序

(1) 描述

  • 我知識淺薄,一開始被“歐幾裏德”的大名唬住了,去搜了一下才知道這就是高中時學過的“輾轉相除法”
  • 輾轉相除法的用處
    • 求兩個正整數的最大公約數
  • 示例
    • a = 30,b = 18,求 a 與 b 的最大公約數
      1. a % b = 12 => a = 18, b = 12
      2. a % b = 6 => a = 12, b = 6
      3. a % b = 0 => 此時的 b 即為原來兩數的最大公約數
  • 總結
    1. 大的數 num1 對小的數 num2 取余
    2. 把 num2 的值賦給 num1,把余數賦給 num2,再進行上一步操作,直到余數為 0
    3. 余數為 0 的那個式子中的 num2 即為最大公約數

(2) 證明

  • 方法來自互聯網

1) 證明方法1

設 num1,num2,m,r,d 均為自然數

不妨設 num1 > num2,d 為兩個數的任意一個公約數;m 表示倍數,r 表示余數

num1 = m * num2 + r

=> r = num1 - m * num2

等式兩邊同除以 d,得 r/d = (num1 - m * num2)/d = num1/d - m * num2/d

因為 d 為 num1,num2 的公約數,且 m 為自然數

所以 r/d 也是自然數

=> d 必是 r 的約數

=> 求 num1 與 num2 的最大公約數,可以轉為求 num2 與 r 的最大公約數

2) 證明方法2

令 d 為 num1,num2 的最大公約數

取 num1 的某一個約數 m1,num2 的某一個約數 m2,使得 num1 = m1 * d,num2 = m2 * d —— (1)

不妨設 r = num1 % num2 = num1 - m * num2 —— (2)

將 (1) 代入 (2),得 r = m1 * d - m * (m2 * d) = (m1 - m * m2) * d

=> d 也是余數 r 的約數

若 (m1 - m * m2) 與 m2 不互質

不妨設 (m1 - m * m2) = k1 * d‘,m2 = k2 * d‘,(d‘>1)

m1 = m * m2 + k1 * d‘ = m * (k2 * d‘) + k1 * d‘ = (m * k2 + k1) * d‘

=> num1 = m1 * d = [(m * k2 + k1) * d‘] * d = (m * k2 + k1) * (d‘ * d)

? num2 = m2 * d = (k2 * d‘) * d = k2 * (d‘ * d)

=> num1 與 num2 有公約數 (d‘ * d)

因為 d‘ > 1,d >= 1

所以 (d‘ * d) > d

=> 與題設矛盾

=> (m1 - m * m2) 與 m2 互質

=> d 也是 num2 與 r 的最大公約數

(3) 要求

  • 寫出“歐幾裏德算法”的程序,起名為 gcd()
    • gcd 為 Greatest Common Divisor(最大公約數) 的縮寫

(3) 程序

1) 代碼

# 解法1

def gcd(num1, num2):    # 不需要規定 x > y,就算 x < y,取一次余就換回來了
    while num2 != 0:
        t = num1 % num2
        num1 = num2
        num2 = t
    
    return num1
# 解法2 更貼近算法的描述

def gcd(num1, num2):
    while num1:
        num1, num2 = num2 % num1, num1
 
    return num2

2) 運行情況

>>> print(gcd(16, 36))

4

[Python3 練習] 008 歐幾裏德算法