280 lines
8.4 KiB
C#
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);
|
|
}
|
|
}
|
|
|
|
} |