數的機器碼表示
@
為了妥善的處理數據運算過程中符號位的問題,於是就產生了 把符號位和數值位一起編碼起來 表示相應的數的各種表示方法。例如我們熟悉的原碼、反碼、補碼、移碼等。通常將未經 編碼的數稱為真值,編碼后的數稱為 機器數或者機器碼。
-
真值的形式:正、負號加某進制數絕對值的形式,即數的實際值。如
+3
,-5
等 -
機器數的形式:真值按某種編碼方式進行編碼后的數值,即真值在機器中的表示,稱為機器數,一般可以分為 無符號數和有符號數兩種如:X=01011 ,Y=11011
原碼
定點整數
若定點整數的原碼形式位\(x_n x_{n-1}\cdot\cdot\cdot x_1x_0\),其中\(x_n\)為符號位,則原碼表示的定義為:
在上式中,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\)
- \(+0=+0_{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代表的是真值。
例如,\(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\)
- \(+0=+0.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\)代表符號位。
則
對於正數,它的反碼為它本身,如+7=0111,它的反碼為0111
對於負數,它的反碼表示為:符號位不變,數值位取反。,如-7=1000
對於0
- +0
- 0000-->0000
- -0
- 1000-->1111
定點小數
假設定點小數的反碼形式為\(x_s.x_1x_2...x_n\)(實際上小數點是不存儲的),其中\(x_s\)代表符號位。則反碼的定義為:
在上式中,x代表的是真值。
反碼的運算
注:如果最高位相加后產生進位,則最后得到的結果要加1。
\(1+(-1)=0\)
0001+1110=1111=-0
在以-126+127=1為例
10000001+01111111=100000000
- 進了一位,末位加一
- 10000000+01111111+1
- 最后結果為00000001
也就是說,反碼解決了把減法化為加法的問題。
補碼
補碼的由來
為了解決原碼的計算問題,人們引入了補碼。
我們先從時鍾的例子來介紹補碼的原理。
比如我們將定在五點的鍾表跳到三點,有2種調法:
我們既可以順時針調也可以逆時針調。也就是說我們\(5-2\)和\(5+10\)的效果是一樣的。
而把這種思想引入到計算機中,不就可以把減法轉為加法了嗎?
在上面的式子中,在模為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代表的是真值。
例如,\(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是不變的。而黑體部分則是取反的。
- 如求\(-127\)的補碼
對於補碼的取值范圍,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代表的是真值。
例如,\(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 |
移碼的表示
移碼表示的機器數為數的真值在數軸上向右平移了 固定的偏移值。
如八位移碼:
移碼的特點
- 在移碼中,最高位為0表示負數,最高位為1表示正數,這與原 碼、補碼、反碼的符號位取值正好相反。
- 移碼為全0時所對應的真值最小,為全1時所對應的真值最大! 因此,移碼的大小直觀地反映了真值的大小,這將有助於兩個 浮點數進行階碼大小比較。
- 真值0在移碼中的表示形式是唯一的,即:[+0]移= [0]移= 100…00
- 移碼把真值映射到一個正數域,所以可將移碼視為無符號數, 直接按無符號數規則比較大小。
- 同一數值的移碼和補碼除最高位相反外,其他各位相同。
原碼、反碼、補碼、移碼
取值范圍的一個比較