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

比较以下两个表达式

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

哪个更好?

【问题讨论】:

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

标签: c++ bitset


【解决方案1】:

根据 godbolt,bitsetpopcount 在最新的 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

【讨论】:

    猜你喜欢
    • 2019-10-24
    • 1970-01-01
    • 1970-01-01
    • 2014-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多