llrand.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /**
  2. * @file llrand.cpp
  3. * @brief Global random generator.
  4. *
  5. * $LicenseInfo:firstyear=2000&license=viewergpl$
  6. *
  7. * Copyright (c) 2000-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #if !LL_WINDOWS
  33. # include <unistd.h> // For getpid()
  34. #endif
  35. #include "linden_common.h"
  36. #include "llrand.h"
  37. #include "llsys.h" // For LLOSInfo::getNodeID()
  38. #include "hbxxh.h"
  39. // Used to be LLUUID::getRandomSeed(), but only in use here, so... HB
  40. static U32 get_random_seed()
  41. {
  42. static unsigned char seed[16];
  43. static bool init_done = false;
  44. if (!init_done)
  45. {
  46. init_done = true;
  47. LLOSInfo::getNodeID(&seed[0]);
  48. // Incorporate the pid into the seed to prevent processes that start
  49. // on the same host at the same time from generating the same seed.
  50. #if LL_WINDOWS
  51. int pid = GetCurrentProcessId();
  52. #else
  53. int pid = getpid();
  54. #endif
  55. seed[6] = (unsigned char)(pid >> 8);
  56. seed[7] = (unsigned char)(pid);
  57. }
  58. LLUUID::getSystemTime((uuid_time_t*)(&seed[8]));
  59. return digest64to32(HBXXH64::digest((const void*)seed, 16));
  60. }
  61. /**
  62. * Through analysis, we have decided that we want to take values which
  63. * are close enough to 1.0 to map back to 0.0. We came to this
  64. * conclusion from noting that:
  65. *
  66. * [0.0, 1.0)
  67. *
  68. * when scaled to the integer set:
  69. *
  70. * [0, 4)
  71. *
  72. * there is some value close enough to 1.0 that when multiplying by 4,
  73. * gets truncated to 4. Therefore:
  74. *
  75. * [0,1-eps] => 0
  76. * [1,2-eps] => 1
  77. * [2,3-eps] => 2
  78. * [3,4-eps] => 3
  79. *
  80. * So 0 gets uneven distribution if we simply clamp. The actual
  81. * clamp utilized in this file is to map values out of range back
  82. * to 0 to restore uniform distribution.
  83. *
  84. * Also, for clamping floats when asking for a distribution from
  85. * [0.0,g) we have determined that for values of g < 0.5, then
  86. * rand*g=g, which is not the desired result. As above, we clamp to 0
  87. * to restore uniform distribution.
  88. */
  89. #if LL_USE_SYSTEM_RAND
  90. # include <cstdlib>
  91. class LLSeedRand
  92. {
  93. public:
  94. LLSeedRand()
  95. {
  96. #if LL_WINDOWS
  97. srand(get_random_seed());
  98. #else
  99. srand48(get_random_seed());
  100. #endif
  101. }
  102. };
  103. static LLSeedRand sRandomSeeder;
  104. static LL_INLINE F64 ll_internal_random_double()
  105. {
  106. # if LL_WINDOWS
  107. return (F64)rand() / (F64)RAND_MAX;
  108. # else
  109. return drand48();
  110. # endif
  111. }
  112. static LL_INLINE F32 ll_internal_random_float()
  113. {
  114. # if LL_WINDOWS
  115. return (F32)rand() / (F32)RAND_MAX;
  116. # else
  117. return (F32)drand48();
  118. # endif
  119. }
  120. #else // LL_USE_SYSTEM_RAND
  121. // Work around bogus deprecated header warning in boost v1.69...
  122. # ifndef BOOST_ALLOW_DEPRECATED_HEADERS
  123. # define BOOST_ALLOW_DEPRECATED_HEADERS 1
  124. # endif
  125. # include "boost/random/lagged_fibonacci.hpp"
  126. # undef BOOST_ALLOW_DEPRECATED_HEADERS
  127. static boost::lagged_fibonacci2281 gRandomGenerator(get_random_seed());
  128. static LL_INLINE F64 ll_internal_random_double()
  129. {
  130. // *HACK: through experimentation, we have found that dual core CPUs (or at
  131. // least multi-threaded processes) seem to occasionally give an obviously
  132. // incorrect random number -- like 5^15 or something. Sooooo, clamp it as
  133. // described above.
  134. F64 rv = gRandomGenerator();
  135. if (rv < 0.0 || rv >= 1.0)
  136. {
  137. return fmod(rv, 1.0);
  138. }
  139. return rv;
  140. }
  141. static LL_INLINE F32 ll_internal_random_float()
  142. {
  143. // The clamping rules are described above.
  144. F32 rv = (F32)gRandomGenerator();
  145. if (rv < 0.f || rv >= 1.f)
  146. {
  147. return fmodf(rv, 1.f);
  148. }
  149. return rv;
  150. }
  151. #endif // LL_USE_SYSTEM_RAND
  152. S32 ll_rand()
  153. {
  154. return ll_rand(RAND_MAX);
  155. }
  156. S32 ll_rand(S32 val)
  157. {
  158. // The clamping rules are described above.
  159. S32 rv = (S32)(ll_internal_random_double() * F64(val));
  160. return rv == val ? 0 : rv;
  161. }
  162. F32 ll_frand()
  163. {
  164. return ll_internal_random_float();
  165. }
  166. F32 ll_frand(F32 val)
  167. {
  168. // The clamping rules are described above.
  169. F32 rv = ll_internal_random_float() * val;
  170. if (val > 0)
  171. {
  172. if (rv >= val)
  173. {
  174. return 0.f;
  175. }
  176. }
  177. else if (rv <= val)
  178. {
  179. return 0.f;
  180. }
  181. return rv;
  182. }
  183. F64 ll_drand()
  184. {
  185. return ll_internal_random_double();
  186. }
  187. F64 ll_drand(F64 val)
  188. {
  189. // The clamping rules are described above.
  190. F64 rv = ll_internal_random_double() * val;
  191. if (val > 0)
  192. {
  193. if (rv >= val)
  194. {
  195. return 0.0;
  196. }
  197. }
  198. else if (rv <= val)
  199. {
  200. return 0.0;
  201. }
  202. return rv;
  203. }