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<N>::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<N>::count()
函数慢 10%,但由于两个函数的 ASM 输出相同,因此基准测试的差异可能是由于其他因素。
【讨论】:
考虑到两个来源产生相同的代码,请参阅 Denis 的 answer,我倾向于假设其他因素导致的运行时差异...... @Aconcagua 实际上,-02
产生相同的 asm 输出,但 -03
不是
尝试了上面的两个链接并更改为-O3
,仍然相同。也许不在代码中使用返回值对优化有一些影响?我可以想象,在第二个示例中,对 __popcountdi2
的汇编调用只是被丢弃了,因为无论如何都没有使用该值。
@Aconcagua 是的,这可能是原因。无论如何,我会注意到基准的差异可能是由于其他因素造成的。推荐还是一样:std::bitset<N>::count()
完全同意该建议;不过,我会限定更强大的原因:即使 如果 我们会发现扩展更快,我们应该更喜欢标准,除非我们在 profiling 期间发现标准成为我们应用程序时间关键部分的瓶颈......【参考方案3】:
当你不知道std::bitset<N>::count
中N的值时,我认为第二个更好
更新: 你可以试试std::popcount
【讨论】:
以上是关于std::bitset<N>::count vs __builtin_popcount的主要内容,如果未能解决你的问题,请参考以下文章
std::bitset<N>::count vs __builtin_popcount
如何编写适用于 32 位和 64 位的 std::bitset 模板