程序員須要瞭解的硬核知識之二進制

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

爲何用二進制表示

咱們你們知道,計算機內部是由IC電子元件組成的,其中 CPU內存 也是 IC 電子元件的一種,CPU和內存圖以下編程語言

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

IC元件兩側排列的四方形塊就是引腳,IC的全部引腳,只有兩種電壓: 0V5V,IC的這種特性,也就決定了計算機的信息處理只能用 0 和 1 表示,也就是二進制來處理。一個引腳能夠表示一個 0 或 1 ,因此二進制的表示方式就變成 0、一、十、十一、100、101等,雖然二進制數並非專門爲 引腳 來設計的,可是和 IC引腳的特性很是吻合。編碼

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

爲何1個字節等於8位呢?由於 8 位可以涵蓋全部的字符編碼,這個記住就能夠了。code

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

用字節處理數據時,若是數字小於存儲數據的字節數 ( = 二進制的位數),那麼高位就用 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

相關文章
相關標籤/搜索