程序員需要了解的硬核知識之二進制

8{icon} {views}

我們都知道,計算機的底層都是使用二進制數據進行數據流傳輸的,那麼為什麼會使用二進製表示計算機呢?或者說,什麼是二進制數呢?在拓展一步,如何使用二進制進行加減乘除?二進制數如何表示負數呢?本文將一一為你揭曉。

為什麼用二進製表示

我們大家知道,計算機內部是由IC电子元件組成的,其中 CPU內存 也是 IC 电子元件的一種,CPU和內存圖如下

CPU 和 內存使用IC电子元件作為基本單元,IC电子元件有不同種形狀,但是其內部的組成單元稱為一個個的引腳。有人說CPU 和 內存內部都是超大規模集成電路,其實IC 就是集成電路(Integrated Circuit)。

IC元件兩側排列的四方形塊就是引腳,IC的所有引腳,只有兩種電壓: 0V5V,IC的這種特性,也就決定了計算機的信息處理只能用 0 和 1 表示,也就是二進制來處理。一個引腳可以表示一個 0 或 1 ,所以二進制的表示方式就變成 0、1、10、11、100、101等,雖然二進制數並不是專門為 引腳 來設計的,但是和 IC引腳的特性非常吻合。

計算機的最小集成單位為 ,也就是 比特(bit),二進制數的位數一般為 8位、16位、32位、64位,也就是 8 的倍數,為什麼要跟 8 扯上關係呢? 因為在計算機中,把 8 位二進制數稱為 一個字節, 一個字節有 8 位,也就是由 8個bit構成。

為什麼1個字節等於8位呢?因為 8 位能夠涵蓋所有的字符編碼,這個記住就可以了。

字節是最基本的計量單位,位是最小單位。

用字節處理數據時,如果数字小於存儲數據的字節數 ( = 二進制的位數),那麼高位就用 0 填補,高位和數學的數字錶示是一樣的,左側表示高位,右側表示低位。比如 這個六位數用二進制數來表示就是 100111,只有6位,高位需要用 0 填充,填充完后是 00100111,佔一個字節,如果用 16 位表示 就是 0000 0000 0010 0111佔用兩個字節。

我們一般口述的 32 位和 64位的計算機一般就指的是處理位數,32 位一次可以表示 4個字節,64位一次可以表示8個字節的二進制數。

我們一般在軟件開發中用十進制數表示的邏輯運算等,也會被計算機轉換為二進制數處理。對於二進制數,計算機不會區分他是 圖片、音頻文件還是数字,這些都是一些數據的結合體。

什麼是二進制數

那麼什麼是二進制數呢?為了說明這個問題,我們先把 00100111 這個數轉換為十進制數看一下,二進制數轉換為十進制數,直接將各位置上的值 * 位權即可,那麼我們將上面的數值進行轉換

也就是說,二進制數代表的 00100111 轉換成十進制就是 39,這個 39 並不是 3 和 9 兩個数字連着寫,而是 3 * 10 + 9 * 1,這裏面的 10 , 1 就是位權,以此類推,上述例子中的位權從高位到低位依次就是 7 6 5 4 3 2 1 0 。這個位權也叫做次冪,那麼最高位就是2的7次冪,2的6次冪 等等。二進制數的運算每次都會以2為底,這個2 指得就是基數,那麼十進制數的基數也就是 10 。在任何情況下位權的值都是 數的位數 – 1,那麼第一位的位權就是 1 – 1 = 0, 第二位的位權就睡 2 – 1 = 1,以此類推。

那麼我們所說的二進制數其實就是 用0和1兩個数字來表示的數,它的基數為2,它的數值就是每個數的位數 * 位權再求和得到的結果,我們一般來說數值指的就是十進制數,那麼它的數值就是 3 * 10 + 9 * 1 = 39。

移位運算和乘除的關係

在了解過二進制之後,下面我們來看一下二進制的運算,和十進制數一樣,加減乘除也適用於二進制數,只要注意逢 2 進位即可。二進制數的運算,也是計算機程序所特有的運算,因此了解二進制的運算是必須要掌握的。

首先我們來介紹移位 運算,移位運算是指將二進制的數值的各個位置上的元素坐左移和右移操作,見下圖

上述例子中還是以 39 為例,我們先把十進制的39 轉換為二進制的 0010 0111,然後向左移位 << 一個字節,也就變成了 0100 1110,那麼再把此二進制數轉換為十進制數就是上面的78, 十進制的78 竟然是 十進制39 的2倍關係。我們在讓 0010 0111 左移兩位,也就是 1001 1100,得出來的值是 156,相當於擴大了四倍!

因此你可以得出來此結論,左移相當於是數值擴大的操作,那麼右移 >> 呢?按理說右移應該是縮小 1/2,1/4 倍,但是39 縮小二倍和四倍不就變成小數了嗎?這個怎麼表示呢?請看下一節

便於計算機處理的補數

剛才我們沒有介紹右移的情況,是因為右移之後空出來的高位數值,有 0 和 1 兩種形式。要想區分什麼時候補0什麼時候補1,首先就需要掌握二進制數表示負數的方法。

二進制數中表示負數值時,一般會把最高位作為符號來使用,因此我們把這個最高位當作符號位。 符號位是 0 時表示正數,是 1 時表示 負數。那麼 -1 用二進制數該如何表示呢?可能很多人會這麼認為: 因為 1 的二進制數是 0000 0001,最高位是符號位,所以正確的表示 -1 應該是 1000 0001,但是這個答案真的對嗎?

計算機世界中是沒有減法的,計算機在做減法的時候其實就是在做加法,也就是用加法來實現的減法運算。比如 100 – 50 ,其實計算機來看的時候應該是 100 + (-50),為此,在表示負數的時候就要用到二進制補數,補數就是用正數來表示的負數。

為了獲得補數,我們需要將二進制的各數位的數值全部取反,然後再將結果 + 1 即可,先記住這個結論,下面我們來演示一下。

具體來說,就是需要先獲取某個數值的二進制數,然後對二進制數的每一位做取反操作(0 —> 1 , 1 —> 0),最後再對取反后的數 +1 ,這樣就完成了補數的獲取。

補數的獲取,雖然直觀上不易理解,但是邏輯上卻非常嚴謹,比如我們來看一下 1 – 1 的這個過程,我們先用上面的這個 1000 0001(它是1的補數,不知道的請看上文,正確性先不管,只是用來做一下計算)來表示一下

奇怪,1 – 1 會變成 130 ,而不是0,所以可以得出結論 1000 0001 表示 -1 是完全錯誤的。

那麼正確的該如何表示呢?其實我們上面已經給出結果了,那就是 1111 1111,來論證一下它的正確性

我們可以看到 1 – 1 其實實際上就是 1 + (-1),對 -1 進行上面的取反 + 1 后變為 1111 1111, 然後與 1 進行加法運算,得到的結果是九位的 1 0000 0000,結果發生了溢出,計算機會直接忽略掉溢出位,也就是直接拋掉 最高位 1 ,變為 0000 0000。也就是 0,結果正確,所以 1111 1111 表示的就是 -1 。

所以負數的二進製表示就是先求其補數,補數的求解過程就是對原始數值的二進制數各位取反,然後將結果 + 1

當然,結果不為 0 的運算同樣也可以通過補數求得正確的結果。不過,有一點需要注意,當運算結果為負的時候,計算結果的值也是以補數的形式出現的,比如 3 – 5 這個運算,來看一下解析過程

3 – 5 的運算,我們按着上面的思路來過一遍,計算出來的結果是 1111 1110,我們知道,這個數值肯定表示負數,但是負數無法直接用十進製表示,需要對其取反+ 1,算出來的結果是 2,因為 1111 1110的高位是 1,所以最終的結果是 -2。

編程語言的數據類型中,有的可以處理負數,有的不可以。比如 C語言中不能處理負數的 unsigned short類型,也有能處理負數的short類型 ,都是兩個字節的變量,它們都有 2 的十六次冪種值,但是取值範圍不一樣,short 類型的取值範圍是 -32768 – 32767 , unsigned short 的取值範圍是 0 – 65536。

仔細思考一下補數的機制,就能明白 -32768 比 32767 多一個數的原因了,最高位是 0 的正數有 0 ~ 32767 共 32768 個,其中包括0。最高位是 1 的負數,有 -1 ~ -32768 共 32768 個,其中不包含0。0 雖然既不是正數也不是負數,但是考慮到其符號位,就將其歸為了正數。

算數右移和邏輯右移的區別

在了解完補數后,我們重新考慮一下右移這個議題,右移在移位后空出來的最高位有兩種情況 0 和 1。當二進制數的值表示圖形模式而非數值時,移位后需要在最高位補0,類似於霓虹燈向右平移的效果,這就被稱為邏輯右移

將二進制數作為帶符號的數值進行右移運算時,移位后需要在最高位填充移位前符號位的值( 0 或 1)。這就被稱為算數右移。如果數值使用補數表示的負數值,那麼右移后在空出來的最高位補 1,就可以正確的表示 1/2,1/4,1/8等的數值運算。如果是正數,那麼直接在空出來的位置補 0 即可。

下面來看一個右移的例子。將 -4 右移兩位,來各自看一下移位示意圖

如上圖所示,在邏輯右移的情況下, -4 右移兩位會變成 63, 顯然不是它的 1/4,所以不能使用邏輯右移,那麼算數右移的情況下,右移兩位會變為 -1,顯然是它的 1/4,故而採用算數右移。

那麼我們可以得出來一個結論:左移時,無論是圖形還是數值,移位后,只需要將低位補 0 即可;右移時,需要根據情況判斷是邏輯右移還是算數右移。

下面介紹一下符號擴展:將數據進行符號擴展是為了產生一個位數加倍、但數值大小不變的結果,以滿足有些指令對操作數位數的要求,例如倍長於除數的被除數,再如將數據位數加長以減少計算過程中的誤差。

以8位二進製為例,符號擴展就是指在保持值不變的前提下將其轉換成為16位和32位的二進制數。將0111 1111這個正的 8位二進制數轉換成為 16位二進制數時,很容易就能夠得出0000 0000 0111 1111這個正確的結果,但是像 1111 1111這樣的補數來表示的數值,該如何處理?直接將其表示成為1111 1111 1111 1111就可以了。也就是說,不管正數還是補數表示的負數,只需要將 0 和 1 填充高位即可。

邏輯運算的竅門

掌握邏輯和運算的區別是:將二進制數表示的信息作為四則運算的數值來處理就是算數,像圖形那樣,將數值處理為單純的 01 的羅列就是邏輯

計算機能夠處理的運算,大體可分為邏輯運算和算數運算,算數運算指的是加減乘除四則運算;邏輯運算指的是對二進制各個數位的 0 和 1分別進行處理的運算,包括邏輯非(NOT運算)、邏輯與(AND運算)、邏輯或(OR運算)和邏輯異或(XOR運算)四種。

  • 邏輯非 指的是將 0 變成 1,1 變成 0 的取反操作
  • 邏輯與 指的是”兩個都是 1 時,運算結果才是 1,其他情況下是 0″
  • 邏輯或 指的是”至少有一方是 1 時,運算結果為 1,其他情況下運算結果都是 0″
  • 邏輯異或 指的是 “其中一方是 1,另一方是 0時運算結果才是 1,其他情況下是 0”

掌握邏輯運算的竅門,就是要摒棄二進制數表示數值這一個想法。大家不要把二進制數表示的值當作數值,應該把它看成是 開關上的 ON/OFF

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計最專業,超強功能平台可客製化

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家公司費用怎麼算?