// $Id: JamesRandom.cc,v 1.6 2010/06/16 17:24:53 garren Exp $ // -*- C++ -*- // // ----------------------------------------------------------------------- // HEP Random // --- HepJamesRandom --- // class implementation file // ----------------------------------------------------------------------- // This file is part of Geant4 (simulation toolkit for HEP). // // This algorithm implements the original universal random number generator // as proposed by Marsaglia & Zaman in report FSU-SCRI-87-50 and coded // in FORTRAN77 by Fred James as the RANMAR generator, part of the MATHLIB // HEP library. // ======================================================================= // Gabriele Cosmo - Created: 5th September 1995 // - Fixed a bug in setSeed(): 26th February 1996 // - Minor corrections: 31st October 1996 // - Added methods for engine status: 19th November 1996 // - Fixed bug in setSeeds(): 15th September 1997 // J.Marraffino - Added stream operators and related constructor. // Added automatic seed selection from seed table and // engine counter: 16th Feb 1998 // Ken Smith - Added conversion operators: 6th Aug 1998 // J. Marraffino - Remove dependence on hepString class 13 May 1999 // V. Innocente - changed pointers to indices 3 may 2000 // M. Fischler - In restore, checkFile for file not found 03 Dec 2004 // M. Fischler - Methods for distrib. instacne save/restore 12/8/04 // M. Fischler - split get() into tag validation and // getState() for anonymous restores 12/27/04 // M. Fischler - Enforcement that seeds be non-negative // (lest the sequence be non-random) 2/14/05 // M. Fischler - put/get for vectors of ulongs 3/14/05 // M. Fischler - State-saving using only ints, for portability 4/12/05 // // ======================================================================= #include "CLHEP/Random/defs.h" #include "CLHEP/Random/Random.h" #include "CLHEP/Random/JamesRandom.h" #include "CLHEP/Random/engineIDulong.h" #include "CLHEP/Random/DoubConv.hh" #include // for strcmp #include #include //#define TRACE_IO namespace CLHEP { static const int MarkerLen = 64; // Enough room to hold a begin or end marker. std::string HepJamesRandom::name() const {return "HepJamesRandom";} // Number of instances with automatic seed selection int HepJamesRandom::numEngines = 0; // Maximum index into the seed table int HepJamesRandom::maxIndex = 215; HepJamesRandom::HepJamesRandom(long seed) : HepRandomEngine() { setSeed(seed,0); setSeeds(&theSeed,0); } HepJamesRandom::HepJamesRandom() // 15 Feb. 1998 JMM : HepRandomEngine() { long seeds[2]; long seed; int cycle = abs(int(numEngines/maxIndex)); int curIndex = abs(int(numEngines%maxIndex)); ++numEngines; long mask = ((cycle & 0x007fffff) << 8); HepRandom::getTheTableSeeds( seeds, curIndex ); seed = seeds[0]^mask; setSeed(seed,0); setSeeds(&theSeed,0); } HepJamesRandom::HepJamesRandom(int rowIndex, int colIndex) // 15 Feb. 1998 JMM : HepRandomEngine() { long seed; long seeds[2]; int cycle = abs(int(rowIndex/maxIndex)); int row = abs(int(rowIndex%maxIndex)); int col = abs(int(colIndex%2)); long mask = ((cycle & 0x000007ff) << 20); HepRandom::getTheTableSeeds( seeds, row ); seed = (seeds[col])^mask; setSeed(seed,0); setSeeds(&theSeed,0); } HepJamesRandom::HepJamesRandom(std::istream& is) : HepRandomEngine() { is >> *this; } HepJamesRandom::~HepJamesRandom() {} void HepJamesRandom::saveStatus( const char filename[] ) const { std::ofstream outFile( filename, std::ios::out ) ; if (!outFile.bad()) { outFile << "Uvec\n"; std::vector v = put(); #ifdef TRACE_IO std::cout << "Result of v = put() is:\n"; #endif for (unsigned int i=0; i v; unsigned long xin; for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) { inFile >> xin; #ifdef TRACE_IO std::cout << "ivec = " << ivec << " xin = " << xin << " "; if (ivec%3 == 0) std::cout << "\n"; #endif if (!inFile) { inFile.clear(std::ios::badbit | inFile.rdstate()); std::cerr << "\nJamesRandom state (vector) description improper." << "\nrestoreStatus has failed." << "\nInput stream is probably mispositioned now." << std::endl; return; } v.push_back(xin); } getState(v); return; } if (!inFile.bad() && !inFile.eof()) { // inFile >> theSeed; removed -- encompased by possibleKeywordInput for (int i=0; i<97; ++i) inFile >> u[i]; inFile >> c; inFile >> cd; inFile >> cm; inFile >> jpos; ipos = (64+jpos)%97; i97 = ipos; j97 = jpos; } } void HepJamesRandom::showStatus() const { std::cout << std::endl; std::cout << "----- HepJamesRandom engine status -----" << std::endl; std::cout << " Initial seed = " << theSeed << std::endl; std::cout << " u[] = "; for (int i=0; i<97; ++i) std::cout << u[i] << " "; std::cout << std::endl; std::cout << " c = " << c << ", cd = " << cd << ", cm = " << cm << std::endl; std::cout << " i97 = " << i97 << ", u[i97] = " << u[i97] << std::endl; std::cout << " j97 = " << j97 << ", u[j97] = " << u[j97] << std::endl; std::cout << "----------------------------------------" << std::endl; } void HepJamesRandom::setSeed(long seed, int) { // The input value for "seed" should be within the range [0,900000000] // // Negative seeds result in serious flaws in the randomness; // seeds above 900000000 are OK because of the %177 in the expression for i, // but may have the same effect as other seeds below 900000000. int m, n; float s, t; long mm; if (seed < 0) { std::cout << "Seed for HepJamesRandom must be non-negative\n" << "Seed value supplied was " << seed << "\nUsing its absolute value instead\n"; seed = -seed; } long ij = seed/30082; long kl = seed - 30082*ij; long i = (ij/177) % 177 + 2; long j = ij % 177 + 2; long k = (kl/169) % 178 + 1; long l = kl % 169; theSeed = seed; for ( n = 1 ; n < 98 ; n++ ) { s = 0.0; t = 0.5; for ( m = 1 ; m < 25 ; m++) { mm = ( ( (i*j) % 179 ) * k ) % 179; i = j; j = k; k = mm; l = ( 53 * l + 1 ) % 169; if ( (l*mm % 64 ) >= 32 ) s += t; t *= 0.5; } u[n-1] = s; } c = 362436.0 / 16777216.0; cd = 7654321.0 / 16777216.0; cm = 16777213.0 / 16777216.0; i97 = 96; j97 = 32; } void HepJamesRandom::setSeeds(const long* seeds, int) { setSeed(seeds ? *seeds : 19780503L, 0); theSeeds = seeds; } double HepJamesRandom::flat() { double uni; do { uni = u[i97] - u[j97]; if ( uni < 0.0 ) uni++; u[i97] = uni; if (i97 == 0) i97 = 96; else i97--; if (j97 == 0) j97 = 96; else j97--; c -= cd; if (c < 0.0) c += cm; uni -= c; if (uni < 0.0) uni += 1.0; } while ( uni <= 0.0 || uni >= 1.0 ); return uni; } void HepJamesRandom::flatArray(const int size, double* vect) { // double uni; int i; for (i=0; i>16) & 0xff); } std::ostream & HepJamesRandom::put ( std::ostream& os ) const { char beginMarker[] = "JamesRandom-begin"; os << beginMarker << "\nUvec\n"; std::vector v = put(); for (unsigned int i=0; i HepJamesRandom::put () const { std::vector v; v.push_back (engineIDulong()); std::vector t; for (int i=0; i<97; ++i) { t = DoubConv::dto2longs(u[i]); v.push_back(t[0]); v.push_back(t[1]); } t = DoubConv::dto2longs(c); v.push_back(t[0]); v.push_back(t[1]); t = DoubConv::dto2longs(cd); v.push_back(t[0]); v.push_back(t[1]); t = DoubConv::dto2longs(cm); v.push_back(t[0]); v.push_back(t[1]); v.push_back(static_cast(j97)); return v; } std::istream & HepJamesRandom::get ( std::istream& is) { char beginMarker [MarkerLen]; is >> std::ws; is.width(MarkerLen); // causes the next read to the char* to be <= // that many bytes, INCLUDING A TERMINATION \0 // (Stroustrup, section 21.3.2) is >> beginMarker; if (strcmp(beginMarker,"JamesRandom-begin")) { is.clear(std::ios::badbit | is.rdstate()); std::cerr << "\nInput stream mispositioned or" << "\nJamesRandom state description missing or" << "\nwrong engine type found." << std::endl; return is; } return getState(is); } std::string HepJamesRandom::beginTag ( ) { return "JamesRandom-begin"; } std::istream & HepJamesRandom::getState ( std::istream& is) { if ( possibleKeywordInput ( is, "Uvec", theSeed ) ) { std::vector v; unsigned long uu; for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) { is >> uu; if (!is) { is.clear(std::ios::badbit | is.rdstate()); std::cerr << "\nJamesRandom state (vector) description improper." << "\ngetState() has failed." << "\nInput stream is probably mispositioned now." << std::endl; return is; } v.push_back(uu); } getState(v); return (is); } // is >> theSeed; Removed, encompassed by possibleKeywordInput() int ipos, jpos; char endMarker [MarkerLen]; for (int i=0; i<97; ++i) { is >> u[i]; } is >> c; is >> cd; is >> cm; is >> jpos; is >> std::ws; is.width(MarkerLen); is >> endMarker; if(strcmp(endMarker,"JamesRandom-end")) { is.clear(std::ios::badbit | is.rdstate()); std::cerr << "\nJamesRandom state description incomplete." << "\nInput stream is probably mispositioned now." << std::endl; return is; } ipos = (64+jpos)%97; i97 = ipos; j97 = jpos; return is; } bool HepJamesRandom::get (const std::vector & v) { if ( (v[0] & 0xffffffffUL) != engineIDulong()) { std::cerr << "\nHepJamesRandom get:state vector has wrong ID word - state unchanged\n"; return false; } return getState(v); } bool HepJamesRandom::getState (const std::vector & v) { if (v.size() != VECTOR_STATE_SIZE ) { std::cerr << "\nHepJamesRandom get:state vector has wrong length - state unchanged\n"; return false; } std::vector t(2); for (int i=0; i<97; ++i) { t[0] = v[2*i+1]; t[1] = v[2*i+2]; u[i] = DoubConv::longs2double(t); } t[0] = v[195]; t[1] = v[196]; c = DoubConv::longs2double(t); t[0] = v[197]; t[1] = v[198]; cd = DoubConv::longs2double(t); t[0] = v[199]; t[1] = v[200]; cm = DoubConv::longs2double(t); j97 = v[201]; i97 = (64+j97)%97; return true; } } // namespace CLHEP