課題がわからないので教えてください

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

課題がわからないので教えてください

#1

投稿記事 by kokoro » 16年前

【問題文】
1] 授業単元: C言語
[2] 問題文(含コード&リンク):
   ・2つの分数の分子と分母を入力すると,それらの和・差・積・商を
    出力する.データは構造体で表現すること.
   ・分数計算では通分・約分には最大公約数が必要になる.通分には分母の最小公倍数が,
    約分には最第公約数が必要である.したがってこれらを計算する関数をそれぞれ作る.
   ・最大公約数を求めるには,次のアルゴリズムを使うとよい(ユークリッドの互除法).
    ① mをnで割る (ただしm>n).
    ② ①の割る数を①の余りで割る.
    ③ ②の割る数を②の余りで割る.
    ④ 以下同様に,余りが0になるまで繰り返し,そのときの「割る数」が最大公約数になる.
   ・2つの数,m,nの最小公倍数は,m*n/(mとnの最大公約数)で求めることができる.


   (実行例)
    1つめの分数の分子・分母の入力―>3  4
    2つめの分数の分子・分母の入力―>1  6
    和:11 / 12
    差: 7 / 12
    積: 1 / 8
    商: 9 / 2

和と差が計算できないのですが、どうすればいいのでしょうか?
教えてください。
ソースは添付しました。

lbfuvab

Re:課題がわからないので教えてください

#2

投稿記事 by lbfuvab » 16年前

ユークリッドの互除法(最大公約数の出し方)は理解していますか?

たいちう

Re:課題がわからないので教えてください

#3

投稿記事 by たいちう » 16年前

通分の方法が間違っています。以下の通りではないかと。

A.son / A.mom = (A.son * new_mom) / (A.mom * new_mom) = (A.son * new_mom / A.mom) / new_mom
(和) = (A.son * new_mom / A.mom + B.son * new_mom / B.mom) / new_mom

バグ

Re:課題がわからないので教えてください

#4

投稿記事 by バグ » 16年前

間違ってたらごめんなさい(苦笑)
しかも、無駄に長いし…(^_^;)
#include <stdio.h>

// 分数表現用の構造体
struct Fraction
{
	int Numerator;		// 分子
	int Denominator;	// 分母
};

// プロトタイプ宣言
void InputFraction(int count, struct Fraction* fraction);
void Addition(struct Fraction fraction1, struct Fraction fraction2, struct Fraction* answer);
void Subtraction(struct Fraction fraction1, struct Fraction fraction2, struct Fraction* answer);
void Multiplication(struct Fraction fraction1, struct Fraction fraction2, struct Fraction* answer);
void Division(struct Fraction fraction1, struct Fraction fraction2, struct Fraction* answer);
int GreatestCommonDivisor(int value1, int value2);
int LeastCommonMultiple(int value1, int value2);
void ReductionToItsLowestTerms(struct Fraction* fraction);

// メイン関数
int main(void)
{
	struct Fraction f1, f2, f3;
	InputFraction(1, &f1);
	InputFraction(2, &f2);

	Addition(f1, f2, &f3);
	printf("たし算 = %d / %d\n", f3.Numerator, f3.Denominator);

	Subtraction(f1, f2, &f3);
	printf("ひき算 = %d / %d\n", f3.Numerator, f3.Denominator);

	Multiplication(f1, f2, &f3);
	printf("かけ算 = %d / %d\n", f3.Numerator, f3.Denominator);

	Division(f1, f2, &f3);
	printf("わり算 = %d / %d\n", f3.Numerator, f3.Denominator);
}

// 分数データの入力
void InputFraction(int count, struct Fraction* fraction)
{
	printf("%d 個目のデータ入力\n", count);

	printf("分子を入力して下さい ");
	scanf("%d", &fraction->Numerator);

	printf("分母を入力して下さい ");
	scanf("%d", &fraction->Denominator);
}

// たし算
void Addition(struct Fraction fraction1, struct Fraction fraction2, struct Fraction* answer)
{
	int lcm = LeastCommonMultiple(fraction1.Denominator, fraction2.Denominator);
	answer->Numerator = fraction1.Numerator * (lcm / fraction1.Denominator) + fraction2.Numerator * (lcm / fraction2.Denominator);
	answer->Denominator = lcm;
	ReductionToItsLowestTerms(answer);
}

// ひき算
void Subtraction(struct Fraction fraction1, struct Fraction fraction2, struct Fraction* answer)
{
	int lcm = LeastCommonMultiple(fraction1.Denominator, fraction2.Denominator);
	answer->Numerator = fraction1.Numerator * (lcm / fraction1.Denominator) - fraction2.Numerator * (lcm / fraction2.Denominator);
	answer->Denominator = lcm;
	ReductionToItsLowestTerms(answer);
}

// かけ算
void Multiplication(struct Fraction fraction1, struct Fraction fraction2, struct Fraction* answer)
{
	answer->Numerator = fraction1.Numerator * fraction2.Numerator;
	answer->Denominator = fraction1.Denominator * fraction2.Denominator;
	ReductionToItsLowestTerms(answer);
}

// わり算
void Division(struct Fraction fraction1, struct Fraction fraction2, struct Fraction* answer)
{
	answer->Numerator = fraction1.Numerator * fraction2.Denominator;
	answer->Denominator = fraction1.Denominator * fraction2.Numerator;
	ReductionToItsLowestTerms(answer);
}

// 最大公約数
int GreatestCommonDivisor(int value1, int value2)
{
	while (value1 % value2 != 0)
	{
		int rest = value2;
		value2 = value1 % value2;
		value1 = rest;
	}
	return value2;
}

// 最小公倍数
int LeastCommonMultiple(int value1, int value2)
{
	return value1 * value2 / GreatestCommonDivisor(value1, value2); 
}

// 約分
void ReductionToItsLowestTerms(struct Fraction* fraction)
{
	int gcd = GreatestCommonDivisor(fraction->Numerator, fraction->Denominator);
	fraction->Numerator /= gcd;
	fraction->Denominator /= gcd;
}

kokoro

Re:課題がわからないので教えてください

#5

投稿記事 by kokoro » 16年前

>>たいちうさん
こればどこに入れればいいんですか?

>>lbfuvabさん
ユークリッドの互除法は int gcd 
のところではないんですか?

たいちう

Re:課題がわからないので教えてください

#6

投稿記事 by たいちう » 16年前

まずは、あなたの頭に。

lbfuvab

Re:課題がわからないので教えてください

#7

投稿記事 by lbfuvab » 16年前

あ、携帯から見てたのでソースが見れなくてアホな事を言ってしまいました。
すいませんでした。

バグ

Re:課題がわからないので教えてください

#8

投稿記事 by バグ » 16年前

華麗にスルーされてる…orz
参考ソースを見ずに、全部オリジナルでおこしたのがマズかったかな?(^_^;)

バグ

Re:課題がわからないので教えてください

#9

投稿記事 by バグ » 16年前

オリジナルソースをある程度は残しつつ作ってみました。
あとはご自身で解読してみて、そのうえで分からないところがあれば、ご質問ください。
#include <stdio.h> 

/* 分数構造体 */
typedef struct bunsu
{
	int son;
	int mom;
}
BUNSU;

/* プロトタイプ宣言 */
int Gcd(int m, int n);
int Lcm(int m, int n);
void Rlt(BUNSU* a);
void Rcd(BUNSU* a, BUNSU* b);

/* メイン関数 */
int main()
{
	BUNSU A, B, C;

	/* 分数の入力 */
	printf("1つめの分数の分子・分母の入力-> \n");
	scanf("%d %d",&A.son, &A.mom);
	printf("2つめの分数の分子・分母の入力-> \n");
	scanf("%d %d",&B.son, &B.mom);

	/* 通分 */
	Rcd(&A, &B);

	/* 和 */
	C.son = A.son + B.son;
	C.mom = A.mom;
	Rlt(&C);
	printf("和:%d / %d\n", C.son, C.mom); 

	/* 差 */
	C.son = A.son - B.son;
	C.mom = A.mom;
	Rlt(&C);
	printf("差:%d / %d\n", C.son, C.mom);

	/* 積 */
	C.son = A.son * B.son;
	C.mom = A.mom * B.mom;
	Rlt(&C);
	printf("積:%d / %d\n", C.son, C.mom); 

	/* 商 */
	C.son = A.son * B.mom;
	C.mom = A.mom * B.son;
	Rlt(&C);
	printf("商:%d / %d\n", C.son, C.mom);

	return 0;
}

/* 最大公約数を求める関数 */
int Gcd(int m,int n)
{
	int temp, amari;

	if (m < n)
	{
		temp = m;
		m = n;
		n = temp;
	}

	while (m % n != 0)
	{
		amari = n;
		n = m % n;
		m = amari;
	}

	return n;
}

/* 最小公倍数を求める関数 */
int Lcm(int m, int n)
{
	return m * n / Gcd(m, n);
}

/* 約分を行う関数 */
void Rlt(BUNSU* a)
{
	int gcd = Gcd(a->son, a->mom);
	a->son /= gcd;
	a->mom /= gcd;
}

/* 通分を行う関数 */
void Rcd(BUNSU* a, BUNSU* b)
{
	int lcm = Lcm(a->mom, b->mom);
	a->son *= (lcm / a->mom);
	a->mom = lcm;
	b->son *= (lcm / b->mom);
	b->mom = lcm;
}

kokoro

Re:課題がわからないので教えてください

#10

投稿記事 by kokoro » 16年前

バグさんありがとうございます。
バグさんのプログラムを実行してみました。
私のプログラムもそうなんですが、商のところで、

問題文の
1つ目の分子・分母ー>3 4
2つ目の分子・分母ー>1 6

を計算すると 9/2と合っている答えが出るのですが、
他の数字たとえば、
1つ目の分子・分母ー>4 5
2つ目の分子・分母ー>3 7

を計算すると答えは 15/28になると思うのですが、
プログラムを実行すると、28/15と逆になってしまいます。
どうしてでしょうか?

教えてください。

kokoro

Re:課題がわからないので教えてください

#11

投稿記事 by kokoro » 16年前

すみません。
私の勘違いだったかもしれないです。
前のはなしで。

Mist

Re:課題がわからないので教えてください

#12

投稿記事 by Mist » 16年前

4/5 ÷ 3/7 = 28/15

で正しいけど。

バグ

Re:課題がわからないので教えてください

#13

投稿記事 by バグ » 16年前

4/5 ÷ 3/7 = 28/15
であってるんではないでしょうか?
問題ないように思うのですが?(^_^;)

TOMONORI

Re:課題がわからないので教えてください

#14

投稿記事 by TOMONORI » 16年前

分数を扱うプログラムって結構面白いですね。
しかし残念なことに自分はCをほとんど知らない上、ユークリッドの~も
忘れてしまったので通分なんかはこんな感じに
void reduce(int * n, int * d, int i = 2)
{
	for(; i <= (* n < * d ? * n : * d); ++ i)
	{
		if(* n % i + * d % i == 0)
		{
			reduce(& (* n /= i), & (* d /= i), i);
		}
	}
}
書いてしまうのですが、再帰呼び出しが汚すぎるうえにポインタを使ってしまっているので
(自分はポインタ嫌い)、Cで書くのはあきらめました。kokoroさんの質問に関しての回答は
すでに解決しているみたいなので、余興的な意味合いでC++での解を貼らせて下さい。
大概のコンパイラは許してくれるはず。分数の要素はunsigned限定で書きました。

改良点等の指摘があったら大喜びです。

(誰かに自分のコードを見てもらいたいと思う病気はどうやったら治るんでしょうか・・・
ぴよぴよを卒業するころには自然に治るのかな?)

閉鎖

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