機器數、真值、原碼、反碼和補碼
文中所有二進制為了表示方便皆采用1字節來表示
一. 機器數、真值
1. 機器數
機器數就是一個數在計算機中的二進制表示,計算機中機器數的最高位是符號位,正數符號位為0,負數符號位為1。機器數包含原碼、反碼和補碼三種表示形式,后文會具體進行解釋。
例如:
十進制中的+2在計算機中的字長為8,轉換成二進制為 0000 0010
十進制中的-2在計算機中的字長為8,轉換成二進制為 1000 0010
上文例子中的0000 0010和1000 0010就是機器數
2. 機器數的真值
真值就是帶符號位的機器數對應的真正數值,個人理解就是用正負號來代替符號位來表示機器數
例如:
機器數 0000 0010 的真值為 +000 0010 也就是+2
機器數 1000 0010 的真值為 -000 0010 也就是-2
二. 機器數的三種表示形式:原碼、反碼、補碼
1. 原碼
原碼就是加了一位符號位的二進制數,正數符號位為0,負數符號位為1,符號位為最高位。
個人理解就是將真值里面的"+"轉換為0,"-"轉換為1。
| 十進制 | 真值 | 原碼 |
|---|---|---|
| +2 | +000 0010 | 0000 0010 |
| -2 | -000 0010 | 1000 0010 |
由此可以得出8位的二進制數的大小范圍為[1111 1111, 0111 1111],也就是[-127, 127]對應java中byte數據類型的大小范圍
2. 反碼
正數的反碼就是其原碼,負數的反碼則是符號位不變,其他位取反(0變1,1變0)
| 十進制 | 原碼 | 反碼 |
|---|---|---|
| +2 | 0000 0010 | 0000 0010 |
| -2 | 1000 0010 | 1111 1101 |
3. 補碼
正數的補碼就是其原碼,負數的補碼則是反碼+1
| 十進制 | 原碼 | 反碼 | 補碼 |
|---|---|---|---|
| +2 | 0000 0010 | 0000 0010 | 0000 0010 |
| -2 | 1000 0010 | 1111 1101 | 1111 1110 |
4. 為何使用反碼、補碼
使用原碼進行計算的時候,對於人而言能夠很輕易的辨別出符號位,然后直接對其他位數值進行計算。然而對於計算機的設計而言辨別出符號位就是一項非常復雜的工程,所以設計的時候就考慮讓符號位直接參與計算,這樣設計計算機就十分簡單了。
對於加法而言符號位對於計算並沒有影響,對於減法而言則考慮通過加上負數來轉換為加法的方式進行計算。
如果通過原碼來直接進行減法計算:
3 - 2
= 3 + (-2)
= 0000 0011(原) + 1000 0010(原)
= 1000 0101
= -5
結果顯而易見,如果通過原碼來直接讓符號位參與運算的話是不正確的,所以為了解決減法的問題引入了反碼的概念。如果通過反碼來進行減法計算:
3 - 2
= 3 + (-2)
= 0000 0011(原) + 1000 0010(原)
= 0000 0011(反) + 1111 1101(反)
= 1 0000 0000(反) -- 最高位產生進位,結果+1
= 0000 0001(反)
= 0000 0001(原)
= 1
結果正確,從上面例子看來如果通過反碼進行減法運算的話是沒有問題的,那為什么又需要補碼呢,我們一起來看下面這個特殊的例子:
2 - 2
= 2 + (-2)
= 0000 0010(原) + 1000 0010(原)
= 0000 0010(反) + 1111 1101(反)
= 1111 1111(反)
= 1000 0000(原)
= -0
0 + 0
= 0000 0000(原) + 0000 0000(原)
= 0000 0000(反) + 0000 0000(反)
= 0000 0000(反)
= 0000 0000(原)
= 0
由於對於0這個數字而言,正負號沒有任何意義,但是經過計算卻有可能出現[0000 0000]和[1000 0000]這兩種不同的原碼表示同一個數字0,這顯然是不合理的,所以此時就引入了補碼的概念。
如果通過補碼來進行上述例子的計算:
2 - 2
= 2 + (-2)
= 0000 0010(原) + 1000 0010(原)
= 0000 0010(反) + 1111 1101(反)
= 0000 0010(補) + 1111 1110(補)
= 1 0000 0000(補) -- 最高位產生進位,進位舍棄
= 0000 0000(補)
= 0000 0000(反)
= 0000 0000(原)
= 0
0 + 0
= 0000 0000(原) + 0000 0000(原)
= 0000 0000(反) + 0000 0000(反)
= 0000 0000(補) + 0000 0000(補)
= 0000 0000(反)
= 0000 0000(原)
= 0
由上述例子可以看出,補碼完美的解決了0的符號問題以及0有兩個不同原碼表示的問題。而且[10000 0000]也可以用來表示-128:
-1 - 127
= -1 + (-127)
= 1000 0001(原) + 1111 1111(原)
= 1111 1110(反) + 1000 0000(反)
= 1111 1111(補) + 1000 0001(補)
= 1 1000 0000(補) --最高位產生進位,進位舍棄
= 1000 0000(補)
-1 - 127的結果為-128,上面例子中-1和-127補碼相加后得出的補碼也是-128。但是這個1000 0000(補)實際上對應的是之前的-0,所以這個補碼是沒有反碼和原碼的。
綜上可以看出使用補碼的話不僅0的符號問題和多原碼問題可以解決,還可以多表示一個最小數。因此對於1字節而言,原碼和反碼的范圍是[-127, 127],而補碼的范圍是[-128, 127],也可以解釋java中int的范圍是[-2, 2-1]。
