位操作实现的加法算法

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;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值