こんばんは。あんみつです。
今日は「符号付き2進数」の計算で用いる「2の補数」について解説します。
はじめに
この記事はコンピュータの基礎知識を勉強されている方に向けた内容です。
以下についてはある程度理解している前提での解説となっております。
・2進数⇔10進数の変換
・ビットとバイト
・C言語の基礎
unsigned charとsigned char(@C言語)
C言語のデータ型でサイズが1バイトなのはchar型ですので、
char型にて説明します。
unsigned charとは、符号なし1バイト
signed charとは、符号付き1バイト
をそれぞれ表します。このとき、
unsigned charで取りうる値 : 0 ~ 255
signed charで取りうる値 : -128 ~ 127
となります。
まず、unsigned charの取りうる値が 0 ~ 255 ということは、
1バイトの2進数で表現できる最小値と最大値を考えるとわかるかと思います。
最小値:0000 0000 ← 10進数では「0」
最大値:1111 1111 ← 10進数では「255」
signed charの計算方法について用いるのが「2の補数」です。
2の補数
「符号付き2進数」とは、最上位ビットの「0」と「1」で正の数か負の数かを表現した2進数のことです。
最上位ビットが「0」なら正数、「1」なら負数という見方をします。
正数の取りうる値を考えるとき、符号付きの場合は最上位ビットを除外して考えます。
すると、
0000 0000 が 0
0111 1111 が 127
です。
これで最大値が127であることはわかりました。
では「-1」は符号つき2進数でどう表現するか?
その計算方法に「2の補数」を用います。
まずは2進数で「1」を示します。
0000 0001
これの「1の補数」を求めます。
「1の補数」とはビットをまるまる反転させることです。
#ちなみに、「足すとオール1にするために補う数」なので「1の補数」と呼ばれているそうです。なるほど。。。
1111 1110
この状態から1ビット足した値を「2の補数」と言います。つまり
1111 1111
これが符号付き2進数の「-1」です。
同じ理屈で、2進数で「128」を示します。
1000 0000
これの「1の補数」は以下です。
0111 1111
この状態から1ビット足して「2の補数」にします。
1000 0000
これが符号付き2進数の「-128」(最小値)になります。
つまり符号付き2進数の負の数の表現は
1111 1111 ⇒ -1
1111 1110 ⇒ -2
・・・
1000 0000 ⇒ -128
と、1ビット目から7ビット目まですべて立った状態が「-1」で、
そこから一つずつ減らしていって最上位ビット以外が全部が0になった値が最小値となります。
2の補数の便利な特徴
2の補数は「2回繰り返すと元の値に戻る」というとても便利な特徴があります。
試してみましょう。
0000 0001
↓ 2の補数を計算
1111 1111
↓ 2の補数を計算
0000 0001
0101 1010
↓ 2の補数を計算
1010 0110
↓ 2の補数を計算
0101 1010
たしかに戻ります。
そもそもなぜ負の数の算出に「2の補数」を使うのか
signed char(符号付き1バイト)の負の数は、
2の補数を使えば求められることはわかりました。
ではなぜそのように表しているのでしょう?
理由は、引き算が「負数の作成」+「足し算」の組み合わせで表現できるようになるためです。
以下の例で試してみます。
123-86=37
上記は普通に10進数での計算結果です。
123は2進数で
0111 1011
です。
86は2進数で
0101 0110
ですので、「-86」を2の補数で作ると、
1010 1010
になります。
0111 1011
と
1010 1010
を足すと、
1 0010 0101
となります。
最上位の1ビットを桁あふれ扱いすると、
0010 0101(10進数で37)という結果になります。
まとめ
・符号付きデータ型の負数の計算には「2の補数」を使う
・「2の補数」とは、全ビットをひっくり返して、1ビット足した値のこと
・「2の補数」は、2回繰り返すと元の値に戻る
です!
いかがでしたでしょうか。
わかりにくい点、間違いがありましたら修正いたしますのでご指摘いただければと思います。