00001 //---------------------------------------------------------------------------- 00002 /** @file SgRandom.h 00003 Random numbers. */ 00004 //---------------------------------------------------------------------------- 00005 00006 #ifndef SG_RANDOM_H 00007 #define SG_RANDOM_H 00008 00009 #include <algorithm> 00010 #include <list> 00011 #include <boost/random/mersenne_twister.hpp> 00012 #include "SgArray.h" 00013 00014 //---------------------------------------------------------------------------- 00015 00016 /** Random number generator. 00017 Uses a Mersenne Twister, because this is faster than std::rand() and 00018 game playing programs usually need faster random numbers more than 00019 high quality ones. All random generators are internally registered to 00020 make it possible to change the random seed for all of them. 00021 00022 SgRandom is thread-safe (w.r.t. different instances) after construction 00023 (the constructor is not thread-safe, because it uses a global variable 00024 for registration). */ 00025 class SgRandom 00026 { 00027 public: 00028 SgRandom(); 00029 00030 ~SgRandom(); 00031 00032 /** Return the global random number generator. 00033 The global generator is stored as a static variable in this function 00034 to ensure that it is initialized at first call if SgRandom is used 00035 in global variables of other compilation units. 00036 @note The global random number generator is not thread-safe. */ 00037 static SgRandom& Global(); 00038 00039 /** Set random seed for all existing and future instances of SgRandom. 00040 @param seed The seed. If negative, no seed will be set. If zero, a 00041 non-deterministic random seed will be used (e.g. derived from the 00042 current time). 00043 Also calls std::srand() 00044 @note This function is not thread-safe. */ 00045 static void SetSeed(int seed); 00046 00047 /** Get random seed. 00048 See SetSeed(int) for the special meaning of zero and negative values. */ 00049 static int Seed(); 00050 00051 /** Get a random integer. 00052 Uses a fast random generator (the Mersenne Twister boost::mt19937), 00053 because in games and Monte Carlo simulations, speed is more important 00054 than quality. */ 00055 unsigned int Int(); 00056 00057 /** Get a random integer in an interval. 00058 @param range The upper limit of the interval (exclusive) 00059 @pre range > 0 00060 @pre range <= SgRandom::Max() 00061 @return An integer in <tt> [0..range - 1]</tt> */ 00062 int Int(int range); 00063 00064 /** See SgRandom::Int(int) */ 00065 std::size_t Int(std::size_t range); 00066 00067 /** Get a small random integer in an interval. 00068 Uses only the lower 16 bits. Faster than SgRandom::Int(int) because it 00069 avoids the expensive modulo operation. 00070 @param range The upper limit of the interval (exclusive) 00071 @pre range > 0 00072 @pre range <= (1 << 16) 00073 @return An integer in <tt> [0..range - 1]</tt> */ 00074 int SmallInt(int range); 00075 00076 /** See SgRandom::SmallInt(int) */ 00077 std::size_t SmallInt(std::size_t range); 00078 00079 /** Get a random integer in [min, max - 1] */ 00080 int Range(int min, int max); 00081 00082 /** Maximum value. */ 00083 unsigned int Max(); 00084 00085 /** convert percentage between 0 and 99 to a threshold for RandomEvent. 00086 Use as in following example: 00087 const unsigned int percent80 = PercentageThreshold(80); */ 00088 unsigned int PercentageThreshold(int percentage); 00089 00090 /** return true if random number SgRandom() <= threshold */ 00091 bool RandomEvent(unsigned int threshold); 00092 00093 private: 00094 struct GlobalData 00095 { 00096 /** The random seed. 00097 Zero means not to set a random seed. */ 00098 boost::mt19937::result_type m_seed; 00099 00100 std::list<SgRandom*> m_allGenerators; 00101 00102 GlobalData(); 00103 }; 00104 00105 /** Return global data. 00106 Global data is stored as a static variable in this function to ensure 00107 that it is initialized at first call if SgRandom is used in global 00108 variables of other compilation units. */ 00109 static GlobalData& GetGlobalData(); 00110 00111 boost::mt19937 m_generator; 00112 00113 void SetSeed(); 00114 }; 00115 00116 inline unsigned int SgRandom::Int() 00117 { 00118 return m_generator(); 00119 } 00120 00121 inline int SgRandom::Int(int range) 00122 { 00123 SG_ASSERT(range > 0); 00124 SG_ASSERT(static_cast<unsigned int>(range) <= SgRandom::Max()); 00125 int i = Int() % range; 00126 SG_ASSERTRANGE(i, 0, range - 1); 00127 return i; 00128 } 00129 00130 inline std::size_t SgRandom::Int(std::size_t range) 00131 { 00132 SG_ASSERT(range <= SgRandom::Max()); 00133 std::size_t i = Int() % range; 00134 SG_ASSERT(i < range); 00135 return i; 00136 } 00137 00138 inline unsigned int SgRandom::Max() 00139 { 00140 return m_generator.max(); 00141 } 00142 00143 inline unsigned int SgRandom::PercentageThreshold(int percentage) 00144 { 00145 return (m_generator.max() / 100) * percentage; 00146 } 00147 00148 inline bool SgRandom::RandomEvent(unsigned int threshold) 00149 { 00150 return Int() <= threshold; 00151 } 00152 00153 inline int SgRandom::Range(int min, int max) 00154 { 00155 return min + Int(max - min); 00156 } 00157 00158 inline int SgRandom::SmallInt(int range) 00159 { 00160 SG_ASSERT(range > 0); 00161 SG_ASSERT(range <= (1 << 16)); 00162 int i = ((Int() & 0xffff) * range) >> 16; 00163 SG_ASSERTRANGE(i, 0, range - 1); 00164 return i; 00165 } 00166 00167 inline std::size_t SgRandom::SmallInt(std::size_t range) 00168 { 00169 SG_ASSERT(range <= (1 << 16)); 00170 std::size_t i = ((Int() & 0xffff) * range) >> 16; 00171 SG_ASSERT(i < range); 00172 return i; 00173 } 00174 00175 //---------------------------------------------------------------------------- 00176 00177 /** Get a random float in [min, max]. 00178 Used std::rand() */ 00179 float SgRandomFloat(float min, float max); 00180 00181 //---------------------------------------------------------------------------- 00182 00183 #endif // SG_RANDOM_H