二進制中補碼計算簡單詳實的講解

本文說明一個基本的問題,補碼的問題。
須要說明一點補碼是對負整數在計算機中存儲的一種形式;另外一種形式是負數在計算機中能夠用符號+負數絕對值的形式表示一個負數;好比(-3: 1000 0011存儲)可是這種表示的負數有兩個零+0,-0,最要命的一點是不能作算術運算。好比10-3=10+(-3)=0000 1010+ 1000 0011=1000 1101=-13顯然是錯的。因此負整數必須以補碼存儲。
負數在計算機中如何表示?
舉例來講,+8在計算機中表示爲二進制的1000,那麼-8怎麼表示呢? 
很容易想到,能夠將一個二進制位(bit)專門規定爲符號位,它等於0時就表示正數,等於1時就表示負數。好比,在8位機中,規定每一個字節的最高位爲符號位。那麼,+8就是00001000,而-8則是10001000。 
可是,隨便找一本《計算機原理》,都會告訴你,實際上,計算機內部採用2的補碼(Two’s Complement)表示負數。ui

在講補碼以前簡單介紹機器數,真值,原碼和反碼的背景。
一、機器數
一個數在計算機中的二進制表示形式,  叫作這個數的機器數。機器數是帶符號的,在計算機用一個數的最高位存放符號, 正數0,負數爲1。
1
好比,十進制中的數 +3 ,計算機字長爲8位,轉換成二進制就是0000 0011。若是是 -3 ,就是 1111 1101 。那麼,這裏的 00000011 和 1111 1101 就是機器數。 機器數包含了符號和數值部分。3d

二、真值
由於第一位是符號位,因此機器數的形式值就不能很好的表示真正的數值。例如上面的有符號數 1111 1101,其最高位1表明負,其真正數值是 -3 而不是形式值253(1111 1101按無符號整數轉換成十進制等於253)。因此,爲區別起見,將帶符號位的機器數對應的真正數值稱爲機器數的真值。 
例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –0111 1111 = –127;這裏所說的好比-3二進制代碼爲10000011,就是咱們計算機裏面對-3表示的源碼。下面介紹源碼 
首先說明一點 
在計算機內,有符號數有3種表示法:原碼、反碼和補碼。blog

三、原碼
原碼就是符號位加上真值的絕對值, 即用第一位表示符號, 其他位表示值. 好比若是是8位二進制 
[+1]原 = 0000 0001 
[-1]原 = 1000 0001 
由於第一位是符號位, 因此如果8位二進制數,其取值範圍就是: 
[1111 1111 , 0111 1111] 
即[-127 , 127] 
原碼是人腦最容易理解和計算的表示方式。部署

4 、反碼
反碼錶示法規定:正數的反碼與其原碼相同;負數的反碼是對其原碼逐位取反,但符號位除外。 
[+1] = [ 00000001 ]原碼 = [ 00000001 ]反碼; 
[-1] = [ 10000001 ]原碼 = [ 11111110 ]反碼; 
可見若是一個反碼錶示的是負數, 人腦沒法直觀的看出來它的數值. 一般要將其轉換成原碼再計算。源碼

什麼是二進制的補碼?
註明:正數的補碼與負數的補碼一致,負數的補碼符號位爲1,這位1便是符號位也是數值位,而後加1it

補碼借鑑的模概念,雖然理解起來有點晦澀難懂。能夠跳過
模的概念:把一個計量單位稱之爲模或模數。例如,時鐘是以12進制進行計數循環的,即以12爲模。 
在時鐘上,時針加上(正撥)12的整數位或減去(反撥)12的整數位,時針的位置不變。14點鐘在捨去模12後,成爲(下午)2點鐘(14=14-12=2)。從0點出發逆時針撥10格即減去10小時,也可當作從0點出發順時針撥2格(加上2小時),即2點(0-10=-10=-10+12=2)。所以,在模12的前提下,-10可映射爲+2。因而可知,對於一個模數爲12的循環系統來講,加2和減10的效果是同樣的;所以,在以12爲模的系統中,凡是減10的運算均可以用加2來代替,這就把減法問題轉化成加法問題了(注:計算機的硬件結構中只有加法器,因此大部分的運算都必須最終轉換爲加法)。10和2對模12而言互爲補數。同理,計算機的運算部件與寄存器都有必定字長的限制(假設字長爲16),所以它的運算也是一種模運算。當計數器計滿16位也就是65536個數後會產生溢出,又從頭開始計數。產生溢出的量就是計數器的模,顯然,16位二進制數,它的模數爲2^16=65536。在計算中,兩個互補的數稱爲「補碼」。好比一個有符號8位的數能夠表示256個數據,最大數是0 1 1 1 1 1 1 1(+127),最小數1 0 0 0 0 0 0 0 (-128);那麼第255個數據,加2和減254都是同樣的效果得出的結果是第一個數據 ,因此2和254是同樣的效果。對於255來講2和254是互補的數。 
求一個正數對應補碼是一種數值的轉換方法,要分二步完成: 
第一步,每個二進制位都取相反值,即取得反碼;0變成1,1變成0。好比,00001000的反碼就是11110111。 
第二步,將上一步獲得的反碼加1。11110111就變成11111000。因此,00001000的二進制補碼就是11111000。也就是說,-8在計算機(8位機)中就是用11111000表示。 
不知道你怎麼看,反正我以爲很奇怪,爲何要採用這麼麻煩的方式表示負數,更直覺的方式難道很差嗎?原理

二進制補碼的好處
首先,要明確一點。計算機內部用什麼方式表示負數,實際上是無所謂的。只要可以保持一一對應的關係,就能夠用任意方式表示負數。因此,既然能夠任意選擇,那麼理應選擇一種用的爽直觀方便的方式。 
二進制的補碼就是最方便的方式。它的便利體如今,全部的加法運算可使用同一種電路完成。 
仍是以-8做爲例子。假定有兩種表示方法。一種是直覺表示法,即10001000;另外一種是2的補碼錶示法,即11111000。請問哪種表示法在加法運算中更方便?隨便寫一個計算式,16 + (-8) = ?16的二進制表示是 00010000,因此用直覺表示法,加法就要寫成: 
 00010000 
+10001000原碼形式-8 
--------- 
 10011000 
能夠看到,若是按照正常的加法規則,就會獲得10011000的結果,轉成十進制就是-24。顯然,這是錯誤的答案。也就是說,在這種狀況下,正常的加法規則不適用於正數與負數的加法,所以必須制定兩套運算規則,一套用於正數加正數,還有一套用於正數加負數。從電路上說,就是必須爲加法運算作兩種電路。因此用原碼錶示負數是不行的。 
如今,再來看二進制的補碼錶示法。 
 00010000 
+11111000補碼形式-8 
--------- 
100001000 
能夠看到,按照正常的加法規則,獲得的結果是100001000。注意,這是一個9位的二進制數。咱們已經假定這是一臺8位機,所以最高的第9位是一個溢出位,會被自動捨去。因此,結果就變成了00001000,轉成十進制正好是8,也就是16 + (-8) 的正確答案。這說明了,2的補碼錶示法能夠將加法運算規則,擴展到整個整數集,從而用一套電路就能夠實現所有整數的加法。擴展

二進制補碼的本質,本質是用來表示負整數的
在回答二進制補碼爲何能正確實現加法運算以前,咱們先看看它的本質,也就是那兩個求補碼步驟的轉換方法是怎麼來的。下面描述了一個正數怎麼求它對應負數在計算機的表達方式。好比128,正數爲10000000,可是驚奇的發現-128也是10000000。可是這裏因爲屬於數據類型的限定,第八位一樣一個1表明不一樣的含義,前面的 1是數值位,後面數的 1是符號位。 
要將正數轉成對應的負數,其實只要用0減去這個數就能夠了。好比,-8其實就是0-8。用模數的概念解釋以下圖 
 
已知8的二進制是00001000,-8就能夠用下面的式子求出: 
 00000000 
-00001000 
---------- - - - 
由於00000000(被減數)小於0000100(減數),因此不夠減。請回憶一下小學算術,若是被減數的某一位小於減數,咱們怎麼辦?很簡單,問上一位借1就能夠了。 
因此,0000000也問上一位借了1,也就是說,被減數實際上是100000000,這是重點;算式也就改寫成: 
100000000 
-00001000 
---------- - - 
 11111000 
進一步觀察,能夠發現可分拆爲100000000 = 11111111 + 1,因此上面的式子能夠拆成兩個: 
11111111 
-00001000 
--------- 
 11110111取反 
+00000001加一 
--------- 
 11111000 
二進制的補碼兩個轉換步驟就是這麼來的。 
舉個例子,好比-128補碼的由來,先把正整數128二進制表示出來10000000求-128的補碼 
1 1 1 1 1 1 1 1 
-1 0 0 0 0 0 0 0 
--------- 
0 1 1 1 1 1 1 1 
+0 0 0 0 0 0 0 1 
--------- 
1 0 0 0 0 0 0 0 
即-128的補碼是10000000。8位的結構能表示的最小數是-128; 
因此能夠總結求補碼的範式是這樣的: 
求n位系統的一個數正數A : 01101101101……….11101100(n位二進制),怎麼求他的補碼呢,就用n位的1111111111111111111…..111(n位) - 11101101101……….11101100(n位二進制) + 1 = A的補碼就行啦!可是 
若是一個1111111111111…..111111(n位全爲1的正整數的補碼),要用1111111111111…….11111(n+1位) - 1111111111111…..111111(n位全爲1的正整數) +1 才能求的她對應的補碼。 
如uint16 A =200, uint16 B =65535,那麼C =A-B; 
65535的補碼:正數65535爲1111 1111 1111 1111,進行下面的計算求得B的補碼即-B;先展現有補碼符號位,即補碼有最高位位1的; 
1 1111 1111 1111 1111 -1111 1111 1111 1111 +1 =1 0000 0000 0000 0001,至關於被減數是10 0000 0000 0000 0000(18位) =1 1111 1111 1111 1111 +1 
由於A和B 都是16位的無符號數,因此65535的補碼最高位捨去,至關於被減數是1 0000 0000 0000 0000 =1111 1111 1111 1111 +1,便可以用上面的範式方法,可是這樣-B就沒有體現它的負數的符號位了;固然這是由於16位運算超出16位的位都捨去了。即-B=1;即A-B= 200+1 =201。其實也能夠用模數概念解釋A -B;以下圖正數的模數 循環


爲何正數加法也適用於二進制的補碼?
實際上,咱們要證實的是,X-Y或X+(-Y)能夠用X加上Y的2的補碼(-Y)完成。 
Y的二進制補碼等於(11111111-Y)+1。因此,X加上Y的2的補碼,就等於:X + (11111111-Y) + 1;咱們假定這個算式的結果等於Z,即 Z = X + (11111111-Y) + 1。 
接下來,分紅兩種狀況討論。 
第一種狀況,若是X小於Y,那麼Z是一個負數。這時,咱們就對Z採用補碼的逆運算,就是在作一次求補碼運算,求出它對應的正數絕對值,只要前面加上負號就好了。因此, 
Z = -[11111111-Z+1] = -[11111111-(X + (11111111-Y) + 1)+1)] = X - Y;這裏若是X Y Z都是無符號型的,且X < Y 那麼Z 最終獲得的數是|X-Y|距離的絕對值了,好比X=1,Y= 255,那麼Z=2,由於從255到1只要加兩次就到了。這裏你不要問我爲何,這裏就用到上面的模概念。 
第二種狀況,若是X大於Y,這意味着Z確定大於11111111,可是咱們規定了這是8位機,最高的第9位是溢出位,必須被捨去,捨去至關於減去嗎!因此減去100000000。因此, 
Z = Z - 100000000 = X + (11111111-Y) + 1 - 100000000 = X - Y 
這就證實了,在正常的加法規則下,能夠利用2的補碼獲得正數與負數相加的正確結果。換言之,計算機只要部署加法電路和補碼電路,就能夠完成全部整數的加法。
 硬件

相關文章
相關標籤/搜索