2008-09-02

long longの左シフト

コンパイル時に整数型のビット数を得るテンプレートを試していて、(long long)(1ll << 64)が0にならないことに気が付いた。しかも、4294967296とかいう妙な値。

そんなわけで、検証プログラム。
#include <iostream>
int main(int argc, char *argv[]) {
signed long long sll = 1;
unsigned long long ull = 1;
for(int i = 30; i < 70; i++) {
std::cout << "1ll<<" << i << " = " << (sll << i)
<< "\t1ull<<" << i << " = " << (ull << i)
<< std::endl;
}
return 0;
}


Sun C++でコンパイルして実行してみると

1ll<<60 = 1152921504606846976 1ull<<60 = 1152921504606846976
1ll<<61 = 2305843009213693952 1ull<<61 = 2305843009213693952
1ll<<62 = 4611686018427387904 1ull<<62 = 4611686018427387904
1ll<<63 = -9223372036854775808 1ull<<63 = 9223372036854775808
1ll<<64 = 4294967296 1ull<<64 = 4294967296
1ll<<65 = 8589934592 1ull<<65 = 8589934592
1ll<<66 = 17179869184 1ull<<66 = 17179869184
1ll<<67 = 34359738368 1ull<<67 = 34359738368
1ll<<68 = 68719476736 1ull<<68 = 68719476736
1ll<<69 = 137438953472 1ull<<69 = 137438953472


g++でコンパイルして実行してみると
1ll<<60 = 1152921504606846976     1ull<<60 = 1152921504606846976
1ll<<61 = 2305843009213693952 1ull<<61 = 2305843009213693952
1ll<<62 = 4611686018427387904 1ull<<62 = 4611686018427387904
1ll<<63 = -9223372036854775808 1ull<<63 = 9223372036854775808
1ll<<64 = 1 1ull<<64 = 1
1ll<<65 = 2 1ull<<65 = 2
1ll<<66 = 4 1ull<<66 = 4
1ll<<67 = 8 1ull<<67 = 8
1ll<<68 = 16 1ull<<68 = 16
1ll<<69 = 32 1ull<<69 = 32
CPUはいずれもAMD Opteron。コンパイラのバージョンは

CC: Sun C++ 5.7 Patch 117831-02 2005/03/30
g++ (GCC) 3.4.3 (csl-sol210-3_4-branch+sol_rpath)

まあ、ビット幅を越えてシフトした場合の振る舞いは未定義だった気がするので、その意味ではおかしくはない。けど、コンパイラによって振る舞いが違うってのはちょっと意外だったなあ。

けど、ビット幅Nの型Xに対して常に(X)(X(1)<<N)==0が成立するとばかり思い込んでいたので、ちょっと期待が外れてしまったりして。

0 件のコメント: