计算位数的最快方法[重复]

2024-01-11

可能的重复:
如何计算 32 位整数中设置的位数? https://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer

给出一个unsigned char类型值,计算其中的总位数。最快的方法是什么? 我写了如下三个函数,最好的方法是什么,有人能想出一个更快的函数吗?(我只想要极快的函数)

const int tbl[] =
{
#define B2(n)   n, n+1, n+1, n+2
#define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
#define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
    B6(0), B6(1), B6(1), B6(2)
};

char naivecount (unsigned char val)
{
    char cnt = 0;
    while (val)
    {
        cnt += (val & 1);
        val = val >> 1;
    }
    return cnt;
}

inline tableLookUp(int val)
{
    assert(val >= 0 && val <= 255);
    return tbl[val];
}

int asmCount(int val)
{
    int res = 0;
    asm volatile("xor %0, %0\n\t"
            "begin:\n\t"
            "cmp $0x0, %1\n\t"
            "jle end\n\t"
            "movl %1, %%ecx\n\t"
            "and $0x1, %%ecx\n\t"
            "addl %%ecx, %0\n\t"
            "shrl %1\n\t"
            "jmp begin\n\t"
            "end:"
            : "=r"(res)
            : "r" (val));
    return res;
}

EDIT:

我已经测试了所有方法,最快的一种是使用popcntl指令。在没有指令的平台上,我将使用查表。


如果您想手动编码,请尝试以下操作:

#include <stdint.h>

int popcnt8(uint8_t x) {

    x = (x & 0x55) + (x >> 1 & 0x55);
    x = (x & 0x33) + (x >> 2 & 0x33);
    x = (x & 0x0f) + (x >> 4 & 0x0f);

    return x;
}

在 x86 上,编译为(AT&T 语法):

popcnt8:
    movl    %edi, %eax
    shrb    %dil
    andl    $85, %eax
    andl    $85, %edi
    addl    %eax, %edi
    movl    %edi, %eax
    shrb    $2, %dil
    andl    $51, %eax
    andl    $51, %edi
    addl    %eax, %edi
    movl    %edi, %eax
    shrb    $4, %dil
    andl    $15, %eax
    addl    %edi, %eax
    movzbl  %al, %eax
    ret

将其与 gcc 使用内在函数生成的内容进行比较:

#include <stdint.h>

int popcnt8_intrin(uint8_t x) { return __builtin_popcount(x); }

在具有 SSE 4.2 的 x86 上:

popcnt8_intrin:
movzbl  %dil, %eax
popcntl %eax, %eax
ret

这不是最佳的; clang 生成:

popcnt8_intrin:
    popcntl %edi,%eax
    ret

将计算减少到一条(!)指令。

在没有 SSE 4.2 的 x86 上:

popcnt8_intrin:
subq    $8, %rsp
movzbl  %dil, %edi
call    __popcountdi2
addq    $8, %rsp
ret

gcc 本质上是在这里调用它的库。不太理想。 clang 做得更好一些:

popcnt8_intrin:                         # @popcnt8_intrin
movl    %edi, %eax
shrl    %eax
andl    $85, %eax
subl    %eax, %edi
movl    %edi, %eax
andl    $858993459, %eax        # imm = 0x33333333
shrl    $2, %edi
andl    $858993459, %edi        # imm = 0x33333333
addl    %eax, %edi
movl    %edi, %eax
shrl    $4, %eax
addl    %edi, %eax
andl    $252645135, %eax        # imm = 0xF0F0F0F
imull   $16843009, %eax, %eax   # imm = 0x1010101
shrl    $24, %eax
ret

clang 计算整个 32 位数字的 popcnt。恕我直言,这不是最佳的。

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

计算位数的最快方法[重复] 的相关文章

  • json.net自定义jobject反序列化

    我正在尝试使用 JsonConvert DeserializeObject string 将字符串反序列化为可与动态一起使用的 jobject 来动态访问 json 文档 但是我想避免知道文档的大小写 以便我可以输入 dynamic doc
  • 为什么 F# 的默认集合是排序的,而 C# 的不是?

    当从 C 世界迁移到 F 最惯用的可能 思维方式时 我发现了这个有趣的差异 在 C 的 OOP mutable 世界中 默认的集合集合似乎是HashSet https learn microsoft com en us dotnet api
  • 删除是如何工作的? [复制]

    这个问题在这里已经有答案了 可能的重复 C 编程 free 如何知道要释放多少 https stackoverflow com questions 1518711 c programming how does free know how m
  • 检测wlan是否关闭

    任何人都可以给我一个提示 如何在 Windows Phone 上以编程方式检测 C 8 1 应用程序 不是 8 0 是否启用 禁用 WLAN 我不想更改这些设置 只是需要知道 该解决方案是一个 Windows 8 1 通用应用程序 Wind
  • 将完整模板参数值映射到原始类型

    我想将数字映射到类型 在这个例子中 我将创建一个函数 将 sizeof 结果映射到有符号的原始类型 我想知道是否有更好的方法来完成我在现代 C 中所做的事情 即采用模板化值并将其转换为类型 现在 这可以将大小转换为已知类型 但我似乎无法在标
  • 解析 JWT 令牌以仅获取有效负载内容,无需 C# 或 Blazor 中的外部库

    我正在使用 Blazor 编写可以访问 JWT 的客户端应用程序 我想知道一种简单的方法来读取令牌有效负载内容而不添加额外的依赖项 因为我不需要其他信息 也不需要验证令牌 我认为解析有效负载内容应该足够简单 只需将其写入方法即可 JwtTo
  • std::call_once 可重入且线程安全吗?

    std call once http en cppreference com w cpp thread call once是线程安全的 但它也是可重入的吗 我使用 VS2012 调试和发布 进行的测试表明 调用std call once从单
  • 运行需要 MySql.Data 的内置 .NET 应用程序

    我在运行我编写的内置 NET 应用程序时遇到问题 我的应用程序使用最新的 MySql 连接器 该连接器安装在我的系统上 当我尝试将其添加为引用时 该连接器显示为 NET 4 Framwork 组件 当我在环境中以调试模式运行应用程序时 一切
  • 是否存在指向不同类型的指针具有不同大小的平台?

    C 标准允许指向不同类型的指针具有不同的大小 例如sizeof char sizeof int 是允许的 但是 它确实要求如果将指针转换为void 然后转换回其原始类型 它必须与其原始值进行比较 因此 从逻辑上来说 sizeof void
  • 在开关中使用“goto”?

    我看到了一个建议的编码标准 内容如下Never use goto unless in a switch statement fall through 我不跟 这个 例外 案例到底是什么样的 这证明了goto 此构造在 C 中是非法的 swi
  • 如何制作可启动程序?

    所以 这个问题可能看起来很奇怪 但假设我编译了 int main void int x 3 int y 4 int z x y 是否可以让CPU这样运行 如何 例如 这允许我写入监视器吗 如果我没记错的话 内存中有些地方可以写入要显示的内容
  • 为什么 VC++ 编译器 MOV+PUSH args 而不是仅仅 PUSH 它们? x86

    在 VC 的反汇编中 正在进行函数调用 编译器在压入本地指针之前将其 MOV 到寄存器 memcpy nodeNewLocation pNode sizeCurrentNode 0041A5DA 8B 45 F8 mov eax dword
  • 如何对 NServiceBus.Configure.WithWeb() 进行单元测试?

    我正在构建一个 WCF 服务 该服务接收外部 IP 上的请求并将其转换为通过 NServiceBus 发送的消息 我的单元测试之一调用Global Application Start 它执行应用程序的配置 然后尝试将 Web 服务解析为 验
  • 析构函数中的异步操作

    尝试在类析构函数中运行异步操作失败 这是代码 public class Executor public static void Main var c1 new Class1 c1 DoSomething public class Class
  • 在 asp.net MVC 中使用活动目录进行身份验证

    我想使用活动目录对我的 asp net mvc 项目中的用户进行身份验证 在网上冲浪了几个小时后 我没有找到任何对我有用的东西 我已经看到了所有结果 但什么也没有 我尝试按照许多帖子的建议编辑我的 web config 如果有人可以帮助我提
  • 英文日期差异

    接近重复 如何计算相对时间 https stackoverflow com questions 11 how do i calculate relative time 如何在 C 中计算某人的年龄 https stackoverflow c
  • 从浏览器访问本地文件?

    您好 我想从浏览器访问系统的本地文件 由于涉及大量安全检查 是否可以通过某种方式实现这一目标 或使用 ActiveX 或 Java Applet 的任何其他工作环境 请帮帮我 要通过浏览器访问本地文件 您可以使用签名的 Java Apple
  • 如何在 winforms 应用程序的主屏幕显示之前显示欢迎屏幕?

    我想在应用程序启动时加载欢迎屏幕 然后用户单击欢迎屏幕上的按钮 然后关闭欢迎屏幕 最后显示主屏幕 static void Main startup method being called Application EnableVisualSt
  • 为什么以下 C 程序会出现总线错误?

    我认为这是第一个失败的 strtok 调用 好久没写C了 有点不知所措 非常感谢 include
  • 结构化绑定的用例有哪些?

    C 17 标准引入了新的结构化绑定 http en cppreference com w cpp language structured binding功能 最初是proposed http www open std org jtc1 sc

随机推荐