最小公倍数を求める
ユークリッドの互除法 により、最大公約数 (GCD: Greatest Common Divisor) を求めます。
正の整数 a, b (a > b) の最大公約数 GCD(a, b)
を求めたいとします。
まず、a が b で割り切れれば、明らかに b が最大公約数になりますので、答えは b です。 問題は割り切れない場合です。 a, b が最大公約数 d を持つとすると、
a = md
b = nd
と書けます。すると、
a-b = (m-n)d
となるので、a-b も最大公約数 d を持つことが分かります。 言い換えると、d の倍数(この場合は a)から d の倍数(この場合は b)を引いても、残りは d の倍数であるということです。
GCD(a, b) = GCD(a-b, b) ただし、a > b
依然として a-b > b のときは、同様に左側の値から b を引き続けて、
GCD(a, b) = GCD(a-b, b)
= GCD(a-2b, b)
= GCD(a-3b, b)
= ...
= GCD(a%b, b) // a%b は a を b で割った時の剰余
結局は、最大公約数は b 以上になることはないので、最後の GCD(a%b, b) を求めるのが一番楽というところに落ち着きます。
簡潔に書くために、a%b = r とおくと、
GCD(a, b) = GCD(r, b)
= GCD(b, r) (b > r なので分かりやすく左に大きい数値をも持ってきた)
この時点で、最初の問題 GCD(a, b) は、より小さな問題 GCD(b, r) に変換できました!!
あとはこの変換を繰り返すだけです。
b が r で割り切れるのであれば、r が最大公約数になります。 まだ割り切れないのであれば、再び GCD(a, b)=GCD(b, a%b) の変換を適用して問題を小さくしていきます。
2 つの数が互いに素(最大公約数が 1)である場合は、最終的に剰余が 1 になった時点で割り切れることになります。1 で割れば余りは必ず 0 になるので、最大公約数が 1 であるという答えが出ます。
最小公倍数 (LCM) を求める
最大公約数 (GCD) を d とすると、a, b の最小公倍数 (LCM) は以下のように求められます。
LCM(a, b) = d * (a/d) * (b/d)
これは、以下のように説明できます。
例えば、30 と 105 の GCD, LCM を求めるとして、それぞれを因数分解すれば以下のように表現できます。
30 = 2 * 3 * 5
105 = 3 * 5 * 7
----------------------------
3 * 5 が最大公約数 (d)
2 * 3 * 5 * 7 が最小公倍数
最大公約数は因数の AND を取った部分 なので、35 となり、最小公倍数は因数の OR を取った部分 なので、2357 となります。 最小公倍数を構成している因数のうち、共通部分は d、30 の因数にしか含まれていないものは 30/d、105 の因数にしか含まれていないものは 105/d で求められます。結局、最小公倍数 (LCM) は以下のように求められます。
LCM(30, 105) = d * 30/d * 105/d
Python と Ruby で実装してみる
Python で最大公約数 (gcd) を求める
Python で最小公倍数 (lcm) を求める
Python で 3 値以上の gcd、lcm を求める
Python の functools.reduce
を使って以下のように求められます。
内部的には次のような処理が行われます。
Ruby で最大公約数 (gcd) を求める
Ruby では 0 が真 (true) になるので、while not b == 0
の部分は、while b
とは書けません。