最小公倍数を求めるプログラムが実行中に止まる

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Yellow

最小公倍数を求めるプログラムが実行中に止まる

#1

投稿記事 by Yellow » 12年前

(最小公倍数)=(2数の積)/(最大公約数)
を利用して、x、y~y+9の最小公倍数を求めるプログラムを作ろうと試みました。

実行はできるのですが、xとyの値を入力したところでプログラムが固まってしまいます。
結果、最小公倍数を表示することができません。

コード:

#include <stdio.h>

int GCD(int x, int y);//最大公約数を求める
int KEISAN(int x, int y);//最小公倍数に変換する

int main(){
	int x,y,LCM_num;
	puts("xの値を入力");
	scanf("%d",&x);
	puts("yの値を入力");
	scanf("%d",&y);

	LCM_num = KEISAN(x,y);
	printf("%dと、%dから%dまでの最小公倍数は%dです",x,y,y+9,LCM_num);

	return 0;
}

int GCD(int x, int y){
	int r;
	while((r = x%y) =! 0){//ユークリッドの互除法
		x = y;
		y = r;
	}
	return y;
}

int KEISAN(int x, int y){
	int i;
	for(i=y;i<y+10;y++){
		y = i;
		x = x*y / GCD(x,y);
	}
	return x;
}
スタックオーバーフローや、警告のメッセージにあったscanfを疑いましたが、原因はわかりませんでした。
もしよろしければ、ご教授お願いします。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 最小公倍数を求めるプログラムが実行中に止まる

#2

投稿記事 by みけCAT » 12年前

KEISAN関数の動作を落ち着いて追ってみましょう。

コード:

int KEISAN(int x, int y){
    int i;
    for(i=y;i<y+10;y++){
        y = i;
        x = x*y / GCD(x,y);
    }
    return x;
}
例えば、x=1,y=2とします。
3行目 i=y;により x=1,y=2,i=1 i<y+10は真
4行目 y=i;により x=1;y=1,i=1
5行目 x=x*y/GCD(x,y); により x=1,y=1,i=1
3行目 y++;により x=1,y=2,i=1 i<y+10は真
4行目 y=i;により x=1,y=1,i=1
5行目 x=x*y/GCD(x,y); により x=1,y=1,i=1
3行目 y++;により x=1,y=2,i=1 i<y+10は真
4行目 y=i;により x=1,y=1,i=1
5行目 x=x*y/GCD(x,y); により x=1,y=1,i=1

きれいにx,y,iが何回回っても同じ値になり、無限ループになっています。
xはy,iには影響を与えないので、無視してもいいです。
for文の初期化にi=yがあるので、y+10<=INT_MAXを満たすyを与えた場合、無限ループになります。
オフトピック

コード:

x = x/GCD(x,y)*y;
とした方がオーバーフローしにくくなります。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

non
記事: 1097
登録日時: 14年前

Re: 最小公倍数を求めるプログラムが実行中に止まる

#3

投稿記事 by non » 12年前

21行 while((r = x%y) =! 0){//ユークリッドの互除法
間違ってる。
non

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 最小公倍数を求めるプログラムが実行中に止まる

#4

投稿記事 by みけCAT » 12年前

non さんが書きました:21行 while((r = x%y) =! 0){//ユークリッドの互除法
間違ってる。
確かに…これはコンパイルエラー不可避ですね。

このコードではない、古いプログラムを実行している可能性があるかもしれません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

non
記事: 1097
登録日時: 14年前

Re: 最小公倍数を求めるプログラムが実行中に止まる

#5

投稿記事 by non » 12年前

みけCAT さんが書きました:
non さんが書きました:21行 while((r = x%y) =! 0){//ユークリッドの互除法
間違ってる。
確かに…これはコンパイルエラー不可避ですね。

このコードではない、古いプログラムを実行している可能性があるかもしれません。
コンパイルエラーはでないかも。
0を否定して、rに代入。
0がFALSEならTRUEを代入し、それを評価で永久ループ。

追記
解釈はコンパイラーによるみたいですね。失礼しました。
non

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 最小公倍数を求めるプログラムが実行中に止まる

#6

投稿記事 by みけCAT » 12年前

non さんが書きました:
みけCAT さんが書きました:
non さんが書きました:21行 while((r = x%y) =! 0){//ユークリッドの互除法
間違ってる。
確かに…これはコンパイルエラー不可避ですね。

このコードではない、古いプログラムを実行している可能性があるかもしれません。
コンパイルエラーはでないかも。
0を否定して、rに代入。
0がFALSEならTRUEを代入し、それを評価で永久ループ。

追記
解釈はコンパイラーによるみたいですね。失礼しました。
C言語ではエラーが出ましたが、C++だとエラーにならないようです。
http://ideone.com/tFOGrE
http://ideone.com/8YjEQV

【追記】
動作も完全に「rに右の等号の右の値を代入する」になっているようですね。
http://ideone.com/LKD1AE
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Yellow

Re: 最小公倍数を求めるプログラムが実行中に止まる

#7

投稿記事 by Yellow » 12年前

レスポンスが遅くなってすみません、質問者です。
回答を参考に色々変えてみたところ、正しい結果を返すプログラムが組めました。
まずそれを貼ります。

コード:

#include <stdio.h>

int GCD(int x, int y);//最大公約数を求める
int KEISAN(int x, int y);

int main(){
	int x,y,LCM_num;
	puts("xの値を入力");
	scanf("%d",&x);
	puts("yの値を入力");
	scanf("%d",&y);

	LCM_num = KEISAN(x,y);
	printf("%dと、%dから%dまでの最小公倍数は%dです\n",x,y,y+9,LCM_num);

	return 0;
}

int GCD(int x, int y){
	int r;
	while((r = x%y != 0){//ユークリッドの互除法
		x = y;
		y = r;
	}
	return y;
}

int KEISAN(int x, int y){
	int i;
	y = y-1;
	for(i=0;i<10;i++){
		y = y++;
		x = x / GCD(x,y)*y;
	}
	return x;
}
x = x/GCD(x,y)*y;

とした方がオーバーフローしにくくなります。
>まず、この通りに変形しました。


KEISAN関数の中身を変えました。

コード:

int KEISAN(int x, int y){
    int i;
    for(i=y;i<y+10;y++){
        y = i;
        x = x*y / GCD(x,y);
    }
    return x;
}
を、

コード:

int KEISAN(int x, int y){
	int i;
	y = y-1;
	for(i=0;i<10;i++){
		y = y++;
		x = x / GCD(x,y)*y;
	}
	return x;
}
にすると正しい値を返すようになりました。
また、

コード:

int KEISAN(int x, int y){
	int i;
	for(i=1;i<11;i++){
		y = y+i;
		x = x / GCD(x,y)*y;
	}
	return x;
}
上のプログラムでも正しい値が返されなかったのですが、これがなぜかわかりません。それから、
3行目 i=y;により x=1,y=2,i=1 i<y+10は真
と書いてくださってましたが、=は右辺に左辺を代入するという意味ならば、i=y;はi=2ということにならないのでしょうか…。
このへんの理解が甘くわかりません。
C言語ではエラーが出ましたが、C++だとエラーにならないようです。
http://ideone.com/tFOGrE
http://ideone.com/8YjEQV

【追記】
動作も完全に「rに右の等号の右の値を代入する」になっているようですね。
http://ideone.com/LKD1AE
>GCD関数とmain関数だけでテストプログラムを実行してみました。GCD関数はC言語の時でもエラーを吐かずに動いていました。http://ideone.com/tFOGrEでエラーになっている理由がわか ... ということでしょうか

non
記事: 1097
登録日時: 14年前

Re: 最小公倍数を求めるプログラムが実行中に止まる

#8

投稿記事 by non » 12年前

Yellow さんが書きました: また、

コード:

int KEISAN(int x, int y){
	int i;
	for(i=1;i<11;i++){
		y = y+i;
		x = x / GCD(x,y)*y;
	}
	return x;
}
上のプログラムでも正しい値が返されなかったのですが、これがなぜかわかりません。
yの初期値が2なら
最初は、3からスタートし、5,8,12と増えますよ。
Yellow さんが書きました: それから、
3行目 i=y;により x=1,y=2,i=1 i<y+10は真
と書いてくださってましたが、=は右辺に左辺を代入するという意味ならば、i=y;はi=2ということにならないのでしょうか…。
このへんの理解が甘くわかりません。
みけCATさんの書き間違えでしょう。
Yellow さんが書きました: もっと安全な書き方があるということでしょうか?
while((r = x%y) =! 0)
が =! のままではエラーになるかならないかという話をしています。
もちろん、訂正されているように != でないといけません。
ただし、添付されたプログラムは括弧が対応していません。
non

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 最小公倍数を求めるプログラムが実行中に止まる

#9

投稿記事 by みけCAT » 12年前

non さんが書きました:
Yellow さんが書きました: それから、
3行目 i=y;により x=1,y=2,i=1 i<y+10は真
と書いてくださってましたが、=は右辺に左辺を代入するという意味ならば、i=y;はi=2ということにならないのでしょうか…。
このへんの理解が甘くわかりません。
みけCATさんの書き間違えでしょう。
すいません、間違えたようですね。
訂正します。

例えば、x=1,y=2とします。
2行目 x=1,y=2,i=?
3行目 i=y;により x=1,y=2,i=2 i<y+10は真
4行目 y=i;により x=1;y=2,i=2
5行目 x=x*y/GCD(x,y); により x=2,y=2,i=2
3行目 y++;により x=2,y=3,i=2 i<y+10は真
4行目 y=i;により x=2,y=2,i=2
5行目 x=x*y/GCD(x,y); により x=2,y=2,i=2
3行目 y++;により x=2,y=3,i=2 i<y+10は真
4行目 y=i;により x=2,y=2,i=2
5行目 x=x*y/GCD(x,y); により x=2,y=2,i=2

Yellow さんが書きました:>GCD関数とmain関数だけでテストプログラムを実行してみました。GCD関数はC言語の時でもエラーを吐かずに動いていました。http://ideone.com/tFOGrEでエラーになっている理由がわか ... ということでしょうか
証拠(スクリーンショットか動作しているURL)の提示をお願いできますか?
Yellow さんが書きました:KEISAN関数の中身を変えました。

コード:

int KEISAN(int x, int y){
    int i;
    for(i=y;i<y+10;y++){
        y = i;
        x = x*y / GCD(x,y);
    }
    return x;
}
を、

コード:

int KEISAN(int x, int y){
	int i;
	y = y-1;
	for(i=0;i<10;i++){
		y = y++;
		x = x / GCD(x,y)*y;
	}
	return x;
}
にすると正しい値を返すようになりました。
y = y++;という式は環境(コンパイラ)依存の気がします。
素直にy++;またはy = y+1;の方がいいのではないですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Yellow

Re: 最小公倍数を求めるプログラムが実行中に止まる

#10

投稿記事 by Yellow » 12年前

non さんが書きました: while((r = x%y) =! 0)
が =! のままではエラーになるかならないかという話をしています。
もちろん、訂正されているように != でないといけません。
ただし、添付されたプログラムは括弧が対応していません。
すみません、その肝心要を理解できておらず、要領の得ない返答をしておりました。
みけCAT さんが書きました:
Yellow さんが書きました:>GCD関数とmain関数だけでテストプログラムを実行してみました。GCD関数はC言語の時でもエラーを吐かずに動いていました。http://ideone.com/tFOGrEでエラーになっている理由がわか ... ということでしょうか
証拠(スクリーンショットか動作しているURL)の提示をお願いできますか?
=!では証拠を貼るまでもなく、コンパイルエラーとなりました。お騒がせしました。

また、KEISAN関数について
non さんが書きました: yの初期値が2なら
最初は、3からスタートし、5,8,12と増えますよ。
これも自分のミスでした。括弧の非対応も凡ミスです。
みけCAT さんが書きました:y = y++;という式は環境(コンパイラ)依存の気がします。
素直にy++;またはy = y+1;の方がいいのではないですか?
確かにあまり良くないと思います、差し替えておきます。

一通り把握できたので質問を解決とさせていただきます。
みけCATさん、nonさん、ありがとうございます。

閉鎖

“C言語何でも質問掲示板” へ戻る