3日目 5日目

4日目

目標


問題3の回答例

問題3の回答例

あくまで回答例であり、この通りである必要はない。

問題 3-1

2月の日数を求めるようなプログラムを考えてみよ。

与えられた閏年かどうかの判定手続きをプログラム化することを考える。 手続きは次の通りであった。

  1. 西暦年数が4で割りきれなければ平年
  2. 西暦年数が400で割りきれると閏年
  3. 西暦年数が400では割りきれず、100で割りきれると平年
  4. 残りは閏年

まず、西暦年数を代入する変数を y とし、 閏年かどうかの判別を行う変数を leapとすることにしよう。

     int y;      /* 西暦年数 */
     int leap;   /* 閏年の場合は 1, 平年の場合は 0 */
  

条件を順番に C で表現してみることにする。

  1. 西暦年数が4で割りきれなければ平年

    「割りきれる」とは「割ったあまりが0」というヒントと合わせると、 まず、yの4で割ったあまりを計算すれば良いことに気付く。 y を4で割ったあまりは剰余演算子%を用いて (y%4)と書ける。これが 0 でなければ平年、つまり leap を 0 にするのであるから

         if ((y%4) != 0) {
             leap = 0;
         }
        

    となる。

  2. 西暦年数が400で割りきれると閏年

    今度は割りきれる場合である。したがって != ではなく、== を 使う必要がある以外には、1番とそれほど変わらない。 問題文には、「1が成立しない場合で」とは明記されていないが、4で割りきれず、400で 割りきれる数は存在しないので、else if を用いることになる。

          else if ((y%400) == 0) {
              leap = 1;
          }
        
  3. 西暦年数が400では割りきれず、100で割りきれると平年

    さらに条件が続くが、これまた、1 と 2 が成立する場合以外であるから、 引き続き、else ifを用いる。また、「西暦年数が400では割りきれず」は 2番目の条件に成立しない場合のみしか、この else ifには該当しないので あえて表現する必要はない。

         else if ((y%100) == 0) {
             leap = 0;
         }
        
  4. 残りは閏年

    「残りは」という事なので、上の3条件に合致しなかったものは無条件に うるう年と言うことであるから、elseを用いて表現する。

         else {
           leap = 1;
         }
        

以上をまとめると

	int y;      /* 西暦年数 */
	int leap;   /* 閏年の場合は 1, 平年の場合は 0 */

	y = 2005;   /* 判断したい年を代入 */

	if ((y%4) != 0) {
	    leap = 0;
	} else if ((y%400) == 0) {
	    leap = 1;
	} else if ((y%100) == 0) {
	    leap = 0;
	} else {
	    leap = 1;
	}
   

となる。


問題 3-2

問題 3-1 と同様、一つづつ順番に考えることとする。条件は次のようであった。

  1. 整数変数 y に年を代入する
  2. 整数変数 m に月を代入する
  3. y から 1600を引く
  4. 次のような条件に基づく処理を行う。
  5. 整数変数 d に(365.25*y)を代入する
  6. d から (y/100) を引く
  7. d に (y/400) を加える
  8. さらに d に 30.6*m + 3.5を加える
  9. 得られた d を7で割った余りは、上で決めたルールにしたがった曜日を表す数字である。

これらのうち、1 および 2 については、すでに入力されているものとして 考えることにする。というのも、最終的には calendar 関数の 引数を、「年、月」としたいわけなので、すでに関数が呼ばれた段階では 値が設定されているからである。

  1. 整数変数 y に年を代入する
  2. 整数変数 m に月を代入する
  3. y から 1600を引く
    y = y - 1600;

    これ以降は、y は「年」を表さなくなっていることに注意。

  4. 次のような条件に基づく処理を行う。

    文章をそのままコードにしてみると、次のようになる。

          if (m == 1 || m == 2) {
              m = m + 9;
    	  y = y - 1;
          } else {
              m = m - 3;
          }
      
  5. 整数変数 d に(365.25*y)を代入する

    いままで、d は出てきていなかったため、関数の先頭部分に

    int d;

    を加えた後、4の続きに

    d = 365.25 * y;

    を加える。

  6. d から (y/100) を引く
    d = d - (y/100);
  7. d に (y/400) を加える
    d = d + (y/400);
  8. さらに d に 30.6*m + 3.5を加える
    d = d + 30.6m + 3.5;
  9. 得られた d を7で割った余りは、上で決めたルールにしたがった曜日を表す数字である。

    曜日は youbiという変数にいれていたので、

    youbi = d % 7;

    となる。

結局、3-1, 3-2 の指示に従うと、calendar関数は次のように 書けることになる。

int calendar(int y, int m) 
{
	int i;
	int leep = 0;
	int mday ;
	int d;
	int youbi;
	int mdays[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};


	if (m > 13 || m < 1) {
		/* 月の値が変なので、カレンダ表示はしない */
		return (1);
	}

	/* まず、年月を表示する */

	printf("\n       %4d/%2d\n",  y, m);
	printf(" Su Mo Tu Wd Th Fr Sa\n");

	if (m == 2) {
		if ((y % 4) != 0) {
			/* 4で割りきれない年は平年 */
			leep = 0;
		} else if ((y % 400) == 0) {
			/* 400 で割りきれる年は閏年 */
			leep = 1;
		} else if ((y % 100) == 0) {
			/* 400で割りきれなくて100で割りきれる年は平年 */
			leep = 0;
		} else {
			/* 残りはうるう年 */
			leep = 1;
		}
	}
	mday = mdays[m] + leep;

	y = y - 1600;
	if (m < 3) {
		m = m + 9;
		y = y - 1;
	} else {
		m = m - 3;
	}
	 
	d = 365.25*y;
	d = d - (y/100);
	d = d + (y/400);
	d = d + 30.6*m + 3.5;

	youbi = d % 7;
	
	for (i = 0; i < youbi; ++i) {
		printf("   ");
	}
	
	for (i = 1; i <= mday; ++i) {
		printf(" %2d", i);
		if ((i%7) == ((7 - youbi)%7)) {
			printf("\n");
		}
	}
	printf("\n");
	return(0); /* カレンダはきちんと表示された */
}

3日目 表紙 5日目

tacha@tack.fukui-med.ac.jp
$Id: 04.html,v 1.1 2005/11/18 02:32:48 tacha Exp $