ビット演算子ではそのオペランドを 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 進数) を表しています:
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
逆操作アルゴリズム: マスクから真偽値の配列を作成
マスクから Booleans
の 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 2017 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 (^ ) |
(有) | (有) | (有) | (有) | (有) | (有) |
左シフト (<< ) |
(有) | (有) | (有) | (有) | (有) | (有) |
右シフト (>> ) |
(有) | (有) | (有) | (有) | (有) | (有) |
符号なし右シフト (>>> ) |
(有) | (有) | (有) | (有) | (有) | (有) |