blob: d083fc6b2f358d8911af9ee5331e20c2b050dc1d [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#ifndef SkRandom_DEFINED
9#define SkRandom_DEFINED
10
reed@android.com8a1c16f2008-12-17 15:59:43 +000011#include "SkScalar.h"
12
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000013/** \class SkLCGRandom
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
15 Utility class that implements pseudo random 32bit numbers using a fast
16 linear equation. Unlike rand(), this class holds its own seed (initially
17 set to 0), so that multiple instances can be used with no side-effects.
18*/
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000019class SkLCGRandom {
reed@android.com8a1c16f2008-12-17 15:59:43 +000020public:
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000021 SkLCGRandom() : fSeed(0) {}
22 SkLCGRandom(uint32_t seed) : fSeed(seed) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000023
24 /** Return the next pseudo random number as an unsigned 32bit value.
25 */
26 uint32_t nextU() { uint32_t r = fSeed * kMul + kAdd; fSeed = r; return r; }
27
28 /** Return the next pseudo random number as a signed 32bit value.
29 */
30 int32_t nextS() { return (int32_t)this->nextU(); }
31
32 /** Return the next pseudo random number as an unsigned 16bit value.
33 */
34 U16CPU nextU16() { return this->nextU() >> 16; }
35
36 /** Return the next pseudo random number as a signed 16bit value.
37 */
38 S16CPU nextS16() { return this->nextS() >> 16; }
39
tfarina@chromium.org223137f2012-11-21 22:38:36 +000040 /**
41 * Returns value [0...1) as a float
42 */
43 float nextF() {
44 // const is 1 / (2^32 - 1)
45 return (float)(this->nextU() * 2.32830644e-10);
46 }
47
48 /**
49 * Returns value [min...max) as a float
50 */
51 float nextRangeF(float min, float max) {
52 return min + this->nextF() * (max - min);
53 }
54
reed@android.com8a1c16f2008-12-17 15:59:43 +000055 /** Return the next pseudo random number, as an unsigned value of
56 at most bitCount bits.
57 @param bitCount The maximum number of bits to be returned
58 */
59 uint32_t nextBits(unsigned bitCount) {
60 SkASSERT(bitCount > 0 && bitCount <= 32);
61 return this->nextU() >> (32 - bitCount);
62 }
63
64 /** Return the next pseudo random unsigned number, mapped to lie within
65 [min, max] inclusive.
66 */
67 uint32_t nextRangeU(uint32_t min, uint32_t max) {
68 SkASSERT(min <= max);
bsalomon@google.com6d5d08f2013-01-25 19:19:20 +000069 uint32_t range = max - min + 1;
70 if (0 == range) {
71 return this->nextU();
72 } else {
73 return min + this->nextU() % range;
74 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 }
76
bsalomon@google.comd4726202012-08-03 14:34:46 +000077 /** Return the next pseudo random unsigned number, mapped to lie within
78 [0, count).
79 */
80 uint32_t nextULessThan(uint32_t count) {
81 SkASSERT(count > 0);
82 return this->nextRangeU(0, count - 1);
83 }
84
reed@android.com8a1c16f2008-12-17 15:59:43 +000085 /** Return the next pseudo random number expressed as an unsigned SkFixed
86 in the range [0..SK_Fixed1).
87 */
88 SkFixed nextUFixed1() { return this->nextU() >> 16; }
89
90 /** Return the next pseudo random number expressed as a signed SkFixed
91 in the range (-SK_Fixed1..SK_Fixed1).
92 */
93 SkFixed nextSFixed1() { return this->nextS() >> 15; }
94
95 /** Return the next pseudo random number expressed as a SkScalar
96 in the range [0..SK_Scalar1).
97 */
98 SkScalar nextUScalar1() { return SkFixedToScalar(this->nextUFixed1()); }
99
100 /** Return the next pseudo random number expressed as a SkScalar
bsalomon@google.com0a7672f2012-08-03 18:12:20 +0000101 in the range [min..max).
102 */
103 SkScalar nextRangeScalar(SkScalar min, SkScalar max) {
mike@reedtribe.orgd173b872014-01-23 02:02:45 +0000104 return this->nextUScalar1() * (max - min) + min;
bsalomon@google.com0a7672f2012-08-03 18:12:20 +0000105 }
106
107 /** Return the next pseudo random number expressed as a SkScalar
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108 in the range (-SK_Scalar1..SK_Scalar1).
109 */
110 SkScalar nextSScalar1() { return SkFixedToScalar(this->nextSFixed1()); }
111
bsalomon@google.comd4726202012-08-03 14:34:46 +0000112 /** Return the next pseudo random number as a bool.
113 */
114 bool nextBool() { return this->nextU() >= 0x80000000; }
115
bsalomon@google.com705e8402012-11-27 15:43:57 +0000116 /** A biased version of nextBool().
117 */
118 bool nextBiasedBool(SkScalar fractionTrue) {
119 SkASSERT(fractionTrue >= 0 && fractionTrue <= SK_Scalar1);
120 return this->nextUScalar1() <= fractionTrue;
121 }
122
reed@google.com57212f92013-12-30 14:40:38 +0000123 /**
124 * Return the next pseudo random number as a signed 64bit value.
125 */
126 int64_t next64() {
127 int64_t hi = this->nextS();
128 return (hi << 32) | this->nextU();
129 }
130
reed@google.com425a8c72012-10-02 17:51:29 +0000131 /**
132 * Return the current seed. This allows the caller to later reset to the
133 * same seed (using setSeed) so it can generate the same sequence.
134 */
135 int32_t getSeed() const { return fSeed; }
136
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137 /** Set the seed of the random object. The seed is initialized to 0 when the
138 object is first created, and is updated each time the next pseudo random
139 number is requested.
140 */
141 void setSeed(int32_t seed) { fSeed = (uint32_t)seed; }
142
143private:
144 // See "Numerical Recipes in C", 1992 page 284 for these constants
145 enum {
146 kMul = 1664525,
147 kAdd = 1013904223
148 };
149 uint32_t fSeed;
150};
151
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000152/** \class SkRandom
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000153
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000154 Utility class that implements pseudo random 32bit numbers using Marsaglia's
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000155 multiply-with-carry "mother of all" algorithm. Unlike rand(), this class holds
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000156 its own state, so that multiple instances can be used with no side-effects.
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000157
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000158 Has a large period and all bits are well-randomized.
159 */
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000160class SkRandom {
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000161public:
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000162 SkRandom() { init(0); }
163 SkRandom(uint32_t seed) { init(seed); }
164 SkRandom(const SkRandom& rand) : fK(rand.fK), fJ(rand.fJ) {}
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000165
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000166 SkRandom& operator=(const SkRandom& rand) {
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000167 fK = rand.fK;
168 fJ = rand.fJ;
169
170 return *this;
171 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000172
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000173 /** Return the next pseudo random number as an unsigned 32bit value.
174 */
175 uint32_t nextU() {
176 fK = kKMul*(fK & 0xffff) + (fK >> 16);
177 fJ = kJMul*(fJ & 0xffff) + (fJ >> 16);
178 return (((fK << 16) | (fK >> 16)) + fJ);
179 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000180
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000181 /** Return the next pseudo random number as a signed 32bit value.
182 */
183 int32_t nextS() { return (int32_t)this->nextU(); }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000184
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000185 /** Return the next pseudo random number as an unsigned 16bit value.
186 */
187 U16CPU nextU16() { return this->nextU() >> 16; }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000188
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000189 /** Return the next pseudo random number as a signed 16bit value.
190 */
191 S16CPU nextS16() { return this->nextS() >> 16; }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000192
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000193 /**
194 * Returns value [0...1) as an IEEE float
195 */
196 float nextF() {
197 unsigned int floatint = 0x3f800000 | (this->nextU() >> 9);
bsalomon@google.com753a3622013-02-07 19:52:30 +0000198 float f = SkBits2Float(floatint) - 1.0f;
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000199 return f;
200 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000201
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000202 /**
203 * Returns value [min...max) as a float
204 */
205 float nextRangeF(float min, float max) {
206 return min + this->nextF() * (max - min);
207 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000208
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000209 /** Return the next pseudo random number, as an unsigned value of
210 at most bitCount bits.
211 @param bitCount The maximum number of bits to be returned
212 */
213 uint32_t nextBits(unsigned bitCount) {
214 SkASSERT(bitCount > 0 && bitCount <= 32);
215 return this->nextU() >> (32 - bitCount);
216 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000217
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000218 /** Return the next pseudo random unsigned number, mapped to lie within
219 [min, max] inclusive.
220 */
221 uint32_t nextRangeU(uint32_t min, uint32_t max) {
222 SkASSERT(min <= max);
223 uint32_t range = max - min + 1;
224 if (0 == range) {
225 return this->nextU();
226 } else {
227 return min + this->nextU() % range;
228 }
229 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000230
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000231 /** Return the next pseudo random unsigned number, mapped to lie within
232 [0, count).
233 */
234 uint32_t nextULessThan(uint32_t count) {
235 SkASSERT(count > 0);
236 return this->nextRangeU(0, count - 1);
237 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000238
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000239 /** Return the next pseudo random number expressed as an unsigned SkFixed
240 in the range [0..SK_Fixed1).
241 */
242 SkFixed nextUFixed1() { return this->nextU() >> 16; }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000243
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000244 /** Return the next pseudo random number expressed as a signed SkFixed
245 in the range (-SK_Fixed1..SK_Fixed1).
246 */
247 SkFixed nextSFixed1() { return this->nextS() >> 15; }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000248
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000249 /** Return the next pseudo random number expressed as a SkScalar
250 in the range [0..SK_Scalar1).
251 */
252 SkScalar nextUScalar1() { return SkFixedToScalar(this->nextUFixed1()); }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000253
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000254 /** Return the next pseudo random number expressed as a SkScalar
255 in the range [min..max).
256 */
257 SkScalar nextRangeScalar(SkScalar min, SkScalar max) {
mike@reedtribe.orgd173b872014-01-23 02:02:45 +0000258 return this->nextUScalar1() * (max - min) + min;
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000259 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000260
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000261 /** Return the next pseudo random number expressed as a SkScalar
262 in the range (-SK_Scalar1..SK_Scalar1).
263 */
264 SkScalar nextSScalar1() { return SkFixedToScalar(this->nextSFixed1()); }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000265
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000266 /** Return the next pseudo random number as a bool.
267 */
268 bool nextBool() { return this->nextU() >= 0x80000000; }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000269
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000270 /** A biased version of nextBool().
271 */
272 bool nextBiasedBool(SkScalar fractionTrue) {
273 SkASSERT(fractionTrue >= 0 && fractionTrue <= SK_Scalar1);
274 return this->nextUScalar1() <= fractionTrue;
275 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000276
reed@google.com57212f92013-12-30 14:40:38 +0000277 /**
278 * Return the next pseudo random number as a signed 64bit value.
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000279 */
reed@google.com57212f92013-12-30 14:40:38 +0000280 int64_t next64() {
281 int64_t hi = this->nextS();
282 return (hi << 32) | this->nextU();
283 }
skia.committer@gmail.comf5e1f632013-12-31 07:01:36 +0000284
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000285 /** Reset the random object.
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000286 */
287 void setSeed(uint32_t seed) { init(seed); }
288
289private:
290 // Initialize state variables with LCG.
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000291 // We must ensure that both J and K are non-zero, otherwise the
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000292 // multiply-with-carry step will forevermore return zero.
293 void init(uint32_t seed) {
294 fK = NextLCG(seed);
295 if (0 == fK) {
296 fK = NextLCG(fK);
297 }
298 fJ = NextLCG(fK);
299 if (0 == fJ) {
300 fJ = NextLCG(fJ);
301 }
302 SkASSERT(0 != fK && 0 != fJ);
303 }
304 static uint32_t NextLCG(uint32_t seed) { return kMul*seed + kAdd; }
305
306 // See "Numerical Recipes in C", 1992 page 284 for these constants
307 // For the LCG that sets the initial state from a seed
308 enum {
309 kMul = 1664525,
310 kAdd = 1013904223
311 };
312 // Constants for the multiply-with-carry steps
313 enum {
314 kKMul = 30345,
315 kJMul = 18000,
316 };
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000317
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000318 uint32_t fK;
319 uint32_t fJ;
320};
321
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322#endif