とらりもんHOME  Index  Search  Changes  Login

とらりもん - 情報のデジタル表現 Diff

  • Added parts are displayed like this.
  • Deleted parts are displayed like this.

計算機の上で情報は「デジタルデータ」として表現される。ここではその形式や仕組みを学ぶ。

!「デジタル」とは?

まず, 君は「デジタル」の意味をわかっているだろうか?

デジタルは英語でdigitalと書く。なので「デジタル」より「ディジタル」と読む方が適切だろう。digitalの中の"digit"は「数字のひと文字」を意味する。digitalを直訳すれば「数字的」である。つまりデジタルデータとは「数値で表現された情報」のことなのだ。

多くのものはデジタルデータで表現できる。例えば音楽は, 演奏時間を細かい間隔に刻んで, 各瞬間の音圧力を数値に換算して並べればデジタルデータになる。後で学ぶ「文字コード」という技術を使えば, 文章もデジタルデータにできる。

計算機で扱う情報は, 基本的に全て「デジタルデータ」で表現される。計算機は数値を扱うのが得意だからである。


!情報の単位 (the units of information)

そもそも「情報」とは何だろう? 例えば明日, サイクリングに行く人が欲しい情報は「明日の天気」である。その内容は「晴れ」「曇り」「雨」という選択肢のうちのどれか? である。つまり, 情報とは「選択肢のうちどれか?」を表すことなのだ。

数値はひとつの選択肢である。例えば「今日正午の気温は23℃」というのは, 「℃」で表した時の気温としてありえる, -30くらいから50くらいまでの選択肢の一つである23を表している。逆に, 「選択肢のうちどれか?」は, 選択肢に番号を振っておけば, 「そのうちの何番?」という数値で表現できる。こう考えれば, 数値と選択肢は同じとみなせる。さっき, 情報は選択肢だ, と言ったので, 結局, 情報工学では情報と選択肢と数値は同じものとみなす。

!!ビット(bit)

最も小さな情報は, 「2つの選択肢のうちどちらか?」である(もし選択肢が1つだけなら, それはもはや選択ではない)。そのような情報をビットと呼ぶ。1ビットは「ひとつのスイッチ」に対応する情報だ。スイッチは, onかoffという, 2とおりの状態のうちのいずれかをとる。「スイッチひとつで表すことのできる情報」が1ビットである。計算機は中に膨大な数のスイッチを持っていて, そのon/offでデータを保持したり処理したりする。なので, 「ビット」という単位は, 計算機の構造とも馴染みが良い。

2つ以上の選択肢がある場合は, 複数のスイッチ(複数のビット)を使えばよい。例えば4つの選択肢がある場合は, スイッチAとスイッチBという2つのスイッチを用意して,
* 「AがoffでBもoff」を選択肢1
* 「AがoffでBがon」を選択肢2
* 「AがonでBがoff」を選択肢3
* 「AがonでBもon」を選択肢4
というふうに取り決めておけば, 2つのスイッチの状態で, 「どの選択肢が選ばれたか」がわかる。一般に, n個のスイッチのon/offでは, 「2のn乗の選択肢のどれか」を表すことができる。これを「nビット」の情報量という。では上述の例のように, 『「晴れ」「曇り」「雨」の3つの選択肢のうちどれ?』を表現する場合はどうすればいいだろう? 1ビット(2つの選択肢)では足りない。かといって2ビット(4つの選択肢)では余ってしまってもったいない。しかし足りないよりはましである。そこで, 2ビットとして扱う。その場合, 例えば,
* 「AがoffでBもoff」は晴れ
* 「AがoffでBがon」は曇り
* 「AがonでBがoff」は雨
* 「AがonでBもon」は欠番(使わない)
というふうに, 4つの選択肢のうちの一つは欠番とするのだ。

!!バイト(byte)

「1ビット」は概念としてはわかりやすいが, 実際の計算機が扱う情報は, もっとたくさんの選択肢からなる(上述の音楽の例のように)。その場合, 「ビット」は細かすぎて面倒である。そこで, 8ビットをひとまとめにして, 「1バイト」という単位で呼ぶ。1バイト=8ビットである。1バイトは, 2の8乗=256通りの情報を表現できる。これは, 化学で分子数を「個」でなく「モル」で表すのにちょっと似ている(1モル=6.02×10^23個)。


!!キロバイト・メガバイト・ギガバイト・テラバイト・ペタバイト

1024バイトを1キロバイト(1KB)と呼ぶ。「キロ」が1000でなくて1024なのは、1024が2の10乗という「きり」の良い数(2進数で)であり、なおかつ1000にかなり近い値だからである。1024KBを1メガバイト(1MB)、1024MBを1ギガバイト(1GB)、1024GB を1テラバイト(TB)、1024TBを1ペタバイト(PB)と呼ぶ。

!2進法(binary), 16進法(hexa-decimal)

!!!!2進法

計算機はビットが最小単位なので0か1という2通りの数が処理の基本である。そのため、数値は2進法で表現される。ある数を10進法表示からを2進法表示に変換するには、2で割って余り(0か1)を記述することを繰り返せばよい。例えば10進法表記の11を2進法表記に変換するには、11割る2は5 余り1、5割る2は2余り1、2割る2は1余り0、1割る2は0余り1だから、余りを右から順に並べて、1011となる。2進法を10進法に変換するには、2進法の第n桁の数(0か1)に2のn-1乗をかけ、足し合わせればよい。

*課題  10進法の29を2進法に変換せよ。(答え:11101)
*課題  2進法の10101010を10進法に変換せよ。(答え:170)

!!!!16進法

2進法は人間にとってあまりに煩雑なので、実際の表記上は4ビットをまとめて16を基数とする16進法を用いることもよくある。この場合、1バイト(8ビット)は4ビットのブロック2つぶんとみなすことができるので、16進法では1バイトは2桁の数字として表現される。16進法では、0〜9の数字に加えて、A, B, C, D, E, Fを, それぞれ(10進で)10〜15の数字に対応させる。16進法での表記は、10進法と区別するために"0x"を先頭に付記することがよくある。16進法では、 1バイトの非負整数は、2桁、つまり0x00から0xFFで表すことができる。16進法のほかに、同様の理由で3ビット相当を基数とする8進法が使われることもある。

*課題  10進法の183を16進法に変換せよ。(答え:B7)
*課題  2進法の10101010を16進法に変換せよ。(答え:0xAA)
*課題  16進法の0xD3を10進法に変換せよ。(答え:211)

!テキストとバイナリ (text & binary)

数値データを表現するときに、数字を文字として表現する方法と、数字を直接2進法で表現する方法がある。前者をテキスト形式、後者をバイナリ形式と呼ぶ。

テキスト形式の利点は、エディターなどで直接覗いたり編集したり印刷したりできることであり、また、数字以外の情報(データの属性や単位などの付帯情報)を含ませることも容易である。テキスト形式の難点は、データサイズが大きくなることである。たとえば10進で135という数をテキスト形式で表現した場合、"1", "3", "5"という3つの文字に対応する文字コードにそれぞれ1バイトを費やすため、3バイトのデータ量となるが、これを2進法で表現した場合は8ビットで収まるため1バイトのデータ量となる。また、文字コードのルールにはいくつかのバリエーションがあり、適切な文字コードで処理しないと読み書きできない(いわゆる、文字化けが起きる)。

バイナリ形式の利点・難点は、テキスト形式の裏返しである。また、バイナリ形式のデータは数字の羅列なので、どこが数字の切れ目になるのかというような情報を、外的に与えてやらねばならない。

!バイナリ形式

バイナリデータ(バイナリ形式のデータ)はバイトの羅列なので、それを意味のある数字として認識するには、いくつかのバイトのかたまりをどのようにしてひとつの数として認識するかというルール(形式)が必要である。それらは主に以下のようなものである:

    形式         名称        表現可能な数の範囲
    符号なし整数(1バイト) "unsigned char"    0〜255
    符号付き整数(1バイト) "signed char"    -128〜127
    符号なし整数(2バイト) "unsigned short"   0〜65535
    符号付き整数(2バイト) "signed short"    -32768〜32767
    符号なし整数(4バイト) "unsigned long"    0〜4294967296
    符号付き整数(4バイト) "signed long"    -2147483648〜2147483647
    浮動小数点実数(4バイト) "IEEE single float"  1.17549435E-38〜 3.40282347E38
    注: ↑上で, 「E-38」というのは, 「10の-38乗」を意味する。同様に, 「E38」というのは, 「10の38乗」を意味する。
    浮動小数点実数(8バイト) "IEEE double float"  とんでもなく広い範囲

!エンディアン

バイナリデータを認識する場合、複数バイトをひとまとまりとして認識する形式では、上位のバイト(桁の大きなほう)と下位のバイト(桁の小さなほう)を、どちらを先に記述するかが問題になる。これをバイトオーダー(byte order)もしくは'''エンディアン'''(endian)という。大きい桁を先に書くのが、我々の10進法の世界でも常識的であり、そのような記法、つまり上位バイトを先に書く方法をbig endianと呼ぶ(most significant byte firstとも言い、MSBもしくはMと略記することがある)。それに対して、下位バイトを先に書く方法をlittle endianと呼ぶ(least significant byte firstとも言い、LSBもしくはLと略記することがある)。これらは計算機の中央演算処理装置(CPU)の仕様で決まっている。つまり、全く同じソフトや同じOSを使っていても、CPUが違えばエンディアンが違う可能性がある。これは画像データの処理でしばしば大きな問題となる。

* big endianの例: SUN/sparc, IBM・Motorola・アップル/Power PCなど
* little endianの例: Intel/PentiumやIntel/CeleronなどのいわゆるIntelアーキテクチャ, Dec/Alphaなど

従って、異なるシステム間でバイナリデータををやりとりするときは、エンディアンを正しく認識し、随時、適切な形式に変換しなければならない。たとえば、一般に、画像データの多くはSunやIBMの計算機で処理されるので、バイナリの画像データをIntelアーキテクチャの計算機で処理するときには問題になることがある。

!テキスト形式

テキスト形式では、データを文字の並び, すなわち「文字列」で表現する。文字なので, 「123」のような数値だけでなく"Hello!"のような単語や文章も表現できる。ところが, その実体は, 数値の羅列である。どういうことかというと, あらかじめ, 各文字には「背番号」が振られてあり, 文字列はその「背番号」の羅列として表現されるのだ。すると, 当然ながら, どの文字にどの数値(背番号)が対応するかという「対応表」が大事になってくる。その対応表を「文字コード」と呼ぶ。

!文字コード
文字コードは, 世界のIT研究者や技術者が相談しあって, 共通のものがいくつか提案されている。

最も大事な文字コードは, 「アスキーコード」である:
*アスキーコード(ascii character code): 半角の英数字・記号等。各文字につき1バイトで表現される。漢字は入っていない。

アスキーコードは歴史が古く, コンピュータで漢字やひらがなが使えなかった頃(そんな頃もあったのです!)から使われてきた。というか, コンピュータの歴史の初期の頃は, アルファベットと数字だけを使うのでも大きな進歩だったのである。アルファベットの大文字と小文字, そして0から9までの数字, さらに, コンマ「,」やドット「.」, コロン「:」, ダブルクオート「"」などの記号(文字)をぜんぶあわせても100種類にもならないので, 1バイト(0から255, もしくは0x00〜0xFF)で十分に表現できる。なので, アスキーコードでは, 「1文字を1バイトの数値で表現する」という取り決めになった。

ところが, コンピュータが発達すると, 日本や中国では漢字を使いたいし, 韓国ではハングル文字を使いたいし, ...というように, 各国で独自に使われている文字もコンピュータで使いたくなったのである。そういうのは種類が膨大である。漢字だけでも(というか主に漢字のせいだが), 何千, 何万種類もある。それらをそれぞれ1バイトで表現するのは無理である(1バイトで表現できるのは256種類まで!)。そこで, それらを2バイト以上の数値で表現する文字コードがいくつか開発された:

*EUC: 漢字・かなを含めた、日本語文字と全角英数字記号の表現のひとつ。2000年頃までのUnixで主流。各文字につき2バイトで表現される。
*Shift-JIS(SJIS)EUC: 漢字・かなを含めた、日本語文字と全角英数字記号の表現のひとつ。Windowsで主流。各文字につき2バイトで表現される。
*[[UTF-8|http://ja.wikipedia.org/wiki/UTF-8]]: 日本語・中国語・アラビア語・韓国語など、世界の多くの言語の文字を統一的に表現する文字コード。現在のUnixで主流。各文字につき2バイト以上6バイトまでの数値で表現される。

EUC, SJIS, UTF-8の間には互換性が無い。だから, 例えばEUCで書かれた文書をUTF-8として表示すると, 「文字化け」を起こす。逆に言えば, 「文字化け」の原因の多くは, 書かれた文書の文字コードと, 表示しようとしているソフトの文字コードの食い違いが原因である。

ただし, これらの文字コードの多くは, (半角の)アルファベットや数字, コンマなどの記号は, 原則的にアスキーコードをそのまま使う。つまり, アスキーコードの拡張という形になっている。従って、(半角の)アルファベットや数字, コンマなどの記号だけで書かれたテキストデータなら, 実質的に文字化けの心配は不要である(なので, 大事なコメントや情報は英語で書こう!)。

* アスキーコードの例:"a"=97, "b"=98, "1"=49, "2"=50, "$"=36, " "=32
* EUCの例: "山"=46011=0xBBB3
* SJISの例: "山"=21134=0x8E52
* UTF-8の例: "山"=0xE5B1B1

さて, 実際にテキストデータを使っていて, 文字化けに出会ったらどうしたらいいだろうか? とりあえずUnix (Linux)のコンソールでテキストデータのファイル"data.txt"をcatコマンドなどで表示したら文字化けした! というような場合は, nkfというコマンドが助けてくれる:

    $ nkf -w data.txt
    もしくは,
    $ cat data.txt | nkf -w
    (-wはUTF-8への変換。EUCへの変換は-e。Shift-JISへの変換なら-s)

!改行コード

テキストデータには, もうひとつ厄介なことがある。同じ文字コードを使っていても、OSによって、改行コード(行の切れ目、つまり段落やパラグラフの終端を表すコード)は, OSによって異なることがあるのだ。実際、Windows, Macintosh, Unixのそれぞれで、改行コードは以下のようにバラバラに決められている:

    Windows:    13 10 (0x0D0A)
    Mac:            13 (0x0D)
    Unix:            10 (0x0A)

このため、例えばUnixで作られたテキストファイルをMacintoshやWindowsで表示しようとすると、うまく改行がされないことがある。

従って、異なるシステム間でテキストデータをやりとりするときは、文字コードと改行コードを正しく認識し、随時、適切な形式に変換しなければならない。たとえば、一般に、衛星データの多くはUNIXで処理されているので、衛星データに付随してくるテキスト形式のファイルをWindowsで処理しようとすると、問題になることがある。

改行コードは、UNIXのコンソールの上で、以下のようにすれば変換することができる:

    $ perl -pe 's/\r\n/\n/' winfile > unixfile
    $ perl -pe 's/\r/\n/g' macfile > unixfile
    $ perl -pe 's/\n/\r\n/' unixfile > winfile

参考ページ: http://www.rsch.tuis.ac.jp/~mizutani/online/with-pc/textline.html

!特殊なテキスト形式 ... CSV形式

表形式のデータを表現するために、「[[CSV形式|https://ja.wikipedia.org/wiki/Comma-Separated_Values]]」という特殊なテキスト形式がある。特殊といっても、表の列の区切りをカンマで表す、という約束があるだけだが。