xref: /aosp_15_r20/external/deqp/framework/delibs/decpp/deRandom.hpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 #ifndef _DERANDOM_HPP
2 #define _DERANDOM_HPP
3 /*-------------------------------------------------------------------------
4  * drawElements C++ Base Library
5  * -----------------------------
6  *
7  * Copyright 2014 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Random number generator utilities.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "deDefs.hpp"
27 #include "deRandom.h"
28 
29 #include <iterator>  // std::distance()
30 #include <algorithm> // std::swap()
31 
32 namespace de
33 {
34 
35 //! Random self-test - compare returned values against hard-coded values.
36 void Random_selfTest(void);
37 
38 class Random
39 {
40 public:
Random(uint32_t seed)41     Random(uint32_t seed)
42     {
43         deRandom_init(&m_rnd, seed);
44     }
~Random(void)45     ~Random(void)
46     {
47     }
48 
getFloat(void)49     float getFloat(void)
50     {
51         return deRandom_getFloat(&m_rnd);
52     }
getDouble(void)53     double getDouble(void)
54     {
55         return deRandom_getDouble(&m_rnd);
56     }
getBool(void)57     bool getBool(void)
58     {
59         return deRandom_getBool(&m_rnd) == true;
60     }
61 
62     float getFloat(float min, float max);
63     double getDouble(double min, double max);
64     int getInt(int min, int max);
65 
getInt64(void)66     int64_t getInt64(void)
67     {
68         uint32_t upper = getUint32();
69         return static_cast<int64_t>((uint64_t)upper << 32ull | (uint64_t)getUint32());
70     }
getUint64(void)71     uint64_t getUint64(void)
72     {
73         uint32_t upper = getUint32();
74         return (uint64_t)upper << 32ull | (uint64_t)getUint32();
75     }
getInt32(void)76     int32_t getInt32(void)
77     {
78         return static_cast<int32_t>(getUint32());
79     }
getUint32(void)80     uint32_t getUint32(void)
81     {
82         return deRandom_getUint32(&m_rnd);
83     }
getUint16(void)84     uint16_t getUint16(void)
85     {
86         return (uint16_t)deRandom_getUint32(&m_rnd);
87     }
getUint8(void)88     uint8_t getUint8(void)
89     {
90         return (uint8_t)deRandom_getUint32(&m_rnd);
91     }
92 
93     template <class InputIter, class OutputIter>
94     void choose(InputIter first, InputIter last, OutputIter result, int numItems);
95 
96     template <typename T, class InputIter>
97     T choose(InputIter first, InputIter last);
98 
99     // \note Weights must be floats
100     template <typename T, class InputIter, class WeightIter>
101     T chooseWeighted(InputIter first, InputIter last, WeightIter weight);
102 
103     template <class Iterator>
104     void shuffle(Iterator first, Iterator last);
105 
106     bool operator==(const Random &other) const;
107     bool operator!=(const Random &other) const;
108 
109 private:
110     deRandom m_rnd;
111 } DE_WARN_UNUSED_TYPE;
112 
113 // Inline implementations
114 
getFloat(float min,float max)115 inline float Random::getFloat(float min, float max)
116 {
117     DE_ASSERT(min <= max);
118     return min + (max - min) * getFloat();
119 }
120 
getDouble(double min,double max)121 inline double Random::getDouble(double min, double max)
122 {
123     DE_ASSERT(min <= max);
124     return min + (max - min) * getDouble();
125 }
126 
getInt(int min,int max)127 inline int Random::getInt(int min, int max)
128 {
129     DE_ASSERT(min <= max);
130     if (min == (int)0x80000000 && max == (int)0x7fffffff)
131         return (int)getUint32();
132     else
133         return min + (int)(getUint32() % ((uint32_t)max - (uint32_t)min + 1u));
134 }
135 
136 // Template implementations
137 
138 template <class InputIter, class OutputIter>
choose(InputIter first,InputIter last,OutputIter result,int numItems)139 void Random::choose(InputIter first, InputIter last, OutputIter result, int numItems)
140 {
141     // Algorithm: Reservoir sampling
142     // http://en.wikipedia.org/wiki/Reservoir_sampling
143     // \note Will not work for suffling an array. Use suffle() instead.
144 
145     int ndx;
146     for (ndx = 0; first != last; ++first, ++ndx)
147     {
148         if (ndx < numItems)
149             *(result + ndx) = *first;
150         else
151         {
152             int r = getInt(0, ndx);
153             if (r < numItems)
154                 *(result + r) = *first;
155         }
156     }
157 
158     DE_ASSERT(ndx >= numItems);
159 }
160 
161 template <typename T, class InputIter>
choose(InputIter first,InputIter last)162 T Random::choose(InputIter first, InputIter last)
163 {
164     T val = T();
165     DE_ASSERT(first != last);
166     choose(first, last, &val, 1);
167     return val;
168 }
169 
170 template <typename T, class InputIter, class WeightIter>
chooseWeighted(InputIter first,InputIter last,WeightIter weight)171 T Random::chooseWeighted(InputIter first, InputIter last, WeightIter weight)
172 {
173     // Compute weight sum
174     float weightSum = 0.0f;
175     int ndx;
176     for (ndx = 0; (first + ndx) != last; ndx++)
177         weightSum += *(weight + ndx);
178 
179     // Random point in 0..weightSum
180     float p = getFloat(0.0f, weightSum);
181 
182     // Find item in range
183     InputIter lastNonZero = last;
184     float curWeight       = 0.0f;
185     for (ndx = 0; (first + ndx) != last; ndx++)
186     {
187         float w = *(weight + ndx);
188 
189         curWeight += w;
190 
191         if (p < curWeight)
192             return *(first + ndx);
193         else if (w > 0.0f)
194             lastNonZero = first + ndx;
195     }
196 
197     DE_ASSERT(lastNonZero != last);
198     return *lastNonZero;
199 }
200 
201 template <class Iterator>
shuffle(Iterator first,Iterator last)202 void Random::shuffle(Iterator first, Iterator last)
203 {
204     using std::swap;
205 
206     // Fisher-Yates suffle
207     int numItems = (int)std::distance(first, last);
208 
209     for (int i = numItems - 1; i >= 1; i--)
210     {
211         int j = getInt(0, i);
212         swap(*(first + i), *(first + j));
213     }
214 }
215 
216 template <typename T>
217 T randomScalar(de::Random &rnd, T minValue, T maxValue);
218 template <>
randomScalar(de::Random & rnd,float minValue,float maxValue)219 inline float randomScalar(de::Random &rnd, float minValue, float maxValue)
220 {
221     return rnd.getFloat(minValue, maxValue);
222 }
223 template <>
randomScalar(de::Random & rnd,int32_t minValue,int32_t maxValue)224 inline int32_t randomScalar(de::Random &rnd, int32_t minValue, int32_t maxValue)
225 {
226     return rnd.getInt(minValue, maxValue);
227 }
228 template <>
randomScalar(de::Random & rnd,uint32_t minValue,uint32_t maxValue)229 inline uint32_t randomScalar(de::Random &rnd, uint32_t minValue, uint32_t maxValue)
230 {
231     if (minValue == 0 && maxValue == 0xffffffff)
232         return rnd.getUint32();
233     return minValue + rnd.getUint32() % (maxValue - minValue + 1);
234 }
235 template <>
randomScalar(de::Random & rnd,int16_t minValue,int16_t maxValue)236 inline int16_t randomScalar(de::Random &rnd, int16_t minValue, int16_t maxValue)
237 {
238     return (int16_t)rnd.getInt(minValue, maxValue);
239 }
240 template <>
randomScalar(de::Random & rnd,uint16_t minValue,uint16_t maxValue)241 inline uint16_t randomScalar(de::Random &rnd, uint16_t minValue, uint16_t maxValue)
242 {
243     return (uint16_t)(minValue + rnd.getUint16() % (maxValue - minValue + 1));
244 }
245 template <>
randomScalar(de::Random & rnd,int8_t minValue,int8_t maxValue)246 inline int8_t randomScalar(de::Random &rnd, int8_t minValue, int8_t maxValue)
247 {
248     return (int8_t)rnd.getInt(minValue, maxValue);
249 }
250 template <>
randomScalar(de::Random & rnd,uint8_t minValue,uint8_t maxValue)251 inline uint8_t randomScalar(de::Random &rnd, uint8_t minValue, uint8_t maxValue)
252 {
253     return (uint8_t)(minValue + rnd.getUint8() % (maxValue - minValue + 1));
254 }
255 
256 } // namespace de
257 
258 #endif // _DERANDOM_HPP
259