std::bitset<N>::count vs __builtin_popcount

Posted

技术标签:

【中文标题】std::bitset<N>::count vs __builtin_popcount【英文标题】: 【发布时间】:2020-02-11 09:44:21 【问题描述】:

比较以下两个表达式

std::bitset<8>(5).count()
__builtin_popcount(5)

哪个更好?

【问题讨论】:

我从来没有听说过第二个,所以在这方面,标准的。另外std::bitset 保证可移植性和行为 “哪个更好?” 依据什么标准?正如@Tas 已经提到的,标准的是可移植的。 什么是“更好”?表现?可移植性?保证行为? 【参考方案1】:

根据 godbolt,bitset 和 popcount 在最新的 g++ 上产生相同的 asm 输出。但是,正如 cmets 中所述,__builtin_popcount 是 gcc 扩展,在 x86 以外的其他编译器和其他体系结构上均不可用。因此,bitset 选项显然更好。

【讨论】:

我会说那是 K.O. popcount 的标准。但此外,popcount one 仅限于 unsigned int,即。 e.通常是 32 位(有时甚至只有 16 位),而从 C++11 开始,bitset 接受 unsigned long long,允许(至少)64 位(好的,我们也可以使用移位和多次调用 popcount,但这很简单不那么好......)。【参考方案2】:
int  __builtin_popcount(unsigned int);

是 GCC 的内置函数,而 std::bitset&lt;N&gt;::count 是 C++ 标准。

两个函数做同样的事情:返回设置为true的位数。

你应该使用什么?

总是倾向于使用 C++ 标准的函数,因为其他编译器不支持 __builtin_popcount 函数。

更新

如果您看一下 Google Benchmark 工具所做的统计数据:

#include <bitset>

static void GccBuiltInPopCount(benchmark::State& state) 
    for (auto _ : state) 
        __builtin_popcount(5);
    


BENCHMARK(GccBuiltInPopCount);

static void StdBitsetCount(benchmark::State& state) 
    for (auto _ : state) 
        std::bitset<8>(5).count();
    


BENCHMARK(StdBitsetCount);

使用 GCC 9.2 和标志 -std=c++2a -O3,GCC 内置函数比 std::bitset&lt;N&gt;::count() 函数慢 10%,但由于两个函数的 ASM 输出相同,因此基准测试的差异可能是由于其他因素。

【讨论】:

考虑到两个来源产生相同的代码,请参阅 Denis 的 answer,我倾向于假设其他因素导致的运行时差异...... @Aconcagua 实际上,-02 产生相同的 asm 输出,但 -03 不是 尝试了上面的两个链接并更改为-O3,仍然相同。也许不在代码中使用返回值对优化有一些影响?我可以想象,在第二个示例中,对 __popcountdi2 的汇编调用只是被丢弃了,因为无论如何都没有使用该值。 @Aconcagua 是的,这可能是原因。无论如何,我会注意到基准的差异可能是由于其他因素造成的。推荐还是一样:std::bitset&lt;N&gt;::count() 完全同意该建议;不过,我会限定更强大的原因:即使 如果 我们会发现扩展更快,我们应该更喜欢标准,除非我们在 profiling 期间发现标准成为我们应用程序时间关键部分的瓶颈......【参考方案3】:

当你不知道std::bitset&lt;N&gt;::count中N的值时,我认为第二个更好

更新: 你可以试试std::popcount

【讨论】:

以上是关于std::bitset<N>::count vs __builtin_popcount的主要内容,如果未能解决你的问题,请参考以下文章

std::bitset<N>::count vs __builtin_popcount

为啥 std::bitset 不带有迭代器?

如何编写适用于 32 位和 64 位的 std::bitset 模板

为啥 std::bitset<8> 变量无法处理 11111111?

如何将任何用户定义的类型转换为 std::bitset?

为啥带有 unsigned long long 参数的 std::bitset 构造函数未标记为显式?