• ベストアンサー

既約分数の表示プログラム

(1)キーボードから,分子,分母に相当する整数2つを入力し,その既約分数を表示せよ。 (2)分母が1の時には,分子のみを表示する。 (3)分子と分母の符号が異なるときにのみ,-符号を表示する。 (4)分母がゼロの入力エラーに対しては、再入力するように促す。 (5)分子と分母の最大公約数も求めて表示する。 (6)また、正しく計算できる最大規約分数を示せ。 #include <stdio.h> int main(void) { int a,b,i=1,x,y,z; printf("分子=");/*分子の入力*/ scanf("%d",&a); printf("分母=");/*分母の入力*/ scanf("%d",&b); if(b==0) { printf("分母が0です。入力が誤っています。\n"); return 0; } if(b==1) { printf("既約分数は %d\n",a); return 0; } while((i<=a)&&(i<=b)) { if((a%i==0)&&(b%i==0)) { x=i;i=i+1; /*xを上書きしていく*/ } else { i=i+1; } } printf("分子と分母の最大公約数=%d より\n",x); y=a/x; z=b/x; printf("既約分数は %d/%d\n",y,z); return 0; } 大学の課題で出されたものです。(1)(2)(4)(5)はできたのですが、(3)と(6)の部分のやり方がいまいちよくわからなかったので質問しました。 どなたかご教授お願いできないでしょうか・・・。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.5

/* 暗に結構コード書いて下さい、って丸投げする質問者ってのも多いんだけど, 質問者さんはそうじゃないみたいで安心した。 きっとこんなコードも読めるんじゃないかな? */ #include <stdio.h> #include <math.h> /* abs(x)はxの絶対値を返す関数で,math.hに定義されているんだよ。 もしこれがなくても自分で作れると思う。 */ int main(void){ int denominator; /* 分母の絶対値 */ int numerator; /* 分子の絶対値 */ int sign; int gcdofthetwo; printf("denominator = "); scanf("%d",&denominator); printf("numerator = "); scanf("%d",&numerator); if(denominator==0){ printf("error : denominator should not be 0. program will exit.\n"); return 0; } if (numerator==0){ printf("0"); return 0; } gcdofthetwo = gcd(abs(numerator),abs(denominator)); /* numerator * denominatorがオーバーフローするかも、っていうのが怖いから (numerator * denominator) / (abs(numerator) * abs(denominator)) って書かずにそれぞれ分割しているんだ */ sign = (numerator / abs(numerator)) * (denominator / abs(denominator)); /* 前回のコードで忘れてた最大公約数*/ printf ("gcd:%d\n", gcdofthetwo); if (abs(denominator) / gcdofthetwo != 1){ printf("answer:%d / %d\n" ,sign * abs(numerator) / gcdofthetwo , abs(denominator) / gcdofthetwo ); }else{ printf("answer:%d\n" ,sign * abs(numerator) / gcdofthetwo ); } } int gcd(int a,int b){ /* ユークリッド互除法 */ int retval; if( (a <= 0) || (b <= 0) ){ return -1; } retval = a % b; while (retval != 0){ a = b; b = retval; retval = a % b; } return b; }

zinrong
質問者

お礼

2つもプログラムを書いて頂いて恐縮です。 上記のプログラムを見て、書き方が違うだけでとてもシンプルにまとめられるのだなぁと感じ、とても勉強になりました。 課題のほうも無事終えることができました。分かりやすい説明やプログラムまで書いてもらって、今回は本当にお世話になりました。有難うございます。

その他の回答 (5)

回答No.6

#5を修正 最初戻り値にするつもりでretvalって変数用意したんだけど return b;って書いているから変数名がおかしい。 ので,変数名はremainderあたりのほうがいいと思う

回答No.4

>#1お礼 if (sign = 1) と if (sign == 1) の違い解る?

zinrong
質問者

お礼

if (sign = 1) と if (sign == 1) の違い解る? >>そういえば忘れていました・・・。 if文の条件を表す部分で「=(等しい)」を表すには「==」と書く、という決まりあったような。以後は気をつけます。

回答No.3

コード修正 if ( rawnumerator / rawdenominator < 0){ を if ( (double)rawnumerator / (double)rawdenominator < 0){ に

回答No.2

全体の流れはこんな感じでしょうか。 ・aとbを入力 ・bが0ならエラー表示 ・aとbの符号が異なるか調べて符号用変数をセット  → (aが負)かつ(bがゼロか正)、または、(aが正かゼロ)かつ(bが負)なら符号が異なる(0は正の扱いとしておく)  →符号が異なるときは符号用変数を-1、符号が同じなら0をセット ・以降の計算は、aもbも正数にして行なう。 ・約分の計算(分子と分母を最大公約数で割る) ・符号用変数が-1なら分子をマイナスにする。 ・分母が1なら分子だけ表示、そうでなければ分子と分母を表示

回答No.1

/* 質問文をベースを活かすと効率は悪いがこうなる。 変数名変えまくっている。 表示内容を英語にしているのは,書いているのがUTF-8のコードで gccでコンパイルして コマンドプロンプト(Shift_JIS)で日本語表示すると化けるから 質問文と違い, 分母 = 2,分子 = 4を入力した場合 4/2ではなく 2と表示する。 質問文と違い, 分母 = 0,分子 = 4を入力した場合 0/4ではなく 0と表示する。 効率的にやるなら 公約数を求める部分を別な関数に分けるし, math.hを利用してabs関数を用いたりする。 三項演算子も使うかもしれない */ #include <stdio.h> int main(void){ int rawdenominator; /* 分母 */ int rawnumerator; /* 分子 */ int absdenominator; /* 分母の絶対値 */ int absnumerator; /* 分子の絶対値 */ int i; /* カウンタ */ int gcd; /* 分母の絶対値と分子の絶対値の公約数 */ int sign; printf("denominator = "); scanf("%d",&rawdenominator); printf("numerator = "); scanf("%d",&rawnumerator); if(rawdenominator==0){ printf("error : denominator should not be 0. program will exit.\n"); return 0; } if (rawnumerator==0){ printf("0"); return 0; } if (rawnumerator < 0){ absnumerator = -rawnumerator; }else{ absnumerator = rawnumerator; } if (rawdenominator < 0){ absdenominator = -rawdenominator; }else{ absdenominator = rawdenominator; } if (rawnumerator / rawdenominator < 0){ sign = -1; }else{ sign = 1; } i = 1; gcd = 1; while((i<=absnumerator)&&(i<= absdenominator)){ if((absnumerator % i==0) && (absdenominator % i==0)){ gcd=i;i=i+1; }else{ i=i+1; } } if (gcd == absdenominator){ if (sign >= 0){ printf("%d",absnumerator / absdenominator); }else{ printf("- %d",absnumerator / absdenominator); } return 0; }else{ if (sign >= 0){ printf("%d / %d",absnumerator / gcd ,absdenominator / gcd); }else{ printf("- %d / %d",absnumerator / gcd ,absdenominator / gcd); } return 0; } }

zinrong
質問者

お礼

わざわざ長いプログラムまで書いてもらってお手数をおかけしました。とても勉強になりました。 1つ質問があるのですが ・ ・ if (gcd == absdenominator){ if (sign >= 0){ printf("%d",absnumerator / absdenominator); }else{ printf("- %d",absnumerator / absdenominator); } return 0; ・ ・ 場合わけの部分でif (sign >= 0)となっていますがif (sign =1)とするとうまく表示されなくなりました。ソース上ではsignは1か-1のどちらかなので>=0を=1にしてもいいのではと考えたのですが・・・。何か理由があるのでしょうか?

関連するQ&A

  • 2つ分数の四則演算を行うプログラム

    <要求事項> 分数は、 例)1|3 のように表す。 1.分母がゼロの時はエラーとする。 2.除算において、除数がゼロの入力エラーに対しては、再入力するように促す。 3.以下範囲の整数(分子、分母にかかわらず)に対して、正しく計算できるようにする。   -2147483648 ~ 2147483647 4.計算結果については,分母が1の時には分子のみ表示。分数がの時には0のみを表示。最終計算結果は既約分数にする。分数が負数の場合、-を分数の前に表示。 #include <stdio.h> #include <math.h> int main(void) { int b,d; /* 分母*/ int a,c; /* 分子*/ int sign,sign2,sign3,sign4; int yakusu,yakusu2,yakusu3,yakusu4; /* 最大公約数*/ printf("分母= "); scanf("%d",&b); printf("分子= "); scanf("%d",&a); if(b==0){ printf("分母が0です。入力が誤っています。\n"); /*分母が0ならエラーとする*/ return 0; } if (a==0){ printf("分数1= 0\n"); /*分子が0のとき*/ } else{ printf("分数1=%d|%d\n",a,b); /*一つ目の分数*/ } printf("\n"); printf("分母= "); scanf("%d",&d); printf("分子= "); scanf("%d",&c); if(d==0){ printf("分母が0です。入力が誤っています。\n"); /*分母が0ならエラーとする*/ return 0; } if (c==0){ printf("分数2= 0\n"); /*分子が0のとき*/ } else{ printf("分数2=%d|%d\n",c,d); /*二つ目の分数*/ } printf("\n"); /* 足し算:a|b + c|d = (a*d + b*c) | (b*d) */ printf("足し算:%d|%d + %d|%d\n",a,b,c,d); yakusu = gcd(abs(a*d + b*c),abs(b*d)); /*最大公約数を求める*/ sign = (a*d + b*c)/abs(a*d + b*c) * (b*d/abs(b*d)); if(sign * abs(a*d + b*c)/yakusu == 0){ /*分子が0となる時*/ printf("0\n"); } if (abs(b*d)/ yakusu!= 1){ printf("既約分数は %d|%d\n" ,sign * abs(a*d + b*c)/yakusu , abs(b*d)/yakusu ); } else{ printf("既約分数は %d\n" ,sign * abs(a*d + b*c)/yakusu ); /*分母が1の場合*/ } printf("\n"); /* 引き算:a|b - c|d = (a*d - b*c) | (b*d) */ printf("引き算:%d|%d - %d|%d\n",a,b,c,d); yakusu2 = gcd(abs(a*d - b*c),abs(b*d)); /*最大公約数を求める*/ sign2 = (a*d - b*c)/abs(a*d - b*c) * (b*d/abs(b*d)); if(sign2 * abs(a*d - b*c)/yakusu2 == 0){ /*分子が0となる時*/ printf("0\n"); } if (abs(b*d)/ yakusu2!= 1){ printf("既約分数は %d|%d\n" ,sign2 * abs(a*d - b*c)/yakusu2 , abs(b*d)/yakusu2 ); } else{ printf("既約分数は %d\n" ,sign2 * abs(a*d - b*c)/yakusu2 ); } printf("\n"); /* 掛け算:a|b * c|d = (a*c) | (b*d) */ printf("掛け算:%d|%d * %d|%d\n",a,b,c,d); yakusu3 = gcd(abs(a*c),abs(b*d)); /*最大公約数を求める*/ sign3 = (a*c)/abs(a*c) * (b*d/abs(b*d)); if(sign3 * abs(a*c)/yakusu3 == 0){ /*分子が0となる時*/ printf("0\n"); } if (abs(b*d)/ yakusu3!= 1){ printf("既約分数は %d|%d\n" ,sign3 * abs(a*c)/yakusu3 , abs(b*d)/yakusu3 ); } else{ printf("既約分数は %d\n" ,sign3 * abs(a*c)/yakusu3 ); /*分母が1の場合*/ } printf("\n"); /* 割り算:a|b / c|d = (a*d) | (b*c) */ printf("割り算:%d|%d / %d|%d\n",a,b,c,d); yakusu4 = gcd(abs(a*d),abs(b*c)); /*最大公約数を求める*/ sign4 = (a*d)/abs(a*d) * (b*c/abs(b*c)); if(sign4 * abs(a*d)/yakusu4 == 0){ /*分子が0となる時*/ printf("0\n"); } if (abs(b*c)/ yakusu4!= 1){ printf("既約分数は %d|%d\n" ,sign4 * abs(a*d)/yakusu4 , abs(b*c)/yakusu4 ); } else{ printf("既約分数は %d\n" ,sign4 * abs(a*d)/yakusu4 );/*分母が1の場合*/ } return 0; } int gcd(int x,int y){ /* ユークリッド互除法*/ int z; if( (x <= 0) || (y <= 0) ){ return -1; } z = x % y; while (z != 0){ x = y; y = z; z = x % y; } return y; } >>大学の課題です。現在の状態は上記の通りです。このプログラムだと、答えの既約分数が0になると表示できなかったり、桁が大きい数で計算しようとすると値がおかしくなってしまいます。 どなたかプログラム改良にご助力願えないでしょうか?

  • 既約分数

    分母と分子の和が50である既約分数がある。これを小数第2位を四捨五入すると0.4となる この分数をy/xとするとき x=? Y=? x+y=50 0.35≦y/x<0.45 1.35≦(x+y)/x <1.45 1.35≦50/x<1.45までしかわかりません

  • 分数の足し算をさせるプログラムが分かりません。どなたか分かりませんか?

    分数の足し算をさせるプログラムが分かりません。 C言語の問題で分数の足し算までは一応できるんですが、答えがでたときに整数で出すやり方と約分して表す方法が分かりません。 どなたか知恵を貸してくれませんか? ユーザから4つの整数を入力し、はじめに入力された2個の整数と後に入力された2個の整数を分数と考え、その分数の和を表示するプログラムを作成せよ。 例えば、「3」「4」「5」「6」と入力されたときは、3/4 + 5/6を計算する。 そのプログラム内では分数の和を計算する関数を作成する。 さらに、 約分を行う関数を 再帰呼び出しを利用して作成する。 void yakubun(int *a1, int *a2) 例えば、以下の場合1/2と表示される。 int i=10,j=20; yakubun(&i,&j); printf(“%d / %d”, i, j); ちなみにここまでできました↓ #include<stdio.h> void bunsu_tasizan(int a1,int a2,int b1,int b2, int *c1,int *c2 ) { *c1=(a1*b2)+(b1*a2); *c2=(a2*b2); } int main() { int x1,x2,y1,y2,z1,z2; printf("整数を入力してください"); scanf("%d",&x1); scanf("%d",&x2); scanf("%d",&y1); scanf("%d",&y2); if(x2==0||y2==0||x2==0&&y2==0) printf("0以外を入力してください"); else{ bunsu_tasizan(x1,x2,y1,y2,&z1,&z2); printf("%d/%d",z1,z2);} return (0); }

  • このプログラム見てほしいです!!

    #include <stdio.h> int gcd2(int a, int b) { if (!b) return a; return gcd2(b, a%b); } int main() { int a, b, c; printf("2つの任意の整数を入力せよ:"); scanf("%d %d",&a,&b); c=gcd2(a,b); printf("最小公倍数は%d\n",a*b/c); printf("最大公約数は%d\n",c); return 0; } で、最小公約数を出すことはできたのですが、全ての公約数を表示させたいんです!!どうやったらいいのでしょうか??プログラミングまだ初心者なので、ちょっと行き詰ってしまいました。。。 お時間があればでいいのですが、もう一つわからないプログラムがあります。 自然数nを入力し、x^2+y^2=z^2 (x<y)を満たすようなn以下の自然数の組(x,y,z)がいくつあるのかを出力するプログラムなのですが、全くわからず行き詰っています。。どなたかお時間があれば教えて頂きたいです。 色々と申し訳ありません。お願いします(__)

  • 分数を表示するプログラム(長文です)

    (整数値)aの値と(整数値)bの値をキーボードから入力して、そこから、a/bという分数を作るプログラムを書きたいと思います。(符号や約分も考えた形にする) 僕は、ヒントを参考に以下のようなプログラムを書いたのですが、ある条件の下では、正しく動きません。 ・aの値が負の場合 ・aもbも負の値の場合 など・・・ #include <stdio.h> #include <math.h> int main ( void ) { int a,b; int k,min,sign; printf("a=?");scanf("%d",&a); printf("b=?");scanf("%d",&b); if (a*b<0) sign = -1; else sign = 1; a = sign*a ; b = sign*b; if (abs(a)>abs(b)) min = b; else min = abs(a); for ( k=2 ; k<=min ; k++){ if (min%k == 0){ a = a/k; b = b/k; } } printf("a/b = %d",a); if (b != 1) printf("/%d\n",b); else printf("\n"); return 0; } これをどのように修正すれば、正確な答えが出るのでしょうか? 教えてください。

  • このプログラムの間違いを指摘していただけませんか?

    まだ、初めて一ヶ月も経たない者です。それでも、勉強しつつ、組んでみたのですが、うまくいきません。数字の足し算をして、結果を表示させたいのですが、四回足しても四回目の数字が、足されずに結果がでてしまいます。1と2と3と4と入力すると、6と出てきます。一体どのようにしたらよいのでしょうか?教えて頂けませんか?(下に書いてあります。) #include <stdio.h> int sub(int x, int y, int z){ return x + y + z; } int main() { int i; int a[i]; for (i=1; i<=1; ++i){ printf("数字は?\n"); scanf ("%d\n", &a[i]); scanf ("%d\n", &a[i+1]); scanf ("%d\n", &a[i+2]); scanf ("%d\n", &a[i+3]); int result,x,y,z; result = sub(a[i],a[i+1],a[i+2]); printf("結果は%d\n",result); } return 0; }

  • 整数を3つ読み込み、一番大きいものを表示するプログラム

    3つが違う数であるとしてこうしたんですが、 #include<stdio.h> int main() {int a,b,c; scanf("%d",&a); scanf("%d",&b); scanf("%d",&c); if(a>b && a>c){ printf("%d\n",a);} if(b>a && b>c){ printf("%d\n",b); if(c>a && c>b){ printf("%d\n",c); }}return 0;} で、コンパイルはできたんですが、実行できません。3つの数値を入力してもその一番大きい数が出てきません。ifの条件は間違ってはいないと思うんですがやはり、最大が2つあるときのことを考えないとできませんか?

  • 分数式とその計算、がわかりません。

    --------は分母と分子を区切る線のことです。 25 * x^2 * y^2 ----------------- 30 * x * y^4 ↓ 5 * x * y ------------ 6 * y^2 ↓ 5xy ------ 6y^2 これで答えが間違っているみたいなのですが、この問題を含めて分数式を約分して既約分数式に直すやり方がわかりません。 まだ学校で教えてもらってなくて問題集を見てやってるんですが、授業までにちゃんとやり方をマスターしておきたいです。 解き方を教えて頂けませんでしょうか

  • c言語 逆行列 掃き出し法 既約分数

    c言語初心者の者です。課題がででソースコードを書き、コマンドプロンプトで入力したら、「a.exeは動作が停止しました」と出ました。恐らくスタックを消費仕切っているのだと思いますが、改善する内容がわかりません。出来れば理由込みで詳しく改善点を教えてほしいです。できるだけ簡単なプログラムで作成をお願いします。 課題内容:4行4列の逆行列を計算するプログラムを作成せよ。但し、分数は既約分数とし、分母に「-」はつけない。掃き出し法を用いて解け。更に、ポインタや構造体や特別な関数を使用してはならない。 ソースコード: #include<stdio.h> int gcdf(int x, int y){ return(y == 0 ? x :gcdf(y,x%y)); /*最大公約数を求める*/ } int gcd(int a, int b){ return(a > b ? gcdf(a, b) : gcdf(a,a)); /*恐らくここも間違いの1つ、gcd(a,a)をどう                   なおせばいいか*/ } int main(void){ int buf[2]; /*データ保存*/ int i, j, k,g; /*カウンタ*/ int n = 4; /*配列の次数*/ int a[4][4][2] = {{{1,1},{2,1},{0,1},{1,2}}, /*問題の行列*/ {{0,1},{2,3},{1,1},{0,1}}, {{1,1},{0,1},{0,1},{-1,1}}, {{1,1},{0,1},{-1,2},{-1,1}}}; int inv_a[4][4][2] = {{{1,1},{0,1},{0,1},{0,1}}, /*単位行列*/ {{0,1},{1,1},{0,1},{0,1}}, {{0,1},{0,1},{1,1},{0,1}}, {{0,1},{0,1},{0,1},{1,1}}}; for(i = 0; i < n; i++){ buf[0] = a[i][i][1]; //分子 buf[1] = a[i][i][0]; //分母 for(j = 0; j < n; j++){ a[i][j][0] = buf[0] * a[i][j][0]; a[i][j][1] = buf[1] * a[i][j][1]; g = gcd(a[i][j][0], a[i][j][1]); a[i][j][0] = a[i][j][0] / g; a[i][j][1] = a[i][j][1] / g; //約分 inv_a[i][j][0] *= buf[0]; inv_a[i][j][1] *= buf[1]; g = gcd(inv_a[i][j][0], inv_a[i][j][1]); inv_a[i][j][0] = inv_a[i][j][0] / g; inv_a[i][j][1] = inv_a[i][j][1] / g; //約分 } for(j = 0; j < n; j++){ if(i != j) buf[0] = a[j][i][0]; buf[1] = a[j][i][1]; for(k = 0; k < n; k++){ a[j][k][0] = a[j][k][0] * a[i][k][1] * buf[1] - a[j][k][1] * a[i][k][0] * buf[0]; a[j][k][1] = a[j][k][1] * a[i][k][1] * buf[1]; g = gcd(a[j][k][0], a[j][k][1]); a[j][k][0] = a[j][k][0] / g; a[j][k][1] = a[j][k][1] / g; inv_a[j][k][0] = inv_a[j][k][0] * inv_a[i][k][1] * buf[1] - inv_a[j][k][1]* inv_a[i][k][0] * buf[0]; inv_a[j][k][1] = inv_a[j][k][1] * inv_a[i][k][1] * buf[1]; g = gcd(inv_a[j][k][0], inv_a[j][k][1]); inv_a[j][k][0] = inv_a[j][k][0] / g; inv_a[j][k][1] = inv_a[j][k][1] / g; }}} printf("1 2 0 1/2 \n 0 2/3 1 0 \n 1 0 0 -1 \n 1 0 -1/2 -1 \n の逆行列は以下の通り"); for(i = 0; i < n; i++){ /*逆行列出力*/ for(j = 0; j < n; j++){ if(inv_a[i][j][1] = 0){ inv_a[i][j][0] *= (-1); inv_a[i][j][1] *= (-1); /*分母のマイナスをプラスに*/ } /*分母が1の時に整数表示*/ if(inv_a[i][j][1] != 1) printf("%d/%d", inv_a[i][j][0],inv_a[i][j][1]); else printf("%d", inv_a[i][j][0]); } } return 0; }

  • 分数コードの見分け方

     分数コードで、D/AとかEmaj9/Bとかありますが 分母も分子もコードの場合と、分子がコードで 分母がベース音の場合があるようですね。 それを、どうやって見分けるのでしょうか?

専門家に質問してみよう