โจทย์
กำหนด Unsigned 32-bit Integer นับจำนวน Bit ที่เป็น 1 (Population Count / Hamming Weight)
ตัวอย่าง
N = 00000000000000100111 (Binary) = 39 (Decimal)
Bits ที่เป็น 1: 4 ตัว → Output: 4
วิธีการแก้
1. Built-in Function (เร็วที่สุด)
#include <bits/stdc++.h>
using namespace std;
int countBits(uint32_t n) {
return __builtin_popcount(n); // GCC/Clang Built-in
}
// หรือ C++20
#include <bit>
int countBits20(uint32_t n) {
return std::popcount(n); // C++20 Standard
}
2. bitset (Standard Library)
#include <bitset>
int countBitsBitset(uint32_t n) {
return bitset<32>(n).count();
}
3. Brian Kernighan's Algorithm (O(k) where k = set bits)
int countBitsBK(uint32_t n) {
int count = 0;
while (n) {
n &= (n - 1); // Clear least significant set bit
count++;
}
return count;
}
4. Lookup Table (Fastest for repeated calls)
int countBitsLookup(uint32_t n) {
static const uint8_t table[256] = {
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4, // 0-15
// ... สร้างตาราง 0-255
};
return table[n & 0xFF] +
table[(n >> 8) & 0xFF] +
table[(n >> 16) & 0xFF] +
table[(n >> 24) & 0xFF];
}
5. Parallel Summing (SWAR Algorithm)
int countBitsSWAR(uint32_t n) {
n = n - ((n >> 1) & 0x55555555);
n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
n = (n + (n >> 4)) & 0x0F0F0F0F;
n = n * 0x01010101;
return n >> 24;
}
Benchmark Comparison
#include <chrono>
#include <random>
void benchmark() {
vector<uint32_t> data(1000000);
mt19937 rng(42);
generate(data.begin(), data.end(), rng);
auto test = [&](auto func, string name) {
auto start = chrono::high_resolution_clock::now();
long long sum = 0;
for (auto x : data) sum += func(x);
auto end = chrono::high_resolution_clock::now();
cout << name << ": "
<< chrono::duration_cast(end - start).count()
<< " μs, sum=" << sum << endl;
};
test(countBits, "__builtin_popcount");
test(countBitsBitset, "bitset<32>.count()");
test(countBitsBK, "Brian Kernighan");
test(countBitsSWAR, "SWAR");
}
ผลลัพธ์ตัวอย่าง
__builtin_popcount: 1200 μs bitset<32>.count(): 2100 μs Brian Kernighan: 3500 μs SWAR: 1800 μs
ผลลัพธ์โค้ดตัวอย่าง
4
สรุป
- Production: ใช้
__builtin_popcount(GCC/Clang) หรือstd::popcount(C++20) - Portable:
bitset<32>(n).count() - Algorithm: Brian Kernighan O(k) ดีกว่า O(32) เมื่อ bits น้อย
- Embedded/No builtin: SWAR หรือ Lookup Table