Răsfoiți Sursa

Fix biased output of randi_range

Yuri Roubinsky 4 ani în urmă
părinte
comite
31faa1f226

+ 11 - 5
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() {}

+ 4 - 0
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,

+ 10 - 0
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;
+	}
+}

+ 1 - 0
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