class GCDTest {
// ユークリッドの互除法により最大公約数を計算するメソッド gcd の定義
// int型の引数 n, m をとり, int型の値を返す
static int gcd(int n,int m){
// デバッグ(プログラムのミスを直す)のための出力
System.out.println("gcd("+n+","+m+")が呼ばれました");
// 剰余を求めて rに入れる
int r=n%m;
// nがmの倍数になっているなら最大公約数は m自身になる.
if(r==0) return m;
// n,mの最大公約数は m,rの最大公約数と等しい
else return gcd(m,r);
}
public static void main(String[] args){
// コマンドラインから
// java GCDTest arg0 arg1
// のようにして起動した時, args[0] -> arg0, args[1] -> arg1 となる.
// 文字列から int 型の整数値に変換するのは Integer.parseInt を使う
int i0=Integer.parseInt(args[0]);
int i1=Integer.parseInt(args[1]);
System.out.println(i0+"と"+i1+"の最大公約数は"+gcd(i0,i1)+"です");
}
}
実行例は以下のようになる.
dell.tanaka.ecc.u-tokyo.ac.jp% java GCDTest 96 1024 gcd(1024,96)が呼ばれました gcd(96,64)が呼ばれました gcd(64,32)が呼ばれました 96と1024の最大公約数は32です
System.out.println("gcd("+n+","+m+")が呼ばれました");
にあたる表示は残しても残さなくても良い.
dell.tanaka.ecc.u-tokyo.ac.jp% java GCDTest 96 1024 96と1024の最大公約数は32です 96と1024の最小公倍数は3072ですヒント
解答例(1)
class GCDTest {
static int gcd(int n,int m){
// 剰余を求めて rに入れる
int r=n%m;
// 元のプログラムでは r==0 が再帰を終了するための条件だった
// 繰り返しの場合は,その否定である r!=0 が繰り返すための条件となる
while(r!=0){
// デバッグ(プログラムのミスを直す)のための出力
System.out.println("n="+n+",m="+m);
// 再帰における引数の置き換えをおこなう.下の2つの文の順序は大切
n=m;
m=r;
// 剰余を求めて rに入れる
r=n%m;
}
return m;
}
public static void main(String[] args){
// コマンドラインから
// java GCDTest arg0 arg1
// のようにして起動した時, args[0] -> arg0, args[1] -> arg1 となる.
// 文字列から int 型の整数値に変換するのは Integer.parseInt を使う
int i0=Integer.parseInt(args[0]);
int i1=Integer.parseInt(args[1]);
System.out.println(i0+"と"+i1+"の最大公約数は"+gcd(i0,i1)+"です");
}
}
上の文は while文を使った例です.for文を使って以下のように短く書くこと
も可能ですが,読みやすくなっているかは疑問です.
static int gcd(int n,int m){
// 剰余を求めて rに入れる
int r=n%m;
// 元のプログラムでは r==0 が再帰を終了するための条件だった
// 繰り返しの場合は,その否定である r!=0 が繰り返すための条件となる
for(r=n%m;r!=0;r=n%m){
// デバッグ(プログラムのミスを直す)のための出力
System.out.println("n="+n+",m="+m);
// 再帰における引数の置き換えをおこなう.下の2つの文の順序は大切
n=m;
m=r;
}
return m;
}
解答例(2)
class LCMTest {
// ユークリッドの互除法により最大公約数を計算するメソッド gcd の定義
// int型の引数 n, m をとり, int型の値を返す
static int gcd(int n,int m){
// デバッグ(プログラムのミスを直す)のための出力
// System.out.println("gcd("+n+","+m+")が呼ばれました");
// 剰余を求めて rに入れる
int r=n%m;
// nがmの倍数になっているなら最大公約数は m自身になる.
if(r==0) return m;
// n,mの最大公約数は m,rの最大公約数と等しい
else return gcd(m,r);
}
static int lcm(int n, int m){
return n/gcd(n,m)*m;
}
public static void main(String[] args){
// コマンドラインから
// java GCDTest arg0 arg1
// のようにして起動した時, args[0] -> arg0, args[1] -> arg1 となる.
// 文字列から int 型の整数値に変換するのは Integer.parseInt を使う
int i0=Integer.parseInt(args[0]);
int i1=Integer.parseInt(args[1]);
System.out.println(i0+"と"+i1+"の最大公約数は"+gcd(i0,i1)+"です");
System.out.println(i0+"と"+i1+"の最小公倍数は"+lcm(i0,i1)+"です");
}
}
ヒントにある通り,nとmの乗算結果から最大公約数を割るだけで,最小公倍数
が計算できます.
n/gcd(n,m)*m;は,演算子の優先順位により,
(n/gcd(n,m))*m;という意味になります.
dell.tanaka.ecc.u-tokyo.ac.jp% java LCMTest 60000 60008 60000と60008の最大公約数は8です 60000と60008の最小公倍数は450060000ですのように,nとmの積が32ビットの符号付整数で表せないが,最小公倍数は表せ るという場合,
(n*m)/gcd(n,m);とすると,
dell.tanaka.ecc.u-tokyo.ac.jp% java LCMTest 60000 60008 60000と60008の最大公約数は8です 60000と60008の最小公倍数は-86810912ですのように誤った答えになってしまいますが,
(n/gcd(n,m))*m;だと正しい答えが出ます.ただし,一般の除算は余りが出ることがあるので, a/b*cと a*c/bは一致するとは限らないことに注意してください.