ビット演算子ではそのオペランドを 10 進数や 16 進数や 8 進数の数値ではなく、(0 や 1 が)32 ビットひと続きになったものとして扱います。例えば、10 進数の 9 の 2 進表現は 1001 です。ビット演算子はこのように 2 進表現にした上で演算を行いますが、標準の JavaScript の数値を返します。
次の表で JavaScript のビット演算子について説明します:
| 演算子 | 使用方法 | 説明 |
|---|---|---|
| ビットごとの AND | a & b |
オペランドの対応するビットがともに 1 である各ビットについて 1 を返します。 |
| ビットごとの OR | a | b |
オペランドの対応するビットがどちらかまたはともに 1 である各ビットについて 1 を返します。 |
| ビットごとの XOR | a ^ b |
オペランドの対応するビットがどちらか一方のみ 1 である各ビットについて 1 を返します。 |
| ビットごとの NOT | ~ a |
オペランドの各ビットを反転します。 |
| 左シフト | a << b |
2 進表現の a を b (< 32) ビット分だけ左にシフトします。右から 0 を詰めます。 |
| 符号を維持する右シフト | a >> b |
2 進表現の a を b (< 32) ビット分だけ右にシフトします。あふれたビットは破棄します。 |
| 0 埋め右シフト | a >>> b |
2 進表現の a を b (< 32) ビット分だけ右にシフトします。あふれたビットは破棄し、左から 0 を詰めます。 |
符号付き 32 ビット整数値
すべてのオペランドは符号付き 32 ビット演算行われ、2の補数を使って負の数を現します。またビッグエンディアン方式でメモリ配置されます。2 の補数形式とは、ある値と、その負数 (例えば 5 と -5)で例えると正数のビットをすべて反転して (正数の NOT ビット演算は1 の補数として知られています) 1 を加えたものになります。以下に整数値 314 (10 進数)と1の補数、2の補数の具体例を紹介します。
00000000000000000000000100111010
以下は ~314、すなわち 314 の 1 の補数を表しています:
11111111111111111111111011000101
最後に、以下は -314、すなわち 314 の 2 の補数を表しています:
11111111111111111111111011000110
2 の補数では、左端のビットが 0 であれば数値は正数、1 であれば数値は負数であることを保証します。よって、そのビットは符号ビットと呼ばれます。
数値 0 は、すべてのビットが 0 で構成される整数です。
0 (10 進数) = 00000000000000000000000000000000 (2 進数)
数値 -1 は、すべてのビットが 1 で構成される整数です。
-1 (10 進数) = 11111111111111111111111111111111 (2 進数)
数値 -2147483648 (16 進表記: -0x80000000) は、最初 (左端) を除きすべてのビットが 0 で構成される整数です。
-2147483648 (10 進数) = 10000000000000000000000000000000 (2 進数)
数値 2147483647 (16 進表記: 0x7fffffff) は、最初 (左端) を除きすべてのビットが 1 で構成される整数です。
2147483647 (10 進数) = 01111111111111111111111111111111 (2 進数)
数値 -2147483648 および 2147483647 は、符号付き 32 ビット数値で表現できる最小および最大の整数です。
ビットごとの論理演算子
概念的にビットごとの論理演算子は、以下のように機能します:
- オペランドは 32 ビット整数に変換され、ビット列(0 と 1)として表現されます。32 ビットを超える数値は、最上位のビットが破棄されます。例えば以下の 32 ビットを超える数値は、32 ビット整数値に変換されます:
変換前: 11100110111110100000000000000110000000000001 変換後: 10100000000000000110000000000001
- 第 1 オペランドの各ビットは第 2 オペランドの対応するビットと対にされます。第 1 ビットと第 1 ビット、 第 2 ビットと第 2 ビット、というように対にされます。
- 演算子は各ビットのペアに適用され、結果はビットごとに組み立てられます。
& (ビットごとの AND)
AND 演算は、ビットの各組で実行します。a AND b は、a と b の両方が 1 である場合にのみ 1 を出力します。AND 演算の真理値表は以下のとおりです:
| a | b | a AND b |
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
. 9 (10 進数) = 00000000000000000000000000001001 (2 進数)
14 (10 進数) = 00000000000000000000000000001110 (2 進数)
--------------------------------
14 & 9 (10 進数) = 00000000000000000000000000001000 (2 進数) = 8 (10 進数)
任意の数値 x と 0 とのビットごとの AND 演算は、0 を出力します。任意の数値 x と -1 とのビットごとの AND 演算は、x を出力します。
| (ビットごとの OR)
OR 演算は、ビットの各組で実行します。a OR b は、a か b のいずれかが 1 である場合に 1 を出力します。OR 演算の真理値表は以下のとおりです:
| a | b | a OR b |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
. 9 (10 進数) = 00000000000000000000000000001001 (2 進数)
14 (10 進数) = 00000000000000000000000000001110 (2 進数)
--------------------------------
14 | 9 (10 進数) = 00000000000000000000000000001111 (2 進数) = 15 (10 進数)
任意の数値 x と 0 とのビットごとの OR 演算は、x を出力します。任意の数値 x と -1 とのビットごとの OR 演算は、-1 を出力します。
^ (ビットごとの XOR)
XOR 演算は、ビットの各組で実行します。a XOR b は、a と b が異なる場合に 1 を出力します。XOR 演算の真理値表は以下のとおりです:
| a | b | a XOR b |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
. 9 (10 進数) = 00000000000000000000000000001001 (2 進数)
14 (10 進数) = 00000000000000000000000000001110 (2 進数)
--------------------------------
14 ^ 9 (10 進数) = 00000000000000000000000000000111 (2 進数) = 7 (10 進数)
任意の数値 x と 0 とのビットごとの XOR 演算は、x を出力します。任意の数値 x と -1 とのビットごとの XOR 演算は、~x を出力します。
~ (ビットごとの NOT)
NOT 演算は、各ビットで実行します。NOT a は、a を反転した値 (1 の補数として知られています) を出力します。NOT 演算の真理値表は以下のとおりです:
| a | NOT a |
| 0 | 1 |
| 1 | 0 |
9 (10 進数) = 00000000000000000000000000001001 (2 進数)
--------------------------------
~9 (10 進数) = 11111111111111111111111111110110 (2 進数) = -10 (10 進数)
任意の数値 x のビットごとの NOT 演算は、-(x + 1) を出力します。例えば、~5 で -6 を出力します。
indexOf を使用する例:
var str = 'rawr';
var searchFor = 'a';
// これは (-1*str.indexOf('a') <= -1) の代替表記
if (~str.indexOf(searchFor)) {
// searchFor が文字列内に存在する
} else {
// searchFor が文字列内に存在しない
}
// (~str.indexOf(searchFor)) が返す値
// r == -1
// a == -2
// w == -3
ビットシフト演算子
ビットシフト演算子は 2 つのオペランドをとります。第 1 のオペランドはシフトされる数を指定し、第 2 のオペランドは、第 1 のオペランドをシフトさせるビット数を指定します。シフト演算の方向は使用する演算子によって決まります。
シフト演算子はそのオペランドをビッグエンディアン形式の 32 ビット整数に変換し、左のオペランドと同じ型の結果を返します。右のオペランドは 32 より小さくするべきであり、そうでない場合は下位 5 ビットのみが用いられます。
<< (左シフト)
この演算子は、第 1 オペランドを指定したビット数分だけ左にシフトします。左にあふれたビットは破棄されます。0 のビットを右から詰めます。
例えば、9 << 2 の結果は 36 になります。
. 9 (10 進数): 00000000000000000000000000001001 (2 進数)
--------------------------------
9 << 2 (10 進数): 00000000000000000000000000100100 (2 進数) = 36 (10 進数)
任意の数値 x を y ビット左にシフトすると、x * 2^y になります。
>> (符号を維持する右シフト)
この演算子は、第 1 オペランドを指定したビット数分だけ右にシフトします。右にあふれたビットは破棄されます。左端のビットのコピーを左から詰めます。新たな左端のビットは従来の左端のビットと同じであることから、符号ビット (左端のビット) は変わりません。それゆえ、"符号を維持" という名称になります。
例えば、9 >> 2 の結果は 2 になります。
. 9 (10 進数): 00000000000000000000000000001001 (2 進数)
--------------------------------
9 >> 2 (10 進数): 00000000000000000000000000000010 (2 進数) = 2 (10 進数)
同様に、-9 >> 2 の結果は符号が維持されるため -3 になります:
. -9 (10 進数): 11111111111111111111111111110111 (2 進数)
--------------------------------
-9 >> 2 (10 進数): 11111111111111111111111111111101 (2 進数) = -3 (10 進数)
>>> (0 埋め右シフト)
この演算子は、第 1 オペランドを指定したビット数分だけ右にシフトします。右にあふれたビットは破棄されます。0 のビットを左から詰めます。符号ビットが 0 になりますので、結果は常に負数になりません。
負数ではない値では、0 埋め右シフトと符号を維持した右シフトは同じ結果になります。例えば、9 >>> 2 の結果は 2 になり、9 >> 2 と同じです:
. 9 (10 進数): 00000000000000000000000000001001 (2 進数)
--------------------------------
9 >>> 2 (10 進数): 00000000000000000000000000000010 (2 進数) = 2 (10 進数)
しかし、これは負数に当てはまりません。例えば、-9 >>> 2 の結果は 1073741821 であり、-9 >> 2 の結果 (-3 になります) と異なります:
. -9 (10 進数): 11111111111111111111111111110111 (2 進数)
--------------------------------
-9 >>> 2 (10 進数): 00111111111111111111111111111101 (2 進数) = 1073741821 (10 進数)
例
フラグとビットマスク
ビット論理演算子は、一連のフラグを作成、操作、あるいは読み取りによく用いられ、それらフラグはバイナリ変数のようなものです。変数は一連のフラグの代わりに用いられますが、バイナリフラグがもつメモリはとても少なく (32倍) なります。
4 つのフラグがあると仮定します:
- フラグ A: 我々は蟻の問題を抱えています
- フラグ B: 我々はコウモリを飼っています
- フラグ C: 我々は猫を飼っています
- フラグ D: 我々はアヒルを飼っています
これらのフラグは一連のビット DCBA で表されます。フラグがセットされると、それは値 1 になります。フラグがクリアされると、それは値 0 になります。変数 flags が 2 進数値 0101 であるとします:
var flags = 5; // 2 進数値 0101
この値は以下を示します:
- flag A は true (蟻の問題を抱えています);
- flag B は false (コウモリを飼っていません);
- flag C は true (猫を飼っています);
- flag D は false (アヒルを飼っていません);
ビット演算は 32 ビットで行われることから、0101 は実際 00000000000000000000000000000101 ですが、先行する 0 は意味のある情報ではないため無視できます。
ビットマスク はフラグの操作や読み取りを可能にするビット列です。一般的に、各フラグ向けの "基本" ビットマスクが定義されます:
var FLAG_A = 1; // 0001 var FLAG_B = 2; // 0010 var FLAG_C = 4; // 0100 var FLAG_D = 8; // 1000
新たなビットマスクを、これら基本ビットマスクのビット論理演算を用いて作成できます。例えば、ビットマスク 1011 は FLAG_A、FLAG_B、FLAG_D の OR 演算により作成できます:
var mask = FLAG_A | FLAG_B | FLAG_D; // 0001 | 0010 | 1000 => 1011
個々のフラグの値はビットマスクとの AND 演算によって抽出され、そのとき値 1 をもつ各ビットが対応するフラグを "抽出" します。ビットマスクは 0 との AND 演算により、関係のないフラグをマスクします (それゆえ、"ビットマスク" という用語になります)。例えば、ビットマスク 0100 はフラグ C がセットされているかの確認に用いることができます:
// 猫を飼っている場合
if (flags & FLAG_C) { // 0101 & 0100 => 0100 => true
// さまざまな処理
}
複数のフラグをセットしたビットマスクは、"いずれか" を表します。例えば、以下 2 つの例は同等です:
// コウモリか猫を飼っている場合
// (0101 & 0010) || (0101 & 0100) => 0000 || 0100 => true
if ((flags & FLAG_B) || (flags & FLAG_C)) {
// さまざまな処理
}
// コウモリか猫を飼っている場合
var mask = FLAG_B | FLAG_C; // 0010 | 0100 => 0110
if (flags & mask) { // 0101 & 0110 => 0100 => true
// さまざまな処理
}
フラグはビットマスクとの OR 演算によって設定でき、値が 1 である各々のビットが対応するフラグを、まだセットされていない場合にセットします。例えば、ビットマスク 1100 はフラグ C と D のセットに用いることができます:
// はい、猫とアヒルを飼っています var mask = FLAG_C | FLAG_D; // 0100 | 1000 => 1100 flags |= mask; // 0101 | 1100 => 1101
フラグはビットマスクとの AND 演算によってクリアでき、値が 0 である各ビットが対応するフラグを、まだクリアされていない場合にクリアします。このビットマスクは、基本ビットマスクの NOT 演算で作成されます。例えば、ビットマスク 1010 はフラグ A と C のクリアに用いることができます:
// いいえ、蟻の問題はありませんし猫を飼ってもいません var mask = ~(FLAG_A | FLAG_C); // ~0101 => 1010 flags &= mask; // 1101 & 1010 => 1000
マスクは ~FLAG_A & ~FLAG_C (ド・モルガンの法則) で作成することもできます:
// いいえ、蟻の問題はありませんし猫を飼ってもいません var mask = ~FLAG_A & ~FLAG_C; flags &= mask; // 1101 & 1010 => 1000
フラグはビットマスクとの XOR 演算によって切り替えることができ、値が 1 である各々のビットが対応するフラグを切り替えます。例えば、ビットマスク 0110 はフラグ B と C の切り替えに用いることができます:
// 以前はコウモリを飼っていませんでしたが今は飼っている、 // および以前飼っていたコウモリとお別れした、 // また猫にも同じことが起きた場合 var mask = FLAG_B | FLAG_C; flags = flags ^ mask; // 1100 ^ 0110 => 1010
最後に、NOT 演算でフラグを反転することができます:
// パラレルワールドに入りました…… flags = ~flags; // ~1010 => 0101
変換用コード部品
2 進数の String を 10 進数の Number に変換します:
var sBinString = "1011"; var nMyNumber = parseInt(sBinString, 2); alert(nMyNumber); // 11 と表示、すなわち 1011
10 進数の Number を 2 進数の String に変換します:
var nMyNumber = 11; var sBinString = nMyNumber.toString(2); alert(sBinString); // 1011 と表示、すなわち 11
マスク作成の自動化
いくつかの Boolean から多くのマスクを作成しなければならない場合に、この作業を自動化できます:
function createMask () {
var nMask = 0, nFlag = 0, nLen = arguments.length > 32 ? 32 : arguments.length;
for (nFlag; nFlag < nLen; nMask |= arguments[nFlag] << nFlag++);
return nMask;
}
var mask1 = createMask(true, true, false, true); // 11、すなわち1011
var mask2 = createMask(false, false, true); // 4、すなわち 0100
var mask3 = createMask(true); // 1、すなわち 0001
// etc.
alert(mask1); // 11 と表示、すなわち 1011
逆操作アルゴリズム: マスクから真偽値の配列を作成
マスクから Boolean の Array を作成したい場合、以下のコードを用いることができます:
function arrayFromMask (nMask) {
// nMask は -2147483648 から 2147483647 の間でなければならない
if (nMask > 0x7fffffff || nMask < -0x80000000) {
throw new TypeError("arrayFromMask - out of range");
}
for (var nShifted = nMask, aFromMask = []; nShifted;
aFromMask.push(Boolean(nShifted & 1)), nShifted >>>= 1);
return aFromMask;
}
var array1 = arrayFromMask(11);
var array2 = arrayFromMask(4);
var array3 = arrayFromMask(1);
alert("[" + array1.join(", ") + "]");
// "[true, true, false, true]" と表示、すなわち 11 および 1011
両方のアルゴリズムを同時に検証できます。
var nTest = 19; // マスク var nResult = createMask.apply(this, arrayFromMask(nTest)); alert(nResult); // 19
(Number.toString(2) メソッドがありますので) 教育的な目的のみになりますが、Boolean の Array ではなく Number の 2 進表記を含む String を作成するためにarrayFromMask アルゴリズムがどのように操作しているかを示します:
function createBinaryString (nMask) {
// nMask は -2147483648 から 2147483647 の間でなければならない
for (var nFlag = 0, nShifted = nMask, sMask = ""; nFlag < 32;
nFlag++, sMask += String(nShifted >>> 31), nShifted <<= 1);
return sMask;
}
var string1 = createBinaryString(11);
var string2 = createBinaryString(4);
var string3 = createBinaryString(1);
alert(string1);
// 00000000000000000000000000001011 と表示、すなわち 11
仕様
| 仕様書 | 策定状況 | コメント |
|---|---|---|
| ECMAScript 1st Edition (ECMA-262) | 標準 | 最初期の定義 |
| ECMAScript 5.1 (ECMA-262) | 標準 | 仕様書内のいくつかのセクションで定義: Bitwise NOT operator, Bitwise shift operators, Binary bitwise operators |
| ECMAScript 2015 (6th Edition, ECMA-262) | 標準 | 仕様書内のいくつかのセクションで定義: Bitwise NOT operator, Bitwise shift operators, Binary bitwise operators |
| ECMAScript Latest Draft (ECMA-262) | ドラフト | 仕様書内のいくつかのセクションで定義: Bitwise NOT operator, Bitwise shift operators, Binary bitwise operators |
ブラウザ実装状況
| 機能 | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
|---|---|---|---|---|---|
ビットごとの NOT (~) |
(有) | (有) | (有) | (有) | (有) |
ビットごとの AND (&) |
(有) | (有) | (有) | (有) | (有) |
ビットごとの OR (|) |
(有) | (有) | (有) | (有) | (有) |
ビットごとの XOR (^) |
(有) | (有) | (有) | (有) | (有) |
左シフト (<<) |
(有) | (有) | (有) | (有) | (有) |
右シフト (>>) |
(有) | (有) | (有) | (有) | (有) |
符号なし右シフト (>>>) |
(有) | (有) | (有) | (有) | (有) |
| 機能 | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
|---|---|---|---|---|---|---|
ビットごとの NOT (~) |
(有) | (有) | (有) | (有) | (有) | (有) |
ビットごとの AND (&) |
(有) | (有) | (有) | (有) | (有) | (有) |
ビットごとの OR (|) |
(有) | (有) | (有) | (有) | (有) | (有) |
ビットごとの XOR (^) |
(有) | (有) | (有) | (有) | (有) | (有) |
左シフト (<<) |
(有) | (有) | (有) | (有) | (有) | (有) |
右シフト (>>) |
(有) | (有) | (有) | (有) | (有) | (有) |
符号なし右シフト (>>>) |
(有) | (有) | (有) | (有) | (有) | (有) |