计算一个整型数字中有多少个bit被置1,一般会想到按位循环遍历的方法。
这里有一个并行计算的方法如下:
先上代码
v = v - ((v >> 1) & 0x55555555); // reuse input as temporary
v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp
c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
就这3步,只有12个operation,
它采用了分治法思想并行计算,
第一行计算了相邻2位的bit和,相邻2位的意思是32bit的数中把bit两两分组,计算每组的bit和,
可以看到0x555是一个magic number,
0x55555555 = 01010101 01010101 01010101 01010101
第一行代码的效果:
首先右移一位,把高位的数给了低位,然后0x55555555是掩码,把高位置0,得到了新的2位数,再用原来的数减去刚刚得到新的两位数,得到想要的结果:
00b >> shifted: ?0b >> masked: 00b >> subtraction: 00b - 00b >> 00b
01b >> shifted: ?0b >> masked: 00b >> subtraction: 01b - 00b >> 01b
10b >> shifted: ?1b >> masked: 01b >> subtraction: 10b - 01b >> 01b
11b >> shifted: ?1b >> masked: 01b >> subtraction: 11b - 01b >> 10b
可以看到得到了相邻2位的bit数。
相邻2位的算出来以后,再进入更大的组,相邻4位,就是4个一组,计算每组的bit数,
而我们看到,4个一组中的2小组都是刚才已经计算好了的。
所以这4个一组中要计算的是里面两个小组的和(刚才相邻两位计算出来的是每两位的bit数,它们相加就是相邻4位的bit数)。
既然是相邻4位,换一个magic number
0x33333333 = 00110011 00110011 00110011 00110011
第2行代码计算的是相邻4位的bit数,效果如下:
要计算的是1010b中相邻的两小组10b和10b的和,应该是10b + 10b = 100b
(注意10b是上一行代码算的相邻2位的bit和)
1010b ---->>----- 0010b
0011b 0011b
----&---- ----&----
0010b 0010b
-------------+---------------
0100b
第3行代码就是进入更大的组,相邻8位的和,思路和上面一样,这回的magic number是
0x0000FFFF = 00000000 00000000 11111111 11111111
第3行(v + (v >> 4) & 0xF0F0F0F)的效果就是计算出相邻8位(8位一组)的bit数
然后32bit的数字可以分为4个8位(A B C D)
最后要求A,B,C,D这4个组的bit数之和,
最后用了bit乘法,* 0x1010101
bit乘法的计算法则如下,和十进制数乘法一样的
所以最后(A B C D) * 0x1010101的结果是(A+B+C+D, B+C+D, C+D, D),
右移24位就是我们要的A+B+C+D.