C++ の除算・剰余算

C++ での、負の整数の除算・剰余算について考察してみました。

 

Python の場合

Python で次のコードを実行してみてください。

結果はこうなります。「-5//3= -2」のあたり、直感的には少し違和感を感じる人もいるかも知れません。

-5 〜 5 の範囲で結果を一覧にしてみるとこうなります。負の数の除算・剰余算が上のような結果になった理由がわかると思います。

i -5 -4 -3 -2 -1 0 1 2 3 4 5
i//3 -2 -2 -1 -1 -1 0 0 0 1 1 1
i%3 1 2 0 1 2 0 1 2 0 1 2

 

 

 

 

 

C++ の場合

C++ で次のコードを実行してみてください。main() 関数等は省略してあります。

gcc 13.2.0 の場合の結果はこうなります。直感的にはこちらのほうが合っているように思うかもしれません。

ところが、-5 〜 5 の範囲で結果を一覧にしてみるとこうなります。

i -5 -4 -3 -2 -1 0 1 2 3 4 5
i/3 -1 -1 -1 0 0 0 0 0 1 1 1
i%3 -2 -1 0 -2 -1 0 1 2 0 1 2

 

 

 

 

 

i=0 の前後で除算・剰余算の振る舞いが不自然になっていて、正・負によって計算結果に連続性がありません。そもそもC言語の言語仕様では負数の除算についての定義が無く、実装依存とされてきた歴史からこのようになっています。現実には上のような振る舞いが C/C++言語の標準になっているようですが、連続した数列を扱うときに正・負で場合分けする必要が出てきたり、面倒なことが起こります。

 

マクロ

対策として、Python と同じふるまいになるようにマクロを作りました。

このマクロを使って試してみましょう。

結果は下のようになり、Python と同じ振る舞いになりました。

i -5 -4 -3 -2 -1 0 1 2 3 4 5
i/3 -2 -2 -1 -1 -1 0 0 0 1 1 1
i%3 1 2 0 1 2 0 1 2 0 1 2

 

 

 

 

 

除算については floor() 関数などもあるので、別の良い方法もあるかもしれません。

 

例題

AtCoder の ABC334 のB問題を解いてみてください。解説動画では正・負を考慮せずに済むように「座標系をずらす」工夫をして正答していますが、pydiv()・pymod() マクロを使えば Python の解と同じように単純に書くことができます。

B - Christmas Trees
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.