數的機器碼錶示——徹底弄清什麼是原碼、反碼、補碼、移碼

數的機器碼錶示


爲了妥善的處理數據運算過程中符號位的問題,於是就產生了把符號位和數值位一起編碼起來表示相應的數的各種表示方法。例如我們熟悉的原碼、反碼、補碼、移碼等。通常將未經編碼的數稱爲真值,編碼後的數稱爲機器數或者機器碼

  • 真值的形式正、負號加某進制數絕對值的形式,即數的實際值。如+3-5

  • 機器數的形式:真值按某種編碼方式進行編碼後的數值,即真值在機器中的表示,稱爲機器數,一般可以分爲 無符號數和有符號數兩種如:X=01011Y=11011

原碼

定點整數

若定點整數的原碼形式位xnxn1x1x0x_n x_{n-1}\cdot\cdot\cdot x_1x_0,其中xnx_n爲符號位,則原碼錶示的定義爲:
x[]={x0x<2n2nx=2n+x2n<x0 x_{[原]}=\left\{\begin{matrix} x & 0 \leqslant x<2^n \\ 2^n-x=2^n+|x| & -2^n<x\leqslant0 \end{matrix}\right.
在上式中,x代表的是真值。

例如,x=+7x=+7,化爲二進制表示爲x=+0111x=+0111;x[]=0111x_{[原]}=0111

x=7x=-7,化爲二進制表示爲x=0111x=-0111;x[]=23(0111)=1000+0111=1111x_{[原]}=2^3-(-0111)=1000+0111=1111

我們可以總結出來:

  • 對於正數x=+xn1...x1x0x=+x_{n-1}...x_1x_0,它的原碼是它自己本身,常常在最高位前面補0,代表它是一個正數。

    • x[]=0xn1...x1x0x_{[原]}=0x_{n-1}...x_1x_0
  • 對於0,根據原碼的定義則有兩種表示形式:

    • +0=+0n1...0100+0=+0_{n-1}...0_10_0
      • 此時正0的原碼爲+0[]=00n1...0100+0_{[原]}=00_{n-1}...0_10_0
    • 0=0n1...0100-0=-0_{n-1}...0_10_0
      • 此時負0的原碼爲0[]=10n1...0100-0_{[原]}=10_{n-1}...0_10_0
  • 對於負數x=xn1...x1x0x=-x_{n-1}...x_1x_0,它的原碼是在最高位前面補1,代表它是一個負數。

    • x[]=xn1...x1x0x_{[原]}=-x_{n-1}...x_1x_0

對於一個定點整數原碼xnxn1...x1x0x_nx_{n-1}...x_1x_0,最高位xnx_n代表符號位,用0來表示正數,用1來表示負數。而xn1...x1x0x_{n-1}...x_1x_0則代表的是數值位。它的大小就是該原碼對應真值的絕對值。

我們很容易求出它的範圍[(2n1),2n1][-(2^n-1),2^n-1]

定點小數

假設定點小數的原碼形式爲xs.x1x2...xnx_s.x_1x_2...x_n(實際上小數點是不存儲的),其中xsx_s代表符號位。則原碼的定義爲:
x[]={x0x<11x=1+x1<x0 x_{[原]}=\left\{\begin{matrix}x & 0 \leqslant x<1 \\ 1-x=1+|x| & -1<x\leqslant0\end{matrix}\right.

在上式中,x代表的是真值。

例如,x=+0.875x=+0.875,化爲二進制表示爲x=+0.111x=+0.111;x[]=0.111x_{[原]}=0.111

x=0.875x=-0.875二進制表示爲x=0.111x=-0.111;x[]=1.000(0.111)=1.000+0.111=1.111x_{[原]}=1.000-(-0.111)=1.000+0.111=1.111。 我們可以總結出來:

  • 對於正數x=+0.xn1...x1x0x=+0.x_{n-1}...x_1x_0,它的原碼是它自己本身,常常在最高位前面補0,代表它是一個正數。(注意,前面的0.實際上是不存儲的,也就是實際最高位是xn1x_{n-1})

    • x[]=0.xn1...x1x0x_{[原]}=0.x_{n-1}...x_1x_0
  • 對於0,根據原碼的定義則有兩種表示形式:

    • +0=+0.0n1...0100+0=+0.0_{n-1}...0_10_0
      • 此時正0的原碼爲+0[]=0.0n1...0100+0_{[原]}=0.0_{n-1}...0_10_0
    • 0=0.0n1...0100-0=-0.0_{n-1}...0_10_0
      • 此時負0的原碼爲0[]=1.0n1...0100-0_{[原]}=1.0_{n-1}...0_10_0
  • 對於負數x=0.xn1...x1x0x=-0.x_{n-1}...x_1x_0,它的原碼是在最高位前面補1,代表它是一個負數。(注意,前面的0.實際上是不存儲的,也就是實際最高位是xn1x_{n-1})

    • x[]=1.xn1...x1x0x_{[原]}=-1.x_{n-1}...x_1x_0

對於一個定點小數原碼 xs.x1x2...xnx_s.x_1x_2...x_n,最高位 xsx_s代表符號位,用0來表示正數,用1來表示負數。而x1x2...xnx_1x_2...x_n則代表的是數值位。它的大小就是該原碼對應真值的絕對值。

我們很容易求出它的範圍[2n1,12n2^{-n}-1,1-2^{-n}]

原碼的計算

​ 原碼雖然表示極爲簡單,但是最大的問題就是加法運算十分複雜

兩數相加時,我們需要考慮兩個數的符號,如果符號相同,我們可以把數值位直接相加,然後在最高位前邊添加上原來的符號位。但如果符號位不相同,那麼我們就要考慮進行減法運算。進行減法的時候,我們需要考慮數值位的絕對值大小來決定符號位。這也就是原碼運算的缺點:參與運算複雜,需要將數值位與符號位分開考慮。

反碼

當進行減法的時候,人們想到如何把減法變爲加法,那麼這樣會更加簡便,只靠加法器就可以完成運算。比如

11=01-1=0

00010001=00000001-0001=0000

1+(1)=01+(-1)=0

0001+1001=1010=20001+1001=1010=-2

顯然是計算錯誤的。

於是人們引入了反碼來表示負數。

定點整數

設定點整數的反碼形式爲xnxn1x1x0x_n x_{n-1}\cdot\cdot\cdot x_1x_0xnx_n代表符號位。


x[]={x0x<2n12n1+x=2n1x(2n1)<x0 x_{[反]}=\left\{\begin{matrix}x & 0 \leqslant x<2^n-1 \\ 2^{n}-1+x=2^n-1-|x| & -(2^n-1) < x\leqslant0\end{matrix}\right.

對於正數,它的反碼爲它本身,如+7=0111,它的反碼爲0111

對於負數,它的反碼錶示爲:符號位不變,數值位取反。,如-7=1000

對於0

  • +0
    • 0000–>0000
  • -0
    • 1000–>1111

定點小數

假設定點小數的反碼形式爲xs.x1x2...xnx_s.x_1x_2...x_n(實際上小數點是不存儲的),其中xsx_s代表符號位。則反碼的定義爲:
x[]={x0x<122n+x=22nx1<x0 x_{[反]}=\left\{\begin{matrix}x & 0 \leqslant x<1 \\ 2-2^{-n}+x=2-2^{-n}-|x| & -1<x\leqslant0\end{matrix}\right.

在上式中,x代表的是真值。

反碼的運算

注:如果最高位相加後產生進位,則最後得到的結果要加1。

1+(1)=01+(-1)=0

0001+1110=1111=-0

在以-126+127=1爲例

10000001+01111111=100000000

  • 進了一位,末位加一
    • 10000000+01111111+1
    • 最後結果爲00000001

也就是說,反碼解決了把減法化爲加法的問題。

補碼

補碼的由來

爲了解決原碼的計算問題,人們引入了補碼

我們先從時鐘的例子來介紹補碼的原理。

比如我們將定在五點的鐘表跳到三點,有2種調法:

image-20200318143453928image-20200318143525840

我們既可以順時針調也可以逆時針調。也就是說我們525-25+105+10的效果是一樣的。

而把這種思想引入到計算機中,不就可以把減法轉爲加法了嗎?

52=5+10MOD125+2=5+10MOD122=10MOD12 5-2=5+10(MOD 12) \\5+(-2)=5+10(MOD 12)\\ -2=10(MOD 12)
在上面的式子中,在模爲12的情況下,-2的補碼就是10。一個負 數用其補碼代替,同樣可以得到正確的運算結果。

那什麼是呢?

計算機中運算器、寄存器、計數器都有一定的位數,不可能容納無限大的任意數。當運算結果超出實際的最大表示範圍, 就會發生溢出,此時所產生的溢出量就是模(module)

可以把模定義爲一個計量器的容量

如一個八位計數器0000 0000~1111 1111,它表示的範圍就是[0,255]。當計數器表示爲1111 1111 時,如果計數器再加一,那麼此計數器就會溢出。計數器上的數值會變成0000 0000.而此計數器的溢出量就是256.

假設此計數器表示一個定點小數,它表示的範圍就是[0,2-282^{-8}]。當表示最大的時候,計數器值爲1.111 1111計數器加一的時候,那麼計數器就會清零,變爲0.0000000。那麼此此定點小數的溢出量就是2.

從上面我們可以推導出,一個n+1位定點整數xnx(n1)...x2x1x0x_n x_{(n-1)} ... x_2 x_1 x_0,它的溢出量爲2n+12^{n+1},所以模爲2n+12^{n+1}

任意一個定點小數xs.x1x2...xnx_s.x_1x_2...x_n,它的溢出量是2,所以模爲2。

在計算機中,機器能表示的數據位數是固定的, 其運算都是有模運算。若運算結果超出了計算機所能表示的數值範圍, 則只保留它的小於模的低n+1位的數值,超過n+1 位的高位部分就自動捨棄了。

下面我們來引入補碼的定義

定點整數

定點整數的補碼形式爲xnxn1x1x0x_n x_{n-1}\cdot\cdot\cdot x_1x_0,其中xnx_n爲符號位,補碼錶示的定義爲:
x[]={x0x<2n2n+1+x=2n+1x2nx0 x_{[補]}=\left\{\begin{matrix}x & 0 \leqslant x<2^n \\ 2^{n+1}+x=2^{n+1}-|x| & -2^n \leqslant x\leqslant0\end{matrix}\right.
在上式中,x代表的是真值

例如,x=+7x=+7,化爲二進制表示爲x=+0111x=+0111;x[]=0111x_{[補]}=0111

x=7x=-7,化爲二進制表示爲x=0111x=-0111;x[]=24+(0111)=100000111=1001x_{[補]}=2^4+(-0111)=10000-0111=1001

我們可以總結出來:

  • 對於正數x=+xn1...x1x0x=+x_{n-1}...x_1x_0,它的補碼是它自己本身,常常在最高位前面補0,代表它是一個正數。

  • x[]=0nxn1...x1x0x_{[補]}=0_nx_{n-1}...x_1x_0

  • 對於0,根據補碼的定義:

    • +0=+0n1...0100+0=+0_{n-1}...0_10_0

      • 此時正0的補碼爲+0[]=0n0n1...0100+0_{[補]}=0_n0_{n-1}...0_10_0
    • 0=0n1...0100-0=-0_{n-1}...0_10_0

      • 此時負0的補碼爲0[]=10n0n1...01000n1...020101mod(10n0n1...0100)=0n0n1...0100-0_{[補]}=(10_n0_{n-1}...0_10_0-0_{n-1}...0_20_10_1)mod(10_n0_{n-1}...0_10_0)=0_n0_{n-1}...0_10_0

      由此可見,零的補碼是唯一的,沒有+0和-0之分。

  • 對於負數x=xn1...x1x0x=-x_{n-1}...x_1x_0

    ​ 常常可以通過把數值位按位取反,然後末位加一來計算負數的補碼

    • 如求127-127的補碼
      • $[-0111 1111]_{[補]}=10000 0000-01111111 $
      • 10000000=11111111+110000000=11111111+1
      • [01111111][]=1111111101111111+1[-0111 1111]_{[補]}=11111111-01111111+1,這一步剛剛說明了上面的計算方法的原理。

    128-128的補碼的求法。

    • -128=-1000 0000
    • [10000000][]=1111111110000000+1=10000000[-10000000]_{[補]}=11111111-10000000+1=10000000

    其實還有一個更爲漸變的補碼的求法:**從右到左遇到第一個 1 的前面各位取反。**也就是從右向左,遇到1之前,還保持原樣。遇到1之後,各位取反。以-126爲例:126=01111110-126=-01111110

    [-01111110]的補碼位10000010,10是不變的。而黑體部分則是取反的。

對於補碼的取值範圍,10000000-11111111——- 128-128~1-1

00000000~011111111 ——0~127

推廣到n位數,則補碼的範圍就是[2n1,2n11-2^{n-1},2^{n-1}-1]

定點小數

定點小數的補碼形式爲xs.x1x2...xnx_s.x_1x_2...x_n(實際上小數點是不存儲的),其中xsx_s代表符號位。則補碼的定義爲:
x[]={x0x<12+x=2x1x0 x_{[原]}=\left\{\begin{matrix}x & 0 \leqslant x<1 \\ 2+x=2-|x| & -1\leqslant x\leqslant0\end{matrix}\right.

在上式中,x代表的是真值。

例如,x=+0.875x=+0.875,化爲二進制表示爲x=+0.111x=+0.111;x[]=0.111x_{[補]}=0.111

x=0.875x=-0.875二進制表示爲x=0.111x=-0.111;x[]=10.000(0.111)=1.001x_{[補]}=10.000-(0.111)=1.001

我們可以總結出來:

  • 對於正數x=+0.xn1...x1x0x=+0.x_{n-1}...x_1x_0,它的補碼是它自己本身,常常在最高位前面補0,代表它是一個正數。(注意,前面的0.實際上是不存儲的,也就是實際最高位是xn1x_{n-1})

  • x[]=0.xn1...x1x0x_{[原]}=0.x_{n-1}...x_1x_0

  • 對於0,根據補碼的定義:

    • +0=+0.0n1...0100+0=+0.0_{n-1}...0_10_0

      • 此時正0的補碼爲+0[]=0.0n1...0100+0_{[補]}=0.0_{n-1}...0_10_0
    • 0=0.0n1...0100-0=-0.0_{n-1}...0_10_0

      • 此時負0的補碼爲0[]=10.0n1...01000.0n1...0100mod(10.0n1...0100)=0.0n1...0100-0_{[補]}=(10.0_{n-1}...0_10_0-0.0_{n-1}...0_10_0)mod(10.0_{n-1}...0_10_0)=0.0_{n-1}...0_10_0

      也就是說**,0的補碼是唯一的**。

  • 對於負數

    按位取反,末位加一,和定點整數一樣。雖然我們看起來有一個小數點,但是實際上小數點是不存儲的。

定點小數的補碼的範圍,0000~0111–> [0,0.875]

1000~1111–> [-1,-0.125]

擴展到n位補碼

我們很容易求出它的範圍$[-1,1-2^{-(n-1)}] $

補碼的運算

假設一個二進制整數補碼有n+1位,xnxn1...x2x1x0x_nx_{n-1}...x_2x_1x_0,則補碼與真值的對應關係可以這麼表示:

X=2n×xn+0n12ixnX_{真值}=-2^n\times x_n+\sum_{0}^{n-1}2^ix_n

當該數爲正整數的時候,xnx_n位變爲0,0xn1...x2x1x00x_{n-1}...x_2x_1x_0,

X=0n12ixnX_{真值}=\sum_{0}^{n-1}2^ix_n

當該數爲負整數的時候,xnx_n位變爲1,1xn1...x2x1x01 x_{n-1}...x_2x_1x_0,

X=2n+0n12ixnX_{真值}=-2^n+\sum_{0}^{n-1}2^ix_n

  • 以-127爲例,-127=-01111111
    • 它的補碼爲10000001
    • 從補碼求真值的過程:-10000000+1=-01111111-1+1=-01111111

上面我們說到過,計算機中用原碼進行加減運算是十分麻煩的,那麼我們來看一下用補碼來運算。

126127=0126-127=0

  • 原碼

    • 011111100111111101111110-01111111

    • 我們需要比較數值位的絕對值大小,來決定符號位,1

    • 1111111-1111110=0000001

    • 10000001

      假設把減法看成加法

      • 01111110+(-01111111)=01111110+11111111=100000001
      • 1會溢出,那麼得到的結果就是00000001,按原碼錶示的化,真值爲1,顯然是錯誤的。
  • 補碼

    • 01111110+10000001=11111111
    • 轉換爲真值後爲-1。正確的
    • 原理是這樣的
      • 126-127=-1
      • 126+(-127)=-1
      • 126+129mod256=-1
      • 這裏-127等效於129mod256

由此,我們可以看出,補碼實際上是可以直接帶符號位運算的運算的。

求相反數的補碼:由[X]補求[-X]補

帶符號位一起取反,然後末位加一

如求我們已知+127的補碼求-127的補碼

  • 01111111
  • 10000001

移碼

移碼通常用於表示浮點數的階碼。由於階碼是k位的整數,假設定點整數移碼形式爲ekek1...e2e1e0e_ke_{k-1}...e_2e_1e_0最高位爲符號位是。移碼的傳統定義是:

[e]=2k+e[e]_移=2^k+e

上式中,e爲真值,2k2^k爲固定的偏移值常數。

與[x]補的區別:符號位相反

真值 補碼 移碼
-8 1000 0000
-7 1001 0001
-6 1002 0002
……
0 0000 1000
+1 0001 1001
……
+7 0111 1111

移碼的表示

移碼錶示的機器數爲數的真值在數軸上向右平移了 固定的偏移值。

如八位移碼:

image-20200319141504001

移碼的特點

  • 在移碼中,最高位爲0表示負數,最高位爲1表示正數,這與原 碼、補碼、反碼的符號位取值正好相反
  • 移碼爲全0時所對應的真值最小,爲全1時所對應的真值最大! 因此,移碼的大小直觀地反映了真值的大小,這將有助於兩個 浮點數進行階碼大小比較
  • 真值0在移碼中的表示形式是唯一的,即:[+0]移= [0]移= 100…00
  • 移碼把真值映射到一個正數域,所以可將移碼視爲無符號數, 直接按無符號數規則比較大小。
  • 同一數值的移碼和補碼除最高位相反外,其他各位相同。

原碼、反碼、補碼、移碼

取值範圍的一個比較

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章