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は一致するとは限らないことに注意してください.