Last active
November 8, 2024 16:40
-
-
Save ElianFabian/acf0c6712d8c6d1d0b3402185c2eb9b2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
// From the Kotlin standard library | |
public class XorWowRandom | |
{ | |
private int x, y, z, w, v, addend; | |
private XorWowRandom() { } | |
public static XorWowRandom FromSeed(int seed) | |
{ | |
XorWowRandom random = new XorWowRandom(); | |
random.SetSeed(seed); | |
return random; | |
} | |
public static XorWowRandom FromSeed(long seed) | |
{ | |
XorWowRandom random = new XorWowRandom(); | |
random.SetSeed(seed); | |
return random; | |
} | |
private void SetSeed(int seed1, int seed2) | |
{ | |
x = seed1; | |
y = seed2; | |
z = 0; | |
w = 0; | |
v = ~seed1; | |
addend = (seed1 << 10) ^ (seed2 >> 4); | |
if ((x | y | z | w | v) == 0) | |
{ | |
throw new ArgumentException("Initial state must have at least one non-zero element."); | |
} | |
// Some trivial seeds can produce several values with zeroes in upper bits, so we discard the first 64 | |
for (int i = 0; i < 64; i++) | |
{ | |
NextInt(); | |
} | |
} | |
public void SetSeed(int seed) | |
{ | |
SetSeed(seed, seed >> 31); | |
} | |
public void SetSeed(long seed) | |
{ | |
SetSeed((int)seed, (int)(seed >> 31)); | |
} | |
public int NextBits(int bitCount) | |
{ | |
return (int)(((uint)NextInt()) >> (32 - bitCount)) & ((-bitCount) >> 31); | |
} | |
public int NextInt() | |
{ | |
// Equivalent to the xorxow algorithm | |
// From Marsaglia, G. 2003. Xorshift RNGs. J. Statis. Soft. 8, 14, p. 5 | |
int t = x; | |
t ^= (int)((uint)t >> 2); | |
x = y; | |
y = z; | |
z = w; | |
int v0 = v; | |
w = v0; | |
t ^= (t << 1) ^ v0 ^ (v0 << 4); | |
v = t; | |
addend += 362437; | |
return t + addend; | |
} | |
public int NextInt(int until) | |
{ | |
return NextInt(0, until); | |
} | |
public int NextInt(int from, int until) | |
{ | |
if (until <= from) | |
{ | |
throw new ArgumentException(string.Format("Random range is empty: [{0}, {1}).", from, until)); | |
} | |
int n = until - from; | |
if (n > 0 || n == int.MinValue) | |
{ | |
int bitCount; | |
int rnd; | |
if ((n & -n) == n) | |
{ | |
bitCount = (int)Math.Log(n, 2); | |
rnd = NextBits(bitCount); | |
} | |
else | |
{ | |
int value = 0; | |
int bits; | |
do | |
{ | |
bits = (int)((uint)NextInt() >> 1); | |
value = bits % n; | |
} while (bits - value + (n - 1) < 0); | |
rnd = value; | |
} | |
return from + rnd; | |
} | |
else | |
{ | |
while (true) | |
{ | |
int rnd = NextInt(); | |
if (rnd >= from && rnd < until) | |
{ | |
return rnd; | |
} | |
} | |
} | |
} | |
public long NextLong() | |
{ | |
return ((long)NextInt() << 32) + NextInt(); | |
} | |
public long NextLong(long until) | |
{ | |
return NextLong(0, until); | |
} | |
public long NextLong(long from, long until) | |
{ | |
if (until <= from) | |
{ | |
throw new Exception(string.Format("Random range is empty: [{0}, {1}).", from, until)); | |
} | |
long n = until - from; | |
if (n > 0) | |
{ | |
long rnd = 0L; | |
if ((n & -n) == n) | |
{ | |
int nLow = (int)n; | |
int nHigh = (int)(n >> 32); | |
if (nLow != 0) | |
{ | |
int bitCount = (int)Math.Log(nLow, 2); | |
rnd = (long)NextBits(bitCount) & 0xFFFFFFFFL; | |
} | |
else if (nHigh == 1) | |
{ | |
rnd = (long)NextInt() & 0xFFFFFFFFL; | |
} | |
else | |
{ | |
int bitCount = (int)Math.Log(nHigh, 2); | |
rnd = ((long)NextBits(bitCount) << 32) + ((long)NextInt() & 0xFFFFFFFFL); | |
} | |
} | |
else | |
{ | |
long value = 0L; | |
long bits; | |
do | |
{ | |
bits = (long)((ulong)NextLong() >> 1); | |
value = bits % n; | |
} while (bits - value + (n - 1) < 0); | |
rnd = value; | |
} | |
return from + rnd; | |
} | |
else | |
{ | |
while (true) | |
{ | |
long rnd = NextLong(); | |
if (rnd >= from && rnd < until) | |
{ | |
return rnd; | |
} | |
} | |
} | |
} | |
public bool NextBoolean() | |
{ | |
return NextBits(1) != 0; | |
} | |
public double NextDouble() | |
{ | |
long hi26 = NextBits(26); | |
int low27 = NextBits(27); | |
return ((hi26 << 27) + low27) / (double) (1L << 53); | |
} | |
public double NextDouble(double until) | |
{ | |
return NextDouble(0.0, until); | |
} | |
public double NextDouble(double from, double until) | |
{ | |
if (until <= from) | |
{ | |
throw new Exception(string.Format("Random range is empty: [{0}, {1}).", from, until)); | |
} | |
double size = until - from; | |
double r; | |
if (double.IsInfinity(size) && !double.IsInfinity(from) && !double.IsInfinity(until)) | |
{ | |
double r1 = NextDouble() * (until / 2 - from / 2); | |
r = from + r1 + r1; | |
} | |
else | |
{ | |
r = from + NextDouble() * size; | |
} | |
if (r >= until) | |
{ | |
return Math.Floor(until); | |
} | |
else return r; | |
} | |
public float NextFloat() | |
{ | |
return (float)(NextBits(24) / (float) (1 << 24)); | |
} | |
public sbyte[] NextBytes(sbyte[] array, int fromIndex = 0, int toIndex = -1) | |
{ | |
if (toIndex == -1) toIndex = array.Length; | |
if (fromIndex < 0 || toIndex > array.Length) | |
{ | |
throw new ArgumentException(string.Format("fromIndex ({0}) or toIndex ({1}) are out of range: 0..{2}.", fromIndex, toIndex, array.Length)); | |
} | |
if (fromIndex > toIndex) | |
{ | |
throw new ArgumentException(string.Format("fromIndex ({0}) must be less than or equal to toIndex ({1}).", fromIndex, toIndex)); | |
} | |
int steps = (int)Math.Floor((toIndex - fromIndex) / 4.0); | |
int position = fromIndex; | |
for (int i = 0; i < steps; i++) | |
{ | |
int value = NextInt(); | |
array[position] = (sbyte)value; | |
array[position + 1] = (sbyte)(value >> 8); | |
array[position + 2] = (sbyte)(value >> 16); | |
array[position + 3] = (sbyte)(value >> 24); | |
position += 4; | |
} | |
int remainder = toIndex - position; | |
int vr = NextBits(remainder * 8); | |
for (int i = 0; i < remainder; i++) | |
{ | |
array[position + i] = (sbyte)(vr >> (i * 8)); | |
} | |
return array; | |
} | |
public sbyte[] NextBytes(int size) | |
{ | |
return NextBytes(new sbyte[size]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment