forked from Alepha/Alepha
72 lines
1.4 KiB
C++
72 lines
1.4 KiB
C++
static_assert( __cplusplus > 2023'00 );
|
|
|
|
#include "fastRandom.h"
|
|
|
|
#include <random>
|
|
|
|
#include <boost/random/taus88.hpp>
|
|
|
|
namespace Alepha::Hydrogen ::detail:: fastRandom_m
|
|
{
|
|
namespace
|
|
{
|
|
struct FastRandomState
|
|
{
|
|
boost::random::taus88 fastRandomState{ std::random_device{}() };
|
|
/* The choice of Taus88 is deliberate. The more familiar Mt19937
|
|
is only slightly slower and its cousin Mt11213b is effectively
|
|
no slower, but they require 100x to 200x as many integers to
|
|
maintain state. Thus with even only one random variable, the
|
|
latter two will exceed cache line size and create cache load,
|
|
but with several/many the cache pressure will be significant and
|
|
affect performance not just for this code but for the system.
|
|
*/
|
|
std::uint32_t pool;
|
|
int remainingBits= 0;
|
|
|
|
void
|
|
next()
|
|
{
|
|
pool= fastRandomState();
|
|
remainingBits= 32;
|
|
}
|
|
|
|
void
|
|
refresh()
|
|
{
|
|
if( remainingBits == 0 ) next();
|
|
}
|
|
|
|
std::uint32_t
|
|
getBit()
|
|
{
|
|
refresh();
|
|
const std::uint32_t rv= pool & 1;
|
|
--remainingBits;
|
|
pool>>= 1;
|
|
return rv;
|
|
}
|
|
|
|
std::uint32_t
|
|
get( int count )
|
|
{
|
|
std::uint32_t rv= 0;
|
|
while( count-- )
|
|
{
|
|
rv<<= 1;
|
|
rv|= getBit();
|
|
}
|
|
return rv;
|
|
}
|
|
};
|
|
|
|
thread_local FastRandomState fastRandom;
|
|
}
|
|
|
|
std::uint32_t
|
|
exports::fastRandomBits( const int numBits )
|
|
{
|
|
return fastRandom.get( numBits );
|
|
}
|
|
}
|