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 }