Geant4  v4-10.4-release
 모두 클래스 네임스페이스들 파일들 함수 변수 타입정의 열거형 타입 열거형 멤버 Friends 매크로 그룹들 페이지들
DualRand.cc
이 파일의 문서화 페이지로 가기
1 // $Id:$
2 // -*- C++ -*-
3 //
4 // -----------------------------------------------------------------------
5 // Hep Random
6 // --- DualRand ---
7 // class implementation file
8 // -----------------------------------------------------------------------
9 // Exclusive or of a feedback shift register and integer congruence
10 // random number generator. The feedback shift register uses offsets
11 // 127 and 97. The integer congruence generator uses a different
12 // multiplier for each stream. The multipliers are chosen to give
13 // full period and maximum "potency" for modulo 2^32. The period of
14 // the combined random number generator is 2^159 - 2^32, and the
15 // sequences are different for each stream (not just started in a
16 // different place).
17 //
18 // In the original generator used on ACPMAPS:
19 // The feedback shift register generates 24 bits at a time, and
20 // the high order 24 bits of the integer congruence generator are
21 // used.
22 //
23 // Instead, to conform with more modern engine concepts, we generate
24 // 32 bits at a time and use the full 32 bits of the congruence
25 // generator.
26 //
27 // References:
28 // Knuth
29 // Tausworthe
30 // Golomb
31 //=========================================================================
32 // Ken Smith - Removed pow() from flat() method: 21 Jul 1998
33 // - Added conversion operators: 6 Aug 1998
34 // J. Marraffino - Added some explicit casts to deal with
35 // machines where sizeof(int) != sizeof(long) 22 Aug 1998
36 // M. Fischler - Modified constructors taking seeds to not
37 // depend on numEngines (same seeds should
38 // produce same sequences). Default still
39 // depends on numEngines. 14 Sep 1998
40 // - Modified use of the various exponents of 2
41 // to avoid per-instance space overhead and
42 // correct the rounding procedure 15 Sep 1998
43 // J. Marraffino - Remove dependence on hepString class 13 May 1999
44 // M. Fischler - Put endl at end of a save 10 Apr 2001
45 // M. Fischler - In restore, checkFile for file not found 03 Dec 2004
46 // M. Fischler - methods for distrib. instacne save/restore 12/8/04
47 // M. Fischler - split get() into tag validation and
48 // getState() for anonymous restores 12/27/04
49 // Mark Fischler - methods for vector save/restore 3/7/05
50 // M. Fischler - State-saving using only ints, for portability 4/12/05
51 //
52 //=========================================================================
53 
54 #include "CLHEP/Random/DualRand.h"
57 
58 #include <string.h> // for strcmp
59 
60 namespace CLHEP {
61 
62 namespace {
63  // Number of instances with automatic seed selection
64  CLHEP_ATOMIC_INT_TYPE numberOfEngines(0);
65 }
66 
67 static const int MarkerLen = 64; // Enough room to hold a begin or end marker.
68 
69 std::string DualRand::name() const {return "DualRand";}
70 
71 // The following constructors (excluding the istream constructor) fill
72 // the bits of the tausworthe and the starting state of the integer
73 // congruence based on the seed. In addition, it sets up the multiplier
74 // for the integer congruence based on the stream number, so you have
75 // absolutely independent streams.
76 
78 : HepRandomEngine(),
79  numEngines(numberOfEngines++),
80  tausworthe (1234567 + numEngines + 175321),
81  integerCong(69607 * tausworthe + 54329, numEngines)
82 {
83  theSeed = 1234567;
84 }
85 
87 : HepRandomEngine(),
88  numEngines(0),
89  tausworthe ((unsigned int)seed + 175321),
90  integerCong(69607 * tausworthe + 54329, 8043) // MF - not numEngines
91 {
92  theSeed = seed;
93 }
94 
95 DualRand::DualRand(std::istream & is)
96 : HepRandomEngine(),
97  numEngines(0)
98 {
99  is >> *this;
100 }
101 
102 DualRand::DualRand(int rowIndex, int colIndex)
103 : HepRandomEngine(),
104  numEngines(0),
105  tausworthe (rowIndex + 1000 * colIndex + 85329),
106  integerCong(69607 * tausworthe + 54329, 1123) // MF - not numengines
107 {
108  theSeed = rowIndex;
109 }
110 
112 
113 double DualRand::flat() {
114  unsigned int ic ( integerCong );
115  unsigned int t ( tausworthe );
116  return ( (t ^ ic) * twoToMinus_32() + // most significant part
117  (t >> 11) * twoToMinus_53() + // fill in remaining bits
118  nearlyTwoToMinus_54() // make sure non-zero
119  );
120 }
121 
122 void DualRand::flatArray(const int size, double* vect) {
123  for (int i = 0; i < size; ++i) {
124  vect[i] = flat();
125  }
126 }
127 
128 void DualRand::setSeed(long seed, int) {
129  theSeed = seed;
130  tausworthe = Tausworthe((unsigned int)seed + 175321);
131  integerCong = IntegerCong(69607 * tausworthe + 54329, 8043);
132 }
133 
134 void DualRand::setSeeds(const long * seeds, int) {
135  setSeed(seeds ? *seeds : 1234567, 0);
136  theSeeds = seeds;
137 }
138 
139 void DualRand::saveStatus(const char filename[]) const {
140  std::ofstream outFile(filename, std::ios::out);
141  if (!outFile.bad()) {
142  outFile << "Uvec\n";
143  std::vector<unsigned long> v = put();
144  for (unsigned int i=0; i<v.size(); ++i) {
145  outFile << v[i] << "\n";
146  }
147  }
148 }
149 
150 void DualRand::restoreStatus(const char filename[]) {
151  std::ifstream inFile(filename, std::ios::in);
152  if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) {
153  std::cerr << " -- Engine state remains unchanged\n";
154  return;
155  }
156  if ( possibleKeywordInput ( inFile, "Uvec", theSeed ) ) {
157  std::vector<unsigned long> v;
158  unsigned long xin;
159  for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
160  inFile >> xin;
161  if (!inFile) {
162  inFile.clear(std::ios::badbit | inFile.rdstate());
163  std::cerr << "\nDualRand state (vector) description improper."
164  << "\nrestoreStatus has failed."
165  << "\nInput stream is probably mispositioned now." << std::endl;
166  return;
167  }
168  v.push_back(xin);
169  }
170  getState(v);
171  return;
172  }
173 
174  if (!inFile.bad()) {
175 // inFile >> theSeed; removed -- encompased by possibleKeywordInput
176  tausworthe.get(inFile);
177  integerCong.get(inFile);
178  }
179 }
180 
181 void DualRand::showStatus() const {
182  int pr=std::cout.precision(20);
183  std::cout << std::endl;
184  std::cout << "-------- DualRand engine status ---------"
185  << std::endl;
186  std::cout << "Initial seed = " << theSeed << std::endl;
187  std::cout << "Tausworthe generator = " << std::endl;
188  tausworthe.put(std::cout);
189  std::cout << "\nIntegerCong generator = " << std::endl;
190  integerCong.put(std::cout);
191  std::cout << std::endl << "-----------------------------------------"
192  << std::endl;
193  std::cout.precision(pr);
194 }
195 
196 DualRand::operator double() {
197  return flat();
198 }
199 
200 DualRand::operator float() {
201  return (float) ( (integerCong ^ tausworthe) * twoToMinus_32()
202  + nearlyTwoToMinus_54() );
203  // add this so that zero never happens
204 }
205 
206 DualRand::operator unsigned int() {
207  return (integerCong ^ tausworthe) & 0xffffffff;
208 }
209 
210 std::ostream & DualRand::put(std::ostream & os) const {
211  char beginMarker[] = "DualRand-begin";
212  os << beginMarker << "\nUvec\n";
213  std::vector<unsigned long> v = put();
214  for (unsigned int i=0; i<v.size(); ++i) {
215  os << v[i] << "\n";
216  }
217  return os;
218 }
219 
220 std::vector<unsigned long> DualRand::put () const {
221  std::vector<unsigned long> v;
222  v.push_back (engineIDulong<DualRand>());
223  tausworthe.put(v);
224  integerCong.put(v);
225  return v;
226 }
227 
228 std::istream & DualRand::get(std::istream & is) {
229  char beginMarker [MarkerLen];
230  is >> std::ws;
231  is.width(MarkerLen); // causes the next read to the char* to be <=
232  // that many bytes, INCLUDING A TERMINATION \0
233  // (Stroustrup, section 21.3.2)
234  is >> beginMarker;
235  if (strcmp(beginMarker,"DualRand-begin")) {
236  is.clear(std::ios::badbit | is.rdstate());
237  std::cerr << "\nInput mispositioned or"
238  << "\nDualRand state description missing or"
239  << "\nwrong engine type found." << std::endl;
240  return is;
241  }
242  return getState(is);
243 }
244 
245 std::string DualRand::beginTag ( ) {
246  return "DualRand-begin";
247 }
248 
249 std::istream & DualRand::getState ( std::istream & is ) {
250  if ( possibleKeywordInput ( is, "Uvec", theSeed ) ) {
251  std::vector<unsigned long> v;
252  unsigned long uu;
253  for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
254  is >> uu;
255  if (!is) {
256  is.clear(std::ios::badbit | is.rdstate());
257  std::cerr << "\nDualRand state (vector) description improper."
258  << "\ngetState() has failed."
259  << "\nInput stream is probably mispositioned now." << std::endl;
260  return is;
261  }
262  v.push_back(uu);
263  }
264  getState(v);
265  return (is);
266  }
267 
268 // is >> theSeed; Removed, encompassed by possibleKeywordInput()
269 
270  char endMarker [MarkerLen];
271  tausworthe.get(is);
272  integerCong.get(is);
273  is >> std::ws;
274  is.width(MarkerLen);
275  is >> endMarker;
276  if (strcmp(endMarker,"DualRand-end")) {
277  is.clear(std::ios::badbit | is.rdstate());
278  std::cerr << "DualRand state description incomplete."
279  << "\nInput stream is probably mispositioned now." << std::endl;
280  return is;
281  }
282  return is;
283 }
284 
285 bool DualRand::get(const std::vector<unsigned long> & v) {
286  if ((v[0] & 0xffffffffUL) != engineIDulong<DualRand>()) {
287  std::cerr <<
288  "\nDualRand get:state vector has wrong ID word - state unchanged\n";
289  return false;
290  }
291  if (v.size() != VECTOR_STATE_SIZE) {
292  std::cerr << "\nDualRand get:state vector has wrong size: "
293  << v.size() << " - state unchanged\n";
294  return false;
295  }
296  return getState(v);
297 }
298 
299 bool DualRand::getState (const std::vector<unsigned long> & v) {
300  std::vector<unsigned long>::const_iterator iv = v.begin()+1;
301  if (!tausworthe.get(iv)) return false;
302  if (!integerCong.get(iv)) return false;
303  if (iv != v.end()) {
304  std::cerr <<
305  "\nDualRand get:state vector has wrong size: " << v.size()
306  << "\n Apparently " << iv-v.begin() << " words were consumed\n";
307  return false;
308  }
309  return true;
310 }
311 
313  words[0] = 1234567;
314  for (wordIndex = 1; wordIndex < 4; ++wordIndex) {
315  words[wordIndex] = 69607 * words[wordIndex-1] + 54329;
316  }
317 }
318 
320  words[0] = seed;
321  for (wordIndex = 1; wordIndex < 4; ++wordIndex) {
322  words[wordIndex] = 69607 * words[wordIndex-1] + 54329;
323  }
324 }
325 
326 DualRand::Tausworthe::operator unsigned int() {
327 
328 // Mathematically: Consider a sequence of bits b[n]. Repeatedly form
329 // b[0]' = b[127] ^ b[97]; b[n]' = b[n-1]. This sequence will have a very
330 // long period (2**127-1 according to Tausworthe's work).
331 
332 // The actual method used relies on the fact that the operations needed to
333 // form bit 0 for up to 96 iterations never depend on the results of the
334 // previous ones. So you can actually compute many bits at once. In fact
335 // you can compute 32 at once -- despite 127 - 97 < 32 -- but 24 was used in
336 // the method used in Canopy, where they wanted only single-precision float
337 // randoms. I will do 32 here.
338 
339 // When you do it this way, this looks disturbingly like the dread lagged XOR
340 // Fibonacci. And indeed, it is a lagged Fibonacii, F(4,3, op) with the op
341 // being the XOR of a combination of shifts of the two numbers. Although
342 // Tausworthe asserted excellent properties, I would be scared to death.
343 // However, the shifting and bit swapping really does randomize this in a
344 // serious way.
345 
346 // Statements have been made to the effect that shift register sequences fail
347 // the parking lot test because they achieve randomness by multiple foldings,
348 // and this produces a characteristic pattern. We observe that in this
349 // specific algorithm, which has a fairly long lever arm, the foldings become
350 // effectively random. This is evidenced by the fact that the generator
351 // does pass the Diehard tests, including the parking lot test.
352 
353 // To avoid shuffling of variables in memory, you either have to use circular
354 // pointers (and those give you ifs, which are also costly) or compute at least
355 // a few iterations at once. We do the latter. Although there is a possible
356 // trade of room for more speed, by computing and saving 256 instead of 128
357 // bits at once, I will stop at this level of optimization.
358 
359 // To remind: Each (32-bit) step takes the XOR of bits [127-96] with bits
360 // [95-64] and places it in bits [0-31]. But in the first step, we designate
361 // word0 as bits [0-31], in the second step, word 1 (since the bits it holds
362 // will no longer be needed), then word 2, then word 3. After this, the
363 // stream contains 128 random bits which we will use as 4 valid 32-bit
364 // random numbers.
365 
366 // Thus at the start of the first step, word[0] contains the newest (used)
367 // 32-bit random, and word[3] the oldest. After four steps, word[0] again
368 // contains the newest (now unused) random, and word[3] the oldest.
369 // Bit 0 of word[0] is logically the newest bit, and bit 31 of word[3]
370 // the oldest.
371 
372  if (wordIndex <= 0) {
373  for (wordIndex = 0; wordIndex < 4; ++wordIndex) {
374  words[wordIndex] = ( (words[(wordIndex+1) & 3] << 1 ) |
375  (words[wordIndex] >> 31) )
376  ^ ( (words[(wordIndex+1) & 3] << 31) |
377  (words[wordIndex] >> 1) );
378  }
379  }
380  return words[--wordIndex] & 0xffffffff;
381 }
382 
383 void DualRand::Tausworthe::put(std::ostream & os) const {
384  char beginMarker[] = "Tausworthe-begin";
385  char endMarker[] = "Tausworthe-end";
386 
387  int pr=os.precision(20);
388  os << " " << beginMarker << " ";
389  for (int i = 0; i < 4; ++i) {
390  os << words[i] << " ";
391  }
392  os << wordIndex;
393  os << " " << endMarker << " ";
394  os << std::endl;
395  os.precision(pr);
396 }
397 
398 void DualRand::Tausworthe::put(std::vector<unsigned long> & v) const {
399  for (int i = 0; i < 4; ++i) {
400  v.push_back(static_cast<unsigned long>(words[i]));
401  }
402  v.push_back(static_cast<unsigned long>(wordIndex));
403 }
404 
405 void DualRand::Tausworthe::get(std::istream & is) {
406  char beginMarker [MarkerLen];
407  char endMarker [MarkerLen];
408 
409  is >> std::ws;
410  is.width(MarkerLen); // causes the next read to the char* to be <=
411  // that many bytes, INCLUDING A TERMINATION \0
412  // (Stroustrup, section 21.3.2)
413  is >> beginMarker;
414  if (strcmp(beginMarker,"Tausworthe-begin")) {
415  is.clear(std::ios::badbit | is.rdstate());
416  std::cerr << "\nInput mispositioned or"
417  << "\nTausworthe state description missing or"
418  << "\nwrong engine type found." << std::endl;
419  }
420  for (int i = 0; i < 4; ++i) {
421  is >> words[i];
422  }
423  is >> wordIndex;
424  is >> std::ws;
425  is.width(MarkerLen);
426  is >> endMarker;
427  if (strcmp(endMarker,"Tausworthe-end")) {
428  is.clear(std::ios::badbit | is.rdstate());
429  std::cerr << "\nTausworthe state description incomplete."
430  << "\nInput stream is probably mispositioned now." << std::endl;
431  }
432 }
433 
434 bool
435 DualRand::Tausworthe::get(std::vector<unsigned long>::const_iterator & iv){
436  for (int i = 0; i < 4; ++i) {
437  words[i] = *iv++;
438  }
439  wordIndex = *iv++;
440  return true;
441 }
442 
444 : state((unsigned int)3758656018U),
445  multiplier(66565),
446  addend(12341)
447 {
448 }
449 
450 DualRand::IntegerCong::IntegerCong(unsigned int seed, int streamNumber)
451 : state(seed),
452  multiplier(65536 + 1024 + 5 + (8 * 1017 * streamNumber)),
453  addend(12341)
454 {
455  // As to the multiplier, the following comment was made:
456  // We want our multipliers larger than 2^16, and equal to
457  // 1 mod 4 (for max. period), but not equal to 1 mod 8
458  // (for max. potency -- the smaller and higher dimension the
459  // stripes, the better)
460 
461  // All of these will have fairly long periods. Depending on the choice
462  // of stream number, some of these will be quite decent when considered
463  // as independent random engines, while others will be poor. Thus these
464  // should not be used as stand-alone engines; but when combined with a
465  // generator known to be good, they allow creation of millions of good
466  // independent streams, without fear of two streams accidentally hitting
467  // nearby places in the good random sequence.
468 }
469 
470 DualRand::IntegerCong::operator unsigned int() {
471  return state = (state * multiplier + addend) & 0xffffffff;
472 }
473 
474 void DualRand::IntegerCong::put(std::ostream & os) const {
475  char beginMarker[] = "IntegerCong-begin";
476  char endMarker[] = "IntegerCong-end";
477 
478  int pr=os.precision(20);
479  os << " " << beginMarker << " ";
480  os << state << " " << multiplier << " " << addend;
481  os << " " << endMarker << " ";
482  os << std::endl;
483  os.precision(pr);
484 }
485 
486 void DualRand::IntegerCong::put(std::vector<unsigned long> & v) const {
487  v.push_back(static_cast<unsigned long>(state));
488  v.push_back(static_cast<unsigned long>(multiplier));
489  v.push_back(static_cast<unsigned long>(addend));
490 }
491 
492 void DualRand::IntegerCong::get(std::istream & is) {
493  char beginMarker [MarkerLen];
494  char endMarker [MarkerLen];
495 
496  is >> std::ws;
497  is.width(MarkerLen); // causes the next read to the char* to be <=
498  // that many bytes, INCLUDING A TERMINATION \0
499  // (Stroustrup, section 21.3.2)
500  is >> beginMarker;
501  if (strcmp(beginMarker,"IntegerCong-begin")) {
502  is.clear(std::ios::badbit | is.rdstate());
503  std::cerr << "\nInput mispositioned or"
504  << "\nIntegerCong state description missing or"
505  << "\nwrong engine type found." << std::endl;
506  }
507  is >> state >> multiplier >> addend;
508  is >> std::ws;
509  is.width(MarkerLen);
510  is >> endMarker;
511  if (strcmp(endMarker,"IntegerCong-end")) {
512  is.clear(std::ios::badbit | is.rdstate());
513  std::cerr << "\nIntegerCong state description incomplete."
514  << "\nInput stream is probably mispositioned now." << std::endl;
515  }
516 }
517 
518 bool
519 DualRand::IntegerCong::get(std::vector<unsigned long>::const_iterator & iv) {
520  state = *iv++;
521  multiplier = *iv++;
522  addend = *iv++;
523  return true;
524 }
525 
526 } // namespace CLHEP
bool possibleKeywordInput(IS &is, const std::string &key, T &t)
Definition: RandomEngine.h:167
virtual ~DualRand()
Definition: DualRand.cc:111
void flatArray(const int size, double *vect)
Definition: DualRand.cc:122
static std::string engineName()
Definition: DualRand.h:97
void restoreStatus(const char filename[]="DualRand.conf")
Definition: DualRand.cc:150
void put(std::ostream &os) const
Definition: DualRand.cc:474
static double nearlyTwoToMinus_54()
void get(std::istream &is)
Definition: DualRand.cc:492
void saveStatus(const char filename[]="DualRand.conf") const
Definition: DualRand.cc:139
static double twoToMinus_32()
virtual std::istream & get(std::istream &is)
Definition: DualRand.cc:228
double flat()
Definition: DualRand.cc:113
unsigned int words[4]
Definition: DualRand.h:120
static std::string beginTag()
Definition: DualRand.cc:245
static const int MarkerLen
Definition: DualRand.cc:67
virtual std::istream & getState(std::istream &is)
Definition: DualRand.cc:249
long seed
Definition: chem4.cc:68
std::vector< unsigned long > put() const
Definition: DualRand.cc:220
static const unsigned int VECTOR_STATE_SIZE
Definition: DualRand.h:103
#define CLHEP_ATOMIC_INT_TYPE
Definition: atomic_int.h:20
typedef int(XMLCALL *XML_NotStandaloneHandler)(void *userData)
void put(std::ostream &os) const
Definition: DualRand.cc:383
void setSeeds(const long *seeds, int)
Definition: DualRand.cc:134
Tausworthe tausworthe
Definition: DualRand.h:137
void showStatus() const
Definition: DualRand.cc:181
static double twoToMinus_53()
static bool checkFile(std::istream &file, const std::string &filename, const std::string &classname, const std::string &methodname)
Definition: RandomEngine.cc:45
IntegerCong integerCong
Definition: DualRand.h:138
ifstream in
Definition: comparison.C:7
std::string name() const
Definition: DualRand.cc:69
void setSeed(long seed, int)
Definition: DualRand.cc:128
void get(std::istream &is)
Definition: DualRand.cc:405
double flat()
Definition: G4AblaRandom.cc:48