二進制補碼的數學原理

博客地址:https://www.cnblogs.com/jackieL/算法

做者: 梁言  spa

時間:2019年2月19日指針

最近在網上查了不少關於補碼的文章,要麼是長篇大論,要麼就是錯誤百出,因此我用簡單的語言把這個問題分析一遍,以便於你們理解記憶,若有錯誤歡迎留言指正。blog

 

一,「原碼」、「反碼」、「補碼」的基本概念同步

針對還不明白這幾個基礎概念的同窗們須要闡述一下,若是已經知道的同窗自行跳過。博客

一、「原碼」數學

就是二進制定點表示法,即最高位爲符號位,「0」表示正,「1」表示負,其他位數表示數字的值。it

如:十進制  6 = 二進制原碼 0000 0110 基礎

  十進制 -6 = 二進制原碼 1000 0110循環

二、「反碼」

正數的反碼與其原碼相同,負數的反碼是對其原碼逐位取反,符號位除外。

 如:十進制 6 = 二進制原碼 0000 0110 = 二進制反碼 0000 0110

   十進制 -6 = 二進制原碼 1000 0110 = 二進制反碼 1111 1001

三、「補碼」

正數的補碼與原碼相同,負數的補碼是在其反碼的末位加1。

如:十進制 6 = 二進制原碼 0000 0110 = 二進制反碼 0000 0110 = 二進制補碼 0000 0110

  十進制 -6 = 二進制原碼 1000 0110 = 二進制反碼 1111 1001 = 二進制補碼 1111 1010

 

2、「原、反、補」的產生緣由

由於計算機cpu只有加法運算器,沒有減法運算器,因此須要把減法轉換爲加法來作,因此天然就產生了「原、反、補」來將減法轉換爲加法計算。

雖然這個東西有點反人類,但畢竟是機器去使用它,咱們只須要明白就行。

 

3、「反碼」應運而生

 

二進制「反碼」很容易產生,由於cpu有一個二進制取反邏輯門電路,只要把「原碼」經過那個「門」出來就變成「反碼」了

「原碼」與「反碼」有一個特色:

以一個字節二進制數據爲例

十進制 -6 = 二進制原碼 1000 0110 = 二進制反碼 1111 1001

任意一個數的「原碼」加上這個數的「反碼」=> 10000 0110 + 1111 1001 = 0111 1111 結果是同樣的十進制127

=> "原碼"  +  「反碼」 = 127

=> "原碼" = 127 -  「反碼」

z 爲一字節二進制正數(就是須要咱們減去的數值),等式兩邊同時減去z

=>"原碼" - z = 127 -  「反碼」 - z 

=>("原碼" - z) = 127 -  (「反碼」 + z) 

由於 "原碼" = 127 -  「反碼」

因此(「反碼」 + z) 爲("原碼" - z)的「新反碼

反之("原碼" - z)(「反碼」 + z)的「新原碼

這樣就把減法轉換爲了加法。

若是沒有看懂同窗沒關係,上圖=====>

4、」補碼「補漏洞

須要注意的是,當(「反碼」 + z)的值大於等於127時,計算結果就會出現錯誤

例如:十進制 8 = 二進制反碼 0000 1000

   十進制 6 = 二進制反碼 0000 0110

   十進制 -6 = 二進制原碼 1000 0110 = 二進制反碼 1111 1001

   6 + (- 6) => (反碼)0000 0110 + (反碼)1111 1001 = (反碼)1111 1111 =>(原碼)1000 0000 結果爲-0,負0在數學上是無定義的

     8 + (-6) => (反碼)0000 1000 + (反碼)1111 1001 = (反碼)0000 0001 =>(原碼)0000 0001結果爲1,明明8-6結果爲2啊,又出錯了

    (-6) + (-6) => (反碼)1111 1001 + (反碼)1111 1001 = (反碼)1111 1010 =>(原碼)1000 0101結果爲-13,明明-6-6結果-12,又出錯了

錯誤是如何產生的了?

由於一個字節二進制的 0000 0000 有8個bit

這個二進制數字的排列數就有2^8個,結果就是256個排列數,256除以2等於128,就是有128種排列用於表示負數,128種排列來表示正數,

(如上圖)原反碼的圓盤只有127個指針數,跟一字節二進制自然的排列數128週期相比就少一個指針數

這樣就致使「原、反碼」算法的循環週期和二進制天然的循環週期不一致,不一樣步而產生錯誤。

 

 引入」補碼「

求 "原碼" + 」補碼「?

由於」補碼「 = 」反碼「 + 1 

=>   "原碼" + 」補碼「 = "原碼" + 」反碼「 + 1 

由於 "原碼" + 」反碼「 = 127

=>  "原碼" + 」反碼「 + 1 = 127 + 1 = 128 

=> "原碼" + 」補碼「 = 128

=> "原碼"  = 128 -  」補碼「

設 爲一字節二進制數(就是須要咱們減去的數值),等式兩邊同時減去z

=> "原碼"  - z = 128 -  」補碼「 - z

=> ("原碼"  - z) = 128 - (」補碼「 + z)

同理(」補碼「 + z)是("原碼"  - z)的新補碼。

這樣咱們就至關於把圓盤刻度增長一位值(見下圖)。

 

這樣算法週期和二進制排列數週期就相匹配了。

須要注意的是:

二進制128個排列是用來表示-128到-1的

二進制128個排列是用來表示0到127的

因此一字節二進制能表示帶符號數的範圍是-128到127.

規定-128 用 1000 0000(補碼) 表示,這個二進制很特殊它減1的效果和它取反的值同樣,因此它的原碼和補碼相等。

-1用 1111 1111(補碼)表示。

相關文章
相關標籤/搜索