PageRenderTime 41ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llrand.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 171 lines | 96 code | 13 blank | 62 comment | 12 complexity | a6c17e933cd22997caebaa5443e5fbe9 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llrand.cpp
  3. * @brief Global random generator.
  4. *
  5. * $LicenseInfo:firstyear=2000&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "llrand.h"
  28. #include "lluuid.h"
  29. /**
  30. * Through analysis, we have decided that we want to take values which
  31. * are close enough to 1.0 to map back to 0.0. We came to this
  32. * conclusion from noting that:
  33. *
  34. * [0.0, 1.0)
  35. *
  36. * when scaled to the integer set:
  37. *
  38. * [0, 4)
  39. *
  40. * there is some value close enough to 1.0 that when multiplying by 4,
  41. * gets truncated to 4. Therefore:
  42. *
  43. * [0,1-eps] => 0
  44. * [1,2-eps] => 1
  45. * [2,3-eps] => 2
  46. * [3,4-eps] => 3
  47. *
  48. * So 0 gets uneven distribution if we simply clamp. The actual
  49. * clamp utilized in this file is to map values out of range back
  50. * to 0 to restore uniform distribution.
  51. *
  52. * Also, for clamping floats when asking for a distribution from
  53. * [0.0,g) we have determined that for values of g < 0.5, then
  54. * rand*g=g, which is not the desired result. As above, we clamp to 0
  55. * to restore uniform distribution.
  56. */
  57. // *NOTE: The system rand implementation is probably not correct.
  58. #define LL_USE_SYSTEM_RAND 0
  59. #if LL_USE_SYSTEM_RAND
  60. #include <cstdlib>
  61. #endif
  62. #if LL_USE_SYSTEM_RAND
  63. class LLSeedRand
  64. {
  65. public:
  66. LLSeedRand()
  67. {
  68. #if LL_WINDOWS
  69. srand(LLUUID::getRandomSeed());
  70. #else
  71. srand48(LLUUID::getRandomSeed());
  72. #endif
  73. }
  74. };
  75. static LLSeedRand sRandomSeeder;
  76. inline F64 ll_internal_random_double()
  77. {
  78. #if LL_WINDOWS
  79. return (F64)rand() / (F64)RAND_MAX;
  80. #else
  81. return drand48();
  82. #endif
  83. }
  84. inline F32 ll_internal_random_float()
  85. {
  86. #if LL_WINDOWS
  87. return (F32)rand() / (F32)RAND_MAX;
  88. #else
  89. return (F32)drand48();
  90. #endif
  91. }
  92. #else
  93. static LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed());
  94. inline F64 ll_internal_random_double()
  95. {
  96. // *HACK: Through experimentation, we have found that dual core
  97. // CPUs (or at least multi-threaded processes) seem to
  98. // occasionally give an obviously incorrect random number -- like
  99. // 5^15 or something. Sooooo, clamp it as described above.
  100. F64 rv = gRandomGenerator();
  101. if(!((rv >= 0.0) && (rv < 1.0))) return fmod(rv, 1.0);
  102. return rv;
  103. }
  104. inline F32 ll_internal_random_float()
  105. {
  106. // The clamping rules are described above.
  107. F32 rv = (F32)gRandomGenerator();
  108. if(!((rv >= 0.0f) && (rv < 1.0f))) return fmod(rv, 1.f);
  109. return rv;
  110. }
  111. #endif
  112. S32 ll_rand()
  113. {
  114. return ll_rand(RAND_MAX);
  115. }
  116. S32 ll_rand(S32 val)
  117. {
  118. // The clamping rules are described above.
  119. S32 rv = (S32)(ll_internal_random_double() * val);
  120. if(rv == val) return 0;
  121. return rv;
  122. }
  123. F32 ll_frand()
  124. {
  125. return ll_internal_random_float();
  126. }
  127. F32 ll_frand(F32 val)
  128. {
  129. // The clamping rules are described above.
  130. F32 rv = ll_internal_random_float() * val;
  131. if(val > 0)
  132. {
  133. if(rv >= val) return 0.0f;
  134. }
  135. else
  136. {
  137. if(rv <= val) return 0.0f;
  138. }
  139. return rv;
  140. }
  141. F64 ll_drand()
  142. {
  143. return ll_internal_random_double();
  144. }
  145. F64 ll_drand(F64 val)
  146. {
  147. // The clamping rules are described above.
  148. F64 rv = ll_internal_random_double() * val;
  149. if(val > 0)
  150. {
  151. if(rv >= val) return 0.0;
  152. }
  153. else
  154. {
  155. if(rv <= val) return 0.0;
  156. }
  157. return rv;
  158. }