计算整数上的位 1 的速度与 GCC __builtin__popcount(int) 一样快

2023-11-27

我编写了一个算法(摘自“C 编程语言”),可以非常快地计算 1 位的数量:

int countBit1Fast(int n)
{
    int c = 0;
    for (; n; ++c)
        n &= n - 1;
    return c;
}

但一位朋友告诉我__builtin__popcount(int)速度快很多,但便携性较差。我尝试了一下,速度快了很多倍!为什么这么快?我想尽可能快地计算位数,但不拘泥于特定的编译器。

EDIT:我可能会在 PIC 微控制器上使用它,也可能在非英特尔处理器上使用它,所以我需要最大的可移植性。


我编写了一个算法(摘自“C 编程语言”),可以非常快地计算 1 位的数量:

我不明白为什么有人会把你的方法描述为“非常快”。它有点聪明,而且平均来说应该比简单的替代方案更快。它也不依赖于表示的宽度int,这是一个优点。我观察到它对负参数有未定义的行为,但这是按位运算符和函数的常见主题。

让我们分析一下,假设有一个非负参数:

int c = 0;
for (; n; ++c)
    n &= n - 1;
  • 执行了多少次循环迭代?

    1 表示值的二进制表示形式中的每 1 位,无论where在每一位所在的值中

  • 每次迭代执行多少工作

    • 一个增量c
    • 的一项比较n反对零(当打破循环时再加上一个)
    • 减一n by 1
    • 一个按位“和”

    这忽略了读取和存储,通过将操作数保存在寄存器中,这很可能可以免费或特别便宜。如果我们假设每个操作的成本相同,则每次迭代有四次操作。对于随机 32 位整数,平均迭代 16 次,总共平均 65 次操作。 (最好的情况只是一次操作,但最坏的情况是 129,这并不比简单的实现更好)。

__builtin_popcount(),另一方面,使用一条指令无论支持它的平台上的输入如何,例如您的平台很可能都是如此。然而,即使对于那些没有专用指令的人来说,也可以更快地完成(平均而言)。

@dbush 提出了一种这样的机制,它与您提出的机制具有类似的优点。特别是,它不依赖于预先选择的整数宽度,尽管它确实依赖于where在 1 位驻留在表示中,对于某些参数(较小的参数),它确实比其他参数运行得更快。如果我数对了,那一个就平均了约20次操作在随机 32 位输入上:四次循环迭代中每一次迭代五次(只有 0.4% 的随机输入需要少于四次迭代)。我正在计算每次迭代读取的一个表,我假设可以从缓存中提供该表,但这可能仍然不如对寄存器中已保存的值进行算术运算快。

严格计算的一种是:

int countBit1Fast(uint32_t n) {
    n = (n & 0x55555555u) + ((n >> 1) & 0x55555555u);
    n = (n & 0x33333333u) + ((n >> 2) & 0x33333333u);
    n = (n & 0x0f0f0f0fu) + ((n >> 4) & 0x0f0f0f0fu);
    n = (n & 0x00ff00ffu) + ((n >> 8) & 0x00ff00ffu);
    n = (n & 0x0000ffffu) + ((n >>16) & 0x0000ffffu);
    return n;
}

这很容易计算:五次加法、五次移位、十次按位“与”运算,以及 5 次常量加载,总共25 次操作对于每个输入(对于 64 位输入,它只增加到 30,尽管这些现在是 64 位操作而不是 32 位操作)。然而,该版本本质上取决于输入数据类型的特定大小。

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

计算整数上的位 1 的速度与 GCC __builtin__popcount(int) 一样快 的相关文章

随机推荐

  • 如何通过电子邮件将我正在开发的 Android 应用程序发送给某人?

    这是我的第一个 Android 应用程序 我需要将迄今为止的内容通过电子邮件发送给某人进行测试 我应该如何导出应用程序并附加它 以免它被视为垃圾 更简单的方法 将 apk 放在您的网络服务器上 使用以下命令创建 QR 条形码图像 然后通过电
  • 为什么 CAP 定理中的 C 与 ACID 中的 C 不同?

    我的问题很简单 正在寻找一个更简单的答案 为什么 CAP 定理中的 C 与 ACID 中的 C 不同 Read thisHN 螺纹 Update NOSQL v1 0 搭便车指南 幻灯片 71 说 CAP 中的 C A C 原子一致性 两个
  • 跟踪数据库模式更改的机制[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心以获得指导 跟踪和 或自动化数据库架构
  • 计算两个 Pandas 列之间的时间差(以小时和分钟为单位)

    我有两列 fromdate and todate 在数据框中 import pandas as pd data todate pd Timestamp 2014 01 24 13 03 12 050000 pd Timestamp 2014
  • 将 std::experimental::filesystem 与 Xcode 9 链接

    我正在使用 std experimental filesystem 和 Xcode 9 0 beta 编译器阶段完成正常 但链接器抱怨未定义的符号 std experimental filesystem v1 path filename c
  • 创建大量线程时出现.Net 内存泄漏

    我有一个随着时间的推移创建大量线程的应用程序 我注意到内存使用量随着它的运行而增加 并最终耗尽内存 但相同的代码在我同事的环境中不会泄漏内存 我们都有相同的 net 版本 我能够使用以下示例代码重现该问题 该代码不会在我同事的笔记本电脑上泄
  • 为什么最好从方法类的实例中静态调用静态方法?

    如果我在 Java 中创建类的实例 为什么最好静态调用同一类的静态方法 而不是使用 this method 当我尝试通过 this staticMethod 从自定义类的构造函数中调用静态方法 staticMethod 时 我收到来自 Ec
  • 获取客户端当前在断开连接事件中所在的房间列表

    我正在尝试查找客户端当前在断开连接事件中所在的房间列表 关闭浏览器 重新加载页面 互联网连接已断开 我需要它的原因如下 用户已进入几个房间 然后其他人也做了同样的事情 然后他关闭了浏览器选项卡 我想通知他所在房间里的所有人他离开了 所以我需
  • pyside qtreewidget 约束拖放

    我试图向 QTreeWidget 拖放功能添加约束 以防止分支进入另一个根中的另一个分支 这是一个让事情更清楚的例子 我有 4 个对象 我们称它们为苹果 香蕉 胡萝卜 榴莲 这棵树看起来像这样 isDelicious Root Backgr
  • Xcode 11.4 beta 在 @Published 属性订阅上崩溃。这是怎么回事?

    我不知道为什么 但我的代码在这个 searchTerm 发布者上崩溃了 我的代码中有很多这样的发布者 其他一切都正常 它仅在这个新的 Xcode 版本中不起作用 而在以前的版本中起作用 如果我评论这一行并将其替换为 searchTerm p
  • 将信息从 javascript 传递到 django 应用程序并返回

    所以我试图基本上建立一个网页 用户在其中选择一个id 然后该网页将id信息发送到python 其中python使用该id来查询数据库 然后将结果返回到网页进行显示 我不太确定该怎么做 我知道如何使用 ajax 调用来调用 python 生成
  • C# FlowDocument 到 HTML 的转换

    基本上 我有一个 RichTextBox 我想将其格式化内容转换为 HTML 以便它可以作为电子邮件发送 我当前使用的方法根本不提供任何格式 string message new TextRange messageTextBox Docum
  • 插入大文件时出现“ORA-03135: 连接失去联系”

    我正在尝试使用实体框架 ODP Net 将可能大量的二进制数据插入到远程 Oracle 11g 数据库中 它对于非常小的文件 我不认为它超时 因为异常发生在执行命令的一秒钟内 我尝试在连接字符串中设置以下两项 但无济于事 Validate
  • 是否可以通过模式切换在64位进程中执行32位代码?

    在这个页面中 http www x86 64 org pipermail discuss 2004 August 005020 html他说有一种方法可以在应用程序中混合 32 位代码和 64 位代码 他假设应用程序是 32 位 兼容模式
  • 哪个 STL C++ 容器用于固定大小的列表?

    我有一个消费应用程序 它需要在列表中存储最多 100 个对象 以提供给回调进行处理 因为如果消费者没有跟上 保留旧数据将是多余的 当新数据到达时 它可以简单地覆盖最旧的元素 我正在考虑使用循环缓冲区容器并猜测它会是 deque 但发现它不使
  • Git-archive远程端挂了

    我试图从 Github 上签出单个文件 关注后 this我尝试过的线程 git archive format tar remote ssh email protected user project git HEAD README md 我收
  • 如何获取“somepage.php#name”中哈希后的值?

    对于给定的网址 我想从数据库中获取哈希后名称的年龄 所以对于像这样的网址thepage php Madonna 你会看到的 119 如何提取 url 中哈希值后的值 我需要一种安全的全浏览器兼容的非 JavaScript 方式 我想像 GE
  • Android Studio 的 Structure 侧边栏中的不同图标和符号代表什么意思?

    当我单击 Android Studio 中的 结构 侧边栏时 它会显示当前类的内容 然而 有一些图标和符号用于指示不同的成员 例如 带有字母 m 的圆圈表示方法等 在哪里可以获得所有图标和符号的完整列表和详细信息 我正在寻找类似解释各种图标
  • 会话在每个 servlet 请求中丢失并创建为新会话

    我有这个大问题 每次我向服务器发出新请求时 我当前的会话都会消失 我查过很多地方 我找不到问题所在 我还包括了 tomcat 和应用程序中 web xml 中的 session config 我还启用了我的浏览器接受 cookie 在每个浏
  • 计算整数上的位 1 的速度与 GCC __builtin__popcount(int) 一样快

    我编写了一个算法 摘自 C 编程语言 可以非常快地计算 1 位的数量 int countBit1Fast int n int c 0 for n c n n 1 return c 但一位朋友告诉我 builtin popcount int