Geant4 Cross Reference |
1 // -*- C++ -*- 2 // 3 // ----------------------------------------------------------------------- 4 // HEP Random 5 // --- RanshiEngine --- 6 // class implementation file 7 // ----------------------------------------------------------------------- 8 // 9 // This algorithm implements the random number generator as proposed by 10 // "F. Gutbrod, Comp. Phys. Comm. 87 (1995) 291-306". 11 // 12 // ======================================================================= 13 // Ken Smith - Created: 9th June 1998 14 // - Removed std::pow() from flat method: 21st Jul 1998 15 // - Added conversion operators: 6th Aug 1998 16 // J. Marraffino - Added some explicit casts to deal with 17 // machines where sizeof(int) != sizeof(long) 22 Aug 1998 18 // M. Fischler - Modified constructors taking seeds to not 19 // depend on numEngines (same seeds should 20 // produce same sequences). Default still 21 // depends on numEngines. 16 Sep 1998 22 // - Modified use of the various exponents of 2 23 // to avoid per-instance space overhead and 24 // correct the rounding procedure 16 Sep 1998 25 // J. Marraffino - Remove dependence on hepString class 13 May 1999 26 // M. Fischler - In restore, checkFile for file not found 03 Dec 2004 27 // M. Fischler - Methods for instance save/restore 12/8/04 28 // M. Fischler - split get() into tag validation and 29 // getState() for anonymous restores 12/27/04 30 // M. Fischler - State-saving using only ints, for portability 4/12/05 31 // L. Garren - use explicit 32bit mask to avoid compiler warnings 6/6/2014 32 // L. Garren - adding pragma for 32bit gcc 4.9 11/20/2014 33 // 34 // ======================================================================= 35 36 #include "CLHEP/Random/RanshiEngine.h" 37 #include "CLHEP/Random/engineIDulong.h" 38 #include "CLHEP/Utility/atomic_int.h" 39 40 #include <atomic> 41 #include <string.h> // for strcmp 42 #include <iostream> 43 #include <string> 44 #include <vector> 45 46 // don't generate warnings about agressive loop optimization 47 #if defined __GNUC__ 48 #if __GNUC__ > 3 && __GNUC_MINOR__ > 8 49 #pragma GCC diagnostic push 50 #pragma GCC diagnostic ignored "-Waggressive-loop-optimizations" 51 #endif 52 #endif 53 54 namespace CLHEP { 55 56 namespace { 57 // Number of instances with automatic seed selection 58 CLHEP_ATOMIC_INT_TYPE numberOfEngines(0); 59 } 60 61 static const int MarkerLen = 64; // Enough room to hold a begin or end marker. 62 63 std::string RanshiEngine::name() const {return "RanshiEngine";} 64 65 RanshiEngine::RanshiEngine() 66 : HepRandomEngine(), 67 halfBuff(0), numFlats(0) 68 { 69 int numEngines = numberOfEngines++; 70 int i = 0; 71 while (i < numBuff) { 72 buffer[i] = (unsigned int)((numEngines+19780503L*(i+1))& 0xffffffff); 73 ++i; 74 } 75 theSeed = numEngines+19780503L*++i; 76 redSpin = (unsigned int)(theSeed & 0xffffffff); 77 78 for( i = 0; i < 10000; ++i) flat(); // Warm-up by running thorugh 10000 nums 79 } 80 81 RanshiEngine::RanshiEngine(std::istream& is) 82 : HepRandomEngine(), 83 halfBuff(0), numFlats(0) 84 { 85 is >> *this; 86 } 87 88 RanshiEngine::RanshiEngine(long seed) 89 : HepRandomEngine(), 90 halfBuff(0), numFlats(0) 91 { 92 for (int i = 0; i < numBuff; ++i) { 93 buffer[i] = (unsigned int)seed&0xffffffff; 94 } 95 theSeed = seed; 96 redSpin = (unsigned int)(theSeed & 0xffffffff); 97 int j; 98 for (j = 0; j < numBuff*20; ++j) { // "warm-up" for engine to hit 99 flat(); // every ball on average 20X. 100 } 101 } 102 103 RanshiEngine::RanshiEngine(int rowIndex, int colIndex) 104 : HepRandomEngine(), 105 halfBuff(0), numFlats(0) 106 { 107 int i = 0; 108 while( i < numBuff ) { 109 buffer[i] = (unsigned int)((rowIndex + (i+1)*(colIndex+8))&0xffffffff); 110 ++i; 111 } 112 theSeed = rowIndex; 113 redSpin = colIndex & 0xffffffff; 114 for( i = 0; i < 100; ++i) flat(); // Warm-up by running thorugh 100 nums 115 } 116 117 RanshiEngine::~RanshiEngine() { } 118 119 double RanshiEngine::flat() { 120 unsigned int redAngle = (((numBuff/2) - 1) & redSpin) + halfBuff; 121 unsigned int blkSpin = buffer[redAngle] & 0xffffffff; 122 unsigned int boostResult = blkSpin ^ redSpin; 123 124 buffer[redAngle] = ((blkSpin << 17) | (blkSpin >> (32-17))) ^ redSpin; 125 126 redSpin = (blkSpin + numFlats++) & 0xffffffff; 127 halfBuff = numBuff/2 - halfBuff; 128 129 return ( blkSpin * twoToMinus_32() + // most significant part 130 (boostResult>>11) * twoToMinus_53() + // fill in remaining bits 131 nearlyTwoToMinus_54()); // non-zero 132 } 133 134 void RanshiEngine::flatArray(const int size, double* vect) { 135 for (int i = 0; i < size; ++i) { 136 vect[i] = flat(); 137 } 138 } 139 140 void RanshiEngine::setSeed(long seed, int) { 141 *this = RanshiEngine(seed); 142 } 143 144 void RanshiEngine::setSeeds(const long* seeds, int) { 145 if (*seeds) { 146 int i = 0; 147 while (seeds[i] && i < numBuff) { 148 buffer[i] = (unsigned int)seeds[i]; 149 ++i; 150 } 151 while (i < numBuff) { 152 buffer[i] = buffer[i-1]; 153 ++i; 154 } 155 theSeed = seeds[0]; 156 redSpin = (unsigned int)theSeed; 157 } 158 theSeeds = seeds; 159 } 160 161 void RanshiEngine::saveStatus(const char filename[]) const { 162 std::ofstream outFile(filename, std::ios::out); 163 if (!outFile.bad()) { 164 outFile << "Uvec\n"; 165 std::vector<unsigned long> v = put(); 166 for (unsigned int i=0; i<v.size(); ++i) { 167 outFile << v[i] << "\n"; 168 } 169 } 170 } 171 172 void RanshiEngine::restoreStatus(const char filename[]) { 173 std::ifstream inFile(filename, std::ios::in); 174 if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) { 175 std::cerr << " -- Engine state remains unchanged\n"; 176 return; 177 } 178 if ( possibleKeywordInput ( inFile, "Uvec", theSeed ) ) { 179 std::vector<unsigned long> v; 180 unsigned long xin; 181 for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) { 182 inFile >> xin; 183 if (!inFile) { 184 inFile.clear(std::ios::badbit | inFile.rdstate()); 185 std::cerr << "\nRanshiEngine state (vector) description improper." 186 << "\nrestoreStatus has failed." 187 << "\nInput stream is probably mispositioned now." << std::endl; 188 return; 189 } 190 v.push_back(xin); 191 } 192 getState(v); 193 return; 194 } 195 196 if (!inFile.bad()) { 197 // inFile >> theSeed; removed -- encompased by possibleKeywordInput 198 for (int i = 0; i < numBuff; ++i) { 199 inFile >> buffer[i]; 200 } 201 inFile >> redSpin >> numFlats >> halfBuff; 202 } 203 } 204 205 void RanshiEngine::showStatus() const { 206 std::cout << std::setprecision(20) << std::endl; 207 std::cout << "----------- Ranshi engine status ----------" << std::endl; 208 std::cout << "Initial seed = " << theSeed << std::endl; 209 std::cout << "Current red spin = " << redSpin << std::endl; 210 std::cout << "Values produced = " << numFlats << std::endl; 211 std::cout << "Side of buffer = " << (halfBuff ? "upper" : "lower") 212 << std::endl; 213 std::cout << "Current buffer = " << std::endl; 214 for (int i = 0; i < numBuff; i+=4) { 215 std::cout << std::setw(10) << std::setiosflags(std::ios::right) 216 << buffer[i] << std::setw(11) << buffer[i+1] << std::setw(11) 217 << buffer[i+2] << std::setw(11) << buffer[i+3] << std::endl; 218 } 219 std::cout << "-------------------------------------------" << std::endl; 220 } 221 222 RanshiEngine::operator double() { 223 return flat(); 224 } 225 226 RanshiEngine::operator float() { 227 unsigned int redAngle = (((numBuff/2) - 1) & redSpin) + halfBuff; 228 unsigned int blkSpin = buffer[redAngle] & 0xffffffff; 229 230 buffer[redAngle] = ((blkSpin << 17) | (blkSpin >> (32-17))) ^ redSpin; 231 232 redSpin = (blkSpin + numFlats++) & 0xffffffff; 233 halfBuff = numBuff/2 - halfBuff; 234 235 return float(blkSpin * twoToMinus_32()); 236 } 237 238 RanshiEngine::operator unsigned int() { 239 unsigned int redAngle = (((numBuff/2) - 1) & redSpin) + halfBuff; 240 unsigned int blkSpin = buffer[redAngle] & 0xffffffff; 241 242 buffer[redAngle] = ((blkSpin << 17) | (blkSpin >> (32-17))) ^ redSpin; 243 244 redSpin = (blkSpin + numFlats++) & 0xffffffff; 245 halfBuff = numBuff/2 - halfBuff; 246 247 return blkSpin; 248 } 249 250 std::ostream& RanshiEngine::put (std::ostream& os ) const { 251 char beginMarker[] = "RanshiEngine-begin"; 252 os << beginMarker << "\nUvec\n"; 253 std::vector<unsigned long> v = put(); 254 for (unsigned int i=0; i<v.size(); ++i) { 255 os << v[i] << "\n"; 256 } 257 return os; 258 } 259 260 std::vector<unsigned long> RanshiEngine::put () const { 261 std::vector<unsigned long> v; 262 v.push_back (engineIDulong<RanshiEngine>()); 263 for (int i = 0; i < numBuff; ++i) { 264 v.push_back(static_cast<unsigned long>(buffer[i])); 265 } 266 v.push_back(static_cast<unsigned long>(redSpin)); 267 v.push_back(static_cast<unsigned long>(numFlats)); 268 v.push_back(static_cast<unsigned long>(halfBuff)); 269 return v; 270 } 271 272 std::istream& RanshiEngine::get (std::istream& is) { 273 char beginMarker [MarkerLen]; 274 is >> std::ws; 275 is.width(MarkerLen); // causes the next read to the char* to be <= 276 // that many bytes, INCLUDING A TERMINATION \0 277 // (Stroustrup, section 21.3.2) 278 is >> beginMarker; 279 if (strcmp(beginMarker,"RanshiEngine-begin")) { 280 is.clear(std::ios::badbit | is.rdstate()); 281 std::cerr << "\nInput mispositioned or" 282 << "\nRanshiEngine state description missing or" 283 << "\nwrong engine type found." << std::endl; 284 return is; 285 } 286 return getState(is); 287 } 288 289 std::string RanshiEngine::beginTag ( ) { 290 return "RanshiEngine-begin"; 291 } 292 293 std::istream& RanshiEngine::getState (std::istream& is) { 294 if ( possibleKeywordInput ( is, "Uvec", theSeed ) ) { 295 std::vector<unsigned long> v; 296 unsigned long uu; 297 for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) { 298 is >> uu; 299 if (!is) { 300 is.clear(std::ios::badbit | is.rdstate()); 301 std::cerr << "\nRanshiEngine state (vector) description improper." 302 << "\ngetState() has failed." 303 << "\nInput stream is probably mispositioned now." << std::endl; 304 return is; 305 } 306 v.push_back(uu); 307 } 308 getState(v); 309 return (is); 310 } 311 312 // is >> theSeed; Removed, encompassed by possibleKeywordInput() 313 314 char endMarker [MarkerLen]; 315 for (int i = 0; i < numBuff; ++i) { 316 is >> buffer[i]; 317 } 318 is >> redSpin >> numFlats >> halfBuff; 319 is >> std::ws; 320 is.width(MarkerLen); 321 is >> endMarker; 322 if (strcmp(endMarker,"RanshiEngine-end")) { 323 is.clear(std::ios::badbit | is.rdstate()); 324 std::cerr << "\nRanshiEngine state description incomplete." 325 << "\nInput stream is probably mispositioned now." << std::endl; 326 return is; 327 } 328 return is; 329 } 330 331 bool RanshiEngine::get (const std::vector<unsigned long> & v) { 332 if ((v[0] & 0xffffffffUL) != engineIDulong<RanshiEngine>()) { 333 std::cerr << 334 "\nRanshiEngine get:state vector has wrong ID word - state unchanged\n"; 335 return false; 336 } 337 return getState(v); 338 } 339 340 bool RanshiEngine::getState (const std::vector<unsigned long> & v) { 341 if (v.size() != VECTOR_STATE_SIZE ) { 342 std::cerr << 343 "\nRanshiEngine get:state vector has wrong length - state unchanged\n"; 344 return false; 345 } 346 for (int i = 0; i < numBuff; ++i) { 347 buffer[i] = (unsigned int)v[i+1]; 348 } 349 redSpin = (unsigned int)v[numBuff+1]; 350 numFlats = (unsigned int)v[numBuff+2]; 351 halfBuff = (unsigned int)v[numBuff+3]; 352 return true; 353 } 354 355 } // namespace CLHEP 356 357 #if defined __GNUC__ 358 #if __GNUC__ > 3 && __GNUC_MINOR__ > 8 359 #pragma GCC diagnostic pop 360 #endif 361 #endif 362