計算機是怎麼懂加減乘除的


計算機是怎麼懂加減乘除的

在學習編程的過程中,計算兩個數的和 int a = b + c 這樣的代碼肯定經常寫到,但是計算機到底是怎麼計算出來的呢?

加法

說到加法,首先提到的一個概念就是全加器,下圖是一個全加器的數字邏輯電路。


計算機是怎麼懂加減乘除的


其中,異或門的輸出 Y = A ^ B ,與非門的輸出就是先與再非,即 Y = !(A & B) 。這裡我就不再列真值表了,我們再來看一下上面全加器的邏輯,通過推導可以得到下面公式:

Sum = A ^ B ^ Cin
Cout = (A ^ B & Cin) | (A & B)

這是一位(1 bit)的加法運算,當我們把 8 個全加器級聯起來的話(低位的 Cout 是高位的 Cin )就實現了一個 8 位的加法器。我們可以用代碼模擬一下(LeetCode 371. 兩整數之和):

計算機是怎麼懂加減乘除的

說到這裡,大家應該大體的瞭解計算機是怎麼計算加法的了,那減法呢?


減法

加法是進位,減法需要考慮的則是借位,是這樣嗎?按我們小時候對加減法學習的經驗是這樣的,但是計算機不是這麼處理的。計算機“只有加法”,“沒有減法”。肯定有同學說,不可能,那我們算 int a = b - c 是怎麼得出來結果的呢?說到這個首先要了解另外一個概念——補碼。

補碼

我們知道,計算機中對於有符號數,用最高位作為符號位,“0” 代表 “+” ,“1” 代表 “-” ;其餘數位用作數值位,代表數值。比如 Byte 類型的取值範圍為 -128 ~ 127。其中,表示數值的只有 7 位,首位表示正負。

怎麼推導一個數字的補碼呢?補碼規定,正數和 0 的補碼就是其原碼(原碼、反碼的定義這裡就不多贅述),負數的補碼是其正數的原碼取反再加 1 。

聽起來有點繞,舉個例子,求 -10 的補碼:

十進制 10 的原碼(按 8 位舉例)為 0000 1010,其反碼為 1111 0101,取反後再加 1 即為其補碼: 1111 0110。因此,-10 的補碼為 1111 0110。

不知道寫到這裡,大家有沒有發現什麼端倪?我們再回到減法計算來。

a = b - c
實際上等同於
a = b + ( -c )

我們算一下下面的式子:

  • 12 - 5
  • = 0000 1100 + 1111 1011
  • = (1)0000 0111
  • = 7 括號裡為進位,因為只有 8 位,所以高於 8 位的進位要去掉。
  • 7 - 9
  • = 0000 1111 + 1111 0111
  • = 1111 1110
  • = -2

通過這兩個例子是不是就清楚了計算機是如何計算減法的了?


乘法

通過說減法,我們是不是對乘法也有一定的啟發了呢?乘法其實就是循環的加法。比如 5 * 3 實際上就是 5 + 5 + 5。貌似就說完了。實際上不僅僅如此的。現在有一個電子器件叫做乘法器,其可以實現二進制的乘法、除法等運算。我們同樣以 5 * 3 做為例子,講解一下乘法器計算乘法的流程。

  • 5 * 3 = 0000 0101 * 0000 0011
3 的第 0 位為 1 ,那麼 5 左移 0 位,結果為 0000 0101 ;
3 的第 1 位為 1 ,那麼 5 左移 1 位,結果為 0000 1010 ;
3 的其他高位都為 0 ,因此不再左移;
兩次左移的結果累加,即 0000 0101 + 0000 1010 = 0000 1111 ,即十進制的 15 。

雖然有乘法器,但是我們發現實際的最終操作流程還是加法和位移操作計算的乘法運算。我們寫的代碼中的乘法到底是用乘法器算的還是轉化成加法運算,我們也並不太確定,有些編譯器編譯的時候會對代碼進行優化,會選取最優的一種算法來計算結果。


除法

除法可以通過減法來實現,比如 10 / 3 等價於 10 一直減 3 直到被減數小於 3 ,減了 3 次,那麼 10 / 3 的結果就為 3 了,餘數為減完剩下的值 1 。

其實上面已經提到了乘法器,除法的原理同樣也類似(這裡不說浮點數的除法,只說整數的除法),但是稍微複雜一點。( LeetCode 29. 兩數相除)

同樣我們舉個例子來說明一下。

  • 209 / 5 = 1101 0001 / 0000 0101
首先取 209 的最高位 1 (101 0001) 小於 101
左移一位 11 (01 0001) 小於 101
左移一位 110 (1 0001) 大於 101 ,商 1 ,餘 1 (1 0001)
左移一位 11 (0001) 小於 101
左移一位 110 (001) 大於 101 ,商 1 ,餘 1 (001)
左移一位 10 (01) 小於 101
左移一位 100 (1) 小於 101
左移一位 1001 大於 101 ,商 1 ,餘 100

於是結果為 00101001 (41),餘數為 100 (4)。

通過上面我們發現,計算機計算加減乘除,都是轉換為加法和位移運算完成的,而事實上也是如此。可能我們平時編程過程中可能用不到這些內容,直接寫 + - * / 就可以了,但是作為一名程序員,還是有必要了解一下計算機基礎的編碼以及基礎的運算的。祝大家學習愉快!


分享到:


相關文章: