1 // $Id: RandEngine.cc,v 1.8 2010/06/16 17:24:53 garren Exp $
2 // -*- C++ -*-
3 //
4 // -----------------------------------------------------------------------
5 // HEP Random
6 // --- RandEngine ---
7 // class implementation file
8 // -----------------------------------------------------------------------
9 // This file is part of Geant4 (simulation toolkit for HEP).
10
11 // =======================================================================
12 // Gabriele Cosmo - Created: 5th September 1995
13 // - Minor corrections: 31st October 1996
14 // - Added methods for engine status: 19th November 1996
15 // - mx is initialised to RAND_MAX: 2nd April 1997
16 // - Fixed bug in setSeeds(): 15th September 1997
17 // - Private copy constructor and operator=: 26th Feb 1998
18 // J.Marraffino - Added stream operators and related constructor.
19 // Added automatic seed selection from seed table and
20 // engine counter. Removed RAND_MAX and replaced by
21 // std::pow(0.5,32.). Flat() returns now 32 bits values
22 // obtained by concatenation: 15th Feb 1998
23 // Ken Smith - Added conversion operators: 6th Aug 1998
24 // J. Marraffino - Remove dependence on hepString class 13 May 1999
25 // M. Fischler - Rapaired bug that in flat() that relied on rand() to
26 // deliver 15-bit results. This bug was causing flat()
27 // on Linux systems to yield randoms with mean of 5/8(!)
28 // - Modified algorithm such that on systems with 31-bit rand()
29 // it will call rand() only once instead of twice. Feb 2004
30 // M. Fischler - Modified the general-case template for RandEngineBuilder
31 // such that when RAND_MAX is an unexpected value the routine
32 // will still deliver a sensible flat() random.
33 // M. Fischler - Methods for distrib. instance save/restore 12/8/04
34 // M. Fischler - split get() into tag validation and
35 // getState() for anonymous restores 12/27/04
36 // M. Fischler - put/get for vectors of ulongs 3/14/05
37 // M. Fischler - State-saving using only ints, for portability 4/12/05
38 //
39 // =======================================================================
40
41 #include "CLHEP/Random/defs.h"
42 #include "CLHEP/Random/RandEngine.h"
43 #include "CLHEP/Random/Random.h"
44 #include "CLHEP/Random/engineIDulong.h"
45 #include <string.h> // for strcmp
46 #include <cstdlib> // for int()
47
48 namespace CLHEP {
49
50 #ifdef NOTDEF
51 // The way to test for proper behavior of the RandEngineBuilder
52 // for arbitrary RAND_MAX, on a system where RAND_MAX is some
53 // fixed specialized value and rand() behaves accordingly, is
54 // to set up a fake RAND_MAX and a fake version of rand()
55 // by enabling this block.
56 #undef RAND_MAX
57 #define RAND_MAX 9382956
58 #include "CLHEP/Random/MTwistEngine.h"
59 #include "CLHEP/Random/RandFlat.h"
60 MTwistEngine * fakeFlat = new MTwistEngine;
61 RandFlat rflat (fakeFlat, 0, RAND_MAX+1);
rand()62 int rand() { return (int)rflat(); }
63 #endif
64
65 static const int MarkerLen = 64; // Enough room to hold a begin or end marker.
66
67 // number of instances with automatic seed selection
68 int RandEngine::numEngines = 0;
69
70 // Maximum index into the seed table
71 const int RandEngine::maxIndex = 215;
72
name() const73 std::string RandEngine::name() const {return "RandEngine";}
74
RandEngine(long seed)75 RandEngine::RandEngine(long seed)
76 : HepRandomEngine()
77 {
78 setSeed(seed,0);
79 setSeeds(&theSeed,0);
80 seq = 0;
81 }
82
RandEngine(int rowIndex,int colIndex)83 RandEngine::RandEngine(int rowIndex, int colIndex)
84 : HepRandomEngine()
85 {
86 long seeds[2];
87 long seed;
88
89 int cycle = std::abs(int(rowIndex/maxIndex));
90 int row = std::abs(int(rowIndex%maxIndex));
91 int col = std::abs(int(colIndex%2));
92 long mask = ((cycle & 0x000007ff) << 20 );
93 HepRandom::getTheTableSeeds( seeds, row );
94 seed = (seeds[col])^mask;
95 setSeed(seed,0);
96 setSeeds(&theSeed,0);
97 seq = 0;
98 }
99
RandEngine()100 RandEngine::RandEngine()
101 : HepRandomEngine()
102 {
103 long seeds[2];
104 long seed;
105 int cycle,curIndex;
106
107 cycle = std::abs(int(numEngines/maxIndex));
108 curIndex = std::abs(int(numEngines%maxIndex));
109 numEngines += 1;
110 long mask = ((cycle & 0x007fffff) << 8);
111 HepRandom::getTheTableSeeds( seeds, curIndex );
112 seed = seeds[0]^mask;
113 setSeed(seed,0);
114 setSeeds(&theSeed,0);
115 seq = 0;
116 }
117
RandEngine(std::istream & is)118 RandEngine::RandEngine(std::istream& is)
119 : HepRandomEngine()
120 {
121 is >> *this;
122 }
123
~RandEngine()124 RandEngine::~RandEngine() {}
125
setSeed(long seed,int)126 void RandEngine::setSeed(long seed, int)
127 {
128 theSeed = seed;
129 srand( int(seed) );
130 seq = 0;
131 }
132
setSeeds(const long * seeds,int)133 void RandEngine::setSeeds(const long* seeds, int)
134 {
135 setSeed(seeds ? *seeds : 19780503L, 0);
136 theSeeds = seeds;
137 }
138
saveStatus(const char filename[]) const139 void RandEngine::saveStatus( const char filename[] ) const
140 {
141 std::ofstream outFile( filename, std::ios::out ) ;
142
143 if (!outFile.bad()) {
144 outFile << "Uvec\n";
145 std::vector<unsigned long> v = put();
146 #ifdef TRACE_IO
147 std::cout << "Result of v = put() is:\n";
148 #endif
149 for (unsigned int i=0; i<v.size(); ++i) {
150 outFile << v[i] << "\n";
151 #ifdef TRACE_IO
152 std::cout << v[i] << " ";
153 if (i%6==0) std::cout << "\n";
154 #endif
155 }
156 #ifdef TRACE_IO
157 std::cout << "\n";
158 #endif
159 }
160 #ifdef REMOVED
161 if (!outFile.bad()) {
162 outFile << theSeed << std::endl;
163 outFile << seq << std::endl;
164 }
165 #endif
166 }
167
restoreStatus(const char filename[])168 void RandEngine::restoreStatus( const char filename[] )
169 {
170 // The only way to restore the status of RandEngine is to
171 // keep track of the number of shooted random sequences, reset
172 // the engine and re-shoot them again. The Rand algorithm does
173 // not provide any way of getting its internal status.
174
175 std::ifstream inFile( filename, std::ios::in);
176 if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) {
177 std::cout << " -- Engine state remains unchanged\n";
178 return;
179 }
180 if ( possibleKeywordInput ( inFile, "Uvec", theSeed ) ) {
181 std::vector<unsigned long> v;
182 unsigned long xin;
183 for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
184 inFile >> xin;
185 #ifdef TRACE_IO
186 std::cout << "ivec = " << ivec << " xin = " << xin << " ";
187 if (ivec%3 == 0) std::cout << "\n";
188 #endif
189 if (!inFile) {
190 inFile.clear(std::ios::badbit | inFile.rdstate());
191 std::cerr << "\nRandEngine state (vector) description improper."
192 << "\nrestoreStatus has failed."
193 << "\nInput stream is probably mispositioned now." << std::endl;
194 return;
195 }
196 v.push_back(xin);
197 }
198 getState(v);
199 return;
200 }
201
202 long count;
203
204 if (!inFile.bad() && !inFile.eof()) {
205 // inFile >> theSeed; removed -- encompased by possibleKeywordInput
206 inFile >> count;
207 setSeed(theSeed,0);
208 seq = 0;
209 while (seq < count) flat();
210 }
211 }
212
showStatus() const213 void RandEngine::showStatus() const
214 {
215 std::cout << std::endl;
216 std::cout << "---------- Rand engine status ----------" << std::endl;
217 std::cout << " Initial seed = " << theSeed << std::endl;
218 std::cout << " Shooted sequences = " << seq << std::endl;
219 std::cout << "----------------------------------------" << std::endl;
220 }
221
222 // ====================================================
223 // Implementation of flat() (along with needed helpers)
224 // ====================================================
225
226 // Here we set up such that **at compile time**, the compiler decides based on
227 // RAND_MAX how to form a random double with 32 leading random bits, using
228 // one or two calls to rand(). Some of the lowest order bits of 32 are allowed
229 // to be as weak as mere XORs of some higher bits, but not to be always fixed.
230 //
231 // The method decision is made at compile time, rather than using a run-time
232 // if on the value of RAND_MAX. Although it is possible to cope with arbitrary
233 // values of RAND_MAX of the form 2**N-1, with the same efficiency, the
234 // template techniques needed would look mysterious and perhaps over-stress
235 // some older compilers. We therefore only treat RAND_MAX = 2**15-1 (as on
236 // most older systems) and 2**31-1 (as on the later Linux systems) as special
237 // and super-efficient cases. We detect any different value, and use an
238 // algorithm which is correct even if RAND_MAX is not one less than a power
239 // of 2.
240
241 template <int> struct RandEngineBuilder { // RAND_MAX any arbitrary value
thirtyTwoRandomBitsCLHEP::RandEngineBuilder242 static unsigned int thirtyTwoRandomBits(long& seq) {
243
244 static bool prepared = false;
245 static unsigned int iT;
246 static unsigned int iK;
247 static unsigned int iS;
248 static int iN;
249 static double fS;
250 static double fT;
251
252 if ( (RAND_MAX >> 31) > 0 )
253 {
254 // Here, we know that integer arithmetic is 64 bits.
255 if ( !prepared ) {
256 iS = (unsigned long)RAND_MAX + 1;
257 iK = 1;
258 // int StoK = S;
259 int StoK = iS;
260 // The two statements below are equivalent, but some compilers
261 // are getting too smart and complain about the first statement.
262 //if ( (RAND_MAX >> 32) == 0) {
263 if( (unsigned long) (RAND_MAX) <= (( (1uL) << 31 ) - 1 ) ) {
264 iK = 2;
265 // StoK = S*S;
266 StoK = iS*iS;
267 }
268 int m;
269 for ( m = 0; m < 64; ++m ) {
270 StoK >>= 1;
271 if (StoK == 0) break;
272 }
273 iT = 1 << m;
274 prepared = true;
275 }
276 int v = 0;
277 do {
278 for ( int i = 0; i < iK; ++i ) {
279 v = iS*v+rand(); ++seq;
280 }
281 } while (v < iT);
282 return v & 0xFFFFFFFF;
283
284 }
285
286 else if ( (RAND_MAX >> 26) == 0 )
287 {
288 // Here, we know it is safe to work in terms of doubles without loss
289 // of precision, but we have no idea how many randoms we will need to
290 // generate 32 bits.
291 if ( !prepared ) {
292 fS = (unsigned long)RAND_MAX + 1;
293 double twoTo32 = std::ldexp(1.0,32);
294 double StoK = fS;
295 for ( iK = 1; StoK < twoTo32; StoK *= fS, iK++ ) { }
296 int m;
297 fT = 1.0;
298 for ( m = 0; m < 64; ++m ) {
299 StoK *= .5;
300 if (StoK < 1.0) break;
301 fT *= 2.0;
302 }
303 prepared = true;
304 }
305 double v = 0;
306 do {
307 for ( int i = 0; i < iK; ++i ) {
308 v = fS*v+rand(); ++seq;
309 }
310 } while (v < fT);
311 return ((unsigned int)v) & 0xFFFFFFFF;
312
313 }
314 else
315 {
316 // Here, we know that 16 random bits are available from each of
317 // two random numbers.
318 if ( !prepared ) {
319 iS = (unsigned long)RAND_MAX + 1;
320 int SshiftN = iS;
321 for (iN = 0; SshiftN > 1; SshiftN >>= 1, iN++) { }
322 iN -= 17;
323 prepared = true;
324 }
325 unsigned int x1, x2;
326 do { x1 = rand(); ++seq;} while (x1 < (1<<16) );
327 do { x2 = rand(); ++seq;} while (x2 < (1<<16) );
328 return x1 | (x2 << 16);
329 }
330
331 }
332 };
333
334 template <> struct RandEngineBuilder<2147483647> { // RAND_MAX = 2**31 - 1
thirtyTwoRandomBitsCLHEP::RandEngineBuilder335 inline static unsigned int thirtyTwoRandomBits(long& seq) {
336 unsigned int x = rand() << 1; ++seq; // bits 31-1
337 x ^= ( (x>>23) ^ (x>>7) ) ^1; // bit 0 (weakly pseudo-random)
338 return x & 0xFFFFFFFF; // mask in case int is 64 bits
339 }
340 };
341
342
343 template <> struct RandEngineBuilder<32767> { // RAND_MAX = 2**15 - 1
thirtyTwoRandomBitsCLHEP::RandEngineBuilder344 inline static unsigned int thirtyTwoRandomBits(long& seq) {
345 unsigned int x = rand() << 17; ++seq; // bits 31-17
346 x ^= rand() << 2; ++seq; // bits 16-2
347 x ^= ( (x>>23) ^ (x>>7) ) ^3; // bits 1-0 (weakly pseudo-random)
348 return x & 0xFFFFFFFF; // mask in case int is 64 bits
349 }
350 };
351
flat()352 double RandEngine::flat()
353 {
354 double r;
355 do { r = RandEngineBuilder<RAND_MAX>::thirtyTwoRandomBits(seq);
356 } while ( r == 0 );
357 return r/4294967296.0;
358 }
359
flatArray(const int size,double * vect)360 void RandEngine::flatArray(const int size, double* vect)
361 {
362 int i;
363
364 for (i=0; i<size; ++i)
365 vect[i]=flat();
366 }
367
operator double()368 RandEngine::operator double() {
369 return flat();
370 }
371
operator float()372 RandEngine::operator float() {
373 return float( flat() );
374 }
375
operator unsigned int()376 RandEngine::operator unsigned int() {
377 return RandEngineBuilder<RAND_MAX>::thirtyTwoRandomBits(seq);
378 }
379
put(std::ostream & os) const380 std::ostream & RandEngine::put ( std::ostream& os ) const
381 {
382 char beginMarker[] = "RandEngine-begin";
383 char endMarker[] = "RandEngine-end";
384
385 os << " " << beginMarker << "\n";
386 os << theSeed << " " << seq << " ";
387 os << endMarker << "\n";
388 return os;
389 }
390
put() const391 std::vector<unsigned long> RandEngine::put () const {
392 std::vector<unsigned long> v;
393 v.push_back (engineIDulong<RandEngine>());
394 v.push_back(static_cast<unsigned long>(theSeed));
395 v.push_back(static_cast<unsigned long>(seq));
396 return v;
397 }
398
get(std::istream & is)399 std::istream & RandEngine::get ( std::istream& is )
400 {
401 // The only way to restore the status of RandEngine is to
402 // keep track of the number of shooted random sequences, reset
403 // the engine and re-shoot them again. The Rand algorithm does
404 // not provide any way of getting its internal status.
405 char beginMarker [MarkerLen];
406 is >> std::ws;
407 is.width(MarkerLen); // causes the next read to the char* to be <=
408 // that many bytes, INCLUDING A TERMINATION \0
409 // (Stroustrup, section 21.3.2)
410 is >> beginMarker;
411 if (strcmp(beginMarker,"RandEngine-begin")) {
412 is.clear(std::ios::badbit | is.rdstate());
413 std::cout << "\nInput stream mispositioned or"
414 << "\nRandEngine state description missing or"
415 << "\nwrong engine type found." << std::endl;
416 return is;
417 }
418 return getState(is);
419 }
420
beginTag()421 std::string RandEngine::beginTag ( ) {
422 return "RandEngine-begin";
423 }
424
getState(std::istream & is)425 std::istream & RandEngine::getState ( std::istream& is )
426 {
427 if ( possibleKeywordInput ( is, "Uvec", theSeed ) ) {
428 std::vector<unsigned long> v;
429 unsigned long uu;
430 for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
431 is >> uu;
432 if (!is) {
433 is.clear(std::ios::badbit | is.rdstate());
434 std::cerr << "\nRandEngine state (vector) description improper."
435 << "\ngetState() has failed."
436 << "\nInput stream is probably mispositioned now." << std::endl;
437 return is;
438 }
439 v.push_back(uu);
440 }
441 getState(v);
442 return (is);
443 }
444
445 // is >> theSeed; Removed, encompassed by possibleKeywordInput()
446
447 char endMarker [MarkerLen];
448 long count;
449 is >> count;
450 is >> std::ws;
451 is.width(MarkerLen);
452 is >> endMarker;
453 if (strcmp(endMarker,"RandEngine-end")) {
454 is.clear(std::ios::badbit | is.rdstate());
455 std::cerr << "\nRandEngine state description incomplete."
456 << "\nInput stream is probably mispositioned now." << std::endl;
457 return is;
458 }
459 setSeed(theSeed,0);
460 while (seq < count) flat();
461 return is;
462 }
463
get(const std::vector<unsigned long> & v)464 bool RandEngine::get (const std::vector<unsigned long> & v) {
465 if ((v[0] & 0xffffffffUL) != engineIDulong<RandEngine>()) {
466 std::cerr <<
467 "\nRandEngine get:state vector has wrong ID word - state unchanged\n";
468 return false;
469 }
470 return getState(v);
471 }
472
getState(const std::vector<unsigned long> & v)473 bool RandEngine::getState (const std::vector<unsigned long> & v) {
474 if (v.size() != VECTOR_STATE_SIZE ) {
475 std::cerr <<
476 "\nRandEngine get:state vector has wrong length - state unchanged\n";
477 return false;
478 }
479 theSeed = v[1];
480 int count = v[2];
481 setSeed(theSeed,0);
482 while (seq < count) flat();
483 return true;
484 }
485 } // namespace CLHEP
486