Project Euler

Project Euler 問題19(日曜日を数える)を解いてみる(続き)

Euler_019

前回は、Project Euler で紹介されている問題19を解いてみました。今回は、別解として汎用的な方法(ツェラーの公式)を紹介します。

再掲載 Project Euler 問題19(日曜日を数える)

次の情報が与えられている。もちろん自分で調べた情報を使ってもよい。

  • 1900年1月1日は、月曜日
  • 4月、6月、9月、11月は30日ある。うるう年の2月は29日、うるう年以外の年の2月は28日ある。それ以外の月は31日ある。
  • 4で割り切れる年はうるう年となる。ただし、100で割り切れる年はうるう年ではない。ただし、400で割り切れる年はうるう年となる。

20世紀(1901年1月1日から2000年12月31日まで)の間に、月の初めが日曜日である月の数を求めよ。

注)Project Euler の表現は、著名な詩をベースにしているかもしれません。事実が分かりやすいように意訳しました。

準備(ツェラーの公式)

前回は、1900年1月1日が月曜日であることを使って解きました。ツェラーの公式を使えば、年と月と日が分かれば直接曜日が分かります。

ツェラーの公式は、いろいろな表現があるようです。この記事では、英語版の Wikipedia に掲載されている式を採用しました。

$$h = \left(q + \left\lfloor \frac{13(m+1)}{5} \right\rfloor + K +
\left\lfloor \frac{K}{4} \right\rfloor +
\left\lfloor \frac{J}{4} \right\rfloor -\, 2J \right) \bmod 7$$

  • h は曜日を表します。日曜日=0、月曜日=1、…、土曜日=6 となります。
  • q は日を表します。
  • m は月を表します。ただし、1月は前の年の13月、2月は前の年の14月とします。
  • K は西暦の下2桁を表します。
  • J は西暦を100で割った値を表します。
  • $\lfloor$ と $ \rfloor$ は、整数の切り捨てを表します。
  • $\bmod 7$ は、7で割った余りを表します。

この式は、グレゴリオ暦(1582年以降)であれば使えます。グレゴリオ暦に切り替わる前のユリウス暦の場合は、公式が異なるため注意が必要です。

解答例(別解)

ツェラーの公式を忠実に実装して、1901年1月から2000年12月までの月初めの曜日を求めて、日曜日の場合は、解答(answer)をインクリメントします。以下は、Cでの実装となります。

#include <stdio.h>

int day_of_week(int year, int month, int day)
{
	int K, J;

	if (month <= 2) {
		month += 12;
		--year;
	}
	K = year % 100;
	J = year / 100;

	return (day + (13 *(month + 1))/ 5 + K + K / 4 + J / 4 - 2 * J) % 7;
}

int main(void)
{
	int year, month;
	int answer = 0;

	for (year = 1901; year <= 2000; ++year) {
		for (month = 1; month <= 12; ++month) {
			if (day_of_week(year, month, 1) == 0) {
				++answer;
			}
		}
	}

	printf("Problem019: %d\n", answer);

	return 0;
}

ツェラーの公式を使っているため、main の実装は簡単なものになっています。

最後に

ツェラーの公式を調べる中で、ユリウス暦とグレゴリオ暦について理解することができました。

簡単に言うと、ユリウス暦はうるう年を4年に1回としていたため、実際の太陽年を考慮すると、うるう年が多くなりすぎます(グレゴリオ暦のうるう年については前回の記事をご覧ください)。このため16世紀末には10日ほどずれることになりました。このため、1582年10月4日(木)の翌日を10月15日(金)としたようです。

日本でも、太陰暦を太陽暦に切り替えたため、明治5年(西暦1872年)12月2日の翌日を明治6年1月1日としました(明治改暦)。

いま、このような改暦を行うと、コンピュータシステムの影響がとんでもないことになりそうです。

引き続き、Project Euler の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA