ユークリッドの互除法は,紀元前300年頃に記された『原論』に登場する,人類最古のアルゴリズムのひとつです.しかし教科書では「gcd(a,b)=gcd(b,amodb)」と書いて終わりがちです.なぜこの操作で最大公約数が求まるのでしょうか?
1 最大公約数の定義
整数 a,b(ともに 0 でない)の最大公約数gcd(a,b) とは,a と b の両方を割り切る正の整数のうち最大のものです.
2 引き算による素朴な方法
最大公約数を求める最も素朴な方法は,引き算の繰り返しです.
a>b>0 のとき,gcd(a,b)=gcd(a−b,b).
d∣a かつ d∣b ならば d∣(a−b).逆に d∣(a−b) かつ d∣b ならば d∣a.よって a,b の公約数の集合と a−b,b の公約数の集合は一致し,その最大値も一致します. □
gcd(48,18) を引き算で求めます: gcd(48,18)=gcd(30,18)=gcd(12,18)=gcd(12,6)=gcd(6,6)=6
この方法は正しいですが,aとbの差が大きいと非常に遅くなります(gcd(109,1)は109回の引き算が必要).
3 割り算への改良 ― なぜ高速化するか
引き算を繰り返す代わりに,一気に割り算してしまいましょう.
a≥b>0 のとき,gcd(a,b)=gcd(b,amodb).
a=qb+r(0≤r<b)とします.d∣a かつ d∣b ならば d∣(a−qb)=r.逆に d∣b かつ d∣r ならば d∣(qb+r)=a.よって gcd(a,b)=gcd(b,r). □
ユークリッドの互除法の計算量は O(log(min(a,b))) です.
4 ベズーの等式 ― GCD は線形結合で書ける
整数 a,b に対し, gcd(a,b)=ax+by
をみたす整数 x,y が存在します.
ユークリッドの互除法を逆にたどることで構成的に x,y を求められます.基底ケース gcd(d,0)=d=d⋅1+0⋅0.再帰ステップ:gcd(b,amodb)=bx′+(amodb)y′ と書けているとき,amodb=a−⌊a/b⌋b を代入すると gcd(a,b)=ay′+b(x′−⌊a/b⌋y′). □
5 拡張ユークリッドの互除法
ベズーの等式の証明をアルゴリズムにしたのが拡張ユークリッドの互除法です.
gcd(111,30) を求め,111x+30y=gcd(111,30) の解を構成します:
111=3×30+21
30=1×21+9
21=2×9+3
9=3×3+0
よって gcd(111,30)=3.逆にたどると:
検算:3×111−11×30=333−330=3.正しいです.
6 逆元計算への応用
gcd(a,n)=1 のとき,ax≡1(modn) をみたす x が存在します.この x を a の n を法とする逆元と呼びます.
ベズーの等式より ax+ny=1 となる x,y が存在します.両辺を modn で見ると ax≡1(modn) です. □
7 まとめ
GCD の計算は「公約数の集合が不変」という不変量に基づいています
引き算 → 割り算の改良で O(log) の高速アルゴリズムになります
ベズーの等式は GCD が線形結合で表せることを保証します
拡張ユークリッドにより,mod 逆元が効率的に計算できます
次の記事では,整数の「原子」である素数と,算術の基本定理がなぜ成り立つのか(そしてどこで崩壊するのか)を見ていきます.