C語言關於補碼的解釋及誤區

來源:互聯網
上載者:User

 

在中文的C語言教材中,總有些人被原碼、反碼、補碼弄得暈頭轉向,下面的文章寫的不錯,闡述明了,特轉載之……

(其實我也覺得反碼之類的東西是有些人自作聰明弄出來的定義,反而弄得人暈頭轉向,有時候簡單挺好)

本文開始:

關於補碼,看過一些書籍和網文,基本都是在“求反加一”的方法、步驟上反覆強調,而對於補碼的本質和定義,討論的不足。這就對初學者的造成了誤導,使得很多人都糾結在-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 位字長的補碼定義為:

       (1)  X ;                 0 <= X <= +127 (正數和0的補碼,就是該數字本身)
  [X]補 =
     (2)  2^8 -|X| ;    -128 <= X < 0 (負數的補碼,就是用 1 0000 0000(2的8次方),減去該數位絕對值)

例如 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的補碼,有個溢出的現象,很多人都在這裡被弄瘸了很長時間。
原碼和反碼也只不過是“人工”進行“求反加一”時的中間過程,在電腦裡面根本是不存在的,它們也就沒有絲毫用處。

做而論道的建議
求取補碼,就按照定義的規定,負數採用“模減去絕對值”的方法來求,這是求補數的通用方法,適合於各種進位、各種大小的數字。
不要用求反加一的方法,也就不用理會原碼和反碼了,也不牽涉符號位的問題。
以後的計算,也就沒有必要特殊說明:“符號位一起參加運算...”,因為根本就沒有什麼符號位。

如果把原碼和反碼、符號位等等垃圾概念,從電腦的書中刪減掉,學習補碼將會省力不少。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.