中介紹了布爾邏輯、數學和電路的關系,我們也得到了與門、或門、非門、或非門、與非門、異或門等門電路以及一個加法器,並且了解了計算機是如何做加法的,這篇文章介紹一下計算機是如何做減法以及乘除法的。
0x01
—
減法
我們先看一下十進制里減法怎么做,存在什么問題?
457減368個位數7減8是不夠減的,所以需要向十位借位,17減8等於9。5變成4,4減6又是不夠減,向百位借位,14減6等於8。百位3減3等於0,結果是89。這個是我們自己計算減法時候一種很通用的方法,這種方法用計算機處理有兩個問題。一個問題是借位,另一個問題是需要掌握20以內的減法。之前的機械計算機減法確實也是這么做的,不過隨着歷史的車輪滾滾前行,計算機的發展過程中人才輩出,還是有人發現了另外一種計算減法的簡單方法-補碼,成功的把減法當成了加法來處理。
我們來看一下,457 – 368等於457 + (1000 – 368) – 1000。1000 – 368等於632。632就是368在10進制數里的補碼。457+632 = 1089,減去剛才的1000,可不就是89嗎?但是這里可能有人會問計算補碼不還是得計算1000減368,沒解決根本問題啊。但是在二進制里,計算起來就方便多了(二進制真是化簡為繁的重大發現)。其實對於一個只能計算三位數的計算機來講,負368計算補碼的正確方式999-368+1。因為三位數的計算機表示不了1000。對於二進制來講,那就是先取反,再加一,取反用非門就可以搞定了。計算機里有符號數用高位表示符號,1是負數,0是正數,所以-1在計算機里用二進制的表示應該是1 1 1 1 1 1 1 1,對應的無符號數是255。
0x02
—
乘法
視頻:https://zh.coursera.org/lecture/jisuanji-zucheng/402-cheng-fa-qi-de-shi-xian-lp2kEc
乘法怎么算呢?同樣我們先看下十進制乘法123 * 321是怎么計算的。
123 * 321 = 123 *(3 * 100 + 2 * 10 + 1)= (123 * 3) * 100 + (123 * 2) * 10 + 123 = 36900 + 2460 + 123 = 39483。
這樣就轉化為乘法、左移和加法操作。有的同學可能又會問,123 * 3計算機怎么算?先別動手,我們還有二進制,最終的乘法其實已經被簡化為被乘數乘以10以內的數,在二進制里,那就是被乘數乘以2以內的數,2以內的數只有0和1,是不是就簡單多了。我們看下11 * 12的二進制數相乘的計算過程。
1011 * 1100 = 1011 * 0 + 10110(1011左移一位)* 0 + 101100(1011左移兩位)* 1 + 1011000(1011左移三位)* 1 。這下是不是簡單多了,不是乘以0就是乘以1,最后通過加法器相加就好了。
public class Multiplier { /** * 模擬計算機乘法器兩數相乘的過程: * 1.數學上m * n表示n個m相加 * 2.但計算機乘法器是二進制的,m乘以n中第i位不為0的比特位意味着m向左移動i位,把所有這樣的結果相加,即為乘法器的計算過程 * @param m 被乘數 * @param n 乘數 * @return 積 */ public static long multiply(int m, int n) { if (m == 0 || n == 0) return 0; long result = 0; // 獲取乘數從最高比特位往低比特位第一個不為零的比特位之間0比特位的數量 int loop = 64 - Long.numberOfLeadingZeros(n); for (int i = 0; i < loop; i++) { if (((1 << i) & n) != 0) result += m << i; } return result; } }
0x03
—
除法
乘法搞定了,就差除法了,除法怎么算呢?老規矩,我們先看下10進制123除以4的計算方法。
123 最高位1,比4小,結果是0,余數是1;
123 上一步的余數1左移1位是10,加上2是12,12除以4等於3,余數是0;
123 最后一位是3,比4小,結果是0,余數是3。
所以結果是30,余數是3。
沒毛病,讓我們看下二進制計算的過程。
1 1 1 1 0 1 1 中的1 比 100小,結果是0,余數是1。
1 1 1 1 0 1 1 上一步中的余數1左移1位,加上1是11,比100小,結果是0,余數是11。
1 1 1 1 0 1 1 上一步中的余數11左移1位,加上1是111,比100大,結果是1,余數是11。
1 1 1 1 0 1 1 上一步中的余數11左移1位,加上1是111,比100大,結果是1,余數是11。
1 1 1 1 0 1 1 上一步中的余數11左移1位,加上0是110,比100大,結果是1,余數是10。
1 1 1 1 0 1 1 上一步中的余數10左移1位,加上1是101,比100大,結果是1,余數是1。
1 1 1 1 0 1 1 上一步中的余數1左移1位,加上1是11,比100小,結果是0,余數是11。
所以結果是0011110(十進制30),余數是11(十進制數3)。
0xff
—
總結
加法是計算機中最基本的操作,我們已經有了加法器,計算加法毫無壓力。減法則通過補碼,巧妙的轉化成了加法的運算。而乘法是通過左移和加法完成的,除法則是通過左移和減法完成的。我們通過加法器以及移位器就能完成基本的加減乘除算術運算。但是這樣只能完成兩個數的操作,如果想完成三個數的操作怎么辦呢?總不能計算兩個數,人工記錄下來結果,然后再與第三個數相加吧,這就需要另外一個東西-寄存器了,有了寄存器,計算機就可以暫存一些中間結果,持續的執行代碼進行計算了。下篇文章,給大家分享一下通過電路怎么記錄數據。