blob: ecaedafc2fc051817d982c52c9332f6e8a261544 [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 SkRandom
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +000014
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000015 Utility class that implements pseudo random 32bit numbers using Marsaglia's
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +000016 multiply-with-carry "mother of all" algorithm. Unlike rand(), this class holds
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000017 its own state, so that multiple instances can be used with no side-effects.
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +000018
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000019 Has a large period and all bits are well-randomized.
20 */
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000021class SkRandom {
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000022public:
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000023 SkRandom() { init(0); }
24 SkRandom(uint32_t seed) { init(seed); }
25 SkRandom(const SkRandom& rand) : fK(rand.fK), fJ(rand.fJ) {}
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000026
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000027 SkRandom& operator=(const SkRandom& rand) {
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000028 fK = rand.fK;
29 fJ = rand.fJ;
30
31 return *this;
32 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +000033
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000034 /** Return the next pseudo random number as an unsigned 32bit value.
35 */
36 uint32_t nextU() {
37 fK = kKMul*(fK & 0xffff) + (fK >> 16);
38 fJ = kJMul*(fJ & 0xffff) + (fJ >> 16);
39 return (((fK << 16) | (fK >> 16)) + fJ);
40 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +000041
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000042 /** Return the next pseudo random number as a signed 32bit value.
43 */
44 int32_t nextS() { return (int32_t)this->nextU(); }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +000045
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000046 /** Return the next pseudo random number as an unsigned 16bit value.
47 */
48 U16CPU nextU16() { return this->nextU() >> 16; }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +000049
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000050 /** Return the next pseudo random number as a signed 16bit value.
51 */
52 S16CPU nextS16() { return this->nextS() >> 16; }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +000053
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000054 /**
55 * Returns value [0...1) as an IEEE float
56 */
57 float nextF() {
58 unsigned int floatint = 0x3f800000 | (this->nextU() >> 9);
bsalomon@google.com753a3622013-02-07 19:52:30 +000059 float f = SkBits2Float(floatint) - 1.0f;
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000060 return f;
61 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +000062
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000063 /**
64 * Returns value [min...max) as a float
65 */
66 float nextRangeF(float min, float max) {
67 return min + this->nextF() * (max - min);
68 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +000069
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000070 /** Return the next pseudo random number, as an unsigned value of
71 at most bitCount bits.
72 @param bitCount The maximum number of bits to be returned
73 */
74 uint32_t nextBits(unsigned bitCount) {
75 SkASSERT(bitCount > 0 && bitCount <= 32);
76 return this->nextU() >> (32 - bitCount);
77 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +000078
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000079 /** Return the next pseudo random unsigned number, mapped to lie within
80 [min, max] inclusive.
81 */
82 uint32_t nextRangeU(uint32_t min, uint32_t max) {
83 SkASSERT(min <= max);
84 uint32_t range = max - min + 1;
85 if (0 == range) {
86 return this->nextU();
87 } else {
88 return min + this->nextU() % range;
89 }
90 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +000091
jvanverth@google.coma8e66f72013-01-30 15:42:19 +000092 /** Return the next pseudo random unsigned number, mapped to lie within
93 [0, count).
94 */
95 uint32_t nextULessThan(uint32_t count) {
96 SkASSERT(count > 0);
97 return this->nextRangeU(0, count - 1);
98 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +000099
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000100 /** Return the next pseudo random number expressed as a SkScalar
101 in the range [0..SK_Scalar1).
102 */
103 SkScalar nextUScalar1() { return SkFixedToScalar(this->nextUFixed1()); }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000104
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000105 /** Return the next pseudo random number expressed as a SkScalar
106 in the range [min..max).
107 */
108 SkScalar nextRangeScalar(SkScalar min, SkScalar max) {
mike@reedtribe.orgd173b872014-01-23 02:02:45 +0000109 return this->nextUScalar1() * (max - min) + min;
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000110 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000111
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000112 /** Return the next pseudo random number expressed as a SkScalar
benjaminwagner12634482016-03-31 06:13:22 -0700113 in the range [-SK_Scalar1..SK_Scalar1).
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000114 */
115 SkScalar nextSScalar1() { return SkFixedToScalar(this->nextSFixed1()); }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000116
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000117 /** Return the next pseudo random number as a bool.
118 */
119 bool nextBool() { return this->nextU() >= 0x80000000; }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000120
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000121 /** A biased version of nextBool().
122 */
123 bool nextBiasedBool(SkScalar fractionTrue) {
124 SkASSERT(fractionTrue >= 0 && fractionTrue <= SK_Scalar1);
125 return this->nextUScalar1() <= fractionTrue;
126 }
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000127
reed@google.com57212f92013-12-30 14:40:38 +0000128 /**
129 * Return the next pseudo random number as a signed 64bit value.
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000130 */
reed@google.com57212f92013-12-30 14:40:38 +0000131 int64_t next64() {
132 int64_t hi = this->nextS();
133 return (hi << 32) | this->nextU();
134 }
skia.committer@gmail.comf5e1f632013-12-31 07:01:36 +0000135
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000136 /** Reset the random object.
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000137 */
138 void setSeed(uint32_t seed) { init(seed); }
139
140private:
141 // Initialize state variables with LCG.
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000142 // We must ensure that both J and K are non-zero, otherwise the
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000143 // multiply-with-carry step will forevermore return zero.
144 void init(uint32_t seed) {
145 fK = NextLCG(seed);
146 if (0 == fK) {
147 fK = NextLCG(fK);
148 }
149 fJ = NextLCG(fK);
150 if (0 == fJ) {
151 fJ = NextLCG(fJ);
152 }
153 SkASSERT(0 != fK && 0 != fJ);
154 }
155 static uint32_t NextLCG(uint32_t seed) { return kMul*seed + kAdd; }
156
benjaminwagner12634482016-03-31 06:13:22 -0700157 /** Return the next pseudo random number expressed as an unsigned SkFixed
158 in the range [0..SK_Fixed1).
159 */
160 SkFixed nextUFixed1() { return this->nextU() >> 16; }
161
162 /** Return the next pseudo random number expressed as a signed SkFixed
163 in the range [-SK_Fixed1..SK_Fixed1).
164 */
165 SkFixed nextSFixed1() { return this->nextS() >> 15; }
166
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000167 // See "Numerical Recipes in C", 1992 page 284 for these constants
168 // For the LCG that sets the initial state from a seed
169 enum {
170 kMul = 1664525,
171 kAdd = 1013904223
172 };
173 // Constants for the multiply-with-carry steps
174 enum {
175 kKMul = 30345,
176 kJMul = 18000,
177 };
skia.committer@gmail.com24d5ee42013-01-31 07:06:15 +0000178
jvanverth@google.coma8e66f72013-01-30 15:42:19 +0000179 uint32_t fK;
180 uint32_t fJ;
181};
182
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183#endif