2015-11-17 06:53:45 +08:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "xorshift128plus.hpp"
|
|
|
|
#include "utils/likely.hpp"
|
|
|
|
|
|
|
|
template <size_t N, class R=Xorshift128plus>
|
|
|
|
class FastBinomial
|
|
|
|
{
|
|
|
|
// fast binomial draws coin tosses from a single generated random number
|
|
|
|
// let's draw a random 4 bit number and count trailing ones
|
|
|
|
//
|
|
|
|
// 1 0000 -> 1 =
|
|
|
|
// 2 0001 -> 2 == 8 x = p = 8/16 = 1/2
|
|
|
|
// 3 0010 -> 1 = 4 x == p = 4/16 = 1/4 p_total = 15/16
|
|
|
|
// 4 0011 -> 3 === 2 x === p = 2/16 = 1/8
|
|
|
|
// 5 0100 -> 1 = 1 x ==== p = 1/16 = 1/16
|
|
|
|
// 6 0101 -> 2 == --------------------------
|
|
|
|
// 7 0110 -> 1 = 1 x ===== p = 1/16 invalid value, retry!
|
|
|
|
// 8 0111 -> 4 ====
|
|
|
|
// 9 1000 -> 1 =
|
|
|
|
// 10 1001 -> 2 ==
|
|
|
|
// 11 1010 -> 1 =
|
|
|
|
// 12 1011 -> 3 ===
|
|
|
|
// 13 1100 -> 1 =
|
|
|
|
// 14 1101 -> 2 ==
|
|
|
|
// 15 1110 -> 1 =
|
|
|
|
// ------------------
|
|
|
|
// 16 1111 -> 5 =====
|
|
|
|
|
2015-11-18 09:23:27 +08:00
|
|
|
static constexpr uint64_t mask = (1ULL << N) - 1;
|
2015-11-17 06:53:45 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
unsigned operator()()
|
|
|
|
{
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
// couting trailing ones is equal to counting trailing zeros
|
|
|
|
// since the probability for both is 1/2 and we're going to
|
|
|
|
// count zeros because they are easier to work with
|
|
|
|
|
|
|
|
// generate a random number
|
|
|
|
auto x = random() & mask;
|
|
|
|
|
|
|
|
// if we have all zeros, then we have an invalid case and we
|
2015-11-18 09:23:27 +08:00
|
|
|
// need to generate again, we have this every (1/2)^N times
|
|
|
|
// so therefore we could say it's very unlikely to happen for
|
|
|
|
// large N. e.g. N = 32; p = 2.328 * 10^-10
|
2015-11-17 06:53:45 +08:00
|
|
|
if(UNLIKELY(!x))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// ctzl = count trailing zeros from long
|
|
|
|
// ^ ^ ^ ^
|
|
|
|
return __builtin_ctzl(x) + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
R random;
|
|
|
|
};
|