はじめに:ビット演算は「試験だけの知識」ではない
ビット演算と聞くと、少し難しそうに感じるかもしれません。
基本情報技術者試験では、AND、OR、XOR、シフト演算などが出題されます。しかし、普段JavaScriptでWebアプリケーションを作っていると、これらを直接書く機会はあまり多くありません。
そのため、「試験には出るけれど、実務ではあまり使わない知識」と思われがちです。
しかし、ビット演算はコンピュータがデータをどのように扱っているのかを理解するうえで、とても重要な考え方です。
たとえば、権限管理、フラグ管理、画像や色の処理、バイナリデータの扱いなどでは、ビット単位の考え方が登場します。たとえ日常的にビット演算子を書かなくても、その仕組みを知っていると、低レイヤーの処理やライブラリの内部実装を理解しやすくなります。
この記事では、JavaScriptのサンプルコードを使いながら、ビット演算の基本を確認していきます。
難しい数式を暗記するのではなく、2進数に直して、1ビットずつ見ていくことを意識すれば、ビット演算はそれほど怖いものではありません。
まずは、ビット演算が「2進数の各桁に対する計算」であることから理解していきましょう。
ビット演算とは
ビット演算とは、数値を2進数として見たときに、各桁のビットに対して行う演算のことです。
コンピュータの内部では、数値や文字、画像などのデータは最終的に0と1の組み合わせで扱われます。この0または1の最小単位を「ビット」と呼びます。
たとえば、10進数の 5 は2進数では次のように表せます。
const value = 5;
console.log(value.toString(2)); // "101"見やすく4桁で表すと、5 は 0101 です。
10進数: 5
2進数 : 0101同じように、10進数の 3 は2進数では 0011 と表せます。
10進数: 3
2進数 : 0011通常の足し算や引き算では、数値全体をまとめて計算します。一方で、ビット演算では、2進数の各桁を1つずつ見て計算します。
たとえば、5 と 3 をビット単位で並べると、次のようになります。
0101 // 5
0011 // 3ここで、各桁に対して「両方が1なら1」「どちらかが1なら1」「片方だけが1なら1」といったルールを適用するのがビット演算です。
JavaScriptでは、ビット演算を行うために &、|、^、~、<<、>>、>>> といった演算子が用意されています。
たとえば、& はAND演算を表します。
const result = 5 & 3;
console.log(result); // 1これは、5 と 3 を2進数として見たときに、各桁で「両方が1のところだけを1にする」計算です。
0101 // 5
0011 // 3
----
0001 // 1このように、ビット演算では10進数のまま結果だけを見ると少しわかりづらいですが、2進数に直して1桁ずつ確認すると理解しやすくなります。
基本情報技術者試験でも、ビット演算の問題は暗記だけで解くよりも、2進数に変換して各桁を追うことが重要です。
次の章では、JavaScriptで使えるビット演算子を一覧で確認し、その後、AND、OR、XORといった代表的な演算を順番に見ていきます。
JavaScriptで使えるビット演算子一覧
JavaScriptには、ビット演算を行うための演算子がいくつか用意されています。
代表的なビット演算子は次のとおりです。
| 演算子 | 名前 | 意味 |
|---|---|---|
& | AND演算 | 両方のビットが1なら1 |
| | OR演算 | どちらかのビットが1なら1 |
^ | XOR演算 | 片方だけのビットが1なら1 |
~ | NOT演算 | ビットを反転する |
<< | 左シフト | ビットを左にずらす |
>> | 符号付き右シフト | 符号を保ったまま右にずらす |
>>> | ゼロ埋め右シフト | 左側を0で埋めて右にずらす |
たとえば、AND演算を行う場合は & を使います。
const result = 5 & 3;
console.log(result); // 1
このように、通常の四則演算で使う + や - と同じように、数値と数値の間にビット演算子を書きます。
ただし、ビット演算では計算の見方が少し異なります。
5 & 3
という式は、10進数の 5 と 3 をそのまま計算しているように見えますが、実際には内部的に2進数のビットとして扱われます。
0101 // 5
0011 // 3
----
0001 // 1
そのため、ビット演算を理解するときは、10進数の結果だけを見るのではなく、2進数に直して各桁を確認することが大切です。
また、JavaScriptのビット演算には注意点があります。
JavaScriptの数値は通常、Number 型として扱われますが、ビット演算を行うときは32ビット整数として処理されます。そのため、小数を含む値や大きすぎる整数に対してビット演算を使う場合は、通常の数値計算とは違った結果になることがあります。
この記事では、まず基本を理解するために、5 や 3 のような小さな整数を使って説明していきます。
次の章からは、AND、OR、XOR、NOT、シフト演算を順番に見ていきましょう。
AND / OR / XORを理解する
ここからは、代表的なビット演算であるAND、OR、XORを順番に見ていきます。
この3つは、基本情報技術者試験でもよく登場する重要な演算です。最初は記号だけを見るとわかりにくいかもしれませんが、2進数に直して1桁ずつ確認すると理解しやすくなります。
AND演算:両方が1のビットだけ残す
AND演算は、2つのビットを比べて、両方が 1 の場合だけ 1 になります。
JavaScriptでは & を使います。
const result = 5 & 3;
console.log(result); // 1
10進数の 5 と 3 を2進数で表すと、次のようになります。
0101 // 5
0011 // 3
----
0001 // 1
右から1桁ずつ見ると、両方が 1 になっているのは一番右のビットだけです。
そのため、結果は 0001、つまり10進数では 1 になります。
AND演算は、「必要なビットだけを取り出す」処理によく使われます。
たとえば、権限や設定をビットで管理している場合に、特定のフラグが立っているかを確認できます。
const READ = 1; // 0001
const WRITE = 2; // 0010
const permission = READ | WRITE; // 0011
const canRead = (permission & READ) !== 0;
console.log(canRead); // true
この例では、permission に READ のビットが含まれているかを & で確認しています。
OR演算:どちらかが1なら1にする
OR演算は、2つのビットを比べて、どちらか一方でも 1 なら 1 になります。
JavaScriptでは | を使います。
const result = 5 | 3;
console.log(result); // 7
2進数で見ると、次のようになります。
0101 // 5
0011 // 3
----
0111 // 7
各桁を見て、どちらかに 1 があれば結果は 1 になります。
そのため、結果は 0111、つまり10進数では 7 です。
OR演算は、「フラグを追加する」処理に使いやすい演算です。
const READ = 1; // 0001
const WRITE = 2; // 0010
const DELETE = 4; // 0100
let permission = READ; // 0001
permission = permission | WRITE; // 0011
console.log(permission); // 3
この例では、最初に READ だけを持っていた permission に、WRITE の権限を追加しています。
実務のコードでは、フラグ管理や設定値の組み合わせを表現するときに、この考え方が使われることがあります。
XOR演算:片方だけが1なら1にする
XOR演算は、2つのビットを比べて、片方だけが 1 の場合に 1 になります。
JavaScriptでは ^ を使います。
const result = 5 ^ 3;
console.log(result); // 6
2進数で見ると、次のようになります。
0101 // 5
0011 // 3
----
0110 // 6
XORは、「同じなら0、違えば1」と考えると理解しやすいです。
たとえば、一番右のビットはどちらも 1 なので、結果は 0 になります。右から2番目のビットは 0 と 1 で異なるため、結果は 1 になります。
XOR演算は、ANDやORに比べると日常のWeb開発で直接使う機会は少ないかもしれません。
ただし、ビットの切り替えや、差分の検出、簡単な暗号化の考え方などにつながる重要な演算です。
たとえば、同じ値で2回XORを行うと元に戻る、という特徴があります。
const value = 5;
const key = 3;
const encoded = value ^ key;
const decoded = encoded ^ key;
console.log(encoded); // 6
console.log(decoded); // 5
この性質は、XORの大きな特徴です。
もちろん、実際の暗号化ではこのような単純な処理だけでは不十分ですが、「同じ操作をもう一度行うと元に戻る」という考え方を理解する例としては役立ちます。
AND、OR、XORは、それぞれ次のように整理できます。
| 演算 | 条件 | 使いどころの例 |
|---|---|---|
| AND | 両方が1なら1 | 特定のビットを取り出す |
| OR | どちらかが1なら1 | フラグを追加する |
| XOR | 片方だけが1なら1 | ビットの切り替え、差分の検出 |
ビット演算では、10進数の結果だけを見ると直感的にわかりにくいことがあります。
迷ったときは、数値を2進数に直して、各桁を1つずつ確認するのが基本です。
NOT / シフト演算を理解する
AND、OR、XORは、2つの値を比べてビットごとに計算する演算でした。
一方、NOT演算やシフト演算は、1つの値に対してビットを反転したり、左右にずらしたりする演算です。
ここでは、JavaScriptでのNOT演算とシフト演算を順番に見ていきましょう。
NOT演算:ビットを反転する
NOT演算は、ビットの 0 と 1 を反転する演算です。
JavaScriptでは ~ を使います。
const result = ~5;
console.log(result); // -6
ここで、5 のビットを反転するなら、結果は単純に 0101 が 1010 になって 10 になるのではないか、と思うかもしれません。
しかし、JavaScriptのビット演算では、数値は32ビットの符号付き整数として扱われます。
つまり、5 は実際には次のような32ビットの値として見られます。
00000000000000000000000000000101
これをNOT演算で反転すると、次のようになります。
11111111111111111111111111111010
左端のビットが 1 になっているため、これは負の数として扱われます。
JavaScriptでは、~x の結果は -(x + 1) と考えると理解しやすいです。
console.log(~5); // -6
console.log(~10); // -11
console.log(~0); // -1
なぜこのような結果になるのかを深く理解するには、「2の補数」という負の数の表現方法が関係します。
基本情報技術者試験でも2の補数は重要ですが、ここではまず「JavaScriptのビット演算では32ビット整数として扱われる」「NOT演算は単純な見た目よりも結果がわかりにくい」という点を押さえておきましょう。
左シフト:ビットを左にずらす
左シフトは、ビットを指定した数だけ左にずらす演算です。
JavaScriptでは << を使います。
const result = 3 << 1;
console.log(result); // 6
10進数の 3 は、2進数では 0011 です。
0011 // 3
これを左に1ビットずらすと、次のようになります。
0110 // 6
結果は 6 です。
左に1ビットずらすと、値はおおよそ2倍になります。
console.log(3 << 1); // 6
console.log(3 << 2); // 12
console.log(3 << 3); // 24
3 << 2 は、3を左に2ビットずらすという意味です。左に2ビットずらすと、2倍を2回行うため、結果は4倍になります。
3 << 1 // 3 * 2 = 6
3 << 2 // 3 * 4 = 12
3 << 3 // 3 * 8 = 24
このように、左シフトは「2の倍数をかける処理」として理解できます。
ただし、実務のJavaScriptで単純な掛け算の代わりにシフト演算を使う必要は、ほとんどありません。読みやすさを考えると、通常は * 2 や * 4 と書いた方が意図が伝わりやすいです。
右シフト:ビットを右にずらす
右シフトは、ビットを指定した数だけ右にずらす演算です。
JavaScriptでは、主に >> と >>> の2種類があります。
まずは、符号付き右シフトである >> を見てみましょう。
const result = 8 >> 1;
console.log(result); // 4
10進数の 8 は、2進数では 1000 です。
1000 // 8
これを右に1ビットずらすと、次のようになります。
0100 // 4
結果は 4 です。
右に1ビットずらすと、値はおおよそ2で割った結果になります。
console.log(8 >> 1); // 4
console.log(8 >> 2); // 2
console.log(8 >> 3); // 1
整数の範囲では、右シフトは「2で割る処理」に近いと考えられます。
ただし、小数は表現されません。
console.log(7 >> 1); // 3
7 / 2 は 3.5 ですが、7 >> 1 の結果は 3 です。
このように、右シフトでは小数部分が切り捨てられるような結果になります。
>> と >>> の違い
JavaScriptには、右シフトとして >> と >>> の2種類があります。
違いがわかりやすく出るのは、負の数を扱う場合です。
console.log(-8 >> 1); // -4
console.log(-8 >>> 1); // 2147483644
>> は符号付き右シフトです。
符号を保ったまま右にずらすため、負の数は負の数のまま扱われます。
一方、>>> はゼロ埋め右シフトです。
左側を 0 で埋めながら右にずらすため、負の数に対して使うと大きな正の数になることがあります。
最初のうちは、次のように整理しておくとよいでしょう。
| 演算子 | 名前 | 特徴 |
|---|---|---|
>> | 符号付き右シフト | 符号を保って右にずらす |
>>> | ゼロ埋め右シフト | 左側を0で埋めて右にずらす |
基本情報技術者試験では、シフト演算そのものの理解が問われることが多いです。一方、JavaScriptでコードを書く場合は、>> と >>> の違いも押さえておくと、言語仕様に踏み込んだ理解につながります。
NOT演算とシフト演算は、AND、OR、XORに比べると少しクセがあります。
特にJavaScriptでは、ビット演算時に32ビット整数として扱われるため、通常の数値計算とは異なる結果になることがあります。
まずは、次のポイントを押さえておきましょう。
| 演算 | 意味 | 覚え方 |
|---|---|---|
~ | ビットを反転する | ~x は -(x + 1) |
<< | 左にずらす | 2倍、4倍、8倍のイメージ |
>> | 右にずらす | 符号を保って2で割るイメージ |
>>> | 右にずらす | 左側を0で埋める |
次の章では、ここまで学んだビット演算が、実務のどのような場面で役立つのかを見ていきます。
実務での使いどころ
ここまで、AND、OR、XOR、NOT、シフト演算といったビット演算を見てきました。
では、これらの知識はWeb開発の実務でどのように役立つのでしょうか。
正直に言うと、一般的なWebアプリケーション開発で、ビット演算を毎日のように書くことは多くありません。
フォーム処理、API通信、画面表示、データベース操作などでは、ビット演算よりも文字列、配列、オブジェクト、SQLなどを扱う場面の方が多いでしょう。
それでも、ビット演算の考え方を知っていると、コンピュータがデータをどのように扱っているのかを理解しやすくなります。
代表的な使いどころの1つが、フラグ管理です。
たとえば、ユーザーの権限を次のようにビットで表すことができます。
const READ = 1; // 0001
const WRITE = 2; // 0010
const DELETE = 4; // 0100
const permission = READ | WRITE;
const canRead = (permission & READ) !== 0;
const canWrite = (permission & WRITE) !== 0;
const canDelete = (permission & DELETE) !== 0;
console.log(canRead); // true
console.log(canWrite); // true
console.log(canDelete); // false
この例では、READ、WRITE、DELETE という権限を、それぞれ別のビットで表しています。
READ | WRITE とすることで、読み取り権限と書き込み権限を1つの数値にまとめています。
そして、permission & READ のようにAND演算を使うことで、特定の権限が含まれているかを確認できます。
もちろん、実際のWebアプリケーションでは、権限を文字列や配列、ロール名で管理する方が読みやすい場合も多いです。
const permissions = ["read", "write"];
const canRead = permissions.includes("read");
console.log(canRead); // true
そのため、何でもビット演算で書けばよいわけではありません。
大切なのは、「複数の状態を1つの数値にまとめる考え方」があると知っておくことです。
ビット演算は、他にも画像処理や色の操作、バイナリデータの解析、通信プロトコルの理解などで登場します。
たとえば、色を表す値は、赤、緑、青の情報をビット単位で持っていることがあります。
const color = 0xff3366;
const red = (color >> 16) & 0xff;
const green = (color >> 8) & 0xff;
const blue = color & 0xff;
console.log(red); // 255
console.log(green); // 51
console.log(blue); // 102
この例では、0xff3366 という色の値から、赤、緑、青の成分を取り出しています。
>> で必要な位置までビットをずらし、& 0xff で下位8ビットだけを取り出しています。
このような処理は、普段のWeb制作ではライブラリが隠してくれていることも多いです。
しかし、Canvas、画像処理、WebGL、バイナリファイルの読み取りなど、少し低レイヤー寄りの処理に踏み込むと、ビット演算の知識が役立ちます。
また、基本情報技術者試験では、ビット演算そのものが問題として出題されます。
実務で頻繁に書かないとしても、ビット演算を理解することは、コンピュータの内部表現を理解するための良い入口になります。
「試験のためだけに覚える」のではなく、「データは最終的に0と1で扱われている」という感覚を身につけるための知識として捉えると、学ぶ意味が見えやすくなるはずです。
基本情報技術者試験での出題ポイント
ビット演算は、基本情報技術者試験でもよく問われるテーマです。
特に重要なのは、演算子の記号を暗記することよりも、2進数に直して1ビットずつ結果を追えるようになることです。
たとえば、次のような式が出てきたとします。
5 & 3
10進数のまま見ると、なぜ結果が 1 になるのか少しわかりにくいかもしれません。
しかし、2進数に直すと考えやすくなります。
0101 // 5
0011 // 3
----
0001 // 1
このように、各桁を順番に確認すれば、AND演算の結果を落ち着いて求めることができます。
試験では、AND、OR、XORの結果を求める問題だけでなく、マスク処理やシフト演算が絡む問題も出題されます。
マスク処理とは、特定のビットだけを取り出したり、不要なビットを無視したりする考え方です。
たとえば、下位4ビットだけを取り出したい場合は、1111 にあたる値でAND演算を行います。
const value = 0b10101101;
const lower4Bits = value & 0b00001111;
console.log(lower4Bits.toString(2)); // "1101"
この例では、0b00001111 を使って、下位4ビットだけを残しています。
10101101
00001111
--------
00001101
基本情報技術者試験では、このように「どのビットを残したいのか」「どのビットを0にしたいのか」を読み取る力が大切です。
シフト演算については、左シフトが2倍、4倍、8倍のような計算に対応し、右シフトが2で割るような計算に対応する点を押さえておきましょう。
console.log(3 << 1); // 6
console.log(3 << 2); // 12
console.log(8 >> 1); // 4
console.log(8 >> 2); // 2
ただし、JavaScriptではビット演算時に32ビット整数として扱われる点や、>> と >>> の違いなど、言語特有の注意点もあります。
試験対策としては、まずは次のポイントを押さえておくとよいでしょう。
| 項目 | 押さえるポイント |
|---|---|
| AND | 両方が1なら1。特定のビットを取り出す |
| OR | どちらかが1なら1。フラグを立てる |
| XOR | 片方だけが1なら1。同じなら0、違えば1 |
| NOT | 0と1を反転する |
| 左シフト | ビットを左へずらす。2倍、4倍のイメージ |
| 右シフト | ビットを右へずらす。2で割るイメージ |
| マスク処理 | 必要なビットだけを残す考え方 |
まとめ:ビット演算は低レイヤー理解の入り口
この記事では、JavaScriptのサンプルコードを使いながら、ビット演算の基本を見てきました。
ビット演算は、普段のWebアプリケーション開発で毎日使うものではないかもしれません。
しかし、コンピュータが数値やデータを0と1で扱っていることを理解するうえで、とても重要な知識です。
AND、OR、XOR、NOT、シフト演算は、最初は記号が多くて難しく感じるかもしれません。
それでも、2進数に直して1桁ずつ確認すれば、決して特別な計算ではありません。
ビット演算を理解するコツ
= 10進数のまま考えず、2進数に直して各桁を見る
また、実務ではフラグ管理、色の操作、画像処理、バイナリデータの解析など、少し低レイヤー寄りの処理でビット演算の考え方が役立ちます。
基本情報技術者試験の対策としても、Webエンジニアとしての基礎理解としても、ビット演算は押さえておきたいテーマです。
まずは、AND、OR、XORの結果を2進数で追えるようになるところから始めてみましょう。

コメント