ハードを知らねばソフトは書けない,
コンピュータの中身を楽しく学ぼう
講師 矢沢 久雄
2進数でも同じ,負の値も補数で表す
コンピュータが実際に使っている2進数の補数を求める方法を説明しよう。ここでは,例として8けたの2進数を取り扱う。16けたでも32けたでも考え方は同じである。
00110101という2進数の補数は,この値に補数を加えると9けた目にけた上がりする値となる。この値は00110101の「0と1のパターンを逆にして1を加えたもの」として求められるが,感覚的に理解してもらえるだろうか。00110101の0と1のパターンを逆にした値は11001010であるが,この時点で2つの値を加えると1111111のようにすべてのけたが1である値になる。従って,パターンを逆にした値に1を加えた値にすれば,11111111に1を足すことになるので,順番にけた上がりしていって,100000000のように9けた目にけたが上がるはずである。
00110101の反転した値は,11001010。これに1を加えた11001011が00110101の補数になる。この手順は「反転して1加える」と覚えてほしい。実際に足し算してけたがあがるかどうかを確かめてみよう。
00110101 | ・・・もとの値 |
+11001011 | ・・・反転して1(補数)加える |
------------ | |
100000000 | ・・・加えるとけた上がりする |
実は,補数の裏技は,減算を実行するためだけではなく,負の値を表すためにも利用する。
例えば,01110111 - 00110101という減算は 01110111+(-00110101)と同じなのだから,00110101の補数11001011は-00110101を表していると考えることもできる*9。
ところが,ここで困った問題が生じてしまう。それは,同じ11001011という2進数であっても,それが負の値を補数で表しているのか,それとそのまま正の値を表しているのかが区別できないということである。そこで,1つのルールが取り決められている。
2進数の最上位けたが1のものは負の値を補数で表したものであり,最上位けたが0のものは正の値を表したものであるとするのである。11001011は,最上位けたが1なので補数で表された負の値であることがわかる。
このルールに従うと,8けたの2進数で表される数値の範囲がおのずと決まってくる。最上位ビットが0で正の値を表すのは00000000~01111111の範囲であり,最上位ビットが1で負の値を表すのは10000000~11111111の範囲である。2進数の00000000~01111111は,10進数の0~127となる。それでは10000000~11111111は10進数のいくつだろうか。これらの値は,もとの値を反転して1を加えたものである。逆算してもとの値を求めるには,1を引いて反転すればいいのだが,そんな面倒なことは暗算ではできない。
表3●データ型と補数使用の有無 |
補数を利用するかどうか,すなわち負の数を表すかどうかは,変数のデータ型によって決まる(表3[拡大表示])。BASICとC言語では,それぞれ実装が異なるので注意してほしい。C言語ではデータ型の先頭にunsignedを指定することで,補数を使わないことが明示的に示されるが,BASICの場合は8ビットのデータ型なら補数を使わず,16ビットのデータ型なら補数を使うという統一性のない仕様となっている。
コード化はプログラマの役目
引き続きハードウエアの観点から,コンピュータが取り扱うデータについて説明しよう。
言うまでもないことかもしれないが,コンピュータが取り扱うデータは,内部的にすべて数値となっている。ワープロ・ソフトの文字データも,お絵かきソフトのグラフィック・データも,ゲーム・ソフトの音声データも,すべて数値として処理されているのだ。さて,16進数で41というデータがあったとしよう。この値は,何を表しているのだろうか?
表4●味覚コード |
本来は数値でない文字や色など情報を数値で表すことを「コード化」と呼ぶ。文字であればすでに国際標準となったJISやシフトJISといったコード体系がある。とはいえ,プログラマが独自にコード化をしなければならない場合もある。例えば,食べ物の味を表す「味覚コード」というものを作ってみよう(表4)。ここでは,10進数で味覚コードを表している。
「あまからい」が「苦い」になる?
表5●味覚コード(改善案) |
例えば,「あまい」と「からい」を表すコードを加算してみよう。「あまからい」という意味合いの値になることを期待したいところだが,
「あまい」+「からい」 | = 1 + 2 |
= 3 | |
=「にがい」 |
加算しても影響の出ないコードを10進数で考えるのは難しいことだが,2進数で考えればすぐにできる。味覚の種類ごとに1とするけたをずらすのである。このコード化なら
「あまい」+「からい」 | = 00000001 + 00000010 |
= 00000011 |
図6●文字コード“A”と“B”の比較 例えばアルファベット順に並べるなどの用途を想定して,文字列はコード化されている |
「からい」-「あまい」 | = 00000010-00000001 |
= 00000001 | |
=「あまい」 |
何かをコード化するのも,コード化したデータをどのように演算するのかを決めるのも,すべてプログラマの役目だ。コンピュータには,プログラマのコード化の意図を知るすべがない。どのようなコード化を行っても,数値として演算するだけである。プログラマにとって重要なことは,どのような演算をするのかに応じて,適切にコード化することだ。
なお,コード化においては,データの比較を考慮する必要があることもある。例えば,文字データをアルファベット順に並べ替える処理を適切に行うためには,文字データを表わすコードがアルファベット順に大きくなっていなければならない。コード化された情報は,値の大小で比較するしかないからだ。実際に,JISコードにしてもシフトJISコードにしても,並べ替えを考慮したコード化がなされている(図6[拡大表示])。
2進数には論理演算
表7●OR演算の真理値表 |
表6●AND演算の真理値表 |
プログラムの中で論理演算が使われる場面には,条件分岐とデータ変換の2通りがある。条件分岐とは,if文を使って「もしも○○なら△△する」といった処理を行うことであり,データ変換とは,8けたの2進数の上位4けただけをすべて0にするといった処理を行うことである。条件分岐に関してはセミナーの第2回で取り上げるので,ここでは論理演算によるデータ変換の方法を説明しよう。
表9●NOT演算の真理値表 |
表8●XOR演算の真理値表 |
ここで注意してほしいのは,論理演算の結果は決してけた上がりしないことである。1けた以上の2進数で論理演算を行う場合には,対応するけたで論理演算する(図7[拡大表示])。けた数の異なる2進数の間では論理演算できない。また,NOT演算は2つの値ではなく,1つの値に対して実行するもので,いわば算術演算のマイナス記号のようなものである。まずこれらを,論理演算の大前提として覚えておいてほしい。
図7●8桁の2進数のAND演算 それぞれのけたで,AND演算をすればよい |
演算子は英語の意味をそのまま表している。それぞれを日本語に訳してみよう。ANDは「どっちも」である。2つの入力値が,どっちも1なら結果が1になる。ORは「どちらか」。2つの値のうち,どちらかが1になれば結果は1になる。両方とも1の場合も1だ。XORは「排他的(eXclusive)にどちらか(OR)」。どちらかが1の場合だけ1になる。両方とも1,あるいは両方とも0の場合は0になる。最後のNOTは一番簡単で「否定」である。入力値は1つで,1なら0,0なら1である。
論理演算をデータ変換に利用する
図8●AND演算によるクリア 1のけただけ残る。0とAND演算したけたは0にクリアする |
AND演算は,特定のけたの値だけをクリアして0にし,その他のけたの値をそのまま残すときに利用できる(図8[拡大表示])。例えば,01011100という8けたの2進数の上位4ビットだけを0クリアし,下位4ビットをそのまま残すなら,00001111という値とAND演算する。00001111を見て分かるように,0クリアしたいけたを0に,そのまま残したいけたを1にした値を使う,というのがポイントである。
図9●OR演算によるセット 1のけただけ,1になる。0とOR演算したけたはそのまま残る |
XOR演算は,特定のけたの値だけを反転し(図10[拡大表示]),その他のけたをそのまま残すために使われる。例えば,01011100という8けたの2進数の上位4ビットだけをすべて反転し,下位4ビットをそのまま残すなら,11110000という値とXOR演算を行えばよい。11110000を見てわかるように,反転したいけたを1に,そのまま残したいけたを0にした値を使うことがポイントである。
図10●XOR演算による反転 1のけただけ反転する。0とXOR演算したけたはそのまま残る |
まとめと次回予告
コンピュータのハードウエアの基礎から始めて,ICのピンから2進数へと話を展開してきたが,十分にご理解いただけただろうか。もしもプログラミングの経験が豊富でありながら,不可解なバグに遭遇してしまったなら,ハードウエアや2進数のレベルまで立ち返って,プログラム・コードを見直してほしい。解決の糸口が見つかることも多いはずだ。
図11●NOT演算による反転 すべてのけたが反転する |
【問題】補数を使って表された
11111111111111111111111111111111
という2進数は,10進数でいくつになるか?
答えは注釈に示しておこう。
さて次回は,「プログラミング手法」というテーマで,プログラミングの基本的な考え方を説明する予定である。お楽しみに。