1 // $Id: Hurd288Engine.cc,v 1.7 2010/07/20 18:07:17 garren Exp $
2 // -*- C++ -*-
3 //
4 // -----------------------------------------------------------------------
5 // HEP Random
6 // --- Hurd288Engine ---
7 // class implementation file
8 // -----------------------------------------------------------------------
9 // An interconnected shift register based on the paper presented by Hurd in
10 // IEEE Transactions on Computers c23, 2 Feb 1974.
11 // =======================================================================
12 // Ken Smith - Initial draft started: 23rd Jul 1998
13 // - Added conversion operators: 6th Aug 1998
14 // J. Marraffino - Added some explicit casts to deal with
15 // machines where sizeof(int) != sizeof(long) 22 Aug 1998
16 // M. Fischler - Modified use of the various exponents of 2
17 // to avoid per-instance space overhead and
18 // correct the rounding procedure 15 Sep 1998
19 // - Modified various methods to avoid any
20 // possibility of predicting the next number
21 // based on the last several: We skip one
22 // 32-bit word per cycle. 15 Sep 1998
23 // - modify word[0] in two of the constructors
24 // so that no sequence can ever accidentally
25 // be produced by differnt seeds. 15 Sep 1998
26 // J. Marraffino - Remove dependence on hepString class 13 May 1999
27 // M. Fischler - Put endl at end of a save 10 Apr 2001
28 // M. Fischler - In restore, checkFile for file not found 03 Dec 2004
29 // M. Fischler - methods for distrib. instacne save/restore 12/8/04
30 // M. Fischler - split get() into tag validation and
31 // getState() for anonymous restores 12/27/04
32 // M. Fischler - put/get for vectors of ulongs 3/14/05
33 // M. Fischler - State-saving using only ints, for portability 4/12/05
34 //
35 // =======================================================================
36
37 #include "CLHEP/Random/defs.h"
38 #include "CLHEP/Random/Random.h"
39 #include "CLHEP/Random/Hurd288Engine.h"
40 #include "CLHEP/Random/engineIDulong.h"
41 #include "CLHEP/Utility/atomic_int.h"
42
43 #include <string.h> // for strcmp
44 #include <cstdlib> // for std::abs(int)
45
46 using namespace std;
47
48 namespace CLHEP {
49
50 namespace {
51 // Number of instances with automatic seed selection
52 CLHEP_ATOMIC_INT_TYPE numberOfEngines(0);
53
54 // Maximum index into the seed table
55 const int maxIndex = 215;
56 }
57
58 static const int MarkerLen = 64; // Enough room to hold a begin or end marker.
59
name() const60 std::string Hurd288Engine::name() const {return "Hurd288Engine";}
61
f288(unsigned int a,unsigned int b,unsigned int c)62 static inline unsigned int f288(unsigned int a, unsigned int b, unsigned int c)
63 {
64 return ( ((b<<2) & 0x7ffc) | ((a<<2) & ~0x7ffc) | (a>>30) ) ^
65 ( (c<<1)|(c>>31) );
66 }
67
Hurd288Engine()68 Hurd288Engine::Hurd288Engine()
69 : HepRandomEngine()
70 {
71 int numEngines = numberOfEngines++;
72 int cycle = std::abs(int(numEngines/maxIndex));
73 int curIndex = std::abs(int(numEngines%maxIndex));
74 long mask = ((cycle & 0x007fffff) << 8);
75 long seedlist[2];
76 HepRandom::getTheTableSeeds( seedlist, curIndex );
77 seedlist[0] ^= mask;
78 seedlist[1] = 0;
79 setSeeds(seedlist, 0);
80 words[0] ^= 0x1324abcd; // To make unique vs long or two unsigned
81 if (words[0]==0) words[0] = 1; // ints in the constructor
82
83 for( int i=0; i < 100; ++i ) flat(); // warm up just a bit
84 }
85
Hurd288Engine(std::istream & is)86 Hurd288Engine::Hurd288Engine( std::istream& is )
87 : HepRandomEngine()
88 {
89 is >> *this;
90 }
91
Hurd288Engine(long seed)92 Hurd288Engine::Hurd288Engine( long seed )
93 : HepRandomEngine()
94 {
95 long seedlist[2]={seed,0};
96 setSeeds(seedlist, 0);
97 words[0] ^= 0xa5482134; // To make unique vs default two unsigned
98 if (words[0]==0) words[0] = 1; // ints in the constructor
99 for( int i=0; i < 100; ++i ) flat(); // warm up just a bit
100 }
101
Hurd288Engine(int rowIndex,int colIndex)102 Hurd288Engine::Hurd288Engine( int rowIndex, int colIndex )
103 : HepRandomEngine()
104 {
105 int cycle = std::abs(int(rowIndex/maxIndex));
106 int row = std::abs(int(rowIndex%maxIndex));
107 int col = colIndex & 0x1;
108 long mask = (( cycle & 0x000007ff ) << 20 );
109 long seedlist[2];
110 HepRandom::getTheTableSeeds( seedlist, row );
111 seedlist[0] = (seedlist[col])^mask;
112 seedlist[1]= 0;
113 setSeeds(seedlist, 0);
114 for( int i=0; i < 100; ++i ) flat(); // warm up just a bit
115 }
116
~Hurd288Engine()117 Hurd288Engine::~Hurd288Engine() { }
118
advance()119 void Hurd288Engine::advance() {
120
121 unsigned int W0, W1, W2, W3, W4, W5, W6, W7, W8;
122
123 W0 = words[0];
124 W1 = words[1];
125 W2 = words[2];
126 W3 = words[3];
127 W4 = words[4];
128 W5 = words[5];
129 W6 = words[6];
130 W7 = words[7];
131 W8 = words[8];
132 W1 ^= W0; W0 = f288(W2, W3, W0);
133 W2 ^= W1; W1 = f288(W3, W4, W1);
134 W3 ^= W2; W2 = f288(W4, W5, W2);
135 W4 ^= W3; W3 = f288(W5, W6, W3);
136 W5 ^= W4; W4 = f288(W6, W7, W4);
137 W6 ^= W5; W5 = f288(W7, W8, W5);
138 W7 ^= W6; W6 = f288(W8, W0, W6);
139 W8 ^= W7; W7 = f288(W0, W1, W7);
140 W0 ^= W8; W8 = f288(W1, W2, W8);
141 words[0] = W0 & 0xffffffff;
142 words[1] = W1 & 0xffffffff;
143 words[2] = W2 & 0xffffffff;
144 words[3] = W3 & 0xffffffff;
145 words[4] = W4 & 0xffffffff;
146 words[5] = W5 & 0xffffffff;
147 words[6] = W6 & 0xffffffff;
148 words[7] = W7 & 0xffffffff;
149 words[8] = W8 & 0xffffffff;
150 wordIndex = 9;
151
152 } // advance()
153
154
flat()155 double Hurd288Engine::flat() {
156
157 if( wordIndex <= 2 ) { // MF 9/15/98:
158 // skip word 0 and use two words per flat
159 advance();
160 }
161
162 // LG 6/30/2010
163 // define the order of execution for --wordIndex
164 double x = words[--wordIndex] * twoToMinus_32() ; // most significant part
165 double y = (words[--wordIndex]>>11) * twoToMinus_53() + // fill in rest of bits
166 nearlyTwoToMinus_54(); // make sure non-zero
167 return x + y;
168 }
169
flatArray(const int size,double * vect)170 void Hurd288Engine::flatArray( const int size, double* vect ) {
171 for (int i = 0; i < size; ++i) {
172 vect[i] = flat();
173 }
174 }
175
setSeed(long seed,int)176 void Hurd288Engine::setSeed( long seed, int ) {
177 words[0] = (unsigned int)seed;
178 for (wordIndex = 1; wordIndex < 9; ++wordIndex) {
179 words[wordIndex] = 69607 * words[wordIndex-1] + 54329;
180 }
181 }
182
setSeeds(const long * seeds,int)183 void Hurd288Engine::setSeeds( const long* seeds, int ) {
184 setSeed( *seeds ? *seeds : 32767, 0 );
185 theSeeds = seeds;
186 }
187
saveStatus(const char filename[]) const188 void Hurd288Engine::saveStatus( const char filename[] ) const {
189 std::ofstream outFile(filename, std::ios::out);
190 if( !outFile.bad() ) {
191 outFile << "Uvec\n";
192 std::vector<unsigned long> v = put();
193 #ifdef TRACE_IO
194 std::cout << "Result of v = put() is:\n";
195 #endif
196 for (unsigned int i=0; i<v.size(); ++i) {
197 outFile << v[i] << "\n";
198 #ifdef TRACE_IO
199 std::cout << v[i] << " ";
200 if (i%6==0) std::cout << "\n";
201 #endif
202 }
203 #ifdef TRACE_IO
204 std::cout << "\n";
205 #endif
206 }
207 #ifdef REMOVED
208 outFile << std::setprecision(20) << theSeed << " ";
209 outFile << wordIndex << " ";
210 for( int i = 0; i < 9; ++i ) {
211 outFile << words[i] << " ";
212 }
213 outFile << std::endl;
214 #endif
215 }
216
restoreStatus(const char filename[])217 void Hurd288Engine::restoreStatus( const char filename[] ) {
218 std::ifstream inFile(filename, std::ios::in);
219 if (!checkFile ( inFile, filename, engineName(), "restoreStatus" )) {
220 std::cerr << " -- Engine state remains unchanged\n";
221 return;
222 }
223 if ( possibleKeywordInput ( inFile, "Uvec", theSeed ) ) {
224 std::vector<unsigned long> v;
225 unsigned long xin;
226 for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
227 inFile >> xin;
228 #ifdef TRACE_IO
229 std::cout << "ivec = " << ivec << " xin = " << xin << " ";
230 if (ivec%3 == 0) std::cout << "\n";
231 #endif
232 if (!inFile) {
233 inFile.clear(std::ios::badbit | inFile.rdstate());
234 std::cerr << "\nHurd288Engine state (vector) description improper."
235 << "\nrestoreStatus has failed."
236 << "\nInput stream is probably mispositioned now." << std::endl;
237 return;
238 }
239 v.push_back(xin);
240 }
241 getState(v);
242 return;
243 }
244
245 if( !inFile.bad() ) {
246 // inFile >> theSeed; removed -- encompased by possibleKeywordInput
247 inFile >> wordIndex;
248 for( int i = 0; i < 9; ++i ) {
249 inFile >> words[i];
250 }
251 }
252 }
253
showStatus() const254 void Hurd288Engine::showStatus() const {
255 std::cout << std::setprecision(20) << std::endl;
256 std::cout << "----------- Hurd2 engine status ----------" << std::endl;
257 std::cout << "Initial seed = " << theSeed << std::endl;
258 std::cout << "Current index = " << wordIndex << std::endl;
259 std::cout << "Current words = " << std::endl;
260 for( int i = 0; i < 9 ; ++i ) {
261 std::cout << " " << words[i] << std::endl;
262 }
263 std::cout << "-------------------------------------------" << std::endl;
264 }
265
operator double()266 Hurd288Engine::operator double() {
267 return flat();
268 }
269
operator float()270 Hurd288Engine::operator float() {
271 if( wordIndex <= 1 ) { // MF 9/15/98: skip word 0
272 advance();
273 }
274 return words[--wordIndex ] * twoToMinus_32();
275 }
276
operator unsigned int()277 Hurd288Engine::operator unsigned int() {
278 if( wordIndex <= 1 ) { // MF 9/15/98: skip word 0
279 advance();
280 }
281 return words[--wordIndex];
282 }
283
put(std::ostream & os) const284 std::ostream& Hurd288Engine::put(std::ostream& os) const {
285 char beginMarker[] = "Hurd288Engine-begin";
286 os << beginMarker << "\nUvec\n";
287 std::vector<unsigned long> v = put();
288 for (unsigned int i=0; i<v.size(); ++i) {
289 os << v[i] << "\n";
290 }
291 return os;
292 #ifdef REMOVED
293 char endMarker[] = "Hurd288Engine-end";
294 int pr = os.precision(20);
295 os << " " << beginMarker << " ";
296 os << theSeed << " ";
297 os << wordIndex << " ";
298 for (int i = 0; i < 9; ++i) {
299 os << words[i] << "\n";
300 }
301 os << endMarker << "\n ";
302 os.precision(pr);
303 return os;
304 #endif
305 }
306
put() const307 std::vector<unsigned long> Hurd288Engine::put () const {
308 std::vector<unsigned long> v;
309 v.push_back (engineIDulong<Hurd288Engine>());
310 v.push_back(static_cast<unsigned long>(wordIndex));
311 for (int i = 0; i < 9; ++i) {
312 v.push_back(static_cast<unsigned long>(words[i]));
313 }
314 return v;
315 }
316
317
get(std::istream & is)318 std::istream& Hurd288Engine::get(std::istream& is) {
319 char beginMarker [MarkerLen];
320 is >> std::ws;
321 is.width(MarkerLen); // causes the next read to the char* to be <=
322 // that many bytes, INCLUDING A TERMINATION \0
323 // (Stroustrup, section 21.3.2)
324 is >> beginMarker;
325 if (strcmp(beginMarker,"Hurd288Engine-begin")) {
326 is.clear(std::ios::badbit | is.rdstate());
327 std::cerr << "\nInput mispositioned or"
328 << "\nHurd288Engine state description missing or"
329 << "\nwrong engine type found." << std::endl;
330 return is;
331 }
332 return getState(is);
333 }
334
beginTag()335 std::string Hurd288Engine::beginTag ( ) {
336 return "Hurd288Engine-begin";
337 }
338
getState(std::istream & is)339 std::istream& Hurd288Engine::getState(std::istream& is) {
340 if ( possibleKeywordInput ( is, "Uvec", theSeed ) ) {
341 std::vector<unsigned long> v;
342 unsigned long uu;
343 for (unsigned int ivec=0; ivec < VECTOR_STATE_SIZE; ++ivec) {
344 is >> uu;
345 if (!is) {
346 is.clear(std::ios::badbit | is.rdstate());
347 std::cerr << "\nHurd288Engine state (vector) description improper."
348 << "\ngetState() has failed."
349 << "\nInput stream is probably mispositioned now." << std::endl;
350 return is;
351 }
352 v.push_back(uu);
353 }
354 getState(v);
355 return (is);
356 }
357
358 // is >> theSeed; Removed, encompassed by possibleKeywordInput()
359
360 char endMarker [MarkerLen];
361 is >> wordIndex;
362 for (int i = 0; i < 9; ++i) {
363 is >> words[i];
364 }
365 is >> std::ws;
366 is.width(MarkerLen);
367 is >> endMarker;
368 if (strcmp(endMarker,"Hurd288Engine-end")) {
369 is.clear(std::ios::badbit | is.rdstate());
370 std::cerr << "\nHurd288Engine state description incomplete."
371 << "\nInput stream is probably mispositioned now." << std::endl;
372 return is;
373 }
374 return is;
375 }
376
get(const std::vector<unsigned long> & v)377 bool Hurd288Engine::get (const std::vector<unsigned long> & v) {
378 if ((v[0] & 0xffffffffUL) != engineIDulong<Hurd288Engine>()) {
379 std::cerr <<
380 "\nHurd288Engine get:state vector has wrong ID word - state unchanged\n";
381 std::cerr << "The correct ID would be " << engineIDulong<Hurd288Engine>()
382 << "; the actual ID is " << v[0] << "\n";
383 return false;
384 }
385 return getState(v);
386 }
387
getState(const std::vector<unsigned long> & v)388 bool Hurd288Engine::getState (const std::vector<unsigned long> & v) {
389 if (v.size() != VECTOR_STATE_SIZE ) {
390 std::cerr <<
391 "\nHurd288Engine get:state vector has wrong length - state unchanged\n";
392 return false;
393 }
394 wordIndex = v[1];
395 for (int i = 0; i < 9; ++i) {
396 words[i] = v[i+2];
397 }
398 return true;
399 }
400
401 } // namespace CLHEP
402