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 240 Rand32::init (unsigned long int seed) 241 { 242 _state = (seed * 0xa5a573a5L) ^ 0x5a5a5a5aL; 243 } 244 245 246 inline 247 Rand32::Rand32 (unsigned long int seed) 248 { 249 init (seed); 250 } 251 252 253 inline void 254 Rand32::next () 255 { 256 _state = 1664525L * _state + 1013904223L; 257 } 258 259 260 inline bool 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 270 Rand32::nexti () 271 { 272 next (); 273 return _state & 0xffffffff; 274 } 275 276 277 inline float 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 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 297 Rand48::Rand48 (unsigned long int seed) 298 { 299 init (seed); 300 } 301 302 303 inline bool 304 Rand48::nextb () 305 { 306 return Imath::nrand48 (_state) & 1; 307 } 308 309 310 inline long int 311 Rand48::nexti () 312 { 313 return Imath::nrand48 (_state); 314 } 315 316 317 inline double 318 Rand48::nextf () 319 { 320 return Imath::erand48 (_state); 321 } 322 323 324 inline double 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 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 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 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 391 gaussSphereRand (Rand &rand) 392 { 393 return hollowSphereRand <Vec> (rand) * gaussRand (rand); 394 } 395 396 } // namespace Imath 397 398 #endif 399