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

# User Rev Content
1 root 1.1 /*
2     * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3     *
4 root 1.6 * Copyright (©) 2010,2011 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.1 *
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 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     typedef lc_rng<3039177861U, 0> borosh_niederreiter_rng;
83     typedef lc_rng<2147001325U, 715136305U> bcpl_rng;
84    
85 root 1.1 template<typename T, int N, int k>
86 root 1.3 struct gfsr_rng
87 root 1.1 {
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 root 1.7 void seed (seed_t seed)
113 root 1.1 {
114 root 1.3 xorshift_rng rng;
115 root 1.1
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 root 1.3 typedef gfsr_rng<uint32_t, 250, 103> r250_rng;
138     typedef gfsr_rng<uint32_t, 521, 168> r521_rng;
139 root 1.1
140     // freeciv uses this one, so it's good enough for us :)
141 root 1.3 typedef gfsr_rng<uint32_t, 55, 24> freeciv_rng;
142 root 1.1
143     // this one should be high quality, but is slightly slower than tausworthe
144 root 1.3 struct r250521_rng
145 root 1.1 {
146 root 1.3 r250_rng r250;
147     r521_rng r521;
148 root 1.1
149     void seed (uint32_t seed);
150     uint32_t next ();
151     };
152    
153 root 1.5 // this is actually an adaptor that provides different
154     // distributions of random numbers.
155 root 1.1 template<class generator>
156     struct random_number_generator : generator
157     {
158 root 1.2 random_number_generator ()
159     {
160     }
161    
162 root 1.7 random_number_generator (seed_t seed)
163 root 1.2 {
164     this->seed (seed);
165     }
166    
167 root 1.1 // 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 root 1.3 uint32_t get_u32 ();
184     uint64_t get_u64 ();
185     float get_float ();
186     double get_double ();
187    
188 root 1.1 // return a number within the half-open interval [0..1[
189 root 1.3 double operator () ()
190 root 1.1 {
191 root 1.3 return get_double ();
192 root 1.1 }
193    
194 root 1.3 uint32_t poisson (double mean);
195 root 1.1
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 root 1.3 typedef random_number_generator<freeciv_rng> rand_gen;
203 root 1.1
204 root 1.2 // used when we often seed
205 root 1.3 typedef random_number_generator<tausworthe_rng> seedable_rand_gen;
206 root 1.2
207 root 1.1 extern rand_gen rndm, rmg_rndm;
208    
209     #endif
210