arith blog

   気ままにらくがきブログ

万年カレンダーに”なる”方法

はじめに

アニメ映画「サマーウォーズ」で、先輩の誕生日を聞いた主人公が「モジュロ演算」という計算を使って何曜日なのか即答していました。モジュロ演算とは聞き慣れない言葉ですが、一体どんな計算なのでしょうか?

というわけで、今回は「道具に頼らない」という条件で日付から曜日が分かる方法についてアレコレ考えてみました(*´ω`*)

モジュロ演算って?

調べてみたところ、「モジュロ(演算)」というのは小学校で習う「割り算で余りを出す計算」のことのようです。別の呼び方で「剰余演算」ともいいますね。
(例えば 94 で割った余り「9\div4=2\cdots1」を「9~\mathrm{mod}~4\equiv1」と書きます)

この「モジュロ」そのものは曜日を計算する専用のものではないのですが、曜日には7日で1周するという性質がありますので「ある数を7で割った余り」を曜日に対応させるという使い方で応用することができるのです。

例えばある日曜日を0日目とした場合、その日からの日数が分かれば「日数を7で割った余り」を求めることで曜日も分かります。どういうことなのか、日数を7で割った余りと曜日の対応を表にしてみました。

0 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 32 33 34
35 36 37 38 39 40 41
42 43 44 45 46 47 48
49 50 51 52 53 54 55

では、年月日から曜日を知りたい場合は一体いくつを7で割ればよいのでしょうか。有名な方法としては「ツェラーの公式」を利用するのが一般的のようです。

実は私もこのツェラーの公式とほぼ同じものを車輪の再発明していたのですが、「もっと暗算にやさしく」と考えてボツ案にしたという経緯がございます。そんな私の試行錯誤っぷりを、まずは御覧くださいませ(;´∀`)

ボツにしたアイデア集(読み飛ばしてOK)

西暦 ccyymd 日の曜日。\lfloor\cdots\rfloor は小数点以下切り捨ての記号です。
出てきた数を7で割った余り 06 が 日曜~土曜 に対応しています。

ボツ案1:2ヶ月で-2日分&補正 作戦

1 月, 2 月 は前年の 5 月, 6 月 として計算

5(cc~\mathrm{mod}~4)+\left\lfloor\frac{10yy}8\right\rfloor+(16-m)+d
(奇数月補正:3,5,7月はさらに -4、9,11月は +4 する)

月単位でみた時、連続する2ヶ月が61日となるケースが1年の内に7回あることに着目した案です。暗算に適した式である反面、謎の奇数月補正で混乱しやすいのが難点。

ボツ案2:5ヶ月で+13日分 作戦

1 月, 2 月 は前年の 13 月, 14 月 または 前年の 5 月, 6 月 として計算

d+\left(\left\lfloor\frac{26(m+1)}{10}\right\rfloor-1\right)+\left\lfloor\frac{10yy}8\right\rfloor-2(cc~\mathrm{mod}~4)

月単位でみた時、連続する5ヶ月が153日となるケースが1年の内に7回あることに着目した案です。ツェラーの公式とほとんど同形で、二桁の掛け算がネック。

ボツ案3:1ヶ月で+3日分&補正 作戦

1 月, 2 月 は前年の 13 月, 14 月 または 前年の 5 月, 6 月 として計算

5(cc~\mathrm{mod}~4)+\left\lfloor\frac{10yy}8\right\rfloor+\left(3(m\pm4)~\mathrm{mod}~8+4\right)+d
(エイプリル補正:4月はさらに +1 する)

月単位でみた時、1ヶ月が31日であるケースが1年の内に7回あることに着目した案です。良案でしたが、後述する方法のが高速だったためお蔵入り。

 

補正処理をなくそうとすると計算が大変になってしまい、バランスが難しいですね。まあ、ボツ案とはいえこれでも十分実用の範囲とは思いますので念の為(;・∀・)

20xx年12月31日

それでは、いよいよ私のアイデア最新版を紹介しましょう。
まずは、20xx年(2000年~2099年)の大晦日の曜日から(*´ω`*)

西暦の下二桁 xx 年を「4で割った商余り」に分割し、次のように計算します。

余り+[7の整数倍])-(4で割った商×2)

[7の整数倍] は(4で割った商×2)を引いて正の数になるなら何倍でもよいです。もちろん0でも!

【2018年12月31日】
 18 →「42

 (2+[7])-(4×2) = 1

この数がその年の12月31日の曜日を表しています。7で割って余りを求めてみると 0~6 が 日~土 に対応しており、この場合は 1 ですから月曜日です。

20xx年m月d日

m月d日って、m月1日の前日(前月最終日)からd日後ですよね。つまり「m月1日の前日の曜日+d」が「m月d日の曜日」を表します。というわけで、次の表を御覧ください。

3月 4月 5月 6月
2 5 0 3
7月 8月 9月 10月
5 1 4 -1
11月 12月 翌1月 翌2月
2 4 0 3

これは、各月1日の前日の曜日が大晦日の曜日と比べて何日分後ろにズレているかをまとめたものです。つまりm月d日の曜日は大晦日の曜日+ズレ日数日と言えますね。

余り+[7の整数倍])-(4で割った商×2)+ズレ日数

【2019年2月11日】←「2018年の翌2月」であることに注意
 18 →「42

 (2+[7])-(4×2)+3+11 = 15
 → 7 で割った余りは 1(月曜日)

でも、このズレ日数を知るためには表を見なければなりません。「道具に頼らない」のが目的ですが、これを暗記するのはチョット面倒そう。計算で求める方法もあるにはありますが、「パターン記憶」を利用する方法がカンタンかもしれません。

上の「パターンを見る」ボタンを押してみてください。10月の「-1」から始まってチェック柄状に 1 ずつ増えながら「0」「1」「2」…と並んでることがお分かりいただけるかと思います。最後の「4」「5」だけやや変則的ですが、これならギリ自力で表を思い出せるのではないでしょうか。

ところで、どうして3月~「翌2月」なのでしょう。1月と2月だけは前の年からみた翌年という扱いになってますよね。その理由は、平年とうるう年で2月の日数が違うためです。1月1日や2月1日から見ると、その直後の3月1日以降では曜日のズレ方に1日分の誤差が生じてしまうのでそれを回避しているってわけなんです。

【オマケ】m月のズレ日数を計算で求める方法
(翌1,翌2月 は 13, 14月 または 5, 6月 として計算してね)

\left\lfloor\frac{26(m+1)}{10}\right\rfloor-1

または

3(m\pm4)~\mathrm{mod}~8+4
 ただし4月はさらに+1します

これらはちょうど、ボツ案2とボツ案3に出てきた式ですね。

20xx年以外の12月31日

西暦の上2桁を4で割った余りによって、最後に[追加] を足してあげるだけ。それ以外は 20xx年 の時とやり方は変わりません。

余り
[追加]

余り+[7の整数倍])-4で割った商×2 +[追加]

【1957年12月31日】
 19 → 余り3 → [1]
 57 →「141

 (1+[28])-(14×2) +[1] = 2
 → 2(火曜日)

実用的には1900年代と2000年代が分かれば十分と思いますので、わざわざこの表を覚える必要もなく、「1900年代のときだけ+1する」と覚えておけば問題ないでしょう。

ちなみに紀元前 Y 年は、400 の倍数から Y-1 を引いたものを年とすればOKです。とはいえ、こちらも実用面であまり意味はないかも。。(;・∀・)

最後に

多少の練習は必要ですが、この方法に慣れれば超速で目的の曜日が分かるようになると思います。もっとお手軽な方法がありましたら是非教えてくださいませ!

もっとも、これだけスマホタブレットなどが普及している現在、それが出来たからといって宴会芸くらいしか使い道ないのですが、頭の体操や知的好奇心を満たすにはちょうどよいネタかなということで。(*´ω`*)

使用素材