組込みエンジニアになろう

/*** 初心者が基礎から組込みスキルを習得して、マイコンを操れるようになるサイト ***/

【C言語(2)】負数の表現

f:id:myra-sctech:20200813001602p:plain

前回の記事では、2進数が必要な理由として「スイッチ*1のON(1)とOFF(0)を考えやすくするため」であることを解説しました。

0と1しか使えない制約のなかで、どのようにしてマイナスの数(負数)を表現するのか、今回も基礎的な内容ですがしっかり習得していきましょう。

今回も最後に問題を用意していますので、理解度の確認に役立ててください。

 はじめに

マイナス記号(-)は使えません

負の数を表現するなら『-』記号を使えば良いのでは?と考えたくなりませんか。

たとえば-3は-0011(2)みたいな。

私は初めてプログラムの勉強をした時に思いました。だって、プログラムで引き算の計算を書くときには『-』記号を使うのですから。

だけど負の数を表現するのに『-』記号は使えないのです。

ここで前回の記事を思い出してください。

マイコンのプログラムはメモリに書き込まれていて、メモリにはON(1)とOFF(0)しかできないスイッチが数十~数百万個あるのでした。

このスイッチの組み合わせによって数値を表現します。

さて、この記事では簡単のためにスイッチ4個*2で話をしていきたいと思います。つまり、4個のスイッチだけで負数を表現しなければなりません。

初心者の頃の私・・・『スイッチでマイナス記号…どやって表現するねん!』と絶望しましたとさ。

 

スイッチ4個でいくつ数えられる?(復習)

前回の記事の復習になりますが、スイッチ4個でいくつ数えられるでしょうか?

0000(2)~1111(2)までですね。10進数で数えれば、0~15までです。

負数を表現しなくても良い場合には0~15まで数えることが出来ますが、負数を表現するようになるとどう変わるのか、そのあたりも注目してもらえればと思います。

それでは、負数の表現法を習得していきましょう!

 

負数の表現法

さっそくスイッチ4個で負数を表現する方法を紹介したいと思います。

私の知る限りでは3種類の表現法があります*3ので、それぞれ紹介したいと思います。

ただし、現在のマイコンで実際に使われているのは最後に紹介する『2の補数』と呼ばれる表現法です。古いマイコンではその他の表現法も使われていたようです。

 

① 符号仮数

素人がどうやって負数を表現するかを考えたときに、最初に思いつきそうな表現法です。

その表現法とは、符号(+/-)の役割を1番左のスイッチに与えるというものです。

つまり、1番左の数字を『+の時には0』、『-の時には1』として符号を表現します。このような表現法を『符号仮数部(ふごうかすうぶ)表現』と呼びます。

 たとえば、+3は0011(2)、-3は0011(2)の一番左を1(-)に置換えて1011(2)とします。

下の表を見てもらえると良く分かりますが、符号仮数部表現の特徴として、表せる数値の範囲は-7~+7です。

また、0の表現が+0:0000(2)と-0:1000(2)の2種類存在します。

なんというか…無駄ですね。

10進数 符号仮数
  +7     0111(2)
  +6     0110(2)
  +5     0101(2)
  +4     0100(2)
  +3     0011(2)
  +2     0010(2)
  +1     0001(2)
  +0     0000(2)
  -0     1000(2)
  -1     1001(2)
  -2     1010(2)
  -3     1011(2)
  -4     1100(2)
  -5     1101(2)
  -6     1110(2)
  -7     1111(2)

 

② 1の補数

『1の補数(ほすう)表現』は、負の数を表す場合に全てのスイッチを反転させる表現法です。

『反転させる』とは、1を0に、0を1に変換する操作のことです。

たとえば、+3は0011(2)、-3は0011(2)を反転させて1100(2)とします。

先と同様に下の表を見てもらえると良く分かりますが、1の補数表現の特徴として、表せる数値の範囲は-7~+7です。

また、0の表現が+0:0000(2)と-0:1111(2)の2種類存在します。符号仮数部と同じような特徴を持っています。

一番左のスイッチが1であれば必ず負の数なので、符号の判定は容易です。

10進数 1の補数
  +7    0111(2)
  +6    0110(2)
  +5    0101(2)
  +4    0100(2)
  +3    0011(2)
  +2    0010(2)
  +1    0001(2)
  +0    0000(2)
  -0    1111(2)
  -1    1110(2)
  -2    1101(2)
  -3    1100(2)
  -4    1011(2)
  -5    1010(2)
  -6    1001(2)
  -7    1000(2)

 

③ 2の補数

『2の補数(ほすう)表現』は、まず1の補数と同様に全てのスイッチを反転させ、その後1を足す表現法です。

反転させるだけであれば『1の補数』、反転させた後に1を足すと『2の補数』です。

たとえば、+3は0011(2)、-3は0011(2)を反転させた1100(2)に1を足して1101(2)とします。

なんだか先に紹介した2つと比較すると理解しにくい表現法に感じますが、2の補数の良いところは後で解説したいと思います。

 

ここで、2の補数の面白い特徴を紹介します。

先に紹介した2つの表現法では0の表現は2種類存在することが分かりました。では、2の補数を使って0000(2)の負数を計算するとどうなるか、試してみましょう。

0000(2)を反転すると1111(2)となります。

それに1を足すと、10000(2)となりますが、今は4つのスイッチしかありませんので、はみ出た1*4は無視して下位4桁のみを答えとします。

したがって、0000(2)の2の補数は0000(2)となり変化しません。

つまり、2の補数では0の表現は1種類のみとなります。

下の表を見てもらえると良く分かりますが、2の補数表現の特徴として、表せる数値の範囲は-8~+7です。

また、0の表現は0000(2)の1種類しか存在しません。

先に紹介した2つの表現法と同様に、一番左のスイッチが1であれば必ず負の数なので、符号の判定も容易です。  

もう少し後の記事でも解説したいと考えていますが、+7である0111(2)に1を足すと1000(2)となり、いきなり-8まで振り切るので注意したいところです。これも2の補数表現の特徴として押さえておきましょう。

10進数 2の補数
  +7    0111(2)
  +6    0110(2)
  +5    0101(2)
  +4    0100(2)
  +3    0011(2)
  +2    0010(2)
  +1    0001(2)
  +0    0000(2)
  -1    1111(2)
  -2    1110(2)
  -3    1101(2)
  -4    1100(2)
  -5    1011(2)
  -6    1010(2)
  -7    1001(2)
  -8    1000(2)

 

引き算は足し算? ~2の補数の良いトコロ~

実はマイコンが引き算を行うときには、足し算*5を行っています。

たとえば『3 - 2』の計算式は『3 + (-2)』と書けますよね。3という値と-2という値を足し算して引き算を実現しています。

それでは、これまでに紹介した負数の表現法を使用して、この計算を行ってみます。

答えは『1』となって欲しいですがどうでしょうか。

ここからは2進数の筆算を行いますが、計算の仕方は簡単です。

0と0を足せば0、0と1もしくは1と0を足せば1、1と1を足せば1繰り上がって0となります。

では、はりきって計算していきましょう!

 

符号仮数

『3 + (-2) = 0011(2) + 1010(2)

f:id:myra-sctech:20200812161757p:plain 

1101(2)は符号仮数部表現では『-5』を表します。

残念ながら、符号仮数部では『1』にはならないようです。

 

1の補数

『3 + (-2) = 0011(2) + 1101(2)

f:id:myra-sctech:20200812181059p:plain

桁の溢れが発生していますが、今は4桁で考えていますので、溢れた1は無視して下4桁を答えとします。

0000(2)は『+0』ですね。

残念ながら、1の補数においても『1』にはならない*6ようです。

 

2の補数

『3 + (-2) = 0011(2) + 1110(2)

f:id:myra-sctech:20200812221122p:plain

今回も1の補数と同様に桁の溢れが発生していますが、下4桁を答えとします。

0001(2)は『1』ですね。

2の補数で計算した結果のみが正しい答えとなりました!

他の値で計算してみても正しく答えが算出されます。

 

2の補数を使えば負の値を足し算することで、引き算を実現することが可能です。これが2の補数の良いトコロです。

 

 理解度チェック

この記事の内容をおさらいしておきましょう。

【答えを表示】をクリックすると回答例を表示します。

 

(1)0101(2)を2の補数で負数に変換してください。

 

1011(2)

((1011)2、0b1011でもOK!)

0101(2)を反転させて1010(2)、それに1を足して1011(2)です。

  

(2)2の補数で表された1001(2)を正数(プラスの数)に変換してください。

 

0111(2)

((0111)2、0b0111でもOK!)

正数 → 負数に変換する手順と全く同じ手順で負数 → 正数に変換できます。

1001(2)を反転させて0110(2)、それに1を足して0111(2)です。

  

(3)0x55を2の補数で負数に変換し、16進数で答えてください。

 

0xAB

((AB)16、AB(16)、AB'h、ABh、ABHでもOK!)

0x55は01010101(2)ですね。反転すると10101010(2)、それに1を足して10101011(2)となります。これを16進数に変換して0xABが答えです。

 

次回はデータの単位について解説します!

 

myra-sctech.hatenablog.com

 

/*** このサイトでは脚注を豊富に記載します ***/

*1:スイッチ:bit(びっと)と呼ぶのが正確ですが、簡単のためにスイッチとして紹介しています。

*2:スイッチ4個:4bitと呼ぶのが正確です。bitの話は、次の記事で紹介したいと考えています。

*3:3種類の表現法があります:本当はもう1つ、『ゲタ履き表現』というのもありますが、ここではややこしいので紹介しません。いつか浮動小数点と呼ばれる数値表現を解説することがあれば、『ゲタ履き表現』も紹介したい(紹介せざるを得ない)です。

*4:はみ出た1:計算を行って桁が溢れた1のことをキャリーと呼んだりします。

*5:足し算:マイコン内のCPUには、『加算器』と呼ばれる足し算を行う機構を備えてます。加算器だけで減算ができることを説明しています。

*6:1の補数においても『1』にはならない:実は1の補数においては、溢れた1(キャリー)を最後に足してあげることで正しい答えが出ます。