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