2.3 ビット、バイト、キロ、メガ‥‥

(1/1)
2進数のイメージ
AI生成コンテンツ / AI-generated content
0と1だけで表される2進数1桁のことをビットと呼ぶ。8ビットで1バイト。1バイトは256種類の値を表すことができる。情報量を表すときは、1000倍ごとのSI接頭語(k、M、G)と、1024倍ごとの2進接頭語(Ki、Mi、Gi)を区別する。
また、2進数⇔10進数の相互変換も筆算でできるようにしておこう。

目次

サンプル・プログラム

ビットとバイト

デジタルデータ風の背景素材(緑)
0と1で表されるデジタルデータ
コンピュータの内部では、プログラムもデータも2進数の値として扱われる。2進数とは0と1の2つだけを使って表現される値のことだ。コンピュータは0と1で動いていると言われるのは、このためである。
2進数の1桁――0と1のことをビット(bit)と呼ぶ。
1ビットは、0と1の2種類の値を表すことができる。
2ビット(2進数2桁)なら、00, 01, 10, 11の4種類の値を表すことができる。
3ビット(2進数3桁)なら、000, 001, 010‥‥111の8種類の値を表すことができる。
一般に2進数N桁は、 $ 2^N $ 種類の値を表すことができる。

8ビットを 1 バイト(byte)と呼ぶ。
1バイトは8ビットだから、 $ 2^8=256 $種類の値を表すことができる。

2進数と10進数の変換

では、18という10進数の整数を2進数で表すとどうなるか――。
10進数→2進数変換
10進数18を2進数へ変換する筆算
むかしの小学校の算数では、左図のような筆算で10進数を2進数に変換した。
18を2で割り、商の9を下の段に書き、剰余の0を右に書く。
9を2で割り、商の4を下の段に書き、剰余の1を右に書く。
これを繰り返し、下から順に並べる。
つまり $ 18_{(10)}=010010_{(2)} $ となる。
逆に、2進数を10進数に変換するときは、2のべき乗を使い
$$ 010010_{(2)}=2^5 \times 0 + 2^4 \times 1 + 2^3 \times 0 + 2^2 \times 0 + 2^1 \times 1 + 2^0 \times 0 = 18_{(10)} $$
と計算する。

10進数と2進数、8進数、16進数

JavaScript の整数は、これまで見てきた10進数のほかに、2進数、8進数、16進数で表記することができる。
2進数表記は $ 0b $ または $ 0B $ ではじめる。b は binary(2進数)の頭文字だ。前述のように、コンピュータ内部ではデータは2進数として保持されていることから、そうしたハードウェア寄りの場面で2進数を使うことは多い。
8進数表記は $ 0o $ または $ 0O $ ではじめる。o は octal(8進数)の頭文字だ。古い非strictモードでは、0から始まる整数を8進数として扱う場合があるが、現在のコードでは誤解のない $ 0o $ 表記を使う。8進数は3ビットを1桁で表せるため、36ビット機などの値を読みやすく表す用途にも使われてきた。
16進数表記は $ 0x $ または $ 0X $ ではじめる。16進数の1桁は4ビット、2桁は1バイトに対応するため、文字コードやバイト列を表すときに便利である。
JavaScript で2進数、8進数、16進数を表記する方法と、簡単な計算を行ってみよう。

convertDecimal.html

  76:     //2進数表記と加算
  77:     let bin1 = 0b1111000;
  78:     let bin2 = 0b11;
  79:     let bin1s = '0b' + bin1.toString(2);    //bin1を文字列にする
  80:     let bin2s = '0b' + bin2.toString(2);    //bin2を文字列にする
  81:     let dec = bin1 + bin2;

まず2進数だが、前述の通り $ 0b $ または $ 0B $ ではじめる。これは数値リテラルであり、そのまま変数へ代入することができる。
変数の内部では2進数で保持されるのだが、これを表示しようとすると原則として10進数で表示するため、toStringメソッドを使って2進数に変換してやる。メソッドについては「5.2 プロパティ、メソッド、イベントハンドラ」で解説するが、ここではNumber型の変数に .toString(N) を付けると、Nで指定した進数の文字列として変換してくれると覚えておこう。なお、toStringメソッドは頭に $ 0x $ を付けてくれないので、これはプログラム側で付けるようにした。
変数 bin1 と bin2 の加算は、普通の演算式を書けばよい。

convertDecimal.html

  87:     //8進数表記と減算
  88:     let oct1 = 0o2333;
  89:     let oct2 = 0o11;
  90:     let oct1s = '0o' + oct1.toString(8);    //oct1を文字列にする
  91:     let oct2s = '0o' + oct2.toString(8);    //oct2を文字列にする
  92:     dec = oct1 - oct2;

次に8進数である。前述の通り $ 0o $ または $ 0O $ ではじめる。2進数の時と同様、そのまま変数へ代入することができる。8進数の文字列に変換するのに toStringメソッドを利用するのも同じだ。減算も、普通の演算式を書けばよい。

convertDecimal.html

  98:     //16進数表記と乗算
  99:     let hex1 = 0xB2B;
 100:     let hex2 = 0x13;
 101:     let hex1s = '0x' + hex1.toString(16).toUpperCase(); //hex1を文字列にする
 102:     let hex2s = '0x' + hex2.toString(16).toUpperCase(); //hex2を文字列にする
 103:     dec = hex1 * hex2;

最後に16進数である。前述の通り $ 0x $ または $ 0X $ ではじめる。2進数、8進数の時と同様、そのまま変数へ代入することができる。
16進数の文字列に変換するのに toStringメソッドを利用するのも同じだが、アルファベットを小文字で返すので、読みやすいように toUpperCaseメソッドを使って大文字に変換してやる。少しややこしいのだが、hex1.toString(16) はString型の変数になっており、このString型の変数に .toUpperCase() を付けると、英小文字を大文字に変換してくれる。
乗算は、普通の演算式を書けばよい。

ちなみに、上表「10進数と2進数、8進数、16進数の対比表」は、手書きで作るのが面倒だったので(誤記したくなかったし)、 JavaScript を使って表示している。興味をお持ちの方は、この記事のソースを読んでみていただきたい。

2のべき乗

プログラムを作っているときに、10進数⇔2進数変換が必要になる場面がよくある。電卓アプリで計算してもいいのだが、ある程度の数字は暗算できた方が便利である。下表の値は覚えておきたい。
べき乗10進数
12
24
38
416
8256
101,024
124,096
1416,384
1665,536
64ビットCPUの「64ビット」は、主に汎用レジスタや整数演算、アドレスの基本幅を指す。64ビットの並びは、10進数に直すと 18,446,744,073,709,551,616($2^{64}$)種類ある。ただし、実際に使えるメモリアドレスの幅や、一度に処理できるデータ量はCPUの設計や命令によって異なる。

キロ、メガ、ギガ

インテル 4002
インテル 4002
1971年(昭和46年)、インテルがプログラム電卓向けに開発した最初のCPU「4004」は4ビットだった。つまり、同時に扱える値は16種類。だが、10進数1桁を扱うなら、これで十分である。算数の筆算と同じで、1桁ずつ計算して、他の桁はメモリに入れておく。
4004と組み合わせて使うRAM 4002 は320ビット(40バイト)のデータを記憶することができた。
これらを搭載したビジコン社のプログラム電卓 141-PF は、プログラムを収めるROM 4001の容量が256バイトしかなかった関係で、14桁表示にとどまったが、それでも、後の8桁の電卓より大きな計算を行うことができた。

メモリICは、内部に電位を蓄えることでデータを保持する。この回路が小さくなればなるほど、同じ大きさのICでより多くのデータを保持することができるようになる。
インテルはCPUより早くメモリICを開発しており、1969年(昭和44年)には256ビットの 1101 を、1970年(昭和45年)には1024ビットのDRAM 1103 を発売した。その後も各社が大容量化を進め、DRAMの容量は急速に増えていった。

メモリ容量が大きくなると、1000倍ごとのSI接頭語と、1024倍ごとの慣用表記が混在するようになった。現在は、1000バイトを1キロバイト(kB)、1024バイトを1キビバイト(KiB)と書き分ける。大文字・小文字にも意味があり、ビットはbitまたはb、バイトはBと表す。
$ 4096 \div 2^{10} = 4 $ なので、4096ビット=4キビビット(Kibit)=512バイト=0.5キビバイト(KiB) である。
2進接頭語
大きさ名称英語記号値
250ペビpebiPi1,125,899,906,842,624
240テビtebiTi1,099,511,627,776
230ギビgibiGi1,073,741,824
220メビmebiMi1,048,576
210キビkibiKi1,024

接頭辞の一覧表を作成する

せっかくなので、2のべき乗を計算して接頭辞の一覧表を作成するプログラムを紹介しよう。

prefixTable.html

  77: <script>
  78: //ページのロード時に実行
  79: window.onload = function() {
  80:     //配列
  81:     let prefix = [
  82:         [10, 'Kibi', 'Ki'],
  83:         [20, 'Mebi', 'Mi'],
  84:         [30, 'Gibi', 'Gi'],
  85:         [40, 'Tebi', 'Ti'],
  86:         [50, 'Pebi', 'Pi'],
  87:     ];
  88: 
  89:     //<table>タグを代入する変数
  90:     let ss = '<caption>2進接頭語</caption>';
  91:     ss += '<tr><th>大きさ</th><th>名称</th><th>記号</th><th>値</th></tr>';
  92: 
  93:     //計算で値を求める
  94:     for (let i = 0; i< prefix.length; i++) {
  95:         let n = Math.pow(2, prefix[i][0]);
  96:         ss += '<tr><td class="index">2<sup>' + prefix[i][0].toString(10) + '</sup></td>';
  97:         ss += '<td class="center">' + prefix[i][1] + '</td>';
  98:         ss += '<td class="center">' + prefix[i][2] + '</td>';
  99:         ss += '<td class="right">' + n.toLocaleString() + '</td></tr>';
 100:     }
 101: 
 102:     //結果を表示
 103:     document.getElementById('prefix').innerHTML = ss;
 104: };
 105: </script>

まだ説明していない仕組みが多く出てくるが(いずれ説明する)、このような定型的な一覧表を作成するのにもプログラムが役立つことを覚えておいていただきたい。

コラム:算数とN進数

勉強のイラスト「テスト勉強・女の子」
N進数の計算を学ぶ
N進数と10進数を相互変換する問題は、IPAの基本情報技術者試験シラバスに含まれる。一方、現在の中学校数学では、2進数そのものは中心的な学習項目ではない。

小学生にプログラミングを学ばせるなら、その前に、基本的なデータの扱いを算数の時間に盛り込み、暗算で、ある程度のデータ変換ができるような基礎力を身に付けるようにしてはどうだろうか。
たとえば、一般的な8ビットRGB画像は、R(赤)、G(緑)、B(青)の各色を256段階で表すので、組み合わせは $ (2^8)^3 = 256^3 = 16,777,216 $通りになる。
一方、カメラの14ビットRAWは、通常、撮像素子の各画素が1色分を $2^{14}=16,384$ 段階で記録するデータであり、そのままRGB3色の組み合わせ数として数えることはできない。現像処理では、この高い階調情報を使って明るさや色を調整し、表示・保存用の画像を作る。
ICT機器を常に携行している子どもたちの世代こそ、自然に2進数の計算結果が頭に思い浮かぶような能力を身につけてほしい。

コラム:メインフレーム

ENIAC
ENIAC
8進数がコンピュータで使われてきた歴史的経緯を補足しておこう――。

1946年(昭和21年)に公開された初期の電子式汎用コンピュータ「ENIAC (エニアック) 」は、2進数の36ビット機ではなく、10進数10桁を扱うアキュムレータで計算した。
もともとアメリカ陸軍の弾道表を計算するために開発された ENIAC は、真空管を多数使い、大きな電力と専用設備を必要とした。
ENIAC の開発者たちが設計した商用コンピュータ UNIVAC I (ユニバック・ワン)  は、12文字を1ワードとして扱った。初期のコンピュータには10進方式、6ビット文字、12・18・36ビット語など多様な設計があり、36ビット語を採用した機種では3ビットごとに区切れる8進表記が便利だった。
IBM System/360
IBM System/360
IBMが1964年(昭和39年)に発表した System/360 は、用途や性能が異なる機種で同じ命令体系を使えるようにしたシリーズで、8ビットを1バイト、4バイトを1ワードとする体系を採用した。文字コードには EBCDIC (エビシディック)  を採用した。EBCDICは8ビットの文字コードであり、「16進数として規格化された」という意味ではない。
System/360が32ビット語を採用したことを、36ビット機から単純に4ビット短くして精度を落としたものと考えることはできない。数値の形式や命令体系は機種ごとに異なり、System/360は商用計算と科学技術計算を1つの互換アーキテクチャで扱うことを目指した。

1970年代に登場した初期のパーソナルコンピュータには8ビットCPUが多く使われ、その後、16ビット、32ビット、64ビットへ発展した。ただし、メインフレームは大量の入出力、高い信頼性、互換性を重視する別の役割を持ち、現在も企業や政府の基幹業務で利用されている。

参考サイト

(この項おわり)
header