1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
#ifndef _Random_h_
#define _Random_h_
#if defined(_MSC_VER) && defined(int64_t)
#undef int64_t
#endif
#include <array>
#include <random>
#include <ctime>
#include "Export.h"
/** \file
*
* A collection of robust and portable random number generation functions that
* share an underlying random generator and which are guarded with locks for
* thread safety.
*/
/** seeds the underlying random number generator used to drive all random number distributions */
FO_COMMON_API void Seed(unsigned int seed);
/** seeds the underlying random number generator used to drive all random number distributions with
the current clock time */
FO_COMMON_API void ClockSeed();
namespace RandomImpl {
static constexpr uint16_t counter_val =
#if defined(__COUNTER__)
__COUNTER__ % 8;
#else
1;
#endif
// convert time as string like "23:59:59" to an int
inline consteval uint32_t TimeToInt(std::array<char, 9> t) noexcept
{ return ((t[7]-'0') + 10*(t[6]-'0')) + 60*((t[4]-'0') + 10*(t[3]-'0')) + 3600*((t[1]-'0') + 10*(t[0]-'0')); }
// shuffle bits in number
inline consteval uint32_t hash(auto val_in) {
auto val = static_cast<uint32_t>(val_in);
val ^= 0x5A5C3AF5;
// copied from Boost "hash_mix for 32 bit size_t"
constexpr uint32_t m1 = 0x21f0aaad;
constexpr uint32_t m2 = 0x735a2d97;
val ^= val >> 16;
val *= m1;
val ^= val >> 15;
val *= m2;
val ^= val >> 15;
return val;
}
// generate a compile-time PRNG int that is seeded differently for each second of the day.
// \a n indicates which value for the current seed to return.
inline consteval uint32_t CxPRNG(int16_t n = counter_val, std::array<char, 9> seed = std::array<char, 9>{__TIME__}) {
uint32_t retval{TimeToInt(seed)};
for (; n > 0; --n)
retval = hash(retval);
return retval;
}
}
/** returns an int from a uniform distribution of integers in the range [\a min, \a max]; */
FO_COMMON_API int RandInt(int min, int max);
/** compile-time "random" time-seeded int from uniform distribution in the range [\a min, \a max] */
inline consteval int32_t RandIntCx(const int32_t min, const int32_t max,
const int16_t n = RandomImpl::counter_val) noexcept
{
if (min >= max)
return min;
const auto range = static_cast<uint32_t>(max - min);
const auto val_in_range = RandomImpl::CxPRNG(n) % (range + 1);
return min + static_cast<int32_t>(val_in_range);
}
inline consteval int32_t RandIntCx(const int32_t min, const int32_t max, const int16_t n,
const std::array<char, 9> seed = std::array<char, 9>{__TIME__}) noexcept
{
if (min >= max)
return min;
const auto range = static_cast<uint32_t>(max - min);
const auto val_in_range = RandomImpl::CxPRNG(n, seed) % (range + 1);
return min + static_cast<int32_t>(val_in_range);
}
inline consteval bool RandBoolCx(int16_t n = RandomImpl::counter_val) noexcept
{ return RandomImpl::CxPRNG(n) % 2 == 0; }
/** returns a double from a uniform distribution of doubles in the range [0.0, 1.0) */
FO_COMMON_API double RandZeroToOne();
/** compile-time random double from nearly-uniform distribution in the range [0.0, 1.0);
* \a n indicates which value in the distribution to return. */
inline consteval double RandZeroToOneCx(int16_t n = 4) noexcept {
const uint32_t arbitrary_prime = 31397;
const auto val = RandomImpl::CxPRNG(n) % arbitrary_prime;
return static_cast<double>(val) / arbitrary_prime;
}
/** returns a double from a uniform distribution of doubles in the range [\a min, \a max) */
FO_COMMON_API double RandDouble(double min, double max);
/** compile-time random double from nearly-uniform distribution in the range [min, max);
* \a n indicates which value in the distribution to return. */
inline consteval double RandDoubleCx(double min, double max, int16_t n = 5) noexcept {
if (min >= max)
return min;
const auto range = max - min;
return min + RandZeroToOneCx(n)*range;
}
/** returns a double from a Gaussian (normal) distribution of doubles centered around \a mean,
with standard deviation \a sigma */
FO_COMMON_API double RandGaussian(double mean, double sigma);
/** shuffles contents of container */
FO_COMMON_API void RandomShuffle(std::vector<uint8_t>& c);
FO_COMMON_API void RandomShuffle(std::vector<int>& c);
#endif
|