1
0
forked from Alepha/Alepha

Add fast random facility.

This is a low-memory-overhead and low-cpu-overhead (per generated
bit) random number generator.  The repeat cycle is around 2**88.
Which means around 2**120 bits are available before a cycle.  Which
means that about 2**102 12-bit samples are available before repeats.

This should be more than sufficient for blob rollover purposes.
If 100 million blobs are split per second (absurdly high), then
that's about 2**27 per second.  If run for 30 years, that's
2**30 seconds.  If run across 128 CPUs, that's 2**7 CPUs.  Thus
2**(27+30+7) total samples are required before loop.  This is
2**64 which is WAAAY less than 2**88.  (And this is overly
conservative, as these generators should be one-per-thread...
so we're really much closer to 2**57, not that it matters.)

For this reason, there's no reseed code.  The cycle length of
mt11213b is significantly longer, however, it has a significantly
larger state.  One goal here is to keep the amount of state for
this generator to a single cache line.  As such, if the cycle
length is later shown to be significantly smaller than 2**48
or so, a reseed code path may need to be added.  (This is on
the assumption that the above described intensive run would
run for more than 1 million seconds, or about two weeks.)
This commit is contained in:
2024-09-05 18:35:39 -04:00
parent 6c165b1603
commit 3bd236b556
3 changed files with 84 additions and 0 deletions

View File

@ -12,6 +12,7 @@ add_library( alepha SHARED
Console.cc Console.cc
ProgramOptions.cc ProgramOptions.cc
string_algorithms.cc string_algorithms.cc
fastRandom.cc
word_wrap.cc word_wrap.cc
Thread.cc Thread.cc
delimited_list.cc delimited_list.cc

63
fastRandom.cc Normal file
View File

@ -0,0 +1,63 @@
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{}() };
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 );
}
}

20
fastRandom.h Normal file
View File

@ -0,0 +1,20 @@
static_assert( __cplusplus > 2023'00 );
#pragma once
#include <Alepha/Alepha.h>
#include <cstdint>
namespace Alepha::Hydrogen ::detail:: fastRandom_m
{
inline namespace exports
{
std::uint32_t fastRandomBits( int numBits );
}
}
namespace Alepha::Hydrogen::inline exports::inline fastRandom_m
{
using namespace detail::fastRandom_m::exports;
}