ビット演算子

(式と演算子)
https://jsprimer.net/basic/operator/

ビット演算子では、オペランドである数値を符号付き32ビット整数(0と1からなる32個のビットの集合)として扱う。
たとえば、1という数値は符号付き32ビット整数のビットでは、00000000000000000000000000000001 として表現される。わかりやすく4ビットごとに区切ると 0000_0000_0000_0000_0000_0000_0000_0001 のような32ビットの集合となる。符号付き32ビット整数では、先頭の最上位ビット(一番左のビット)は符号を表し、0の場合は正の値、1の場合は負の値であることを示している。

符号付き32ビット整数では負の数値は、2の補数形式という形式で表現される。2の補数とは、それぞれのビットを反転して1ビットを足した値となる。
たとえば、-1 という数値の符号付き32ビット整数は、次のように2の補数で求められる。

  • 10進数の1は、符号付き32ビット整数では0000_0000_0000_0000_0000_0000_0000_0001となる
  • 0000_0000_0000_0000_0000_0000_0000_0001 の各ビットを反転すると1111_1111_1111_1111_1111_1111_1111_1110 となる
  • これに1ビットを足すと 1111_1111_1111_1111_1111_1111_1111_1111 となる

これによって、-1の符号付き32ビット整数は 1111_1111_1111_1111_1111_1111_1111_1111 となる。
符号付き32ビット整数で表現できる数値の範囲は、1000_0000_0000_0000_0000_0000_0000_0000から0111_1111_1111_1111_1111_1111_1111_1111までとなる。10進数に直すと-(2^31)(2の31乗の負の数)から (2^31) – 1(2の31乗から1引いた数)までとなる。32ビットを超える数値については、32ビットをはみ出るビットが最上位(一番左)から順番に捨てられる。

ビット論理積(&)

ビット論理積演算子(&)はビットごとのAND演算した結果を返す。AND演算では、オペランドの各ビットがどちらも1の場合は1となり、それ以外の場合は0となる。
次のコードでは、10進数の15と9をAND演算している。15は、符号付き32ビット整数では0000_0000_0000_0000_0000_0000_0000_1111となる。9は、符号付き32ビット整数では0000_0000_0000_0000_0000_0000_0000_1001となる。これらをAND演算した結果は0000_0000_0000_0000_0000_0000_0000_1001となり、10進数の値である9を返す。

console.log(15 & 9); // => 9
console.log(0b1111 & 0b1001); // => 0b1001

ビット論理和(|)

ビット論理和演算子(|)はビットごとのOR演算した結果を返す。OR演算では、オペランドの各ビットがどちらか片方でも1の場合は1となり、両方とも0の場合は0となる。

console.log(15 | 9); // => 15
console.log(0b1111 | 0b1001); // => 0b1111

ビット排他的論理和(^)

ビット排他的論理和演算子(^)はビットごとのXOR演算した結果を返す。 XOR演算では、オペランドのビットが異なるなら1、両方とも同じなら0となる。

console.log(15 ^ 9); // => 6
console.log(0b1111 ^ 0b1001); // => 0b0110

ビット否定(~)

単項演算子の否定演算子(~)はオペランドの各ビットを反転した値を返す。これは1の補数として知られている値と同じものである。
次のコードでは、10進数で15を否定演算子(~)で各ビットを反転させた値を得ている。15 は0000_0000_0000_0000_0000_0000_0000_1111である。各ビットを反転させると1111_1111_1111_1111_1111_1111_1111_0000になり、10進数では-16 となる。

console.log(~15); // => -16

~xのようにxをビット否定演算子で演算した結果は、-(x + 1)となる。この性質を利用する形で、ビット否定演算子(~)はビット演算以外でも使われていることがある。

否定演算子(~)は1の補数を返すため、~(-1)は0となる。

console.log(~0); // => -1
console.log(~(-1)); // => 0

左シフト演算子(<<)

num << bit;

左シフト演算子は、数値であるnumをbitの数だけ左へシフトする。左にあふれたビットは破棄され、0のビットを右から詰める。
次のコードでは、9を2ビット分だけ左へシフトしている。

console.log(9 << 2); // => 36
console.log(0b1001 << 2); // => 0b10_0100

右シフト演算子(>>)

num >> bit;

右シフト演算子は、数値であるnumをbitの数だけ右へシフトする。右にあふれたビットは破棄され、左端のビットのコピーを左から詰める。
次のコードでは、-9を2ビット分だけ右へシフトしている。左端のビットのコピーを使うため、常に符号は維持される。

console.log((-9) >> 2); // => -3
// 1111_1111_1111_1111_1111_1111_1111_0111 >> 2
// => 1111_1111_1111_1111_1111_1111_1111_1101

ゼロ埋め右シフト演算子(>>>)

ゼロ埋め右シフト演算子は、数値であるnumをbitの数だけ右へシフトするのは右シフト演算子(>>)と同じである。異なる点としては右にあふれたビットは破棄され、0のビットを左から詰める。
次のコードでは、-9を2ビット分だけゼロ埋め右シフトしている。左端のビットは0となるため、常に正の値となる。

console.log((-9) >>> 2); // => 1073741821
// 1111_1111_1111_1111_1111_1111_1111_0111 >>> 2
// => 0011_1111_1111_1111_1111_1111_1111_1101
inserted by FC2 system