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