10進数・2進数・8進数・16進数を相互に変換する計算方法。コンピュータの内部表現を理解する第一歩です。
私たちが普段使っている数は10進数(=0〜9の10種類の数字を使う数え方)です。 しかしコンピュータの世界ではこの10進数の他に、2進数(0と1だけ)、8進数(0〜7)、16進数(0〜FでAが10、Bが11...Fが15)という表し方が使われます。
これらはすべて同じ数を別の書き方で表しているだけです。たとえば10進数の「156」は、2進数では「10011100」、8進数では「234」、16進数では「9C」と書きます。 上のツールのスライダーを動かすと、同じ数がそれぞれの進数でどう表されるかリアルタイムで確認できます。
コンピュータの中身は、突き詰めると電気が流れているか、いないかの2つの状態しか判別できない電子回路です。 電圧が高い(HIGH)なら「1」、低い(LOW)なら「0」。この2つの状態を使って情報を表すのが2進数です。
「なぜ10進数ではダメなのか?」と思うかもしれません。電圧を10段階に分けて0〜9を表すこともできなくはないのですが、 ノイズ(電気的な誤差)の影響で「5と6の区別がつかない」といった問題が起きやすくなります。 2段階(HIGH/LOW)なら区別がはっきりつくので、誤りが起きにくく信頼性が高いのです。
身近な例でいえば、電気のスイッチ(ON/OFF)や信号機の赤/青も2状態です。 コンピュータはこの単純な「0か1か」を何十億個も超高速で組み合わせることで、文字・画像・音声・動画など、あらゆる情報を処理しています。
10進数では各桁が「1の位」「10の位」「100の位」...と10倍ずつ大きくなりますが、2進数では各桁が2倍ずつ大きくなります。 右端から順に 1, 2, 4, 8, 16, 32, 64, 128... という重みがつきます。
2進数を10進数に直すには、「1」が書かれている桁の重みを全部足すだけです。 たとえば10011100なら、 128の桁が1、16の桁が1、8の桁が1、4の桁が1 → 128 + 16 + 8 + 4 = 156 です。
この「重み」の考え方はすべての進数に共通です。10進数の「156」も 1×100 + 5×10 + 6×1 ですよね。 上のツールの「重み展開」パネルで、入力した数がどの重みの組み合わせになるかを確認できます。
8進数は0〜7の8種類の数字を使います。 8 = 23(2の3乗)なので、8進数の1桁はちょうど2進数の3桁(3ビット)に対応します。 つまり2進数を右から3桁ずつ区切るだけで、そのまま8進数になります。
たとえば2進数010 011 100を 3桁ずつ見ると 010=2, 011=3, 100=4 なので、8進数では234です。
8進数はかつてUNIX系システムのファイルパーミッションでよく使われていました(例:chmod 755)。 現在では16進数の方が主流ですが、パーミッション表記では今でも見かけます。
16進数では1桁で0〜15の16通りを表す必要がありますが、数字は0〜9の10種類しかありません。 そこで10〜15をA〜Fのアルファベットで表します(A=10, B=11, C=12, D=13, E=14, F=15)。
16 = 24 なので、16進数の1桁は2進数の4桁(4ビット)に対応します。 8ビット(=1バイト)の値を16進数ではたった2桁で表せるので、長い2進数を書く代わりに16進数がよく使われます。 たとえば2進数の10011100は 16進数では9Cの2桁で済みます。
16進数が使われている身近な例として、
・カラーコード:#FF6600 → 赤=FF(255), 緑=66(102), 青=00(0)
・メモリアドレス:0x7FFF0000
・MACアドレス:AA:BB:CC:DD:EE:FF
があります。上のツールでいろいろな数を入力して、16進数の「A〜F」がどこで登場するか試してみてください。
基数変換には3つのルートがあります。組み合わせによって使う方法が変わります。
・10進 ↔ 2進:10進→2進は「2で割り続けて余りを下から読む(割り算法)」、2進→10進は「各桁の重みを足す(重み計算)」
・10進 ↔ 16進:基本は同じで割る数が16になるだけ。割り算法と重み計算で対応
・2進 ↔ 16進:4桁ずつ区切るだけで変換できる(最も楽!)
なぜ2進↔16進が「4桁ずつ区切るだけ」で済むのか。それは 16 = 2の4乗という関係があるからです。2進数4桁で表せる値が0〜15まで16種類、ちょうど16進数1桁と一致します。だから4桁の2進数グループと16進1桁は「完全に1対1で対応」していて、変換がそのままできます。
上のツールでは「割り算法」の過程をアニメーションで確認できます。まずはプリセット「255」を選んで2進変換と16進変換を切り替えてみてください。2進変換(8ステップ)と16進変換(2ステップ)の手間の差が一目でわかります。
割り算法(じょざんほう)とは、10進数を2進数や16進数に変換するときに使う、繰り返し割り算する方法です。手順は2ステップで終わります。
・① 変換先の基数(2か16)で割り続ける。商が0になるまで繰り返す
・② 出てきた余りを下から順に読む。それが答え
なぜ「下から読む」のか、それが逆では?と思うかもしれません。最初に出る余りは最も小さい桁(右端)の値で、最後に出る余りが最も大きい桁(左端)の値になるからです。割るたびに桁が1つ左(大きい方向)に移動していくイメージです。
上のツールは「割り算法」の各ステップを縦に並べて表示しています。変換先を「2進」にして小さな数(15や13など)を入力すると、ステップが少なくて確認しやすいです。余りが右端に強調表示され、それを下から読むと2進数になる様子を目で追えます。
| 進数 | プレフィックス | 例(156) | 使用言語 |
|---|---|---|---|
| 2進数 | 0b | 0b10011100 | Python, JS, Java, C |
| 8進数 | 0o / 0 | 0o234 | Python(0o), C(0) |
| 16進数 | 0x | 0x9C | ほぼすべての言語 |
プログラミングでは数値の先頭にプレフィックスをつけて何進数かを区別します。 特に0x(16進数)はメモリアドレスやカラーコード(#FF0000)でよく使われるので、見慣れておきましょう。
| 10進 | 2進 | 16進 | 意味 |
|---|---|---|---|
| 0 | 0000 | 0 | |
| 15 | 1111 | F | 4ビット全部1 |
| 127 | 01111111 | 7F | 7ビット最大値 |
| 128 | 10000000 | 80 | 8ビットの半分 |
| 255 | 11111111 | FF | 1バイト最大値 |
| 256 | 100000000 | 100 | 1バイト+1 |
| 1024 | 10000000000 | 400 | 1KiB |
| 65535 | 1111111111111111 | FFFF | 2バイト最大値 |
これらの値はコンピュータの世界で繰り返し登場します。特に255(0xFF)は「1バイトで表せる最大の数」、1024(0x400)は「1KiB(キビバイト)」としてよく目にします。 上のツールのプリセットボタンで、これらの値がどう変換されるかすぐに確認できます。