static_assert( __cplusplus > 2023'00 ); #include "fastRandom.h" #include #include 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 ); } }