本文已参与「新人创作礼」活动, 一起开启掘金创作之路。 用于统计一个位数组中非0二进制位的数量。
static int swar(int i) {
// 每两个一组,每一组的数字表示这一组中有几个1
i = (i&0x55555555) + ((i>>>1)&0x55555555);
// 每4个一组,这个数据是根据上一个数据计算出来的
i = (i&0x33333333) + ((i>>>2)&0x33333333);
// 同理,每8个一组记录1的个数
i = (i&0x0f0f0f0f) + ((i>>>4)&0x0f0f0f0f);
i = (i*(0x01010101)) >>> 24;
return i;
}
举例:
每两个一组 0x55(16进制) => 0x0101,0101(2进制) i取值0x1101,1010
(i&0x55) + ((i>>>1)&0x55);
i&0x55
0x1101,1010
&0x0101,0101
0x0101,0000
(i>>>1)&0x55
0x0110,1101
&0x0101,0101
0x0100,0101
最终结果:
原值:0x11 01 10 10
新值:0x10 01 01 01 注意对应的是每组1的个数
每4个一组、每8个一组同理
比较难理解的点
i = (i*(0x01010101)) >>> 24;
拆分来看
(i*(0x01010101))
满足乘法分配律
(i*(0x01000000)) + (i*(0x00010000)) + (i*(0x00000100)) + (i*(0x00000001))
A, B, C, D 每一个字母代表 8 位数, 那么 32 为数可以被 (A, B, C, D) 表示
0x01010101 * (A, B, C, D ) = (A+B+C+D, B+C+D, C+D, D)
根据乘法分配律
i*0x0100 0000 + i*0x0001 0000 + i*0x0000 0100 + i*0x0000 0001
i*0x0100 0000 实际上等于左移24位
D, _, _, _ i*0x0100 0000
+C, D, _, _ i*0x0001 0000
+B, C, D, _ i*0x0000 0100
+A, B, C, D i*0x0000 0001
A+B+C+D, B+C+D, C+D, D