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 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
#ifndef _GLOBAL_RNG_H
#define _GLOBAL_RNG_H
#include <limits>
#include "lib/streflop/streflop_cond.h"
#include "System/float3.h"
#if 0
struct LCG16 {
public:
typedef uint16_t res_type;
typedef uint32_t val_type;
LCG16(const val_type _val = def_val, const val_type _seq = def_seq) { seed(_val, _seq); }
LCG16(const LCG16& rng) { *this = rng; }
void seed(const val_type initval, const val_type initseq) {
val = initval;
seq = initseq;
}
res_type next() { return (((val = (val * 214013L + seq)) >> 16) & max_res); }
res_type bnext(const res_type bound) { return (next() % bound); }
val_type state() const { return val; }
public:
static constexpr res_type min_res = 0;
static constexpr res_type max_res = 0x7fff;
static constexpr val_type def_val = 0;
static constexpr val_type def_seq = 2531011L;
private:
val_type val;
val_type seq;
};
#endif
struct PCG32 {
public:
typedef uint32_t res_type;
typedef uint64_t val_type;
PCG32(const val_type _val = def_val, const val_type _seq = def_seq) { seed(_val, _seq); }
PCG32(const PCG32& rng) { *this = rng; }
void seed(const val_type initval, const val_type initseq) {
val = 0u;
seq = (initseq << 1u) | 1u;
next();
val += initval;
next();
}
res_type next() {
const val_type oldval = val;
// advance internal state
val = oldval * 6364136223846793005ull + seq;
// calculate output function (XSH RR), uses old state for max ILP
const res_type xsh = ((oldval >> 18u) ^ oldval) >> 27u;
const res_type rot = oldval >> 59u;
return ((xsh >> rot) | (xsh << ((-rot) & 31)));
}
res_type bnext(const res_type bound) {
const res_type threshold = -bound % bound;
res_type r = 0;
// generate a uniformly distributed number, r, where 0 <= r < bound
for (r = next(); r < threshold; r = next());
return (r % bound);
}
val_type state() const { return val; }
public:
static constexpr res_type min_res = std::numeric_limits<res_type>::min();
static constexpr res_type max_res = std::numeric_limits<res_type>::max();
static constexpr val_type def_val = 0x853c49e6748fea9bULL;
static constexpr val_type def_seq = 0xda3e39cb94b95bdbULL;
private:
val_type val;
val_type seq;
};
template<typename RNG, bool synced> class CGlobalRNG {
public:
typedef typename RNG::val_type rng_val_type;
typedef typename RNG::res_type rng_res_type;
void Seed(rng_val_type seed) { SetSeed(seed); }
void SetSeed(rng_val_type seed, bool init = false) {
// use address of this object as sequence-id for unsynced RNG, modern systems have ASLR
if (init) {
gen.seed(initSeed = seed, static_cast<rng_val_type>(size_t(this)) * (1 - synced) + RNG::def_seq * synced);
} else {
gen.seed(lastSeed = seed, static_cast<rng_val_type>(size_t(this)) * (1 - synced) + RNG::def_seq * synced);
}
}
rng_val_type GetInitSeed() const { return initSeed; }
rng_val_type GetLastSeed() const { return lastSeed; }
rng_val_type GetGenState() const { return (gen.state()); }
// needed for std::{random_}shuffle
rng_res_type operator()( ) { return (gen. next( )); }
rng_res_type operator()(rng_res_type N) { return (gen.bnext(N)); }
static constexpr rng_res_type min() { return RNG::min_res; }
static constexpr rng_res_type max() { return RNG::max_res; }
rng_res_type NextInt(rng_res_type N = max()) { return ((*this)(N)); }
float NextFloat(rng_res_type N = max()) { return ((NextInt(N) * 1.0f) / N); } // [0,1) rounded to multiple of 1/N
float NextFloat32() { return (math::ldexp(NextInt(max()), -32)); } // [0,1) rounded to multiple of 1/(2^32)
float3 NextVector2D() { return (NextVector(0.0f)); }
float3 NextVector(float y = 1.0f) {
float3 ret;
do {
ret.x = (NextFloat() * 2.0f - 1.0f);
ret.y = (NextFloat() * 2.0f - 1.0f) * y;
ret.z = (NextFloat() * 2.0f - 1.0f);
} while (ret.SqLength() > 1.0f);
return ret;
}
private:
RNG gen;
// initial and last-set seed
rng_val_type initSeed = 0;
rng_val_type lastSeed = 0;
};
// synced and unsynced RNG's no longer need to be different types
typedef CGlobalRNG<PCG32, true> CGlobalSyncedRNG;
typedef CGlobalRNG<PCG32, false> CGlobalUnsyncedRNG;
#endif
|