好久沒寫資料了,一方面是現在要寫的東西太多,思考的事情也太多,都沒什么時間來坐下來整理一下有趣的資料出來(其實還是因為自己太懶。)
今晚偶然間看到有人問起了不用內置 + 運算符怎么實現 + 法,這個問題讓我想起了不用比較運算符( < 、 > 、 = )怎么實現比較,其實都不是問題,用我的理解方式去理解其實就是一個小學的問題 = -= 。
那按我前面所說的就設置一個最終目標吧。
如何從零開始實現一個比較運算符。
(顯然今天這篇是講不到最終目標了,也許以后也講不到了,不過看完這篇文章后,你應該就知道怎么做了。)
首先我們先在數學上講得通道理,再拿到計算機里面看着實現,比較這事情呢,主要就看與 0 的結果。
比如:a > b => a - b > 0,那我們只需要知道 (a - b) 的結果的正負號就可以做出比較的結果了。
所以我們得有正負數的定義吧,然后還得有(a - b)的減法實現吧。
那么如何實現減法呢?一個正數加上一個負數是不是就有了減法呢?確實是。
所以今天的主題就回到標題上,只要有了加法,那就會有了減法,同樣也會有乘法,甚至就會有了比較運算,就如上解釋可知。
小時候,我們最早計算 9 + 11 的時候是這樣算的。
11
+ 9
-------
20
沒錯吧,這個我認為中國人都應該知道的吧,自行百度 豎式計算 。
其實,這個在二進制數中也是可行的,而上面那個是十進制的,二進制的就叫逢二進一。
11 => 1011
+ 9 => + 1001
------- --------
20 10100
這個結果你能接受的話,那我們就進入到代碼實現部分吧。
對於二進制的豎式計算中存在兩個邏輯,分別是 進位 和 合並 。
進位指對列同為 1 的執行逢二進一,合並指對列不同數值的執行為 1 。
以上邏輯將分別用二進制運算來取代,前者可以視為按位與(&)和左移一位,后者可以視為兩數執行按位或。
我附加一點二進制運算說明吧。
在位運算中 ^ 和 & 分別產生以下結果。
1011
^ 1001
---------
0010
數學意義為,模擬逢二進一的相加結果,保留未進位的結果,這是為了模擬豎式計算的加法結果。
(因為同為 1 則進位,同為 0 無結果,最終結果都是要將其變為 0 ,則可以理解為進位后的結果。)
1011
& 1001
---------
1001
數學意義為,標記所有進位位置,對其執行 << 1 即可得到進位的結果。
以 1011 + 1001 為例:
根據豎式運算可知:
1011 //
+ 1001 //
---------
00010 // 先 1011 ^ 1001 合並得到未進位的結果( 1011 ^ 1001 = 00010 )
10010 // 1011 & 1001 = 1001 不為 0 存在進位,故執行 1001 << 1 得到進位后的結果 1001
---------
10000 // 通過 00010 ^ 10010 合並得到未進位的結果( 00010 ^ 10010 = 10000 )
00100 // 00010 & 10010 = 00010 不為 0 存在進位,故執行 00010 << 1 得到進位后的結果 00100
---------
10100 // 通過 10000 ^ 00100 合並得到未進位的結果( 10000 ^ 00100 = 10100 )
00000 // 10000 & 00100 = 00000 ,此時結束運算。
---------
合並(^)結果后檢查是否為可進位(&),直到最終不存在可進位的數,則說明加法結束。
最后貼個代碼。
uint add(uint a, uint b)
{
uint sum, carry;
while(1)
{
sum = a ^ b, carry = a & b;
if(0 == carry)
{
break;
}
a = sum, b = carry << 1;
}
return sum;
}
uint Add(uint a, uint b)
{
uint sum = a ^ b, carry = a & b;
return (0 != carry) ? Add(sum, carry << 1) : sum;
}