很久沒寫資料了,一方面是如今要寫的東西太多,思考的事情也太多,都沒什麼時間來坐下來整理一下有趣的資料出來(其實仍是由於本身太懶。)ui
今晚偶然間看到有人問起了不用內置 + 運算符怎麼實現 + 法,這個問題讓我想起了不用比較運算符( < 、 > 、 = )怎麼實現比較,其實都不是問題,用個人理解方式去理解其實就是一個小學的問題 = -= 。code
那按我前面所說的就設置一個最終目標吧。數學
如何從零開始實現一個比較運算符。class
(顯然今天這篇是講不到最終目標了,也許之後也講不到了,不過看完這篇文章後,你應該就知道怎麼作了。)百度
首先咱們先在數學上講得通道理,再拿到計算機裏面看着實現,比較這事情呢,主要就看與 0 的結果。 好比:a > b => a - b > 0,那咱們只須要知道 (a - b) 的結果的正負號就能夠作出比較的結果了。 因此咱們得有正負數的定義吧,而後還得有(a - b)的減法實現吧。 那麼如何實現減法呢?一個正數加上一個負數是否是就有了減法呢?確實是。 因此今天的主題就回到標題上,只要有了加法,那就會有了減法,一樣也會有乘法,甚至就會有了比較運算,就如上解釋可知。二進制
小時候,咱們最先計算 9 + 11 的時候是這樣算的。計算機
11 + 9 ------- 20
沒錯吧,這個我認爲中國人都應該知道的吧,自行百度 豎式計算 。 其實,這個在二進制數中也是可行的,而上面那個是十進制的,二進制的就叫逢二進一。時間
11 => 1011 + 9 => + 1001 ------- -------- 20 10100
這個結果你能接受的話,那咱們就進入到代碼實現部分吧。思考
對於二進制的豎式計算中存在兩個邏輯,分別是 進位 和 合併 。 進位指對列同爲 1 的執行逢二進一,合併指對列不一樣數值的執行爲 1 。 以上邏輯將分別用二進制運算來取代,前者能夠視爲按位與(&)和左移一位,後者能夠視爲兩數執行按位或。 我附加一點二進制運算說明吧。while
在位運算中 ^ 和 & 分別產生如下結果。
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; }