剰余演算 % の符号がJavaと異なる理由
Pythonの%は除数の符号に合わせた結果を返します。Javaなど多くの言語は被除数の符号に合わせるため、負の数を扱うと結果が変わります。
なぜエラーが出ないのか
出力: 1
(エラーなし)- Pythonは何も報告しません。文法として正しいためです
出力: 1- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 x = -7 2 y = 3 3 remainder = abs(x) % y ^ 4 print(remainder)
Pythonの%は除数の符号に合わせた結果を返します。abs()で絶対値にしてから計算すると、その正しい挙動を壊してしまいます。
直し方: abs(x) % y を x % y にします。
パターン2
1 day = -3 2 remainder = abs(day) % 7 ^ 3 print(remainder)
曜日を7で割った余りで表す場合も同じです。絶対値を取ってから割ると、負の日付が表す「巻き戻り」の意味が失われます。
直し方: abs(day) % 7 を day % 7 にします。
パターン3
1 hour = -2 2 remainder = abs(hour) % 24 ^ 3 print(remainder)
24時間表記の巻き戻り計算でも同様です。Pythonの%はそのまま使えば正しく巻き戻ってくれるので、絶対値を取る必要はありません。
直し方: abs(hour) % 24 を hour % 24 にします。
パターン4
1 index = -1 2 size = 5 3 pos = abs(index) % size ^ 4 print(pos)
末尾からの位置を表す負の添字の計算でも、abs()を挟むと本来欲しい「末尾から何番目か」という値が壊れます。
直し方: abs(index) % size を index % size にします。
パターン5
1 step = -10 2 cycle = 6 3 phase = abs(step) % cycle ^ 4 print(phase)
周期的な巻き戻り計算でも同様です。絶対値を取ってから割ると、負の方向へ進んだ分の意味が失われます。
直し方: abs(step) % cycle を step % cycle にします。
よくある誤解
他言語の経験から「結果は負になるはず」と考え、abs()で絶対値に変換してから計算すると、Pythonが本来返す正しい結果を壊してしまいます。
実務での勘所
この設計にはPython特有の実用上のメリットもあります。循環的な添字計算(index % len(items))をするとき、indexが負の値になってもPythonの%は常に0以上除数未満の結果を返すため、そのままlistの添字として使える都合の良い性質があります。Javaのように%が被除数の符号に合わせる言語では、負のindexを使うと%の結果も負になってしまい、そのままでは添字として使えず(index % len + len) % lenのような補正が別途必要になります。