1. 程式人生 > >計算機二進位制中的原碼,反碼,補碼

計算機二進位制中的原碼,反碼,補碼

> **公號:碼農充電站pro** > **主頁:** 計算機最基本的工作是處理資料,而資料的最底層表現形式是二進位制,並非是我們人類熟悉的十進位制。可以這麼認為,計算機其實是很“笨的”,它只理解二進位制資料。 今天,主要介紹計算機是怎樣做加減運算的。你可能會想,加減運算?這麼簡單的事情,還用介紹?也許還真不是你想的那樣。 計算機的運算是由CPU 完成的,而CPU 只會做加法運算,不會做減法運算,那計算機怎樣完成減法工作呢? ### 1,二進位制數 我們先來看看二進位制數。 二進位制數是由0,1 組成的,比如: - 十進位制的5,用二進位制表示是 101。 - 十進位制的7,用二進位制表示是 111。 數字由正數和負陣列成。為了表示正負數,計算機中就有了**有符號數**和**無符號數**之分: - 無符號數:英文為 `unsigned`,只能表示正數。 - 有符號數:英文為`signed`,即能表示正數,又能表示負數。 >
**C/C++** 語言中的數字有**有符號數**和**無符號數**之分。 > **Java** 語言所有的數字都是**有符號數**。 假如,我們用 4 位二進位制,來表示無符號數,也就是隻表示正數,能表示的範圍是 `0 到 15`,轉換關係如下表: | 十進位制數 | 二進位制數 |十進位制數 | 二進位制數 | |--|--|--|--| | 0 | 0000 |8 | 1000 | | 1 | 0001 |9 | 1001 | | 2 | 0010 |10 | 1010 | | 3 | 0011 |11 | 1011 | | 4 | 0100 |12 | 1100 | | 5 | 0101 |13 | 1101 | | 6 | 0110 |14 | 1110 | | 7 | 0111 |15 | 1111 | 有符號數,即要表示正數,也要表示負數。 要用二進位制表示有符號數,需要用二進位制的**最高位**來表示符號,`0` 表示`正`,`1` 表示`負`。所謂的最高位,也就是最左邊那一位。 用 4 位二進位制,來表示有符號數,能表示的範圍是 `-8 到 7`,轉換關係如下表: | 十進位制數 | 二進位制數 |十進位制數 | 二進位制數 | |--|--|--|--| | 0 | `0`000 |**-8** | **`1`000** | | 1 | `0`001 |-1 | `1`001 | | 2 | `0`010 |-2 | `1`010 | | 3 | `0`011 |-3 | `1`011 | | 4 | `0`100 |-4 | `1`100 | | 5 | `0`101 |-5 | `1`101 | | 6 | `0`110 |-6 | `1`110 | | 7 | `0`111 |-7 | `1`111 | 上表中的最高位的符號位,已標紅。 >
要注意,對於有符號的4 位二進位制 ----`1000` 不是 `-0`,而是 `-8`。 可以總結出,對於`N` 位的二進位制數: - 無論是表示**有符號數**還是**無符號數**,都能表示`2^N` 個數字。 - 若用於表示**無符號數**,則能表示的範圍是 `[0, 2^N - 1]`。 - 若用於表示**有符號數**,則能表示的範圍是 `[-2^(N-1), 2^(N-1) - 1]`。 - **需要注意**,在有符號數中,對於符號位是 `1`,後面 `N-1` 位全是 `0`,這種情況表示的是 `-2^(N-1)`(也就是所能表示的最小值),而不是 `-0`。 - 實際上是將`-0` 這種情況解釋成了`最小值`,否則就會出現 `+0` 和 `-0` 兩個`0`。 ### 2,二進位制原碼 上面介紹到的二進位制就是原碼形式。 **原碼就是除符號位外的其他位,儲存該二進位制數的絕對值。** ***用原碼進行加法計算*** 計算機中的數字運算都會先轉成二進位制數再進行計算。 我們用原碼來計算加法,用4 位二進位制數來計算 `3 + 2`,過程如下: ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201121115329554.png?#pic_center) 可以看到,用原碼計算加法是沒有問題的。 ***用原碼進行減法計算*** 我們再用原碼來計算減法,因為CPU 只會計算加法,所以計算減法時,會將減法轉換成加法。 比如,用4 位二進位制數來計算計算 `3 - 2`,會將其轉換成 `3 + (-2)`, 過程如下: ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201121120031179.png?#pic_center) 可以看到 `3-2` 計算出來的結果是 `-5`,顯然是錯誤的。 所以,用二進位制原碼來計算減法是行不通的。實際上,計算機計算減法用的是**補碼**。 在介紹補碼之前,我們先來看下什麼是**溢位**。 ### 3,數字溢位 計算機中數字的表示是需要記憶體空間的,不同型別的數字所能佔用的空間是不一樣的。 比如,在Java 語言中`short` 型別佔用 2 個位元組,`int` 型別佔用 4 個位元組。 >
一個位元組等於 8 位。 既然空間大小是有限制的,所以計算機中的數字也是有範圍的,即**上限**和**下限**,如果數字超出限制,就會產生**溢位**。超出上限叫**上溢位**,超出下限叫**下溢位**。***而溢位的部分會直接被捨去***。 就像我們在上文中介紹的,對於`N` 位二進位制**有符號整數**,所能表示的範圍是 `[-2^(N-1), 2^(N-1) - 1]`。 由於溢位的部分會被捨去,那麼最大值加1,將發生上溢位,變為最小值;最小值減1,將發生下溢位,變為最大值。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201121124424444.png?#pic_center) 我們用**Java** 中的`int` 型別來驗證,**Java** 中`int` 型別的最大、最小值分別是: - 最大值:`Integer.MAX_VALUE`,是 `2147483647`。 - 最小值:`Integer.MIN_VALUE`,是 `-2147483648`。 用下面程式碼驗證: ```java System.out.println(Integer.MAX_VALUE + 1 == Integer.MIN_VALUE); // true System.out.println(Integer.MIN_VALUE - 1 == Integer.MAX_VALUE); // true ``` 這兩行程式碼的輸出均為`true`,說明最大值加1 變為最小值,最小值減1 變為最大值。 所以,在計算機中,只要一個整數的型別確定了,那麼它所能佔用的記憶體空間大小也就確定了,從而它所能表示的數字範圍也就確定了。那麼不管給這個整數加多大的數字,或者減多大的數字,最終的結果都只能在這個範圍內旋轉。 就像錶盤一樣,當錶針走過最大值的時候,就變成了最小值。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201121125009922.png?#pic_center) 同樣,這也等同於數學中的**取餘**運算。只要分母確定了,不管分子是多大,或者多小的數字,最終的結果也都是在一個確定的範圍之內。 比如我們對十進位制`5` 進行**取餘**計算,那麼最終的結果都是在`[0, 4]` 範圍之內,如下: - `0 % 5 = 0` - `2 % 5 = 2` - `397 % 5 = 2` - `99999 % 5 = 4` 可以總結出,對數字`N` 進行取餘,`N >= 2` 且為整數,那麼結果都在 `[0, N-1]` 範圍之內。 ### 4,二進位制反碼與補碼 知道了**溢位**,就可以介紹CPU 如何計算減法了。CPU 的減法運算使用了二進位制補碼,補碼實際上就是採用了**溢位**的原理。 我們直接給出**反碼與補碼**的定義: - 反碼定義:**正數的反碼等於其原碼,負數的反碼是其原碼除符號位外,按位取反。** - 補碼定義:**正數的補碼等於其原碼,負數的補碼是其反碼加1。** 比如下面的幾個數字: | 十進位制數 | 2 | 3 | -2 |-5 | |--|--|--|--|--| | **二進位制原碼** | **0010** | **0011** | **`1`010** | **`1`101** | | **二進位制反碼** | **0010** | **0011** | **`1`101** | **`1`010** | | **二進位制補碼** |**0010** | **0011** | **`1`110** |**`1`011** 我們用`4` 位二進位制補碼來計算 `3+(-2)`,如下: ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201121215718758.png?#pic_center) 最高位的`1` 發生上溢位,直接被捨去,所以結果是正確的。 所以,要記住,**真實的計算機中的二進位制是用補碼錶示的,而不是原碼**。 ### 5,總結 本篇文章主要介紹了: - CPU 只能做加法,不能做減法,減法要轉成加法做計算。 - 二進位制數字有三種表示方式: - 原碼:除符號位外的其他位,儲存該二進位制數的絕對值。 - 反碼:正數的反碼等於其原碼,負數的反碼是其原碼除符號位外,按位取反。 - 補碼:正數的補碼等於其原碼,負數的補碼是其反碼加1。 - 計算機中的數字採用二進位制補碼錶示,而不是原碼錶示。 - 補碼採用了溢位的原理。 - 計算機中的數字是有範圍限制的,超出限制會發生溢位。 - 超出上限叫做上溢位。最大值加1會發生上溢位,變為最小值。 - 超出下限叫做下溢位。最小值減1會發生下溢位,變為最大值。 (本節完。) --- **推薦閱讀:** [***決策樹演算法-理論篇***](https://www.cnblogs.com/codeshell/p/13948083.html) [***決策樹演算法-實戰篇***](https://www.cnblogs.com/codeshell/p/13984334.html) [***樸素貝葉斯分類-理論篇***](https://www.cnblogs.com/codeshell/p/13999440.html) [***設計模式之高質量程式碼***](https://www.cnblogs.com/codeshell/p/13968620.html) [***如何高效使用VIM***](https://www.cnblogs.com/codeshell/p/12726516.html) --- 歡迎關注作者公眾號,獲取更多技術乾貨。 ![碼農充電站pro](https://img-blog.csdnimg.cn/20200505082843773.png?#pic