ユークリッド互除法
2数の最大公約数を求める。
拡張ユークリッド互除法
2数 x,y の最大公約数 gcd(x,y) とともに、
ax+by=gcd(x,y)
となる (a,b) の組の1つも見つける。
組の1つが見つかれば、後は u=xgcd(x,y),v=ygcd(x,y) として
...,(a−2v,b+2u),(a−v,b+u),(a,b),(a+v,b−u),(a+2v,b−2u),...
が過不足なく全て等式を満たす組となる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 引用(もといパクリ) # Python で RSA 公開鍵暗号をなぞってみる - CAMPHOR- Tech Blog def ex_euclid(x, y): c0, c1 = x, y a0, a1 = 1 , 0 b0, b1 = 0 , 1 while c1 ! = 0 : m = c0 % c1 q = c0 / / c1 c0, c1 = c1, m a0, a1 = a1, (a0 - q * a1) b0, b1 = b1, (b0 - q * b1) return c0, a0, b0 |
ユークリッドの互除法の調整
互除法とは直接関係ないが、一緒に使うことがある制約条件について。
- x,y,z から、ax+by=z となる a,b を求める
- ただし a≥0,b≥0
- a をあり得る中で最小にする
a,b が正という条件で全探索する時、a を最小(最大でもいいが)にしておくとやりやすい。
まず、c=gcd(x,y) として、z が c の倍数で無い場合、等式は不可能である。
次に、拡張ユークリッド互除法で a′x+b′y=c となる a′,b′ を求める。w=zc とすると、a′xw+b′yw=cw=z となり、(a,b)=(a′w,b′w) が答えの一つとなる。
その後、非負チェックと a の最小化を行う。a は v=yc 単位でしか増減できないので a%v が最小値となる。負の場合だが、pythonでは a が負であっても a%v で正の最小値が求まる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
def exex_euclid(x,y): c, a, b = ex_euclid(x, y) w, m = divmod (z, c) # zがcの倍数でないなら等式は不可能 if m ! = 0 : return None u, v = x / / c, y / / c a, b = a * w, b * w # aを非負数の中で最小にする f, a = divmod (a, v) b + = u * f # aを最小にしたのにbが負なら、ともに正の組は不可能 if b < 0 : return None return c, a, b, u, v |