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

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

公號:碼農充電站pro
主頁:https://codeshellme.github.io

計算機最基本的工作是處理資料,而資料的最底層表現形式是二進位制,並非是我們人類熟悉的十進位制。可以這麼認為,計算機其實是很“笨的”,它只理解二進位制資料。

今天,主要介紹計算機是怎樣做加減運算的。你可能會想,加減運算?這麼簡單的事情,還用介紹?也許還真不是你想的那樣。

計算機的運算是由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 0000 -8 1000
1 0001 -1 1001
2 0010 -2 1010
3 0011 -3 1011
4 0100 -4 1100
5 0101 -5 1101
6 0110 -6 1110
7 0111 -7 1111

上表中的最高位的符號位,已標紅。

要注意,對於有符號的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,過程如下:

可以看到,用原碼計算加法是沒有問題的。

用原碼進行減法計算

我們再用原碼來計算減法,因為CPU 只會計算加法,所以計算減法時,會將減法轉換成加法。

比如,用4 位二進位制數來計算計算 3 - 2,會將其轉換成 3 + (-2), 過程如下:

可以看到 3-2 計算出來的結果是 -5,顯然是錯誤的。

所以,用二進位制原碼來計算減法是行不通的。實際上,計算機計算減法用的是補碼

在介紹補碼之前,我們先來看下什麼是溢位

3,數字溢位

計算機中數字的表示是需要記憶體空間的,不同型別的數字所能佔用的空間是不一樣的。

比如,在Java 語言中short 型別佔用 2 個位元組,int 型別佔用 4 個位元組。

一個位元組等於 8 位。

既然空間大小是有限制的,所以計算機中的數字也是有範圍的,即上限下限,如果數字超出限制,就會產生溢位。超出上限叫上溢位,超出下限叫下溢位而溢位的部分會直接被捨去

就像我們在上文中介紹的,對於N 位二進位制有符號整數,所能表示的範圍是 [-2^(N-1), 2^(N-1) - 1]

由於溢位的部分會被捨去,那麼最大值加1,將發生上溢位,變為最小值;最小值減1,將發生下溢位,變為最大值。

我們用Java 中的int 型別來驗證,Javaint 型別的最大、最小值分別是:

  • 最大值:Integer.MAX_VALUE,是 2147483647
  • 最小值:Integer.MIN_VALUE,是 -2147483648

用下面程式碼驗證:

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 變為最大值。

所以,在計算機中,只要一個整數的型別確定了,那麼它所能佔用的記憶體空間大小也就確定了,從而它所能表示的數字範圍也就確定了。那麼不管給這個整數加多大的數字,或者減多大的數字,最終的結果都只能在這個範圍內旋轉。

就像錶盤一樣,當錶針走過最大值的時候,就變成了最小值。

同樣,這也等同於數學中的取餘運算。只要分母確定了,不管分子是多大,或者多小的數字,最終的結果也都是在一個確定的範圍之內。

比如我們對十進位制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 1010 1101
二進位制反碼 0010 0011 1101 1010
二進位制補碼 0010 0011 1110 1011

我們用4 位二進位制補碼來計算 3+(-2),如下:

最高位的1 發生上溢位,直接被捨去,所以結果是正確的。

所以,要記住,真實的計算機中的二進位制是用補碼錶示的,而不是原碼

5,總結

本篇文章主要介紹了:

  • CPU 只能做加法,不能做減法,減法要轉成加法做計算。
  • 二進位制數字有三種表示方式:
    • 原碼:除符號位外的其他位,儲存該二進位制數的絕對值。
    • 反碼:正數的反碼等於其原碼,負數的反碼是其原碼除符號位外,按位取反。
    • 補碼:正數的補碼等於其原碼,負數的補碼是其反碼加1。
  • 計算機中的數字採用二進位制補碼錶示,而不是原碼錶示。
    • 補碼採用了溢位的原理。
  • 計算機中的數字是有範圍限制的,超出限制會發生溢位。
    • 超出上限叫做上溢位。最大值加1會發生上溢位,變為最小值。
    • 超出下限叫做下溢位。最小值減1會發生下溢位,變為最大值。

(本節完。)


推薦閱讀:

決策樹演算法-理論篇

決策樹演算法-實戰篇

樸素貝葉斯分類-理論篇

設計模式之高質量程式碼

如何高效使用VIM


歡迎關注作者公眾號,獲取更多技術乾貨。