From c659c65d02d4d92b614ccdf2e2a4a0dcf859a8cd Mon Sep 17 00:00:00 2001 From: Jacek Antonelli Date: Fri, 15 Aug 2008 23:44:49 -0500 Subject: Second Life viewer sources 1.13.3.2 --- linden/indra/llmath/llrand.cpp | 107 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 101 insertions(+), 6 deletions(-) (limited to 'linden/indra/llmath') diff --git a/linden/indra/llmath/llrand.cpp b/linden/indra/llmath/llrand.cpp index 4c214c4..c0f03d2 100644 --- a/linden/indra/llmath/llrand.cpp +++ b/linden/indra/llmath/llrand.cpp @@ -30,34 +30,129 @@ #include "llrand.h" #include "lluuid.h" +/** + * Through analysis, we have decided that we want to take values which + * are close enough to 1.0 to map back to 0.0. We came to this + * conclusion from noting that: + * + * [0.0, 1.0) + * + * when scaled to the integer set: + * + * [0, 4) + * + * there is some value close enough to 1.0 that when multiplying by 4, + * gets truncated to 4. Therefore: + * + * [0,1-eps] => 0 + * [1,2-eps] => 1 + * [2,3-eps] => 2 + * [3,4-eps] => 3 + * + * So 0 gets uneven distribution if we simply clamp. The actual + * clamp utilized in this file is to map values out of range back + * to 0 to restore uniform distribution. + * + * Also, for clamping floats when asking for a distribution from + * [0.0,g) we have determined that for values of g < 0.5, then + * rand*g=g, which is not the desired result. As above, we clamp to 0 + * to restore uniform distribution. + */ + +// *NOTE: The system rand implementation is probably not correct. +#define LL_USE_SYSTEM_RAND 0 + +#if LL_USE_SYSTEM_RAND +#include +#endif + +#if LL_USE_SYSTEM_RAND +class LLSeedRand +{ +public: + LLSeedRand() + { +#if LL_WINDOWS + srand(LLUUID::getRandomSeed()); +#else + srand48(LLUUID::getRandomSeed()); +#endif + } +}; +static LLSeedRand sRandomSeeder; +inline F64 ll_internal_random_double() +{ +#if LL_WINDOWS + return (F64)rand() / (F64)RAND_MAX; +#else + return drand48(); +#endif +} +inline F32 ll_internal_random_float() +{ +#if LL_WINDOWS + return (F32)rand() / (F32)RAND_MAX; +#else + return (F32)drand48(); +#endif +} +#else static LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed()); +inline F64 ll_internal_random_double() +{ + // *HACK: Through experimentation, we have found that dual core + // CPUs (or at least multi-threaded processes) seem to + // occasionally give an obviously incorrect random number -- like + // 5^15 or something. Sooooo, clamp it as described above. + F64 rv = gRandomGenerator(); + if(!((rv >= 0.0) && (rv < 1.0))) return 0.0; + return rv; +} + +inline F32 ll_internal_random_float() +{ + // The clamping rules are described above. + F32 rv = (F32)gRandomGenerator(); + if(!((rv >= 0.0f) && (rv < 1.0f))) return 0.0f; + return rv; +} +#endif S32 ll_rand() { - return (S32)(gRandomGenerator() * RAND_MAX); + return ll_rand(RAND_MAX); } S32 ll_rand(S32 val) { - return (S32)(gRandomGenerator() * val); + // The clamping rules are described above. + S32 rv = (S32)(ll_internal_random_double() * val); + if(rv == val) return 0; + return rv; } F32 ll_frand() { - return (F32)gRandomGenerator(); + return ll_internal_random_float(); } F32 ll_frand(F32 val) { - return (F32)gRandomGenerator() * val; + // The clamping rules are described above. + F32 rv = ll_internal_random_float() * val; + if(rv >= val) return 0.0f; + return rv; } F64 ll_drand() { - return gRandomGenerator(); + return ll_internal_random_double(); } F64 ll_drand(F64 val) { - return gRandomGenerator() * val; + // The clamping rules are described above. + F64 rv = ll_internal_random_double() * val; + if(rv >= val) return 0.0; + return rv; } -- cgit v1.1