1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
4 // Digital Ltd. LLC
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are
10 // met:
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 // * Neither the name of Industrial Light & Magic nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 ///////////////////////////////////////////////////////////////////////////
34
35
36 #ifndef INCLUDED_IMATHRANDOM_H
37 #define INCLUDED_IMATHRANDOM_H
38
39 //-----------------------------------------------------------------------------
40 //
41 // Generators for uniformly distributed pseudo-random numbers and
42 // functions that use those generators to generate numbers with
43 // non-uniform distributions:
44 //
45 // class Rand32
46 // class Rand48
47 // solidSphereRand()
48 // hollowSphereRand()
49 // gaussRand()
50 // gaussSphereRand()
51 //
52 // Note: class Rand48() calls erand48() and nrand48(), which are not
53 // available on all operating systems. For compatibility we include
54 // our own versions of erand48() and nrand48(). Our functions have
55 // been reverse-engineered from the corresponding Unix/Linux man page.
56 //
57 //-----------------------------------------------------------------------------
58
59 #include <stdlib.h>
60 #include <math.h>
61
62 namespace Imath {
63
64 //-----------------------------------------------
65 // Fast random-number generator that generates
66 // a uniformly distributed sequence with a period
67 // length of 2^32.
68 //-----------------------------------------------
69
70 class Rand32
71 {
72 public:
73
74 //------------
75 // Constructor
76 //------------
77
78 Rand32 (unsigned long int seed = 0);
79
80
81 //--------------------------------
82 // Re-initialize with a given seed
83 //--------------------------------
84
85 void init (unsigned long int seed);
86
87
88 //----------------------------------------------------------
89 // Get the next value in the sequence (range: [false, true])
90 //----------------------------------------------------------
91
92 bool nextb ();
93
94
95 //---------------------------------------------------------------
96 // Get the next value in the sequence (range: [0 ... 0xffffffff])
97 //---------------------------------------------------------------
98
99 unsigned long int nexti ();
100
101
102 //------------------------------------------------------
103 // Get the next value in the sequence (range: [0 ... 1[)
104 //------------------------------------------------------
105
106 float nextf ();
107
108
109 //-------------------------------------------------------------------
110 // Get the next value in the sequence (range [rangeMin ... rangeMax[)
111 //-------------------------------------------------------------------
112
113 float nextf (float rangeMin, float rangeMax);
114
115
116 private:
117
118 void next ();
119
120 unsigned long int _state;
121 };
122
123
124 //--------------------------------------------------------
125 // Random-number generator based on the C Standard Library
126 // functions erand48(), nrand48() & company; generates a
127 // uniformly distributed sequence.
128 //--------------------------------------------------------
129
130 class Rand48
131 {
132 public:
133
134 //------------
135 // Constructor
136 //------------
137
138 Rand48 (unsigned long int seed = 0);
139
140
141 //--------------------------------
142 // Re-initialize with a given seed
143 //--------------------------------
144
145 void init (unsigned long int seed);
146
147
148 //----------------------------------------------------------
149 // Get the next value in the sequence (range: [false, true])
150 //----------------------------------------------------------
151
152 bool nextb ();
153
154
155 //---------------------------------------------------------------
156 // Get the next value in the sequence (range: [0 ... 0x7fffffff])
157 //---------------------------------------------------------------
158
159 long int nexti ();
160
161
162 //------------------------------------------------------
163 // Get the next value in the sequence (range: [0 ... 1[)
164 //------------------------------------------------------
165
166 double nextf ();
167
168
169 //-------------------------------------------------------------------
170 // Get the next value in the sequence (range [rangeMin ... rangeMax[)
171 //-------------------------------------------------------------------
172
173 double nextf (double rangeMin, double rangeMax);
174
175
176 private:
177
178 unsigned short int _state[3];
179 };
180
181
182 //------------------------------------------------------------
183 // Return random points uniformly distributed in a sphere with
184 // radius 1 around the origin (distance from origin <= 1).
185 //------------------------------------------------------------
186
187 template <class Vec, class Rand>
188 Vec
189 solidSphereRand (Rand &rand);
190
191
192 //-------------------------------------------------------------
193 // Return random points uniformly distributed on the surface of
194 // a sphere with radius 1 around the origin.
195 //-------------------------------------------------------------
196
197 template <class Vec, class Rand>
198 Vec
199 hollowSphereRand (Rand &rand);
200
201
202 //-----------------------------------------------
203 // Return random numbers with a normal (Gaussian)
204 // distribution with zero mean and unit variance.
205 //-----------------------------------------------
206
207 template <class Rand>
208 float
209 gaussRand (Rand &rand);
210
211
212 //----------------------------------------------------
213 // Return random points whose distance from the origin
214 // has a normal (Gaussian) distribution with zero mean
215 // and unit variance.
216 //----------------------------------------------------
217
218 template <class Vec, class Rand>
219 Vec
220 gaussSphereRand (Rand &rand);
221
222
223 //---------------------------------
224 // erand48(), nrand48() and friends
225 //---------------------------------
226
227 double erand48 (unsigned short state[3]);
228 double drand48 ();
229 long int nrand48 (unsigned short state[3]);
230 long int lrand48 ();
231 void srand48 (long int seed);
232
233
234 //---------------
235 // Implementation
236 //---------------
237
238
239 inline void
init(unsigned long int seed)240 Rand32::init (unsigned long int seed)
241 {
242 _state = (seed * 0xa5a573a5L) ^ 0x5a5a5a5aL;
243 }
244
245
246 inline
Rand32(unsigned long int seed)247 Rand32::Rand32 (unsigned long int seed)
248 {
249 init (seed);
250 }
251
252
253 inline void
next()254 Rand32::next ()
255 {
256 _state = 1664525L * _state + 1013904223L;
257 }
258
259
260 inline bool
nextb()261 Rand32::nextb ()
262 {
263 next ();
264 // Return the 31st (most significant) bit, by and-ing with 2 ^ 31.
265 return !!(_state & 2147483648UL);
266 }
267
268
269 inline unsigned long int
nexti()270 Rand32::nexti ()
271 {
272 next ();
273 return _state & 0xffffffff;
274 }
275
276
277 inline float
nextf(float rangeMin,float rangeMax)278 Rand32::nextf (float rangeMin, float rangeMax)
279 {
280 float f = nextf();
281 return rangeMin * (1 - f) + rangeMax * f;
282 }
283
284
285 inline void
init(unsigned long int seed)286 Rand48::init (unsigned long int seed)
287 {
288 seed = (seed * 0xa5a573a5L) ^ 0x5a5a5a5aL;
289
290 _state[0] = (unsigned short int) (seed & 0xFFFF);
291 _state[1] = (unsigned short int) ((seed >> 16) & 0xFFFF);
292 _state[2] = (unsigned short int) (seed & 0xFFFF);
293 }
294
295
296 inline
Rand48(unsigned long int seed)297 Rand48::Rand48 (unsigned long int seed)
298 {
299 init (seed);
300 }
301
302
303 inline bool
nextb()304 Rand48::nextb ()
305 {
306 return Imath::nrand48 (_state) & 1;
307 }
308
309
310 inline long int
nexti()311 Rand48::nexti ()
312 {
313 return Imath::nrand48 (_state);
314 }
315
316
317 inline double
nextf()318 Rand48::nextf ()
319 {
320 return Imath::erand48 (_state);
321 }
322
323
324 inline double
nextf(double rangeMin,double rangeMax)325 Rand48::nextf (double rangeMin, double rangeMax)
326 {
327 double f = nextf();
328 return rangeMin * (1 - f) + rangeMax * f;
329 }
330
331
332 template <class Vec, class Rand>
333 Vec
solidSphereRand(Rand & rand)334 solidSphereRand (Rand &rand)
335 {
336 Vec v;
337
338 do
339 {
340 for (unsigned int i = 0; i < Vec::dimensions(); i++)
341 v[i] = (typename Vec::BaseType) rand.nextf (-1, 1);
342 }
343 while (v.length2() > 1);
344
345 return v;
346 }
347
348
349 template <class Vec, class Rand>
350 Vec
hollowSphereRand(Rand & rand)351 hollowSphereRand (Rand &rand)
352 {
353 Vec v;
354 typename Vec::BaseType length;
355
356 do
357 {
358 for (unsigned int i = 0; i < Vec::dimensions(); i++)
359 v[i] = (typename Vec::BaseType) rand.nextf (-1, 1);
360
361 length = v.length();
362 }
363 while (length > 1 || length == 0);
364
365 return v / length;
366 }
367
368
369 template <class Rand>
370 float
gaussRand(Rand & rand)371 gaussRand (Rand &rand)
372 {
373 float x; // Note: to avoid numerical problems with very small
374 float y; // numbers, we make these variables singe-precision
375 float length2; // floats, but later we call the double-precision log()
376 // and sqrt() functions instead of logf() and sqrtf().
377 do
378 {
379 x = float (rand.nextf (-1, 1));
380 y = float (rand.nextf (-1, 1));
381 length2 = x * x + y * y;
382 }
383 while (length2 >= 1 || length2 == 0);
384
385 return x * sqrt (-2 * log (double (length2)) / length2);
386 }
387
388
389 template <class Vec, class Rand>
390 Vec
gaussSphereRand(Rand & rand)391 gaussSphereRand (Rand &rand)
392 {
393 return hollowSphereRand <Vec> (rand) * gaussRand (rand);
394 }
395
396 } // namespace Imath
397
398 #endif
399