質問のタイトルが示すように、2^31 を符号付きおよび符号なしの 32 ビット整数変数に割り当てると、予期しない結果が生じます。
C++
これは、何が起こっているかを確認するために作成した短いプログラム ( ) です。
#include <cstdio>
using namespace std;
int main()
{
unsigned long long n = 1<<31;
long long n2 = 1<<31; // this works as expected
printf("%llu\n",n);
printf("%lld\n",n2);
printf("size of ULL: %d, size of LL: %d\n", sizeof(unsigned long long), sizeof(long long) );
return 0;
}
出力は次のとおりです。
MyPC / # c++ test.cpp -o test
MyPC / # ./test
18446744071562067968 <- Should be 2^31 right?
-2147483648 <- This is correct ( -2^31 because of the sign bit)
size of ULL: 8, size of LL: 8
次に、別の関数を追加p()
しました。
void p()
{
unsigned long long n = 1<<32; // since n is 8 bytes, this should be legal for any integer from 32 to 63
printf("%llu\n",n);
}
コンパイルして実行すると、これが私をさらに混乱させます:
MyPC / # c++ test.cpp -o test
test.cpp: In function ‘void p()’:
test.cpp:6:28: warning: left shift count >= width of type [enabled by default]
MyPC / # ./test
0
MyPC /
左シフト カウントが大きすぎるとコンパイラが文句を言うのはなぜですか? sizeof(unsigned long long
) は 8 を返すので、そのデータ型の最大値は 2^63-1 ではないでしょうか?
おそらく n*2 と n<<1 が常に同じように動作するとは限らないことに気がついたので、これを試しました。
void s()
{
unsigned long long n = 1;
for(int a=0;a<63;a++) n = n*2;
printf("%llu\n",n);
}
これにより、出力として2 ^ 63の正しい値が得られます9223372036854775808
(Pythonを使用して確認しました)。しかし、左のたわごとをすることの何が問題なのですか?
n による左算術シフトは、2 nを乗算することと同じです (値がオーバーフローしない場合)。
-- ウィキペディア
値はオーバーフローしていません。値が 2^63 (すべてのビットが設定されている) であるため、マイナス記号のみが表示されます。
左シフトで何が起こっているのかまだわかりません。誰か説明してもらえますか?
PS: このプログラムは、Linux Mint を実行している 32 ビット システムで実行されました (それが役立つ場合)。