165 lines
4.7 KiB
C++
165 lines
4.7 KiB
C++
/**
|
|
\file G3D/Random.h
|
|
|
|
\maintainer Morgan McGuire, http://graphics.cs.williams.edu
|
|
|
|
\created 2009-01-02
|
|
\edited 2012-07-20
|
|
|
|
Copyright 2000-2012, Morgan McGuire.
|
|
All rights reserved.
|
|
*/
|
|
#ifndef G3D_Random_h
|
|
#define G3D_Random_h
|
|
|
|
#include "G3D/platform.h"
|
|
#include "G3D/g3dmath.h"
|
|
#include "G3D/GMutex.h"
|
|
|
|
namespace G3D {
|
|
|
|
/** Random number generator.
|
|
|
|
Threadsafe.
|
|
|
|
Useful for generating consistent random numbers across platforms
|
|
and when multiple threads are involved.
|
|
|
|
Uses the Fast Mersenne Twister (FMT-19937) algorithm.
|
|
|
|
On average, uniform() runs about 2x-3x faster than rand().
|
|
|
|
@cite http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html
|
|
|
|
On OS X, Random is about 10x faster than drand48() (which is
|
|
threadsafe) and 4x faster than rand() (which is not threadsafe).
|
|
|
|
\sa Noise
|
|
*/
|
|
class Random {
|
|
protected:
|
|
|
|
/** Constants (important for the algorithm; do not modify) */
|
|
enum {
|
|
N = 624,
|
|
M = 397,
|
|
R = 31,
|
|
U = 11,
|
|
S = 7,
|
|
T = 15,
|
|
L = 18,
|
|
A = 0x9908B0DF,
|
|
B = 0x9D2C5680,
|
|
C = 0xEFC60000};
|
|
|
|
/**
|
|
Prevents multiple overlapping calls to generate().
|
|
*/
|
|
Spinlock lock;
|
|
|
|
/** State vector (these are the next N values that will be returned) */
|
|
uint32* state;
|
|
|
|
/** Index into state */
|
|
int index;
|
|
|
|
bool m_threadsafe;
|
|
|
|
/** Generate the next N ints, and store them for readback later.
|
|
Called from bits() */
|
|
virtual void generate();
|
|
|
|
/** For subclasses. The void* parameter is just to distinguish this from the
|
|
public constructor.*/
|
|
Random(void*);
|
|
|
|
|
|
private:
|
|
|
|
Random& operator=(const Random&) {
|
|
alwaysAssertM(false,
|
|
"There is no copy constructor or assignment operator for Random because you "
|
|
"probably didn't actually want to copy the state--it would "
|
|
"be slow and duplicate the state of a pseudo-random sequence. Maybe you could "
|
|
"provide arguments to a member variable in the constructor, "
|
|
"or pass the Random by reference?");
|
|
return *this;
|
|
}
|
|
|
|
Random(const Random& r) {
|
|
*this = r;
|
|
}
|
|
|
|
public:
|
|
|
|
/** \param threadsafe Set to false if you know that this random
|
|
will only be used on a single thread. This eliminates the
|
|
lock and improves performance on some platforms.
|
|
*/
|
|
Random(uint32 seed = 0xF018A4D2, bool threadsafe = true);
|
|
|
|
virtual ~Random();
|
|
|
|
virtual void reset(uint32 seed = 0xF018A4D2, bool threadsafe = true);
|
|
|
|
/** Each bit is random. Subclasses can choose to override just
|
|
this method and the other methods will all work automatically. */
|
|
virtual uint32 bits();
|
|
|
|
/** Uniform random integer on the range [min, max] */
|
|
virtual int integer(int min, int max);
|
|
|
|
/** Uniform random float on the range [min, max] */
|
|
virtual inline float uniform(float low, float high) {
|
|
// We could compute the ratio in double precision here for
|
|
// about 1.5x slower performance and slightly better
|
|
// precision.
|
|
return low + (high - low) * ((float)bits() / (float)0xFFFFFFFFUL);
|
|
}
|
|
|
|
/** Uniform random float on the range [0, 1] */
|
|
virtual inline float uniform() {
|
|
// We could compute the ratio in double precision here for
|
|
// about 1.5x slower performance and slightly better
|
|
// precision.
|
|
const float norm = 1.0f / (float)0xFFFFFFFFUL;
|
|
return (float)bits() * norm;
|
|
}
|
|
|
|
/** Normally distributed reals. */
|
|
virtual float gaussian(float mean, float stdev);
|
|
|
|
/** Returns 3D unit vectors distributed according to
|
|
a cosine distribution about the positive z-axis. */
|
|
virtual void cosHemi(float& x, float& y, float& z);
|
|
|
|
/** Returns 3D unit vectors distributed according to
|
|
a cosine distribution about the z-axis. */
|
|
virtual void cosSphere(float& x, float& y, float& z);
|
|
|
|
/** Returns 3D unit vectors distributed according to a cosine
|
|
power distribution (\f$ \cos^k \theta \f$) about
|
|
the z-axis. */
|
|
virtual void cosPowHemi(const float k, float& x, float& y, float& z);
|
|
|
|
/** Returns 3D unit vectors uniformly distributed on the
|
|
hemisphere about the z-axis. */
|
|
virtual void hemi(float& x, float& y, float& z);
|
|
|
|
/** Returns 3D unit vectors uniformly distributed on the sphere */
|
|
virtual void sphere(float& x, float& y, float& z);
|
|
|
|
/**
|
|
A shared instance for when the performance and features but not
|
|
consistency of the class are desired. It is slightly (10%)
|
|
faster to use a distinct instance than to use the common one.
|
|
|
|
Threadsafe.
|
|
*/
|
|
static Random& common();
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|