二進制補碼的數學原理
博客地址: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(補碼)表示。
二進制補碼的數學原理