You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
5.7 KiB
164 lines
5.7 KiB
//////////////////////////////////////////////////////////////////// |
|
// 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<float>(); |
|
} |
|
FORCEINLINE double randomd() { |
|
return RANDOM<double>(); |
|
} |
|
FORCEINLINE long double randomld() { |
|
return RANDOM<long double>(); |
|
} |
|
STATIC_ASSERT(RAND_MAX < 2147483648); // integer randomRange assumes this is capped |
|
template<typename T> |
|
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>(float fMin, float fMax) { |
|
return fMin + (fMax - fMin) * random(); |
|
} |
|
template<> |
|
FORCEINLINE double randomRange<double>(double fMin, double fMax) { |
|
return fMin + (fMax - fMin) * randomd(); |
|
} |
|
template<> |
|
FORCEINLINE long double randomRange<long double>(long double fMin, long double fMax) { |
|
return fMin + (fMax - fMin) * randomld(); |
|
} |
|
template<typename T> |
|
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>(float mean, float delta/*=(max-min)/2*/) { |
|
return mean + delta * (2.f * random() - 1.f); |
|
} |
|
template<> |
|
FORCEINLINE double randomMeanRange<double>(double mean, double delta/*=(max-min)/2*/) { |
|
return mean + delta * (2.0 * randomd() - 1.0); |
|
} |
|
template<> |
|
FORCEINLINE long double randomMeanRange<long double>(long double mean, long double delta/*=(max-min)/2*/) { |
|
return mean + delta * (2.0L * randomld() - 1.0L); |
|
} |
|
// gaussian random number generation |
|
template<typename T> |
|
FORCEINLINE T gaussian(T val, T sigma) { |
|
return EXP(-SQUARE(val/sigma)/2)/(SQRT(T(M_PI*2))*sigma); |
|
} |
|
template<typename T> |
|
FORCEINLINE T randomGaussian(T mean, T sigma) { |
|
T x, y, r2; |
|
do { |
|
x = T(-1) + T(2) * RANDOM<T>(); |
|
y = T(-1) + T(2) * RANDOM<T>(); |
|
r2 = x * x + y * y; |
|
} while (r2 > T(1) || r2 == T(0)); |
|
return mean + sigma * y * SQRT(T(-2) * LOGN(r2) / r2); |
|
} |
|
template<typename T> |
|
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<typename T=result_type> |
|
FORCEINLINE typename std::enable_if<std::is_floating_point<T>::value, T>::type random() { |
|
return (T)random()/(T)max(); |
|
} |
|
// returns a uniform random number in the range [0, max()] |
|
template<typename T=result_type> |
|
FORCEINLINE typename std::enable_if<std::is_integral<T>::value, T>::type random() { |
|
return (T)operator()(); |
|
} |
|
|
|
// returns a uniform random number in the range [nMin, nMax] |
|
template<typename T=result_type> |
|
FORCEINLINE typename std::enable_if<std::is_floating_point<T>::value, T>::type randomRange(T nMin, T nMax) { |
|
return nMin + (nMax-nMin) * random<T>(); |
|
} |
|
template<typename T=result_type> |
|
FORCEINLINE typename std::enable_if<std::is_integral<T>::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<typename T=result_type> |
|
FORCEINLINE typename std::enable_if<std::is_floating_point<T>::value, T>::type randomMeanRange(T mean, T delta/*=(max-min)/2*/) { |
|
return mean + delta * (T(2) * random<T>() - T(1)); |
|
} |
|
template<typename T=result_type> |
|
FORCEINLINE typename std::enable_if<std::is_integral<T>::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<typename T=result_type> |
|
FORCEINLINE typename std::enable_if<std::is_floating_point<T>::value, T>::type randomUniform(T nMin, T nMax) { |
|
return std::uniform_real_distribution<T>(nMin, nMax)(*this); |
|
} |
|
template<typename T=result_type> |
|
FORCEINLINE typename std::enable_if<std::is_integral<T>::value, T>::type randomUniform(T nMin, T nMax) { |
|
return std::uniform_int_distribution<T>(nMin, nMax)(*this); |
|
} |
|
|
|
// returns a gaussian random number using std implementation |
|
template<typename T=result_type> |
|
FORCEINLINE T randomGaussian(T mean, T stddev) { |
|
return std::normal_distribution<T>(mean, stddev)(*this); |
|
} |
|
}; |
|
/*----------------------------------------------------------------*/ |
|
|
|
} // namespace SEACAVE |
|
|
|
#endif // __SEACAVE_RANDOM_H__
|
|
|