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

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

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

正文開始: spa

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

用補數代替原數,可把減法轉變爲加法。出現的進位就是模,此時的進位,就應該忽略不計總結

二進制數的模
前面說過的十進制數 25 和 75,它們是 2 位數的運算,模是 100,即 1 的後面加上 2 個 0。
若是有 3 位數參加運算,模就是 1000,即 1 的後面加上 3 個 0。
這裏的 1000,是十進制數的一千,能夠寫成 10^3,即 10 的 3 次方。
推論:有多少位數參加運算,模就是在 1 的後面加上多少個 0。 img

對於二進制數字,模也是這樣推算。
若是是 3 位二進制數參加運算,模就是 1000,即 1 的後面加上 3 個 0;
那麼當 8 位二進制數參加運算,模就是 1 0000 0000,即 1 的後面加上 8 個 0。
16 位二進制數參加運算,模可就大了,是 1 的後面加上 16 個 0。
注意:這裏提到的 一、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(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),結果就是正確的。

這些關於補數、補碼的定義、方法、步驟,讀者若是看懂了前面的文字,相信你們本身均可以總結出來。
那麼爲何總有些網友要提出關於求取補碼的問題呢?
在作而論道看來,就是由於不少教材和網文都在這個問題上「多此一舉」。

關於補碼的蛇足
補碼出現後,後人又補充了很多「蛇足」:符號位、求反加1、原碼、反碼......。
下面的表格給出了一些 8 位數的補碼。

--符號位

從這個表格中,能夠看出特色:正數的最高位都是0,負數的最高位都是1
這樣一來,有人就把最高位理解成了符號位。說什麼是規定的用0表明正號,......。而且鄭重其事的補充說明:「符號位也參加運算」。真能忽悠!賣柺、賣車的都甘拜下風。
其實,前面說過的 補數 和 補碼的定義式 裏面,根本就沒有什麼符號位。這最高位的一、0是天然出現的,並非由人來規定的。
--求反加一
負數補碼的後面七位,也能夠看出一個不徹底的規律:它們和絕對值之間存在着「求反加一」的關係。
因而,又有人推出了這個不一樣於定義式的算法
--原碼和反碼
因爲使用「求反加一」來求取補碼,順便又引出了 原碼 和 反碼 兩個垃圾概念。

其實,「求反加一」的計算方法只是適用於計算二進制形式的補數,它並非通用的。
而且把「求反加一」用於求-128的補碼,有個溢出的現象,不少人都在這裏被弄瘸了很長時間。
原碼和反碼也只不過是「人工」進行「求反加一」時的中間過程,在計算機裏面根本是不存在的,它們也就沒有絲毫用處。

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

若是把原碼和反碼、符號位等等垃圾概念,從計算機的書中刪減掉,學習補碼將會省力很多。

相關文章
相關標籤/搜索