拡張ユークリッドの互除法は逆元の計算に利用できるアルゴリズムですね。逆元を求めれば、mod上で割り算をすることができます。この記事では逆元を計算することにフォーカスして、2種類の実装から拡張ユークリッドの互除法を理解することを目指します!ここの記事ではユークリッドの互除法については解説していません。
拡張ユークリッドの互除法
modp上での整数nに対する逆元は以下のように表すことができます。pは素数とします。
n−1∗n=1modp
逆元の定義はnにかけたとき、1になる数なのでこれは明らかです。次に右辺を移項します。
n−1∗n−1=0modp
これにより、n∗n−1−1がpで割り切れることになります。つまり任意の整数mを使って
n−1∗n−1=m∗p
と表すことができます。これを式変形すると
n−1∗n+m∗p=1
となります。拡張ユークリッドの互除法は
a,bを0でない整数とする。以下を満たすx,yが存在し、計算することが出来る。
x∗a+y∗b=GCD(a,b)
というアルゴリズムでした。n−1∗n+m∗p=1を見ると、GCD(n,p)=1ならn−1とmを求めるのに利用できそうです。つまり、拡張ユークリッドの互除法で逆元が計算できます。
n,pを0でなく互いに素な整数とする。以下を満たすn−1,mが存在し、計算することが出来る。
n−1∗n+m∗p=1
以下ではこのn−1,mを計算するアルゴリズムを実装します!以下では、x∗a+y∗b=GCD(a,b)の表記を倣ってプログラムを書いています。例えば、x=n−1でy=mです。
表記について
以下のような表記が登場します。
ai∗xi+bi∗yi=1
この表記は変形の過程で現れる i番目の方程式 を表しています。読んでください。例えばi=1なら
a1∗x1+b1∗y1=1
です。なお、iは0から開始します。
その1 非再帰
まずは非再帰でユークリッドの互除法を実装します。飛ばして再帰の実装まで進んでも構いません。プログラムから見ていきます。
何やら1とか0とか出てきてよくわからないかもしれません。これはaとbが次のように表せる事実を利用しています。
1∗a+0∗b=a0∗a+1∗b=b
なぜこのような形にするのかといえば、拡張ユークリッドの式x∗a+y∗b=GCD(a,b)に形を合わせるためです。この方法では右辺ではユークリッドの互除法を行い、左辺は等式が成立するように式を変形させます。変形を繰り返して式が
GCD(a,b)=x∗a+y∗b
となったときのxとyが答えです。変形方法は以下のような式に表せます。
⎩⎨⎧x0∗a+y0∗b=r0 x1∗a+y1∗b=r1 (xi−2−xi−1∗⌊ri−1ri−2⌋)∗a+(yi−2−yi−1∗⌊ri−1ri−2⌋)∗b=ri−2modri−1=ri (i=0)(i=1)(2≤i)
(2≤i)の式が何やら複雑ですが、ここではまだわからなくても問題ありません。
具体例をあげましょう。a=97,b=53のとき0番目の方程式と1番目の方程式は
1∗97+0∗53=970∗97+1∗53=53
です。2番目を求めるためには(2≤i)の式を利用します。
r2=(x0−x1∗⌊r0r1⌋)∗a+(y0−y1∗⌊r0r1⌋)∗b=(1−0∗⌊5397⌋)∗97+(0−1∗⌊5397⌋)∗53=1∗97+(−1)∗53=44
となります。これは97mod53=44をx∗a+y∗bの形で表すことができたことになります!
もう一度やってみましょう。今回は3番目を求めます。変わらずa=97,b=53なので
r3=(x1−x2∗⌊r1r2⌋)∗a+(y1−y2∗⌊r1r2⌋)∗b=(0−1∗⌊4453⌋)∗97+(1−(−1)∗⌊4453⌋)∗53=(−1)∗97+2∗53=9
となります。これは53mod44=9をx∗a+y∗bの形で表すことができたことになります!
これをri=0まで繰り返します。
r4r5r6=5∗97+(−9)∗53=(1−(−1)∗4)∗97+(−1−2∗4)∗53=8=−6∗97+11∗53=(−1−5∗1)∗97+(2−(−9)∗1)∗53=1=0
6番目でr4modc5=0で割り切れているので、5番目のときの右辺1がGCD(97,53)であり、(x5,y5)=(−6,11)が拡張ユークリッドの互除法の答えになります。
実際に97∗(−6)mod53=1なので逆元となっていますね。
i<=2の式について
(2≤i)の式について解説します。最初、aとbは次のように表しました。
1∗a+0∗b=a0∗a+1∗b=b
amodbはaとbの商q=⌊ba⌋を使って次のように表せます。
amodb=a−q∗b
これは上述の式を使うと
a−q∗b=1∗a+0∗b−(0∗a+1∗b)∗q
これをaとbごとにくくると、
1∗a+0∗b−(0∗a+1∗b)∗q=(1−0∗q)∗a+(0−1∗q)∗b
と表せます。つまり、2番目は0番目と1番目から計算できます。同様に3番目を1番目と2番目から計算し....を繰り返して変形し続ければ、i番目をi−2番目とi−1番目から求める時、ri−2modri−1=0ならri−1の右辺がGCD(a,b)となっています。
上の式を一般化することを考えます。r0=a,r1=bとし
(1−0∗q)∗a+(0−1∗q)∗b=(x0−x1∗q)∗a+(y0−y1∗q)∗b
とします。q=⌊ri−1ri−2⌋なので
(xi−2−xi−1∗⌊ri−1ri−2⌋)∗a+(yi−2−yi−1∗⌊ri−1ri−2⌋)∗b=ri−2modri−1=ri
と一般化できます。これは(2≤i)の式です。
実装との対応
プログラムは次のような内容でした。
次の4行は
次の初期条件を設定しています。
{x0∗a+y0∗b=r0 x1∗a+y1∗b=r1 (i=0)(i=1)
次の4行は
次の式と対応しています。
⌊ri−1ri−2⌋ri−2modri−1xi−2−xi−1∗⌊ri−1ri−2⌋yi−2−yi−1∗⌊ri−1ri−2⌋
その2 再帰
次は再帰でユークリッドの互除法を書いてみます。次のようになります。
また、a0=97とb0=53の例でやってみます。まずはやることは、a=b,b=amodbを繰り返すだけです。ユークリッドの互除法と同じですね。
x0∗97+y0∗53=GCD(97,53)
このとき、
ab=53=97mod53=44
となります。よって、1番目の方程式は
x∗53+y∗44=1
です。これをb=0まで繰り返します。
x∗53+y∗44=1x∗44+y∗9=1x∗9+y∗8=1x∗8+y∗1=1x∗1+y∗0=1
5番目の方程式で、b=0になりました。ここで再帰が終わるので解を復元します。まず、1つ前の4番目の方程式のx4とy4を求めることを考えます。i番目のx,yをそれぞれxi,yiとすると以下で求まります。
x4y4=y5=0=x5−y5∗q=1−0∗18=1
これを一般化すると次のようになります。
xiyi=yi+1=xi+1−yi+1∗⌊biai⌋
適用を繰り返すことで、与式97∗x0+53∗y0∗1のx0とy0を求められそうです。実際に適用してみると
x4y4x3y3x2y2x1y1x0y0=y5=0=x5−y5∗⌊b4a4⌋=1−0∗⌊18⌋=1=y4=1=x4−y4∗⌊b3a3⌋=0−1∗⌊89⌋=−1=y3=−1=x3−y3∗⌊b2a2⌋=1−(−1)∗⌊944⌋=5=y2=5=x2−y2∗⌊b1a1⌋=−1−5∗⌊4453⌋=−6=y1=−6=x1−y1∗⌊b0a0⌋=−5−(−6)∗⌊5397⌋=11
(x,y)=(−6,11)です。実際に97∗(−6)mod53=1なので逆元となっていますね。
式の解説
xiyi=yi+1=xi+1−⌊biai⌋∗yi+1
この式はどこから出てきたのでしょう。i=0の例を考えます。
x0∗a0+y0∗b0=1
ここでa0=q∗b0+rとして、a0を使わずに等式を成立させることを考えます。ここでq=⌊a0/b0⌋,r=a0−q∗b0です。つまり、商と余りです。
x0∗(q∗b0+r)+y0∗b0=1
です。このとき
x0∗(q∗b0+r)+y0∗b0=b0∗(x0∗q+y0)+r∗x0
この式をc1として書き換えると
b0∗(x0∗q+y0)+r∗x0=a1∗x1+b1∗y1=1
ですね!これにより、
x1y1=x0∗q+y0=x0
であったことが分かります。これをx0,y0についての方程式にすると
y0x0=x1−x0∗q=y1
ですね。結局x0=y1なので、
x0y0=y1=x1−y1∗q
であり、これは一般化した式そのものです。さらにa1=b0,a1=a0modb0になっていることも分かります。
実装との対応
プログラムは次のような内容でした。
まず、次の部分はa=b,b=amodbを繰り返して、b=0で再帰を打ち切っています。b=0まではこの2行しか実行されません。
次の部分は
以下と対応しています。
⌊biai⌋xi=yi+1yi=xi+1−⌊biai⌋∗yi+1
まとめ
ユークリッドの互除法は比較的理解しやすいアルゴリズムだと思うのですが、拡張ユークリッドの互除法はアルゴリズムとして記述すると複雑になりがちだと思います。この記事を通して自分のアルゴリズムへの理解が随分深まりました。
間違いや質問がありましたらコメントまでよろしくおねがいします!
Discussion
こんにちは。とても勉強になりました。
めちゃくちゃ些細で釈迦に説法ではありますが、
冒頭の部分
m*p を左辺に持ってきているので -m * p が良さそうですかね。
m' =-m とおくのでも良いかもです。
そもそもmは任意の整数なのであれですが..