數的機器碼錶示
爲了妥善的處理數據運算過程中符號位的問題,於是就產生了
把符號位和數值位一起編碼起來
表示相應的數的各種表示方法。例如我們熟悉的原碼、反碼、補碼、移碼等。通常將未經
編碼的數稱爲真值,編碼後的數稱爲
機器數或者機器碼。
原碼
定點整數
若定點整數的原碼形式位xnxn−1⋅⋅⋅x1x0,其中xn爲符號位,則原碼錶示的定義爲:
x[原]={x2n−x=2n+∣x∣0⩽x<2n−2n<x⩽0
在上式中,x代表的是真值。
例如,x=+7,化爲二進制表示爲x=+0111;x[原]=0111。
x=−7,化爲二進制表示爲x=−0111;x[原]=23−(−0111)=1000+0111=1111。
我們可以總結出來:
-
對於正數x=+xn−1...x1x0,它的原碼是它自己本身,常常在最高位前面補0,代表它是一個正數。
- x[原]=0xn−1...x1x0
-
對於0,根據原碼的定義則有兩種表示形式:
- +0=+0n−1...0100
- 此時正0的原碼爲+0[原]=00n−1...0100
- −0=−0n−1...0100
- 此時負0的原碼爲−0[原]=10n−1...0100
-
對於負數x=−xn−1...x1x0,它的原碼是在最高位前面補1,代表它是一個負數。
- x[原]=−xn−1...x1x0
對於一個定點整數原碼xnxn−1...x1x0,最高位xn代表符號位,用0來表示正數,用1來表示負數。而xn−1...x1x0則代表的是數值位。它的大小就是該原碼對應真值的絕對值。
我們很容易求出它的範圍[−(2n−1),2n−1]
定點小數
假設定點小數的原碼形式爲xs.x1x2...xn(實際上小數點是不存儲的),其中xs代表符號位。則原碼的定義爲:
x[原]={x1−x=1+∣x∣0⩽x<1−1<x⩽0
在上式中,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.xn−1...x1x0,它的原碼是它自己本身,常常在最高位前面補0,代表它是一個正數。(注意,前面的0.實際上是不存儲的,也就是實際最高位是xn−1)
- x[原]=0.xn−1...x1x0
-
對於0,根據原碼的定義則有兩種表示形式:
- +0=+0.0n−1...0100
- 此時正0的原碼爲+0[原]=0.0n−1...0100
- −0=−0.0n−1...0100
- 此時負0的原碼爲−0[原]=1.0n−1...0100
-
對於負數x=−0.xn−1...x1x0,它的原碼是在最高位前面補1,代表它是一個負數。(注意,前面的0.實際上是不存儲的,也就是實際最高位是xn−1)
- x[原]=−1.xn−1...x1x0
對於一個定點小數原碼 xs.x1x2...xn,最高位 xs代表符號位,用0來表示正數,用1來表示負數。而x1x2...xn則代表的是數值位。它的大小就是該原碼對應真值的絕對值。
我們很容易求出它的範圍[2−n−1,1−2−n]
原碼的計算
原碼雖然表示極爲簡單,但是最大的問題就是加法運算十分複雜。
兩數相加時,我們需要考慮兩個數的符號,如果符號相同,我們可以把數值位直接相加,然後在最高位前邊添加上原來的符號位。但如果符號位不相同,那麼我們就要考慮進行減法運算。進行減法的時候,我們需要考慮數值位的絕對值大小來決定符號位。這也就是原碼運算的缺點:參與運算複雜,需要將數值位與符號位分開考慮。
反碼
當進行減法的時候,人們想到如何把減法變爲加法,那麼這樣會更加簡便,只靠加法器就可以完成運算。比如
1−1=0
0001−0001=0000
1+(−1)=0
0001+1001=1010=−2
顯然是計算錯誤的。
於是人們引入了反碼來表示負數。
定點整數
設定點整數的反碼形式爲xnxn−1⋅⋅⋅x1x0,xn代表符號位。
則
x[反]={x2n−1+x=2n−1−∣x∣0⩽x<2n−1−(2n−1)<x⩽0
對於正數,它的反碼爲它本身,如+7=0111,它的反碼爲0111
對於負數,它的反碼錶示爲:符號位不變,數值位取反。,如-7=1000
對於0
定點小數
假設定點小數的反碼形式爲xs.x1x2...xn(實際上小數點是不存儲的),其中xs代表符號位。則反碼的定義爲:
x[反]={x2−2−n+x=2−2−n−∣x∣0⩽x<1−1<x⩽0
在上式中,x代表的是真值。
反碼的運算
注:如果最高位相加後產生進位,則最後得到的結果要加1。
1+(−1)=0
0001+1110=1111=-0
在以-126+127=1爲例
10000001+01111111=100000000
- 進了一位,末位加一
- 10000000+01111111+1
- 最後結果爲00000001
也就是說,反碼解決了把減法化爲加法的問題。
補碼
補碼的由來
爲了解決原碼的計算問題,人們引入了補碼。
我們先從時鐘的例子來介紹補碼的原理。
比如我們將定在五點的鐘表跳到三點,有2種調法:
我們既可以順時針調也可以逆時針調。也就是說我們5−2和5+10的效果是一樣的。
而把這種思想引入到計算機中,不就可以把減法轉爲加法了嗎?
5−2=5+10(MOD12)5+(−2)=5+10(MOD12)−2=10(MOD12)
在上面的式子中,在模爲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
位定點整數xnx(n−1)...x2x1x0,它的溢出量爲2n+1,所以模爲2n+1。
任意一個定點小數xs.x1x2...xn,它的溢出量是2,所以模爲2。
而在計算機中,機器能表示的數據位數是固定的, 其運算都是有模運算。若運算結果超出了計算機所能表示的數值範圍, 則只保留它的小於模的低n+1位的數值,超過n+1 位的高位部分就自動捨棄了。
下面我們來引入補碼的定義:
定點整數
定點整數的補碼形式爲xnxn−1⋅⋅⋅x1x0,其中xn爲符號位,補碼錶示的定義爲:
x[補]={x2n+1+x=2n+1−∣x∣0⩽x<2n−2n⩽x⩽0
在上式中,x代表的是真值。
例如,x=+7,化爲二進制表示爲x=+0111;x[補]=0111。
x=−7,化爲二進制表示爲x=−0111;x[補]=24+(−0111)=10000−0111=1001。
我們可以總結出來:
-
對於正數x=+xn−1...x1x0,它的補碼是它自己本身,常常在最高位前面補0,代表它是一個正數。
-
x[補]=0nxn−1...x1x0
-
對於0,根據補碼的定義:
-
對於負數x=−xn−1...x1x0
常常可以通過把數值位按位取反,然後末位加一來計算負數的補碼。
- 如求−127的補碼
- $[-0111 1111]_{[補]}=10000 0000-01111111 $
- 10000000=11111111+1
- [−01111111][補]=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位數,則補碼的範圍就是[−2n−1,2n−1−1]
定點小數
定點小數的補碼形式爲xs.x1x2...xn(實際上小數點是不存儲的),其中xs代表符號位。則補碼的定義爲:
x[原]={x2+x=2−∣x∣0⩽x<1−1⩽x⩽0
在上式中,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.xn−1...x1x0,它的補碼是它自己本身,常常在最高位前面補0,代表它是一個正數。(注意,前面的0.實際上是不存儲的,也就是實際最高位是xn−1)
-
x[原]=0.xn−1...x1x0
-
對於0,根據補碼的定義:
-
對於負數
按位取反,末位加一,和定點整數一樣。雖然我們看起來有一個小數點,但是實際上小數點是不存儲的。
定點小數的補碼的範圍,0000~0111–> [0,0.875]
1000~1111–> [-1,-0.125]
擴展到n位補碼
我們很容易求出它的範圍$[-1,1-2^{-(n-1)}] $
補碼的運算
假設一個二進制整數補碼有n+1位,xnxn−1...x2x1x0,則補碼與真值的對應關係可以這麼表示:
X真值=−2n×xn+∑0n−12ixn
當該數爲正整數的時候,xn位變爲0,0xn−1...x2x1x0,
X真值=∑0n−12ixn
當該數爲負整數的時候,xn位變爲1,1xn−1...x2x1x0,
X真值=−2n+∑0n−12ixn
- 以-127爲例,-127=-01111111
- 它的補碼爲10000001
- 從補碼求真值的過程:-10000000+1=-01111111-1+1=-01111111
上面我們說到過,計算機中用原碼進行加減運算是十分麻煩的,那麼我們來看一下用補碼來運算。
126−127=0
-
原碼
-
補碼
- 01111110+10000001=11111111
- 轉換爲真值後爲-1。正確的
- 原理是這樣的
- 126-127=-1
- 126+(-127)=-1
- 126+129mod256=-1
- 這裏-127等效於129mod256
由此,我們可以看出,補碼實際上是可以直接帶符號位運算的運算的。
求相反數的補碼:由[X]補求[-X]補
帶符號位一起取反,然後末位加一
如求我們已知+127的補碼求-127的補碼:
移碼
移碼通常用於表示浮點數的階碼。由於階碼是k位的整數,假設定點整數移碼形式爲ekek−1...e2e1e0最高位爲符號位是。移碼的傳統定義是:
[e]移=2k+e
上式中,e爲真值,2k爲固定的偏移值常數。
與[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
- 移碼把真值映射到一個正數域,所以可將移碼視爲無符號數, 直接按無符號數規則比較大小。
- 同一數值的移碼和補碼除最高位相反外,其他各位相同。
原碼、反碼、補碼、移碼
取值範圍的一個比較