聊聊使用位運算來實現加法(老物)

很久沒寫資料了,一方面是如今要寫的東西太多,思考的事情也太多,都沒什麼時間來坐下來整理一下有趣的資料出來(其實仍是由於本身太懶。)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;
}
相關文章
相關標籤/搜索