關於補碼,看過一些書籍和網文,基本都是在“求反加一”的方法、步驟上反復強調,而對於補碼的本質和定義,討論的不足。這就對初學者的造成了誤導,使得很多人都糾結在-128的補碼求取過程中。
關於反碼和原碼,大家都是在鄭重其事的講解,其實,學過的人都知道,它們的重要性是 0 !
做而論道把自己對於補碼的認識寫在下面,但願對讀者有些幫助。
加法器
計算機里面,只有加法器,沒有減法器,所有的減法運算,都必須用加法進行。
即:減去某個數字(或者說加上某個負數)的運算,都應該研究如何用加法來完成。
模、補數
在日常生活當中,可以看到很多這樣的事情:
把某物體左轉 90 度,和右轉 270 度,在不考慮圈數的條件下,最終的效果是相同的;
把分針倒撥 20 分鍾,和正撥 40 分鍾,在不考慮時針的條件下,效果也是相同的;
把數字 87,減去 25,和加上 75,在不考慮百位數的條件下,效果也是相同的;
……。
上述幾組數字,有這樣的關系:
90 + 270 = 360
20 + 40 = 60
25 + 75 = 100
式中的 360、60 和 100,就是“模”。
式中的 90 和 270、20 和 40,以及 25 和 75,就是一對對“互補”的數字。
知道了“模”,求某個數字的“補數”,就是輕而易舉的了:
如果模為 365,數字 120 的補數為:365 - 120 = 245。
用補數代替原數,可把減法轉變為加法。出現的進位就是模,此時的進位,就應該忽略不計。
二進制數的模
前面說過的十進制數 25 和 75,它們是 2 位數的運算,模是 100,即 1 的后面加上 2 個 0。
如果有 3 位數參加運算,模就是 1000,即 1 的后面加上 3 個 0。
這里的 1000,是十進制數的一千,可以寫成 10^3,即 10 的 3 次方。
推論:有多少位數參加運算,模就是在 1 的后面加上多少個 0。
對於二進制數字,模也是這樣推算。
如果是 3 位二進制數參加運算,模就是 1000,即 1 的后面加上 3 個 0;
那么當 8 位二進制數參加運算,模就是 1 0000 0000,即 1 的后面加上 8 個 0。
16 位二進制數參加運算,模可就大了,是 1 的后面加上 16 個 0。
注意:這里提到的 1、0,都是二進制數。
8 位二進制數的模可以按照十進制寫成 2^8,即 256。
16 位數二進制數的模,就是 2^16,按照十進制,它就是 65536。
二進制數的補碼
求二進制數的補數,目的是往計算機里面存放。
在計算機里面,存放的數字什么的,都稱為機器碼;那么二進制形式的補數,也就改稱為補碼了。
一般情況下,都是以 8 位二進制數來討論補碼,少數也有用 16 位數的。
計算時加上正數,是不需要進行求取補數的;只有進行減法(或者加上負數),才需要對減數求補數。
補碼就是按照這個要求來定義的:正數不變,負數即用模減去絕對值。
已知一個數 X,其 8 位字長的補碼定義為:
/ X 0 <= X <= +127 ;正數和0的補碼,就是該數字本身
[X]補 = |
\ 2^8 -|X| -128 <= X < 0 ;負數的補碼,就是用 1 0000 0000,減去該數字的絕對值
例如 X = -126,其補碼為 1000 0010,計算方法如下:
1 0000 0000
- 0111 1110
-----------
1000 0010
可以看出,按照補碼的定義來求補碼,概念十分清晰,方法、步驟也是十分簡單的。
應用補碼進行計算
用補碼計算:83-25=58。
83 ---都變成補碼,再用加法運算--> 0101 0011
- 25 -> 1 0000 0000 - 0001 1001-> + 1110 0111
----- --------
58 <--忽略進位1,結果就是正確的--[1] 0011 1010
計算結果如果超出了-128~+127的范圍,結果將是錯誤的,這是沒有辦法糾正的。
應用補碼進行計算,完全符合前面介紹的“用補數可把減法轉換成加法”的做法,只要忽略進位(這個進位1,就是求補的時候,加進去的1 0000 0000中的1),結果就是正確的。
這些關於補數、補碼的定義、方法、步驟,讀者如果看懂了前面的文字,相信大家自己都可以總結出來。
那么為什么總有些網友要提出關於求取補碼的問題呢?
在做而論道看來,就是因為很多教材和網文都在這個問題上“畫蛇添足”。
關於補碼的蛇足
補碼出現后,后人又補充了不少“蛇足”:符號位、求反加一、原碼、反碼......。
下面的表格給出了一些 8 位數的補碼。

--符號位
從這個表格中,可以看出特點:正數的最高位都是0,負數的最高位都是1。
這樣一來,有人就把最高位理解成了符號位。說什么是規定的用0代表正號,......。並且鄭重其事的補充說明:“符號位也參加運算”。真能忽悠!賣拐、賣車的都甘拜下風。
其實,前面說過的 補數 和 補碼的定義式 里面,根本就沒有什么符號位。這最高位的1、0是自然出現的,並不是由人來規定的。
--求反加一
負數補碼的后面七位,也可以看出一個不完全的規律:它們和絕對值之間存在着“求反加一”的關系。
於是,又有人推出了這個不同於定義式的算法。
--原碼和反碼
由於使用“求反加一”來求取補碼,順便又引出了 原碼 和 反碼 兩個垃圾概念。
其實,“求反加一”的計算方法只是適用於計算二進制形式的補數,它並不是通用的。
並且把“求反加一”用於求-128的補碼,有個溢出的現象,很多人都在這里被弄瘸了很長時間。
原碼和反碼也只不過是“人工”進行“求反加一”時的中間過程,在計算機里面根本是不存在的,它們也就沒有絲毫用處。
做而論道的建議
求取補碼,就按照定義的規定,負數采用“模減去絕對值”的方法來求,這是求補數的通用方法,適合於各種進制、各種大小的數字。
不要用求反加一的方法,也就不用理會原碼和反碼了,也不牽涉符號位的問題。
以后的計算,也就沒有必要特殊說明:“符號位一起參加運算...”,因為根本就沒有什么符號位。
如果把原碼和反碼、符號位等等垃圾概念,從計算機的書中刪減掉,學習補碼將會省力不少。
http://hi.baidu.com/%D7%F6%B6%F8%C2%DB%B5%C0/blog/item/d92cc986c2a1523bc75cc380.html