summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuri Roubinsky <chaosus89@gmail.com>2020-10-29 15:40:53 +0300
committerYuri Roubinsky <chaosus89@gmail.com>2020-10-29 15:41:00 +0300
commit31faa1f22626b8745ed4a1541497832b6f595df2 (patch)
tree25baec4470e850e40c1ab5099ff8d9886c6087de
parent13e93fe90499b3aac569ac09440c8d6056efba68 (diff)
Fix biased output of randi_range
-rw-r--r--core/math/random_number_generator.h16
-rw-r--r--core/math/random_pcg.h4
-rw-r--r--thirdparty/misc/pcg.cpp10
-rw-r--r--thirdparty/misc/pcg.h1
4 files changed, 26 insertions, 5 deletions
diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h
index 416e52ea87..2e7941b345 100644
--- a/core/math/random_number_generator.h
+++ b/core/math/random_number_generator.h
@@ -58,12 +58,18 @@ public:
_FORCE_INLINE_ real_t randfn(real_t mean = 0.0, real_t deviation = 1.0) { return randbase.randfn(mean, deviation); }
_FORCE_INLINE_ int randi_range(int from, int to) {
- unsigned int ret = randbase.rand();
- if (to < from) {
- return ret % (from - to + 1) + to;
- } else {
- return ret % (to - from + 1) + from;
+ int range;
+ int min;
+ if (to > from) {
+ range = to - from + 1;
+ min = from;
+ } else if (to < from) {
+ range = from - to + 1;
+ min = to;
+ } else { // from == to
+ return from;
}
+ return randbase.rand(range) + min;
}
RandomNumberGenerator() {}
diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h
index 09b13ab74d..dfdae53eed 100644
--- a/core/math/random_pcg.h
+++ b/core/math/random_pcg.h
@@ -81,6 +81,10 @@ public:
current_seed = pcg.state;
return pcg32_random_r(&pcg);
}
+ _FORCE_INLINE_ uint32_t rand(uint32_t bounds) {
+ current_seed = pcg.state;
+ return pcg32_boundedrand_r(&pcg, bounds);
+ }
// Obtaining floating point numbers in [0, 1] range with "good enough" uniformity.
// These functions sample the output of rand() as the fraction part of an infinite binary number,
diff --git a/thirdparty/misc/pcg.cpp b/thirdparty/misc/pcg.cpp
index c421e16f89..5f4bf40460 100644
--- a/thirdparty/misc/pcg.cpp
+++ b/thirdparty/misc/pcg.cpp
@@ -23,3 +23,13 @@ void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
rng->state += initstate;
pcg32_random_r(rng);
}
+
+// Source from https://github.com/imneme/pcg-c-basic/blob/master/pcg_basic.c
+uint32_t pcg32_boundedrand_r(pcg32_random_t *rng, uint32_t bound) {
+ uint32_t threshold = -bound % bound;
+ for (;;) {
+ uint32_t r = pcg32_random_r(rng);
+ if (r >= threshold)
+ return r % bound;
+ }
+}
diff --git a/thirdparty/misc/pcg.h b/thirdparty/misc/pcg.h
index 6f42b3b094..0faab73e64 100644
--- a/thirdparty/misc/pcg.h
+++ b/thirdparty/misc/pcg.h
@@ -11,5 +11,6 @@
typedef struct { uint64_t state; uint64_t inc; } pcg32_random_t;
uint32_t pcg32_random_r(pcg32_random_t* rng);
void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq);
+uint32_t pcg32_boundedrand_r(pcg32_random_t* rng, uint32_t bound);
#endif // RANDOM_H