Integer.bitCount(int i)的理解

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;
    }

其中:

  1. 0x55555555转换成二进制:0101 0101 0101 0101 0101 0101 0101 0101
  2. 0x33333333转换成2进制是:0011 0011 0011 0011 0011 0011 0011 0011
  3. 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+...+b30*2^31

(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的数量。

原文:https://blog.csdn.net/qq_33977728/article/details/80252241 

猜你喜欢

转载自blog.csdn.net/zuoyouzouzou/article/details/88739118