預備知識
二進制,十六進制,二進制與十進制的轉化運算
根據馮諾依曼結構的運算器,只有加法運算器,沒有減法運算器
所以,計算機中不是直接做減法,是通過加法來實現的。所以就必須引入一個符號位
原碼,反碼,補碼 的產生就是為了解決這個問題
原碼
最簡單的機器數表示法
原碼:
最高位表示符號位,1表示負,0表示正
其他位存放該數的二進制的絕對值
直接用原碼運算
0001+0010=0011 (1+2=3)正確
0000+1000=1000 ((+0)+(-0)=-0)
0001+1001=1010 (1+(-1)=-2)出錯
1001+1001= ?
原碼正數之間的加法通常不會出錯
正數與負數相加,或負數與負數相加,問題就出現了
所以,原碼直觀易懂,易於正值轉換,但用來實現加減法的話,運算規則總歸是太復雜,於是反碼來了
反碼
原碼最大的問題就在於一個數加上他的相反數不等於零,反碼的設計思想就是為了解決這一點
反碼:
正數的反碼=原碼
負數的反碼=原碼除符號位外,按位取反
我們試着用反碼運算
0001+1110=1111 (1+(-1)=(-0)) 有點問題,也正確
1110+1101=1011 (-1)+(-2)=(-4) 兩個負數相加,出錯
負數相加出錯,問題不大,我們只需要在兩個負數相加時,將兩個負數反碼包括符號位全部按位取反相加,然后再給他的符號位強置‘1’就可以了。
反碼表示法其實已經解決了減法的問題,他不僅不會像原碼那樣出現兩個相反數相加不為零的情況,而且對於任意的一個正數加負數,計算結果是正確的
然后就有了補碼
補碼
補碼:
正數的補碼=原碼
負數的補碼=反碼+1
負數的補碼的另外一種算法:
自低位向高位,尾數第一個1及其右部的0保持不變,左部取反,符號位不變
其實上面兩段話,都只是補碼的求法,而不是補碼的定義,基礎工作者並不會心血來潮的把反碼+1就定義為補碼,只不過是補碼正好就等於反碼加1罷了
暫時先忘記書上那句負數的補碼等於它的反碼+1,我們的理解陷入了誤區
這也是為什么《計算機組成原理》要特意先講補碼,再講反碼
接下來我們要重點講講補碼的思想
補碼的思想
為了理解,先得引入模和同余的思想
模 其實就是一個計量器的容量大小,比如鍾表的模M=12
同余 是指兩個整數A和B除以同一個正整數M,所得余數相同,比如1點和13點,2點和14點就是同余的,可以寫作
1 = 13 mod (12), 2 = 14 mod (12)
如果說現在時針現在停在10點鍾,那么什么時候時針會停在8點鍾呢?
這么說吧,因為過去2個小時前是8點,所以未來10個小時候也是8點
也就是說:倒撥2小時 或 正撥10小時 都是八點鍾
10-2=8,(10+10)mod(12)=8
所以,10-2和10+10從另一個角度來看是等效的,它都使時針指向了8點鍾
既然是等效的,那在時鍾運算中,減去一個數,其實就相當於加上另外一個數(這個數與減數相加正好等於12,也就是同余數)
我再次強調,原碼,反碼,補碼的引入是為了解決做減法的問題。在原碼,反碼表示法中,我們把減法化為加法的思維是減去一個數,等於加上一個數的相反數,結果由於引入符號位造成了各種問題
那你應該知道我要說什么了,利用模和同余的概念,我們可以使減法運算轉化為加法運算
而現在,我們不引入負數的概念,就可以把減法當成加法來算
所以接下來我們聊4位二進制數的運算,也不必急於引入符號位。因為補碼的思想,把減法當成加法時並不是必須要引入符號位的。
而且我們可以通過下面的例子,也許能回答另一個問題,為什么負數的符號位是‘1’,而不是正數的符號位是‘1’
四位二進制補碼運算實例
0110 - 0010 (6-2=4) 計算機中沒有減法器,不能直接算
但是現在你知道,減去一個數,可以等同於加上另外一個正數(同余數)
那么這個數是什么呢?時鍾運算中我們可以看出這個數與減數相加正好等於模M=12
四位二進制數的模(計量器)=四位二進制數最大容量=2^4=16=10000B
那么2(0010)的同余數,就等於10000-0010=1110(14)
既然如此
0110(6) - 0010(2) = 0110(6) + 1110(14) = 10100(16+4=20)
OK,我們看到按照這種算法得出的結果是10100,但是對於四位二進制數,最大只能存放4位(硬件決定),正好是0100(4)
,就是我們想要的結果,至於最高位的 1
,計算機會把他放入psw寄存器進位位中。8位機則會放在cy中,x86會放在cf中(不作討論)
這個時候,我們再想想在四位二進制數中,減去2,就相當於加上它的同余數14
但是減去2,從另外一個角度來說,也是加上(-2)。即加上(-2)和加上14其實得到的二進制結果除了進位位,結果是一樣的。
如果我們把1110(14)的最高位看作符號位后就是(-2)的補碼,這可能也是為什么負數的符號位是‘1’而不是‘0’,
而且在有符號位的四位二進制數中,能表示的只有‘-8~7’,而無符號位數(14)的作用和有符號數(-2)的作用效果其實是一樣的。
那正數的補碼呢?加上一個正數,加法器就直接可以實現。所以它的補碼就還是它本身。
到這里,我們發現原碼,反碼的問題,補碼基本解決了。
做減法時,0001(1)+1111(-1)=0000
,我們再也不需要一個1000
來表示負0
了,就把1000規定為-8
負數與負數相加的問題也解決了1111(-1)+1110(-2)=1101(-3)
為什么可以+1
然后我們再來看看為什么負數的補碼的求法為什么是反碼+1
因為負數的反碼加上這個負數的絕對值正好等於1111,再加1,就是1000,也就是四位二進數的模
而負數的補碼是它的絕對值的同余數,可以通過模減去負數的絕對值,得到他的補碼。
所以,負數的補碼就是它的反碼+1
算補碼的小技巧
如果我們把-8當成負數的原點。那么-5的補碼是多少呢?
-5 = -8 + 3
-5的補碼就是-8的補碼加3
1000(-8) + 0011(3) = 1011(-5)
也可以記住-1的補碼是1111
口算減法得出
1111(-1) - 0100(4) = 1011(-5)
對於八位加法器的話,可以把-128
當補碼原點。十六位可以把-32768
當補碼原點。
是的,128
是256
(八位二進制數的模)的一半,32768
是65536
(十六位二進數的模)的一半
也很方便有沒有,而且簡單的是
補碼原點總是最高位是‘1’,其他位是‘0’
感謝閱讀