ImathRandom.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. //
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Copyright Contributors to the OpenEXR Project.
  4. //
  5. //
  6. // Generators for uniformly distributed pseudo-random numbers and
  7. // functions that use those generators to generate numbers with
  8. // non-uniform distributions
  9. //
  10. // Note: class Rand48() calls erand48() and nrand48(), which are not
  11. // available on all operating systems. For compatibility we include
  12. // our own versions of erand48() and nrand48(). Our functions
  13. // have been reverse-engineered from the corresponding Unix/Linux
  14. // man page.
  15. //
  16. #ifndef INCLUDED_IMATHRANDOM_H
  17. #define INCLUDED_IMATHRANDOM_H
  18. #include "ImathExport.h"
  19. #include "ImathNamespace.h"
  20. #include <math.h>
  21. #include <stdlib.h>
  22. IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
  23. /// Fast random-number generator that generates
  24. /// a uniformly distributed sequence with a period
  25. /// length of 2^32.
  26. class Rand32
  27. {
  28. public:
  29. /// Constructor, given a seed
  30. IMATH_HOSTDEVICE Rand32 (unsigned long int seed = 0);
  31. /// Re-initialize with a given seed
  32. IMATH_HOSTDEVICE void init (unsigned long int seed);
  33. /// Get the next value in the sequence (range: [false, true])
  34. IMATH_HOSTDEVICE bool nextb();
  35. /// Get the next value in the sequence (range: [0 ... 0xffffffff])
  36. IMATH_HOSTDEVICE unsigned long int nexti();
  37. /// Get the next value in the sequence (range: [0 ... 1[)
  38. IMATH_HOSTDEVICE IMATH_EXPORT float nextf ();
  39. /// Get the next value in the sequence (range [rangeMin ... rangeMax[)
  40. IMATH_HOSTDEVICE float nextf (float rangeMin, float rangeMax);
  41. private:
  42. IMATH_HOSTDEVICE void next();
  43. unsigned long int _state;
  44. };
  45. /// Random-number generator based on the C Standard Library
  46. /// functions erand48(), nrand48() & company; generates a
  47. /// uniformly distributed sequence.
  48. class Rand48
  49. {
  50. public:
  51. /// Constructor
  52. IMATH_HOSTDEVICE Rand48 (unsigned long int seed = 0);
  53. /// Re-initialize with a given seed
  54. IMATH_HOSTDEVICE void init (unsigned long int seed);
  55. /// Get the next value in the sequence (range: [false, true])
  56. IMATH_HOSTDEVICE bool nextb();
  57. /// Get the next value in the sequence (range: [0 ... 0x7fffffff])
  58. IMATH_HOSTDEVICE long int nexti();
  59. /// Get the next value in the sequence (range: [0 ... 1[)
  60. IMATH_HOSTDEVICE double nextf();
  61. /// Get the next value in the sequence (range [rangeMin ... rangeMax[)
  62. IMATH_HOSTDEVICE double nextf (double rangeMin, double rangeMax);
  63. private:
  64. unsigned short int _state[3];
  65. };
  66. /// Return random points uniformly distributed in a sphere with
  67. /// radius 1 around the origin (distance from origin <= 1).
  68. template <class Vec, class Rand> IMATH_HOSTDEVICE Vec solidSphereRand (Rand& rand);
  69. /// Return random points uniformly distributed on the surface of
  70. /// a sphere with radius 1 around the origin.
  71. template <class Vec, class Rand> IMATH_HOSTDEVICE Vec hollowSphereRand (Rand& rand);
  72. /// Return random numbers with a normal (Gaussian)
  73. /// distribution with zero mean and unit variance.
  74. template <class Rand> IMATH_HOSTDEVICE float gaussRand (Rand& rand);
  75. /// Return random points whose distance from the origin
  76. /// has a normal (Gaussian) distribution with zero mean
  77. /// and unit variance.
  78. template <class Vec, class Rand> IMATH_HOSTDEVICE Vec gaussSphereRand (Rand& rand);
  79. //---------------------------------
  80. // erand48(), nrand48() and friends
  81. //---------------------------------
  82. /// @cond Doxygen_Suppress
  83. IMATH_HOSTDEVICE IMATH_EXPORT double erand48 (unsigned short state[3]);
  84. IMATH_HOSTDEVICE IMATH_EXPORT double drand48();
  85. IMATH_HOSTDEVICE IMATH_EXPORT long int nrand48 (unsigned short state[3]);
  86. IMATH_HOSTDEVICE IMATH_EXPORT long int lrand48();
  87. IMATH_HOSTDEVICE IMATH_EXPORT void srand48 (long int seed);
  88. /// @endcond
  89. //---------------
  90. // Implementation
  91. //---------------
  92. IMATH_HOSTDEVICE inline void
  93. Rand32::init (unsigned long int seed)
  94. {
  95. _state = (seed * 0xa5a573a5L) ^ 0x5a5a5a5aL;
  96. }
  97. IMATH_HOSTDEVICE inline Rand32::Rand32 (unsigned long int seed)
  98. {
  99. init (seed);
  100. }
  101. IMATH_HOSTDEVICE inline void
  102. Rand32::next()
  103. {
  104. _state = 1664525L * _state + 1013904223L;
  105. }
  106. IMATH_HOSTDEVICE inline bool
  107. Rand32::nextb()
  108. {
  109. next();
  110. // Return the 31st (most significant) bit, by and-ing with 2 ^ 31.
  111. return !!(_state & 2147483648UL);
  112. }
  113. IMATH_HOSTDEVICE inline unsigned long int
  114. Rand32::nexti()
  115. {
  116. next();
  117. return _state & 0xffffffff;
  118. }
  119. IMATH_HOSTDEVICE inline float
  120. Rand32::nextf (float rangeMin, float rangeMax)
  121. {
  122. float f = nextf();
  123. return rangeMin * (1 - f) + rangeMax * f;
  124. }
  125. IMATH_HOSTDEVICE inline void
  126. Rand48::init (unsigned long int seed)
  127. {
  128. seed = (seed * 0xa5a573a5L) ^ 0x5a5a5a5aL;
  129. _state[0] = (unsigned short int) (seed & 0xFFFF);
  130. _state[1] = (unsigned short int) ((seed >> 16) & 0xFFFF);
  131. _state[2] = (unsigned short int) (seed & 0xFFFF);
  132. }
  133. IMATH_HOSTDEVICE inline Rand48::Rand48 (unsigned long int seed)
  134. {
  135. init (seed);
  136. }
  137. IMATH_HOSTDEVICE inline bool
  138. Rand48::nextb()
  139. {
  140. return nrand48 (_state) & 1;
  141. }
  142. IMATH_HOSTDEVICE inline long int
  143. Rand48::nexti()
  144. {
  145. return nrand48 (_state);
  146. }
  147. IMATH_HOSTDEVICE inline double
  148. Rand48::nextf()
  149. {
  150. return erand48 (_state);
  151. }
  152. IMATH_HOSTDEVICE inline double
  153. Rand48::nextf (double rangeMin, double rangeMax)
  154. {
  155. double f = nextf();
  156. return rangeMin * (1 - f) + rangeMax * f;
  157. }
  158. template <class Vec, class Rand>
  159. IMATH_HOSTDEVICE Vec
  160. solidSphereRand (Rand& rand)
  161. {
  162. Vec v;
  163. do
  164. {
  165. for (unsigned int i = 0; i < Vec::dimensions(); i++)
  166. v[i] = (typename Vec::BaseType) rand.nextf (-1, 1);
  167. } while (v.length2() > 1);
  168. return v;
  169. }
  170. template <class Vec, class Rand>
  171. IMATH_HOSTDEVICE Vec
  172. hollowSphereRand (Rand& rand)
  173. {
  174. Vec v;
  175. typename Vec::BaseType length;
  176. do
  177. {
  178. for (unsigned int i = 0; i < Vec::dimensions(); i++)
  179. v[i] = (typename Vec::BaseType) rand.nextf (-1, 1);
  180. length = v.length();
  181. } while (length > 1 || length == 0);
  182. return v / length;
  183. }
  184. template <class Rand>
  185. IMATH_HOSTDEVICE float
  186. gaussRand (Rand& rand)
  187. {
  188. float x; // Note: to avoid numerical problems with very small
  189. float y; // numbers, we make these variables singe-precision
  190. float length2; // floats, but later we call the double-precision log()
  191. // and sqrt() functions instead of logf() and sqrtf().
  192. do
  193. {
  194. x = float (rand.nextf (-1, 1));
  195. y = float (rand.nextf (-1, 1));
  196. length2 = x * x + y * y;
  197. } while (length2 >= 1 || length2 == 0);
  198. return x * sqrt (-2 * log (double (length2)) / length2);
  199. }
  200. template <class Vec, class Rand>
  201. IMATH_HOSTDEVICE Vec
  202. gaussSphereRand (Rand& rand)
  203. {
  204. return hollowSphereRand<Vec> (rand) * gaussRand (rand);
  205. }
  206. IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
  207. #endif // INCLUDED_IMATHRANDOM_H