アルゴリズム論特論(塩田)第3回 (4) 拡張ユークリッドアルゴリズム
拡張ユークリッドアルゴリズム
ユークリッドのアルゴリズムを改良して
ax+by=gcd(a,b)
を満たす
x,
y も求めましょう。
Algorithm 9 (拡張ユークリッドアルゴリズム)
- 入力:a, b
- 出力:d=gcd(a,b) と、ax+by=gcd(a,b) を満たす x, y
- 3つの数列 {rn}, {xn}, {yn} を宣言する
- r0←a, r1←b,
x0←1, x1←0, y0←0, y1←1, n←0 とおく
- rn+1=0 ならば 5° へ
- q←(rn÷rn+1 の商 ),
rn+2←rn−q×rn+1,
xn+2←xn−q×xn+1,
yn+2←yn−q×yn+1,
n←n+1 として 3° へ
- rn<0 ならば (rn,xn,yn)←(−rn,−xn,−yn),
- (d,x,y)=(rn,xn,yn) を出力
証明 {rn} は
Alg.6 と同じものなので、
出力の
d が
gcd(a,b) であることと、
有限回のステップで終了することは証明できています。
あとは、全ての番号
n について
rn=axn+byn
が成り立つことを帰納法で示します。
n=0,
1 のときは、初期値設定から
r0=a=a×1+b×0=ax0+by0,
r1=b=a×0+b×1=ax1+by1
となって成り立っています。
n,
n+1 のとき正しければ
rn+2 | = | rn−q×rn+1 |
| = | (axn+byn)−q×(axn+1+byn+1) |
| = | a(xn−q×xn+1)+b(yn−q×yn+1) |
| = | axn+2+byn+2. |
(証明終)
実行例
Ex.10 13579x+2468y=1 を満たす
x,
y は?
n | q | rn | xn | yn |
0 | | 13579 | 1 | 0 |
1 | | 2468 | 0 | 1 |
2 | 5=⌊13579/2468⌋ | 1239 | 1 | −5 |
3 | 1=⌊2468/1239⌋ | 1229 | −1 | 6 |
4 | 1=⌊1239/1229⌋ | 10 | 2 | −11 |
5 | 122=⌊1229/10⌋ | 9 | −245 | 1348 |
6 | 1=⌊10/9⌋ | 1 | 247 | −1359 |
7 | 9=⌊9/1⌋ | 0 | | |
rn が
0 になる直前の行から
gcd(13579,2468)=1=13579×247+2468×(−1359).
( 表の作り方:
r2=r0−5×r1=13579−5×2468=1239
に合わせて
x2=x0−5×x1=1−5×0=10
y2=y0−5×y1=0−5×1=−5
のように計算します。)
Ex.10' 13579x+2468y=1 を満たす
x,
y を、負の余りも使うパターンでも計算してみましょう。
n | q | rn | xn | yn |
0 | | 13579 | 1 | 0 |
1 | | 2468 | 0 | 1 |
2 | 6=round(13579/2468) | −1229 | 1 | −6 |
3 | −2=round(2468/(−1229)) | 10 | −2 | 13 |
4 | −123=round((−1229)/10) | 1 | 247 | −1359 |
5 | 10=round(10/1) | 0 | | |
rn が
0 になる直前の行から
gcd(13579,2468)=1=13579×247+2468×(−1359).
プログラミング上の注意
- 数列 {rn}, {xn}, {yn} はいずれも直前の 2 項しか残す必要が無いので、変数を使い回せば配列を使わなくて済みます。
- y は y=(gcd(a,b)−ax)/b によって計算できるので、必ずしも {yn} を計算しなくて済みます。
- 整数商は、Python 2 では / でも // でもOKですが、Python 3 では // と書いてください。
Python3 で / を使うと実数値での計算結果が返されてしまいます。