ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/include/rng.h
Revision: 1.7
Committed: Tue Apr 26 14:41:36 2011 UTC (13 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.6: +4 -2 lines
Log Message:
*** empty log message ***

File Contents

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