CLHEP VERSION Reference Documentation
CLHEP Home Page CLHEP Documentation CLHEP Bug Reports |
00001 // $Id: MTwistEngine.cc,v 1.6 2010/06/16 17:24:53 garren Exp $ 00002 // -*- C++ -*- 00003 // 00004 // ----------------------------------------------------------------------- 00005 // HEP Random 00006 // --- MTwistEngine --- 00007 // class implementation file 00008 // ----------------------------------------------------------------------- 00009 // A "fast, compact, huge-period generator" based on M. Matsumoto and 00010 // T. Nishimura, "Mersenne Twister: A 623-dimensionally equidistributed 00011 // uniform pseudorandom number generator", to appear in ACM Trans. on 00012 // Modeling and Computer Simulation. It is a twisted GFSR generator 00013 // with a Mersenne-prime period of 2^19937-1, uniform on open interval (0,1) 00014 // ======================================================================= 00015 // Ken Smith - Started initial draft: 14th Jul 1998 00016 // - Optimized to get std::pow() out of flat() method 00017 // - Added conversion operators: 6th Aug 1998 00018 // J. Marraffino - Added some explicit casts to deal with 00019 // machines where sizeof(int) != sizeof(long) 22 Aug 1998 00020 // M. Fischler - Modified constructors such that no two 00021 // seeds will match sequences, no single/double 00022 // seeds will match, explicit seeds give 00023 // determined results, and default will not 00024 // match any of the above or other defaults. 00025 // - Modified use of the various exponents of 2 00026 // to avoid per-instance space overhead and 00027 // correct the rounding procedure 16 Sep 1998 00028 // J. Marfaffino - Remove dependence on hepString class 13 May 1999 00029 // M. Fischler - In restore, checkFile for file not found 03 Dec 2004 00030 // M. Fischler - Methods for distrib. instacne save/restore 12/8/04 00031 // M. Fischler - split get() into tag validation and 00032 // getState() for anonymous restores 12/27/04 00033 // M. Fischler - put/get for vectors of ulongs 3/14/05 00034 // M. Fischler - State-saving using only ints, for portability 4/12/05 00035 // M. Fischler - Improved seeding in setSeed (Savanah bug #17479) 11/15/06 00036 // - (Possible optimization - now that the seeding is improved, 00037 // is it still necessary for ctor to "warm up" by discarding 00038 // 2000 iterations?) 00039 // 00040 // ======================================================================= 00041 00042 #include "CLHEP/Random/defs.h" 00043 #include "CLHEP/Random/Random.h" 00044 #include "CLHEP/Random/MTwistEngine.h" 00045 #include "CLHEP/Random/engineIDulong.h" 00046 #include <string.h> // for strcmp 00047 #include <cstdlib> // for std::abs(int) 00048 00049 namespace CLHEP { 00050 00051 static const int MarkerLen = 64; // Enough room to hold a begin or end marker. 00052 00053 std::string MTwistEngine::name() const {return "MTwistEngine";} 00054 00055 int MTwistEngine::numEngines = 0; 00056 int MTwistEngine::maxIndex = 215; 00057 00058 MTwistEngine::MTwistEngine() 00059 : HepRandomEngine() 00060 { 00061 int cycle = std::abs(int(numEngines/maxIndex)); 00062 int curIndex = std::abs(int(numEngines%maxIndex)); 00063 long mask = ((cycle & 0x007fffff) << 8); 00064 long seedlist[2]; 00065 HepRandom::getTheTableSeeds( seedlist, curIndex ); 00066 seedlist[0] = (seedlist[0])^mask; 00067 seedlist[1] = 0; 00068 setSeeds( seedlist, numEngines ); 00069 count624=0; 00070 ++numEngines; 00071 for( int i=0; i < 2000; ++i ) flat(); // Warm up just a bit 00072 } 00073 00074 MTwistEngine::MTwistEngine(long seed) 00075 : HepRandomEngine() 00076 { 00077 long seedlist[2]={seed,17587}; 00078 setSeeds( seedlist, 0 ); 00079 count624=0; 00080 for( int i=0; i < 2000; ++i ) flat(); // Warm up just a bit 00081 } 00082 00083 MTwistEngine::MTwistEngine(int rowIndex, int colIndex) 00084 : HepRandomEngine() 00085 { 00086 int cycle = std::abs(int(rowIndex/maxIndex)); 00087 int row = std::abs(int(rowIndex%maxIndex)); 00088 int col = std::abs(int(colIndex%2)); 00089 long mask = (( cycle & 0x000007ff ) << 20 ); 00090 long seedlist[2]; 00091 HepRandom::getTheTableSeeds( seedlist, row ); 00092 seedlist[0] = (seedlist[col])^mask; 00093 seedlist[1] = 690691; 00094 setSeeds(seedlist, 4444772); 00095 count624=0; 00096 for( int i=0; i < 2000; ++i ) flat(); // Warm up just a bit 00097 } 00098 00099 MTwistEngine::MTwistEngine( std::istream& is ) 00100 : HepRandomEngine() 00101 { 00102 is >> *this; 00103 } 00104 00105 MTwistEngine::~MTwistEngine() {} 00106 00107 double MTwistEngine::flat() { 00108 unsigned int y; 00109 00110 if( count624 >= N ) { 00111 register int i; 00112 00113 for( i=0; i < NminusM; ++i ) { 00114 y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff); 00115 mt[i] = mt[i+M] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 ); 00116 } 00117 00118 for( ; i < N-1 ; ++i ) { 00119 y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff); 00120 mt[i] = mt[i-NminusM] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 ); 00121 } 00122 00123 y = (mt[i] & 0x80000000) | (mt[0] & 0x7fffffff); 00124 mt[i] = mt[M-1] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 ); 00125 00126 count624 = 0; 00127 } 00128 00129 y = mt[count624]; 00130 y ^= ( y >> 11); 00131 y ^= ((y << 7 ) & 0x9d2c5680); 00132 y ^= ((y << 15) & 0xefc60000); 00133 y ^= ( y >> 18); 00134 00135 return y * twoToMinus_32() + // Scale to range 00136 (mt[count624++] >> 11) * twoToMinus_53() + // fill remaining bits 00137 nearlyTwoToMinus_54(); // make sure non-zero 00138 } 00139 00140 void MTwistEngine::flatArray( const int size, double *vect ) { 00141 for( int i=0; i < size; ++i) vect[i] = flat(); 00142 } 00143 00144 void MTwistEngine::setSeed(long seed, int k) { 00145 00146 // MF 11/15/06 - Change seeding algorithm to a newer one recommended 00147 // by Matsumoto: The original algorithm was 00148 // mt[i] = (69069 * mt[i-1]) & 0xffffffff and this gives 00149 // problems when the seed bit pattern has lots of zeros 00150 // (for example, 0x08000000). Savanah bug #17479. 00151 00152 theSeed = seed ? seed : 4357; 00153 int mti; 00154 const int N1=624; 00155 mt[0] = (unsigned int) (theSeed&0xffffffffUL); 00156 for (mti=1; mti<N1; mti++) { 00157 mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); 00158 /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ 00159 /* In the previous versions, MSBs of the seed affect */ 00160 /* only MSBs of the array mt[]. */ 00161 /* 2002/01/09 modified by Makoto Matsumoto */ 00162 mt[mti] &= 0xffffffffUL; 00163 /* for >32 bit machines */ 00164 } 00165 for( int i=1; i < 624; ++i ) { 00166 mt[i] ^= k; // MF 9/16/98: distinguish starting points 00167 } 00168 // MF 11/15/06 This distinction of starting points based on values of k 00169 // is kept even though the seeding algorithm itself is improved. 00170 } 00171 00172 void MTwistEngine::setSeeds(const long *seeds, int k) { 00173 setSeed( (*seeds ? *seeds : 43571346), k ); 00174 int i; 00175 for( i=1; i < 624; ++i ) { 00176 mt[i] = ( seeds[1] + mt[i] ) & 0xffffffff; // MF 9/16/98 00177 } 00178 theSeeds = seeds; 00179 } 00180 00181 void MTwistEngine::saveStatus( const char filename[] ) const 00182 { 00183 std::ofstream outFile( filename, std::ios::out ) ; 00184 if (!outFile.bad()) { 00185 outFile << theSeed << std::endl; 00186 for (int i=0; i<624; ++i) outFile <<std::setprecision(20) << mt[i] << " "; 00187 outFile << std::endl; 00188 outFile << count624 << std::endl; 00189 } 00190 } 00191 00192 void MTwistEngine::restoreStatus( const char filename[] ) 00193 { 00194 std::ifstream inFile( filename, std::ios::in); 00195 if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) { 00196 std::cerr << " -- Engine state remains unchanged\n"; 00197 return; 00198 } 00199 00200 if (!inFile.bad() && !inFile.eof()) { 00201 inFile >> theSeed; 00202 for (int i=0; i<624; ++i) inFile >> mt[i]; 00203 inFile >> count624; 00204 } 00205 } 00206 00207 void MTwistEngine::showStatus() const 00208 { 00209 std::cout << std::endl; 00210 std::cout << "--------- MTwist engine status ---------" << std::endl; 00211 std::cout << std::setprecision(20); 00212 std::cout << " Initial seed = " << theSeed << std::endl; 00213 std::cout << " Current index = " << count624 << std::endl; 00214 std::cout << " Array status mt[] = " << std::endl; 00215 for (int i=0; i<624; i+=5) { 00216 std::cout << mt[i] << " " << mt[i+1] << " " << mt[i+2] << " " 00217 << mt[i+3] << " " << mt[i+4] << std::endl; 00218 } 00219 std::cout << "----------------------------------------" << std::endl; 00220 } 00221 00222 MTwistEngine::operator float() { 00223 unsigned int y; 00224 00225 if( count624 >= N ) { 00226 register int i; 00227 00228 for( i=0; i < NminusM; ++i ) { 00229 y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff); 00230 mt[i] = mt[i+M] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 ); 00231 } 00232 00233 for( ; i < N-1 ; ++i ) { 00234 y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff); 00235 mt[i] = mt[i-NminusM] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 ); 00236 } 00237 00238 y = (mt[i] & 0x80000000) | (mt[0] & 0x7fffffff); 00239 mt[i] = mt[M-1] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 ); 00240 00241 count624 = 0; 00242 } 00243 00244 y = mt[count624++]; 00245 y ^= ( y >> 11); 00246 y ^= ((y << 7 ) & 0x9d2c5680); 00247 y ^= ((y << 15) & 0xefc60000); 00248 y ^= ( y >> 18); 00249 00250 return (float)(y * twoToMinus_32()); 00251 } 00252 00253 MTwistEngine::operator unsigned int() { 00254 unsigned int y; 00255 00256 if( count624 >= N ) { 00257 register int i; 00258 00259 for( i=0; i < NminusM; ++i ) { 00260 y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff); 00261 mt[i] = mt[i+M] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 ); 00262 } 00263 00264 for( ; i < N-1 ; ++i ) { 00265 y = (mt[i] & 0x80000000) | (mt[i+1] & 0x7fffffff); 00266 mt[i] = mt[i-NminusM] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 ); 00267 } 00268 00269 y = (mt[i] & 0x80000000) | (mt[0] & 0x7fffffff); 00270 mt[i] = mt[M-1] ^ (y >> 1) ^ ((y & 0x1) ? 0x9908b0df : 0x0 ); 00271 00272 count624 = 0; 00273 } 00274 00275 y = mt[count624++]; 00276 y ^= ( y >> 11); 00277 y ^= ((y << 7 ) & 0x9d2c5680); 00278 y ^= ((y << 15) & 0xefc60000); 00279 y ^= ( y >> 18); 00280 00281 return y; 00282 } 00283 00284 std::ostream & MTwistEngine::put ( std::ostream& os ) const 00285 { 00286 char beginMarker[] = "MTwistEngine-begin"; 00287 char endMarker[] = "MTwistEngine-end"; 00288 00289 int pr = os.precision(20); 00290 os << " " << beginMarker << " "; 00291 os << theSeed << " "; 00292 for (int i=0; i<624; ++i) { 00293 os << mt[i] << "\n"; 00294 } 00295 os << count624 << " "; 00296 os << endMarker << "\n"; 00297 os.precision(pr); 00298 return os; 00299 } 00300 00301 std::vector<unsigned long> MTwistEngine::put () const { 00302 std::vector<unsigned long> v; 00303 v.push_back (engineIDulong<MTwistEngine>()); 00304 for (int i=0; i<624; ++i) { 00305 v.push_back(static_cast<unsigned long>(mt[i])); 00306 } 00307 v.push_back(count624); 00308 return v; 00309 } 00310 00311 std::istream & MTwistEngine::get ( std::istream& is ) 00312 { 00313 char beginMarker [MarkerLen]; 00314 is >> std::ws; 00315 is.width(MarkerLen); // causes the next read to the char* to be <= 00316 // that many bytes, INCLUDING A TERMINATION \0 00317 // (Stroustrup, section 21.3.2) 00318 is >> beginMarker; 00319 if (strcmp(beginMarker,"MTwistEngine-begin")) { 00320 is.clear(std::ios::badbit | is.rdstate()); 00321 std::cerr << "\nInput stream mispositioned or" 00322 << "\nMTwistEngine state description missing or" 00323 << "\nwrong engine type found." << std::endl; 00324 return is; 00325 } 00326 return getState(is); 00327 } 00328 00329 std::string MTwistEngine::beginTag ( ) { 00330 return "MTwistEngine-begin"; 00331 } 00332 00333 std::istream & MTwistEngine::getState ( std::istream& is ) 00334 { 00335 char endMarker [MarkerLen]; 00336 is >> theSeed; 00337 for (int i=0; i<624; ++i) is >> mt[i]; 00338 is >> count624; 00339 is >> std::ws; 00340 is.width(MarkerLen); 00341 is >> endMarker; 00342 if (strcmp(endMarker,"MTwistEngine-end")) { 00343 is.clear(std::ios::badbit | is.rdstate()); 00344 std::cerr << "\nMTwistEngine state description incomplete." 00345 << "\nInput stream is probably mispositioned now." << std::endl; 00346 return is; 00347 } 00348 return is; 00349 } 00350 00351 bool MTwistEngine::get (const std::vector<unsigned long> & v) { 00352 if ((v[0] & 0xffffffffUL) != engineIDulong<MTwistEngine>()) { 00353 std::cerr << 00354 "\nMTwistEngine get:state vector has wrong ID word - state unchanged\n"; 00355 return false; 00356 } 00357 return getState(v); 00358 } 00359 00360 bool MTwistEngine::getState (const std::vector<unsigned long> & v) { 00361 if (v.size() != VECTOR_STATE_SIZE ) { 00362 std::cerr << 00363 "\nMTwistEngine get:state vector has wrong length - state unchanged\n"; 00364 return false; 00365 } 00366 for (int i=0; i<624; ++i) { 00367 mt[i]=v[i+1]; 00368 } 00369 count624 = v[625]; 00370 return true; 00371 } 00372 00373 } // namespace CLHEP