我在这里提到了这个算法:How does this algorithm to count the number of set bits in a 32-bit integer work?
我在上面的链接中运行了“yeer”提交的算法,因为这些算法或多或少看起来都一样。
我编写了传统的(较慢的方法,假设)代码来检查性能有多大提升。
Yeer Code:
unsigned int number=0xFFFFFFFF;
number= (number & 0x55555555) + ((number>>1) & 0x55555555);
number= (number & 0x33333333) + ((number>>2) & 0x33333333);
number= (number & 0x0F0F0F0F) + ((number>>4) & 0x0F0F0F0F);
number= (number & 0x00FF00FF) + ((number>>8) & 0x00FF00FF);
number= (number & 0x0000FFFF) + ((number>>16) & 0x0000FFFF);
printf("%d",number);
传统方式:
unsigned int number=0xFFFFFFFF;
unsigned char i=0;
unsigned char count=0;
for(i=0;i<32;i++)
{
if((number>>i) & 1)
count++;
}
printf("%d",count);
第二个代码超越了“yeers”方法。
对于输入值0xFF(使用变量作为unsigned char),Traditional = 0.047s,Other = 0.063s 对于输入值0xFFFFFFFF(使用变量作为unsigned int),Traditional = 0.141s,Other = 0.141s
其他算法有什么特别之处?
我使用Codeblocks IDE来运行这两个代码。
答案 0 :(得分:2)
我为不同的代码运行了一个简单的基准测试。每个片段都执行了1亿次。代码编译为gcc
,没有optmization标志。每个案例都进行了几次,以确保结果不会被其他系统活动过度扭曲。重新运行时执行时间变化不到10%。
如您所见,yeer提交的算法比其他算法快得多。
测试驱动程序:
int main(int argc, char *argv[]) {
int i, result;
for (i= 0; i < 100000000; i++) {
result = SWAR(i);
}
return 0;
}
代码1,优化的yeer代码:
int SWAR(unsigned int i) {
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
时间:0.772s
代码2,未优化的版本:
int SWAR(unsigned int number) {
number= (number & 0x55555555) + ((number>>1) & 0x55555555);
number= (number & 0x33333333) + ((number>>2) & 0x33333333);
number= (number & 0x0F0F0F0F) + ((number>>4) & 0x0F0F0F0F);
number= (number & 0x00FF00FF) + ((number>>8) & 0x00FF00FF);
number= (number & 0x0000FFFF) + ((number>>16) & 0x0000FFFF);
return number;
}
时间:1.241s
代码3,没有if
的位计数器:
int SWAR(unsigned int number) {
int i, count = 0;
for(i=0;i<32;i++) {
count += (number>>i) & 1;
}
return count;
}
时间:8.921s
代码4,位计数器if
:
int SWAR(unsigned int number) {
int i, count = 0;
for(i=0;i<32;i++) {
if ((number>>i) & 1) {
count++;
}
}
return count;
}
时间:21.058s
答案 1 :(得分:1)
第一种方法没有分支,在大多数系统上将产生大约15个机器代码cpu指令(5个adda,5个shift和5个和')。
您的方法通常有128条指令(32条4条指令),即使使用预测分支,大多数cpus在错误估计循环条件时也必须至少转储一次管道,导致运行+130个cpu周期结果
我建议你尝试在随机数据上运行数百万次,你会看到差异。
尝试使用来自rand()
的数据设置的数组的1到100万的for循环您的时间可能是其他事情,与您的代码无关,将以微秒执行