1. 程式人生 > >二進制補碼的數學原理

二進制補碼的數學原理

ont 產生 錯誤 特殊 inf === 分析 ron 需要

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

作者: 梁言

時間:2019年2月19日

最近在網上查了很多關於補碼的文章,要麽是長篇大論,要麽就是錯誤百出,所以我用簡單的語言把這個問題分析一遍,以便於大家理解記憶,如有錯誤歡迎留言指正。

一,“原碼”、“反碼”、“補碼”的基本概念

針對還不明白這幾個基礎概念的同學們需要闡述一下,如果已經知道的同學自行跳過。

1、“原碼”

就是二進制定點表示法,即最高位為符號位,“0”表示正,“1”表示負,其余位數表示數字的值。

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

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

2、“反碼”

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

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

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

3、“補碼”

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

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

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

二、“原、反、補”的產生原因

因為計算機cpu只有加法運算器,沒有減法運算器,所以需要把減法轉換為加法來做,所以自然就產生了“原、反、補”來將減法轉換為加法計算。

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

三、“反碼”應運而生

二進制“反碼”很容易產生,因為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)的“新原碼

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

如果沒有看懂同學不要緊,上圖=====>

技術分享圖片

四、”補碼“補漏洞

需要註意的是,當(“反碼” + 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

=> "原碼" - z = 128 - ”補碼“ - z

=> ("原碼" - z) = 128 - (”補碼“ + z)

同理(”補碼“ + z)是("原碼" - z)的新補碼。

這樣我們就相當於把圓盤刻度增加一位值(見下圖)。

技術分享圖片

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

需要註意的是:

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

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

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

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

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

二進制補碼的數學原理