zoukankan      html  css  js  c++  java
  • JDK源码 Integer.bitCount(i)

    1.问题:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

    2.解决方法很多,JDK提供了一种,如下图

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

    3.算法分析:(借鉴于 https://blog.csdn.net/cor_twi/article/details/53720640)

    原理: 两个两个一组,求二进制1的个数,并且用两位二进制存储在原处,然后四个四个一组,求二进制位1的个数,再把它存储以4位二进制到原处。以此类推直到计算完成。

    前提:对于两位的二进制而言,总共有 4 种情况

    二进制值(x) 1的个数(使用二进制表示)(y) 解释
    00 00 两位都没有1
    01 01 低位为1
    10 01 高位为1
    11 10 高低位都为1

      

     

    从这里我们可以得出以下式子(等式左边为1的个数,被减数是二进制值):

     00 = 00 - 00;

       01 = 01 - 00;

       01 = 10 - 01;

       10 = 11 - 01;

    由此可得 y = x - i ;

    i 如果用 x 来表示如何表示,观察你可以发现 i = x >>> 1;(00 无符号右移一位是 00 ,01 无符号右移一位是 00 ,10 无符号右移是一位 01,11 无符号右移一位是 01);

    所以 y = x - (x>>>1);

    注意上述式子前提条件时 x 是两位二进制数;如果 x 是四位二进制数呢,比如 0110 :

    按照上面的思路,我们是希望得到 01 无符号右移三位 00,10 无符号右移一位是 01 我们期望是得到 0001,

    但是 0110 无符号右移一位,结果则是0011,出现这种情况的原因很容易分析出来,前两位二进制移动影响了后两位二进制中的高位。

    如何解决上面的问题?我们仔细观察那4个式子,会发现所有的两位二进制数无符号右移一位之后高位一定是0

    理解完上面之后,我们就可以把高位都给消为0,可得出:

    y = x - ((x>>>1) & 0101 0101 0101 0101 0101 0101 0101 0101) = x - ((x>>>1) & 0x55555555);

     注意:这时候这个 int 型的数对应的二进制中含有1的个数 就转变为了 16组两位二进制数的相加,通俗一点 

    0010(ab) 0011(cd) 1011(ef) 1011(gh) 0010(ij) 0011(km) 1011(op) 1011(qr) (总共1的个数为 a+b+c+d+e+f+g+h+i+j+k+m+o+p+q+r)

    分成每四位一组

    每组中高二位1的总个数为 : (y>>>2)& 0x33333333 右移两位则将原来是高二位的变成了低二位,移动之后的所有高二位无用,直接通过和 0011 0011 0011 0011 0011 0011 0011 0011 相与消除所有高二位

    每组中低二位1的总个数为 : y & 0x33333333 (同上面一样,高二位无用,消除)

    此时:y = ((y >>>2) & 0x33333333) + (y & 0x33333333);//运算每4位有几个1

    同理:分成每八位一组,16位一组,32位一组:

    y = ((y >>>4) & 0x0f0f0f0f) + y & 0x0f0f0f0f; //运算每8位有几个1 先算前四位1的个数,再计算后四位1的个数
    y = (y >>>8) + y; //运算每16位有几个1 //这里不用 & 的运算的原因是因为,高8位已经没有用了,因为最大值为2^5 ,再做个 & 运算没必要了
    y = (y >>>16) + y;//运算每32位有几个1

    最后:
    0000 0000 0000 0000 0000 0000 0011 1111 = 0x3F 
    y = y & 0x3F,就是把前面的无效的高位直接给消除,最多保留6位二进制。

    最后汇总可得:
    public static int bitCount(int i) {
        i = i - ((i >>> 1) & 0x55555555);//每两位代表着1的个数
        i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);//每四位代表1的个数
        i = (i + (i >>> 4)) & 0x0f0f0f0f;//每八位代表1的个数
        i = i + (i >>> 8);//每16位代表1的个数
        i = i + (i >>> 16);//每32位代表1的个数
        return i & 0x3f;
    }
    

      



    -- 整理于网络,加上自己的理解,大家一起学习,进步就好
  • 相关阅读:
    java读取ldif文件并创建新的节点
    AngularJS的基本概念和用法
    前端开发环境需要的工具
    解决:使用ajax验证登录信息返回前端页面时,当前整个页面刷新。
    js中switch语句不执行
    使用html5中required属性
    H-ui.admin v3.1学习之路(一):导航栏信息无法在内容区显示
    解决:@Auarowired为null
    scrapy框架整理
    django项目的部署
  • 原文地址:https://www.cnblogs.com/shulipeng/p/8954226.html
Copyright © 2011-2022 走看看