&的妙用

    最近看Netty源码,看到了一段这样的代码:

private static boolean isPowerOfTwo(int val) {
        return (val & -val) == val;
}

一开始无法理解是什么意思,看方法名然后搜了一下,发现是用来判断一个数字是否为2的次方的,例如1,2,4,8,……这样的数。那为什么可以用来判断一个数是否为2的次方呢(要是我来写,估计写个循环然后不断乘2直到和给的入参相同return true,看上去写的弱爆了),明显他这个写法比较高端。所以来学习一下高端写法的原理。
    涉及到位运算,我们第一个想法是推出值的补码,因为计算机运算都是基于补码运算的。所以这里就有涉及到原码反码补码的概念了,大学一年级老掉牙的东西还是温习一下:一个有符号数字,最高位为符号位,0为正,1为负。正数的反码补码都等于原码,负数的反码=原码除符号位的每一位取反,负数的补码=反码+1,举个例子:

1 = [00000001]原=[00000001]反=[00000001]补
-1 =[10000001]原=[11111110]原=[11111111]补

正是得益于补码运算,才有了上面的代码,我们看1和-1会发现,-1的补码高位全部都是1,我们都知道:和1做&运算,等于本身,我们再举个例子:

[2]=[00000010]原=[00000010]反=[00000010]补
[-2]=[10000010]原=[11111101]反=[11111110]补
[4]=[00000100]原=[00000100]反=[00000100]补
[-4]=[10000100]原=[11111011]反=[11111100]补

故而有了代码(val & -val)==val为2的次方。 后来看了,网上还盛传另一种基于位运算高效判断2的次方的方法:

private static boolean isPowerOfTwo2(int val) {
        return (val & (val-1))==0;
}

通过和自身-1的数求与判断是否为2的次方,他的原理是,2的次方形如2,4,8这样的数,都是(000……00100……00)这样的,只有一个1,然后减一之后就变成了(0……0111……1)这样的了,然后一求与,所有位都是0,这一特性来判断是否为2的次方。对于这一特性的运用,在Netty源码中还看到在求余数中被使用,我们正常求余数都是通过%来求余数,但是如果是2的次方,求余数则可以利用减一之后,全是1的特性来进行求与:

//length为2的次方时,可以这样求余数
public EventExecutor next() {
    return children[childIndex.getAndIncrement() & children.length - 1];
}
//正常情况下求余数
public EventExecutor next() {
    return children[Math.abs(childIndex.getAndIncrement() % children.length)];
}

在Netty中还看到这样一段源码:

if ((runTasks & 0x3F) == 0) {
	  lastExecutionTime = ScheduledFutureTask.nanoTime();
	  if (lastExecutionTime >= deadline) {
	      break;
	  }
}

每64个任务数判断一次是否超时,(runTasks & 0x3F) == 0用来判断是否是第64个任务数,0x3F其实就是16进制的63,其实和上面求余数一个当立,runTask & (length-1),length=64,当64时,求余数为0,从而来判断是否为64个任务数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值