TrueSync-Math/TrueSync-Math/Math/TSRandom.cs

280 lines
8.4 KiB
C#

using System;
namespace TrueSync {
/**
* @brief Generates random numbers based on a deterministic approach.
**/
public class TSRandom {
// From http://www.codeproject.com/Articles/164087/Random-Number-Generation
// Class TSRandom generates random numbers
// from a uniform distribution using the Mersenne
// Twister algorithm.
private const int N = 624;
private const int M = 397;
private const uint MATRIX_A = 0x9908b0dfU;
private const uint UPPER_MASK = 0x80000000U;
private const uint LOWER_MASK = 0x7fffffffU;
private const int MAX_RAND_INT = 0x7fffffff;
private uint[] mag01 = { 0x0U, MATRIX_A };
private uint[] mt = new uint[N];
private int mti = N + 1;
/**
* @brief Static instance of {@link TSRandom} with seed 1.
**/
public static TSRandom instance;
internal static void Init() {
instance = New(1);
}
/**
* @brief Generates a new instance based on a given seed.
**/
public static TSRandom New(int seed) {
TSRandom r = new TSRandom(seed);
return r;
}
private TSRandom() {
init_genrand((uint)DateTime.Now.Millisecond);
}
private TSRandom(int seed) {
init_genrand((uint)seed);
}
private TSRandom(int[] init) {
uint[] initArray = new uint[init.Length];
for (int i = 0; i < init.Length; ++i)
initArray[i] = (uint)init[i];
init_by_array(initArray, (uint)initArray.Length);
}
public static int MaxRandomInt { get { return 0x7fffffff; } }
/**
* @brief Returns a random integer.
**/
public int Next() {
return genrand_int31();
}
/**
* @brief Returns a random integer.
**/
public static int CallNext() {
return instance.Next();
}
/**
* @brief Returns a integer between a min value [inclusive] and a max value [exclusive].
**/
public int Next(int minValue, int maxValue) {
if (minValue > maxValue) {
int tmp = maxValue;
maxValue = minValue;
minValue = tmp;
}
int range = maxValue - minValue;
return minValue + Next() % range;
}
/**
* @brief Returns a {@link FP} between a min value [inclusive] and a max value [inclusive].
**/
public FP Next(float minValue, float maxValue) {
int minValueInt = (int)(minValue * 1000), maxValueInt = (int)(maxValue * 1000);
if (minValueInt > maxValueInt) {
int tmp = maxValueInt;
maxValueInt = minValueInt;
minValueInt = tmp;
}
return (FP.Floor((maxValueInt - minValueInt + 1) * NextFP() +
minValueInt)) / 1000;
}
/**
* @brief Returns a integer between a min value [inclusive] and a max value [exclusive].
**/
public static int Range(int minValue, int maxValue) {
return instance.Next(minValue, maxValue);
}
/**
* @brief Returns a {@link FP} between a min value [inclusive] and a max value [inclusive].
**/
public static FP Range(float minValue, float maxValue) {
return instance.Next(minValue, maxValue);
}
/**
* @brief Returns a {@link FP} between 0.0 [inclusive] and 1.0 [inclusive].
**/
public FP NextFP() {
return ((FP) Next()) / (MaxRandomInt);
}
/**
* @brief Returns a {@link FP} between 0.0 [inclusive] and 1.0 [inclusive].
**/
public static FP value {
get {
return instance.NextFP();
}
}
/**
* @brief Returns a random {@link TSVector} representing a point inside a sphere with radius 1.
**/
public static TSVector insideUnitSphere {
get {
return new TSVector(value, value, value);
}
}
private float NextFloat() {
return (float)genrand_real2();
}
private float NextFloat(bool includeOne) {
if (includeOne) {
return (float)genrand_real1();
}
return (float)genrand_real2();
}
private float NextFloatPositive() {
return (float)genrand_real3();
}
private double NextDouble() {
return genrand_real2();
}
private double NextDouble(bool includeOne) {
if (includeOne) {
return genrand_real1();
}
return genrand_real2();
}
private double NextDoublePositive() {
return genrand_real3();
}
private double Next53BitRes() {
return genrand_res53();
}
public void Initialize() {
init_genrand((uint)DateTime.Now.Millisecond);
}
public void Initialize(int seed) {
init_genrand((uint)seed);
}
public void Initialize(int[] init) {
uint[] initArray = new uint[init.Length];
for (int i = 0; i < init.Length; ++i)
initArray[i] = (uint)init[i];
init_by_array(initArray, (uint)initArray.Length);
}
private void init_genrand(uint s) {
mt[0] = s & 0xffffffffU;
for (mti = 1; mti < N; mti++) {
mt[mti] = (uint)(1812433253U * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
mt[mti] &= 0xffffffffU;
}
}
private void init_by_array(uint[] init_key, uint key_length) {
int i, j, k;
init_genrand(19650218U);
i = 1;
j = 0;
k = (int)(N > key_length ? N : key_length);
for (; k > 0; k--) {
mt[i] = (uint)((uint)(mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525U)) + init_key[j] + j);
mt[i] &= 0xffffffffU;
i++;
j++;
if (i >= N) {
mt[0] = mt[N - 1];
i = 1;
}
if (j >= key_length)
j = 0;
}
for (k = N - 1; k > 0; k--) {
mt[i] = (uint)((uint)(mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) *
1566083941U)) - i);
mt[i] &= 0xffffffffU;
i++;
if (i >= N) {
mt[0] = mt[N - 1];
i = 1;
}
}
mt[0] = 0x80000000U;
}
uint genrand_int32() {
uint y;
if (mti >= N) {
int kk;
if (mti == N + 1)
init_genrand(5489U);
for (kk = 0; kk < N - M; kk++) {
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1U];
}
for (; kk < N - 1; kk++) {
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1U];
}
y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1U];
mti = 0;
}
y = mt[mti++];
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680U;
y ^= (y << 15) & 0xefc60000U;
y ^= (y >> 18);
return y;
}
private int genrand_int31() {
return (int)(genrand_int32() >> 1);
}
FP genrand_FP() {
return (FP)genrand_int32() * (FP.One / (FP)4294967295);
}
double genrand_real1() {
return genrand_int32() * (1.0 / 4294967295.0);
}
double genrand_real2() {
return genrand_int32() * (1.0 / 4294967296.0);
}
double genrand_real3() {
return (((double)genrand_int32()) + 0.5) * (1.0 / 4294967296.0);
}
double genrand_res53() {
uint a = genrand_int32() >> 5, b = genrand_int32() >> 6;
return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
}
}
}