一切都會好起來的
主要介紹原碼,反碼和補碼的概念。試着換個角度去看這個“人造”的概念。
原碼
我們平時的計數運算都是通過十進制來進行的,對於負數,我們就在十進制數前面加負號,但是對於數字電路來說,平時計算計數都是用二進制來進行的,這就涉及到一個問題那就是如何用二進制來表示負數。
一種方式就是類似於我們對十進制數操作那樣,我們在數字的前面加一位表示符號的位,叫符號位,符號位為0表示這個數是正數,符號位為1表示這個數是負數,這種形式的數成為原碼。
對於數字電路來說,加法運算我們可以通過加法器來實現,加法器我們可以通過異或門或者組合邏輯來實現,但對於減法器來說實現起來就沒有那么簡單了,這時我們用原碼來運算就比較麻煩了。我們希望能不能用容易實現的加法器來實現數字減法的操作,這里我們就要引入補碼的概念。
反碼,補碼
如何用加法來實現減法?對於正常的數值運算應該是做不到的,因為我們一般操作的時候數值的取值范圍是無窮大,但如果說我們做運算的范圍是在有限域之中,那情況就不一樣了。
舉個例子,對於一個有限域,他的數值域中是進行模12的操作,那么
通過有限域內取模的操作我們可以將\(10-5\)的問題轉化為\(10+7\)的形式,將減法轉換成了加法操作,我們就稱\(7\)是對模\(12\)的補數,也稱作為補碼(Complement)。
而對於數字運算來說,有限位的二進制運算也可以看作有限域,比如對於4位二進制加減運算,他的結果是有限的,只有16種可能的結果,我們就可以將減法運算通過有限維二進制隱含的取模操作來進行。
舉個例子,在不考慮符號位的情況下,
如果不再用減法器,只用加法器的情況下,舍棄最高位的進位,則可以用
因為四位二進制數的進位基數是\(16(10000)\),所以\(1001(9)\)恰好是\(0111(7)\)對模\(16\)的補碼。
從數學方面的角度,不包括符號位,只考慮數據位,對於有效數字位\(n\)位的二級制數\(N\),它的補碼\((N)_{COMP}\)可以表示為
即正數(當符號位為0時)的補碼與原碼相同,負數(當符號位為1時)的補碼等於\(2^n - N\)。注意大括號中參與其中運算的只有數值部分,而條件中\(N\)為負數,則包含符號位(要不哪來的負數之說)。如果考慮符號位,符號位保持不變。
為了避免在求補碼的過程中做減法運算,通常時先求出\(N\)的反碼\((N)_{INV}\),然后在負數的反碼上加一得到補碼。
二進制\(N\)的反碼\((N)_{INV}\)是這樣定義的
當\(N\)為負數時,\(N+(N)_{INV}=2^n-1\),\(n\)位全為\(1\)的二進制數表示\(2^n-1\)的十進制數,則\((N)_{INV}\)表示將二進制數按位取反的結果(因為加上按位取反,則每一位上全都是),在二進制電路中,取反操作是很容易實現的。
當\(N\)為負數時,\((N)_{INV}+1=2^n-N\),\((N)_{COMP}=2^n-N\),所以可以得到
即二進制負數的補碼為他的反碼加一,即除了符號位,按位取反再加一。
關於符號位,為什么符號位不參與求補碼的運算呢?
由前面的數學定義,參與運算的只有運算數的數值部分,符號是包含在條件之中的,那為什么符號數要保持不變,有會不會對運算產生影響呢
我個人的看法,首先對於一個數,我們要知道他是正是負,所以需要符號位,在運算的時候,符號位相當於后面數值位的進位。
舉個例子:
首先我們看一下四位二進制的原碼補碼表:
從圖上我們可以看到,當負數比較小時,后面數值位上的數值比較大,當負數比較大時,后面數值位上的數值比較小。
結合上面兩個圖,當13加上-10時,-10負數比較小,所以他的數值位數值比較大,和13的數值位相加會產生進位,進位和-10的符號位相加,符號位變成0,當-13加上10時,-13負數比較大,所以他的數值位數值比較小,和10的數值相加不會產生進位,所以最后的符號位還是1,如何讓定義數值的大小,還拿10舉例子,當相加的數是-10時,最后的結果是0,當相加數大於-10,數值位比較小,則數值位相加不會產生進位,當相加數小於-10時,數值位比較大,則數值位相加會產生進位。
需要注意的是,兩個同符號數相加時,它們的絕對值之和不能超過有效數字位所能表示的最大值,否則則會得出錯誤的計算結果,因為數值位相加產生了進位,影響到了符號位。