雑記
2進法の話
最終更新:
匿名ユーザー
-
view
両手で1000まで数えられますか?
正確には0から1023まで。
知っている人には、簡単な問題ですが・・・。
知っている人には、簡単な問題ですが・・・。
両手をグーにします。これが、「0」の状態。
右手の親指を立てます。これが「1」の状態。
右手の人差し指を立て、親指は戻します。これが、「2」の状態。
右手の親指を立てます。これが「1」の状態。
右手の人差し指を立て、親指は戻します。これが、「2」の状態。
つまり、2進法で数えれば、2の10乗、つまり1024通りの状態を表すことができるわけです。
そんなわけで、2進法の話。
コンピュータはご存知のとおり、内部的に2進法で数値を表現しています。なんていうと難しそうですが、単純にスイッチのOn/Offの状態でしかありません。
直流で電圧が5ないしは3.3Vの時が「1」、0Vの時が「0」というわけです。
直流で電圧が5ないしは3.3Vの時が「1」、0Vの時が「0」というわけです。
したがって、つい今しがた述べた表現は正確ではありません。
実際には「2進法でしか数値を表現できない」というのが正しいのです。
実際には「2進法でしか数値を表現できない」というのが正しいのです。
スイッチのOn/Offによってしか内部の状態を現わせられないというのはいささか不便に感じる方もいるでしょう。
例えばアナログに近く、0Vの電圧なら0、3.3Vなら1、5Vなら2なんていう3進法でもいいじゃん、なんて思うかもしれません。
例えばアナログに近く、0Vの電圧なら0、3.3Vなら1、5Vなら2なんていう3進法でもいいじゃん、なんて思うかもしれません。
しかし、その方法ではデータの信頼性が低くなってしまうのです。
例えば、ノイズが乗ったり、電源の調子が不安定だったりした場合に、閾値(基準となる値)の周辺で電圧が上がったり下がったりしてしまいます。
そうすると、あるタイミングで見ると2になったり1になったりしてしまう可能性が出てしまうのです。
したがって、電圧が「高い」か「低い」の二つの状態しか持たせないようにすることでそういった揺らぎを防いでいるというわけです。
例えば、ノイズが乗ったり、電源の調子が不安定だったりした場合に、閾値(基準となる値)の周辺で電圧が上がったり下がったりしてしまいます。
そうすると、あるタイミングで見ると2になったり1になったりしてしまう可能性が出てしまうのです。
したがって、電圧が「高い」か「低い」の二つの状態しか持たせないようにすることでそういった揺らぎを防いでいるというわけです。
そう聞いて、「じゃあ例えば5VがOnで0VがOffの時でも2.5Vなんて電圧ならどうなるのか?」と思った方は鋭いです。
実は単純に「高い/低い」だけではなく、「ヒステリシス」と言われる特性を持たせてあることが多いです。
実は単純に「高い/低い」だけではなく、「ヒステリシス」と言われる特性を持たせてあることが多いです。
これは何かというと、自分の今の状態を維持しようとする特性のことです。と、言われても何のことやらって感じですよね。
つまり、0VがOff5VがOnだとします。今0Vの電圧だったとして、2.5Vではなく3.5Vくらいにあがって初めて「On」になる、また今5Vだったとすると今度は逆に2Vくらいまで下がった時にやっと「Off」になるというような感じです。回路としてはシュミットトリガ回路といいます。
話がだいぶそれたわけですが。
コンピュータが2進法を使うのは、それがコンピュータの構造とマッチしているからなんですね。
厳密に言えば2進法ではなくても、「0」と「1」のあるパターンをある数値に1対1で対応させさえすればいいわけですが。
厳密に言えば2進法ではなくても、「0」と「1」のあるパターンをある数値に1対1で対応させさえすればいいわけですが。
一つ一つのスイッチでは二つの状態しか表せないので、それをいくつか組み合わせてできるだけ多くの状態を表現するために2進法を使用しているわけです。
例えば、1バイトであらわせる数値は 0~255 ですが、これは8個の「0か1か」の状態の集合によって256種類の状態を作ることができるということです。8個のスイッチがあるということは、
2 × 2 × 2 × 2 × 2 × 2 × 2 × 2 = 256
ということです。
注目すべきは、「bit(スイッチ)が一つ増えるごとにあらわせる状態数が2倍になる」ということでしょう。
これによって少ないスイッチでたくさんの状態を表すことができるわけです。
例えば、32bit環境ではその名のとおり32bitが処理の基本なので、C言語のintで表せる数値は32本のスイッチで表せる範囲ということになります。これは1677万7216種類の状態を表せるということです。たかだか32個のスイッチでこれだけ大きな数値を表現することができるわけです。
では、マイナスの値はどうやって表すのでしょうか。
これによって少ないスイッチでたくさんの状態を表すことができるわけです。
例えば、32bit環境ではその名のとおり32bitが処理の基本なので、C言語のintで表せる数値は32本のスイッチで表せる範囲ということになります。これは1677万7216種類の状態を表せるということです。たかだか32個のスイッチでこれだけ大きな数値を表現することができるわけです。
では、マイナスの値はどうやって表すのでしょうか。
一般的には、最上位bitが1である場合はマイナスとみなされます。(もちろん、宣言する型による)
実際にはマイナスでない数値の2の補数となります。
実際にはマイナスでない数値の2の補数となります。
例えば。
int i = -1;
とした時のiは0xffffffffとなっています。
int i = -1;
とした時のiは0xffffffffとなっています。
2の補数とすることで、整合性が保てるようになります。例えば上のiに1を足すと、桁上がり・桁あふれが生じて結局0x00000000となるわけです。これは、-1に1を足して0になるわけですから、整合性が取れています。
ただし、プログラミングにおけるデータというのは、プログラマの意図によって使い分けることができます。
したがって上記のような数値としては2進数のデータも、プログラマの意図によっては違う意味と使い方を持たせることができます。
例えば、状態をbitで持つ、など。こうすると複数の状態をあらわすことができます。また、マルチタスクな環境などではタスク間のイベントを表すのにも使われたりします。
そういった使い方をする場合には、今度は2進法の数値としてではなく、一つ一つのbitが0か1かということが重要になるわけです。
こういったbitの使い方をフラグ、と言ったりもします。
このようなbitの使い方をする場合には、論理演算が極めて重要な意味を持つことになります。高校数学の「集合」と「命題」のあたりの知識があれば、難しくは無いのですが、忘れてしまったと言う方も多いでしょう。
例えばbit1が通信の接続状態(On/Off)をあらわしているとして、bit2が実際にデータをやり取りしているかどうかをあらわしているとすると、00000001かつ00000010であれば「通信中かつデータ送受信中」というステータスを表現できるわけです。これは「集合」の考え方です。
bitで表現するならば (00000001 | 00000010)となります。これは00000011という状態と等価です。
これを論理和といいますね。
bitで表現するならば (00000001 | 00000010)となります。これは00000011という状態と等価です。
これを論理和といいますね。
論理演算をここで述べると果てしなく長くなってしまうので割愛しますが、こういった論理演算によって1bitずつのbitを比較的容易に扱うことができます。
さて、このようにコンピュータの中で数値は2進法で管理されているわけですが、2進法は人間にはわかりにくく、かつ表現するのに資源(この場合は「文字数が多くかかる」と言うくらいの意味)を使ってしまいます。
したがって、数値として表す場合には2進法と相互の奇数変換のやりやすいn進法を使うことになります。
1byteが8bitである、と言うことを考えると、256進法で管理されていると言ってもいいのですが、256もの種類の状態を一桁で表そうとすると人間にとってわかりにくくなってしまいます。また、電卓などのCPUなどは未だに4bit µ-com使ってたりするので、その場合はそもそも「1byte」という単位を使いません(4bit = 1nibbleという単位を使います。)
実のところ、2の乗数進法であれば親和性は高いのですが、一般的によく使われるのは16進法でしょう。8進法もちょくちょく見かけることはありますが。
16進法であらわすと、1byte(8bit)は二桁であらわすことができます。これは256進法の一桁には比べられませんが、きわめて資源を節約して表現することができるわけです。そして、16種類くらいなら人間が直感的に把握するのに無理が無い状態数でもあります。
コンピュータはデータであれ、CPUに対する命令であれ、すべてをこうした「数値」で持っています。少なくとも、現在のデジタルコンピュータにおいては。
したがって、こういったコンピュータの「数値」を理解することは重要だと思います。