數的機器碼錶示——徹底弄清什麼是原碼、反碼、補碼、移碼
阿新 • • 發佈:2020-03-19
## 數的機器碼錶示
@[toc]
為了妥善的處理資料運算過程中符號位的問題,於是就產生了**把符號位和數值位一起編碼**起來**表示相應的數**的各種表示方法。例如我們熟悉的原碼、反碼、補碼、移碼等。通常將未經**編碼的數稱為真值**,編碼後的數稱為**機器數或者機器碼**。
- **真值的形式**:**正、負號加某進位制數絕對值的形式**,即**數的實際值**。如`+3`,`-5`等
- **機器數的形式**:真值按某種編碼方式進行編碼後的數值,即**真值在機器中的表示**,稱為機器數,一般可以分為 **無符號數和有符號數**兩種如:**X=01011** ,**Y=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^n0000
- -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
我們既可以順時針調也可以逆時針調。也就是說我們$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]的補碼位**100000**10,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=**1**00000001
- 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](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL2MxYXRhL2ltZ2JlZDIwMjAvaW1nL2ltYWdlLTIwMjAwMzE5MTQxNTA0MDAxLnBuZw?x-oss-process=image/format,png)
#### 移碼的特點
- 在移碼中,最高位為0表示負數,最高位為1表示正數,這與**原 碼、補碼、反碼的符號位取值正好相反**。
- 移碼為全0時所對應的真值最小,為全1時所對應的真值最大! 因此,**移碼的大小直觀地反映了真值的大小,這將有助於兩個 浮點數進行階碼大小比較**。
- 真值0在移碼中的表示形式是**唯一**的,即:**[+0]移= [0]移= 100…00**
- 移碼**把真值對映到一個正數域**,所以可將移碼視為無符號數, 直接按無符號數規則比較大小。
- 同一數值的移碼和補碼除最高位相反外,其他各位相同。
### 原碼、反碼、補碼、移碼
取值範圍的一個比較
![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L2doL2MxYXRhL2ltZ2JlZDIwMjAvaW1nLyVFNyVBNyVCQiVFNyVBMCU4MSVFNSU4RiU4RCVFNyVBMCU4MSVFNSU4RSU5RiVFNyVBMCU4MSVFOCVBMSVBNSVFNyVBMCU4MS5qcGc?x-oss-process=image/form