The OpenD Programming Language

1 /++
2 $(SCRIPT inhibitQuickIndex = 1;)
3 
4 $(BOOKTABLE $(H2 Generators)
5 
6     $(TR $(TH Generator name) $(TH Description))
7     $(RROW Xorshift1024StarPhi, `xorshift1024*φ`: when something larger than `xoroshiro128+` is needed)
8     $(RROW Xorshift64Star32, `xorshift64*/32`: internal state of 64 bits and output of 32 bits)
9     $(TR $(TD $(LREF Xorshift32) .. $(LREF Xorshift160)) $(TD Basic xorshift generator with `n` bits of state (32, 64, 96, 128, 160)))
10     $(RROW Xorshift192, Generator from Marsaglia's paper combining 160-bit xorshift with a counter)
11     $(RROW Xorshift, An alias to one of the generators in this package))
12 
13 $(BOOKTABLE $(H2 Generic Templates)
14 
15     $(TR $(TH Template name) $(TH Description))
16     $(RROW XorshiftStarEngine, `xorshift*` generator with any word size and any number of bits of state.)
17     $(RROW XorshiftEngine, `xorshift` generator with any word size and any number of bits of state.)
18 )
19 
20 Copyright: Copyright Andrei Alexandrescu 2008 - 2009, Masahiro Nakagawa, Ilya Yaroshenko 2016-.
21 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
22 Authors: Masahiro Nakagawa, Ilya Yaroshenko (rework), Nathan Sashihara
23 
24 Macros:
25     WIKI_D = $(HTTP en.wikipedia.org/wiki/$1_distribution, $1 random variable)
26     WIKI_D2 = $(HTTP en.wikipedia.org/wiki/$1_distribution, $2 random variable)
27     T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
28     RROW = $(TR $(TDNW $(LREF $1)) $(TD $+))
29 +/
30 module mir.random.engine.xorshift;
31 
32 import std.traits;
33 
34 // These generators were moved to mir.random.engine.xoshiro.
35 // Publicly import them so code expecting them to be in this module
36 // continues to work.
37 public import mir.random.engine.xoshiro : Xoshiro256StarStar,
38     Xoshiro128StarStar_32, XoshiroEngine, Xoroshiro128Plus;
39 
40 /+
41 Mixin to initialize an array of ulongs `s` from a single ulong `x0`.
42 If s.length > 1 this will never initialize `s` to all zeroes. If
43 s.length == 1 it is up to the caller to check s[0].
44 
45 Remark from Sebastino Vigna:
46 <blockquote>
47 We suggest to use a SplitMix64 to initialize the state of our generators
48 starting from a 64-bit seed, as research has shown[*] that initialization
49 must be performed with a generator radically different in nature from the
50 one initialized to avoid correlation on similar seeds.
51 </blockquote>
52 [*] https://dl.acm.org/citation.cfm?doid=1276927.1276928
53 +/
54 private enum init_s_from_x0_using_splitmix64 =
55 q{
56     static assert(is(typeof(s[0]) == ulong));
57     static assert(is(typeof(x0) == ulong));
58     //http://xoroshiro.di.unimi.it/splitmix64.c
59     foreach (ref e; s)
60     {
61         ulong z = (x0 += 0x9e3779b97f4a7c15uL);
62         z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9uL;
63         z = (z ^ (z >>> 27)) * 0x94d049bb133111ebuL;
64         e = z ^ (z >>> 31);
65     }
66 };
67 
68 /+
69 Mixin to initialize an array of uints `s` from a single uint `x0`.
70 Ensures no element of `s` is 0.
71 +/
72 private enum init_s_from_x0_using_mt32_nozero =
73 q{
74     static assert(is(typeof(s[0]) == uint));
75     static assert(is(typeof(x0) == uint));
76     // Initialization routine from MersenneTwisterEngine.
77     foreach (uint i, ref e; s)
78     {
79         e = (x0 = 1812433253U * (x0 ^ (x0 >> 30)) + i + 1);
80         if (e == 0)
81             e = (i + 1);
82     }
83 };
84 
85 /++
86 Xorshift generator.
87 Implemented according to $(HTTP www.jstatsoft.org/v08/i14/paper, Xorshift RNGs)
88 (Marsaglia, 2003) with Sebastino Vigna's optimization for large arrays.
89 
90 Period is `2 ^^ bits - 1` except for a legacy 192-bit uint version (see
91 note below).
92 
93 Params:
94     UIntType = Word size of this xorshift generator and the return type
95                of `opCall`.
96     bits = The number of bits of state of this generator. This must be
97            a positive multiple of the size in bits of UIntType. If
98            bits is large this struct may occupy slightly more memory
99            than this so it can use a circular counter instead of
100            shifting the entire array.
101     sa = The direction and magnitude of the 1st shift. Positive
102          means left, negative means right.
103     sb = The direction and magnitude of the 2nd shift. Positive
104          means left, negative means right.
105     sc = The direction and magnitude of the 3rd shift. Positive
106          means left, negative means right.
107 
108 Note:
109 For historical compatibility when `bits == 192` and `UIntType` is `uint`
110 a legacy hybrid PRNG is used consisting of a 160-bit xorshift combined
111 with a 32-bit counter. This combined generator has period equal to the
112 least common multiple of `2 ^^ 160 - 1` and `2 ^^ 32`.
113 +/
114 struct XorshiftEngine(UIntType, uint bits, int sa, int sb, int sc)
115 if (isUnsigned!UIntType)
116 {
117     static assert(bits > 0 && bits % (UIntType.sizeof * 8) == 0,
118         "bits must be an even multiple of "~UIntType.stringof
119         ~".sizeof * 8, not "~bits.stringof~".");
120 
121     static assert(!((sa >= 0) == (sb >= 0) && (sa >= 0) >= (sc >= 0))
122         && (sa * sb * sc != 0),
123         "shifts cannot be zero and cannot all be in same direction: cannot be ["
124         ~sa.stringof~", "~sb.stringof~", "~sc.stringof~"].");
125 
126     static assert(sa != sb && sb != sc,
127         "consecutive shifts with the same magnitude and direction would cancel!");
128 
129     // Shift magnitudes.
130     private enum a = (sa < 0 ? -sa : sa);
131     private enum b = (sb < 0 ? -sb : sb);
132     private enum c = (sc < 0 ? -sc : sc);
133 
134     // Shift expressions to mix in.
135     private enum shiftA(string expr) = `((`~expr~`) `~(sa > 0 ? `<< a)` : ` >>> a)`);
136     private enum shiftB(string expr) = `((`~expr~`) `~(sb > 0 ? `<< b)` : ` >>> b)`);
137     private enum shiftC(string expr) = `((`~expr~`) `~(sc > 0 ? `<< c)` : ` >>> c)`);
138 
139     /// Marker for `mir.random.isRandomEngine`
140     enum isRandomEngine = true;
141     /// Largest generated value.
142     enum UIntType max = UIntType.max;
143 
144     /*
145      * Marker indicating it's safe to construct from void
146      * (i.e. the constructor doesn't depend on the struct
147      * being in an initially valid state).
148      * Non-public because we don't want to commit to this
149      * design.
150      */
151     package enum bool _isVoidInitOkay = true;
152 
153     private
154     {
155         enum uint N = bits / (UIntType.sizeof * 8);
156         // Ugly legacy 192 bit uint hybrid counter/xorshift.
157         // Retained for backwards compatibility for now.
158         enum bool isLegacy192Bit = UIntType.sizeof == uint.sizeof && bits == 192;
159         enum bool usePointer = N > 3 && !isLegacy192Bit;
160         static if (usePointer)
161             uint p;
162         else
163             enum uint p = N - 1;
164         enum uint initialP = UIntType.sizeof <= uint.sizeof ? N - 1 : 0;
165         static if (isLegacy192Bit)
166             UIntType value_;
167         static if (N == 1)
168             union {
169                 UIntType s0_;
170                 UIntType[N] s;
171             }
172         else
173             UIntType[N] s = void;
174     }
175 
176     @disable this();
177     @disable this(this);
178 
179     /**
180      * Constructs a $(D XorshiftEngine) generator seeded with $(D_PARAM x0).
181      */
182     static if (UIntType.sizeof > uint.sizeof)
183     this()(UIntType x0) @nogc nothrow pure @safe
184     if (UIntType.sizeof > uint.sizeof) // Repeat condition so it appears in DDoc.
185     {
186         static if (usePointer)
187             p = initialP;
188         static if (UIntType.sizeof == ulong.sizeof)
189         {
190             //Seed using splitmix64 as recommended by Vigna.
191             mixin(init_s_from_x0_using_splitmix64);
192         }
193         else
194         {
195             //Seed using PCG variant with k bits of state and k bits of output.
196             import mir.random.engine.pcg : PermutedCongruentialEngine, rxs_m_xs_forward, stream_t;
197             alias RndElementType = Unsigned!(Unqual!UIntType);
198             alias RndEngine = PermutedCongruentialEngine!(rxs_m_xs_forward!(RndElementType,RndElementType),stream_t.oneseq,true);
199             static assert(is(ReturnType!((ref RndEngine a) => a()) == RndElementType));
200 
201             auto rnd = RndEngine(cast(RndElementType) x0);
202             foreach (ref e; s)
203             {
204                 e = cast(UIntType) rnd();
205             }
206         }
207         //If N > 1 the internal state cannot be all zeroes by construction.
208         //If N == 1 we need to check.
209         static if (N == 1)
210         {
211             if (s[0] == 0)
212                 s[0] = cast(Unqual!UIntType) 3935559000370003845UL;
213         }
214     }
215     /// ditto
216     static if (UIntType.sizeof <= uint.sizeof)
217     this()(uint x0) @nogc nothrow pure @safe
218     if (UIntType.sizeof <= uint.sizeof) // Repeat condition so it appears in DDoc.
219     {
220         static if (usePointer)
221             p = initialP;
222         mixin(init_s_from_x0_using_mt32_nozero);
223         opCall();
224     }
225 
226     /// Advances the random sequence.
227     UIntType opCall() @nogc nothrow pure @safe
228     {
229         static if (isLegacy192Bit)
230         {
231             import mir.internal.utility: Iota;
232             auto x = s[0] ^ mixin(shiftA!`s[0]`);
233             foreach (i; Iota!(N - 1))
234                 s[i] = s[i + 1];
235             s[N-2] = s[N-2] ^ mixin(shiftC!`s[N-2]`) ^ x ^ mixin(shiftB!`x`);
236             value_ = s[N-2] + (s[N-1] += 362437);
237             return value_;
238         }
239         else static if (N == 1)
240         {
241             s0_ ^= mixin(shiftA!`s0_`);
242             s0_ ^= mixin(shiftB!`s0_`);
243             s0_ ^= mixin(shiftC!`s0_`);
244             return s0_;
245         }
246         else static if (N > 1 && !usePointer)
247         {
248             import mir.internal.utility: Iota;
249             auto x = s[0] ^ mixin(shiftA!`s[0]`);
250             foreach (i; Iota!(N - 1))
251                 s[i] = s[i + 1];
252             s[N-1] = s[N-1] ^ mixin(shiftC!`s[N-1]`) ^ x ^ mixin(shiftB!`x`);
253             return s[N-1];
254         }
255         else
256         {
257             const s_N_minus_1 = s[p];
258             static if ((N & (N - 1)) == 0)
259             {
260                 p = (p + 1) & (N - 1);
261             }
262             else
263             {
264                 if (++p >= N)
265                     p = 0;
266             }
267             auto x = s[p];
268             x ^= mixin(shiftA!`x`);
269             return s[p] = s_N_minus_1 ^ mixin(shiftC!`s_N_minus_1`) ^ x ^ mixin(shiftB!`x`);
270         }
271     }
272 }
273 
274 // Keep this public so code using it still works, but don't include it
275 // in the documentation.
276 template XorshiftEngine(uint bits, uint a, uint b, uint c)
277 {
278     // Assume uint and shift directions so the defaults will work.
279     static if (bits <= 32)
280         alias XorshiftEngine = .XorshiftEngine!(uint, bits, a, -b, c);//left, right, left
281     else static if (bits == 192)
282         alias XorshiftEngine = .XorshiftEngine!(uint, bits, -a, b, c);//right, left, left
283     else
284         alias XorshiftEngine = .XorshiftEngine!(uint, bits, a, -b, -c);//left, right, right
285 }
286 
287 /++
288 Define `XorshiftEngine` generators with well-chosen parameters for 32-bit architectures.
289 `Xorshift` is an alias of one of the generators in this module.
290 +/
291 alias Xorshift32  = XorshiftEngine!(32,  13, 17, 15) ;
292 alias Xorshift64  = XorshiftEngine!(64,  10, 13, 10); /// ditto
293 alias Xorshift96  = XorshiftEngine!(96,  10, 5,  26); /// ditto
294 alias Xorshift128 = XorshiftEngine!(128, 11, 8,  19); /// ditto
295 alias Xorshift160 = XorshiftEngine!(160, 2,  1,  4);  /// ditto
296 alias Xorshift192 = XorshiftEngine!(192, 2,  1,  4);  /// ditto
297 alias Xorshift    = Xorshift128;                      /// ditto
298 
299 ///
300 @safe version(mir_random_test) unittest
301 {
302     import mir.random.engine;
303     auto rnd = Xorshift(cast(uint)unpredictableSeed);
304     auto num = rnd();
305 
306     import std.traits;
307     static assert(is(ReturnType!rnd == uint));
308     static assert(isSaturatedRandomEngine!Xorshift);
309 }
310 
311 
312 /++
313 Template for the $(HTTP vigna.di.unimi.it/ftp/papers/xorshift.pdf,
314 xorshift* family of generators) (Vigna, 2016; draft 2014).
315 
316 <blockquote>
317 xorshift* generators are very fast, high-quality PRNGs (pseudorandom
318 number generators) obtained by scrambling the output of a Marsaglia
319 xorshift generator with a 64-bit invertible multiplier (as suggested by
320 Marsaglia in his paper). They are an excellent choice for all
321 non-cryptographic applications, as they are incredibly fast, have long
322 periods and their output passes strong statistical test suites.
323 </blockquote>
324 
325 Params:
326     StateUInt = Word size of this xorshift generator.
327     nbits = The number of bits of state of this generator. This must be
328             a positive multiple of the size in bits of UIntType. If
329             nbits is large this struct may occupy slightly more memory
330             than this so it can use a circular counter instead of
331             shifting the entire array.
332     sa = The direction and magnitude of the 1st shift. Positive
333               means left, negative means right.
334     sb = The direction and magnitude of the 2nd shift. Positive
335               means left, negative means right.
336     sc = The direction and magnitude of the 3rd shift. Positive
337               means left, negative means right.
338     multiplier = Output of the internal xorshift engine is multiplied
339                  by a constant to eliminate linear artifacts except
340                  in the low-order bits. This constant must be an odd
341                  number other than 1.
342     OutputUInt = Return type of `opCall`. By default same as StateUInt
343                  but can be set to a narrower unsigned type in which
344                  case the high bits of the multiplication result are
345                  returned.
346 
347 Note:
348 If `sa`, `sb`, and `sc` are all positive (which if interpreted
349 as same-direction shifts could not result in a full-period xorshift
350 generator) the shift directions are instead implicitly
351 right-left-right when `bits == UIntType.sizeof * 8` and in all
352 other cases left-right-right. This maintains full compatibility
353 with older versions of `XorshiftStarEngine` that took all shifts as
354 unsigned magnitudes.
355 +/
356 struct XorshiftStarEngine(StateUInt, uint nbits, int sa, int sb, int sc, StateUInt multiplier, OutputUInt = StateUInt)
357 if (isUnsigned!StateUInt && isUnsigned!OutputUInt && OutputUInt.sizeof <= StateUInt.sizeof
358     && !(sa >0 && sb > 0 && sc > 0))
359 {
360     static assert(multiplier != 1 && multiplier % 2 != 0,
361         typeof(this).stringof~": multiplier must be an odd number other than 1!");
362 
363     static assert(OutputUInt.sizeof <= StateUInt.sizeof,
364         typeof(this).stringof~": OutputUInt cannot be larger than StateUInt!");
365 
366     static assert(nbits > 0 && nbits % (StateUInt.sizeof * 8) == 0,
367         "bits must be an even multiple of "~StateUInt.stringof
368         ~".sizeof * 8, not "~nbits.stringof~".");
369 
370     static assert(!((sa >= 0) == (sb >= 0) && (sa >= 0) >= (sc >= 0))
371         && (sa * sb * sc != 0),
372         "shifts cannot be zero and cannot all be in same direction: cannot be ["
373         ~sa.stringof~", "~sb.stringof~", "~sc.stringof~"].");
374 
375     static assert(sa != sb && sb != sc,
376         "consecutive shifts with the same magnitude and direction would cancel!");
377 
378     // Shift magnitudes.
379     private enum a = (sa < 0 ? -sa : sa);
380     private enum b = (sb < 0 ? -sb : sb);
381     private enum c = (sc < 0 ? -sc : sc);
382 
383     // Shift expressions to mix in.
384     private enum shiftA(string expr) = `((`~expr~`) `~(sa > 0 ? `<< a)` : ` >>> a)`);
385     private enum shiftB(string expr) = `((`~expr~`) `~(sb > 0 ? `<< b)` : ` >>> b)`);
386     private enum shiftC(string expr) = `((`~expr~`) `~(sc > 0 ? `<< c)` : ` >>> c)`);
387 
388     /// Marker for `mir.random.isRandomEngine`
389     enum isRandomEngine = true;
390     /// Largest generated value.
391     enum OutputUInt max = OutputUInt.max;
392 
393     /++
394     Note that when StateUInt is the same size as OutputUInt the two lowest bits
395     of this generator are
396     $(LINK2 https://en.wikipedia.org/wiki/Linear-feedback_shift_register,
397     LFSRs), and thus will fail binary rank tests.
398     To provide some context, $(I every) bit of a Mersenne Twister generator
399     (either the 32-bit or 64-bit variant) is an LFSR.
400 
401     The `rand!T` functions in `mir.random` automatically will discard
402     the low bits when generating output smaller than `OutputUInt` due to
403     this generator having `preferHighBits` defined `true`.
404     +/
405     enum bool preferHighBits = true;
406 
407     /*
408      * Marker indicating it's safe to construct from void
409      * (i.e. the constructor doesn't depend on the struct
410      * being in an initially valid state).
411      * Non-public because we don't want to commit to this
412      * design.
413      */
414     package enum bool _isVoidInitOkay = true;
415 
416   private:
417     enum uint N = nbits / (StateUInt.sizeof * 8);
418     enum bool usePointer = N > 3;
419     StateUInt[N] s = void;
420     static if (usePointer)
421         uint p;
422     else
423         enum p = N - 1;
424     enum uint initialP = StateUInt.sizeof <= uint.sizeof ? N - 1 : 0;
425 
426   public:
427 
428     @disable this();
429     @disable this(this);
430 
431     /**
432      * Constructs a $(D XorshiftStarEngine) generator seeded with $(D_PARAM x0).
433      */
434     this()(StateUInt x0) @safe pure nothrow @nogc
435     {
436         static if (N == 1)
437         {
438             s[0] = x0;
439         }
440         else static if (StateUInt.sizeof == ulong.sizeof)
441         {
442             //Seed using splitmix64 as recommended by Vigna.
443             mixin(init_s_from_x0_using_splitmix64);
444         }
445         else
446         {
447             //Seed using PCG variant with k bits of state and k bits of output.
448             import mir.random.engine.pcg : PermutedCongruentialEngine, rxs_m_xs_forward, stream_t;
449             alias RndElementType = Unsigned!(Unqual!StateUInt);
450             alias RndEngine = PermutedCongruentialEngine!(rxs_m_xs_forward!(RndElementType,RndElementType),stream_t.oneseq,true);
451             static assert(is(ReturnType!((ref RndEngine a) => a()) == RndElementType));
452 
453             auto rnd = RndEngine(cast(RndElementType) x0);
454             foreach (ref e; s)
455             {
456                 e = cast(StateUInt) rnd();
457             }
458         }
459         static if (usePointer)
460             p = 0;
461         //If N > 1 the internal state cannot be all zeroes by construction.
462         //If N == 1 we need to check.
463         static if (N == 1)
464         {
465             if (s[0] == 0)
466                 s[0] = cast(Unqual!StateUInt) 3935559000370003845UL;
467         }
468     }
469 
470     /// Advances the random sequence.
471     OutputUInt opCall()() @safe pure nothrow @nogc
472     {
473         static if (N == 1)
474         {
475             auto x = s[0];
476             x ^= mixin(shiftA!`x`);
477             x ^= mixin(shiftB!`x`);
478             x ^= mixin(shiftC!`x`);
479         }
480         else static if (N > 1 && !usePointer)
481         {
482             import mir.internal.utility: Iota;
483             auto x = s[0] ^ mixin(shiftA!`s[0]`);
484             foreach (i; Iota!(N - 1))
485                 s[i] = s[i + 1];
486             x = s[N-1] ^ mixin(shiftC!`s[N-1]`) ^ x ^ mixin(shiftB!`x`);
487         }
488         else
489         {
490             const s_N_minus_1 = s[p];
491             static if ((N & (N - 1)) == 0)
492             {
493                 p = (p + 1) & (N - 1);
494             }
495             else
496             {
497                 if (++p >= N)
498                     p = 0;
499             }
500             auto x = s[p];
501             x ^= mixin(shiftA!`x`);
502             x = s_N_minus_1 ^ mixin(shiftC!`s_N_minus_1`) ^ x ^ mixin(shiftB!`x`);
503         }
504         s[p] = x;
505 
506         static if (StateUInt.sizeof > OutputUInt.sizeof)
507         {
508             enum uint rshift = (StateUInt.sizeof - OutputUInt.sizeof) * 8;
509             return cast(OutputUInt) ((x * multiplier) >>> rshift);
510         }
511         else
512         {
513             return cast(OutputUInt) (x * multiplier);
514         }
515     }
516 
517     static if (nbits == 1024 && N == 16 && sa == 31 && sb == -11 && sc == -30)
518     {
519         /**
520          * This is the jump function for the standard 1024-bit generator.
521          * It is equivalent to $(D 2 ^^ 512) invocations of $(D opCall());
522          * it can be used to generate $(D 2 ^^ 512) non-overlapping
523          * subsequences for parallel computations. This function will only be
524          * defined if the shifts are the same as for $(D Xorshift1024StarPhi).
525          */
526         void jump()() @safe pure nothrow @nogc
527         if (nbits == 1024 && N == 16 && sa == 31 && sb == -11 && sc == -30)
528         {
529             static immutable ulong[16] JUMP = [0x84242f96eca9c41duL,
530                 0xa3c65b8776f96855uL, 0x5b34a39f070b5837uL, 0x4489affce4f31a1euL,
531                 0x2ffeeb0a48316f40uL, 0xdc2d9891fe68c022uL, 0x3659132bb12fea70uL,
532                 0xaac17d8efa43cab8uL, 0xc4cb815590989b13uL, 0x5ee975283d71c93buL,
533                 0x691548c86c1bd540uL, 0x7910c41d10a1e6a5uL, 0x0b5fc64563b3e2a8uL,
534                 0x047f7684e9fc949duL, 0xb99181f2d8f685cauL, 0x284600e3f30e38c3uL];
535             ulong[16] t;
536             foreach (jump; JUMP)
537             {
538                 foreach (uint b; 0 .. 64)
539                 {
540                     if (0 != (jump & (ulong(1) << b)))
541                     {
542                         foreach (j, ref e; t)
543                             e ^= s[(j + p) & 15];
544                     }
545                     opCall();
546                 }
547             }
548             foreach (j, e; t)
549                 s[(j + p) & 15] = cast(StateUInt) e;
550         }
551     }
552 }
553 /// ditto
554 template XorshiftStarEngine(StateUInt, uint nbits, int sa, int sb, int sc, StateUInt multiplier, OutputUInt = StateUInt)
555 if (isUnsigned!StateUInt && isUnsigned!OutputUInt && OutputUInt.sizeof <= StateUInt.sizeof
556     && (sa >0 && sb > 0 && sc > 0))
557 {
558     static if (nbits == StateUInt.sizeof * 8)
559         alias XorshiftStarEngine = .XorshiftStarEngine!(StateUInt, nbits, -sa, sb, -sc, multiplier, OutputUInt);
560     else
561         alias XorshiftStarEngine = .XorshiftStarEngine!(StateUInt, nbits, sa, -sb, -sc, multiplier, OutputUInt);
562 }
563 
564 /++
565 Define $(D XorshiftStarEngine) with well-chosen parameters
566 for large simulations on 64-bit machines.
567 
568 Period of $(D (2 ^^ 1024) - 1), 16-dimensionally equidistributed,
569 and $(HTTP xoroshiro.di.unimi.it/#quality, faster and statistically
570 superior) to $(REF_ALTTEXT Mt19937_64, Mt19937_64, mir, random, engine, mersenne_twister)
571 while occupying significantly less memory. This generator is recommended
572 for random number generation on 64-bit systems except when $(D 1024 + 32)
573 bits of state are excessive.
574 
575 As described by Vigna in the 2014 draft of
576 $(HTTP vigna.di.unimi.it/ftp/papers/xorshift.pdf, his paper published in
577 2016 detailing the xorshift* family), except with a better multiplier recommended by the
578 author as of 2017-10-08.
579 
580 Public domain reference implementation:
581 $(HTTP xoroshiro.di.unimi.it/xorshift1024star.c).
582 +/
583 alias Xorshift1024StarPhi = XorshiftStarEngine!(ulong,1024,31,11,30,0x9e3779b97f4a7c13uL);
584 
585 ///
586 @nogc nothrow pure @safe version(mir_random_test) unittest
587 {
588     import mir.random.engine : EngineReturnType, isSaturatedRandomEngine;
589     auto rnd = Xorshift1024StarPhi(12434UL);
590     auto num = rnd();
591     assert(num != rnd());
592 
593     static assert(is(EngineReturnType!Xorshift1024StarPhi == ulong));
594     static assert(isSaturatedRandomEngine!Xorshift1024StarPhi);
595 
596     //Xorshift1024StarPhi has a jump function that is equivalent
597     //to 2 ^^ 512 invocations of opCall.
598     rnd.jump();
599     num = rnd();
600     assert(num != rnd());
601 }
602 
603 /++
604 Generates 32 bits of output from 64 bits of state. A fast generator
605 with excellent statistical properties for memory-constrained situations
606 where more than 64 bits of state would be too much and generating
607 only 32 bits with each `opCall` will not cause a slowdown. If you need
608 a generator with 64 bits of state that produces output 64 bits at a time
609 $(REF_ALTTEXT SplitMix64, SplitMix64, mir, random, engine, splitmix)
610 is an option.
611 
612 Note that `xorshift64*/32` is slower than `xorshift1024*` even when only
613 32 bits of output are needed at a time.
614 <a href="https://web.archive.org/web/20151209100332/http://xorshift.di.unimi.it:80/">
615 Per Vigna:</a>
616 <blockquote>
617 The three xor/shifts of a `xorshift64*` generator must be executed sequentially,
618 as each one is dependent on the result of the previous one. In a `xorshift1024*`
619 generator two of the xor/shifts are completely independent and can be
620 parallelized internally by the CPU.
621 </blockquote>
622 
623 <a href="https://web.archive.org/web/20151011045529/http://xorshift.di.unimi.it:80/xorshift64star.c">
624 Public domain xorshift64* reference implementation (Internet Archive).</a>
625 +/
626 alias Xorshift64Star32 = XorshiftStarEngine!(ulong,64,12,25,27,2685821657736338717uL,uint);
627 ///
628 @nogc nothrow pure @safe version(mir_random_test) unittest
629 {
630     import mir.random.engine : isSaturatedRandomEngine;
631     static assert(isSaturatedRandomEngine!Xorshift64Star32);
632     Xorshift64Star32 rnd = Xorshift64Star32(123456789);
633     uint x = rnd();
634     assert(x == 3988833114);
635 }
636 
637 // Verify that code rewriting has not changed algorithm results.
638 @nogc nothrow pure @safe version(mir_random_test) unittest
639 {
640     import std.meta: AliasSeq;
641     alias PRNGTypes = AliasSeq!(
642         Xorshift32, Xorshift64, Xorshift128,
643         XorshiftEngine!(ulong, 64, -12, 25, -27),
644         XorshiftEngine!(ulong, 128, 23, -18, -5),
645         XorshiftEngine!(ulong, 1024, 31, -11, -30),
646         Xorshift64Star32, Xorshift1024StarPhi);
647     // Each PRNG has a length 4 array.
648     // The first two items are the first two results after seeding with 123456789.
649     // If the PRNG has a jump function the next two items in the array are the
650     // results after the jump. Otherwise they are 0.
651     immutable ulong[4][PRNGTypes.length] expected = [
652         // xorshift 32, 64, 128 with uint words
653         [2731401742UL, 136850760UL, 0, 0],
654         [2549865778UL, 1115114167UL, 0, 0],
655         [894632230UL, 3350973606UL, 0, 0],
656         // xorshift 64, 128, 1024 with ulong words
657         [2224398112249372979UL, 5942945680377883074UL, 0, 0],
658         [4028400848060651388UL, 13895196393457319541UL, 0, 0],
659         [4907124740424754446UL, 15368750743520076923UL, 0, 0],
660         // xorshift*64/32
661         [3988833114UL, 2123560186UL, 0, 0],
662         // xorshift1024*
663         [13627154139265517578UL, 4343624370592319777UL, 12213380293688671629UL, 12219340912072210038UL],
664     ];
665     foreach (i, PRNGType; PRNGTypes)
666     {
667         auto rnd = PRNGType(123456789);
668         assert(rnd() == expected[i][0]);
669         assert(rnd() == expected[i][1]);
670         // Test jump functions.
671         static if (is(typeof(rnd.jump())))
672         {
673             rnd.jump();
674             assert(rnd() == expected[i][2]);
675             assert(rnd() == expected[i][3]);
676         }
677         else
678         {
679             static assert(expected[i][2] == 0 && expected[i][3] == 0);
680         }
681     }
682 }