237 lines
4.6 KiB
C++
237 lines
4.6 KiB
C++
#ifndef RANDOMGENERATOR_H
|
|
|
|
#define RANDOMGENERATOR_H
|
|
|
|
|
|
/////////////////////////////////////////////////
|
|
// Random Generators
|
|
// created : AGoTH
|
|
// date : 01/12/01
|
|
/////////////////////////////////////////////////
|
|
#include <cstdlib>
|
|
|
|
//
|
|
template <class R>
|
|
float
|
|
GaussianDistribution(const R& iRG, float iMean, float iDeviation)
|
|
{
|
|
// Generic form of the Box-Muller transformation
|
|
// float x1 = iRG();
|
|
// float x2 = iRG();
|
|
// float y1 = XSqrt( -2.0f * logf(x1) ) * cos( 2 * 3.14f * x2 );
|
|
// float y2 = XSqrt( -2.0f * logf(x1) ) * sin( 2 * 3.14f * x2 );
|
|
// We will use the Polar form for efficiency
|
|
|
|
static int useLast = 0;
|
|
static float y2;
|
|
float y1;
|
|
|
|
if (useLast) {
|
|
y1 = y2;
|
|
useLast = 0;
|
|
} else {
|
|
float x1, x2, w;
|
|
do {
|
|
x1 = 2.0f * iRG() - 1.0f;
|
|
x2 = 2.0f * iRG() - 1.0f;
|
|
w = x1 * x1 + x2 * x2;
|
|
} while ( w >= 1.0f );
|
|
|
|
// I need to /4 otherwise it pass the bounds !
|
|
w = 0.25f * XSqrt( (-2.0f * logf(w) )/w);
|
|
y1 = x1 * w;
|
|
y2 = x2 * w;
|
|
useLast = 1;
|
|
}
|
|
|
|
return (iMean + y1 * iDeviation);
|
|
}
|
|
|
|
//
|
|
class StandardRandomGenerator
|
|
{
|
|
public:
|
|
StandardRandomGenerator()
|
|
{
|
|
}
|
|
|
|
// Initialize the random generator
|
|
// for a given seed, the sequence
|
|
// of generated number will be the same
|
|
void Init(unsigned int iSeed) const
|
|
{
|
|
// sets a random starting point
|
|
srand(iSeed);
|
|
}
|
|
|
|
// Returns an uniformely distribued float
|
|
// value : [0,1)
|
|
float operator ()() const
|
|
{
|
|
return (INVRANDMAX*rand());
|
|
}
|
|
|
|
// returns a random number distribued
|
|
// "gaussianly" with a mean and a deviation
|
|
// value : [iMean-iDeviation,iMean+iDeviation)
|
|
float Gaussian(float iMean, float iDeviation) const
|
|
{
|
|
return GaussianDistribution(*this,iMean,iDeviation);
|
|
}
|
|
|
|
private:
|
|
static const float INVRANDMAX;
|
|
};
|
|
|
|
const float StandardRandomGenerator::INVRANDMAX = 1.0f/RAND_MAX;
|
|
|
|
//
|
|
class QuasiRandomGenerator
|
|
{
|
|
public:
|
|
QuasiRandomGenerator()
|
|
{
|
|
Init();
|
|
}
|
|
|
|
// Returns an uniformely distribued float
|
|
// value : [0,1)
|
|
float operator ()() const
|
|
{
|
|
unsigned int im = m_Index++;
|
|
|
|
// find rightmost zero bit
|
|
int j;
|
|
for (j = 0; j < s_MaxBit; j++, im >>= 1) {
|
|
if ( (im & 1L) == 0 ) break;
|
|
}
|
|
|
|
m_IX ^= s_IV[j + 0]; // integer values
|
|
return (float) ( s_Factor * m_IX );
|
|
|
|
}
|
|
|
|
// returns a random number distribued
|
|
// "gaussianly" with a mean and a deviation
|
|
// value : [iMean-iDeviation,iMean+iDeviation)
|
|
float Gaussian(float iMean, float iDeviation) const
|
|
{
|
|
return GaussianDistribution(*this,iMean,iDeviation);
|
|
}
|
|
|
|
private:
|
|
// Methods
|
|
void Init()
|
|
{
|
|
#define INDEX(k,j) [(k) + (j-1)]
|
|
|
|
int j, k, l, ipp, niv;
|
|
unsigned int i, mval;
|
|
|
|
s_IV = new unsigned int[niv = 1 * s_MaxBit];
|
|
|
|
for (k = 0; k < niv; k++)
|
|
s_IV[k] = 0;
|
|
|
|
for (k = 0; k < 1; k++)
|
|
s_IV[k] = 1;
|
|
|
|
mval = 4;
|
|
ipp = 1;
|
|
|
|
for (k = 1, j = 0; k < niv-1; k += 2)
|
|
{
|
|
s_IV[k] = ipp;
|
|
if (++j == 1)
|
|
{
|
|
mval *= 2;
|
|
ipp += 2;
|
|
j = 0;
|
|
}
|
|
|
|
if ( ipp > (int)mval )
|
|
ipp = 1;
|
|
|
|
s_IV[k+1] = ipp;
|
|
if (++j == 1)
|
|
{
|
|
mval *= 2;
|
|
ipp += 2;
|
|
j = 0;
|
|
}
|
|
else
|
|
{
|
|
ipp += 2;
|
|
if ( ipp > (int)mval )
|
|
ipp = 1;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
for (k = 0; k < 1; k++)
|
|
{
|
|
// normalize the set s_IV values
|
|
for (j = 1; j <= mdeg[k]; j++)
|
|
s_IV INDEX(k,j) *= (1L << (s_MaxBit - j));
|
|
|
|
// calcululate the rest of the s_IV values
|
|
for (j = mdeg[k] + 1; j <= s_MaxBit; j++)
|
|
{
|
|
ipp = ip[k];
|
|
|
|
// calculate Gray code of s_IV
|
|
i = s_IV INDEX(k, j - mdeg[k]);
|
|
i ^= i / (1L << mdeg[k]);
|
|
|
|
for (l = mdeg[k] - 1; l >= 1; l--)
|
|
{
|
|
if ( ipp & 1 )
|
|
i ^= s_IV INDEX(k, j-l);
|
|
ipp /= 2;
|
|
}
|
|
|
|
s_IV INDEX(k,j) = i;
|
|
|
|
}
|
|
}
|
|
|
|
s_Factor = 1.0 / (1L << s_MaxBit);
|
|
}
|
|
// Members
|
|
static const int s_MaxBit;
|
|
static unsigned int* s_IV;
|
|
static double s_Factor;
|
|
static const int ip[];
|
|
static const int mdeg[];
|
|
|
|
mutable unsigned int m_Index;
|
|
mutable unsigned int m_IX;
|
|
};
|
|
const int QuasiRandomGenerator::s_MaxBit = 30;
|
|
unsigned int* QuasiRandomGenerator::s_IV;
|
|
double QuasiRandomGenerator::s_Factor;
|
|
|
|
// the primitive polynomial coefficients for up to degree 8
|
|
const int QuasiRandomGenerator::ip[] = { 0, 1, 1, 2, 1, 4, 2, 4, 7, 11, 13, 14,
|
|
1, 13, 16, 19, 22, 25,
|
|
1, 4, 7, 8, 14, 19, 21, 28, 31, 32, 37, 41, 42,
|
|
50, 55, 56, 59, 62,
|
|
14, 21, 22, 38, 47, 49, 50, 52, 56, 67, 70, 84,
|
|
97, 103, 115, 122 };
|
|
const int QuasiRandomGenerator::mdeg[] = { 1, 2, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5,
|
|
6, 6, 6, 6, 6, 6,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
|
|
};
|
|
|
|
//
|
|
const QuasiRandomGenerator&
|
|
GetQuasiRandomGenerator()
|
|
{
|
|
static QuasiRandomGenerator qrg;
|
|
return qrg;
|
|
}
|
|
|
|
|
|
#endif // RANDOMGENERATOR_H
|