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


數的機器碼表示

@


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

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

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

原碼

定點整數

若定點整數的原碼形式位\(x_n x_{n-1}\cdot\cdot\cdot x_1x_0\),其中\(x_n\)為符號位,則原碼表示的定義為:

\[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=+7\),化為二進制表示為\(x=+0111\);\(x_{[原]}=0111\)

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

我們可以總結出來:

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

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

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

    • \(x_{[原]}=-x_{n-1}...x_1x_0\)

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

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

定點小數

假設定點小數的原碼形式為\(x_s.x_1x_2...x_n\)(實際上小數點是不存儲的),其中\(x_s\)代表符號位。則原碼的定義為:

\[x_{[原]}=\left\{\begin{matrix}x & 0 \leqslant x<1 \\ 1-x=1+|x| & -1<x\leqslant0\end{matrix}\right. \]

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

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

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

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

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

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

    • \(x_{[原]}=-1.x_{n-1}...x_1x_0\)

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

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

原碼的計算

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

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

反碼

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

\(1-1=0\)

\(0001-0001=0000\)

\(1+(-1)=0\)

\(0001+1001=1010=-2\)

顯然是計算錯誤的。

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

定點整數

設定點整數的反碼形式為\(x_n x_{n-1}\cdot\cdot\cdot x_1x_0\)\(x_n\)代表符號位。

\[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

定點小數

假設定點小數的反碼形式為\(x_s.x_1x_2...x_n\)(實際上小數點是不存儲的),其中\(x_s\)代表符號位。則反碼的定義為:

\[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)=0\)

0001+1110=1111=-0

在以-126+127=1為例

10000001+01111111=100000000

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

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

補碼

補碼的由來

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

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

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

image-20200318143453928image-20200318143525840

我們既可以順時針調也可以逆時針調。也就是說我們\(5-2\)\(5+10\)的效果是一樣的。

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

\[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-\(2^{-8}\)]。當表示最大的時候,計數器值為1.111 1111計數器加一的時候,那么計數器就會清零,變為0.0000000。那么此此定點小數的溢出量就是2.

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

任意一個定點小數\(x_s.x_1x_2...x_n\),它的溢出量是2,所以模為2。

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

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

定點整數

定點整數的補碼形式為\(x_n x_{n-1}\cdot\cdot\cdot x_1x_0\),其中\(x_n\)為符號位,補碼表示的定義為:

\[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=+7\),化為二進制表示為\(x=+0111\);\(x_{[補]}=0111\)

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

我們可以總結出來:

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

  • \(x_{[補]}=0_nx_{n-1}...x_1x_0\)

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

    • \(+0=+0_{n-1}...0_10_0\)

      • 此時正0的補碼為\(+0_{[補]}=0_n0_{n-1}...0_10_0\)
    • \(-0=-0_{n-1}...0_10_0\)

      • 此時負0的補碼為\(-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=-x_{n-1}...x_1x_0\)

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

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

    \(-128\)的補碼的求法。

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

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

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

對於補碼的取值范圍,10000000-11111111——- \(-128\)~\(-1\)

00000000~011111111 ——0~127

推廣到n位數,則補碼的范圍就是[\(-2^{n-1},2^{n-1}-1\)]

定點小數

定點小數的補碼形式為\(x_s.x_1x_2...x_n\)(實際上小數點是不存儲的),其中\(x_s\)代表符號位。則補碼的定義為:

\[x_{[原]}=\left\{\begin{matrix}x & 0 \leqslant x<1 \\ 2+x=2-|x| & -1\leqslant x\leqslant0\end{matrix}\right. \]

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

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

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

我們可以總結出來:

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

  • \(x_{[原]}=0.x_{n-1}...x_1x_0\)

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

    • \(+0=+0.0_{n-1}...0_10_0\)

      • 此時正0的補碼為\(+0_{[補]}=0.0_{n-1}...0_10_0\)
    • \(-0=-0.0_{n-1}...0_10_0\)

      • 此時負0的補碼為\(-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位,\(x_nx_{n-1}...x_2x_1x_0\),則補碼與真值的對應關系可以這么表示:

\(X_{真值}=-2^n\times x_n+\sum_{0}^{n-1}2^ix_n\)

當該數為正整數的時候,\(x_n\)位變為0,\(0x_{n-1}...x_2x_1x_0\),

\(X_{真值}=\sum_{0}^{n-1}2^ix_n\)

當該數為負整數的時候,\(x_n\)位變為1,\(1 x_{n-1}...x_2x_1x_0\),

\(X_{真值}=-2^n+\sum_{0}^{n-1}2^ix_n\)

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

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

\(126-127=0\)

  • 原碼

    • \(01111110-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位的整數,假設定點整數移碼形式為\(e_ke_{k-1}...e_2e_1e_0\)最高位為符號位是。移碼的傳統定義是:

\([e]_移=2^k+e\)

上式中,e為真值,\(2^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
  • 移碼把真值映射到一個正數域,所以可將移碼視為無符號數, 直接按無符號數規則比較大小。
  • 同一數值的移碼和補碼除最高位相反外,其他各位相同。

原碼、反碼、補碼、移碼

取值范圍的一個比較


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM