基礎●○○○○

2進数

Binary Number ・ にしんすう

0と1の2種類の数字で数を表す方法。コンピュータのすべての情報表現の土台。

✦ 30秒で試す — 航海同じ0と1の並びが、255にも−1にも読める1を足した後、器の中の値は?予想してみる

概要

2進数は、0と1のたった2種類の数字だけで数を表す方法です。私たちが日常で使う10進数が「0〜9の10種類の数字を使い、10集まると桁が上がる」のに対し、2進数は「0と1の2種類だけを使い、2集まると桁が上がる」数え方です。たとえば10進数の5は、2進数では101と書きます。

なぜこれがコンピュータの世界で最重要なのかというと、コンピュータの内部にあるすべての情報 — 数値も、文字も、画像も、音声も、プログラムそのものも — が最終的にはこの0と1の列として記録・処理されているからです。この0か1かの最小単位を「ビット(bit)」と呼び、8ビットをひとまとめにした単位を「バイト(byte)」と呼びます。ファイルサイズの「KB」「MB」、メモリの「16GB」といった日常的に目にする単位は、すべてこのバイトの積み重ねです。

2進数そのものを手で計算する機会は実務では多くありません。しかしIPアドレスのサブネット計算、権限フラグの読み方、桁あふれによるバグ、バイナリファイルのバイト順など、あちこちで「下に2進数が敷かれている」場面に出会います。土台として一度きちんと理解しておくと、後のさまざまな語彙の見通しが良くなります。

なぜ生まれたか

コンピュータが2進数を採用したのは、数学的な美しさのためではなく、物理的な都合のためです。コンピュータの内部では、情報は電圧の高い/低い、スイッチのON/OFFといった電気的な状態で保持されます。もし10進数をそのまま扱おうとすると、1本の信号線で10段階の電圧を正確に区別しなければなりません。電圧はノイズや温度でわずかに揺らぐため、10段階の区別は誤読のもとになります。

一方、「電圧が高いか低いか」の2択なら、多少ノイズが乗っても判定を間違えにくく、回路も単純に作れます。しかも1937年にシャノンが示したように、2つの状態を扱うスイッチの回路は、ブールの論理代数(真と偽の計算)でそのまま設計できます。信頼性と設計のしやすさを取って「1本の線では2状態だけを表し、代わりに線をたくさん並べて桁数を稼ぐ」— これが2進数コンピュータの基本設計です。ENIAC(1945年)のように10進数で動くコンピュータも実在しましたが、1945年のフォン・ノイマンの報告書が2進数を採るべきだと論じ、以後の設計は2進数に収束していきました。

詳細

桁の重みで読む

10進数の「352」が「100が3個、10が5個、1が2個」を意味するように、2進数も各桁に重みがあります。ただし重みは10倍ずつではなく2倍ずつ、右から 1, 2, 4, 8, 16, 32, 64, 128… と増えていきます。たとえば2進数の 11001010 は、重み128・64・8・2の桁が1なので、128 + 64 + 8 + 2 = 202 と読めます。

8ビット(=1バイト)で表せるのは 00000000〜11111111、10進数でいえば0〜255の256通りです。IPアドレス(IPv4)が「192.168.0.1」のように0〜255の数を4つ並べた形をしているのは、まさに「1バイトを4つ並べた32ビットの値」だからです。

16進数 — 2進数の速記法

2進数は桁数がすぐ長くなり、人間には読み書きしづらいという弱点があります。そこで実務では、2進数4桁をちょうど1文字で表せる16進数(0〜9とA〜Fの16種類の文字を使う数え方)が速記法として使われます。4ビットは16通りなので、2進数を右から4桁ずつ区切って置き換えるだけで機械的に変換できます。この4ビットのまとまりを「ニブル」と呼びます。

桁の重み12864321684212進数1100101016進数CA1100 = 8+4 = 12 = C1010 = 8+2 = 10 = A10進数 202 = 128 + 64 + 8 + 2 = 16進数 0xCA
同じ値202の3つの表記 — 2進数を4桁ずつ区切ると16進数の1文字に対応する

メモリダンプやハッシュ化の結果の値、カラーコード(#FF5733)などが16進数で書かれるのは、この「2進数との相性の良さ」が理由です。「16進数の2文字 = 1バイト」という対応を覚えておくと、ハッシュ値の長さ(SHA-256なら16進数64文字 = 32バイト = 256ビット)なども即座に読み解けるようになります。

桁あふれと2の補数 — 器の大きさには上限がある

紙の上の数と違い、コンピュータの数値には「何ビットで表すか」という器の大きさが決まっています。8ビットの器で255(11111111)に1を足すと、下の桁から繰り上がりが次々に伝わり、8桁すべてが0になったうえで、9桁目の1は器からこぼれ落ちます。結果は0です。これが「桁あふれ(オーバーフロー)」で、カウンタが突然0や負の値に化けるバグの正体です。2038年問題(32ビットの符号付き整数で秒を数えてきたUNIX時刻が、2038年1月19日にあふれる)も同じ構造の問題です。

負の数は「2の補数」という表現で扱うのが標準です。2の補数では、最上位の桁の重みを +128 ではなく −128 と読みます。すると 10000000 は −128、11111111 は −128 + 127 = −1 になり、8ビットで −128〜127 を表せます。「最上位ビットが符号」とよく言われますが、正確には符号の印が付いているのではなく、重みが負の普通の桁です。この読み方の利点は、足し算の回路を符号なしとまったく共有できることです。−1(11111111)に1を足すと、符号なしのときと同じく繰り上がりが器からこぼれて 00000000、つまり 0 という正しい答えになります。

256通りの値を時計の文字盤のように輪に並べると、2つの話が1つにまとまります。符号なしでは、255 の次で輪が一周して 0 に戻ります。符号付きでは、輪の半分が負の数として読み直され、127 の次が −128 という「崖」になります。ビット列は同じで、どこで数え直すかが違うだけです。下の輪で、+1 を押し続けて確かめてください。

⚡ 体験: 8ビットの数の輪 — 桁あふれと2の補数
読み方
0641281922552500xFA桁の重み128164132116181402110器の外FA4桁ずつ区切ると16進の1文字+1−1
2進1111 101016進0xFA符号なし250符号付き-6

「+1」を押し続けてみてください(長押しで連続)。いまは 250。下の桁から繰り上がりが走り、255 の先で何が起きるかが見えます。

同じビット列 11111111 が、符号なしでは255、符号付きでは−1と読まれる — 「ビット列そのものに意味はなく、解釈の規則が意味を与える」という感覚が、2進数理解の核心です。

バイトの並び順 — エンディアン

もう1つ、実務で最もよく踏む落とし穴が、複数バイトの値をメモリやファイルに置くときの「バイトの並び順」です。32ビットの値 0x12345678 は4バイトに分かれますが、これを番地の小さい方から 12 34 56 78 と置くか、78 56 34 12 と置くかは、CPU やフォーマットの取り決め次第です。前者をビッグエンディアン(大きい桁が先)、後者をリトルエンディアン(小さい桁が先)と呼びます。

値 0x12345678(上位 12 … 下位 78)ビッグ大きい桁が先12345678100番地101番地102番地103番地リトル小さい桁が先78563412100番地101番地102番地103番地ビッグ: ネットワークの通信(TCP/IP のヘッダ)、多くのファイル形式(PNG など)リトル: x86・ARM など現在の主要な CPU のメモリ、ZIP や BMP など一部のファイル形式
同じ32ビットの値 0x12345678 を、番地の小さい方から置いたときの2つの並べ方

同じ種類のマシンの中だけで読み書きしているうちは問題になりません。困るのは境界をまたぐときです。ネットワークの通信(TCP/IP のヘッダの数値)は「ネットワークバイトオーダー」としてビッグエンディアンに決められているので、リトルエンディアンの CPU は送る前と受けた後に並べ替えます(C の htonl・ntohl がそのための関数です)。バイナリファイルを自前で解析して、ポート番号 80(0x0050)を 20480(0x5000)と読んでしまう、というのが典型的な事故です。文字コードの UTF-16 に「BOM(バイト順マーク)」があるのも、2バイト単位の文字をどちらの順で並べたかを先頭で申告するためです。

すべては解釈次第 — 実務で顔を出す場面

「解釈が意味を与える」という原則は、そのまま他の語彙への入口になります。ビット列を小数として解釈する規則が浮動小数点、文字として解釈する規則が文字コードです。文字化けとは、ビット列を書いたときと違う規則で読んでしまう事故にほかなりません。また、ビット列を数ではなく「フラグの集まり」として直接操作するのがビット演算で、IPアドレスのサブネットマスクや、ファイルシステムの権限(Unix の 755 = 111 101 101)で実際に使われています。

普段は高級言語やライブラリがこの層を隠してくれますが、数値が突然おかしくなったとき、バイナリファイルを覗くとき、ネットワークのビットを数えるとき — 抽象の底が抜けたときに立ち返る場所が、この2進数です。

試問

8桁の2進数(0と1だけで書く数)の器です。下に並んだ8つのビットのセルを押すと、その桁が 0 と 1 で入れ替わり、輪と中央の数字にその値が出ます。上の切り替えで、読み方を「符号なし(0〜255)」と「符号付き・2の補数」(負の数も表す標準の読み方で、最上位の桁の重みを −128 と読む)から選べます。

✦ 命題挑戦中

符号付き(2の補数)の読みで、8ビットで表せるいちばん小さい数を、ビットを押して作れ

  • 読み方を「符号付き・2の補数」にする
  • 符号付きで読んだ値を、8ビットで表せるいちばん小さい数にする
⚡ 体験: ビットを押して、符号付きの最小の数を作る
読み方
0641281922552500xFA桁の重み128164132116181402110器の外FA4桁ずつ区切ると16進の1文字
2進1111 101016進0xFA符号なし250符号付き-6

いまの値は 250(2進で 11111010)。ビットのセルを押すと、その桁が 0 と 1 で入れ替わります。