bitCount源码解析

前言

bitCount 源码采用自底向上的分治思想,通过找到数字规律,来完成分治。

一、源码解析

1、源码

/**
     * Returns the number of one-bits in the two's complement binary
     * representation of the specified {@code int} value.  This function is
     * sometimes referred to as the <i>population count</i>.
     *
     * @param i the value whose bits are to be counted
     * @return the number of one-bits in the two's complement binary
     *     representation of the specified {@code int} value.
     * @since 1.5
     */
    @HotSpotIntrinsicCandidate
    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;
    }

2、核心所在

1)每两位统计1的个数、每四位统计1的个数、每八位统计1的个数…
2)将统计好的1放在每几位的低位上。
关键问题:
1- 两两分组得到1的个数?
通过将 i 拆解成多项式,然后对其做一定操作,得到每两位相加放在低位上。

- i >>> 1 后,
    i = b1*2^0 + b2*2^1 + ... + b31*2^30
        
- (i >>> 1) & 0x55555555 后,
	i = b1*2^0 + b2*2^1 + ... + b31*2^30
        - (b2*2^1 + b4*2^3 + ... + b30*2^29)
        
- i - ((i >>> 1) & 0x55555555) 后,
	i = b0*2^0 + b1*2^1 + ... + b31*2^31
        - (b1*2^0 + b2*2^1 + ... + b31*2^30
        - b2*2^1 + b4*2^3 + ... + b30*2^29)
      = b0*2^0 + b1*2^1 + ... + b31*2^31
        - (b1*2^0 + b3*2^2 + ... + b29*2^28 + b31*2^30)
      = b0*2^0 + b1*(2^1-2^0) + ... + b31*(2^31-2^30)
      = (b0+b1)*2^0 + (b2+b3)*2^2 + ... + (b30+b31)*2^30

2- 四四分组得到1的个数

- 运算前, 原始的i已被两两位一组的分为16组, 每组表示这两位中二进制1的个数
	i = (b0+b1)*2^0 + (b2+b3)*2^2 + ... + (b30+b31)*2^30
- 运算后, 原始的i被四四位一组的分为8组,每组表示这四位中二进制1的个数
	i = (b0+b1+b2+b3)*2^0 + (b4+b5+b6+b7)*2^4 + ... +(b28+b29+b30+b31)*2^28

3- 八八分组

- 运算后, i继续被八八位一组的分成4组, 每组表示这八位中二进制1的个数, 并且这八位中的前四位为0,, 因为4位二进制足够表示出每组中最大的数字8
	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

4- 十六十六分组

- 运算后, i继续被分成4组, 但只有第一组和第三组是有效数据(每组表示这十六位中二进制1的个数), 其他组为垃圾数据
	i = (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

5- 三十二位

- 运算后, i继续被分成4组, 但只有第一组是有效数据(表示这32位中二进制1的个数), 其他组为垃圾数据
	i = (b0+b1+...+b31)*2^0
        + (b8+b9+...+b30+b31)*2^8
        + (b16+b17+...+b30+b31)*2^16
        + (b24+b25+b26+b27+b28+b29+b30+b31)*2^24

6- 得到结果

- 运算后, 将上一步中第一组的有效数据提取了出来, 因为与上0x3f时大于2^5的数据都被置0, 而6位二进制足够表示32位int中的最大bitCount, 即32
	i = (b0+b1+...+b31)*2^0 & 0x00111111
      = (b0+b1+...+b31)*2^0
      = b0+b1+...+b31

参考文献

[1] JDK 11
[2] bitCount 源码解析

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值