コード中のマジックナンバーを読む
& 0xFF、>>> 24、| (1 << 3)、0o644——第 11–15 レッスンまで学べば、これらの断片がどのビットを取っているのか、どのビットを立てているのか一目で分かります。
Guide
基数変換とビット演算講座は 17 レッスンの対話形式チュートリアルで、「2 進数」という抽象的な概念を手で触れるスイッチに変えます。数値を入力すると 2・8・10・16 進数の 4 つの表記が同時に変わり、あるビットを点灯・消灯すると値がすぐに更新されます。2 つの数で AND / OR / XOR / シフトを行うと結果がビットごとに桁をそろえて表示され、小数を入力すればそれが符号・指数・仮数の 3 フィールドに分解され、倍精度で正確に等しい10 進小数がどれかも分かります。各レッスンには具体的な目標があります——ある数を基数変換する、200 を組み立てる、-5 の 2 の補数を書く、5 << 3 を計算する——判定はその場で返ります。
更新日 2026-09-094 sources14 min read
基数変換とビット演算講座は 17 レッスンの対話形式チュートリアルで、「2 進数」という抽象的な概念を手で触れるスイッチに変えます。数値を入力すると 2・8・10・16 進数の 4 つの表記が同時に変わり、あるビットを点灯・消灯すると値がすぐに更新されます。2 つの数で AND / OR / XOR / シフトを行うと結果がビットごとに桁をそろえて表示され、小数を入力すればそれが符号・指数・仮数の 3 フィールドに分解され、倍精度で正確に等しい10 進小数がどれかも分かります。各レッスンには具体的な目標があります——ある数を基数変換する、200 を組み立てる、-5 の 2 の補数を書く、5 << 3 を計算する——判定はその場で返ります。
講座は 4 つの段階に分かれます。基数変換(2 ↔ 10、2 のべき乗、16 進数と 8 進数がなぜ「速記」なのか)。符号付き整数(2 の補数がどうやって引き算を足し算に変えるか、オーバーフローでなぜ 127 + 1 が -128 になるのか)。ビット演算(AND によるマスク、OR によるビットのセット、XOR による反転、シフトによる乗除算、そしてそれらが Linux の権限ビット 755 でどう使われるか)。浮動小数点(IEEE 754 のフィールド配置と、0.1 + 0.2 !== 0.3 の本当の理由)。
学習時間は約 45 分。プログラミングを学び始めた人、面接対策中の開発者、そして 0x1F、& 0xFF、chmod 644 を見るたびに調べ直している人に向いています。数学の素養は不要で、足し算ができれば十分です。
0x を付けてもかまいません。?lesson=n で特定のレッスンへ直接移動できます。このページの上部が講座本体です。数値を変え、ビットスイッチを押し、答えを入力できます。
第 9 レッスン「2 の補数を求める」では、-5 の 8 ビットの 2 の補数を書きます。
第 16 レッスン「IEEE 754 のフィールド」で 0.15625 を入力すると、パネルは次のように表示します。
絶対値 5 0 0 0 0 0 1 0 1
ビット反転 1 1 1 1 1 0 1 0
+1 1 1 1 1 1 0 1 1 ← 答え 11111011
検算 符号なし 251、符号あり 251 − 256 = −5 ✓0.15625 = 0.00101₂ = 1.01₂ × 2⁻³
符号 0
指数 −3 + 127 = 124 = 01111100 ← 答え 124
仮数 01000000000000000000000(先頭の 1 は暗黙)
32 ビット 0 01111100 01000000000000000000000 = 0x3E200000どの基数も「位の重みの合計」です。10 進数の 203 = 2×100 + 0×10 + 3×1、2 進数の 1011 = 1×8 + 0×4 + 1×2 + 1×1 = 11。右から左へ位の重みは 1、2、4、8、16、32、64、128……と続きます。2 進数から 10 進数へは 1 になっている位の重みを足すだけで、10 進数から 2 進数へは 2 で割り続けて余りを記録するか、大きい 2 のべき乗から順に貪欲に引いていきます(第 7 レッスンのビットスイッチはこの手順の可視化です)。
は 1000 と 2.4% しか違いません。そこで初期には KB を 1024 バイトの意味で使いました。これが今も混乱を生んでいます。ハードディスクメーカーは を 1 GB として表記し、OS は で計算するため、500 GB のディスクは 465 GiB と表示されます。IEC はこのために KiB、MiB、GiB(2 進接頭辞)を定義し、Linux と macOS は順次採用しましたが、Windows は依然として GB と表示しながら GiB で計算しています。覚えておきたい数値は 、、、 です。
2 進数は長すぎて人間には読みにくい。16 進数(0–9 に A–F を加えたもの)は 1 文字で 4 ビットを表し、1 バイトはちょうど 2 文字になります。11111111 = FF、10110110 = B6。変換に 10 進数を経由する必要はありません。2 進数を右から 4 ビットずつ区切り、各区間を表で引くだけです(第 5 レッスンで練習します)。8 進数は 1 文字で 3 ビットを表し、歴史的には 12、24、36 ビット幅のマシンで使われました。現在は主に Linux の権限(755)と C の \012 エスケープの中に生きています。プログラム中の接頭辞は 0x が 16 進数、0o が 8 進数、0b が 2 進数です。
0 以上の整数は 2 進表記が 1 通りしかないため、8 ビットの数は互いに干渉しない 8 個のスイッチ(フラグ)として使えます。flags = READ | WRITE、if (flags & EXEC) のようにです。CSS の font-weight、Unix のファイル権限、ネットワークプロトコルのヘッダーにあるフラグフィールドはどれもこの形で詰め込まれています。第 7 レッスンではスイッチをクリックするだけで 200 を作ります。最上位から貪欲に進み、200 ≥ 128 で点灯、残り 72 ≥ 64 で点灯、残り 8 = 2³ で点灯、結果は 11001000 です。
負の数はどう保存するのか。直感的には 1 ビットを符号に使いたくなりますが、それだと「+0」と「−0」の 2 つのゼロができ、加算回路も場合分けが必要になります。2 の補数(two's complement)の決まりは、最上位ビットが 1 なら負数で、値は符号なしの値から を引いたもの、というものです。8 ビットでは 11111111 は 255 であり、255 − 256 = −1 でもあります。10000000 は −128 です。負の数の 2 の補数は、絶対値を書いて、ビットを反転して、1 を足します。−5 なら 00000101 → 11111010 → 11111011 です。
2 の補数の妙味は、足し算が正負を知らなくてよい点にあります。−5 + 5 = 11111011 + 00000101 = 1 00000000 で、9 ビット目の桁上がりを捨てればちょうど 0 になります。引き算は「2 の補数を足す」ことに変わり、CPU は加算器ひとつで済みます。8 ビットの 2 の補数の範囲は −128 から 127 で、負数のほうが 1 つ多いのは、0 が正数側の位置を占めているためです。
ビット幅には限りがあるので、足しすぎると回り込みます。int8 の 127 = 01111111 に 1 を足すと 10000000 になり、2 の補数として読むと −128 です。C、Java、Go の整数オーバーフローはこのように黙って起きます。JavaScript の通常の Number は浮動小数点なのでオーバーフローしませんが、Int8Array、|0、そしてすべてのビット演算は 32 ビットの 2 の補数上で行われ、(2 ** 31) | 0 は −2147483648 になります。有名な 2038 年問題は、32 ビット符号付き秒数が 2038-01-19 03:14:07 UTC に負へあふれる問題です。昔のゲームの「スコアが負になる」「コインが 0 に戻る」も同じ現象です。
3 つのビット論理演算にはそれぞれ決まった用途があります。
| 演算 | 規則 | 慣用句 |
|---|---|---|
AND & |
両方 1 のときだけ 1 | マスクで取り出す: x & 0x0F で下位 4 ビット、IP & サブネットマスク でネットワークアドレス、n & 1 で偶奇判定 |
OR | |
どちらかが 1 なら 1 | ビットを立てる: flags | READ で他のフラグに触れずに 1 つだけ点ける |
XOR ^ |
2 つが異なるときだけ 1 | 反転 / 復元: x ^ m ^ m = x。ワンタイムパッド、チェックサム、一時変数なしの交換 |
あるビットを「消す」のは AND と NOT の組み合わせで flags & ~FLAG です。XOR の 2 つの恒等式 、 がすべての用途の源です。a ^= b; b ^= a; a ^= b で 2 つの数を交換でき、配列の中で 1 回しか現れない要素を探すには全要素を XOR するだけで済みます。
n ビットの左シフトは の掛け算(下位に 0 を補う)、n ビットの右シフトは の割り算で小数点以下を切り捨てたものです。5 << 3 = 101000 = 40。シフトは最も安い乗除算であり、より一般的な用途は小さなフィールドを 1 つの整数に詰め込むことです。(r << 16) | (g << 8) | b は 0–255 の 3 つを 24 ビットの色値にまとめ、逆に (rgb >> 8) & 0xFF で G を取り出します。右シフトには 2 種類ある点に注意してください。算術右シフト >> は符号ビットを保ち(負数は負のまま)、論理右シフト >>> は 0 を補います。JavaScript のシフトは 32 ビット上で行われ、1 << 31 は −2147483648、1 << 32 は 1 << 0 = 1 になります。シフト量が 32 の剰余で扱われるためです。
Linux のファイル権限は 9 ビットです。所有者・グループ・その他ユーザーがそれぞれ 3 ビットを持ち、読み r = 4、書き w = 2、実行 x = 1 の順です。3 ビットずつの合計がそのまま 8 進数 1 桁になります。rwxr-xr-x = 7、5、5 → 755、rw-r--r-- = 644。これは位の重みとマスクが日常の運用にもっとも直接現れる例です。chmod u+x は 0o100 の OR、chmod o-w は ~0o002 の AND です。さらに前に第 10–12 ビット(setuid、setgid、sticky)が付くことがあり、4755 のような 4 桁表記を見ることもあります。
浮動小数点数は 2 進数の科学表記法です。
単精度 32 ビット = 符号 1 ビット s + 指数 8 ビット e(バイアス 127)+ 仮数 23 ビット f。倍精度 64 ビット = 1 + 11(バイアス 1023)+ 52。仮数が保存するのは小数部分だけで、整数部分の 1 は暗黙なので、精度が 1 ビットおまけで付いてきます。指数にバイアスを足して保存するのは、浮動小数点数をビット列として比較したときに整数と同じように単調にするためです。0.15625 = = で、指数フィールドは −3 + 127 = 124 = 01111100、仮数フィールドは 01 の後を 0 で埋めた形になります。
特殊な符号化がいくつかあります。指数がすべて 0 なら非正規化数(0 に極めて近い値と ±0 を表します)。指数がすべて 1 で仮数がすべて 0 なら ±∞。指数がすべて 1 で仮数が非 0 なら NaN です。だから 0/0 は NaN で 1/0 は Infinity になり、NaN には多くのビットパターンがあるのにどれも「自分自身と等しくない」のです。
2 進小数が正確に表せるのは 2 の負のべき乗の和だけです。0.5、0.25、0.125……。 は 2 進数では無限循環小数 になり、52 ビットの仮数では丸めが必要です。その結果、倍精度の 0.1 は正確に
であり、0.1 よりわずかに大きくなります。0.2 も同様にわずかに大きく、両者を足して丸めると 0.3000000000000000444… になります。一方、リテラル 0.3 に最も近い倍精度値は 0.29999999999999998889… です。2 つは別の 2 進数なので、0.1 + 0.2 === 0.3 は false になります。これは JavaScript の不具合ではなく、IEEE 754 を使うどの言語(Python、Java、C、Go)でも同じです。
対策は場面ごとに変わります。お金は整数の「分」か 10 進ライブラリ(decimal、BigDecimal、Decimal.js)。比較は誤差の範囲 Math.abs(a − b) < ε。表示は toFixed(2) で最後の 1 回だけ丸める。数え上げは整数で、倍精度は までの整数を正確に表せるので、それを超えるなら BigInt を使います。講座の最終レッスンの選択問題「保存される 0.1 は真の値より大きいか小さいか」の答えは「大きい」です。正確な展開の 18 桁目以降にある 55511… を見れば分かります。
BigInt のビット演算は扱いません。Math.fround、半精度と bfloat16 は扱いません。0x を付けてもかまいません。10000000 は −0 ではなく −128 で、−1 はすべてのビットが 1 です。>> は 2 で割ること」: 負数の場合は 0 方向ではなく負の無限大方向への切り捨てになります。−5 >> 1 は −3、Math.trunc(−5 / 2) は −2 です。toFixed を使えば金額の問題は解決する」: toFixed は表示を丸めるだけなので、途中の演算誤差はすでに積み上がっています。金額は最初から整数の分で扱うべきです。Int32Array、| 0 はすべて 32 ビットの 2 の補数上で動くのでオーバーフローします。Number は を超えると整数の精度を失います。& 0xFF、>>> 24、| (1 << 3)、0o644——第 11–15 レッスンまで学べば、これらの断片がどのビットを取っているのか、どのビットを立てているのか一目で分かります。
第 10 レッスンのオーバーフローと第 17 レッスンの丸めが、この種のバグの大半を説明します。前者はより広い型か BigInt に、後者は整数の分か 10 進ライブラリに切り替えます。
サブネットマスクは AND マスクです(第 11 レッスン)。192.168.1.37 & 255.255.255.0 = 192.168.1.0。chmod 755 / 644 の意味と「なぜスクリプトに実行権限がないのか」は第 15 レッスンです。
2 の補数、オーバーフロー、XOR 交換、シフトによる乗除算、IEEE 754 のフィールド、0.1 + 0.2 は最頻出の基礎問題で、各レッスンの判定がそのまま自習テストになります。
ほとんどのレッスンは先頭の 0 を省略できます(1011 も 00001011 も正解)。「8 ビットの 2 の補数」と明記したレッスンはちょうど 8 ビットが必要です。ビット幅自体が答えの一部だからです。
0x は必要ですか?違いはありません。ff、FF、0xFF はどれも正解です。
同じビット列の 2 通りの読み方です。符号なしは最上位を と見なし、符号ありは と見なします。11111111 は 8 ビットでは符号なしで 255、符号ありで −1 です。
倍精度の仮数と指数を定義どおりに有理数へ展開し、長除法で 10 進数の全桁を求めています。近似ではなく、その 2 進数の正確な 10 進表記です。
このブラウザーの localStorage で、アップロードされません。「このレッスンを共有」のリンクはレッスン番号だけを運び、進捗は含みません。
講座はすべてブラウザー内で動作します。基数変換、ビット演算、浮動小数点フィールドの分解と正確な展開はすべてページ内の純粋な関数計算で、サーバーへ問い合わせません。クリア状況は端末の localStorage に保存されます。
chmod ツール——シンボルモードと 8 進モードの定義: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/chmod.html(参照日:2026-09-09)更新日 2026-09-09
全 17 レベル:2/8/16 進数の変換、ビットの切り替え、2 の補数とオーバーフロー、AND/OR/XOR/シフト、chmod のパーミッションビット、IEEE 754 の分解と 0.1+0.2 の謎
このツールの翻訳は未完了です。一部は原文または代替言語で表示されます。
目標値パネルにはバイナリ 1011 が表示されます。 10進数では何になりますか?
各桁の位の値は 2 の累乗です。右端は 2⁰=1、次に 2、4、8、16… ビットが 1 である重みを追加します: 1011 = 8 + 0 + 2 + 1 = 11。パネル内の任意のビットをクリックすると、小数がすぐに更新されます。これは、ルールを暗記するよりも直感を構築するための迅速な方法です。