`
BrokenDreams
  • 浏览: 256196 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
68ec41aa-0ce6-3f83-961b-5aa541d59e48
Java并发包源码解析
浏览量:101240
社区版块
存档分类
最新评论

计算一个int型数值中bit-1的个数

 
阅读更多
        之前面试遇到过这样的问题:写一个方法,统计出一个int型数值中比特值为1的比特个数,后来群里也讨论过,在这里总结一下。
        直观的看一下这个问题的解法。
        假设一个int型数值为80。
        首先,将这个数值转化成二进制形式。
80 = 00000000 00000000 00000000 01010000

        然后数一数为1的bit有几个,很明显是2个,那么结果就是2。

        但是写程序要怎么做呢?
        首先看一个小技巧,x & (x-1)会把x中最右边为1的bit变成0,利用这个小技巧我们可以写出下面的程序:
public static int bitCount(int n){
		int count = 0;
		while(n != 0){
			n = n & (n-1);
			count++;
		}
		return count;
	}

        这个过程相当于从右往左数1的个数,假设n为-1,就得数32次,相当于一个线性时间的操作,有没有更好的呢?

        在Hackers Delight里面介绍了很好的技巧。
        这种技巧是一种分治的思想,假设我们要求32位数值的bit-1个数,我们只要计算出前16位和后16位的bit-1个数,然后把他们加起来就行了,那么对于16位的bit-1个数的求法,我们采取同样的方式...直到我们计算2位bit-1个数的时候,我们只要把两个1位bit的值加起来就好了,这相当于是子问题的基本情况,递归的出口。
        下面的图展示了这个过程:

注:图片来之Hackers Delight。

        按照这个思路,我们便可以写出如下代码:
public static int bitCount1(int n){
		n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);
		n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
		n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);
		n = (n & 0x00ff00ff) + ((n >>> 8) & 0x00ff00ff);
		n = (n & 0x0000ffff) + ((n >>> 16) & 0x0000ffff);
		return n;
	}

        相对于上面线性时间的求法来说,这个"分治"的求法只用了log(32)=5步便完成了运算,非常巧妙。

        但是。这个还能优化,首先想一下结果最大也就是32了,所以可以减少一些"与"操作,在最后让n和0x0000003f相与就行了。从上图可以看出,当我们在进行8位到16位步骤的时候,8位的高4位对于我们来说已经没用了,所以从这里开始,我们可以不管高位,减少"与"操作,这样能减少一些指令。
        代码如下:
public static int bitCount1(int n){
		n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);
		n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
		n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);
		n = n + (n >>> 8);
		n = n + (n >>> 16);
		return n & 0x0000003f;
	}

        其实n可以看成是(n & 0x55555555)加上(((n >>> 1) & 0x55555555) << 1),也就是
n = (n & 0x55555555) + (((n >>> 1) & 0x55555555) * 2)
(n & 0x55555555) = n - (((n >>> 1) & 0x55555555) * 2)

        将这个代入上面的程序,就得到如下代码:
public static int bitCount2(int n){
		n = n - ((n >>> 1) & 0x55555555);
		n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
		n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);
		n = n + (n >>> 8);
		n = n + (n >>> 16);
		return n & 0x0000003f;
	}

        这样一来,代码的第一行又减少了一个指令。
        OK!
    
        这段代码也被Java采用作为Integer类中bitCount方法的实现。
  • 大小: 44.5 KB
分享到:
评论

相关推荐

    用循环求 任意一个int类型的数字里面含有多少个 1.

    在计算机科学与编程领域中,经常需要对二进制数据进行操作,比如统计一个整数(int类型)中的二进制位中1的个数。这种需求在算法设计、密码学、硬件设计等领域中十分常见。下面我们将详细介绍如何使用Java语言实现这...

    计算机组成原理实验运动码表-计算机组成原理.pdf

    这种形式的数的范围为-2^(n-1) ~ +2^(n-1)-1。 13. 高级语言编程中定义的short / int / long型数据是怎么表示的?:这些类型的数据都是用补码表示的整数,bit数不同,能够表示的数的范围也不同。

    树状数组的简单介绍.pdf

    3. **Lowbit函数**:是树状数组中一个重要的操作,用来返回参数转为二进制后,最后一个1的位置所代表的数值。例如,`Lowbit(34)`的返回值是2;而`Lowbit(12)`返回4;`Lowbit(8)`返回8。 #### 四、基本操作 - **...

    NOIP2018提高组C试题.pdf

    - **题目**: 为了统计一个非负整数的二进制形式中 1 的个数,代码如下: ```c int CountBit(int x) { int ret = 0; while (x) { ret++; ________; } return ret; } ``` 则空格内要填入的语句是( )。 ...

    2021-2022计算机二级等级考试试题及答案No.13003.docx

    例如,要在名为 `students` 的表中添加一个名为 `age` 的新字段,可以使用以下命令:`ALTER TABLE students ADD age INT;`。 ### 23. 计算机资料检索的应用领域 使用计算机进行资料检索是一种数据处理活动,它涉及...

    2021-2022计算机二级等级考试试题及答案No.1005.docx

    一个Byte由8个bit组成,是大多数现代计算机系统中最小的可寻址单位。 - **重要性**:理解这些基本概念对于掌握计算机硬件和数据处理的基础至关重要。 #### 题目4:随机数生成 - **知识点**:如何在编程中生成指定...

    51寄存器详解

    程序状态寄存器(PSW)是8051微控制器中一个重要的寄存器,用于保存算术运算后的状态信息。它是一个8位的寄存器,其中每一位都有特定的功能。 - **Cy(Carry Flag)**: 高位进位标志位。当执行加法或减法运算时,...

    《单片机(C51)技术》复习题

    定义一个位变量 key1: bit key1;。 19. 指针:指针是 C 语言中一个重要的概念,指针型变量以 * 标记。 20. 按键消抖:按键消抖一般有两种方法:硬件消抖和软件消抖,软件消抖中,当单片机检测到有键按下时,可以...

    树状数组超详解外加大量题解

    对于一个整数x,其低位二进制位`Lowbit(x)`定义为x二进制表示中最右侧的1所代表的值。例如,对于数字6(二进制110),其`Lowbit(6)`为2(二进制10)。 #### 三、树状数组的关键函数 树状数组中有三个关键函数:`Lowbit...

    各种排序 冒泡 快速 堆 希尔 基数等九种

    // 将(1——i-1)重新调整为一个大堆 } } void Merge( RedType S[], RedType T[], int i,int m,int n) { // 将有序的S前一部分和后一部分归并为有序的T int j,k; for (j=m+1,k=i;i; ++k)// 将S中记录由小到大...

    Java 自学宝典 第二章 数据类型

    `Integer.bitCount(int i)` 方法用于计算 `int` 类型变量的二进制表示中1的个数。 ```java int num = 10; // 二进制形式为 1010 System.out.println(Integer.bitCount(num)); // 输出 2 ``` ##### 2.6.4 Highest ...

    MYSQL安装包官方试用版

    这说明MySQL簇中的表中的VARCHAR列的行为如同类型CHAR(不同的是每个记录仍然有一个额外字节空间)。例如,在Cluster表中,声明为VARCHAR(100)的列中的每个记录存储时将占用101个字节,无论实际存储的记录中的字符串的...

    2017年第二十三届NOIP(C语言)普及组初赛试题及详细答案

    - **解析:** 最坏情况下,每次比较只能确定一个元素的位置,因此需要进行n+n-1=2n-1次比较来确定所有元素的位置。 - **答案:** D. 2n-1 **18. 从()年开始,NOIP竞赛将不再支持Pascal语言** - **解析:** 本题未...

    mysql常用函数

    - 例如:`SIGN(-10)` 返回 `-1`。 15. **SQRT(x)**: 返回`x`的平方根。 - 例如:`SQRT(16)` 返回 `4`。 16. **TRUNCATE(x,y)**: 返回数字`x`截断为`y`位小数的结果。 - 例如:`TRUNCATE(3.14159,2)` 返回 `3.14...

    汇编语言程序测试参考题型+部分参考

    计算字节或字中1的个数可以使用位操作指令,如`AND`、`SHR`等。 **示例代码**: ```assembly LEA SI, BYTE_DATA ; 或 LEA SI, WORD_DATA XOR BX, BX ; 初始化计数器 NEXT_BIT: TEST [SI], 1 JZ NOT_SET INC BX ...

    sqlserver 知识点列表.pdf

    1. 数值型:int、smallint、bigint、float、money、bit、numeric、decimal(10,2) 2. 字符型:char、varchar、nchar、nvarchar、text、ntext(推荐使用varchar(max)和nvarchar(max)) 3. 日期型:datetime、...

    BigInteger:为Java实现BigInteger

    - `bitLength()`:返回二进制表示中1的个数。 - `setBit(int bitPosition)`, `clearBit(int bitPosition)`, `flipBit(int bitPosition)`:对指定位进行设置、清除或翻转操作。 - `shiftLeft(int n)` 和 `shift...

    华为编程开发规范与案例

    近日在CDB并行测试中发现一个问题:我们需要的小区负荷话统结果总是为零,开始还以为小区负荷太小,于是加大短消息下发数量,但还为零,于是在程序中加入测试代码,把收到的数据在BAM上打印出来, 结果打印出来的...

    海康视频卡动态库

    /// 此DSP上第一个编码通道在所有编码通道中的索引 /// uint firstEncodeChannelIndex; /// /// 此DSP所包含的解码通道个数 /// uint decodeChannelCount; /// /// 此DSP上第一个解码通道在所有解码...

Global site tag (gtag.js) - Google Analytics