上午看到了一篇关于位运算技巧的分享博客,其中有一个例子是关于用位运算求不大于某个数的2的最大幂数,看到他的例子就自己上手验证了一下,虽然不知道博主的思路来源,但验证结果却让人大跌眼镜
1.原文中给出的普通while循环方法:
public static void main(String[] args) {
// 不讨论负数情况
int N = Integer.MAX_VALUE - 123456789;
System.out.println(fixCompute(N));
}
public static int compute(int num) {
if (num == 0) {
return 0;
}
int sum = 1;
while (true) {
if (sum * 2 > num) {
return sum;
}
sum *= 2;
System.out.println(sum);
}
}
如果你在idea.properties中配置了idea.cycle.buffer.size=disabled,你会得到如下的控制台输出信息
不仅没有正常输出,而且代码执行会陷入死循环,问题就处在当int类型数据的从左到右数第31位如果为1且小于给定的整数,那么再乘以2就会导致整型溢出变为负数
修改之后的compute方法:
public static int compute(int num){
long sum = 1;
while(true){
if(sum * 2 > num){
return (int)sum;
}
sum *= 2;
}
}
2.原文中给出的位运算方法:
public static void main(String[] args) {
int N = Integer.MAX_VALUE - 123456789;
System.out.println("给定的整数N = " + N);
System.out.println("计算出2的幂 = " + bitCompute(N));
}
public static int bitCompute(int num) {
num |= num >> 1;
num |= num >> 2;
num |= num >> 4;
num |= num >> 8;
return (num + 1) >> 1;
}
运行之后你会得到一下输出:
这个结果真的有点小。。。
我怀疑博主写法的起因是因为我认为对于int整型数据,只左移15位是不能保证计算结果恰好是2的次方,我直接的想法就是对于二进制数如果从左到右数第31位为1,其余为0,那么得出的结果就是一个高16位全是1低15位全是0的数据,而正确的结果它本身,这显然不正确,这也说明了上面的错误不能简单通过使用无符号左移来解决
修改之后的bitCompute方法:
public static int bitCompute(int num) {
num |= num >> 1;
num |= num >> 2;
num |= num >> 4;
num |= num >> 8;
num |= num >> 16;
return (num + 1) >>> 1;
}
左移16位确保右起第一个1之后的所有位都被置位1,加1无符号左移1位确保原来的数据除右起第一个1之后的所有1都被置0,就得到了不大于给定整数的2的最大幂数