Commit | Line | Data |
---|---|---|
81923e5c BA |
1 | // ISAAC PRNG |
2 | // Initial code by Bob Jenkins, March 1996 - modified in 2008 | |
3 | // Reference: http://burtleburtle.net/bob/rand/isaacafa.html | |
4 | // Further slightly modified by Benjamin Auder, 2013 | |
5 | ||
6 | #include "Util/rng.h" | |
7 | #include <stdlib.h> | |
8 | #include <time.h> | |
9 | ||
10 | // Internal state | |
11 | static uint32_t mm[256]; | |
12 | static uint32_t aa, bb, cc; | |
13 | ||
14 | // initialize the (pseudo-)random generator | |
15 | void init_rng(int flag) | |
16 | { | |
17 | // 'bootstrap' isaac with basic bad PRNG | |
18 | srand(time(NULL)); | |
19 | ||
20 | aa = rand() & 0xffffffff; | |
21 | bb = rand() & 0xffffffff; | |
22 | cc = rand() & 0xffffffff; | |
23 | ||
24 | uint32_t a, b, c, d, e, f, g, h, i; | |
25 | // The golden ratio: | |
26 | a = b = c = d = e = f = g = h = 0x9e3779b9; | |
27 | // Scramble it | |
28 | for (i = 0; i < 4; ++i) | |
29 | mix(a, b, c, d, e, f, g, h); | |
30 | ||
31 | // Fill in mm[] with messy stuff (the seed) | |
32 | uint32_t seedArray[256]; | |
33 | for (i = 0; i < 256; ++i) mm[i] = seedArray[i] = rand() & 0xffffffff; | |
34 | for (i = 0; i < 256; i += 8) | |
35 | { | |
36 | if (flag) | |
37 | { | |
38 | // Use all the information in the seed | |
39 | a += seedArray[i ]; | |
40 | b += seedArray[i + 1]; | |
41 | c += seedArray[i + 2]; | |
42 | d += seedArray[i + 3]; | |
43 | e += seedArray[i + 4]; | |
44 | f += seedArray[i + 5]; | |
45 | g += seedArray[i + 6]; | |
46 | h += seedArray[i + 7]; | |
47 | } | |
48 | mix(a, b, c, d, e, f, g, h); | |
49 | mm[i ] = a; | |
50 | mm[i + 1] = b; | |
51 | mm[i + 2] = c; | |
52 | mm[i + 3] = d; | |
53 | mm[i + 4] = e; | |
54 | mm[i + 5] = f; | |
55 | mm[i + 6] = g; | |
56 | mm[i + 7] = h; | |
57 | } | |
58 | ||
59 | if (flag) | |
60 | { | |
61 | // Do a second pass to make all of the seed affect all of mm | |
62 | for (i = 0; i < 256; i += 8) | |
63 | { | |
64 | a += mm[i ]; | |
65 | b += mm[i + 1]; | |
66 | c += mm[i + 2]; | |
67 | d += mm[i + 3]; | |
68 | e += mm[i + 4]; | |
69 | f += mm[i + 5]; | |
70 | g += mm[i + 6]; | |
71 | h += mm[i + 7]; | |
72 | mix(a, b, c, d, e, f, g, h); | |
73 | mm[i ] = a; | |
74 | mm[i + 1] = b; | |
75 | mm[i + 2] = c; | |
76 | mm[i + 3] = d; | |
77 | mm[i + 4] = e; | |
78 | mm[i + 5] = f; | |
79 | mm[i + 6] = g; | |
80 | mm[i + 7] = h; | |
81 | } | |
82 | } | |
83 | } | |
84 | ||
85 | // return a (pseudo-)random integer | |
86 | uint32_t get_rand_int() | |
87 | { | |
88 | // TODO: register variables ? (x,y,i) | |
89 | uint32_t x, y; | |
90 | static uint32_t i = 0; | |
91 | ||
92 | if (i == 0) | |
93 | { | |
94 | cc = cc + 1; // cc just gets incremented once per 256 results | |
95 | bb = bb + cc; // then combined with bb | |
96 | } | |
97 | ||
98 | x = mm[i]; | |
99 | switch (i % 4) | |
100 | { | |
101 | case 0: | |
102 | aa = aa^(aa << 13); | |
103 | break; | |
104 | case 1: | |
105 | aa = aa^(aa >> 6); | |
106 | break; | |
107 | case 2: | |
108 | aa = aa^(aa << 2); | |
109 | break; | |
110 | case 3: | |
111 | aa = aa^(aa >> 16); | |
112 | break; | |
113 | } | |
114 | ||
115 | // NOTE: bits 2..9 are chosen from x but 10..17 are chosen | |
116 | // from y. The only important thing here is that 2..9 and 10..17 | |
117 | // don't overlap. 2..9 and 10..17 were then chosen for speed in | |
118 | // the optimized version (rand.c) */ | |
119 | // See http://burtleburtle.net/bob/rand/isaac.html | |
120 | // for further explanations and analysis. | |
121 | ||
122 | aa = mm[(i + 128) % 256] + aa; | |
123 | mm[i] = y = mm[(x >> 2) % 256] + aa + bb; | |
124 | bb = mm[(y >> 10) % 256] + x; | |
125 | ||
126 | i = (i + 1) % 256; | |
127 | ||
128 | return bb; | |
129 | } | |
130 | ||
131 | // return a (pseudo-)random real number in [0,1] | |
132 | Real get_rand_real() | |
133 | { | |
134 | return (Real) (INV_RANDMAX * (double) get_rand_int()); | |
135 | } |