ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/include/rng.h
Revision: 1.16
Committed: Wed Dec 5 21:18:37 2018 UTC (5 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.15: +1 -1 lines
Log Message:
nuke compiler.h

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
5 * Copyright (©) 2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
6 *
7 * Deliantra is free software: you can redistribute it and/or modify it under
8 * the terms of the Affero GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the Affero GNU General Public License
18 * and the GNU General Public License along with this program. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 * The authors can be reached via e-mail to <support@deliantra.net>
22 */
23
24 #ifndef RNG_H__
25 #define RNG_H__
26
27 #include "ecb.h"
28
29 typedef uint32_t seed_t; // overkill
30
31 // P. L'Ecuyer, “Maximally Equidistributed Combined Tausworthe Generators”, Mathematics of Computation, 65, 213 (1996), 203–213.
32 // http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps
33 // http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps
34 struct tausworthe_rng
35 {
36 uint32_t state [4];
37
38 void seed (uint32_t seed);
39 uint32_t next ();
40 };
41
42 // Xorshift RNGs, George Marsaglia
43 // http://www.jstatsoft.org/v08/i14/paper
44 // this one is about 40% faster than the tausworthe one above (i.e. not much),
45 // despite the inlining, and has the issue of only creating 2**32-1 numbers.
46 // see also http://www.iro.umontreal.ca/~lecuyer/myftp/papers/xorshift.pdf
47 struct xorshift_rng
48 {
49 uint32_t x, y;
50
51 void seed (uint32_t seed)
52 {
53 x = seed ? seed : 0xdeadbeef;
54 y = x * 69069U;
55 }
56
57 uint32_t next ()
58 {
59 uint32_t t = x ^ (x << 10);
60 x = y;
61 y = y ^ (y >> 13) ^ t ^ (t >> 10);
62 return y;
63 }
64 };
65
66 template<uint32_t A, uint32_t B>
67 struct lc_rng
68 {
69 uint32_t x;
70
71 void seed (uint32_t seed)
72 {
73 x = seed;
74 }
75
76 uint32_t next ()
77 {
78 x = x * A + B;
79 return x;
80 }
81 };
82
83 typedef lc_rng<3039177861U, 0U> borosh_niederreiter_rng;
84 typedef lc_rng<2147001325U, 715136305U> bcpl_rng;
85 typedef lc_rng< 1664525U, 1U> lavaux_janssens_rng;
86 typedef lc_rng< 1664525U, 1013904223U> numerical_recipes_rng;
87
88 template<typename T, int N, int k>
89 struct gfsr_rng
90 {
91 int i;
92 T x[N];
93
94 // rng must have same bitwidth as T
95 template<typename RNG>
96 void seed_rng (RNG rng)
97 {
98 i = N;
99
100 do
101 x [--i] = rng.next ();
102 while (i > sizeof (T) * 8);
103
104 T m = 1;
105
106 do
107 {
108 x [--i] = (rng.next () | m) & ~(m - 1);
109 m <<= 1;
110 }
111 while (i);
112 }
113
114 // actually should subclass to gfsr32... :)
115 void seed (seed_t seed)
116 {
117 xorshift_rng rng;
118
119 rng.seed (seed);
120 this->seed_rng (rng);
121 }
122
123 T next ()
124 {
125 int j = i + (k - N);
126
127 if (j < 0)
128 j += N;
129
130 T v = (x [i] ^= x [j]);
131
132 i = (i ? i : N) - 1;
133
134 return v;
135 }
136 };
137
138 // these are about 2-3 times faster than tausworthe, non-inlined,
139 // and likely of higher quality.
140 typedef gfsr_rng<uint32_t, 250, 103> r250_rng;
141 typedef gfsr_rng<uint32_t, 521, 168> r521_rng;
142
143 // freeciv uses this one, so it's good enough for us :)
144 // (also known as mitchell moore generator)
145 typedef gfsr_rng<uint32_t, 55, 24> freeciv_rng;
146
147 // this one should be high quality, but is slightly slower than tausworthe
148 struct r250521_rng
149 {
150 r250_rng r250;
151 r521_rng r521;
152
153 void seed (uint32_t seed);
154 uint32_t next ();
155 };
156
157 /////////////////////////////////////////////////////////////////////////////
158
159 // this is actually an adaptor that provides different
160 // distributions of random numbers.
161 template<class generator>
162 struct random_number_generator : generator
163 {
164 random_number_generator ()
165 {
166 }
167
168 random_number_generator (seed_t seed)
169 {
170 this->seed (seed);
171 }
172
173 // uniform distribution, [0 .. num - 1]
174 uint32_t operator ()(uint32_t num)
175 {
176 return !ecb_is_constant (num) ? get_range (num) // non-constant
177 : num & (num - 1) ? (this->next () * (uint64_t)num) >> 32U // constant, non-power-of-two
178 : this->next () & (num - 1); // constant, power-of-two
179 }
180
181 // return a number within the closed interval [min .. max], max can be >, < or == min.
182 int operator () (int r_min, int r_max)
183 {
184 return ecb_is_constant (r_min <= r_max) && r_min <= r_max
185 ? r_min + operator ()(r_max - r_min + 1)
186 : get_range (r_min, r_max);
187 }
188
189 uint32_t get_u32 ();
190 uint64_t get_u64 ();
191 float get_float ();
192 double get_double ();
193
194 // return a number within the half-open interval [0..1[
195 double operator () ()
196 {
197 return get_double ();
198 }
199
200 uint32_t poisson (double mean);
201
202 protected:
203 uint32_t get_range (uint32_t r_max);
204 int get_range (int r_min, int r_max);
205 };
206
207 // the default rng used in the game
208 typedef random_number_generator<freeciv_rng> rand_gen;
209
210 // used when we often seed
211 typedef random_number_generator<tausworthe_rng> seedable_rand_gen;
212
213 extern rand_gen rndm, rmg_rndm;
214
215 #endif
216