//////////////////////////////////////////////////////////////////// // Random.h // // Copyright 2007 cDc@seacave // Distributed under the Boost Software License, Version 1.0 // (See http://www.boost.org/LICENSE_1_0.txt) #ifndef __SEACAVE_RANDOM_H__ #define __SEACAVE_RANDOM_H__ // I N C L U D E S ///////////////////////////////////////////////// // D E F I N E S /////////////////////////////////////////////////// namespace SEACAVE { // S T R U C T S /////////////////////////////////////////////////// // Stateless random number generation // uniform random number generation FORCEINLINE float random() { return RANDOM(); } FORCEINLINE double randomd() { return RANDOM(); } FORCEINLINE long double randomld() { return RANDOM(); } STATIC_ASSERT(RAND_MAX < 2147483648); // integer randomRange assumes this is capped template FORCEINLINE T randomRange(T nMin, T nMax) { ASSERT(nMin <= nMax && nMax-nMin+1 < 8589934596); // not to overflow a uint64_t return nMin + T((uint64_t(nMax-nMin)*RAND()+RAND_MAX/2)/RAND_MAX); } template<> FORCEINLINE float randomRange(float fMin, float fMax) { return fMin + (fMax - fMin) * random(); } template<> FORCEINLINE double randomRange(double fMin, double fMax) { return fMin + (fMax - fMin) * randomd(); } template<> FORCEINLINE long double randomRange(long double fMin, long double fMax) { return fMin + (fMax - fMin) * randomld(); } template FORCEINLINE T randomMeanRange(T mean, T delta/*=(max-min)/2*/) { ASSERT(delta >= 0 && delta*2+1 < 8589934596); // not to overflow a uint64_t return (mean + T((uint64_t(delta)*2*RAND()+RAND_MAX/2)/RAND_MAX)) - delta; } template<> FORCEINLINE float randomMeanRange(float mean, float delta/*=(max-min)/2*/) { return mean + delta * (2.f * random() - 1.f); } template<> FORCEINLINE double randomMeanRange(double mean, double delta/*=(max-min)/2*/) { return mean + delta * (2.0 * randomd() - 1.0); } template<> FORCEINLINE long double randomMeanRange(long double mean, long double delta/*=(max-min)/2*/) { return mean + delta * (2.0L * randomld() - 1.0L); } // gaussian random number generation template FORCEINLINE T gaussian(T val, T sigma) { return EXP(-SQUARE(val/sigma)/2)/(SQRT(T(M_PI*2))*sigma); } template FORCEINLINE T randomGaussian(T mean, T sigma) { T x, y, r2; do { x = T(-1) + T(2) * RANDOM(); y = T(-1) + T(2) * RANDOM(); r2 = x * x + y * y; } while (r2 > T(1) || r2 == T(0)); return mean + sigma * y * SQRT(T(-2) * LOGN(r2) / r2); } template FORCEINLINE T randomGaussian(T sigma) { return randomGaussian(T(0), sigma); } FORCEINLINE float randomGaussian() { return randomGaussian(0.f, 1.f); } FORCEINLINE double randomGaussiand() { return randomGaussian(0.0, 1.0); } FORCEINLINE long double randomGaussianld() { return randomGaussian(0.0L, 1.0L); } /*----------------------------------------------------------------*/ // Encapsulates state for random number generation // based on C++11 random number generator functionality struct Random : std::mt19937 { typedef std::mt19937 generator_type; Random() : generator_type(std::random_device()()) {} Random(result_type seed) : generator_type(seed) {} // integer randomRange assumes this is capped STATIC_ASSERT(max() < 4294967296); // returns a uniform random number in the range [0, 1] template FORCEINLINE typename std::enable_if::value, T>::type random() { return (T)random()/(T)max(); } // returns a uniform random number in the range [0, max()] template FORCEINLINE typename std::enable_if::value, T>::type random() { return (T)operator()(); } // returns a uniform random number in the range [nMin, nMax] template FORCEINLINE typename std::enable_if::value, T>::type randomRange(T nMin, T nMax) { return nMin + (nMax-nMin) * random(); } template FORCEINLINE typename std::enable_if::value, T>::type randomRange(T nMin, T nMax) { ASSERT(nMin <= nMax && nMax-nMin+1 < 4294967297); // not to overflow a uint64_t return nMin + (T)(((uint64_t)(nMax-nMin) * random() + max()/2)/max()); } // returns a uniform random number in the range [mean-delta, mean+delta] template FORCEINLINE typename std::enable_if::value, T>::type randomMeanRange(T mean, T delta/*=(max-min)/2*/) { return mean + delta * (T(2) * random() - T(1)); } template FORCEINLINE typename std::enable_if::value, T>::type randomMeanRange(T mean, T delta/*=(max-min)/2*/) { ASSERT(delta >= 0 && delta*T(2)+1 < 4294967297); // not to overflow a uint64_t return mean + (T)(((uint64_t)delta*2 * random() + max()/2)/max()) - delta; } // returns a uniform random number in the range [nMin, nMax] using std implementation template FORCEINLINE typename std::enable_if::value, T>::type randomUniform(T nMin, T nMax) { return std::uniform_real_distribution(nMin, nMax)(*this); } template FORCEINLINE typename std::enable_if::value, T>::type randomUniform(T nMin, T nMax) { return std::uniform_int_distribution(nMin, nMax)(*this); } // returns a gaussian random number using std implementation template FORCEINLINE T randomGaussian(T mean, T stddev) { return std::normal_distribution(mean, stddev)(*this); } }; /*----------------------------------------------------------------*/ } // namespace SEACAVE #endif // __SEACAVE_RANDOM_H__