这种位操作在 Java 中是如何工作的?

2024-01-29

我正在研究 Java 如何计算 int 的位集。
我脑子里有这样简单的事情(我认为是正确的):

public static int bitCount(int number){  
        final int MASK = 0x1;  
        int count = 0;  

        for(int i = 0; i < 32; i++){  
            if(((number >>> i) & MASK) == MASK){  
                count++;  
            }  
        }  
        return count;  
    }  

相反,我找到了一种我完全不知道在做什么的方法(对我来说似乎很神奇):

 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;  

有人可以帮助理解它的作用以及为什么像我首先想到的那样的简单函数是/可能是坏的吗?


Sure

i = i - ((i >>> 1) & 0x55555555);

5 的位模式是0101(四位),因此掩码是位模式的重复01十六次。该行计算数字的每个两位对中的位数。如果考虑两位数对,(i >>> 1) & 0x1获取低位中的高位。现在,有四种可能的两位模式

00 ~> 00 - 00 = 00
01 ~> 01 - 00 = 01
10 ~> 10 - 01 = 01
11 ~> 11 - 01 = 10

现在,每个两位对都包含原始数据在这些位置中的位数。

i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);

接下来,我们计算每个四位组(也称为半字节)中的位。通过掩盖一个小口0x3 = 0011(b),我们得到半字节低两位的位数,并且(i >>> 2) & 0x3从半字节的高位两位获取计数。现在添加了这些计数。由于每次计数最多为 2,因此总和最多为 4,因此不会留下半字节。

i = (i + (i >>> 4)) & 0x0f0f0f0f;

现在对每个八位位组中的位进行计数。每个半字节包含原始数据中该位置设置的位数。右移四位将计数从每个位置的高位半字节移动到低位半字节,并将它们相加。然后,我们还将计数从相邻八位字节的低阶半字节移动到高阶半字节,该计数被& 0x0f0f0f0f。由于每个八位位组最多可以设置八位,因此计数不会留下八位位组的低位半字节。

i = i + (i >>> 8);

现在我们将相邻八位位组对的计数相加。

i = i + (i >>> 16);

现在我们将高位两个八位位组和低位两个八位位组中的计数总数相加。

return i & 0x3f;

最后,除了最低阶八位位组之外的所有八位位组都被屏蔽掉,因为高阶八位位组仍然包含中间计数。

您的简单实现可能被认为不好的原因是性能。复杂的位破解使用更少的操作并且没有分支,因此速度更快。然而,它更容易出错。

另一种计算设置位的巧妙方法int (or long) is

public static int bitCount(int n) {
    int count = 0;
    while(n != 0) {
        ++count;
        n = n & (n-1);
    }
    return count;
}

这有效是因为n = n & (n-1)清除最后设置的位n并保持其他一切不变。如果位模式为n以。。结束

...100...0

位模式n-1 is

...011...1

以及最后 1 位之前的位n是相同的。在 Java 中,这也保证适用于负数,因为整数溢出具有环绕语义,所以如果n = Integer.MIN_VALUE,位模式是100...0 and n - 1变成Integer.MAX_VALUE与位模式011...1.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

这种位操作在 Java 中是如何工作的? 的相关文章

  • java.lang.NoSuchMethodError: org.mockito.Mockito.framework()Lorg/mockito/MockitoFramework

    我一直面临一个特殊的问题 基本上 当我正常运行 Mockito 测试 即 作为 Junit 测试运行 时 它会出现以下错误 有人可以帮我看看我的错误是什么吗 收到的错误 java lang NoSuchMethodError org moc
  • 行类型 Spark 数据集的编码器

    我想写一个编码器Row https spark apache org docs 2 0 0 api java index html org apache spark sql Row html输入 DataSet 用于我正在执行的地图操作 本
  • Java如何从字符串实例化一个类[重复]

    这个问题在这里已经有答案了 可能的重复 在 Java 中从变量创建新类 https stackoverflow com questions 1268817 create new class from a variable in java 我
  • Java 应用程序可以检测到调试器已连接吗?

    我知道 jvm 启动选项可以让 jvm 等待附加调试器 这不是我在这里的意思 是否有可能从 Java 代码中也检测调试器的附件 以便我可以例如编写一个正在执行某些操作的 脚本 然后在某个时刻让我的应用程序等待调试器 不会 这些选项是 JVM
  • Java 正则表达式中 \w 和 \b 的 Unicode 等效项?

    许多现代正则表达式实现解释 w字符类简写为 任何字母 数字或连接标点符号 通常 下划线 这样 正则表达式就像 w 匹配像这样的词hello l ve GO 432 or gefr ig 不幸的是 Java 没有 在爪哇 w仅限于 A Za
  • 如何在首次运行时填充大型 SQLite 数据库

    我正在开发一个基于 SQLite 数据库的字典应用程序 该数据库包含超过 300 000 行 问题在于 最终形式的数据库文件由全文索引表组成 并且重量远远超过150Mb 我通过创建无内容的 fts4 表设法将 db 文件大小降至最低 数据库
  • 如何仅使用命令行运行 Maven 创建的 jar 文件

    我需要一些帮助来尝试使用命令行运行以下 Maven 项目 https github com sarxos webcam capture https github com sarxos webcam capture webcam captur
  • 在 Java/Android 中查找 UTF-8 字符串中的字符数

    我试图找出字符串以 UTF 8 存储时的长度 我尝试了以下方法 String str Charset UTF8 CHARSET Charset forName UTF 8 byte abc str getBytes UTF8 CHARSET
  • 在 Graal.js 中使用 java 类

    使用 Graal js 如何将 java 类导入到 JS 脚本中 以下代码适用于 Nashorn JJS 但不适用于 Graal js 因为没有Java type 在graal中 我需要在某个时候调用truffle吗 var ArrayLi
  • Android-如何在指定时间后台下载数据

    我提前很抱歉没有发布任何代码 主要是因为我一生都无法弄清楚我需要如何做我需要做的事情 基本上 在一天中的指定时间间隔 例如下午 5 点 我希望我的应用程序从我的服务器下载一些数据并将其存储在设备上 这是为了减少每次运行应用程序时下载数据对我
  • 使用 TestRestTemplate 和 MockRestServiceServer 时,解析异常而不是实体列表不起作用

    我有一个简单的控制器 CODE https github com joergi tryouts blob main kotlin mockrestserver src main kotlin io joergi kotlinmockrest
  • maven默认过滤器目录的好处[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 最近我发现了maven资源过滤并在文档中看到了一条注释 标准目录布局src main filters 资源过滤器文件 我注意到maven不搜索声
  • Java - 修剪字节数组中的尾随空格

    我有与此类似的字节数组 77 83 65 80 79 67 32 32 32 32 32 32 32 大致等于 M S A P O C when printed as chars 现在我想修剪尾随空白 使其看起来像 77 83 65 80
  • 多少次函数调用会导致堆栈溢出

    你好 Android Java 开发者 当一个函数调用一个函数并且该函数调用另一个函数等等时 有多少次调用 堆栈长度 会让我陷入堆栈溢出 有一般经验法则吗 我问的原因是因为我现在对于我的 5 人纸牌游戏来说哪个更有效 设计明智 解决方案一
  • Spring Boot 中的外部化配置,多个应用程序在同一容器中运行

    我正在构建多个 Spring Boot 应用程序 这些应用程序将部署在同一个 servlet 容器上 但我很难让 Spring Boot 按照我想要的方式使用外部化配置文件 而不是像框架想要的那样 情况 多个 Spring Boot 应用程
  • 使 @Schedule 在集群环境中仅运行一次

    我有两个 tomee 实例集群 每个都有一个方法注释如下 Schedule dayOfWeek public void runMeDaily 我只想每天运行一次这个方法 每天不两次 每个实例一次 我可以使用此处描述的标志仅在一个WebLog
  • 在Android中创建自定义按钮类

    我正在尝试为我的 Android 应用程序创建自定义按钮类 public class TicTacButton extends Button 我已经在里面设置了所有构造函数TicTacButton并创建了自定义方法和属性 在我的主要活动中
  • JFrame 类型的方法 ... 未定义

    我正在尝试制作一个带有两个菜单列表的 gui 每个菜单列表有 3 个项目 我的问题是 当我单击某个项目时 出现错误 JFrame 类型的方法 displayList int AirplaneList 未定义 AirplaneControll
  • JPanel 无法使用 setSize 和 setPreferedSize

    请解释为什么它不起作用 您也可以发布解决方案来解决此问题 非常感谢您提前 public class Run extends JFrame Fields static JPanel jpanel private int x y Constru
  • Struts2 中有多种结果类型?

    我有一个使用 Tiles 的 Struts2 应用程序 如何在操作映射中获取多种结果类型 因为我需要将de输出设置为JSON数据 并且同时Tiles 我努力了

随机推荐