補(bǔ)碼

轉(zhuǎn)載需首行注明原地址

本章參考 車向泉老師的公開課《計(jì)算機(jī)系統(tǒng)中的數(shù)據(jù)表示》

目標(biāo):真正理解為什么要有補(bǔ)碼,明白補(bǔ)碼的各種性質(zhì)

目錄

  1. 原碼
  2. 模運(yùn)算
  3. 補(bǔ)碼
  4. 補(bǔ)碼的性質(zhì)
  1. 計(jì)算機(jī)不會存小數(shù)點(diǎn), 多一個小數(shù)點(diǎn),意味著數(shù)據(jù)需要多占一位,而且計(jì)算起來,需要拆分小數(shù)點(diǎn)后進(jìn)行運(yùn)算,所以計(jì)算機(jī)存的都是定點(diǎn)數(shù)(提前就拆分好,避免運(yùn)算時(shí)拆分)。
    而浮點(diǎn)數(shù)可以用兩個定點(diǎn)數(shù)表示,所以以下我們研究的各種存儲編“碼”都是針對定點(diǎn)數(shù)而言。

1. 原碼

大家都知道計(jì)算機(jī)里面存的是2進(jìn)制,而實(shí)際的數(shù)據(jù)是有正負(fù)之分的,為了標(biāo)識正負(fù),很容易想到給數(shù)加上一個進(jìn)制位。
于是就有了原碼,規(guī)定加0表示正數(shù),加1表示負(fù)數(shù)。

  • 定義:


  • 整體來講:
    原碼就是首位用0表示正數(shù),1表示負(fù)數(shù),所以非常簡單直觀。
    這種簡單和直觀會帶來很多個頭疼的問題:
    1 +0和-0,0不唯一了
    2 加減運(yùn)算及其復(fù)雜
    例如:要計(jì)算 A - B,首先要判斷A和B的數(shù)的正負(fù)和大小,以此來判斷最終的正負(fù)及運(yùn)算規(guī)則,比如A>B,A+B- (+表示正,A+表示A是正數(shù),同理,B-表示B是負(fù)數(shù)),那么實(shí)際上算A+|B|,如果A<B,A+B+,那么實(shí)際上應(yīng)該算 B-A,結(jié)果上放上負(fù)號,如果....
    無疑,這樣的設(shè)計(jì)放到運(yùn)算器上,可能今天就沒有PC了,那么這種運(yùn)算最致命的地方在哪里? 為什么會如此復(fù)雜?
    其根源在于: +-號無法帶入運(yùn)算,這時(shí),數(shù)可能是正負(fù),運(yùn)算可能是加減,同時(shí)A,B本身還有大小,則可能出現(xiàn)222共計(jì)16種情況。

  • 那么如何把+-號帶入計(jì)算機(jī)呢?
    首先必須了解計(jì)算最基本的運(yùn)算,然后帶入正負(fù),通過正數(shù)求負(fù)數(shù)。

2. 模運(yùn)算

計(jì)算機(jī)有個非常討人厭的且無可避免的情況,“溢出“,因?yàn)橛?jì)算機(jī)的字長是有限的,而計(jì)算的數(shù)可以生成無限的結(jié)果。那么當(dāng)計(jì)算出來的數(shù)超過字長,應(yīng)該怎么處理呢?

  • 一般來說有兩個處理方法,一個返回錯誤,一個將無法表示的位丟棄(溢出)。
  • 返回錯誤這當(dāng)然沒什么好說,盡管"溢出"同樣讓人"不爽"。但是還是應(yīng)該研究溢出,建立“溢出”模型。

于是便有了模運(yùn)算(這并不是歷史,我是瞎推測的)

模運(yùn)算定義:
在一個運(yùn)算系統(tǒng)內(nèi),若A、B、M滿足以下關(guān)系:A=B+K*M (K為整數(shù)),則記作A≡B(mod M)。

一個很形象的例子:時(shí)鐘,我把時(shí)鐘上任意一個時(shí)間,撥動一圈,它又回到撥動前的時(shí)間。而“溢出”的就是一個天的時(shí)間,這和計(jì)算機(jī)內(nèi)部非常像。

3. 補(bǔ)碼

知道了計(jì)算機(jī)最基本的運(yùn)算規(guī)則:有模運(yùn)算。那么應(yīng)該帶入正號來求出負(fù)數(shù)。
首先,還是規(guī)定首位為0就是正數(shù)。例如正數(shù)A。
那么負(fù)數(shù)可以看成:-A(0<=A<M,M為模)
已知:A=B+K*M ,可得 :-A = -A + M ,
同時(shí):已知0<=A<M , 可得 :(-A+M) > 0。
這相當(dāng)于用一個正數(shù) (-A+M) 表示出一個負(fù)數(shù) -A 。
同理可得,A = A+M。

由此,可以得出補(bǔ)碼的定義:
對于任意一個數(shù) X ,都有X = X + M (X mod M)。

推廣到計(jì)算機(jī)(假設(shè)字長為n),可以得到定義:


(注意:負(fù)數(shù)部分=號,是強(qiáng)制規(guī)定,例如8位字長機(jī)器碼對應(yīng)10000000,我們強(qiáng)制認(rèn)定為-128)

4.補(bǔ)碼的性質(zhì)

4.1 補(bǔ)碼的符號位

由此可知,首位0一定是正數(shù),首位1一定是負(fù)數(shù)。

4.2 補(bǔ)碼中的0唯一

4.3 補(bǔ)碼的范圍

假設(shè)機(jī)器字長為n。

  • 定點(diǎn)小數(shù):
    -1 <= x < 1- 2^(-(n-1)) ==> 1.0 ~ 0.111....1 (n-1個1)

  • 定點(diǎn)整數(shù):
    -2^(n-1) <= x <= 2^(n-1)-1 ==>1000...0 ~ 0999..9

4.4 補(bǔ)碼、真值、原碼間的相互轉(zhuǎn)換

4.4.1 真值 => 補(bǔ)碼

x為真值

  • 當(dāng) x >= 0 ,補(bǔ)碼==真值==原碼
  • 當(dāng) x <= 0

假設(shè)字長為n, |x|代表數(shù)值位
小數(shù):

      x補(bǔ) = 2 + x  // -1 <= x <=  2^(-(n-1)
          = 1+(1-2^(-(n-1)))-|x| + 2^(-(n-1)) // 1+ 0.111...1 - |x| + 0.000...1          
          = 符號位為一 + |x|全部位按位取反 + 末位加一 

          //x為-1時(shí),|x|=1,溢出了,結(jié)果為0。按位取反+1后繼續(xù)溢出為0,符號位設(shè)置1,結(jié)果剛好對-1(主要原因是-1這個是強(qiáng)制認(rèn)定的值)

整數(shù):

      x補(bǔ) = 2^n + x // -2^(n-1) <= x < 0
          =2^(n-1) + (2^(n-1)  - 1) - |x|  + 1
          =符號位為一 + |x|全部位按位取反 + 末位加一 

由此,得到一個經(jīng)驗(yàn)"按位取反,末尾加一"

然而,這個多了一個“加一”,計(jì)算機(jī)多跑了一次,有辦法優(yōu)化嗎?


我們發(fā)現(xiàn),可以從左往右早第一個1,1和1右邊的不變,左邊的按位取反。
例如 ,-0.10100100 ,可以一步寫出答案1.01011100。

4.4.2 補(bǔ)碼 => 真值

假設(shè)字長為n,x為補(bǔ)碼
小數(shù):

x真 = x - 2
    = -(1-2^(-(n-1)) - (x-1) +  2^(-(n-1))  // -(0.111..1 - 數(shù)值位 + 0.000...1)
    = -(補(bǔ)碼數(shù)值位按位取反 + 0.000...1)

整數(shù):

x真 = x - 2^n
    = -(2^(n-1)-1 - (x-2^(n-1)) + 1)// -(111...1 - 數(shù)值位 + 1)
    =- (補(bǔ)碼數(shù)值位按位取反 + 1)

同 真值轉(zhuǎn)補(bǔ)碼,補(bǔ)碼轉(zhuǎn)真值也可以優(yōu)化:
從左往右早第一個1,1和1右邊的不變,左邊的按位取反,再加上-號。

4.5 符號的擴(kuò)展

原則:擴(kuò)展后,不能影響大小。

正數(shù):
小數(shù)尾位補(bǔ)0,整數(shù)高位補(bǔ)0,因?yàn)檠a(bǔ)碼等于真值,所以擴(kuò)展后保持不變。

負(fù)數(shù):

  • 小數(shù):末尾補(bǔ)0
  • 整數(shù):高位補(bǔ)1

簡單證明下整數(shù):(注意,x為什么可以替換,因?yàn)槲覀兪菙U(kuò)展符號位,而x擴(kuò)展前后必須想等)


4.6 補(bǔ)碼的算術(shù)右移


所以,定點(diǎn)小數(shù),正數(shù)右移高位補(bǔ)0,負(fù)數(shù)高位補(bǔ)1

我們推導(dǎo)一下定點(diǎn)整數(shù):
正數(shù):

[1/2x補(bǔ)] = 1/2x = 1/2x補(bǔ)

負(fù)數(shù):

[1/2x補(bǔ)] = 2^n + 1/2x
         =2^n + 1/2(-2^n + x補(bǔ))
         =2^(n-1) + 1/2x補(bǔ)

所以,定點(diǎn)整數(shù),正數(shù)右移高位補(bǔ)0,負(fù)數(shù)高位補(bǔ)1

由此,可以得到結(jié)論,正數(shù)右移,高位補(bǔ)0,負(fù)數(shù)右移高位補(bǔ)1。

4.7 補(bǔ)碼的算術(shù)左移

這里主要的問題:算術(shù)左移會讓模變大,否則溢出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容