java中Integer.bitCount()方法的实现(个人理解)

Integer.bitCount()方法用于统计二进制中1的个数。
方法体如下:
public static int bitCount(int i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
其中:0x55555555转换成二进制:0101 0101 0101 0101 0101 0101 0101 0101
0x33333333转换成2进制是:0011 0011 0011 0011 0011 0011 0011 0011
0x0f0f0f0f转换成2进制是:0000 1111 0000 1111 0000 1111 0000 1111
第一步: i = i - ((i >>> 1) & 0x55555555);
其中:
i >>>1就是i右移1位, i可以表示为b0*2 ^0+b1*2^1+...+b31*2^31,那右移一位之后就是:
b1*2 ^0+b2*2^1+...+b31*2^30
(i >>> 1) & 0x55555555:就是b1*2 ^0+b2*2^1+...+b31*2^30-(b2*2^1+b4*2^3+...+b30*2^29)
i - ((i >>> 1) & 0x55555555):即 b0*2 ^0+b1*2^1+...+b31*2^31-(b1*2 ^0+b2*2^1+...+b31*2^30-(b2*2^1+b4*2^3+...+b31*2^29))
=b0*2 ^0+b1*2^1+...+b31*2^31-(b1*2^0+b3*2^2+...+b31*2^30)
= b0*2^0+b1*(2^1-2^0)+b2*2^2+b3*(2^3-2^2)+...+b30*2^30+b31*(2^31-2^30)
=(b0+b1)*2^0+(b2+b3)*2^2+...+(b30+b31)*2^30
这样就把原本的i按两个一组拆分成多个组,然后把每组的1的个数加起来,然后每组之间的差距是2^2倍。

 

 

第二步:i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
此时i已经是(b0+b1)*2^0+(b2+b3)*2^2+...+(b30+b31)*2^30;
其中:
i & 0x33333333:其中0x33333333是00110011001100110011001100110011
这一步就是 (b0+b1)*2^0+(b2+b3)*2^2+...+(b30+b31)*2^30-((b2+b3)*2^2+(b6+b7)*2^6+...+(b30+b31)2^30)
=(b0+b1)*2^0+(b4+b5)*2^4+...+(b28+b29)*2^28
(i >>> 2):是 (b2+b3)*2^0+(b4+b5)*2^2+...+(b30+b31)*2^28
(i >>> 2) & 0x33333333:就是 (b2+b3)*2^0+(b4+b5)*2^2+...+(b30+b31)*2^28-((b4+b5)*2^2+(b8+b9)*2^6+...+(b28+b29)*2^26)
=(b2+b3)*2^0+(b6+b7)*2^4+(b10+b11)*2^8+(b14+b15)*2^12+(b18+b19)*2^16+(b22+b23)*2^20+(b26+b27)*2^24+(b30+b31)*2^28
(i & 0x33333333) + ((i >>> 2) & 0x33333333):
就是 (b0+b1)*2^0+(b4+b5)*2^4+...+(b28+b29)*2^28+(b2+b3)*2^0+(b6+b7)*2^4+(b10+b11)*2^8+(b14+b15)*2^12+(b18+b19)*2^16+(b22+b23)*2^20+(b26+b27)*2^24+(b30+b31)*2^28
=(b0+b1+b2+b3)*2^0+(b4+b5+b6+b7)*2^4+...+(b28+b29+b30+b31)*2^28
这一步把i进一步合并,把之前的相邻两组合并成一组,按照4位一组去计算每组中1的个数,两组中靠后的那组除4,然后再新组中算每组的1的个数,其实就是每组的数都加起来,因为数只有1和0,所以计算的就是每组中1的个数,相邻两组的差距是2^4倍。
 
第三步: i = (i + (i >>> 4)) & 0x0f0f0f0f;
此时i已经是(b0+b1+b2+b3)*2^0+(b4+b5+b6+b7)*2^4+...+(b28+b29+b30+b31)*2^28
0x0f0f0f0f:2进制是00001111000011110000111100001111
继续合并,按8位一组进行合并;
其中:
i >>> 4: (b4+b5+b6+b7)*2^0+(b8+b9+b10+b11)*2^4+...+(b28+b29+b30+b31)*2^24;
i + (i >>> 4):(b0+b1+b2+b3)*2^0+(b4+b5+b6+b7)*2^4+...+(b28+b29+b30+b31)*2^28 + (b4+b5+b6+b7)*2^0+(b8+b9+b10+b11)*2^4+...+(b28+b29+b30+b31)*2^24
=(b0+b1+b2+b3+b4+b5+b6+b7)*2^0+(b4+b5+b6+b7+b8+b9+b10+b11)*2^4+...+(b24+b25+b26+b27+b28+b29+b30+b31)*2^24+(b28+b29+b30+b31)*2^28
(i + (i >>> 4)) & 0x0f0f0f0f:
( b0+b1+b2+b3+b4+b5+b6+b7) *2^0+(b4+b5+b6+b7+b8+b9+b10+b11)*2^4+...+(b24+b25+b26+b27+b28+b29+b30+b31)*2^24+(b28+b29+b30+b31)*2^28
-((b4+b5+b6+b7+b8+b9+b10+b11)*2^4+(b12+b13+b14+b15+b16+b17+b18+b19)*2^12+(b20+b21+b22+b23+b24+b25+b26+b27)*2^20+(b28+b29+b30+b31)*2^28)
=(b0+b1+b2+b3+b4+b5+b6+b7)*2^0+(b8+b9+b10+b11+b12+b13+b14+b15)*2^8+(b16+b17+b18+b19+b20+b21+b22+b23)*2^16+(b24+b25+b26+b27+b28+b29+b30+b31)*2^24
这一步执行以后,i现在是按照8位一组合并计算每组1的数量了,i也变成(b0+b1+b2+b3+b4+b5+b6+b7)*2^0+(b8+b9+b10+b11+b12+b13+b14+b15)*2^8+(b16+b17+b18+b19+b20+b21+b22+b23)*2^16+(b24+b25+b26+b27+b28+b29+b30+b31)*2^24
 
第四步: i = i + (i >>> 8);
i>>>8:(b8+b9+b10+b11+b12+b13+b14+b15)*2^0+(b16+b17+b18+b19+b20+b21+b22+b23)*2^8+(b24+b25+b26+b27+b28+b29+b30+b31)*2^16
i + (i >>> 8):(b0+b1+b2+b3+b4+b5+b6+b7)*2^0+(b8+b9+b10+b11+b12+b13+b14+b15)*2^8+(b16+b17+b18+b19+b20+b21+b22+b23)*2^16+(b24+b25+b26+b27+b28+b29+b30+b31)*2^24+(b8+b9+b10+b11+b12+b13+b14+b15)*2^0+(b16+b17+b18+b19+b20+b21+b22+b23)*2^8+(b24+b25+b26+b27+b28+b29+b30+b31)*2^16
=(b0+b1+b2+b3+b4+b5+b6+b7+b8+b9+b10+b11+b12+b13+b14+b15)*2^0+(b8+b9+b10+b11+b12+b13+b14+b15+b16+b17+b18+b19+b20+b21+b22+b23)*2^8+(b16+b17+b18+b19+b20+b21+b22+b23+b24+b25+b26+b27+b28+b29+b30+b31)*2^16+
(b24+b25+b26+b27+b28+b29+b30+b31)*2^24
 

 

第五步: i = i + (i >>> 16);
i >>> 16:
(b16+b17+b18+b19+b20+b21+b22+b23+b24+b25+b26+b27+b28+b29+b30+b31)*2^0+
(b24+b25+b26+b27+b28+b29+b30+b31)*2^8
i + (i >>> 16):
(b0+b1+b2+b3+b4+b5+b6+b7+b8+b9+b10+b11+b12+b13+b14+b15)*2^0+(b8+b9+b10+b11+b12+b13+b14+b15+b16+b17+b18+b19+b20+b21+b22+b23)*2^8+(b16+b17+b18+b19+b20+b21+b22+b23+b24+b25+b26+b27+b28+b29+b30+b31)*2^16+
(b24+b25+b26+b27+b28+b29+b30+b31)*2^24+
(b16+b17+b18+b19+b20+b21+b22+b23+b24+b25+b26+b27+b28+b29+b30+b31)*2^0+
(b24+b25+b26+b27+b28+b29+b30+b31)*2^8
=(b0+b1+...+b31) *2^0+(b8+b9+...+b24+b25+b26+b27+b28+b29+b30+b31)*2^8+
(b16+b17+b18+b19+b20+b21+b22+b23+b24+b25+b26+b27+b28+b29+b30+b31)*2^16+
(b24+b25+b26+b27+b28+b29+b30+b31)*2^24
第六步:i & 0x3f;
0x3f:二进制是0011 1111,用i & 0x3f可以把i中后面几项全部抹掉,因为后面几项都是乘2^8、2^16、2^24,而0x3f大于2^5的都是0。

i & 0x3f:结果是(b0+b1+...+b31)*2^0,就是b0+b1+...+b31,就是要处理的这个数二进制所有位数之和,因为二进制每一位只能是0或者1,因此就是1的数量。

 

 

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值