わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

時刻の足し算,曜日の足し算,文字コードの足し算

  • 曜日は7進数と考えられる。
  • だから、日曜を起点に0と考えると、以下のような計算が成り立つはず。

月曜+月曜=火曜
月曜+火曜=水曜
火曜+水曜=金曜

  • 普段、曜日を計算するという概念はないので「何だこれは?」という感覚かもしれないが、
  • きっと、少年にとっての足し算の感覚とは、上記のような感覚なのかもしれない。
足し算の概念と少年の頭の中 - ザリガニが見ていた...。

駄文にゅうすつながりです.なお,内容の賛否を記したり,少年の頭の中を『線型代数』の知見でもって解明したりすることは,本エントリの意図ではありません.プログラミングでもあるんだよなあというのが,主な目的です.
曜日の足し算は,初めて見ましたが,時刻の足し算は,すぐ後で示すように,9月に書いています.
それらの足し算を説明するには,「アフィン空間」です.先月,取り上げました.

x+y=(x-a)+(y-a)+a

順序数どうしの足し算,アフィン空間,量再考

時刻の足し算を,見直してみます.

「(2時)+(3時)=(5時)」とし,他の時刻間についても同様に加法を定義したとき,日本の2時と3時は,中国では時差によって1時と2時になり,日本では(2時)+(3時)=(5時)なのが中国では(1時)+(2時)=(3時),あれっ時差が2時間になっていませんかっとのこと.

時刻+時刻,時間+時刻

時刻をアフィン空間,時間を線形空間とします.言い換えると,原点がどこであれ,時刻と時間の足し算,時刻どうしの引き算,時間どうしの足し算と引き算が行えることを前提とします.
そして,日本の0時を原点とします.細かいことを言うと,「ある日の0時」であり,時刻表記は24時間制とすることも,断っておくべきでしょうね.
このとき,上の加法の式にx=2時,y=3時,a=0時を代入すると,2時+3時=(2時−0時)+(3時−0時)+0時 と書け,あとは,=2時間+3時間+0時=5時間+0時=5時 となります.
日本の0時は,中国では前の日の23時です.これを「-1時」と表記することにして,中国の1時と2時を足すと,1時+2時=(1時−(-1時))+(2時−(1時))+(-1時)=2時間+3時間+(-1時)=5時間+(-1時)=4時 となり,日本の5時と中国の4時は同じ時刻ということで辻褄が合います.
日本では,1時+2時=(1時−0時)+(2時−0時)+0時=1時間+2時間+0時=3時間+0時=3時 です.このとき「日本では1時+2時=3時,中国では1時+2時=4時,どういうこと?」と思うのは,原点を無視しているからであって,「日本で原点となる時刻」「中国で原点となる時刻」を定めることにより,そのつど計算ができる(結果が一意に定まる)わけです*1
曜日の足し算を見ます.「月曜+月曜=火曜」について,日曜を原点(0),他の曜日を日曜からの経過日数とするよう,アフィン空間から線形空間への写像を(もちろんその逆写像も)決めれば,月曜+月曜=(月曜−日曜)+(月曜−日曜)+日曜=1+1+日曜=2+日曜=火曜 となります.「月曜+火曜=水曜」,「火曜+水曜=金曜」も同様です.
ただし,週をまたぐとき,経過日数は7で割った余りにする必要があり,例えば,金曜+土曜=11+日曜≡4+日曜=木曜 です.ここで「11≡4 (mod 7)」という,7を法とした合同式を利用しました.言葉にするなら,「日曜から11日後の曜日は,日曜から4日後の曜日と同じ」です.
そして,先週の授業で資料を配布し,今週の授業で取り上げた,「次の文字にする」のにも,同じ種類の足し算・引き算を使用していることに気づいたのでした.
具体的なコードは次のとおり(一部書き換えています).

c = (c - 'a' + 1) % 26 + 'a';

これは,char型変数cに格納されている値が'a'なら'b'に,'b'なら'c'に,…,'y'なら'z'に,そして'z'なら'a'に変更します.なお,'a'から'z'まで(文字コードが)連続していること,cがその範囲にある(範囲外なら,この代入をしない)ようif文で制限していることは,正しく動作するための前提として,授業で示しています.
この式のうち「- 'a'」と「+ 'a'」は,アフィン空間から線形空間,そしてその逆に移すための操作です.cに'c'が入っていたら,c - 'a'は2になりますが,これは,「'a'を原点として,そこから2だけ離れた文字コード」を意味します.
ここまではいいのですが,「+ 1」で引っかかります.これを,線形空間の足し算とすると違和感があります.むしろ,後者関数(successor)のようなものです.写像によって移す操作と,後者関数の適用を分けて書くと,次のようになります.

int succ1(int v)
{
  return v + 1;
}
...
  c = succ1(c - 'a') % 26 + 'a';

いや,「25の次は(26ではなく)0」というのも後者関数に取り入れて,

int succ2(int v)
{
  return (v + 1) % 26;
  /* 0≦v<26なら,以下と同じ:
  if (v == 25) {
    return 0;
  }
  return v + 1;
  */
}
...
  c = succ2(c - 'a') + 'a';

とするほうが,より自然に思えます.

*1:それでも,「2時+3時=5時」という等式の妥当性・実用性の検討は,不可欠でしょうね.常にこの等式が成り立つとするのは,賛成できません.