Pioneer
Loading...
Searching...
No Matches
Random.h
Go to the documentation of this file.
1// Copyright © 2008-2024 Pioneer Developers. See AUTHORS.txt for details
2// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
3
4// A deterministic random number generator for use by the rest of the
5// engine. It *should* give the same output for a given input regardless
6// of the processor architecture. If it doesn't then it needs to be fixed!
7
8// Based on: http://www.javamex.com/tutorials/random_numbers/xorshift.shtml
9
10#ifndef RAND_H
11#define RAND_H
12
13#include <assert.h>
14#include <cmath>
15#include <cstdint>
16#include <initializer_list>
17
18#include "RefCounted.h"
19#include "fixed.h"
20
21extern "C" {
22#include "jenkins/lookup3.h"
23}
24
25#define PCG_LITTLE_ENDIAN 1
26#include "pcg-cpp/pcg_random.hpp"
27
28// A deterministic random number generator
29class Random : public RefCounted {
30 pcg32 mPCG;
31
32 // For storing second rand from Normal
33 bool cached;
34 double z1;
35
36public:
37 //
38 // Constructors
39 //
40
41 // Construct a new random generator using the given seed
42 Random(const Uint32 initialSeed = 0xabcd1234)
43 {
44 seed(initialSeed);
45 }
46
47 // Construct a new generator given an array of 32-bit seeds.
48 Random(const Uint32 *const seeds, size_t length)
49 {
50 seed(seeds, length);
51 }
52
53 // Construct a new random generator from an array of 64-bit
54 // seeds.
55 Random(const Uint64 *const seeds, size_t length)
56 {
57 seed(reinterpret_cast<const Uint32 *>(seeds), length * 2);
58 }
59
60 // Construct a new generator given an array of 32-bit seeds.
61 Random(std::initializer_list<uint32_t> seeds)
62 {
63 seed(seeds);
64 }
65
66 //
67 // Seed functions
68 //
69
70 // Seed the RNG using the hash of the given array of seeds.
71 void seed(const Uint32 *const seeds, size_t length)
72 {
73 const Uint32 hash = lookup3_hashword(seeds, length, 0);
74 mPCG.seed(hash);
75 cached = false;
76 }
77
78 // Seed using an array of 64-bit integers
79 void seed(const Uint64 *const seeds, size_t length)
80 {
81 seed(reinterpret_cast<const Uint32 *>(seeds), length * 2);
82 }
83
84 // Seed using an initializer_list of 32-bit integers
85 void seed(std::initializer_list<uint32_t> list) {
86 seed(&*list.begin(), list.size());
87 }
88
89 // Seed using a single 32-bit integer
90 void seed(const Uint32 value)
91 {
92 seed(&value, 1);
93 }
94
95 //
96 // Number generators.
97 //
98 // Starting from a given seed value the generator will return the
99 // same sequence of numbers. Unless otherwise stated the numbers
100 // are 32-bit and each call consumes one
101 //
102
103 // Get the next integer from the sequence
104 // interval [0, 2**32)
105 inline Uint32 Int32()
106 {
107 return mPCG();
108 }
109
110 // Pick an integer like you're rolling a "choices" sided die,
111 // a 6 sided die would return a number between 0 and 5.
112 // interval [0, choices)
113 inline Uint32 Int32(const int choices)
114 {
115 return Int32() % choices;
116 }
117
118 // Pick a number between min and max, inclusive.
119 // interval [min, max]
120 inline int Int32(const int min, const int max)
121 {
122 return (Int32() % (1 + max - min)) + min;
123 }
124
125 // Pick a number in the half open interval [0, 1)
126 inline double Double()
127 {
128 return double(Int32()) * (1. / 4294967296.); // divided by 2^32
129 }
130
131 // Pick a number in the closed interval [0, 1]
132 inline double Double_closed()
133 {
134 return double(Int32()) * (1. / 4294967295.); // divided by 2^32 - 1
135 }
136
137 // Pick a number in the open interval (0, 1)
138 inline double Double_open()
139 {
140 return (double(Int32()) + .5) * (1. / 4294967296.); // divided by 2^32
141 }
142
143 // Pick a 53-bit resolution double in the half open interval [0, 1)
144 // This method consumes two 32-bit numbers from the sequence.
145 inline double Double53()
146 {
147 return (double(Int32() >> 5) * 67108864. + double(Int32() >> 6)) * (1. / 9007199254740992.);
148 }
149
150 // Pick a number in the half-open interval [min, limit)
151 inline double Double(double min, double limit)
152 {
153 return Double(limit - min) + min;
154 }
155
156 // Pick a number in the half-open interval [0, limit)
157 inline double Double(double limit)
158 {
159 return limit * Double();
160 }
161
162 // Pick a number between 0 and max inclusive
163 // interval [0, max]
164 inline double Double_closed(double max)
165 {
166 return max * Double_closed();
167 }
168
169 // Pick a number between min and max inclusive
170 // interval [min, max]
171 inline double Double_closed(double min, double max)
172 {
173 return Double_closed(max - min) + min;
174 }
175
176 // interval [0,1)
177 inline double NDouble(int p)
178 {
179 double o = Double(1.0);
180 while (--p > 0)
181 o *= Double(1.0);
182 return o;
183 }
184
185 // Normal distribution with zero mean, and unit variance
186 inline double Normal()
187 {
188 return Normal(0.0, 1.0);
189 }
190
191 // Normal distribution with unit variance
192 inline double Normal(const double mean)
193 {
194 return Normal(mean, 1.0);
195 }
196
197 //Normal (Gauss) distribution
198 inline double Normal(const double mean, const double stddev)
199 {
200 //https://en.wikipedia.org/wiki/Box-Muller_transform#Polar_form
201 double u, v, s, z0;
202
203 if (cached) {
204 z0 = z1;
205 cached = false;
206 } else {
207 do {
208 u = Double_closed(-1, 1);
209 v = Double_closed(-1, 1);
210 s = u * u + v * v;
211 } while (s >= 1.0);
212
213 s = sqrt((-2.0 * log(s)) / s);
214 z0 = u * s;
215 z1 = v * s;
216 cached = true;
217 }
218
219 return mean + z0 * stddev;
220 }
221
222 inline int Poisson(const double lambda)
223 {
224 int k = 0;
225 double p = Double();
226 const double target = exp(-lambda);
227 while (p > target) {
228 k += 1;
229 p *= Double();
230 }
231 return k;
232 }
233
234 // Pick a fixed-point integer half open interval [0,1)
235 inline fixed Fixed()
236 {
237 return fixed(Int32());
238 }
239
240 // interval [0,1)
241 inline fixed NFixed(int p)
242 {
243 fixed o = Fixed();
244 while (--p > 0)
245 o *= Fixed();
246 return o;
247 }
248
249 // Returns an approximation of a normal distribution in the bounded interval
250 // (-1, 1)
252 {
253 // Because addition is fully commutative, the compiler can order these
254 // Fixed() calls in any order it wants without changing the result
255 fixed o = Fixed() + Fixed() + Fixed();
256 return o * fixed(10, 15) - fixed(1, 1);
257 }
258
259 // interval (mean - maxdev, mean + maxdev)
260 // this is an approximation of a gaussian distribution with cross-platform determinism
261 inline fixed NormFixed(fixed mean, fixed maxdev)
262 {
263 return mean + maxdev * NormFixed();
264 }
265
266 const pcg32 &GetPCG() const { return mPCG; }
267
268private:
269 Random(const Random &); // copy constructor not defined
270 void operator=(const Random &); // assignment operator not defined
271};
272
273#endif // RAND_H
Definition: Random.h:29
fixed NormFixed(fixed mean, fixed maxdev)
Definition: Random.h:261
double Double_closed(double min, double max)
Definition: Random.h:171
double Double(double min, double limit)
Definition: Random.h:151
double NDouble(int p)
Definition: Random.h:177
void seed(std::initializer_list< uint32_t > list)
Definition: Random.h:85
int Poisson(const double lambda)
Definition: Random.h:222
double Double_closed()
Definition: Random.h:132
double Double53()
Definition: Random.h:145
fixed Fixed()
Definition: Random.h:235
double Double()
Definition: Random.h:126
Random(std::initializer_list< uint32_t > seeds)
Definition: Random.h:61
double Double_closed(double max)
Definition: Random.h:164
int Int32(const int min, const int max)
Definition: Random.h:120
fixed NormFixed()
Definition: Random.h:251
fixed NFixed(int p)
Definition: Random.h:241
double Normal(const double mean)
Definition: Random.h:192
double Normal()
Definition: Random.h:186
double Double(double limit)
Definition: Random.h:157
double Double_open()
Definition: Random.h:138
Random(const Uint32 initialSeed=0xabcd1234)
Definition: Random.h:42
void seed(const Uint32 value)
Definition: Random.h:90
const pcg32 & GetPCG() const
Definition: Random.h:266
Random(const Uint32 *const seeds, size_t length)
Definition: Random.h:48
Uint32 Int32(const int choices)
Definition: Random.h:113
Random(const Uint64 *const seeds, size_t length)
Definition: Random.h:55
void seed(const Uint64 *const seeds, size_t length)
Definition: Random.h:79
void seed(const Uint32 *const seeds, size_t length)
Definition: Random.h:71
double Normal(const double mean, const double stddev)
Definition: Random.h:198
Uint32 Int32()
Definition: Random.h:105
Definition: RefCounted.h:11
fixedf< 32 > fixed
Definition: fixed.h:242
vector3< T > max(const vector3< T > &lhs, const vector3< T > &rhs)
Definition: vector3.h:312
vector3< T > min(const vector3< T > &lhs, const vector3< T > &rhs)
Definition: vector3.h:320