天天看點

計算機中的數(二)之原碼、補碼、反碼及其轉換

上一篇:計算機中的數之一 無符号數與有符号數

原碼

原碼是機器數中最簡單的一種表示形式,符号位為0表示正數,符号位為1表示負數,數值位即是真值的絕對值,故原碼又稱為帶符号的絕對值表示。譬如101的原碼是0,101。我們用逗号 " , " "," ","作為符号位和數值部分的分隔符。

原碼正數定義

[ x ] 原 = { 0 , x 2 n > x ≥ 0 2 n − x , 0 ≥ x > − 2 n [x]_原=\begin{cases} 0,x \quad 2^n>x\geq 0\\ 2^n-x,0\geq x>-2^n\\ \end{cases} [x]原​={0,x2n>x≥02n−x,0≥x>−2n​

解釋

正數比較好了解。負數需要稍微解釋下。為什麼是 2 n − x 2^n-x 2n−x呢?

我們舉個例子,具體體會下。比如-101這個二進制數将其表示為原碼表示法。根據原碼的含義我們直覺可以寫出1,101這個原碼來。但是要用數學式子定義該怎麼辦呢?很容易想到把101加個負号(負負得正)然後再加上一個1000就可以了。 1 , 101 = 1000 − ( − 101 ) = 1 , 101 1,101=1000-(-101)=1,101 1,101=1000−(−101)=1,101把這個具體的例子推向一般化就可以得到上述的公式了。

注意要點

這個定義有個問題?就是0的原碼表示有兩個。如果把0作為正數(0固然不是正數,隻是把0放到上面那個表達式裡計算原碼),那麼0的原碼就是 0 , 0 0,0 0,0,如果把0作為負數,那麼0的原碼就是 2 − 0 = 10 − 0 = 1 , 0 2-0=10-0=1,0 2−0=10−0=1,0。可見

[ 0 + ] 原 ≠ [ 0 − ] 原 [0_+]_原\neq[0_-]_原 [0+​]原​​=[0−​]原​

原碼小數定義

[ x ] 原 = { x , 1 > x ≥ 0 1 − x , 0 ≥ x > − 1 [x]_原=\begin{cases} x,\quad 1>x\geq 0\\ 1-x, \quad 0 \geq x>-1\\ \end{cases} [x]原​={x,1>x≥01−x,0≥x>−1​

解釋

這裡讨論的是純小數。

小數方面我們是使用小數點來作為符号位和數值位的分隔符的。譬如 − 0.101 -0.101 −0.101的原碼表示就是 1.101 1.101 1.101請注意小數點前面的1表示的是符号的意思。

首先正數自然很好了解,不作解釋。關于負數作少許解釋,思想與正數類同。首先舉例子: − 0.101 -0.101 −0.101直覺寫出原碼便是 1.101 1.101 1.101毋庸置疑。那麼怎麼用數學式子來求解呢?與上面相同我們考慮先将 − 0.101 -0.101 −0.101添個符号讓其變成正的,然後加1變得到結果咯。再将這個思想推廣為一般方法就得到上述的式子了。

注意要點

我們還是要讨論下0的小數原碼。

可以預見0的小數原碼還是有兩種。

當0取0.00時,正數的原碼為 0.00 0.00 0.00,負數的為 1.00 1.00 1.00。

總結

原碼中: [ 0 + ] 原 ≠ [ 0 − ] 原 [0_+]_原\neq[0_-]_原 [0+​]原​​=[0−​]原​

0的表示有兩個 0 − , 0 + 0_-,0_+ 0−​,0+​。這也就産生了一定的浪費。

補碼

補碼的引入背景是很有意思的。我們可以從鐘表中得到啟示。因為太長,這裡不做解釋。一般的數電課本或者計算機組成原理課本上都會做引入解釋,有興趣的讀者可以自行閱讀。

補碼整數表達式

[ x 補 ] = { 0 , x 2 n ≥ x ≥ 0 2 n + 1 + x 0 > x ≥ − 2 n ( m o d 2 n + 1 ) [x_補]=\begin{cases} 0,x \quad 2^n\geq x \geq0\\ 2^{n+1}+x \quad 0>x\geq-2^n(mod 2^{n+1}) \end{cases} [x補​]={0,x2n≥x≥02n+1+x0>x≥−2n(mod2n+1)​

解釋

一般而言要得到一個負數的補碼,隻要用模去加上這個數就行了。

注意

1.這裡的模是數值部分的位數n再加上1也就是n+1。為什麼模要是 2 n + 1 2^{n+1} 2n+1而不是 2 n 2^n 2n呢?舉個例子來解釋。比如 − 101 -101 −101如果用模3來求補碼: [ − 101 ] 補 = 1000 − 101 = 0 , 011 [-101]_補=1000-101=0,011 [−101]補​=1000−101=0,011這樣就和正數的補碼産生沖突了。是以我們用模 2 n + 1 2^{n+1} 2n+1來求負數的補碼。這個例子就是

[ − 101 ] 補 = 10000 − 101 = 1 , 011 [-101]_補=10000-101=1,011 [−101]補​=10000−101=1,011這樣就符合了我們的了解了。

補碼小數表達式

[ x ] 補 = { x 1 > x ≥ 0 2 + x 0 > x ≥ − 1 ( m o d 2 ) [x]_補=\begin{cases} x\quad 1>x\geq0\\ 2+x\quad 0>x\geq-1(mod2) \end{cases} [x]補​={x1>x≥02+x0>x≥−1(mod2)​

解釋

負數可能比較難了解。為什麼是 2 + x 2+x 2+x呢?

首先我們舉個例子一個數值位有三位的小數x。

x m a x = 0.111 x_{max}=0.111 xmax​=0.111與1差了0.001,但是我們直接用1去加的話就隻能得到0.001這同樣産生了沖突。是以要用2來加。

關于0的補碼

我們以整數為例子。 [ − 0 ] 補 = 100 − 000 = 100 [-0]_補=100-000=100 [−0]補​=100−000=100舍去1也就是00。

[ + 0 ] 補 = 0 [+0]_補=0 [+0]補​=0

是以

[ − 0 ] 補 = [ + 0 ] 補 [-0]_補=[+0]_補 [−0]補​=[+0]補​

這樣補碼就可以多表示一位負數。也就是上一篇文章(開頭有上一篇連結)為什麼int的表示範圍,負數比整數多一個的原因了。

反碼

反碼就比較容易了。他就是把原碼的每一位取反。這裡也給出數學表達式,有了前面補碼和原碼的學習,反碼的數學表達式易如反掌。

反碼整數表達式

[ x ] 反 = { 0 , x 2 n > x ≥ 0 ( 2 n + 1 − 1 ) + x 0 ≥ x > − 2 n [x]_反=\begin{cases} 0,x\quad 2^n>x\geq0\\ (2^{n+1}-1)+x \quad 0\geq x>-2^n \end{cases} [x]反​={0,x2n>x≥0(2n+1−1)+x0≥x>−2n​

反碼整數表達式

[ x ] 反 = { 0 , x 1 > x ≥ 0 ( 2 − 2 − n ) + x 0 ≥ x > − 1 ( m o d ( 2 − 2 − n ) ) [x]_反=\begin{cases} 0,x\quad 1>x\geq0\\ (2-2^{-n})+x \quad 0\geq x>-1 (mod(2-2^{-n})) \end{cases} [x]反​={0,x1>x≥0(2−2−n)+x0≥x>−1(mod(2−2−n))​

原碼、補碼、反碼 轉換方式 。

原碼-補碼

①每位取反 ②末位+1

不管是整數還是小數 原碼到補碼,補碼到原碼都可以這麼算。讀者可自行驗算幾個碼。

原碼-反碼

每位取反,反之亦然。

補碼-反碼

末位減一,反之末位加一