マンガでよめる痔のこと・薬のこと

<要求事項>
分数は、 例)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になると表示できなかったり、桁が大きい数で計算しようとすると値がおかしくなってしまいます。
どなたかプログラム改良にご助力願えないでしょうか?

このQ&Aに関連する最新のQ&A

A 回答 (6件)

No.2です


>オーバーフローというものは良く分からないのですが、アドバイスを踏まえて色々やってみます。

オーバーフローの概念だけ簡単に。
例えば、0~99までが入る変数型「sample」があったとします(ここでわかりやすく10進数でいきます)

sample a, b, c;
a = 99;
b = 99;
c = 0;
c = a * b;

という計算を行った場合、cの値はいくつになるでしょうか?
単純に「a * b」を計算すると「99 * 99 = 9801」となります。
しかし、sample型で扱うるの「0~99」です。
そのため100以上の値は「c」に格納することができず桁あふれ(オーバーフロー)が発生してしまいます。
このため、桁あふれ分はcに格納することができず「c = a * b」の結果「c」には桁あふれで残った(sample型に格納できる)分「1」が入ることになります。

注:あくまで概念の説明です。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。オーバーフローの概念を理解することができ、課題もなんとか終わらせることができました。分かりやすい説明ありがとうございました。

お礼日時:2008/07/29 16:06

>桁が大きい数で計算しようとすると値がおかしくなってしまいます。


 
 ・今回の質問では、標準入力からの分母と分子は int なので、内部では、-2147483648 ~ 2147483647 と「正しく」扱われる。

 ・この分母、分子を「計算(かけ算、たし算)しよう」とした時、「おかしく」なる。

   例)2147483647 + 1 = -2147483648  -1 * -2147483648 = -2147483648

 ・「おかしく」なる理屈は、分母、分子、丸ごとスタックにおくられ、演算が行われる際に、有限のスタック(今回は32ビット)に【納めきれなくなる】。
 
☆そんなら、丸ごとスタックにやらず、1桁ずつ「計算」をすればよいのでは・・。

 例えば、筆算で、
 
  123
 ×234
 
 の計算をするとき、まず3×4をやって12の2を・・と下位から1桁ずつ確定していきますよね。
 この過程をコード化すればよいのではと・・。
 
 で重要なのは、この結果は、「表示」にしか用いない(というか用いられない)。

 今回の質問内容では、これで十分ですよね↑・・。

 巷のπの計算だって、何万桁まで「内部で扱う数」としてでなく、「結果表示」でのみ有効なものですよね。
 でないと、正しいか検証もできないし・・。
------------------------------------------------
★「足し算」、「かけ算」について、筆算もどきのソースを投稿します(BorlandC++5.6.4)。

 「値がおかしくなって」しまう数で呼び出してみて下さい。

・「足し算」は、オーバーフローするか判定し、するものについて筆算もどきしてます。
  判定:「演算」で、正+正が負のとき、負+負が正のときをオーバーフローとしています。
・「かけ算」は、上述の方法です。

共に、20個の配列(20桁)で「筆算もどき」しています。
-------------------------------------------
#include <stdio.h>
#include <stdlib.h>

void Output( char cKekka[] )
{
 int i, iSumi = 0;

 for( i = 0; i <= 20; i++ ){

  if( ( 0 == iSumi ) && ( 0x00 == cKekka[ i ] ) ) continue;

  printf( "%c", ( 0x30 + cKekka[ i ] ) );

  iSumi = 1;
 }
 printf( "\n" );
}
void Tashizan( int iVal1, int iVal2 )
{
 int iOver = 0, kk = 20, iDum;
 char cKekka[32] = { 0x00 };

 if( iVal1 <= 0 ){ // オーバーフロー判定

  if( iVal2 < 0 ){ // 双方負

   iOver = iVal1 + iVal2;

   if( iOver >= 0 ) iOver = 1;
  }
 }
 if( iVal1 > 0 ){ // オーバーフロー判定

  if( iVal2 > 0 ){ // 双方正

   iOver = iVal1 + iVal2;

   if( iOver <= 0 ) iOver = 2;
  }
 }
 if( ! iOver ){ // オーバーフローしない:通常「演算」

  printf( "%d\n", ( iVal1 + iVal2 ) );
 }
 if( iOver ){ // オーバーフローするので筆算もどき

  while( iVal1 || iVal2 ){ // 1桁ずつの足し算

   iDum = cKekka[ kk ];
   iDum += abs( iVal1 % 10 ); // 下1桁
   iDum += abs( iVal2 % 10 );

   cKekka[ kk ] = (char)( iDum % 10 );
   cKekka[ kk - 1 ] = (char)( iDum / 10 ); // 繰り上がり

   kk--; // 上位の桁へ

   iVal1 /= 10;
   iVal2 /= 10;
  }
  if( 1 == iOver ) printf( "-" );

  Output( cKekka );
 }
}
void Kakezan( int iVal1, int iVal2 )
{
 int i, j, kk, iTotal = 0;
 char c1[ 32 ] = { 0x00 }, c2[ 32 ] = { 0x00 };
 char cKekka[ 32 ] = { 0x00 };

 if( iVal1 < 0 ) c1[ 31 ] = 0x01; // 負
 if( iVal2 < 0 ) c2[ 31 ] = 0x01;

 for( i = 20; i >= 0; i-- ){ // 1桁ずつ配列へ

  c1[ i ] = (char)abs( iVal1 % 10 );
  c2[ i ] = (char)abs( iVal2 % 10 );

  iVal1 /= 10;
  iVal2 /= 10;
 }
 for( i = 20; i >= 0; i-- ){ // 下位から筆算もどき

  for( j = 20; j >= 0; j-- ){ // 被乗数桁

   kk = j - ( 20 - i ); // 格納桁

   if( ( kk - 1 ) <= 0 ) break;

   cKekka[ kk ] += (char)( c1[ j ] * c2[ i ] );

   cKekka[ kk - 1 ] += (char)( cKekka[ kk ] / 10 ); // 繰り上がり

   cKekka[ kk ] = (char)( cKekka[ kk ] % 10 );

   iTotal += cKekka[ kk ];
  }
 }
 cKekka[ 31 ] = (char)( c1[ 31 ] + c2[ 31 ] ); // 符号:奇数なら負

 if( iTotal && ( cKekka[ 31 ] % 2 ) ) printf( "-" );

 if( 0 == iTotal ) printf( "0" );

 Output( cKekka );
}
注:インデントに全角空白を用いています。タブに一括変換して下さい。
    • good
    • 1
この回答へのお礼

回答ありがとうございます。課題のほうですが、何とか終わらせることができましたので、お書き頂いたプログラムはこれからの学習に役立てていきたいとます。

お礼日時:2008/07/29 16:03

反則になるかもしれませんが、


1.64ビットの整数がつかえるなら、それを使用されてはいかがですか。
linuxならlong long int型になります。
これで、約20桁の数値が格納できます。
2.それでも足りないなら、多倍長演算のライブラリを使用します。
これで、メモリが許す限り、無限桁の数値が扱えます。
参考URLを参照下さい。(多倍長演算のライブラリの一例です)
3.また、C言語でなくてよいなら、rubyで計算することを推奨します。
rubyの変数は、上限及び下限がありません。四則演算程度なら、半日でrubyの文法は覚えられます。

参考URL:http://mitv2.net/software/tiny_mp/tiny_mp.html
    • good
    • 0
この回答へのお礼

アドバイスありがとうございます。
long int~の話は初耳だったので試してみます。URLの方も参考にさせていただきます。

お礼日時:2008/07/24 20:18

「桁が大きいと結果がおかしい」というのは, 多分オーバーフローですね. ことあるごとに gcd を使って約分していくしかないと思います.


例えば a/b + c/d を計算するのに, (ad + bc) / (bd) としてしまってはダメで, 分母を最初から b と d の最小公倍数にする必要があります. とはいっても, これだけで本当に十分とは思えないんですが....
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
正直なところ、gcd関数はあまり理解できていないのですが、もう少しがんばって考えてみます。

お礼日時:2008/07/24 20:05

>桁が大きい数で計算しようとすると値がおかしくなってしまいます


の部分ならある程度推測できます。
「int * int」の式が多いですが、この乗算の結果がintの最大値をオーバーフローしている場合に問題が出ていませんか?
オーバーフローしないように工夫する必要はあります。
例えば
sign3 = (a*c)/abs(a*c) * (b*d/abs(b*d));
 ↓
sign3 = (a/abs(a) * c/abs(c)) * ((b/abs(b) * d/abs(d));
とか(元の計算式があってるかは確認していません)
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
オーバーフローというものは良く分からないのですが、アドバイスを踏まえて色々やってみます。

お礼日時:2008/07/24 20:00

気になる点


・ ユークリッド互除法gcdの入力の制約を満たしていない
 xがy以上.x,yは自然数の制約.
 引数の0であるのにgcdを呼ぶ場合があるのでは?
・符号のチェックが少しわかりにくい
 sign = (a*d + b*c) / (b*d);
 sign = sign / abs(sign);
 こうしたほうがあとから見てわかりやすいのでは?
・冗長な部分が多い
 分数の入力,計算結果の表示は関数にできますね.
    • good
    • 0
この回答へのお礼

ご指摘ありがとうございます。
アドバイスを踏まえ、もう一度再考した結果、より短くまとめることができました。

お礼日時:2008/07/24 19:58

このQ&Aに関連する人気のQ&A

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

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

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

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

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);
}

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

C言語の問題で分数の足し算までは一応できるんですが、答えがでたときに整数で出すやり方と約分して表す方法が分かりません。
どなたか知恵を貸してくれませんか?

ユーザから4つの整数を入力し、はじめに入力された2個の整数と後に入力された2個の整数を分数と考え、その分数の和を表示するプログラムを作成せよ。
例えば、「3」「4」「5」「6」と入力されたときは、3/4 + 5/6を計算する。
そのプログラム内では分数の和を計算する関数を作成する。
...続きを読む

Aベストアンサー

#4 です.

> 再帰はどのように使えばいいのでしょうか?

#4 に挙げた URL の英語版には,再帰版と非再帰 (繰り返し) 版の
擬似コードがあります.

Euclidean algorithm (Wikipedia)
http://en.wikipedia.org/wiki/Euclidean_algorithm
→ Using recursion (再帰版擬似コード)
→ Using iteration (繰り返し版擬似コード)

Cで書けば,

// mとnの最大公約数 (GCD) を求める.
unsigned gcd(unsigned m, unsigned n)
{
 return (n == 0) ? m : gcd(n, m % n);
}

たったこんだけ.

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

(整数値)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の値と(整数値)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;
elsesi...続きを読む

Aベストアンサー

★アドバイス
・まずは算数からアドバイスします。
 - - ⇒+
 - + ⇒-
 + - ⇒-
 + + ⇒+
 ですよね。
・だから入力された 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

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

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

(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)の部分のやり方がいまいちよくわからなかったので質問しました。
どなたかご教授お願いできないでしょうか・・・。

(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("分母=");/*分母の...続きを読む

Aベストアンサー

/*
暗に結構コード書いて下さい、って丸投げする質問者ってのも多いんだけど, 質問者さんはそうじゃないみたいで安心した。
きっとこんなコードも読めるんじゃないかな?
*/

#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;

}

/*
暗に結構コード書いて下さい、って丸投げする質問者ってのも多いんだけど, 質問者さんはそうじゃないみたいで安心した。
きっとこんなコードも読めるんじゃないかな?
*/

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

/*
abs(x)はxの絶対値を返す関数で,math.hに定義されているんだよ。
もしこれがなくても自分で作れると思う。
*/

int main(void){

int denominator; /* 分母の絶対値 */
int numerator; /* 分子の絶対値 */

int sign;
int gcdofthetwo;

printf("denominator = ");
s...続きを読む

Q分数計算で分母と分子を維持するには?

「1/2+1/3と引数を渡して、5/6という返り値を得る」という汎用のライブラリってありますでしょうか?

現状では1/2+1/3=0.5+0.33333333=0.833333333と計算
 ↓
continued fractions(http://mathforum.org/library/drmath/view/51886.html)
の手法で分数に変換してます。

しかし、近似解であり厳密解でないため、収束条件をかえると違う値を返してきます。

「MathematicaやMapleというalgebra softwareをC#から呼び出す」と簡単に実装できるのですが
単に分数計算するためだけなのに○十万円するのはちょっと、。。

で、
(1)商用であってもいいんだけど、できれば1万円以下
(2).netから呼べる。
(3)分数の厳密解を返す
みたいなものをご存知のかたがおられましたらよろしくご教示ください。

よろしくお願いします。

Aベストアンサー

若干ずれた回答かもしれませんが、外部から他の数式処理システム呼び出してもよく、市販の数式処理ソフトが高価な事が問題なのであれば、Maximaのようなフリーのものを使うというのはダメでしょうか?
私はMaximaしか使ったことありませんし、外部から呼び出したことはないので、連携のしやすさなどはちょっとわからないのですが、フリーの数式処理ソフトは結構あるみたいですよ。
http://ja.wikipedia.org/wiki/%E6%95%B0%E5%BC%8F%E5%87%A6%E7%90%86%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AE%E4%B8%80%E8%A6%A7

Q「割り算」 と 「分数の掛け算」

double型の変数にある値が代入されていて、
その数を半分にしようとしました。
演算部分を /2 としたらエラーが出てしまいました。
いろいろ試した結果、*0.5とすれば
ちゃんと計算されるようなのですが、
どうしてこのようなことが起こるのか、よくわかりません。
どなたか、ご教授ください。よろしくお願いします。

Aベストアンサー

>#define c 1
と言うことで、c は int の定数と判断されます

>double b;
で、格納する変数は double になっているのですが、

>b = c / 2;
の右辺を見ると、
定数のintである1を、定数のintである2で割っているため、この文の結果はintになってしまいます。
本来なら0.5となるべきところですが、/ の両辺が int の場合は、結果を int で返しますので、0.5 の実数部分の0が結果となるわけです。
これを右辺の b に代入するときに 暗黙の型変換にてdouble として入れているのですが、すでに切り捨てられてしまった小数部分は帰ってこないわけですね。

2.0 とするとうまくいくのは、
/ のどちらかが double の場合は、片方の int を暗黙に double に変換して double の結果を返すからですね。

演算式の、型変換について、もう一度ヘルプ等で調べて見てください。

Q分数の計算のプログラミングです。

 2つの分数 U/SとV/tの足し算は、Sとtの最小公倍数を l とするとき、
u×l/S+u×l/t 分のlによっておこなわれるんですが、最小公倍数を
ユークリッドの互除法で求め、分数の足し算を分数のまま実行するには
どうプログラムすればよいのでしょうか?教えてください。
宜しくお願いいたします。 

 

Aベストアンサー

まず、ユークリッドの互除法で求められるのは、最大公約数ですよね。

これは、
int Euclid(int S, int T){
int x,y,z;
x=S;y=T;
for(;;){
z=x%y;
if(z==0){break;}
x=y;y=z;
}
return y;
}
で、求まります。
最小公倍数は、
S*T/Euclid( S, T);
で求まります。
あとは、
l=S*T/Euclid( S, T);
((u*l/S)+(v*l/T))/l;
これで、U/S+V/Tが求められます。

部分部分細切れになっているので、つなげればできますよね。

Q数字の位ごとの値を表示するプログラム

scanfで入力した数字の位ごとの値を表示するプログラムを作りたいのですがどうしたらいいですか?

例えば1234という数字を入れたら
10の位・・・3
1の位・・・4
という感じです

Aベストアンサー

> 10の位・・・3

1234を10で割って小数点以下を切り捨て。→123.4→123
123を10で割った余りを求める。→3

> 1の位・・・4

1234を1で割って小数点以下を切り捨て。→1234
1234を10で割った余りを求める。→4

とか。

QC#にて別クラスの関数を使いたい

C#にて、別クラスの関数を使用する方法を教えてほしいです。

下記のような、構造体を受け取るメソッドを作りました。

*****************************
private struct MyPoint
{
public int x;
public int y;
}

private void proc1(MyPoint pt)
{
MessageBox.Show("座標:" ; pt.x + "," + pt.y + "実行結果");
}

private void button1_Click(object sender ,System.EventArgs e)
{

MyPoint pt;
pt.x = 10;
pt.y = 20;
proc(pt);
}
*****************************

別のフォームのクラスから、proc1を呼び出したいのですが、やり方がわかりません。
どうか、教えてください。

Aベストアンサー

同じ定義をしたとしても別の名前空間に書いた構造体は同一とはみなされません。

呼び出し先クラスでの構造体を private では無く、public で宣言して下さい。

呼び出し元では、

MyClass.MyPoint pt;

のようにして実体を作ります。

Q配列の要素数に変数を入れたいときには

よろしくお願いします。
配列の要素数には定数しか入れられないのですが,どうしても変数を入れたいときは,それを引数として関数を呼び出すしか方法はないでしょうか。
具体的には,scanfで手に入れたint型の変数を要素数とする配列を宣言したいのですが,どうすれば良いでしょうか。
ご教授ください。

Aベストアンサー

c99と呼ばれる最近の規格では、配列の大きさに変数を使用できます。
bccはc99に対応していないようです。

それ以前の規格では、動的領域確保関数 malloc や callocを使って領域を確保するか、効率等を無視してバカデカい配列を用意しておくかです。
「それを引数として関数を呼び出す」っていうのは、malloc/callocのことですか?

Qfgetsで拾われる改行文字を削除したい

お世話になります

 C言語初心者のものです。今課題でC言語を用いたプログラミングを
Fedora上でやっています。問題は、fgetsでテキストファイルから、取得
した文字列の中から改行文字を削除できないことです。文字変数のアド
レスはわかっているのですが、終端文字に置換しようとすると、セグメ
ントエラーになってしまいます。これは如何にして解決すべきでしょう
か。よろしくお願いします。

Aベストアンサー

ポインタとかアドレスとか、C言語の用語としてあるものを別の意味に使うとまぎらわしいです。

「ポインタ」「アドレス」と言われたら、 この例なら str, str+i が思い浮びます。
「文字変数のアドレス」だと
char c ;
に対しての
&c
が思い浮びます。

配列なら「添字」、意味的には「x文字目」ですね。

> for(i=0;;i++){
> if(*(str+i)=='/n') {
> *(str+i)='\0';
> break;
> }
> }
/nが\nの間違いなら、この方法で半分正解です。もう少し広い範囲(可能なら全体)で見ないことにはなんとも言えません。
fgetsが最大文字数に達したり、ファイルの最後になったりで、strに改行文字が含まれない場合には、このループは止まりません(Segmentension Falutになって止まる)

・そのような状態になってないか、予めチェックする
・ループを終了させる仕組みを用意しておく
: forの終了条件を記述する、for中で if(*(str+i)=='\0') { break;} 等としておく、等
といった対策が必要です。


あと細かいところを言えば
・strを配列で用意したなら *(s+i)じゃなくてs[i]でいいんじゃないかな
・あるいは char *pみたいにしておいて、 iのループでなく pでループを組む( for(p=str;*p!='\0';p++) )とか。

ポインタとかアドレスとか、C言語の用語としてあるものを別の意味に使うとまぎらわしいです。

「ポインタ」「アドレス」と言われたら、 この例なら str, str+i が思い浮びます。
「文字変数のアドレス」だと
char c ;
に対しての
&c
が思い浮びます。

配列なら「添字」、意味的には「x文字目」ですね。

> for(i=0;;i++){
> if(*(str+i)=='/n') {
> *(str+i)='\0';
> break;
> }
> }
/nが\nの間違いなら、この方法で半分正解です。もう少し広い範囲(可能なら全体)で見ないことにはなんとも言えません。
fgetsが...続きを読む


人気Q&Aランキング