西暦1〜3年で、Go は止まり、JavaScript は NaN、PHP は空欄。Python だけが正しかった
干支は「(西暦 − 4) を 10 と 12 で割った余り」で決まります。西暦3年なら 3 − 4 = −1 なので、余りは数学では 10 で割って 9(癸)、12 で割って 11(亥)、答えは 癸亥 です。
同じ (year - 4) % 12 という1行が、4言語で4通りの結果になりました。
| 言語 | (3 - 4) % 12 | 配列の −1 番目を読むと | 返した干支 |
|---|---|---|---|
| Python | 11 | 正しく「亥」 | 癸亥(正解) |
| Go | −1 | index out of range [-1] でパニック | なし(処理が止まる) |
| JavaScript | −1 | undefined | undefined + undefined = NaN |
| PHP | −1 | 警告(Undefined array key -1)と null | 空文字 |
なぜ割れたのか
割り算の余り(%)を、負の数でどう定義するかが言語で違います。
- Python: 余りは割る数と同じ符号になる。12 で割れば必ず 0〜11
- Go・JavaScript・PHP: 余りは割られる数と同じ符号になる。−1 を 12 で割った余りは −1
この題材では、Python の「よくある書き方」がそのまま正解でした。ほかの3言語は、負の余りを配列の番号に使ったことで、それぞれの言語らしい壊れ方をしました。Go は止まり、JavaScript は黙って NaN を返し、PHP は警告を出しつつ空の答えを返しています。
西暦1〜3年は生まれ年としては現れませんが、「◯年前の干支」や紀元前をさかのぼる計算では、同じ形で負の数が入ります。
どう直したか
余りを数学の剰余(0 以上)にそろえる関数を通してから、配列の番号に使いました。
const mod = (n, m) => ((n % m) + m) % m;
仕様の元になったシルギアのツールは、最初からこの書き方で正しく計算しています。直した書き方は、西暦1〜9999年の全9,999通りで4言語とも正解と一致しました。