# 原码、反码、补码和移码详解 # 原码、反码、补码和移码的“由来”
一、原碼、反碼、補碼和移碼的一般求法
| 原碼 | 符號位用0表示正數,1表示負數,其余位不變。 |
| 反碼 | 正數的反碼與原碼一樣,負數的反碼是對它的原碼(除符號位外)各位取反。 |
| 補碼 | 正數的補碼與原碼一樣,負數的補碼是其反碼尾部加1。 |
| 移碼 | 不管正負數,將其補碼的符號位取反即可。 |
二、移碼的“真正”求法
移碼:移碼表示法是在數X上增加一個偏移量來定義的,通常用于表示浮點數的階碼。
如果機器字長為n,規定偏移 量為2n-1,則移碼定義如下:
X 為純整數:[X]移=2n-1+X(-2n-1≤X<2n-1)
X 為純小數:[X]移=1+X(-1≤X<1)
【舉個栗子】
[+1]移=28-1+1=129=1 000 0001
[-1]移=28-1 -1=127=0 111 1111
[+127]移=28-1+127=255=1 111 1111
[-127]移=28-1 -127=1=0 000 0001
[+45]移=28-1+45=173=1 010 1101
[-45]移=28-1 -45=83=0 101 0011
[+0.5]移=1+0.5=1.5=1 100 0000
[-0.5]移=1-0.5=0.5=0 100 0000
[+0]移=[-0]移=1 000 0000
三、原碼、反碼、補碼和移碼的“由來”
1. 原碼
原碼:符號位用0表示正數,1表示負數,其余位不變。
對于計算機,加減乘除是最基礎的運算,要設計的盡量簡單。
計算機辨別“符號位”顯然會讓計算機的基礎電路設計變得十分復雜!于是科學家想出了將符號位也參與運算的方法。
我們知道,根據運算法則,減去一個正數等于加上一 個負數,即:1-1=1+(-1)=0,所以機器可以只有加法而沒有減法,這樣計算機運算的設計就更簡單了。
在運算中,原碼進行加法運算是沒有問題的,但是在減法運算中會出問題,如:(D表示十進制)
1D-1D
=1D+(-1)D
=[0 000 0001]原+[1 000 0001]原
=[1 000 0010]原
=-2D
這個結果明顯是錯誤的!
如果用原碼表示,讓符號位也參與計算,顯然對于減法來說,結果是不正確的。這也就是為何計算機內部不使用原碼表示一個數的原因。
所以為了解決原碼做減法的問題,出現了反碼。
2. 反碼
反碼:正數的反碼與原碼一樣,負數的反碼是對它的原碼(除符號位外)各位取反。
【舉個栗子】
使用反碼計算 1-1 過程如下:
1D-1D
= 1D+(-1)D
= [0 000 0001]原+[1 000 0001]原
=[0 000 0001]反+[1 111 1110]反
=[1 111 1111]反
=[1 000 0000]原
= - 0D
發現用反碼計算減法,結果的真值部分是正確的。
而唯一的問題其實就出現在“0”這個特殊的數值上。雖然人們理解上+0 和-0 是一樣的, 但在這里 0 帶符號是沒有任何意義的,而且會有[0 0000000]原和[1 0000000]原兩個編碼表示 0。 于是補碼出現了,解決了 0 的符號和 0 的兩個編碼問題,以及原碼和補碼進行減法運算時出現的問題。
3. 補碼
補碼:正數的補碼與原碼一樣,負數的補碼是其反碼尾部加1。
使用補碼計算 1-1 過程如下:
1D-1D
=1D+(-1)D
=[0 000 0001]原+[1 000 0001]原
=[0 000 0001]補+[1 111 1111]補
=[0 000 0000]反
=[0 000 0000]原
=0D
這樣 0 用 0 000 0000 表示,而以前出現問題的-0 則不存在了,且在補碼中 0 也只有一種唯一的表示形式。
假設機器字長為 8 位,使用補碼則可以用[1 000 0000]補表示-128D;
(-1)D+(-127)D
=[1 000 0001]原+[1 111 1111]原
=[1 111 1111]補+[1 000 0001]補
=[1 000 0000]補
最終運算結果應為 [1 1000 0000]補,但由于機器字長為 8 位,最左邊的“1”被丟掉了,故只剩下[1 000 0000]補。 -1-127 的結果應該是-128,在用補碼運算的結果中,[1 000 0000]補就是-128。
但是注意因為實際上是使用以前的 -0 的補碼來表示 -128,所以-128 并沒有原碼和反碼表示(對-128 的補碼表示[1 000 0000]補算出來的原碼是[0 000 0000]原,這是不正確的)。
使用補碼,不僅僅修復了 0 的符號以及 0 的兩個編碼的問題,而且還能夠多表示一個最低數。這就是為什么 8 位二進制使用原碼或反碼表示的范圍為[-127,+127],而使用補碼表示的范圍為[-128,127]的原因。
因為機器使用補碼,所以對于編程中常用到的 32 位 int 類型,可以表示范圍是(最高位是符號位):[-231,231-1],使用補碼表示時可以多保存一個最小值 - 231。
假設機器字長為 n 位,則使用補碼表示的最小的一個數是 -2n-1。
4. 移碼
移碼:不管正負數,將其補碼的符號位取反即可。
常用來比較大小,一般會把浮點數的階碼用移碼表示。當把數值用移碼表示出來可一眼看出它們的大小,這樣很容易判斷階碼的大小,移碼可用于簡化浮點數的乘除法運算。
四、原碼、反碼、補碼和移碼的取值范圍
| 原碼 | -(2n-1-1) ~ +(2n-1-1) | -(1-2-(n-1)) ~ +(1-2-(n-1)) |
| 反碼 | -(2n-1-1) ~ +(2n-1-1) | -(1-2-(n-1)) ~ +(1-2-(n-1)) |
| 補碼 | -2n-1 ~ +(2n-1-1) | -1 ~ +(1-2-(n-1)) |
| 移碼 | -2n-1 ~ +(2n-1-1) | -1 ~ +(1-2-(n-1)) |
【定點小數的取值范圍的推算】
以補碼為例:一個數用 n 位存儲,用掉一個符號位后,還有 (n-1) 位,如果小數點在最右邊,此時表示的是整數,可表示 -2n-1 ~ +(2n-1-1) 范圍的數,把小數點左移 n-1 位,相當于除以 2(n-1) ,結果為:
-1 ~ +(1-2-(n-1))
同理可以將其他碼制的范圍求出來。
【總結】
總之,反碼用來解決負數加法運算問題,將減法運算轉換為加法運算,從而簡化運算規則;
補碼解決負數加法運算正負零問題,彌補了反碼的不足。
反碼與補碼都是為了解決負數運算問題,跟正數沒關系,因此,不管是正整數還是正小數,原碼,反碼,補碼都全部相同。
將補碼符號位取反即得到相應的移碼。
總結
以上是生活随笔為你收集整理的# 原码、反码、补码和移码详解 # 原码、反码、补码和移码的“由来”的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自制WIN7原版ISO支持NVME,支持
- 下一篇: 5分钟教你用GANs生成CryptoPu