一、 前导零统计函数__builtin_clz()
1.用处:
此函数可以用来优化整数位运算或者在需要统计前导零的情况下使用
2.函数的三个模版:
(1)__builtin_clz(unsigned int x) 用于无符号整数
(2)int__builtin_clzl(unsigned long x) 用于无符号长整数
(2)int__builtin_clzll(unsigned long long x) 用于无符号长长整数
###这些函数均返回给定整数最高位前面的0的个数(如输入为0,则结果是未定的)
3.代码:
//c/c++ 使用二分来实现这一功能
int __Builtin_clz(uint num){
uint clz = 0;
if ((num >> 16) == 0) {
clz += 16;
num <<= 16;
}
if ((num >> 24) == 0) {
clz += 8;
num <<= 8;
}
if ((num >> 28) == 0) {
clz += 4;
num <<= 4;
}
if ((num >> 30) == 0) {
clz += 2;
num <<= 2;
}
if ((num >> 31) == 0) {
clz += 1;
}
return clz;
}
###原理也很好理解:就是不断地通过位运算置0来检查并将找到的为0的位数加到开辟的变量clz中
二、统计二进制中为1的位数的函数__builtin_popcount()
1.用处:
统计为1的位数
2.函数模版
__builtin_popcount (unsigned int) 用于无符号整数
3.代码:
(1)###通过清除 u 最低的 bit 1 ,直至 u 为 0 ,每次都为计数器加 1 。
时间复杂度为 O (m) , m 为 bit 1 的个数
//c/c++
unsigned popcnt (uint num)
{
uint ret = 0;
while (num)
{
num = (num & (num - 1)); // 将 u 最右边的 1 清除
ret ++;
}
return ret;
}
(2)###使用二分法,比较巧妙,跟踪调试一下就知道原理了。
运用了分治的思想,时间复杂度为 O (lg N) , N 为位数
//c/c++ 分治思想
int popcount(uint num) {
num = (num & 0x55555555) + ((num >> 1) & 0x55555555);
num = (num & 0x33333333) + ((num >> 2) & 0x33333333);
num = (num & 0x0F0F0F0F) + ((num >> 4) & 0x0F0F0F0F);
num = (num & 0x00FF00FF) + ((num >> 8) & 0x00FF00FF);
num = (num & 0x0000FFFF) + ((num >> 16) & 0x0000FFFF);
return num;
}
解释:
共计16位:
如下:(分治思想)
第一次:(x+x)+(x+x)+(x+x)+(x+x)+(x+x)+(x+x)+(x+x)+(x+x)+
(x+x)+(x+x)+(x+x)+(x+x)+(x+x)+(x+x)+(x+x)+(x+x)
第二次:(x+x+x+x)+(x+x+x+x)+(x+x+x+x)+(x+x+x+x)+
(x+x+x+x)+(x+x+x+x)+(x+x+x+x)+(x+x+x+x)
第三次:(x+x+x+x+x+x+x+x)+(x+x+x+x+x+x+x+x)+
(x+x+x+x+x+x+x+x)+(x+x+x+x+x+x+x+x)
第四次:(x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x)+
(x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x)
第五次:(x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x+x)
0x55555555 --> 0101 0101 0101 0101 0101 0101 0101 0101
0x33333333 --> 0011 0011 0011 0011 0011 0011 0011 0011
0x0F0F0F0F --> 0000 1111 0000 1111 0000 1111 0000 1111
0x00FF00FF --> 0000 0000 1111 1111 0000 0000 1111 1111
0x0000FFFF --> 0000 0000 0000 0000 1111 1111 1111 1111