この前、C言語でマイナスの剰余をしていて引っかかったことがあったのでメモ。
私が欲しかった処理としては、右が入力されるとキャラクタが右に動いて、左が入力されると左に動き、画面端まで到達したうえで更にはみ出す方向に入力があると、逆の画面端から現れるというもの。
その処理が、このようなごく簡単な処理で実装できると思ったが、上手く動いてくれなかった。
//マップの横幅(キャラクタの座標は0〜15) #define MAP_WIDTH 16 int main(void){ //キャラクタの座標を表す int charactor = 0; while(1){ if(右が入力された){ //ここでもし16になってしまっても charactor++; //16 % 16 = 0座標となり、期待通り charactor %= MAP_WIDTH; } if(左が入力された){ //ここでもし-1になってしまっても charactor--; //-1 % 16 = 15座標となり、期待通り……かに思えた charactor %= MAP_WIDTH; } } }
剰余のうまい使い方でこういう処理が出来ることを思いついたときは、それなりの感動があったわけだが、どうも上手く動いてくれない(ちなみに、googleで「-1 % 16」とやると、ちゃんと15と表示される)
それについて質問してみると、C99という規格が出来るまではマイナスの除算について曖昧で、処理系依存なこともあったそうだ。ところが、C99で「片方がマイナスの場合、除算結果は0方向に丸められる」と定められたため、これを実装するコンパイラに関しては、「-1 % 16」の結果は「-1」になるんだそうだ。
うーん、今回の件に関して言えば、そういう実装にして欲しくなかったなぁという感想。実際、15が結果として得られたほうが、有用性が高いと思うのは私だけか。
追記
5 / 3 = 1 ... 2 6 / 3 = 2 ... 0 2 / 5 = 0 ... 2 -1 / 16 = -1 ... 15 (除算が0方向に丸められない場合) -1 / 16 = 0 ... -1 (除算が0方向に丸められた場合)
4行目は納得できないかもしれない。しかし、検算してみるとこれの結果も正しいことが証明できる。
商 * 割る数 + 剰余 = 割られる数 1 * 3 + 2 = 5 2 * 3 + 0 = 6 0 * 5 + 2 = 2 -1 * 16 + 15 = -1 0 * 16 + (-1) = -1
ピンバック: Story of Your Life » Blog Archive » 【算術演算小話 その二】 負の剰余について