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