見出し画像

【コンピュータ】負の数を表す2の補数表現とは? 後編 2の補数を10進数にする裏技とは

こんにちは、すうじょうです。さて、今回は前回の2の補数表現の続きです。今回は、2の補数表現についてできるだけ分かりやすく解説していきたいと思います。後編では、10進数と2の補数表現、相互の変換方法についてできるだけ分かりやすく解説していきたいと思います。

※本記事は、2023/04/03に内容を改訂しました。

前編のおさらい

まず、前編の内容について軽く触れておきます。前編では、負の数を2進数で表現する別の方法として、「符号+絶対値」表現を説明して、その方法には欠点があり、2の補数表現はそれを克服しているということを説明しました。また、n桁(nビット)の2の補数表現の2進数で表せる数の範囲が、
$${-2^{n-1}~2^{n-1}-1}$$であることも言いました。特にこの範囲は、今回説明する計算のオーバーフローと関わってくるので、よくおさえておいてください。

10進数から2の補数表現への変換方法

まずは、10進数から2の補数表現への変換方法について説明します。そこで、まず2の補数表現において、ある正の数とそれに-を付けた数の関係を説明します。

正の数の各ビット(各桁の0,1のこと)を反転して、1を足したものがそれに-を付けた数となっています。ビットの反転というのは、0を1に、1を0に変えることで、1の補数をとったのと同じ結果となります。

例として、前編でも扱った3と-3を考えてみましょう。3を、4桁の設定で2進数に表すと0011です。そして、0011のビットを反転すると、1100です。これに1を足すと1101になります。この1101が-3を2の補数表現で表したものです。

前編でも同じ計算をしていますが、改めて確認します。-3+3=0を2の補数表現で計算します。1101+0011=10000ですが、4桁の設定なので5桁目を無視して0000となります。この結果は、10進数と一致します。

ここまでの説明をまとめて、一般的に以下のようにすれば10進数から2の補数表現が得られます。

まず、表したい数が設定された桁数で表せるか確認する。$${n}$$桁のとき、$${-2^{n-1}~2^{n-1}-1}$$の範囲しか表現できない。
正の数の場合
10進数を設定された桁の2進数にしたもの(最上位ビットは0)が補数表現となっている。
負の数の場合
① 10進数の絶対値を設定された桁の2進数にする。
② ①のビットを反転(1の補数をとる)して、1を足す。

以下に2の補数表現の例題と解答を示します。

例題1
次の10進数の数を5桁の2の補数表現で表しなさい。
(1) 4    (2)-4    (3)-10    (4)-16

[解答]
まず, 5桁で表現できる数の範囲を確認する.
$${-2^4~2^4-1}$$ = -16~15
(1) 4 = 00100
(2) (1)より, 00100をビット反転して, 11011
     これに1を足して, 11100
(3) 10 = 01010より, ビット反転して, 10101
     これに1を足して, 10110
(4) 16 = 10000(補数表現では16は範囲外だが、通常表現の5桁で考える)
     より, ビット反転して, 01111
     これに1を足して, 10000

※(4)のように、対象の数が設定された桁で表せる最小の補数表現の場合、絶対値は補数表現で表せる数の範囲外だが、便宜上補数を考えない場合の5桁で表して考える。

2の補数表現から10進数への変換方法とその裏技

ここまで、10進数の数を2の補数表現にする方法について確認しました。次は逆に2の補数表現から10進数に変換する方法です。まず、以下のように計算しているサイトや解説があります。

例題2
2の補数表現で表された10101を10進数で表しなさい。

[解答①]
10101をビット反転して, 01010
これに1を足して, 01011
これを10進数で表すと, 11である
よって, これにマイナスを付けると, -11

もちろん、この方法でも変換はできます。この方法は、10進数から2の補数表現への変換と同じことを行っています。しかし、実はもっと簡単に10進数にできる裏技的な方法があります。この記事ではそれを紹介したいと思います。そして、この裏技を使うために必要な知識を紹介します。

$${n}$$桁($${n}$$ビット)の2の補数表現の数があったときに、1桁目(最下位ビット)から$${n-1}$$桁目まではそれぞれ$${2^0=1の位, 2^1=2の位, 2^2=4の位, … , 2^{n-2}の位}$$です。そして次が重要です。n桁目(最上位ビット)が$${-2^{n-1}}$$の位であると考えます。すると、10進数への計算が普通の2進数のときと同様の方法で計算できます。

つまり、0か1に2の冪(べき、2の何乗かのこと)を掛けたものを足せば10進数が求まります。そして、このことから最上位ビットが1である2の補数表現の数は10進数にすると必ず負の数になることが分かります。(10進数が負の数であることと2の補数表現の最上位ビットが1であることは同値です)

この方法が正しいことをさきほどの例で確認してみます。

例題2
2の補数表現で表された10101を10進数で表しなさい。

[解答②]

$${(1×2^0)+(0×2^1)+(1×2^2)+(0×2^3)+(1×(-2^4))}$$
$${=1+0+4+0-16}$$
$${=-11}$$

この裏技で計算しても、-11となり、解答①と同じ結果となりました。解答①では、ビット反転して1を足してから10進数にしていましたが、このやり方ではいきなり10進数へと変換できます。ちなみにこの考え方を例題1にうまく使えば頭の中で考えるだけで答えを出せる人もいるかもしれません。特に(4)の-16はすぐに答えがわかる人が多いと思います。

演習問題

ここまでの内容について簡単な確認問題を用意したので、ぜひ解いてみてください。

問題1
次の10進数の計算を4桁(4ビット)の2の補数で行い, その結果を10進数で示しなさい。
(1) 1 + 3   (2) 6 - 2    (3) -3 - 2    (4) 4 + 5

[解答]
まず、4桁で表現できる数の範囲を確認する.
$${-2^3~2^3-1 = -8~7}$$
(1) 1 = 0001, 3 = 0011より, 1 + 3 = 0001 + 0011 = 0100 = 4
(2) 6 = 0110である。2 = 0010より, ビット反転して, 1101
     これに1を足して, -2 = 1110
     よって, 6 - 2 = 6 + (-2) = 0110 + 1110 = 10100
     4桁で表現するので, 5桁目の数字は無視して, 0100 = 4
(3)  3 = 0011より, ビット反転して, 1100
     これに1を足して, 1101
     (2)より, -2 = 1110
     よって, -3 - 2 = -3 + (-2) = 1101 + 1110 = 11011
     4桁で表現するので, 5桁目の数字は無視して,
     1011 = $${(1×(-2^3)) + (1×2^1) + (1×2^0) }$$= -8 + 2 + 1 = -5
(4) 4 = 0100, 5 = 0101より, 4 + 5 = 0100 + 0101 = 1001 = -8 + 1 = -7

※(2), (3)のような無視できる指定された桁より上の位に繰り上がった数のことをキャリーと呼ぶこともある。

演習問題で前編と本記事の内容をおおよそ復習できると思います。さて、この問題の解答を確認して、(4)の解答に疑問を持つ部分があるのではないだろうか。

(4)では、2の補数表現にして計算した結果-7が10進数の計算結果である9と違っている。そもそも9は4桁で表せる数の範囲外です。このため、計算結果が意図しないものになっています。このように、表せる数の範囲を超えていることによって、計算はできるが、正しい結果ではない結果が得られることをオーバーフローするといいます。オーバーフローとは、Wikipediaによると、

コンピュータの演算において数値型が表現可能な値の上限を超えること、およびそれによって発生したエラー。

とのことで、プログラミングにおいても計算結果が表現可能範囲を超えた時に発生します。

また、この問題にあったように2の補数表現で表した場合、引き算も負の数との足し算と考えて計算することができます。単純な方法では、足し算よりも引き算の方がコンピュータに計算させるには、複雑な構造が必要で時間がかかります。一方、2の補数表現ではこのような問題はありません。

最後に

ここまでの前後編でコンピュータに関する基礎知識である、負の数を表現する方法に関する説明は以上です。2の補数表現自体は知っていても、今回扱った裏技については、知らなかった人もいるかもしれません。この記事がどなたか1人でものお役に立てば幸いです。では。

以下の記事は、コンピュータで小数を表す方法である浮動小数点について解説したものです。

この記事が気に入ったらサポートをしてみませんか?