グレゴリウス暦を使った問題です。

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

グレゴリウス暦を使った問題です。

#1

投稿記事 by カル » 17年前

はじめまして、今とある宿題を出されて悩んでいます。
OS:Windows xp
コンパイラ名とバージョン:VisualStudio2005
言語: C
C言語を勉強しだして3日たってもわからない初心者です、今は変数と演算について勉強してます
ですがこの問題がまったくわかりません

問題 グレゴリウス暦の定義を利用して、入力された日は何曜日か?
西暦1年1月はは月曜とし1年は365日、閏年は366日
4で割り切れる年は閏年、400で割り切れる年も閏年
100で割り切れる年は閏年ではない

備考
goto文は使用しない、変数名、関数名の命名規約を作成
外部変数は使用しない
途中でreturn exitは使用しない。
ツェラーの公式以外で。

今のところわかっているのは、前年までの総日数+前月までの総日数+今月の日数÷7で余った値が曜日になる
という事だけです。

VOW

Re:グレゴリウス暦を使った問題です。

#2

投稿記事 by VOW » 17年前

>西暦1年1月はは月曜とし

まったく意味がわからないです。
これでは誰も返答できないのでは?

カル

Re:グレゴリウス暦を使った問題です。

#3

投稿記事 by カル » 17年前

ですよね・・・間違えました・・
「西暦1年1月1日は月曜日」
と書いてありました。
スイマセン。

たかぎ

Re:グレゴリウス暦を使った問題です。

#4

投稿記事 by たかぎ » 17年前

↓でもよく似た質問をされている方がいます。参考にしてはいかがでしょうか?
http://okwave.jp/qa3698783.html

やそ

Re:グレゴリウス暦を使った問題です。

#5

投稿記事 by やそ » 17年前

C言語初心者(3日レベル)に対しての問題としては、ちょっとレベルが高めの問題に感じます。
しかもツェラーの公式を使えないなんて^^;

まずは流れを考えて見ましょう。

1.曜日を知りたい日付を入力させる。
2.入力された日付を基準日から何日たっているか数える。
3.曜日判定する。
4.結果を出力する。

1.の日付入力は、とりあえずエラーチェックの類は省いたほうが簡単そうですね。
(間違った日付は入力されないのが前提ということ)
また、年、月、日は別々に入力させたほうが処理するほうは楽ですね^^

2.基準日から何日たっているか数えるところでは、ループを用いましょう。
年(前年まで)の回数分ループさせるようにして、
ループの内部ではその年がうるう年かの判定をして、
365を足すか、366を足すかを決めます。

ループ終了後、求められた日数に
(その年の1月1日から)前月までの総日数+今月の日数
を計算し、
÷7で余った値が曜日になる

です。
あとはそれを表示するだけです。

ポイントとしては、年、月は計算する際には前年、前月まで計算すると言うところです。
(理屈を理解すれば分かることですが^^)

本当はプログラムを書いて見せてあげればいいんでしょうけど、それでは勉強になりませんので、
個人的にはこのような形で返答することにしています。

がんばって下さい。

やそ

Re:グレゴリウス暦を使った問題です。

#6

投稿記事 by やそ » 17年前

補足。

基準日の初期値はZEROでしょうか。

それによって割った際の余りの値が変わってきます。

基準日を0とした場合
余りの値 0 1 2 3 4 5 6 
曜日   月 火 水 木 金 土 日

基準日を1とした場合
余りの値 0 1 2 3 4 5 6 
曜日   日 月 火 水 木 金 土 

となると思います。

やそ

Re:グレゴリウス暦を使った問題です。

#7

投稿記事 by やそ » 17年前

連投失礼します。

他には・・・

year という変数に年を入力するとして、
int u4=0,u100=0,u400=0;

year-b=year--; //前年

u400=year-b/400
u100=year-b/100
u4=year-b/4

でうるう年、非うるう年の回数を計算して合計することで、
ループを使わずに計算することも可能です。

まあ、こちらは理屈が分かった上での方がいいので、次の段階でしょうか?

カル

Re:グレゴリウス暦を使った問題です。

#8

投稿記事 by カル » 17年前

たくさんのヒントありがとうございます。
とりあえずここまで考えてみました

# include <stdio.h>

int main () {

int year =0 /*年数*/
int months=0 /*月*/
int day =0 /*日数*/
int uruu =0 /*閏年*/
int days[13]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
char weekname[7]={"日", "月", "火", "水", "木", "金", "土"};

printf("西暦は何年ですか?\n");
scanf("%d",&nyear);
printf("何月ですか?\n")
scanf("%d",&nmonths);
printf"何日ですか?\n");
scanf("%d"&nday);

day=365*(year-1);

y % 4 == 0 && y % 100 != 0 || y % 400 == 0

めちゃくちゃな感じになってしまってるかもしれませんが・・・

やそ

Re:グレゴリウス暦を使った問題です。

#9

投稿記事 by やそ » 17年前

コンパイル・・・してなさそうですね^^;

int main () {

int year =0; /*年数*/
int months=0; /*月*/
int day =0; /*日数*/
int uruu =0; /*閏年*/
int days[13]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
char weekname[7]={"日", "月", "火", "水", "木", "金", "土"};

printf("西暦は何年ですか?\n");
scanf("%d",&nyear); &nyearではなく&yearでは?
printf("何月ですか?\n")
scanf("%d",&nmonths); &nmonthsではなく&monthsでは?


printf"何日ですか?\n");
scanf("%d"&nday); &ndayではなく&dayでは?
/* うるう年チェックの優先順位をもう一度良く考えて見ましょう */
/* また、yって宣言してますか? */
day=365*(year-1);

y % 4 == 0 && y % 100 != 0 || y % 400 == 0


引き続きがんばってください^^

カル

Re:グレゴリウス暦を使った問題です。

#10

投稿記事 by カル » 17年前

問題の訂正
4で割り切れる年は閏年、400で割り切れる年も閏年
100で割り切れる年は閏年ではない

4で割り切れる年は閏年
100で割り切れる年は閏年ではない
400で割り切れる年は閏年
でした。

やそ

Re:グレゴリウス暦を使った問題です。

#11

投稿記事 by やそ » 17年前

んー、問題文の記述の順番が違っていたとしても、その内容は変わってませんよね?
(変わったらおかしいですが)
で、
「4で割り切れる」
「100で割り切れる」
「400で割り切れる」
と言うのは、どの順番で行ったら(チェックしたら)良いと思いますか?
と言うことを言いたかったのです。

また、
y % 4 == 0 && y % 100 != 0 || y % 400 == 0

は構文として成立していませんね。
(if文でくくりたい内容なのだとは思いますが)

たとえば2001年1月1日の曜日を検索したいとして、
まずは2000年12月31日までの日数を計算します。

で、2000を4で割ると500。余り0。
2000を100で割ると20。余り0。
2000を400で割ると5。余り0。

となります。

さてどうやってチェックしましょうか?

コレが出来たら2005年10月10日など、いろいろな年月日で検証してみると良いでしょう。

カル

Re:グレゴリウス暦を使った問題です。

#12

投稿記事 by カル » 17年前

int main () {

int year =0; /*年数*/
int months=0; /*月*/
int day =0; /*日数*/
int uruu =0; /*閏年*/
int y
int days[13]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
char weekname[7]={"日", "月", "火", "水", "木", "金", "土"};

printf("西暦は何年ですか?\n");
printf("西暦は何年ですか?\n");
scanf("%d"&year);
printf("何月ですか?\n");
scanf("%d",&months);
printf"何日ですか?\n");
scanf("%d"&day);

uruu = year/4;
days += uruu;

/*100で割れる年*/
uruu = year/100;
days -= uruu;

/400で割れる年*/
uruu = year/400;
days += uruu;
こんな感じでしょうか・・・・

カル

Re:グレゴリウス暦を使った問題です。

#13

投稿記事 by カル » 17年前

あ、スイマセン、考え直してきます。

やそ

Re:グレゴリウス暦を使った問題です。

#14

投稿記事 by やそ » 17年前

一度、ご自分の思ったとおりにプログラムを組んでみて、コンパイルしてみることをオススメします。

初めから完璧なコードを書きたい気持ちは分かりますが、このようなやり取りが続くことを考えると、
完成まで何ヶ月かかるか?です。

問題文と私の助言?を基に最後の曜日の表示まで作ってみてください。

プログラム作成の基本と言うか身に付けたいなら何度もTRY&エラーを繰り返すべきです。
よほどのことがない限り、コンピュータを壊すようなことはありませんので、安心?して失敗してください。

エラーに慣れる。ことが上達の早道です^^

カル

Re:グレゴリウス暦を使った問題です。

#15

投稿記事 by カル » 17年前

そうですね、一度やってみようとおもうのですが
コンパイルするにもソフトがないんです・・
ないならネットとかでDLできますかね?(世間知らずでスイマセン)
あと最後の質問なのですが
#include <stdio.h>

int main () {

int y, m, d, sum = 0;
int m_array[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
char *week[7] = {"日", "月", "火", "水", "木", "金", "土"};
printf("input (e.g. ****/**/**)\n>>");
scanf("%d/%d/%d", &y, &m, &d);

if (m > 2 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) {
++sum;
}

for (m -= 2; m >= 0; --m) {
sum += m_array[m];
}

--y;

sum = sum + y * 365 + y / 4 - y / 100 + y / 400 + d;
printf("%s曜日", week[sum%7]);
return 0;
}
これでなら一応完成でしょうか?

YuO

Re:グレゴリウス暦を使った問題です。

#16

投稿記事 by YuO » 17年前

学校なりでVisual Studio 2005を使っているのであれば,
http://www.microsoft.com/japan/msdn/vst ... past/2005/
から,Visual C++ 2005 Express Editionをダウンロードしてインストールするのがよいでしょう。

やそ

Re:グレゴリウス暦を使った問題です。

#17

投稿記事 by やそ » 17年前

やそです。
コンパイラが無かったんですか。
上達の早道はたくさん書くこと、なれること。ですのでコンパイラの導入をオススメします^^

早速ですが、
#include <stdio.h> 

int main () { 

  int y, m, d, sum ,i= 0; 
  int m_array[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; 
  char *week[7] = {"日", "月", "火", "水", "木", "金", "土"}; 

  printf("input (e.g. ****/**/**)\n>>"); 
  scanf("%d/%d/%d", &y, &m, &d); 

 ↑ここはなんで入力を纏めてしまったのでしょう?個別に聞いたほうが使用者に優しい気がしたのですが。

  if (m > 2 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) { 
    ++sum; 
  } 

 ↑ここでは・・・検索する当年の月を見てうるう年かの判定をしているようですね。

  for (m -= 2; m >= 0; --m) { 
    sum += m_array[m]; 
  } 

 ↑これ、おかしいです。初期値で既にマイナスになりえますから^^;当年の検索月の前月まで足したい処理だとは思うのですが、これでは・・・

検索月が5月なら1から4月の日数を足すわけですが、ならば
// m_array[0] ・・・1月
// m_array[1] ・・・2月
// m_array[2] ・・・3月
// m_array[3] ・・・4月
// 添え字は0から始まるので-1。更に前月までなので-1 = 検索月-2となる
  for (i=0; i <= m-2; i++) { 
    sum += m_array; 
  }



  --y; 

  sum = sum + y * 365 + y / 4 - y / 100 + y / 400 + d; 
// 最終的な表示が曜日だけではさびしいので
  printf("%d年%d月%d日は%s曜日です", ++y, m, d, week[sum%7]); 
//  のほうが見栄えがいいです。
  printf("%s曜日", week[sum%7]); 

  return 0; 
}


思わずコードを少し書いてしまいましたが、例によって私もコンパイルは(頭の中でしか)していないので、
きちんとコンパイルして検証することをオススメします。

カル

Re:グレゴリウス暦

#18

投稿記事 by カル » 17年前

アドバイスありがとうございます
さっそくDLしてコンパイルしてみたら
#include "stdafx.h"' をソースに追加しましたか?
とエラーが出てしまいます・・・
これを追加しても同じエラーが出てしまいます

管理人

Re:グレゴリウス暦

#19

投稿記事 by 管理人 » 17年前

空のオブジェクト、にチェックを入れた方が解りやすいと思います。

最初はプロジェクトを作るだけでも大変ですよね。

手元に2005が無いので少し違うかもしれませんが。。

メニューから「新規作成」>「プロジェクト」

「新しいプロジェクト」のウィンドウが出てきます。
左の Win32 をチェックし、Win32コンソールアプリケーションを選択。
好きなプロジェクト名を入力して「OK」を押す
Win32アプリケーションウィザードのウィンドウが出てきます。
そこでウィンドウ左の「アプリケーションの設定」をチェックし、
「空のプロジェクト」にチェックを入れて、完了します。

すると、何もないからのプロジェクトが出来上がります。
ソリューションエクスプローラーが表示されていなければ、「表示」から指定して表示してください。
「ソースファイル」右クリックで「追加」>「新しい項目」
そして出てきたウィンドウで、
左のVc++から「コード」をチェックし右で「C++ファイル(.cpp)」を選択。好きなファイル名を書いて終了。

後は出てきたエディタ画面にコードを書いてF5キーを押せばOKです。
コンパイルエラーの場合は、エラーメッセージが下に出てきます。
とりあえずこれをコンパイルしてください。
#include<stdio.h>
void main(){
	printf("Hello");
}
 
Helloと出れば成功です。
(本来int mainであり、最後にreturn (0);がいります)


・・・ところで、うちの大学の1回生用の最終課題として出した問題と全く同じなんですが、もしかして大学の課題ですか?

C歴3日とかかれているので、違うとは思いますが、もしかしたらと思いましたので・・。

カル

Re:グレゴリウス暦

#20

投稿記事 by カル » 17年前

いえ、大学の方はすでに卒業しております。
今独学で学んでいまして、友人にちょくちょく教えてもらっていて課題を出されたんです。
設定の情報ありがとうございます
がんばってやってみます。

カル

Re:グレゴリウス暦

#21

投稿記事 by カル » 17年前

#include <stdio.h>
	int main()
    int iyear, imonths,iday;
	int sum,i;
	int m_array[12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	char*cweek[7] = {"日", "月", "火", "水", "木", "金", "土"};
	
	sum =0;
	printf ("input (e.g ****/**/**\n>>");
	scanf ("%d/%d/%d/%d",&iear,&imonths,&iday);
         /*閏年の判定*/
	if ((imonths >2) && ((iyear % 4 == 0) && ((iyear % 100 !=0 ) || (iyear % 400 == 0)))) { 
	sum++;    
	}                  
         /*前月までの日数*/
	for (i = 0; i < imonths-1; i++) { 
	sum += m_array;
	}

	iyear--;
         /*前月と前年度と今月の日数の合計*/
	sum = sum + iyear * 365+((( +iyear / 4) - (iyear / 100)) + (iyear / 400)))+ iday;
	printf("%s曜日",cweek[sum%7]);
	return 0;

}

色々とコードを書いて頂き、ありがとうございます、とりあえずこれでOKだそうです。コンパイルしてみましたが問題はありませんでした。

box

Re:グレゴリウス暦

#22

投稿記事 by box » 17年前

> コンパイルしてみましたが問題はありませんでした。

こちらの環境ではエラーが頻発してコンパイルできませんでした。
特に最終形のコードを載せられる際は、エディタかどこかで
コピー&ペーストしたものを、そのまま"pre"タグと"/pre"タグではさんで
くださると、見やすくて助かります。

管理人

Re:グレゴリウス暦

#23

投稿記事 by 管理人 » 17年前

括弧の対応があちこちおかしいのでコンパイルできません。まずmainに括弧が無いところからして・・。
全角スペースもありますし、コピーじゃなくてみながら手入力されたのでしょうか?

後、コードを投稿するときは

<pre>と</pre>タグではさんでください。見やすくなります。(<>は半角)

カル

Re:グレゴリウス暦

#24

投稿記事 by カル » 17年前

#include<stdio.h>

	int main() {

	int iyear,imonths,iday;
	int sum,i;
	int m_array[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
	char*cweek[7] = {"日","月","火","水","木","金","土"};

	sum =0;
	printf ("input (e.g. ****/**/**)\n>>");
	scanf ("%d/%d/%d",&iyear,&imonths,&iday);
	/*閏年の判定*/
	if ((imonths >2) && ((iyear % 4 == 0) && ((iyear % 100 !=0) || (iyear % 400 == 0)))) {
	sum++;
	}
	/*前月までの日数*/
	for (i =0; i < imonths-1; i++) {
	sum += m_array;
	}

	iyear--;
	/*前月と前年度と今月の日数の合計*/
	sum = sum + iyear * 365 + (((iyear / 4)-(iyear / 100))+(iyear / 400))+iday;
	printf("%s曜日",cweek[sum%7]);
	return 0;

}

直しました、これでいけると思います、何度もスイマセンでした。やっぱりまだ慣れてないせいかミスが多いですね。あと宿題が追加されたのですが「間違った日付が入力された場合」ということなのですが
これはやそさんが言っていた「1.の日付入力は、とりあえずエラーチェックの類は省いたほうが簡単そうですね。 (間違った日付は入力されないのが前提ということ)」 これが関係しているのでしょうか?

管理人

Re:グレゴリウス暦

#25

投稿記事 by 管理人 » 17年前

>「間違った日付が入力された場合」
が追加されたと言うことですが、
「間違った日付が入力された場合、再入力させる仕様にする」でいいのでしょうか。
それならscanfの部分をwhile文でループにし、読み取った値が正常なものであればbreakしてぬけ、
正常でなければもう一度ループして入力させる仕様にすればいいと思います。
例えば
while(1){
    printfで入力を促す
    scanfで読み取る
    if(読み取った値が正常値なら)
        break;
    else
        printf("入力値が異常です。再入力してください\n");
}
 

感じとしてはこんな感じでしょうか。

カル

Re:グレゴリウス暦

#26

投稿記事 by カル » 17年前

「間違った日付が入力された場合、再入力させる仕様にする」
たぶんそれですね、ヒントありがとうございます

Re:グレゴリウス暦

#27

投稿記事 by » 17年前

どうでも良いのですが・・・<pre></pre>で囲むのはコードだけのほうが良いですよ。
文字も囲うと書いた行をそのまま表示しようとするので。
while(1){
	printf(***);
	scanf(***);
	
	//これで良いか確認を取る
	printf(***);
	scanf(***);
	
	//scanfで良いと判断できれば
	if(***){ break; }
	
}
の方が僕は良いと思いますが…

因みに ***は自由に
    変数は自分でお願いします。

カル

Re:グレゴリウス暦

#28

投稿記事 by カル » 17年前

コードだけですか、無知でスイマセン・・・
難しそうですね、(実際はそうでもないかもしれませんけど)
ヒントありがとうございます、やってみます!

Re:

#29

投稿記事 by » 17年前

//これで良いか確認を取る
printf(***);
scanf(***);
のところの
printfは前のscanfの内容をそのまま表示
scanfはただの選択肢用です。

説明へたですいません^^;

カル

Re:

#30

投稿記事 by カル » 17年前

("%d/%d/%d",&iyear,&imonths,&iday);
コレのことでしょうか?

やそ

Re:

#31

投稿記事 by やそ » 17年前

話の流れから言って多分その辺の表示のことでしょう^^;

入力年月日のエラーチェックをしたいのですから、
それが正しいか、入力者に確認させるために
printf(*****);
させてるのでしょう?

管理人さんや雷さんがほぼ理想的な解答を提示してくれてますよ。
それを自分なりにアレンジして完成させるだけです。

細かく言えば、どんな入力にも対応できるように、文字(列)で入力を取得して、
入力内容が

 1.数値の範囲
 2.正常な年月日(13月とか50日とか、負数ではない)

ことを確認し、
数値に変換する。

ここまでやればパーペキね(^^)d

カル

Re:

#32

投稿記事 by カル » 17年前

できました!なんかちょっぴり感動ですw
ありがとうございました。

閉鎖

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