1 /*******************************************************************************
2 
3         Copyright:
4             Copyright (C) 1997--2004, Makoto Matsumoto, Takuji Nishimura, and
5                 Eric Landry;
6             Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
7             All rights reserved.
8 
9         License:
10             Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
11             See LICENSE_TANGO.txt for details.
12 
13         Version: Jan 2008: Initial release
14 
15         Authors: KeYeR (D interface) keyer@team0xf.com
16 
17 *******************************************************************************/
18 
19 module ocean.math.random.Twister;
20 
21 import core.sys.posix.sys.time : timeval, gettimeofday;
22 
23 /*******************************************************************************
24 
25         Wrapper for the Mersenne twister.
26 
27         The Mersenne twister is a pseudorandom number generator linked to
28         CR developed in 1997 by Makoto Matsumoto and Takuji Nishimura that
29         is based on a matrix linear recurrence over a finite binary field
30         F2. It provides for fast generation of very high quality pseudorandom
31         numbers, having been designed specifically to rectify many of the
32         flaws found in older algorithms.
33 
34         Mersenne Twister has the following desirable properties:
35         ---
36         1. It was designed to have a period of 2^19937 - 1 (the creators
37            of the algorithm proved this property).
38 
39         2. It has a very high order of dimensional equidistribution.
40            This implies that there is negligible serial correlation between
41            successive values in the output sequence.
42 
43         3. It passes numerous tests for statistical randomness, including
44            the stringent Diehard tests.
45 
46         4. It is fast.
47         ---
48 
49 *******************************************************************************/
50 
51 struct Twister
52 {
53         public alias natural  toInt;
54         public alias fraction toReal;
55 
56         private enum : uint                     // Period parameters
57                 {
58                 N          = 624,
59                 M          = 397,
60                 MATRIX_A   = 0x9908b0df,        // constant vector a
61                 UPPER_MASK = 0x80000000,        //  most significant w-r bits
62                 LOWER_MASK = 0x7fffffff,        // least significant r bits
63                 }
64 
65         private uint[N] mt;                     // the array for the state vector
66         private uint mti=mt.length+1;           // mti==mt.length+1 means mt[] is not initialized
67         private uint vLastRand;                 // The most recent random uint returned.
68 
69         /**********************************************************************
70 
71                 A global, shared instance, seeded via startup time
72 
73         **********************************************************************/
74 
75         public static Twister instance;
76 
77         static this ()
78         {
79                 instance.seed;
80         }
81 
82         /**********************************************************************
83 
84                 Creates and seeds a new generator with the current time
85 
86         **********************************************************************/
87 
88         static Twister opCall ()
89         {
90                 Twister rand;
91                 rand.seed;
92                 return rand;
93         }
94 
95         /**********************************************************************
96 
97                 Returns X such that 0 <= X < max
98 
99         **********************************************************************/
100 
101         uint natural (uint max)
102         {
103                 return natural % max;
104         }
105 
106         /**********************************************************************
107 
108                 Returns X such that min <= X < max
109 
110         **********************************************************************/
111 
112         uint natural (uint min, uint max)
113         {
114                 return (natural % (max-min)) + min;
115         }
116 
117         /**********************************************************************
118 
119                 Returns X such that 0 <= X <= uint.max
120 
121         **********************************************************************/
122 
123         uint natural (bool pAddEntropy = false)
124         {
125                 uint y;
126                 static uint[2] mag01 =[0, MATRIX_A];
127 
128                 if (mti >= mt.length) {
129                         int kk;
130 
131                         if (pAddEntropy || mti > mt.length)
132                         {
133                                 seed (5489U, pAddEntropy);
134                         }
135 
136                         for (kk=0;kk<mt.length-M;kk++)
137                         {
138                                 y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
139                                 mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 1U];
140                         }
141                         for (;kk<mt.length-1;kk++) {
142                                 y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
143                                 mt[kk] = mt[kk+(M-mt.length)] ^ (y >> 1) ^ mag01[y & 1U];
144                         }
145                         y = (mt[mt.length-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
146                         mt[mt.length-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 1U];
147 
148                         mti = 0;
149                 }
150 
151                 y = mt[mti++];
152 
153                 y ^= (y >> 11);
154                 y ^= (y << 7)  &  0x9d2c5680U;
155                 y ^= (y << 15) &  0xefc60000U;
156                 y ^= (y >> 18);
157 
158                 vLastRand = y;
159                 return y;
160         }
161 
162         /**********************************************************************
163 
164                 generates a random number on [0,1] interval
165 
166         **********************************************************************/
167 
168         double inclusive ()
169         {
170                 return natural*(1.0/cast(double)uint.max);
171         }
172 
173         /**********************************************************************
174 
175                 generates a random number on (0,1) interval
176 
177         **********************************************************************/
178 
179         double exclusive ()
180         {
181                 return ((cast(double)natural) + 0.5)*(1.0/(cast(double)uint.max+1.0));
182         }
183 
184         /**********************************************************************
185 
186                 generates a random number on [0,1$(RPAREN) interval
187 
188         **********************************************************************/
189 
190         double fraction ()
191         {
192                 return natural*(1.0/(cast(double)uint.max+1.0));
193         }
194 
195         /**********************************************************************
196 
197                 generates a random number on [0,1$(RPAREN) with 53-bit resolution
198 
199         **********************************************************************/
200 
201         double fractionEx ()
202         {
203                 uint a = natural >> 5, b = natural >> 6;
204                 return(a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
205         }
206 
207         /**********************************************************************
208 
209                 Seed the generator with current time
210 
211         **********************************************************************/
212 
213         void seed ()
214         {
215                 ulong s;
216 
217                 timeval tv;
218 
219                 gettimeofday (&tv, null);
220                 s = tv.tv_usec;
221 
222                 return seed (cast(uint) s);
223         }
224 
225         /**********************************************************************
226 
227                 initializes the generator with a seed
228 
229         **********************************************************************/
230 
231         void seed (uint s, bool pAddEntropy = false)
232         {
233                 mt[0]= (s + (pAddEntropy ? vLastRand + cast(uint) (&this) : 0)) & 0xffffffffU;
234                 for (mti=1; mti<mt.length; mti++){
235                         mt[mti] = (1812433253U * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
236                         mt[mti] &= 0xffffffffU;
237                 }
238         }
239 
240         /**********************************************************************
241 
242                 initialize by an array with array-length init_key is
243                 the array for initializing keys
244 
245         **********************************************************************/
246 
247         void init (uint[] init_key, bool pAddEntropy = false)
248         {
249                 int i, j;
250                 size_t k;
251                 i=1;
252                 j=0;
253 
254                 seed (19650218U, pAddEntropy);
255                 for (k = (mt.length > init_key.length ? mt.length : init_key.length); k; k--)   {
256                         mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525U))+ init_key[j] + j;
257                         mt[i] &=  0xffffffffU;
258                         i++;
259                         j++;
260 
261                         if (i >= mt.length){
262                                 mt[0] = mt[mt.length-1];
263                                 i=1;
264                         }
265 
266                         if (j >= init_key.length){
267                                 j=0;
268                         }
269                 }
270 
271                 for (k=mt.length-1; k; k--)     {
272                         mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941U))- i;
273                         mt[i] &=  0xffffffffU;
274                         i++;
275 
276                         if (i>=mt.length){
277                                 mt[0] = mt[mt.length-1];
278                                 i=1;
279                         }
280                 }
281                 mt[0] |=  0x80000000U;
282                 mti=0;
283         }
284 }
285 
286 
287 /******************************************************************************
288 
289 
290 ******************************************************************************/
291 
292 debug (Twister)
293 {
294         import ocean.io.Stdout;
295         import ocean.time.StopWatch;
296 
297         void main()
298         {
299                 auto dbl = Twister();
300                 auto count = 100_000_000;
301                 StopWatch w;
302 
303                 w.start;
304                 double v1;
305                 for (int i=count; --i;)
306                      v1 = dbl.fraction;
307                 Stdout.formatln ("{} fraction, {}/s, {:f10}", count, count/w.stop, v1);
308 
309                 w.start;
310                 for (int i=count; --i;)
311                      v1 = dbl.fractionEx;
312                 Stdout.formatln ("{} fractionEx, {}/s, {:f10}", count, count/w.stop, v1);
313 
314                 for (int i=count; --i;)
315                     {
316                     auto v = dbl.fraction;
317                     if (v <= 0.0 || v >= 1.0)
318                        {
319                        Stdout.formatln ("fraction {:f10}", v);
320                        break;
321                        }
322                     v = dbl.fractionEx;
323                     if (v <= 0.0 || v >= 1.0)
324                        {
325                        Stdout.formatln ("fractionEx {:f10}", v);
326                        break;
327                        }
328                     }
329         }
330 }