Skip to content

Instantly share code, notes, and snippets.

@ElianFabian
Last active November 8, 2024 16:40
Show Gist options
  • Save ElianFabian/acf0c6712d8c6d1d0b3402185c2eb9b2 to your computer and use it in GitHub Desktop.
Save ElianFabian/acf0c6712d8c6d1d0b3402185c2eb9b2 to your computer and use it in GitHub Desktop.
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