Created
June 24, 2013 00:00
-
-
Save lichray/5846992 to your computer and use it in GitHub Desktop.
Fastest popcount https://en.wikipedia.org/wiki/Hamming_weight
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <limits> | |
#include <climits> | |
#include <type_traits> | |
template <int bit> | |
struct fill_bits | |
{ | |
template <typename Int> | |
static constexpr auto apply(Int n) -> Int | |
{ | |
return _lambda(fill_bits<bit / 2>::apply(n)); | |
} | |
private: | |
template <typename Int> | |
static constexpr auto _lambda(Int x) -> Int | |
{ | |
return (x << (bit / 2)) ^ x; | |
} | |
}; | |
template <> | |
struct fill_bits<CHAR_BIT> | |
{ | |
template <typename Int> | |
static constexpr auto apply(Int n) -> Int | |
{ | |
return n; | |
} | |
}; | |
template <typename Int> | |
constexpr auto magic(Int n) | |
-> typename std::enable_if<std::is_unsigned<Int>::value, Int>::type | |
{ | |
return fill_bits<std::numeric_limits<Int>::digits>::apply(n); | |
} | |
template <typename Int> | |
struct m1 : std::integral_constant<Int, magic(Int(0x55))> {}; | |
template <typename Int> | |
struct m2 : std::integral_constant<Int, magic(Int(0x33))> {}; | |
template <typename Int> | |
struct m4 : std::integral_constant<Int, magic(Int(0x0f))> {}; | |
template <typename Int> | |
struct h01 : std::integral_constant<Int, magic(Int(0x01))> {}; | |
template <typename Int> | |
/* c++14 */ inline auto popcount(Int x) -> std::size_t | |
{ | |
x -= (x >> 1) & m1<Int>(); | |
x = (x & m2<Int>()) + ((x >> 2) & m2<Int>()); | |
x = (x + (x >> 4)) & m4<Int>(); | |
return Int(x * h01<Int>()) >> | |
(std::numeric_limits<Int>::digits - CHAR_BIT); | |
} | |
#include <iostream> | |
#include <chrono> | |
#include <cstdlib> | |
int main() { | |
using namespace std::chrono; | |
using traits = std::numeric_limits<uint32_t>; | |
steady_clock::time_point t1, t2; | |
t1 = steady_clock::now(); | |
for (uint32_t x = 0; x < traits::max(); ++x) | |
if (popcount(x) > traits::digits) | |
std::exit(1); | |
t2 = steady_clock::now(); | |
std::cout << "my popcount: " | |
<< duration_cast<duration<double>>(t2 - t1).count() << std::endl; | |
t1 = steady_clock::now(); | |
for (uint32_t x = 0; x < traits::max(); ++x) | |
if (__builtin_popcount(x) > traits::digits) | |
std::exit(1); | |
t2 = steady_clock::now(); | |
std::cout << "__builtin_popcount: " | |
<< duration_cast<duration<double>>(t2 - t1).count() << std::endl; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment