位操作實現的加法算法

java裏的相加運算,int32位只能有31位有效。。。這真沒轍,當然整數爆了就變負數了

第一種方法,逐位相加

	static int bitAdd(int a, int b)
	{
		//如果兩個數有一個爲0直接返回這個數
		//相對來說b==0的機會比a==0要大一些
		if(b == 0 || a == 0)
		{
			return a | b;
		}
		//移位變量,表示每次位移多少位
		int shift = 1;
		//位指針用來表示當前計算到那一位,同時它也是一個掩碼
		//遞增指針用來標記從位指針開始向連續的1相加,也是掩碼
		int bitPos,incPos;
		//從最後一位逐位向前,將b的每一位爲1的值加到a中
		//每完成一位,位指針左移一位,當位指針的掩碼爲0
		//時表示所有位相加完畢
		for(bitPos = 1; bitPos != 0; bitPos <<= shift)
		{
			//如果b中位指針所指的位爲0,則不進行相加
			if((b & bitPos) != 0)
			{
				//遞增指針從位指針位置開始標記,逢1進1
				//直到某一位爲0變1停止
				for(incPos = bitPos; incPos != 0; incPos <<= shift)
				{
					//如果a的當前指針位爲1,則變1爲0,左移1位繼續
					if((a & incPos) != 0)
					{
						//a &= ~incPos;這麼寫的我不認識他
						a ^= incPos;
					}
					//如果a的當前指針位爲0,則變0爲1,跳出進行b的下一位
					else
					{
						a |= incPos;
						break;
					}
				}
			}
		}
		return a;
	}

第二種,不同位相加,同位進一
這種方法比第一種好的地方是不用運算那麼多次數,統一運算,包括所有不同位相加的異或操作a^b,所有相同位(指都爲1)相加的進位操作a&b <<1。但也有缺點,如果兩個數都爲正數或者負數則無影響,如果兩數中有一個爲負數,運算次數雖然可以預見,但還是太多了。如果實在難以理解,下邊這個輸出的結果應該便於理解。

System.out.println(bitAdd1(123214123, 6222224));

a =          00000111010110000001100100101011
b =          00000000010111101111000110010000
a ^ b =      00000111000001101110100010111011
a & b << 1 = 00000000101100000010001000000000
===========================>
a =          00000111000001101110100010111011
b =          00000000101100000010001000000000
a ^ b =      00000111101101101100101010111011
a & b << 1 = 00000000000000000100000000000000
===========================>
a =          00000111101101101100101010111011
b =          00000000000000000100000000000000
a ^ b =      00000111101101101000101010111011
a & b << 1 = 00000000000000001000000000000000
===========================>
a =          00000111101101101000101010111011
b =          00000000000000001000000000000000
a ^ b =      00000111101101100000101010111011
a & b << 1 = 00000000000000010000000000000000
===========================>
a =          00000111101101100000101010111011
b =          00000000000000010000000000000000
a ^ b =      00000111101101110000101010111011
a & b << 1 = 00000000000000000000000000000000
===========================>
b == 0 return 129436347

這個代碼是網上比較流行的原文,不過有瑕疵。。。

	static int bitAdd1(int a, int b)
	{
	
		if (b == 0)
		{
			return a;
		}
		else
		{
			return bitAdd1(a ^ b, (a & b) << 1);
		}
	}

這裏邊的b==0實際上增加了代碼一次遞歸,從上邊輸出來看,在倒數第二步時,只需要a|b就能得到最終的結果,而不需額外遞歸一次。

同時還有一種情況還需要考慮,當a==b時,直接返回a<<1是不是最效率,其實不是,相同的兩個數相加,只需要上行邏輯執行2次,第一拿到0和這個數的2倍,第二次a|b。但是從概率來考慮,兩個相等的數碰到概率極低,所以相對更多次遞歸中的額外判斷所浪費的時間,不用它會更好一些。

public class ddd
{
	
	static int bitAdd(int a, int b)
	{
	
		// 如果兩個數有一個爲0直接返回這個數
		// 相對來說b==0的機會比a==0要大一些
		if (b == 0 || a == 0)
		{
			return a | b;
		}
		// 移位變量,表示每次位移多少位
		int shift = 1;
		// 位指針用來表示當前計算到那一位,同時它也是一個掩碼
		// 遞增指針用來標記從位指針開始向連續的1相加,也是掩碼
		int bitPos, incPos;
		// 從最後一位逐位向前,將b的每一位爲1的值加到a中
		// 每完成一位,位指針左移一位,當位指針的掩碼爲0
		// 時表示所有位相加完畢
		for (bitPos = 1; bitPos != 0; bitPos <<= shift)
		{
			// 如果b中位指針所指的位爲0,則不進行相加
			if ((b & bitPos) != 0)
			{
				// 遞增指針從位指針位置開始標記,逢1進1
				// 直到某一位爲0變1停止
				for (incPos = bitPos; incPos != 0; incPos <<= shift)
				{
					// 如果a的當前指針位爲1,則變1爲0,左移1位繼續
					if ((a & incPos) != 0)
					{
						// a &= ~incPos;這麼寫的我不認識他
						a ^= incPos;
					}
					// 如果a的當前指針位爲0,則變0爲1,跳出進行b的下一位
					else
					{
						a |= incPos;
						break;
					}
				}
			}
		}
		return a;
	}
	
	static int bitAdd1(int a, int b)
	{
	
		if ((a & b) == 0)
		{
			System.out.print("a & b == 0   a | b   a + b = ");
			return a | b;
		}
		else
		{
			System.out.println("a =          " + get32BinaryString(a));
			System.out.println("b =          " + get32BinaryString(b));
			System.out.println("a ^ b =      " + get32BinaryString(a ^ b));
			System.out.println("a & b << 1 = " + get32BinaryString((a & b) << 1));
			System.out.println("===========================>");
			return bitAdd1(a ^ b, (a & b) << 1);
		}
	}
	
	private static String	defaultB32	= "00000000000000000000000000000000";
	
	public static String get32BinaryString(int value)
	{
	
		String binary = Integer.toBinaryString(value);
		String b32 = defaultB32.substring(0, defaultB32.length() - binary.length()) + binary;
		return b32;
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章