ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/include/rng.h
Revision: 1.14
Committed: Sat Nov 17 23:33:18 2018 UTC (5 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.13: +4 -4 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 /*
2     * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 root 1.12 *
4 root 1.13 * Copyright (©) 2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.12 *
6 root 1.1 * 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 root 1.12 *
11 root 1.1 * 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 root 1.12 *
16 root 1.1 * 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 root 1.12 *
20 root 1.1 * 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 root 1.7 typedef uint32_t seed_t; // overkill
29    
30 root 1.1 // 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 root 1.3 struct tausworthe_rng
34 root 1.1 {
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 root 1.3 struct xorshift_rng
47 root 1.1 {
48     uint32_t x, y;
49    
50     void seed (uint32_t seed)
51     {
52 root 1.4 x = seed ? seed : 0xdeadbeef;
53 root 1.1 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 root 1.3 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 root 1.10 typedef lc_rng<3039177861U, 0U> borosh_niederreiter_rng;
83     typedef lc_rng<2147001325U, 715136305U> bcpl_rng;
84     typedef lc_rng< 1664525U, 1U> lavaux_janssens_rng;
85     typedef lc_rng< 1664525U, 1013904223U> numerical_recipes_rng;
86 root 1.3
87 root 1.1 template<typename T, int N, int k>
88 root 1.3 struct gfsr_rng
89 root 1.1 {
90     int i;
91     T x[N];
92    
93     // rng must have same bitwidth as T
94     template<typename RNG>
95     void seed_rng (RNG rng)
96     {
97     i = N;
98    
99     do
100     x [--i] = rng.next ();
101     while (i > sizeof (T) * 8);
102    
103     T m = 1;
104    
105     do
106     {
107     x [--i] = (rng.next () | m) & ~(m - 1);
108     m <<= 1;
109     }
110     while (i);
111     }
112    
113     // actually should subclass to gfsr32... :)
114 root 1.7 void seed (seed_t seed)
115 root 1.1 {
116 root 1.3 xorshift_rng rng;
117 root 1.1
118     rng.seed (seed);
119     this->seed_rng (rng);
120     }
121    
122     T next ()
123     {
124     int j = i + (k - N);
125    
126     if (j < 0)
127     j += N;
128    
129     T v = (x [i] ^= x [j]);
130    
131     i = (i ? i : N) - 1;
132    
133     return v;
134     }
135     };
136    
137     // these are about 2-3 times faster than tausworthe, non-inlined,
138     // and likely of higher quality.
139 root 1.3 typedef gfsr_rng<uint32_t, 250, 103> r250_rng;
140     typedef gfsr_rng<uint32_t, 521, 168> r521_rng;
141 root 1.1
142     // freeciv uses this one, so it's good enough for us :)
143 root 1.11 // (also known as mitchell moore generator)
144 root 1.3 typedef gfsr_rng<uint32_t, 55, 24> freeciv_rng;
145 root 1.1
146     // this one should be high quality, but is slightly slower than tausworthe
147 root 1.3 struct r250521_rng
148 root 1.1 {
149 root 1.3 r250_rng r250;
150     r521_rng r521;
151 root 1.1
152     void seed (uint32_t seed);
153     uint32_t next ();
154     };
155    
156 root 1.8 /////////////////////////////////////////////////////////////////////////////
157    
158 root 1.5 // this is actually an adaptor that provides different
159     // distributions of random numbers.
160 root 1.1 template<class generator>
161     struct random_number_generator : generator
162     {
163 root 1.2 random_number_generator ()
164     {
165     }
166    
167 root 1.7 random_number_generator (seed_t seed)
168 root 1.2 {
169     this->seed (seed);
170     }
171    
172 root 1.1 // uniform distribution, [0 .. num - 1]
173     uint32_t operator ()(uint32_t num)
174     {
175 root 1.14 return !ecb_is_constant (num) ? get_range (num) // non-constant
176     : num & (num - 1) ? (this->next () * (uint64_t)num) >> 32U // constant, non-power-of-two
177     : this->next () & (num - 1); // constant, power-of-two
178 root 1.1 }
179    
180     // return a number within the closed interval [min .. max], max can be >, < or == min.
181     int operator () (int r_min, int r_max)
182     {
183 root 1.14 return ecb_is_constant (r_min <= r_max) && r_min <= r_max
184 root 1.1 ? r_min + operator ()(r_max - r_min + 1)
185     : get_range (r_min, r_max);
186     }
187    
188 root 1.3 uint32_t get_u32 ();
189     uint64_t get_u64 ();
190     float get_float ();
191     double get_double ();
192    
193 root 1.1 // return a number within the half-open interval [0..1[
194 root 1.3 double operator () ()
195 root 1.1 {
196 root 1.3 return get_double ();
197 root 1.1 }
198    
199 root 1.3 uint32_t poisson (double mean);
200 root 1.1
201     protected:
202     uint32_t get_range (uint32_t r_max);
203     int get_range (int r_min, int r_max);
204     };
205    
206     // the default rng used in the game
207 root 1.3 typedef random_number_generator<freeciv_rng> rand_gen;
208 root 1.1
209 root 1.2 // used when we often seed
210 root 1.3 typedef random_number_generator<tausworthe_rng> seedable_rand_gen;
211 root 1.2
212 root 1.1 extern rand_gen rndm, rmg_rndm;
213    
214     #endif
215