1 module sfmt;
2 
3 import std.stdio;
4 static import sfmt.internal;
5 alias recursion = sfmt.internal.recursion!(18, 1, 11, 1, masks);
6 import sfmt.internal : func1, func2, idxof, ucent_;
7 
8 import std.algorithm : max, min;
9 
10 version (MT19937)
11 {
12     enum SFMT_MEXP = 19937;
13     enum SFMT_N = (SFMT_MEXP >> 7) + 1;
14     enum SFMT_N64 = SFMT_N << 1;
15     enum SFMT_N32 = SFMT_N << 2;
16     enum SFMT_POS1 = 122;
17     enum masks = [0xdfffffefU, 0xddfecb7fU, 0xbffaffffU, 0xbffffff6U];
18     enum parity = [0x00000001U, 0x00000000U, 0x00000000U, 0x13c9e684U];
19     enum id = "SFMT-19937:122-18-1-11-1:dfffffef-ddfecb7f-bffaffff-bffffff6";
20 
21     struct SFMT
22     {
23         enum id = .id;
24         this (uint seed)
25         {
26             this.seed(seed);
27         }
28         this (uint[] seed)
29         {
30             this.seed(seed);
31         }
32         void printState()
33         {
34             import std.stdio;
35             "state:".writeln;
36             foreach (row; state[0..2]~state[$-2..$])
37                 "%(%08x %)".writefln(row.u32);
38         }
39         void fillState(ubyte b)
40         {
41             ucent_ x;
42             x.u32[0] = b;
43             x.u32[0] = x.u32[0] << 8 | x.u32[0];
44             x.u32[0] = x.u32[0] << 16 | x.u32[0];
45             x.u32[1..$] = x.u32[0];
46             state[] = x;
47         }
48         // checked
49         void seed(uint seed)
50         {
51             uint* psfmt32 = &(state[0].u32[0]);
52             psfmt32[idxof!0] = seed;
53             foreach (i; 1..SFMT_N32)
54                 psfmt32[i.idxof] = 1812433253U * (psfmt32[(i - 1).idxof] ^ (psfmt32[(i - 1).idxof] >> 30)) + i;
55             idx = SFMT_N32;
56             assureLongPeriod;
57         }
58         void seed(uint[] seed)
59         {
60             enum size = SFMT_N * 4;
61             static if (size >= 623)
62                 enum lag = 11;
63             else static if (size >= 68)
64                 enum lag = 7;
65             else static if (size >= 39)
66                 enum lag = 5;
67             else
68                 enum lag = 3;
69             enum mid = (size - lag) / 2;
70             fillState(0x8b);
71             immutable count = seed.length.max(SFMT_N32 - 1);
72             uint* psfmt32 = &(state[0].u32[0]);
73             uint r = func1(psfmt32[idxof!0] ^ psfmt32[idxof!mid] ^ psfmt32[idxof!(SFMT_N32 - 1)]);
74             psfmt32[idxof!mid] += r;
75             r += seed.length;
76             psfmt32[idxof!(mid+lag)] += r;
77             psfmt32[idxof!0] = r;
78 
79             size_t i = 1;
80             foreach (j; 0..count.min(seed.length))
81             {
82                 r = func1(
83                         psfmt32[i.idxof]
84                       ^ psfmt32[((i+mid)%SFMT_N32).idxof]
85                       ^ psfmt32[((i+SFMT_N32-1)%SFMT_N32).idxof]);
86                 psfmt32[((i+mid)%SFMT_N32).idxof] += r;
87                 r += seed[j] + i;
88                 psfmt32[((i+mid+lag)%SFMT_N32).idxof] += r;
89                 psfmt32[i.idxof] = r;
90                 i = (i + 1) % SFMT_N32;
91             }
92             foreach (j; count.min(seed.length)..count)
93             {
94                 r = func1(
95                         psfmt32[i.idxof]
96                       ^ psfmt32[((i+mid)%SFMT_N32).idxof]
97                       ^ psfmt32[((i+SFMT_N32-1)%SFMT_N32).idxof]);
98                 psfmt32[((i+mid)%SFMT_N32).idxof] += r;
99                 r += i;
100                 psfmt32[((i+mid+lag)%SFMT_N32).idxof] += r;
101                 psfmt32[i.idxof] = r;
102                 i = (i + 1) % SFMT_N32;
103             }
104             foreach (j; 0..SFMT_N32)
105             {
106                 r = func2(
107                         psfmt32[i.idxof]
108                       + psfmt32[((i+mid)%SFMT_N32).idxof]
109                       + psfmt32[((i+SFMT_N32-1)%SFMT_N32).idxof]);
110                 psfmt32[((i+mid)%SFMT_N32).idxof] ^= r;
111                 r -= i;
112                 psfmt32[((i+mid+lag)%SFMT_N32).idxof] ^= r;
113                 psfmt32[i.idxof] = r;
114                 i = (i + 1) % SFMT_N32;
115             }
116             idx = SFMT_N32;
117             assureLongPeriod;
118         }
119         version (Big32){} else
120         T next(T)()
121             if (is (T == ulong))
122         {
123             ulong* psfmt64 = &(state[0].u64[0]);
124             assert (idx % 2 == 0, "out of alignment");
125             if (SFMT_N32 <= idx)
126                 generateAll;
127             immutable r = psfmt64[idx / 2];
128             idx += 2;
129             return r;
130         }
131         version (Big64){} else
132         T next(T)()
133             if (is (T == uint))
134         {
135             uint* psfmt32 = &(state[0].u32[0]);
136             if (SFMT_N32 <= idx)
137                 generateAll;
138             immutable r = psfmt32[idx];
139             idx += 1;
140             return r;
141         }
142         T next(T)(size_t size)
143             if (is (T == ulong[]) || is (T == uint[]))
144         {
145             return cast(T)fill(cast(ucent_[])(new T(size)));
146         }
147         private auto fill(ucent_[] array)
148         {
149             immutable size = array.length;
150             recursion(
151                 array[0], state[0],
152                 state[0 + SFMT_POS1],
153                 state[SFMT_N - 2], state[SFMT_N - 1]);
154             recursion(
155                 array[1], state[1],
156                 state[1 + SFMT_POS1],
157                 state[SFMT_N - 1], array[0]);
158 
159             foreach (i; 2 .. SFMT_N-SFMT_POS1)
160             {
161                 recursion(
162                     array[i], state[i],
163                     state[i + SFMT_POS1],
164                     array[i - 2], array[i - 1]);
165             }
166             foreach (i; SFMT_N-SFMT_POS1 .. SFMT_N)
167             {
168                 recursion(
169                     array[i], state[i],
170                     array[i + SFMT_POS1 - SFMT_N],
171                     array[i - 2], array[i - 1]);
172             }
173             foreach (i; SFMT_N .. size-SFMT_N)
174             {
175                 recursion(
176                     array[i], array[i - SFMT_N],
177                     array[i + SFMT_POS1 - SFMT_N],
178                     array[i - 2], array[i - 1]);
179             }
180             foreach (j; 0..ptrdiff_t(2*SFMT_N-size).max(0))
181             {
182                 state[j] = array[j + size - SFMT_N];
183             }
184             size_t j = ptrdiff_t(2*SFMT_N-size).max(0);
185             foreach (i; size-SFMT_N..size)
186             {
187                 recursion(
188                     array[i], array[i - SFMT_N],
189                     array[i + SFMT_POS1 - SFMT_N],
190                     array[i - 2], array[i - 1]);
191                 state[j] = array[i];
192                 j += 1;
193             }
194             return array;
195         }
196         private void generateAll()
197         {
198             recursion(
199                 state[0], state[0],
200                 state[0+SFMT_POS1],
201                 state[SFMT_N - 2], state[SFMT_N - 1]);
202             recursion(
203                 state[1], state[1],
204                 state[1+SFMT_POS1],
205                 state[SFMT_N - 1], state[0]);
206             foreach (i; 2..SFMT_N-SFMT_POS1)
207             {
208                 recursion(
209                     state[i], state[i],
210                     state[i+SFMT_POS1],
211                     state[i - 2], state[i - 1]);
212             }
213             foreach (i; SFMT_N-SFMT_POS1..SFMT_N)
214             {
215                 recursion(
216                     state[i], state[i],
217                     state[i+SFMT_POS1-SFMT_N],
218                     state[i - 2], state[i - 1]);
219             }
220             idx = 0;
221         }
222         ucent_[SFMT_N] state;
223         int idx;
224         /// returns true if modification is done
225         bool assureLongPeriod()
226         {
227             uint inner;
228             uint* psfmt32 = &(state[0].u32[0]);
229             foreach (i; 0..4)
230                 inner ^= psfmt32[i.idxof] ^ parity[i];
231             foreach (i; [16, 8, 4, 2, 1])
232                 inner ^= inner >> i;
233             inner ^= 1;
234             if (inner == 1)
235                 return false;
236             foreach (i; 0..4)
237             {
238                 uint working = 1;
239                 foreach (j; 0..32)
240                 {
241                     if (working & parity[i])
242                     {
243                         psfmt32[i.idxof] ^= working;
244                         return true;
245                     }
246                     working <<= 1;
247                 }
248             }
249             assert (false, "unreachable?");
250         }
251     }
252 }
253 else
254 {
255     static assert (false, "Not supported");
256 }
257 
258 version (BigEndian)
259 {
260     pragma (msg, "not tested");
261     version (Only64bit)
262         version = Big64;
263     else version (With32bit)
264         version = Big32;
265     else static assert (false, "Specify Only64bit or With32bit in BigEndian environment");
266 }
267 version (LittleEndian)
268 {
269     pragma (msg, "supported");
270 }
271 
272 version (Only64bit)
273     version (With32bit)
274         static assert (false, "Specify (at most) one of Only64bit or With32bit");
275