見出し画像

C#で学ぶ!指カレンダーの使い方~新しい手順(4/4)


日付の範囲

日付として有効な範囲はグレゴリオ暦の$${1}$$年$${1}$$月$${1}$$日から$${9999}$$年$${12}$$月$${31}$$日まで(※)です.

※:世界史において実際にグレゴリオ暦(新暦とも呼ばれる)が採用されたのは$${1582}$$年$${10}$$月$${15}$$日からです.

日付の変換

与えられた日付について, 年数を$${Y}$$, 月数を$${M}$$, 日数を$${D}$$とします. ただし, 月数が$${1}$$か$${2}$$の場合は「年数$${-1}$$」を$${Y}$$に, 「月数$${+12}$$」を$${M}$$とします.
(例)$${2000}$$年$${1}$$月$${1}$$日なら, (月数が$${1}$$なので)$${Y=2000-1=1999,M=1+12=13}$$.

手順

それでは, 手順の説明に移ります. 手順は従来の指カレンダーと同様にコードによって表すことにします.

新しい指カレンダーの手順(C#による記述):

int Year = 9999;
int Month = 12;
int Day = 31;
int number = 0;
int yubi = 0;

// Calculation for "Year".
number = 0;
while (number + 2000 <= Year) { number = number + 2000; yubi = (yubi + 0) % 7; }
while (number + 400 <= Year) { number = number + 400; yubi = (yubi + 0) % 7; }
while (number + 100 <= Year) { number = number + 100; yubi = (yubi + 5) % 7; }
while (number + 20 <= Year) { number = number + 20; yubi = (yubi + 4) % 7; }
while (number + 4 <= Year) { number = number + 4; yubi = (yubi + 5) % 7; }
while (number + 1 <= Year) { number = number + 1; yubi = (yubi + 1) % 7; }

// Calculation for "Month".
switch(Month)
{
    case 3: yubi = (yubi + 2) % 7; break;
    case 4: yubi = (yubi + 5) % 7; break;
    case 5: yubi = (yubi + 0) % 7; break;
    case 6: yubi = (yubi + 3) % 7; break;
    case 7: yubi = (yubi + 5) % 7; break;
    case 8: yubi = (yubi + 1) % 7; break;
    case 9: yubi = (yubi + 4) % 7; break;
    case 10: yubi = (yubi + 6) % 7; break;
    case 11: yubi = (yubi + 2) % 7; break;
    case 12: yubi = (yubi + 4) % 7; break;
    case 13: yubi = (yubi + 0) % 7; break;
    case 14: yubi = (yubi + 3) % 7; break;
}

// Calculation for "Day".
number = 0;
while (number + 10 <= Day) { number = number + 10; yubi = (yubi + 3) % 7; }
while (number + 5 <= Day) { number = number + 5; yubi = (yubi + 5) % 7; }
while (number + 1 <= Day) { number = number + 1; yubi = (yubi + 1) % 7; }

始めに変数を設定してからこのコードを実行してみてください. (コード内では与えられた日付が$${9999}$$年$${12}$$月$${31}$$日だったとして設定しています. )

最終的に$${yubi}$$という変数に計算結果($${0}$$から$${6}$$までの整数)が入力され, その値によって与えられた日付の曜日が分かります.

yubiと曜日の対応表

初期設定のしかた:

  • $${Y}$$,$${M}$$,$${D}$$をそれぞれ$${Year}$$, $${Month}$$, $${Day}$$に入力する($${1}$$~$${3}$$行目).

yubiの計算について

コード内で$${yubi}$$には$${0}$$から$${6}$$までの整数が入力され, 何度か更新されます. その更新する際に行っている入力や計算は, 従来の指カレンダーと同様に指を使って行います. その方法については,

を参照してください.

3つのセクションは入れ替え可能

このコードは$${Year}$$に関する計算を行う部分($${8}$$~$${14}$$行目),

$${Month}$$に関する計算を行う部分($${17}$$~$${31}$$行目),

$${Day}$$に関する計算を行う部分($${34}$$~$${37}$$行目)

という$${3}$$つのセクションがあります. コードでは$${Year}$$, $${Month}$$, $${Day}$$という順番にセクションが並んでいますが, これらの順番は入れ替え可能です. 各々ご自分が思う好きな順番で計算してください.

Yearに関する計算

$${Year}$$には$${Y}$$が入力されています. つまり$${Year}$$は日付の年数に関する数値で, $${0}$$から$${9999}$$までの整数が入ります. それに対して, $${number}$$という計算用の変数には最初に$${0}$$が入力され, この$${number}$$の値を足し算を使って徐々に増やしていくことで, 最終的に$${Year}$$と一致させるという流れになります. そして重要なポイントとしては, $${number}$$の値が更新されるごとに, 同じタイミングで$${yubi}$$という変数の値も更新されます.

$${Year}$$に関する計算と, 後述の$${Day}$$に関する計算では, while文という制御文が頻繁に使われています. というか, 最初から最後までほぼそれしか使われていません. このwhile文は, 繰り返し文の一種で, 条件が成立する間ずっとブロック内の命令を繰り返し実行するというものです.

そして, $${Year}$$に関する計算のwhile文を見てみると, そのブロック内の命令文はどれも「$${number = number + a; yubi = (yubi + b) \% 7;}$$」という形をしています.

この$${a}$$と$${b}$$の対応を表にすると次のようになります.

aとbの対応表

(例:$${9999}$$年$${12}$$月$${31}$$日の場合)
8行目:

$${number=0}$$.

9行目:

(yubiにはもともと$${5}$$行目で$${0}$$が入力されています. )

10行目:

11行目:

12行目:

13行目:

14行目:

Yearに関する計算はカスタマイズ可能

実は$${Year}$$に関する計算にあるいくつかの行はオプションであり, 実行しなくても構いません. 具体的には, $${8}$$,$${10}$$,$${11}$$,$${13}$$,$${14}$$行のみが必須で, その他の行については, 勝手に選んでコメントアウトしたとしても(つまり実行しなかったとしても)結果は同じです. ただし, そうして行を減らすとコードとしてはすっきりして記憶への負担は減る代わりに今度は計算回数が増えてしまうのであまりおすすめはできません.

矢印の行は必須(その他は実行してもしなくてもよい)

その他のTips

$${9}$$~$${10}$$行目にある$${yubi}$$を更新する式に注目すると, 値がまったく変化しないことに注目してください.

一方で$${number}$$の値に注目すると, 始めに$${0}$$が設定されて($${8}$$行目), それから$${9}$$~$${10}$$行目で条件次第で何度か値に数が加えられます. しかし, 例え数が加えられたとしてもそれはすべて$${400}$$の倍数なので, 結果的に$${number}$$には$${400}$$の倍数が格納されることになります.

さらに$${10}$$行目を終えたときには$${number ≤ Year < number + 400}$$という状態になっています. よって結論としては, $${9}$$~$${10}$$行目を終えた時点では,

  • $${yubi}$$の値は変化せず($${9}$$~$${10}$$行目を)実行する前と同じ値が入力されている.

  • $${number}$$には$${Year}$$以下で最大の$${400}$$の倍数が入力されている.

ことになります. $${400}$$の倍数は簡単に見分けることができる(※)ので, それを利用し$${9}$$~$${10}$$行目をスキップすることができます.
※:$${0}$$以上の整数$${n}$$について(十進数で表記したときに), 下二桁がいずれも$${0}$$で, 百の位から千の位までの二桁の数が$${4}$$の倍数であることが, $${n}$$が$${400}$$の倍数であるための必要十分条件です. (例)$${0}$$, $${400}$$, $${1200}$$, $${4400}$$, $${1600}$$, $${5600}$$, $${10000}$$など.

Monthに関する計算

続いて, $${Month}$$に関する計算を見ていきます. このセクションで使用されているswitch文は, 評価対象の値によって分岐する働きをします. コードだと$${Month}$$に入力されている値によって分岐するのですが, $${Month}$$には$${M}$$が入力されています. この$${M}$$は日付の月数に由来する$${3}$$から$${14}$$までの整数でした. 指カレンダーのコードではそのいずれの場合についても「$${yubi=(yubi+a) \% 7}$$」という式で対応します.

この$${Month}$$と$${a}$$の対応関係を表にすると下表のようになります.

Monthとaの対応表

この全部で$${12}$$通りの対応関係はもう記憶していただく他ありません. 始めは語呂合わせでもなんでもいいのでとにかく覚えましょう. 使っているうちにマッスルメモリーがなんとかしてくれます.

(例:$${9999}$$年$${12}$$月$${31}$$日の場合)

$${yubi=2}$$.

Dayに関する計算

最後に$${Day}$$に関する計算の説明をします. この計算は$${Year}$$に関する計算のときとやっていることは基本同じです. $${Day}$$には$${D}$$が入力されていて, $${D}$$は日付の日数で$${1}$$から$${31}$$までの整数です. それに対して計算用の変数$${number}$$に再び$${0}$$を入力しておいてから, 徐々にその$${number}$$の値を足し算で増やし$${Day}$$に近づけていって, 最終的に$${Day}$$と一致させます. ただしここでも重要なポイントとして$${number}$$の更新と同時に$${yubi}$$も更新させます.

そしてここでもおなじみのwhile文が使用されています. その命令文はどれも「$${number = number + a; yubi = (yubi + b) \% 7;}$$」という形で,

この式の$${a}$$と$${b}$$の対応を表にすると次のようになります.

aとbの対応表

(例:$${9999}$$年$${12}$$月$${31}$$日の場合)
34行目:

$${number=0}$$.

35行目:

37行目:

この記事が気に入ったらサポートをしてみませんか?