NAMD
Random.h
Go to the documentation of this file.
1 
7 /*
8  * Copyright (c) 1993 Martin Birgmeier
9  * All rights reserved.
10  *
11  * You may redistribute unmodified or modified versions of this source
12  * code provided that the above copyright notice and this and the
13  * following conditions are retained.
14  *
15  * This software is provided ``as is'', and comes with no warranties
16  * of any kind. I shall in no event be liable for anything that happens
17  * to anyone/anything when using this software.
18  */
19 
20 #ifndef RANDOM_H
21 #define RANDOM_H
22 
23 #include "common.h"
24 #include "Vector.h"
25 
26 #ifdef _MSC_VER
27 #define UINT64_LITERAL(X) X ## ui64
28 #else
29 #define UINT64_LITERAL(X) X ## ULL
30 #endif
31 
32 #define RAND48_SEED UINT64_LITERAL(0x00001234abcd330e)
33 #define RAND48_MULT UINT64_LITERAL(0x00000005deece66d)
34 #define RAND48_ADD UINT64_LITERAL(0x000000000000000b)
35 #define RAND48_MASK UINT64_LITERAL(0x0000ffffffffffff)
36 
37 class Random {
38 
39 private:
40 
41  double second_gaussian;
42  uint64_t second_gaussian_waiting;
43  uint64_t rand48_seed;
44  uint64_t rand48_mult;
45  uint64_t rand48_add;
46 
47 public:
48 
49  // default constructor
50  Random(void) {
51  init(0);
52  rand48_seed = RAND48_SEED;
53  }
54 
55  // constructor with seed
56  Random(unsigned long seed) {
57  init(seed);
58  }
59 
60  // reinitialize with seed
61  void init(unsigned long seed) {
62  second_gaussian = 0;
63  second_gaussian_waiting = 0;
64  rand48_seed = seed & UINT64_LITERAL(0x00000000ffffffff);
65  rand48_seed = rand48_seed << 16;
66  rand48_seed |= RAND48_SEED & UINT64_LITERAL(0x0000ffff);
67  rand48_mult = RAND48_MULT;
68  rand48_add = RAND48_ADD;
69  }
70 
71  // advance generator by one (seed = seed * mult + add, to 48 bits)
72  void skip(void) {
73  rand48_seed = ( rand48_seed * rand48_mult + rand48_add ) & RAND48_MASK;
74  }
75 
76  // split into numStreams different steams and take stream iStream
77  void split(int iStream, int numStreams) {
78 
79  int i;
80 
81  // make sure that numStreams is odd to ensure maximum period
82  numStreams |= 1;
83 
84  // iterate to get to the correct stream
85  for ( i = 0; i < iStream; ++i ) skip();
86 
87  // save seed and add so we can use skip() for our calculations
88  uint64_t save_seed = rand48_seed;
89 
90  // calculate c *= ( 1 + a + ... + a^(numStreams-1) )
91  rand48_seed = rand48_add;
92  for ( i = 1; i < numStreams; ++i ) skip();
93  uint64_t new_add = rand48_seed;
94 
95  // calculate a = a^numStreams
96  rand48_seed = rand48_mult;
97  rand48_add = 0;
98  for ( i = 1; i < numStreams; ++i ) skip();
99  rand48_mult = rand48_seed;
100 
101  rand48_add = new_add;
102  rand48_seed = save_seed;
103 
104  second_gaussian = 0;
105  second_gaussian_waiting = 0;
106  }
107 
108  // return a number uniformly distributed between 0 and 1
109  BigReal uniform(void) {
110  skip();
111  const double exp48 = ( 1.0 / (double)(UINT64_LITERAL(1) << 48) );
112  return ( (double) rand48_seed * exp48 );
113  }
114 
115  // return a number from a standard gaussian distribution
117  BigReal fac, r, v1, v2;
118 
119  if (second_gaussian_waiting) {
120  second_gaussian_waiting = 0;
121  return second_gaussian;
122  } else {
123  r = 2.; // r >= 1.523e-8 ensures abs result < 6
124  while (r >=1. || r < 1.523e-8) { // make sure we are within unit circle
125  v1 = 2.0 * uniform() - 1.0;
126  v2 = 2.0 * uniform() - 1.0;
127  r = v1*v1 + v2*v2;
128  }
129  fac = sqrt(-2.0 * log(r)/r);
130  // now make the Box-Muller transformation to get two normally
131  // distributed random numbers. Save one and return the other.
132  second_gaussian_waiting = 1;
133  second_gaussian = v1 * fac;
134  return v2 * fac;
135  }
136  }
137 
178  BigReal sum_of_squared_gaussians(int64_t num_gaussians) {
179  BigReal z, u, v;
180 
181  if (num_gaussians <= 2) {
182  v = 0.0;
183  for(int i=0; i<num_gaussians; ++i) {
184  z = gaussian();
185  v += z*z;
186  }
187  return v;
188  } else if (2 < num_gaussians && num_gaussians <= 200) {
189  const BigReal d = 0.5*num_gaussians - 1./3;
190  const BigReal c = 1. / (3*sqrt(d));
191  const BigReal zmin = -1. / c;
192  do {
193  do {
194  z = gaussian();
195  }
196  while(z <= zmin);
197  u = uniform();
198  v = (1 + c*z); v = v*v*v; // v = (1 + c*z)^3
199  }
200  while(log(u) >= (0.5*z*z + d*(1 - v + log(v))));
201  return 2*d*v;
202  } else {
203  return num_gaussians + sqrt(2*num_gaussians)*gaussian();
204  }
205  }
206 
207  // return a vector of gaussian random numbers
209  return Vector( gaussian(), gaussian(), gaussian() );
210  }
211 
212  // return a random long
213  // signed int32 ranges from 0 to (2^31)-1
214  long integer(void) {
215  skip();
216  return ( ( rand48_seed >> 17 ) & UINT64_LITERAL(0x000000007fffffff) );
217  }
218 
219  // randomly order an array of whatever
220  template <class Elem> void reorder(Elem *a, int n) {
221  for ( int i = 0; i < (n-1); ++i ) {
222  int ie = i + ( integer() % (n-i) );
223  if ( ie == i ) continue;
224  const Elem e = a[ie];
225  a[ie] = a[i];
226  a[i] = e;
227  }
228  }
229 
233  void uniform_array_f(float *a, int n) {
234  // for now just call uniform()
235  // ultimately we will provide faster implementation
236  for (int i=0; i < n; i++) {
237  a[i] = (float)uniform();
238  }
239  }
240 
244  void gaussian_array_f(float *a, int n) {
245  // for now just call gaussian()
246  // ultimately we will provide faster implementation
247  for (int i=0; i < n; i++) {
248  a[i] = (float)gaussian();
249  }
250  }
251 
252 };
253 
254 #endif // RANDOM_H
255 
Vector gaussian_vector(void)
Definition: Random.h:208
BigReal uniform(void)
Definition: Random.h:109
BigReal gaussian(void)
Definition: Random.h:116
Random(void)
Definition: Random.h:50
void skip(void)
Definition: Random.h:72
Definition: Vector.h:64
BigReal sum_of_squared_gaussians(int64_t num_gaussians)
Return the sum of i.i.d. squared Gaussians.
Definition: Random.h:178
void uniform_array_f(float *a, int n)
Definition: Random.h:233
void split(int iStream, int numStreams)
Definition: Random.h:77
void reorder(Elem *a, int n)
Definition: Random.h:220
#define RAND48_ADD
Definition: Random.h:34
void init(unsigned long seed)
Definition: Random.h:61
Definition: Random.h:37
long integer(void)
Definition: Random.h:214
Random(unsigned long seed)
Definition: Random.h:56
gridSize z
void gaussian_array_f(float *a, int n)
Definition: Random.h:244
#define RAND48_SEED
Definition: Random.h:32
#define RAND48_MULT
Definition: Random.h:33
#define UINT64_LITERAL(X)
Definition: Random.h:29
#define RAND48_MASK
Definition: Random.h:35
double BigReal
Definition: common.h:114