diff options
author | Yuri Roubinsky <chaosus89@gmail.com> | 2020-10-29 15:40:53 +0300 |
---|---|---|
committer | Yuri Roubinsky <chaosus89@gmail.com> | 2020-10-29 15:41:00 +0300 |
commit | 31faa1f22626b8745ed4a1541497832b6f595df2 (patch) | |
tree | 25baec4470e850e40c1ab5099ff8d9886c6087de | |
parent | 13e93fe90499b3aac569ac09440c8d6056efba68 (diff) |
Fix biased output of randi_range
-rw-r--r-- | core/math/random_number_generator.h | 16 | ||||
-rw-r--r-- | core/math/random_pcg.h | 4 | ||||
-rw-r--r-- | thirdparty/misc/pcg.cpp | 10 | ||||
-rw-r--r-- | thirdparty/misc/pcg.h | 1 |
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 |