PageRenderTime 24ms CodeModel.GetById 11ms app.highlight 10ms 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
  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
 27#include "linden_common.h"
 28
 29#include "llrand.h"
 30#include "lluuid.h"
 31
 32/**
 33 * Through analysis, we have decided that we want to take values which
 34 * are close enough to 1.0 to map back to 0.0.  We came to this
 35 * conclusion from noting that:
 36 *
 37 * [0.0, 1.0)
 38 *
 39 * when scaled to the integer set:
 40 *
 41 * [0, 4)
 42 *
 43 * there is some value close enough to 1.0 that when multiplying by 4,
 44 * gets truncated to 4. Therefore:
 45 *
 46 * [0,1-eps] => 0
 47 * [1,2-eps] => 1
 48 * [2,3-eps] => 2
 49 * [3,4-eps] => 3
 50 *
 51 * So 0 gets uneven distribution if we simply clamp. The actual
 52 * clamp utilized in this file is to map values out of range back
 53 * to 0 to restore uniform distribution.
 54 *
 55 * Also, for clamping floats when asking for a distribution from
 56 * [0.0,g) we have determined that for values of g < 0.5, then
 57 * rand*g=g, which is not the desired result. As above, we clamp to 0
 58 * to restore uniform distribution.
 59 */
 60
 61// *NOTE: The system rand implementation is probably not correct.
 62#define LL_USE_SYSTEM_RAND 0
 63
 64#if LL_USE_SYSTEM_RAND
 65#include <cstdlib>
 66#endif
 67
 68#if LL_USE_SYSTEM_RAND
 69class LLSeedRand
 70{
 71public:
 72	LLSeedRand()
 73	{
 74#if LL_WINDOWS
 75		srand(LLUUID::getRandomSeed());
 76#else
 77		srand48(LLUUID::getRandomSeed());
 78#endif
 79	}
 80};
 81static LLSeedRand sRandomSeeder;
 82inline F64 ll_internal_random_double()
 83{
 84#if LL_WINDOWS
 85	return (F64)rand() / (F64)RAND_MAX; 
 86#else
 87	return drand48();
 88#endif
 89}
 90inline F32 ll_internal_random_float()
 91{
 92#if LL_WINDOWS
 93	return (F32)rand() / (F32)RAND_MAX; 
 94#else
 95	return (F32)drand48();
 96#endif
 97}
 98#else
 99static LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed());
100inline F64 ll_internal_random_double()
101{
102	// *HACK: Through experimentation, we have found that dual core
103	// CPUs (or at least multi-threaded processes) seem to
104	// occasionally give an obviously incorrect random number -- like
105	// 5^15 or something. Sooooo, clamp it as described above.
106	F64 rv = gRandomGenerator();
107	if(!((rv >= 0.0) && (rv < 1.0))) return fmod(rv, 1.0);
108	return rv;
109}
110
111inline F32 ll_internal_random_float()
112{
113	// The clamping rules are described above.
114	F32 rv = (F32)gRandomGenerator();
115	if(!((rv >= 0.0f) && (rv < 1.0f))) return fmod(rv, 1.f);
116	return rv;
117}
118#endif
119
120S32 ll_rand()
121{
122	return ll_rand(RAND_MAX);
123}
124
125S32 ll_rand(S32 val)
126{
127	// The clamping rules are described above.
128	S32 rv = (S32)(ll_internal_random_double() * val);
129	if(rv == val) return 0;
130	return rv;
131}
132
133F32 ll_frand()
134{
135	return ll_internal_random_float();
136}
137
138F32 ll_frand(F32 val)
139{
140	// The clamping rules are described above.
141	F32 rv = ll_internal_random_float() * val;
142	if(val > 0)
143	{
144		if(rv >= val) return 0.0f;
145	}
146	else
147	{
148		if(rv <= val) return 0.0f;
149	}
150	return rv;
151}
152
153F64 ll_drand()
154{
155	return ll_internal_random_double();
156}
157
158F64 ll_drand(F64 val)
159{
160	// The clamping rules are described above.
161	F64 rv = ll_internal_random_double() * val;
162	if(val > 0)
163	{
164		if(rv >= val) return 0.0;
165	}
166	else
167	{
168		if(rv <= val) return 0.0;
169	}
170	return rv;
171}