2.2. データ#
私たちは普段、ウェブブラウザで調べ物をしたり、文章作成ソフトウェアや表計算ソフトウェアを使って実験結果を整理したりしています。これらはすべて、コンピューターにとっては「データ」です。データといっても、文字や数字だけに限らず、画像・音声・動画といったものも含まれます。さらに、OS も数多くのプログラムが集まって構成されており、その正体もまた膨大な文字データの集合体です。このようにデータにはさまざまな形がありますが、コンピューターのストレージが直接扱えるのは「磁気の向き」や「電気信号」といった物理的な状態だけです。そしてその状態は 2 種類しか存在せず、それぞれを数字の 0 と 1 に対応させています。そのため、コンピューターでデータを保存したり処理したりするためには、最終的にすべてを 0 と 1 の並びに変換する必要があるのです。本節では、さまざまなデータをどのようにして二進数に変換していくのかを説明します。
2.2.1. 二進数#
私たちが普段使うのは十進法(decimal system)で、0 から 9 の十種類の数字を使います。これで表現された数値を十進数(decimal number)と呼びます。十進法は便利さや歴史的な背景から社会で広く使われていますが、時刻や暦では六十進法、二十四進法、十二進法といった別の記数法も利用されています。
一方、コンピューターは磁気や電気を使うため、0 と 1 からなる二進法(binary numeral system)しか扱えません。したがって、人間が普段扱う数値や文字、画像なども、コンピューターに保存したり処理させたりするときには二進数(binary number)に変換されます。二進法では次のように数を数えます。なお、十進数と区別するために、二進数の末尾には b をつけています。
10 進数 |
2 進数 |
---|---|
0 |
0b |
1 |
1b |
2 |
10b |
3 |
11b |
4 |
100b |
5 |
101b |
6 |
110b |
7 |
111b |
8 |
1000b |
9 |
1001b |
10 |
1010b |
11 |
1011b |
12 |
1100b |
13 |
1101b |
14 |
1110b |
15 |
1111b |
16 |
10000b |
17 |
10001b |
18 |
10010b |
19 |
10011b |
20 |
10100b |
21 |
10101b |
しかし、二進数は数が少し大きくなるだけで桁数が増え、人間には非常に扱いにくい表記です。そこで、ソフトウェア開発や動作確認などでは、二進数を十六進数(hexadecimal number)に変換して表記するのが一般的です。十六進数では 0 から 9 の数字に加えて A から F の 6 文字を用い、1 桁で 0 から 15 までの数値を表現できます。また、十六進数を十進数と区別するために、通常は数値の先頭に 0x を付けて表記します。
10 進数 |
2 進数 |
16 進数 |
---|---|---|
0 |
0b |
0x0 |
1 |
1b |
0x1 |
2 |
10b |
0x2 |
3 |
11b |
0x3 |
4 |
100b |
0x4 |
5 |
101b |
0x5 |
6 |
110b |
0x6 |
7 |
111b |
0x7 |
8 |
1000b |
0x8 |
9 |
1001b |
0x9 |
10 |
1010b |
0xA |
11 |
1011b |
0xB |
12 |
1100b |
0xC |
13 |
1101b |
0xD |
14 |
1110b |
0xE |
15 |
1111b |
0xF |
16 |
10000b |
0x10 |
17 |
10001b |
0x11 |
18 |
10010b |
0x12 |
19 |
10011b |
0x13 |
20 |
10100b |
0x14 |
21 |
10101b |
0x15 |
なお、コンピューターの世界ではバイト(byte)という単位でデータを扱います。1 バイトは 8 ビット(bit)で構成され、1 ビットは、0 または 1 の二進数 1 桁に対応します。そのため、データを二進数や十六進数で表す際には、1 バイト(8 ビット)単位で区切って表記するのが一般的です。数値が小さく桁数が足りない場合には、先頭に 0 を補って 8 桁に揃えます。たとえば、十進数の 3 は二進数で 00000011b、十六進数で 0x03 のように表されます。
2.2.2. 数値データ#
数値データとひとくくりに言っても、整数と小数があります。整数の場合は、これまでに見てきたように、十進数で表された値を二進数に変換することも、その逆も可能です。桁数が大きくなることはあっても、基本的には変換に困ることはありません。しかし、小数になると、十進数と二進数の間で単純に変換できない場合があります。そのため、コンピュータの世界では、小数点の位置と数値の並びを分けて記録し、あたかも整数のように扱う方法がとられています。その方法として、固定小数点数(fixed-point number)と浮動小数点数(floating-point number)があります。
固定小数点数は、小数点の位置を固定して数値を扱う方法です。たとえば「小数点以下は 2 桁」と決めておけば、123.45 は内部的に 12345 として扱えるようになります。また、計算も整数に近い形で行えるため、正確かつ処理が高速で、金融計算のように誤差が許されない場合に向いています。ただし、小数点の位置が固定されているため、非常に大きな値や非常に小さな値を扱うには不向きです。
浮動小数点数は、小数を仮数(mantissa)と指数(exponent)に分けて記録し、指数の値によって小数点の位置を調整する仕組みです。小数点の位置を自由に動かせるため、非常に大きな数や非常に小さな数も効率よく表現できます。このしくみによって、科学技術計算やグラフィック処理など、幅広い範囲の数値計算が可能になります。ただし、浮動小数点数は有限のビット数で表されるため、すべての数を正確に表せるわけではありません。たとえば、十進数の 0.01 を二進数で表すと、
0.00001010001111010111 00001010001111010111 ... b
のように循環小数になります。コンピューターは無限の桁を扱えないので、どこかで打ち切って近似値として保存します。このため、十進数の 0.01 とはごくわずかな誤差が生じます。結果として、0.01 を 100 回足しても正確に 1 にはならない、といった現象が起こります。
n = 0.0
for i in range(100):
n += 0.01
if n == 1:
print("ピッタリかくにん!よかった。")
else:
print("ほらね、誤差だらけの現実。")
ほらね、誤差だらけの現実。
設計は完璧のはず、でも現実は常に誤差だらけ。人生設計もまた。
2.2.3. 文字データ#
文字データは、文字コード(character encoding)と呼ばれる規則に従って、文字と数値が対応づけられています。たとえば、ASCII コードを用いると、A
という文字は 0x41
として扱われます。また、あ
という文字は、UTF-8 では 0xE38182
、Shift JIS では 0x82A0
として表されます。このように、文字データはすべて文字コードで定義されているため、最終的には二進数として扱うことが可能です。文字と数値の変換は、基本的にソフトウェアが自動的に行ってくれるため、私たちが意識する必要はほとんどありません。
ASCII コードは、1960 年代前半に制定された規格で、英語のアルファベットや数字、記号などの基本的な文字を 7 ビットで表しています。7 ビットで 27 = 128 文字を表せるため、アルファベットの大文字・小文字や数字、記号(!”#$%&’()*+,-./:;<=>?@ など)、改行や削除などを十分にカバーできます。しかし、当時のコンピューターでは 8 ビットを 1 バイトとして扱うことが主流になりつつあったため、ASCII 文字も 1 バイト(8 ビット)単位で扱われるようになりました。後に、余った 8 ビット目の空き領域には、他の文字(ÄÊÎÖæ など)や記号(€†‰™©®¼ など)が割り当てられ、拡張 ASCII コード が作られました。現在、英語圏の文字は、1 文字が 1 バイトとして簡潔に扱われています。
一方、日本語や中国語など、多くの文字を含む言語では 1 バイトでは足りません。そこで、世界中の文字を統一的に扱うために Unicode という規格が使われます。Unicode では、UTF-8 や UTF-16 といったエンコーディング方式を用いて、1 文字あたりのバイト数を可変にして表現します。たとえば、UTF-8 では、ギリシャ文字やフランス語・ドイツ語のアクセント付き文字、アラビア文字などは 2 バイトで表され、仮名や漢字は 3 バイト、絵文字や特殊記号などは 4 バイトで表されます。
文字コードを統一して扱うことで、異なる言語環境でも文字データを正しく読み書きでき、国際化や多言語対応が容易になります。ソフトウェアやファイル形式では、文字コードが明示されていないと文字化けの原因となるため、正しい文字コードの理解と使用が重要です。また、プログラム内で文字列を操作する際も、1 文字が必ずしも 1 バイトとは限らないことを意識する必要があります。現在では、UTF-8 を利用することが一般的です。
2.2.4. 画像データ#
画像データも、コンピューターの世界では 0 と 1 の二進数として扱われます。画像は小さな点の集まりでできており、これらの一つ一つの点をピクセル(pixel)と呼びます。1 枚の画像は、縦 × 横に並んだピクセルで構成され、各ピクセルには色の情報が割り当てられています。その色の情報が数値で表されます。
一般的には RGB 方式 が用いられます。RGB とは、赤(red)、緑(green)、青(blue)の三原色のことで、各色を 0x00 から 0xFF の数値で表します。3 つの値を組み合わせることで、約 1,677 万色(256 × 256 × 256)を表現できます。たとえば、赤色のピクセルは (0xFF, 0x00, 0x00)、緑色は (0x00, 0xFF, 0x00)、青色は (0x00, 0x00, 0xFF) として数値で表され、1 ピクセルあたり 3 バイトが使われます。コンピューターはこれらの数値を読み取り、モニター上の各カラーフィルタに対応する光源を点灯させることで、色を表示します。
画像データは、1 つのピクセルに 3 バイト必要なため、解像度が高い画像ではファイルサイズが非常に大きくなります。そのため、多くの場合は 圧縮 して保存されます。代表的な画像形式には以下があります。
BMP: ピクセルごとの色情報をそのまま保存する方式。
JPEG: 人間の目にあまり目立たない部分の情報を削って圧縮する方式。写真向きで、複雑な色合いの表現に向く。圧縮すると画質が劣化する非可逆圧縮。
PNG: 可逆圧縮で、線画やイラストなどに向く。また、透明情報(アルファチャンネル)を含めることが可能。
圧縮された画像も、最終的にはすべて二進数としてコンピューターに保存されます。ソフトウェアはその二進数を読み取り、どのピクセルがどの色かを計算して画面に表示します。
2.2.5. 音声データ#
音声データも、コンピューターにとってはすべて 0 と 1 の二進数として扱われます。人間の声や音楽などの音は空気の振動として伝わりますが、コンピューターは振動そのものを扱えないため、これを数値に変換して保存します。この変換をデジタル化と呼び、主にサンプリングと量子化からなります。
音は時間とともに連続的に変化する波(アナログ信号)として存在します。サンプリングとは、この連続した波を一定の時間間隔で「点」に分けることです。この点のことをサンプルと呼びます。たとえば CD 音質では、1 秒間に 44,100 回(44.1 kHz)音の高さを測定します。次に、各サンプルにおける波の高さを測定し、整数値として記録します。この作業を量子化といいます。波の高さを整数で表す範囲はビット深度によって決まります。たとえば 16 ビットで量子化すると、1 つのサンプルの波の高さは 0 から 65,535 の範囲の整数値として記録されます。
サンプリングと量子化を行うことで、音声データは整数の羅列となります。そして、コンピューターはこれらの整数を順番に読み取り、スピーカーを振動させて元の音声を再現します。
ただし、そのまま保存するとファイルサイズが非常に大きくなるため、用途に応じて圧縮方法が用いられます。
WAV:非圧縮で音の情報をそのまま保存する形式。
MP3:人間の耳に聞こえにくい部分の情報を削ることで圧縮する形式。ファイルサイズは小さくなりますが、情報の一部が失われる非可逆圧縮。
FLAC:可逆圧縮形式。圧縮しても元の音を完全に復元できるため、音質を保ちながらファイルサイズを抑えらる。
最終的に、どの形式の音声データも コンピューターにとっての二進数の列として保存されます。ソフトウェアやハードウェアは、この二進数を読み取り、スピーカーやイヤホンを振動させることで音として再生します。
2.2.6. 動画データ#
動画データは、連続する画像と音声の組み合わせで構成されています。動画の画像データは、1 秒間に 30 枚ほどの静止画(フレーム)を連続して表示することで、人間には動いているように見えます。一般的に、1 秒間に 30 枚の画像(30fps)を表示すれば違和感なく動きとして認識できます。日本のテレビ放送では 30fps が標準で、4K 放送などでは 60fps が用いられることもあります。動画に含まれる音声データは、サンプリングと量子化によって整数の列に変換されます。動画では、画像データと音声データを時間軸に沿って同期させることで、映像と音声がずれずに再生されます。