整数の除算とシフト演算子の仕様

C++ の除算はどうなってるんだろう…後で調べてみよう RT @rane_hs: "割り算の結果はすべて 0 方向に切り捨てる"あとでソースを探した方がいいかも知れない : プログラミング言語 C の新機能 http://seclan.dll.jp/c99d/c99d05.htm

http://twitter.com/melponn/status/5547041584

てことで気になったので調べたところ、

どうやら 0 方向に切り捨てられるらしい。

http://twitter.com/melponn/status/5547457880

ということになった。ソースは N2960 (10M PDF 注意) の 5.6.4。

For integral operands the / operator yields the algebraic quotient with any fractional part discarded;

algebraic quotient とかよく分かんないけど普通に計算したときの商って考えておくとして、最後で分数部分は捨てられるって書いてあって、注釈にも

This is often called truncation towards zero.

とか書いてあるので 0 方向に切り捨てるので間違い無さそう。
C++03 の仕様読めよとか言われそうだけどまあ一緒でしょってことで。


あと以前 id:uskz 先生に「C++ のシフト演算子Java と違って仕様が明確に決まっていない」みたいな話を聞いたのでそっちもついでに調べてみた。

E1 << E2 は E1 を E2 ビット左シフトする。空いた場所は 0 で埋められる。

http://twitter.com/melponn/status/5547679218

E1 が unsigned 型の場合、結果は E1×(2^E2)になる。signed の場合のことはどこにも書かれてない・・・

http://twitter.com/melponn/status/5547775336

E1 >> E2 は E1 を E2 ビット右シフトする。

http://twitter.com/melponn/status/5547838178

E1 が unsigned 型か signed 型でマイナスの値でない場合、結果は E1/(2^E2) になる。もし E1 が signed 型でマイナスの値の場合、結果は実装依存である。KOEEEEEEEE!!!!

http://twitter.com/melponn/status/5547866737

まあ要するにシフトするなら unsigned で扱えよ、と。

http://twitter.com/melponn/status/5547890124

ついでに該当部分の仕様も。

The value of E1 << E2 is E1 (interpreted as a bit pattern) left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 multiplied by the quantity 2 raised to the power E2, reduced modulo ULLONG_MAX+1 if E1 has type unsigned long long int, ULONG_MAX+1 if E1 has type unsigned long int, UINT_MAX+1 otherwise.
The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 divided by the quantity 2 raised to the power E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.

ということらしい。signed な値に対するシフト演算子は怖いと。


追記:
あと自分は余りの計算でマイナスの値を使った場合は環境毎に違う値を返すんじゃないかと思ってたんだけど、

(a/b)*b + a%b is equal to a.

という記述があって、a/b を普通に計算したときの値を求めて小数を常に 0 方向に丸める仕様によって a/b がどんな環境でも同じ値になりそうなので、a%b はどんな環境でも同じ値になりそうな予感がする。


追記2:
まだちゃんと確認できてないけど、なんか C++03 と C++0x で剰余の仕様がちょっと変わってる気がする。

あれ、もしかして C++0xC++03 の除算の仕様って変わってるの?とりあえずC++03のJISの方を確認してみたら負数がある場合の符号は処理系依存とか書いてる。N2960 には implementation-defined なんてのはどこにも書いてない。

http://twitter.com/melponn/status/5612846001

ということで後で調べる。