// Fisher-Yates shuffle, shuffling an array of 32-bit values, use the provided key. public static void Xorshift128plusShuffle32(ref Xorshift128PlusKey key, uint32[] storage) { uint32 i = 0; uint32 nextpos1 = 0, nextpos2 = 0; for (i = (uint32)storage.Length; i > 2; i -= 2) { Xorshift128Plus_bounded_two_by_two(ref key, i, i - 1, ref nextpos1, ref nextpos2); uint32 tmp1 = storage[i - 1]; // Probably in cache uint32 val1 = storage[nextpos1]; storage[i - 1] = val1; storage[nextpos1] = tmp1; uint32 tmp2 = storage[i - 2]; // Probably in cache uint32 val2 = storage[nextpos2]; storage[i - 2] = val2; storage[nextpos2] = tmp2; } if (i > 1) { uint32 nextpos = Xorshift128Plus_bounded(ref key, i); uint32 tmp = storage[i - 1]; // Probably in cache uint32 val = storage[nextpos]; storage[i - 1] = val; storage[nextpos] = tmp; } }
// Returns a new 64-bit random number. public static uint64 Xorshift128Plus(ref Xorshift128PlusKey nextKey) { uint64 s1 = nextKey.s1; uint64 s0 = nextKey.s2; nextKey.s1 = s0; s1 ^= s1 << 23; // a nextKey.s2 = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5); // b, c return(nextKey.s2 + s0); }
private static void Xorshift128Plus_bounded_two_by_two( ref Xorshift128PlusKey key, uint32 bound1, uint32 bound2, ref uint32 bounded1, ref uint32 bounded2 ) { uint64 rand = Xorshift128Plus(ref key); bounded1 = (uint32)((((rand & 0xFFFFFFFF) * bound1)) >> 32); bounded2 = (uint32)(((rand >> 32) * bound2) >> 32); }
// Equivalent to skipping 2^64 xorshift128plus() calls // useful to generate a new key from an existing one (multi-threaded context). public static void XorshiftPlusJump(ref Xorshift128PlusKey key) { uint64 s0 = 0; uint64 s1 = 0; for (uint32 i = 0; i < JumpTable.Length; i++) { for (int b = 0; b < 64; b++) { if ((JumpTable[i] & 1UL) << b != 0) { s0 ^= key.s1; s1 ^= key.s2; } Xorshift128Plus(ref key); } } key.s1 = s0; key.s2 = s1; }
static uint32 Xorshift128Plus_bounded(ref Xorshift128PlusKey key, uint32 bound) { uint64 rand = Xorshift128Plus(ref key); return((uint32)(((rand & (0xFFFFFFFF)) * bound) >> 32)); }