JavaScript ビット演算・ビットマスクについてまとめてみました。
2016.03.15
この記事は最終更新日から1年以上が経過しています。
最近、記事もJavaScriptも書いてないなぁ。と思ったので、なんかJavaScriptについて書きます。
選んだのが、ビット演算・ビットマスクと言う事で、全然真新しくも無く、使いどころの少ない事柄で全く申し訳ないのですが、まぁいいですよね。
まとめていないなと思ったので、また今更感たっぷりなんですがまとめてみます。
通常のWebサイトや、Webサービスを作成する際は、ほとんど使用するシーンも無く、私の経験上、ビット演算など使っていると周りから煙たがれるかと思います(笑)
本当に必要なシーンならともかく、「え、ここでいるか?」って言うのかあった事もありまして(笑)
実際、煙たがっていたのも事実です(笑)
(なんか、書けますよ。って事をアピールしたかったのでしょうね(笑))
と、ビット演算子を利用するシーンは少ない印象ではありますが、よくあるのがカラーコードを扱ったり、ゲーム制作の現場ではビットマスクなどを用いた演算を結構利用する事が多いですね。
詳細なんですが、はっきり言いまして、こちらのページにほとんど記載されていますが、
JavaScript | MDN
ビット演算子・ビットマスクって何??って方向けに分かりやすくまとめられればと思います。
ビット演算子
ビット演算子ではそのオペランドを 10 進数や 16 進数や 8 進数の数値ではなく、32 ビットの集合(0 と 1)として 扱います。
と、ありますね。
そうですね。ビット演算子は2進数の計算となります。
2進数とは「0」と「1」の2個の数字を使って数を表現します。
その2進数の計算がビット演算子となります。
演算子 | 使用方法 | 説明 |
---|---|---|
ビットごとの 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 を詰めます。 |
まるっと、引用で申し訳ないのですが、上記がビット演算子となります。
今回は、「AND」「OR」「XOR」「NOT」に注目して書いていきます。
aとbの2つの2進数をビット演算子で演算した例です。
a | b | 論理積 AND(a&b) | 論理和OR(a | b) | 排他的論理和XOR(a^b) |
---|---|---|---|---|
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
0 | 1 | 0 | 1 | 1 |
0 | 0 | 0 | 0 | 0 |
a | 論理否定NOT(~a) |
---|---|
1 | 0 |
0 | 1 |
うー。わかんないよー。って方に少し分かりやすく噛み砕いて書いていきますね。
まず、ビット演算子に入る前に、数値リテラルについて復習しておきます。
ヘキサリテラル
最先頭に『0x』 で、16 進数表記となります。
// 16 進数表記で数値を作成する var value = 0x00000112; //274
オクタルリテラル(非推奨仕様)
最先頭に『0』 で、8 進数表記となります。
// 8 進数表記で数値を作成する(非推奨) var value = 021; //17
非推奨の為、strict モードでは使用できません。
オクタルリテラル
最先頭に『0o』 で、8 進数表記となります。
// 8 進数表記で数値を作成する var value = 0o0021; //17
新仕様の為、一部ブラウザで動作。
バイナリリテラル
最先頭に『0b』 で、2 進数表記となります
// 2 進数表記で数値を作成する var value = 0b0010; //2
一部のブラウザで動作します。
論理演算子
& (ビットごとの AND)
まずは、「AND」から。
論理積ANDは、「どちらも1の場合1。それ以外0」です。
a | b | 論理積 AND(a&b) |
---|---|---|
1 | 1 | 1 |
0 | 1 | 0 |
1010 & 1100 = 1000 (2進数)
となります。
10(10進数) = 1010(2進数)
12(10進数) = 1100(2進数)
10 & 12 = 1000(2進数)= 8(10進数)
となります。
| (ビットごとの OR)
論理和OR(a | b)はどちらか、1の場合1となります。
a | b | 論理和OR(a | b) |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1010 | 0011 = 1011(2進数)
となります。
10(10進数) = 1010(2進数)
3(10進数) = 0011(2進数)
10 | 3 = 1011(2進数)= 11(10進数)
となります。
^ (ビットごとの XOR)
排他的論理和XORは「どちらか異なる場合 1となります」
a | b | 排他的論理和XOR(a^b) |
---|---|---|
1 | 1 | 0 |
1 | 0 | 1 |
1010 ^ 0011 = 1001(2進数)
となります。
10(10進数) = 1010(2進数)
3(10進数) = 0011(2進数)
10 ^ 3 = 1001(2進数)= 9(10進数)
となります。
~ (ビットごとの NOT)
最後、論理否定NOTは、「全てのビットを反転させます」
a | 論理否定NOT(~a) |
---|---|
1 | 0 |
0 | 1 |
9 (10 進数) = 1001 (2 進数)
~9 (10 進数) = 0110 (2 進数) = -10 (10 進数)
ビットマスク
ビット演算子について、ザッとではありますが、振り返ってみました。
では、「どこで使うの?」と疑問も上がってくるかと思います。
実際に使うシーンは一つの変数で、バイナリフラグとして持つ、「ビットマスク」がゲーム制作の現場で使用されたりします。
ビットマスクとは、通常「真(true)」「偽(false)」を表す bool型は2種類しかなく「真(true)1」「偽(false)0」で表現する事ができます。
この「0」「1」の1ビットの数値を用いて、1つの変数で複数のフラグを表現するのが、「ビットマスク」となります。
では、ビットマスクの定義例を。
定数名 | 2進数 | 10進数 | 16進数 | 概要 |
---|---|---|---|---|
NONE | 00000000 | 0 | 0x0000 | 何も飼っていない |
CAT | 00000001 | 1 | 0x0001 | 猫を飼っている |
DOG | 00000010 | 2 | 0x0002 | 犬を飼っている |
BIRD | 00000100 | 4 | 0x0004 | 鳥を飼っている |
このような定数が定義されていたとします。
ビットマスクに使うのは「論理積AND」と「論理和OR」となります。
ある変数に「CAT」のフラグを立てる時は、「OR」を用いてフラグをtrueにします。
man = man | CAT;
これは、以下のように記述できます。
man |= CAT;
逆にフラグが立っているか判定の場合は「AND」を用いて判定します。
if((man & CAT) != 0) { 処理.. }
猫と犬を飼っている場合のみ処理を行う場合は、
if ((man & CAT) && (man & DOG)) { 処理.. }
みたいな感じとなります。
猫か犬を飼っているビットマスク変数を作成しようとすると、
var mask = CAT | DOG;
このように、「OR演算」を用いて作成する事ができます。
ビットマスクは 0 との AND 演算により、関係のないフラグをマスクします (それゆえ、”ビットマスク” という用語になります)。
if (man & mask) { 処理.. }
と、言った感じに利用されます。
ザッとではありましたが、ビット演算子、ビットマスクに関して軽くまとめてみました。
通常のWebサイトやWebサービスではなかなか使う機会も少ないですが、覚えておいて損は無いかと思います。
(必要無いのに、むやみやたらに使うのはやめましょう(被害経験あり)(笑))
次は評価関数辺り書けて行ければと思う今日この頃です。
ではではー。