OVR_Rand.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /************************************************************************************
  2. PublicHeader: OVR_Kernel.h
  3. Filename : OVR_Rand.h
  4. Content : Random number generator
  5. Created : Aug 28, 2014
  6. Author : Chris Taylor
  7. Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
  8. Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
  9. you may not use the Oculus VR Rift SDK except in compliance with the License,
  10. which is provided at the time of installation or download, or which
  11. otherwise accompanies this software in either electronic or hard copy form.
  12. You may obtain a copy of the License at
  13. http://www.oculusvr.com/licenses/LICENSE-3.2
  14. Unless required by applicable law or agreed to in writing, the Oculus VR SDK
  15. distributed under the License is distributed on an "AS IS" BASIS,
  16. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. See the License for the specific language governing permissions and
  18. limitations under the License.
  19. ************************************************************************************/
  20. #ifndef OVR_Rand_h
  21. #define OVR_Rand_h
  22. #include "OVR_Types.h"
  23. #include <math.h>
  24. namespace OVR {
  25. /*
  26. This is designed to generate up to 2^^32 numbers per seed.
  27. Its period is about 2^^126 and passes all BigCrush tests.
  28. It is the fastest simple generator that passes all tests.
  29. It has a few advantages over the stdlib RNG, including that
  30. all bits of the output are equally good in quality.
  31. Furthermore, the input seeds are hashed to avoid linear
  32. relationships between the input seeds and the low bits of
  33. the first few outputs.
  34. */
  35. class RandomNumberGenerator
  36. {
  37. protected:
  38. uint64_t Rx;
  39. uint64_t Ry;
  40. double NextRandN;
  41. bool Seeded;
  42. bool HaveRandN;
  43. public:
  44. RandomNumberGenerator() :
  45. Seeded(false),
  46. HaveRandN(false)
  47. // Other members left uninitialized
  48. {
  49. }
  50. bool IsSeeded() const
  51. {
  52. return Seeded;
  53. }
  54. // Seed with a random state
  55. void SeedRandom();
  56. // Start with a specific seed
  57. void Seed(uint32_t x, uint32_t y);
  58. // Returns an unsigned uint32_t uniformly distributed in interval [0..2^32-1]
  59. OVR_FORCE_INLINE uint32_t Next()
  60. {
  61. // If it is not Seeded yet,
  62. if (!IsSeeded())
  63. {
  64. SeedRandom();
  65. }
  66. // Sum of two long-period MWC generators
  67. Rx = (uint64_t)0xfffd21a7 * (uint32_t)Rx + (uint32_t)(Rx >> 32);
  68. Ry = (uint64_t)0xfffd1361 * (uint32_t)Ry + (uint32_t)(Ry >> 32);
  69. return (((uint32_t)Rx << 7) | ((uint32_t)Rx >> (32 - 7))) + (uint32_t)Ry; // ROL(x, 7) + y
  70. }
  71. // The following functions are inspired by the Matlab functions rand(), randi(), and randn()
  72. // Uniform distribution over open interval (0..2^32)
  73. // (i.e. closed interval [1..2^32-1], not including 0)
  74. OVR_FORCE_INLINE uint32_t NextNonZero()
  75. {
  76. uint32_t n;
  77. do
  78. {
  79. n = Next();
  80. } while (n == 0);
  81. return n;
  82. }
  83. // Double uniformly distributed over open interval (0..1)
  84. OVR_FORCE_INLINE double Rand()
  85. {
  86. return NextNonZero() * (1.0 / 4294967296.0); // 2^32
  87. }
  88. // Double uniformly distributed over open interval (dmin..dmax)
  89. OVR_FORCE_INLINE double Rand(double dmin, double dmax)
  90. {
  91. return dmin + (dmax - dmin) * (1.0 / 4294967296.0) * NextNonZero(); // 2^32
  92. }
  93. // Integer uniformly distributed over closed interval [0..imax-1]
  94. // (NOTE: Matalb randi(imax) returns 1..imax)
  95. OVR_FORCE_INLINE int RandI(int imax)
  96. {
  97. return (int)(Next() % imax);
  98. }
  99. // Integer uniformly distributed over closed interval [imin..imax-1]
  100. // (NOTE: Matlab randi() returns imin..imax)
  101. OVR_FORCE_INLINE int RandI(int imin, int imax)
  102. {
  103. return imin + (int)(Next() % (imax - imin));
  104. }
  105. // Coordinate (x,y) uniformly distributed inside unit circle.
  106. // Returns magnitude squared of (x,y)
  107. OVR_FORCE_INLINE double RandInUnitCircle(double& x, double& y)
  108. {
  109. double r2;
  110. do
  111. {
  112. x = Rand(-1.0, 1.0);
  113. y = Rand(-1.0, 1.0);
  114. r2 = x*x + y*y;
  115. } while (r2 >= 1.0);
  116. return r2;
  117. }
  118. // Standard normal (gaussian) distribution: mean 0.0, stdev 1.0
  119. double RandN()
  120. {
  121. if (HaveRandN)
  122. {
  123. HaveRandN = false;
  124. return NextRandN;
  125. }
  126. else
  127. {
  128. double x, y;
  129. double r2 = RandInUnitCircle(x, y);
  130. // Box-Muller transform
  131. double f = sqrt(-2 * log(r2) / r2);
  132. // Return first, save second for next call
  133. NextRandN = y * f;
  134. HaveRandN = true;
  135. return x * f;
  136. }
  137. }
  138. // Uniform coordinate (c,s) ON unit circle.
  139. // This function computes cos(theta), sin(theta)
  140. // of rotation uniform in (0..2*pi).
  141. // [ c s] is a random 2D rotation matrix.
  142. // [-s c]
  143. // Reference: Numerical Recipes in C++, chap. 21
  144. OVR_FORCE_INLINE void RandOnUnitCircle(double& c, double& s)
  145. {
  146. double r2 = RandInUnitCircle(c, s);
  147. double normalize = 1.0 / sqrt(r2);
  148. c *= normalize;
  149. s *= normalize;
  150. }
  151. // Uniform coordinate (x,y,z,w) on surface of 4D hypersphere.
  152. // This is a quaternion rotation uniformly distributed across all rotations
  153. // Reference: Numerical Recipes in C++, chap. 21
  154. OVR_FORCE_INLINE void RandOnUnitSphere4(double& x, double& y, double& z, double& w)
  155. {
  156. double r2xy = RandInUnitCircle(x, y);
  157. double u, v;
  158. double r2uv = RandInUnitCircle(u, v);
  159. double f = sqrt((1.0 - r2xy) / r2uv);
  160. z = u * f;
  161. w = v * f;
  162. }
  163. };
  164. } // namespace OVR
  165. #endif // OVR_Rand_h