JavaScript で 2^32
の値が必要になりました。そこで、1 << 32
を計算したところ、1
になってしまいました。試しに 1 << 31
を計算してみると、-2147483648
と負の値が返ることがわかりました。
以下のコードを書いてみると、1 << 30
までは期待通りの結果が得られているようですが、1 << 30
より大きい値は変な結果になってしまいました。
for (let i = 1; i <= 32; i++) {
console.log(`1 << ${i}: ${1 << i}`);
}
console.log("1 << 32 << 32 << 32 << 32:", 1 << 32 << 32 << 32 << 32);
1 << 1: 2
1 << 2: 4
1 << 3: 8
1 << 4: 16
1 << 5: 32
1 << 6: 64
1 << 7: 128
1 << 8: 256
1 << 9: 512
1 << 10: 1024
1 << 11: 2048
1 << 12: 4096
1 << 13: 8192
1 << 14: 16384
1 << 15: 32768
1 << 16: 65536
1 << 17: 131072
1 << 18: 262144
1 << 19: 524288
1 << 20: 1048576
1 << 21: 2097152
1 << 22: 4194304
1 << 23: 8388608
1 << 24: 16777216
1 << 25: 33554432
1 << 26: 67108864
1 << 27: 134217728
1 << 28: 268435456
1 << 29: 536870912
1 << 30: 1073741824
1 << 31: -2147483648
1 << 32: 1
1 << 32 << 32 << 32 << 32: 1
原因
JavaScript ではビット演算は符号付き 32 ビット演算で行われます。
1 << 30
は
1 << 30 = 0b010000000000000000000000000000000
であり、 2147483648
と解釈されますが、1 << 31
は
1 << 31 = 0b100000000000000000000000000000000
となります。ここで、負の値は 2 の補数形式で表現されることに注意しましょう。最上位ビットが 1 のときは、負の値であることを表します。よって、 1 << 31
は -2147483648
と解釈されます。また、ビット演算は 31 ビットシフトまでしかサポートされていないようです。そのため、1 << 32
も正しく計算できませんでした。
ビット演算子 - JavaScript | MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators
JavaScript の数値型は大きな値も保持できる 1 ので適当にビットシフトしても大丈夫だろうと考えていましたが、大丈夫ではありませんでした...。
対策
べき乗演算子 **
を使いましょう。2 ** 32
(1 << 32
) も正しく計算できます。
for (let i = 1; i <= 32; i++) {
console.log(`2 ** ${i}: ${2 ** i}`);
}
2 ** 1: 2
2 ** 2: 4
2 ** 3: 8
2 ** 4: 16
2 ** 5: 32
2 ** 6: 64
2 ** 7: 128
2 ** 8: 256
2 ** 9: 512
2 ** 10: 1024
2 ** 11: 2048
2 ** 12: 4096
2 ** 13: 8192
2 ** 14: 16384
2 ** 15: 32768
2 ** 16: 65536
2 ** 17: 131072
2 ** 18: 262144
2 ** 19: 524288
2 ** 20: 1048576
2 ** 21: 2097152
2 ** 22: 4194304
2 ** 23: 8388608
2 ** 24: 16777216
2 ** 25: 33554432
2 ** 26: 67108864
2 ** 27: 134217728
2 ** 28: 268435456
2 ** 29: 536870912
2 ** 30: 1073741824
2 ** 31: 2147483648
2 ** 32: 4294967296
C++ では?
ちなみに、C++ でも試したのですが、1 << 31
は JavaScript と同様に -2147483648
になってしまいます!
#include <iostream>
int main()
{
long long i = 1 << 31;
std::cout << i << std::endl;
}
-2147483648
これは整数リテラル 1
が int
型であり、32 ビット符号付き整数型のためです。きちんと long long
型であることを明示しましょう。
#include <iostream>
int main()
{
long long i = 1 << 31;
std::cout << i << std::endl;
long long j = 1L << 31;
std::cout << j << std::endl;
}
-2147483648
2147483648