程序设计中经常遇到用一个数的每个bit表示一个状态,有时需要计算被置为1的bit数目。
方法1. 最直接的方法就是一位一位的判断
U8 nonZeroBitNum(U32 x) {
U8 num = 0;
for(U8 i = 0; i++; i<32)
num += (x>>i) & 1; // 右移,与,加 运算,需要三个CPU指令周期
return num;
}
这种方法逻辑简单,但是每个32位数都需要循环32次得出结果
方法2. 利用 (2^N - 1) & 2^N = 0的原理对方法1进行优化
一个无符号数32位数可以表示为,bit31*2^31 + bit30*2^30 + .... + bit1*2^1 + bit0*2^0
U8 nonZeroBitNum(U32 x) {
U8 num = 0;
while(x){
x &= x-1; // 减,与 运算,需要2个CPU指令周期
num++; // ++运算,1个CPU指令周期
}
return num;
}
可以看出方法2循环内的运算复杂度与方法1是相同的,考虑到不是所有数据的所有bit都是1,假设所有数据平均有16 bit会被置为1,那么这种方法只需要循环16次既可以算出结果,比方法1节省了1半的时间。如果大部分数据只有少数bit被置为1,那么效率的提升就更明显了。
虽然只是个小技巧,但是觉得还是挺有意思的。如果谁有更好的方法,也可以分享一下。