File: GlobalRNG.h

package info (click to toggle)
spring 104.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 47,512 kB
  • sloc: cpp: 391,093; ansic: 79,943; python: 12,356; java: 12,201; awk: 5,889; sh: 1,826; xml: 655; makefile: 486; perl: 405; php: 211; objc: 194; sed: 2
file content (156 lines) | stat: -rw-r--r-- 4,221 bytes parent folder | download
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