アプリ版:「スタンプのみでお礼する」機能のリリースについて

(整数値)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;
elsesign = 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;
}
これをどのように修正すれば、正確な答えが出るのでしょうか?
教えてください。

A 回答 (10件)

 


#include <stdio.h>
#include <stdlib.h>

int GCD(int a, int b)
{
if(!b) return a;
return GCD(b, a % b);
}

int main(void)
{
int a, b, sign, gcd;
char *signc[] = {"", "-",};

scanf("%d %d", &a, &b);
if(!b) puts("Error");
else if(!a) puts("0");
else{
sign = (a < 0) ^ (b < 0);
a = abs(a);
b = abs(b);
gcd = GCD(a, b);
printf("%s%d/%d\n", signc[sign], a / gcd, b / gcd);
}
return 0;
}
 
    • good
    • 0

★回答者 No.5、6、8です。

→訂正
・約分の for ループ内に一箇所、記述ミスがありました。
 間違い⇒if ( !(a % k) && !(b & k) ){
 正しい⇒if ( !(a % k) && !(b % k) ){
 ※『&』文字を『%』文字に修正して下さい。
 以上です。
    • good
    • 0

★そうですね。


>b = 0の時は不能ですが,
>bが0でなくa = 0の時は、0が表示されるべきです。
 でも、それならば 0 で割ったときは『無限大』とか、『ゼロ除算エラー』とか表示するのもありですね。
・数学では 0 で割ると『商』は無限大になります。
 123 ÷ 0.1 = 1230
 123 ÷ 0.01 = 12300
 123 ÷ 0.001 = 123000
 123 ÷ 0.0001 = 1230000
 123 ÷ 0.000…001 = 1230000…000(無限大)
 ↑
 このことから限りなく 0 に近い数で割ると無限大となります。
 電卓ではエラー、ゼロ除算エラーまたはオーバーフローとして最大値など表示されます。
・以上。
    • good
    • 0

b = 0の時は不能ですが,


bが0でなくa = 0の時は、0が表示されるべきです。

0/5 = 0
    • good
    • 0

★追記。


・符号の判定はオーバーフローや int 型が 16、32ビットにも対応するように
 次のようにするのも良いでしょう。
 // マクロ関数
 #define GetSign(a) (((a) < 0) ? -1 : ((a) > 0) ? +1 : 0)
 
 // 3項演算子で符号を判定
 sign = (GetSign(a) * GetSign(b));
 ↑
 これが分数全体の符号です。
・この sign には -1、+1、0 が入ります。
 もし 0 ならば入力をやり直すようにも使えます。
 つまり、
 // a、b を入力
 do {
  printf( "a=?" ); scanf( "%d", &a );
  printf( "b=?" ); scanf( "%d", &b );
  
  // 3項演算子で符号を判定
  sign = (GetSign(a) * GetSign(b));
 } while ( sign == 0 );
 ↑
 これで a、b が 0 以外ならば do-while を抜けます。
・以上。
    • good
    • 1

★アドバイス


・まずは算数からアドバイスします。
 - - ⇒+
 - + ⇒-
 + - ⇒-
 + + ⇒+
 ですよね。
・だから入力された a、b の符号から分数全体の sign を処理します。
 その後に a、b の2つの値を強制的に絶対値にします。→abs()関数で。
・あとは 2 から順に a、b のどちらかの小さい数まで約分を行います。
 このときに a、b の両方が割り切れるかをチェックします。
 両方が割り切れたときに割り算を行います。
・約分まで終わったら分数の形で表示して処理終了です。
 それではサンプルを載せますので見比べて下さい。

サンプル:
#include <stdio.h>
#include <stdlib.h>

int main( void )
{
 int a, b, k, min, sign;
 
 // a、b を入力
 printf( "a=?" ); scanf( "%d", &a );
 printf( "b=?" ); scanf( "%d", &b );
 
 // 3項演算子で符号を判定
 sign = (((a * b) < 0) ? -1 : +1);
 
 // 強制的に絶対値に変換
 a = abs( a );
 b = abs( b );
 min = ((a < b) ? a : b);
 
 // 約分
 for ( k = 2 ; k <= min ; k++ ){
  if ( !(a % k) && !(b & k) ){ ←a、bのが両方割り切れるか判定
   a /= k;
   b /= k;
  }
 }
 // 表示
 if ( b == 1 ){
  printf( "a/b = %+d\n", (sign * a) );
 }
 else{
  printf( "a/b = %+d/%d\n", (sign * a), b );
 }
 return 0;
}

最後に:
・分数全体の符号は表示する部分で掛け算すれば楽です。
 あと a、b のどちらか一方が 0 だった場合の処理を追加してみて下さい。
 回答者 No.4 さんの『do { … } while ( !(a | b) );』のやり方で入力を繰り返すのが
 一番スマートかなと思います。
 以上。

参考URL:http://www9.plala.or.jp/sgwr-t/c/sec14.html
    • good
    • 0

#include <stdio.h>


#include <math.h>
#define REV 0x80000000

int main ( void )
{
int a,b;
int k,min,max,sign;
char sign_ch;

do{
printf("a=?");scanf("%d",&a);
printf("b=?");scanf("%d",&b);
}while(!(a&b));


sign=(a&REV)|(b&REV)?-1:1;
a*=((a&REV)&&!(b&REV))?1:sign,b*=(b&REV)?-1:1;
if (abs(a)>abs(b)) min=b,max=abs(a);
else min=abs(a),max=b;
for ( k=2 ; k<=min ; k++){
while (!(a%k||b%k)){
a/=k;
b/=k;
printf("%d/%d,%d\r\n",a,b,k);
}
}
sign_ch=a&REV?'-':' ';
printf("a/b = %c%d",sign_ch,abs(a));
if (abs(b) != 1)
printf("/%d\n",abs(b));
else printf("\n");
return 0;
}

こんな感じでしょうか…。
    • good
    • 0

あ、いけね。

手を抜きすぎた気がする
sign = a/abs(a) * b / abs(b);
/*
でないと、a * bがオーバーフローするかもしれない
*/
/*
ついでに言うと、bが表示されないのは、

b=1の時だけではなく a=0の時もそう。(a % b = 0)
(俺のコードだとa = 0またはb = 0の時,0除算エラーが出る)
b = 0の時は処理を飛ばさなきゃいけない
ってことも忘れないようにしないとね!
*/
    • good
    • 0

/*


バグっているかもしれないが元の奴よりもずっとマシなはず。
質問文のコード
min = abs(b);のつもりがmin = b;になってたよね(汗。
bが負でaがそれより大きいと、ループの終了条件にいきなりひっかかるんですけど。
*/

#include <stdio.h>
#include <math.h>

int commonfactor(int val1,int val2);

int main ( void )
{
int a,b;
int factor;
int sign;
printf("a=?");
scanf("%d",&a);

printf("b=?");
scanf("%d",&b);

factor = commonfactor(abs(a),abs(b));
sign = a * b / (abs(a) * abs(b));
b = abs(b)/factor;
a = sign * abs(a)/factor;
printf("a/b = %d",a);
if (b != 1)
{printf("/%d\n",b);}
else
{printf("\n");}
return 0;

}

int commonfactor(int val1,int val2)
{
/* バグっているかもしれないといったのは
ここで引数をabs関数にくぐらせず、呼び出し元でくぐらせた事 */
int i;
int maxfactor = 1;

int min;

if (val1 > val2)
{
min = val2;
}
else
{
min = val1;
}

/* でも多分実は最小値算出は不要。何故なら余りが0になることは無いから */

for (i = 2 ;i < min + 1;i++)
{
if ((val1 % i == 0) && (val2 % i == 0))
{
maxfactor = i;
}
}

return maxfactor;

}
    • good
    • 0

#include <stdio.h>


#include <math.h>
/* 答えは言わないけど、考えてみよう*/
/*俺 if文この書き方じゃないと落ち着かないんだ。・・・*/
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);}

printf("min:%d\n",min);
for ( k=2 ; k<=min ; k++){
if (min % k == 0){ /* a = 15, b = 6の時どうなるかやってみると? */
a = a/k;
b = b/k;
printf("k:%d\n",k); /*ここを見よう!*/
printf("a:%d\n",a); /*ここを見よう!*/
printf("b:%d\n",b); /*ここを見よう!*/
printf("\n");
}
}


printf("a/b = %d",a);
if (b != 1)
printf("/%d\n",b);
else printf("\n");
return 0;
}
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!