6

Comparing the following two expressions

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

which one is better?

Milo Lu
  • 3,176
  • 3
  • 35
  • 46
  • 2
    I've never heard of the second, so in that regard, the standard one. Also `std::bitset` guarantees portability and behaviour – Tas Feb 11 '20 at 09:45
  • 2
    _"which one is better?"_ According to what criteria ? As @Tas already mentioned, the standard one is portable. – Fareanor Feb 11 '20 at 09:48
  • 3
    What is "better"? Performance? Portability? Guaranteed behavior? – Holt Feb 11 '20 at 09:49

3 Answers3

7
int  __builtin_popcount(unsigned int);

is a built in function of GCC while std::bitset<N>::count is a C++ standard.

Both function do the same thing: return the number of bits that are set to true.

What should you use?

Always tend to use C++ standard's functions because other compilers don't support __builtin_popcount function.

UPDATE

If you take a look at the statistics made by Google Benchmark tool:

#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);

with GCC 9.2 and flags -std=c++2a -O3, GCC built in function is 10% slower than the std::bitset<N>::count() function but, since the ASM output is the same for both function, the difference in benchmark could be due to other factors.

NutCracker
  • 11,485
  • 4
  • 44
  • 68
  • Considering that both sources produce the same code, see Denis' [answer](https://stackoverflow.com/a/60166085/1312382), I tend to assume the runtime difference resulting from other factors... – Aconcagua Feb 11 '20 at 10:57
  • @Aconcagua actually, `-02` produces the same asm output but `-03` not – NutCracker Feb 11 '20 at 10:58
  • Tried both links above and changed to `-O3`, still both the same. Maybe not using the return values in your code has some influence on optimisations? I could imagine that the assembler call to `__popcountdi2` simply is discarded in second example as the value is not used anyway. – Aconcagua Feb 11 '20 at 11:05
  • 2
    @Aconcagua yes, that could be the reason. Anyway, I will note that the difference in the benchmark could be due to other factors. Recommendation is still the same: `std::bitset::count()` – NutCracker Feb 11 '20 at 11:15
  • Fully agree on the recommendation; I'd qualify the reasons for even stronger, though: Even *if* we would have discovered the extension to be faster, we should prefer the standard, unless we discover during *profiling* the standard to be a bottleneck in a time critical part of our application... – Aconcagua Feb 11 '20 at 11:27
  • *"Both function do the same thing: return the number of bits that are set to true."* - Note that both functions are not equivalent. The two functions are only equivalent when `N == sizeof(unsigned int)` and you pass positive values. – Holt Feb 11 '20 at 12:01
7

According to godbolt, bitset and popcount yields just the same asm output on latest g++. However, as mentioned in the comments, __builtin_popcount is an gcc extension and won't be available on neither other compilers nor other architectures than x86. Therefore, bitset option is clearly better.

Denis Sheremet
  • 2,453
  • 2
  • 18
  • 34
  • 1
    I'd say that's the K.O. criterion for popcount already. But additionally, with popcount one is limited to unsigned int, i. e. usually 32 (sometimes even only 16) bits, whereas, since C++11, bitset accepts unsigned long long, allowing for (at least) 64 bits (OK, we could use bitshifts and multiple calls for popcount as well, but that's simply not as nice...). – Aconcagua Feb 11 '20 at 13:46
0

When you don’t know the value of N in std::bitset<N>::count, I think the second one is better

update: you can try std::popcount

Kargath
  • 450
  • 5
  • 15
  • 1
    For runtime-determined bitset size, boost::dynamic_bitset is available, which also has a count method. – fjs Dec 12 '22 at 05:03