我們都知道,計算機的底層都是使用二進制數據進行數據流傳輸的,那麼為什麼會使用二進制表示計算機呢?或者說,什麼是二進制數呢?在拓展一步,如何使用二進制進行加減乘除?二進制數如何表示負數呢?本文将一一為你揭曉。
我們大家知道,計算機内部是由IC電子元件組成的,其中 CPU 和 内存 也是 IC 電子元件的一種,CPU和内存圖如下
CPU
内存
CPU 和 内存使用IC電子元件作為基本單元,IC電子元件有不同種形狀,但是其内部的組成單元稱為一個個的引腳。有人說CPU 和 内存内部都是超大規模集成電路,其實IC 就是集成電路(Integrated Circuit)。
IC元件切面圖
IC元件兩側排列的四方形塊就是引腳,IC的所有引腳,隻有兩種電壓: 0V 和 5V,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 即可,先記住這個結論,下面我們來演示一下。
-1 取反過程
具體來說,就是需要先獲取某個數值的二進制數,然後對二進制數的每一位做取反操作(0 —> 1 , 1 —> 0),最後再對取反後的數 1 ,這樣就完成了補數的獲取。
補數的獲取,雖然直觀上不易理解,但是邏輯上卻非常嚴謹,比如我們來看一下 1 - 1 的這個過程,我們先用上面的這個 1000 0001(它是1的補數,不知道的請看上文,正确性先不管,隻是用來做一下計算)來表示一下
1 - 1 分析圖
奇怪,1 - 1 會變成 130 ,而不是0,所以可以得出結論 1000 0001 表示 -1 是完全錯誤的。
那麼正确的該如何表示呢?其實我們上面已經給出結果了,那就是 1111 1111,來論證一下它的正确性
1 - 1 正确的分析圖
我們可以看到 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 的解析過程
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 填充高位即可。
邏輯運算的竅門
掌握邏輯和運算的區别是:将二進制數表示的信息作為四則運算的數值來處理就是算數,像圖形那樣,将數值處理為單純的 0 和 1 的羅列就是邏輯
計算機能夠處理的運算,大體可分為邏輯運算和算數運算,算數運算指的是加減乘除四則運算;邏輯運算指的是對二進制各個數位的 0 和 1分别進行處理的運算,包括邏輯非(NOT運算)、邏輯與(AND運算)、邏輯或(OR運算)和邏輯異或(XOR運算)四種。
- 邏輯非 指的是将 0 變成 1,1 變成 0 的取反操作
- 邏輯與 指的是”兩個都是 1 時,運算結果才是 1,其他情況下是 0”
- 邏輯或 指的是”至少有一方是 1 時,運算結果為 1,其他情況下運算結果都是 0”
- 邏輯異或 指的是 “其中一方是 1,另一方是 0時運算結果才是 1,其他情況下是 0”
與或非異或真值表
掌握邏輯運算的竅門,就是要摒棄二進制數表示數值這一個想法。大家不要把二進制數表示的值當作數值,應該把它看成是 開關上的 ON/OFF。
文章參考:
《程序是怎樣跑起來的》
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!