アルゴリズムについて
最大公約数をgcd(x,y)とし、
x、yがともに偶のとき,gcd(x,y)→2*gcd(x/2,y/2)
xが奇,yが偶のとき、gcd(x,y)→gcd(x,y/2)
x,yどちらも奇のとき、gcd(x,y)→gcd((x,y)/2,y)
という要領で計算します。
これが間違っています。
まず、互除法をちゃんと理解しましょう。
gcd((x-y)/2,y)が正しいとのことなので、互除法はわかっていますね。
プログラムのデバッグについて
突然、大きな数字でやるのではなく、小さな数字から始めましょう。
2と3の最大公約数は求められるでしょうか。
python
1def gcd(x, y):
2 if y==0:
3 return x
4 elif x&1==0 and y&1==0 and y!=0:
5 x, y=x/2, y/2
6 return 2*gcd(x, y)
7 elif x&1==0 and y&1==1 and y!=0:
8 x=x/2
9 return gcd(x, y)
10 elif x&1==1 and y&1==0 and y!=0:
11 y=y/2
12 return gcd(x, y)
13 elif x&1==1 and y&1==1 and x<y and y!=0:
14 x, y=x, (y-x)/2
15 return gcd(x, y)
16 else:
17 x, y=(x-y)/2, y
18 return gcd(x, y)
19
20print(gcd(2,3))
実行するとエラーが出ますね。
python
1> python gcd.py
2Traceback (most recent call last):
3 File "gcd.py", line 20, in <module>
4 print(gcd(2,3))
5 File "gcd.py", line 9, in gcd
6 return gcd(x, y)
7 File "gcd.py", line 4, in gcd
8 elif x&1==0 and y&1==0 and y!=0:
9TypeError: unsupported operand type(s) for &: 'float' and 'int'
4行目、つまり elif x&1==0 and y&1==0 and y!=0:のところで、float型とint型で&はできませんというエラーメッセージが出ています。これは理解できますか。
自力で解決できたようなので、いくつかのサンプルを載せておきます。
syoutaro22さんのアルゴリズムですが、これは互減法のアルゴリズムに2だけ割るアルゴリズムを付け加えたものです。こういう発想はプロ的なのですが、syoutaro22さんは初心者ということですので、たまたま思いつけたということなのでしょう。一般的には、数字が小さいときには互減法は互除法より高速なのです。python3の場合は、64ビットを超えると整数の割り算が極端に遅くなるので、その場合も有効かもしれません。
互減法は、割り算機能のついていない組み込み用の小さなCPUなどでも使います。
互減法については最大公約数をもっと高速に求めるなどを見てみてください。
python
1def gcd(x, y):
2 if y==0:
3 return x
4 elif x < y:
5 return gcd(y, x) #こうやっておいたほうが間違いが少ない。
6 elif x&1==0 and y&1==0:
7 return 2*gcd(x//2, y//2)
8 elif x&1==0 and y&1==1:
9 return gcd(x//2, y)
10 elif x&1==1 and y&1==0:
11 return gcd(x, y//2)
12 elif x&1==1 and y&1==1:
13 return gcd(x-y, y) # 大きいほうから小さいほうを引く
14 else:
15 print('proguram error') # ここに来るならプログラムの間違い
16 raise(Exception)
一方、互除法でやるには、y_waiwaiさんが勧めていたようにやります。以下をご覧下さい。
python
1def gcd(x, y):
2 if x < y:
3 return gcd(y, x)
4 elif y==0:
5 return x
6 elif x == x // y*y:
7 return y
8 else:
9 return gcd(x-y, y)