search
LoginSignup
3
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

2の補数表現の考え方

はじめに

たまに「2の補数表現」がわかりづらいという意見がありますので
自分なりにイメージしやすいようにメモしました
2の補数表現を知らない方は「10進数で考える」まで読み飛ばしたほうがいいかもしれません

2の補数表現とは

2の補数(にのほすう)は、2、ないし2のべき乗の補数、またそれによる負の値の表現法である。特に二進法で使われる。
頭の部分の1個以上の0を含む(正規化されていない)ある桁数の二進法で表現された数があるとき、その最上位ビット (MSB) よりひとつ上のビットが1で、残りが全て0であるような値(8ビットの整数であれば、{100000000(2)=256})から、元の数を引いた数が2の補数である。MSBの重みが1であるような固定小数点表現の場合は特に「2」の補数となる。

refer from Wikipedia

要するに
「表現できる最大値に1を加えた値」を基準にプラスとマイナスの値を半々に割り振ったものである

2の補数の特徴

  1. bit数を「N」とおいたとき,表現できる値は「-2^(N-1)」から「2^(N-1)-1」となる
  2. 値がプラスの時最上位bitは「0」になり,マイナスの時最上位bitが「1」になる
  3. 2の補数で表現された2つの値を加算するとマイナスの値を加味した計算になる
  4. ビット反転して1を足すと符号が反転する
  5. 3.と4.の特徴より加算器をほんの少し改良するだけで加減算器にできる

10進数で考える

上の説明だけではイメージがつかないと思うので10進法で考えます
最大で表現できる桁を4桁だとします
『「表現できる最大値に1を加えた値」を基準にプラスとマイナスの値を半々に割り振ったものである』
より10000が基準に半々に割ると
-5000~+4999が表現できる範囲です(0は正の値として扱われます)
また10000を基準にプラスとマイナスを考えると
「+0~+4999」は「10000~14999」ですが4桁しか表現しないので「0000~4999」のまま
「-1~-5000」は「9999~5000」となり
「0000~9999」が定義できています
このことを踏まえて上記の「2の補数の特徴」内の5つの特徴について考えていきます

特徴1

桁数をNとすると-5*10^(N-1)~+5*10^(N-1)-1になる
つまり桁数を1から考えると
-5~4
-50~49
-500~499
・・・
となるわけです
正と負で半々に割って「0」の分を正に含むので正は「-1」となっているということです

特徴2

わかりづらいですが最上位の桁の値が正の時は4以下,負の時は5以上であるという意味です
2進数だと正の時は0以下,負の時は1以上なので0と1しかないのでまとめてあります
これは特徴1の定義域を考えると一目瞭然ですね

特徴3

例えば(-1)+(+5)をやろうとすると対応する値より
(9999)+(0005)=(10004)となり
4桁しか入りきれないので(0004)となります
なぜこのようにうまく計算できるかというと
(-1)は5桁目を無視できるという特徴からいいかえると(10000-1)です
そこで
(10000)+(-1)+(0005)=(10000)+(0004)= (10000)+(0004)
となりマイナスを考慮した演算になります

特徴4

10進数でビット反転に該当するものは足して「9」になる数字に変えるということです
4なら5,2なら7,0なら9とかです
つまりビット反転した値は「9999」から引いた値ということです
そのことを踏まえてビット反転した値に1を足してみると
(9999)-(XXXX)+(1)=(10000)-(XXXX)=(10000)-(XXXX)
となりマイナスの値になります

特徴5

計算機で加算を行う際は一番下の桁同士を足しあって繰り上がれば次の桁にその情報を渡して,
次の桁では同じ桁同士と先ほどの繰り上がりを足しあって繰り上がり情報を出して・・・
という風に筆算を行うように計算しています※
(※厳密には桁上げ先見構造が取られていたりしますが今回は気にしなくていいです)
桁ごとに同じことをやっているので
「2つの値」と「繰り上がりの値」から「その桁の値」と「繰り上がりの値」を出すパーツを桁数分つなぎ合わせることによって加算を行います

一度話が戻りますが特徴3,特徴4より減算を行うには片方をビット反転して1を足すことでマイナスにして加算すればいいわけです
なので
A-B=A+(反転B)+1と書けます

1@X = (反転X)
0@X = (X)
となるような式を使うと
A-B=A+(1@B)+1
と書けます

一方で加算は
A+B=A+(0@B)+0
とも書けます

なので減算したい時に1,加算の時は0という入力(s)を使うと
A±B=A+(s@B)+s
とまとめられます
ここでさっきのパーツについて考えると
1桁目には下の桁から繰り上がりの情報は来ませんので,減算するときは1桁目の繰り上がり値に1を入れればいいわけです
これによって簡単に加減算器ができるわけです

さいごに

自分が書いた内容を改めて見たのですが,結構読みづらいですね・・・
もう少し図も追加した方がいいかもしれません
見やすくなるような意見がある方はコメントを書いていただけるとありがたいです
もちろんそのほかのコメントも大歓迎です

長文になってしまいましたが読んでいただきありがとうございました
以上「2の補数表現の考え方」でした

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
3
Help us understand the problem. What are the problem?