Merge pull request #88883 from joaoh82/add-weighted-random-method
Add `RandomNumberGenerator::rand_weighted` method
This commit is contained in:
commit
bd7637248c
5 changed files with 48 additions and 0 deletions
|
@ -42,6 +42,7 @@ void RandomNumberGenerator::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("randfn", "mean", "deviation"), &RandomNumberGenerator::randfn, DEFVAL(0.0), DEFVAL(1.0));
|
ClassDB::bind_method(D_METHOD("randfn", "mean", "deviation"), &RandomNumberGenerator::randfn, DEFVAL(0.0), DEFVAL(1.0));
|
||||||
ClassDB::bind_method(D_METHOD("randf_range", "from", "to"), &RandomNumberGenerator::randf_range);
|
ClassDB::bind_method(D_METHOD("randf_range", "from", "to"), &RandomNumberGenerator::randf_range);
|
||||||
ClassDB::bind_method(D_METHOD("randi_range", "from", "to"), &RandomNumberGenerator::randi_range);
|
ClassDB::bind_method(D_METHOD("randi_range", "from", "to"), &RandomNumberGenerator::randi_range);
|
||||||
|
ClassDB::bind_method(D_METHOD("rand_weighted", "weights"), &RandomNumberGenerator::rand_weighted);
|
||||||
ClassDB::bind_method(D_METHOD("randomize"), &RandomNumberGenerator::randomize);
|
ClassDB::bind_method(D_METHOD("randomize"), &RandomNumberGenerator::randomize);
|
||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
|
||||||
|
|
|
@ -57,6 +57,8 @@ public:
|
||||||
_FORCE_INLINE_ real_t randfn(real_t p_mean = 0.0, real_t p_deviation = 1.0) { return randbase.randfn(p_mean, p_deviation); }
|
_FORCE_INLINE_ real_t randfn(real_t p_mean = 0.0, real_t p_deviation = 1.0) { return randbase.randfn(p_mean, p_deviation); }
|
||||||
_FORCE_INLINE_ int randi_range(int p_from, int p_to) { return randbase.random(p_from, p_to); }
|
_FORCE_INLINE_ int randi_range(int p_from, int p_to) { return randbase.random(p_from, p_to); }
|
||||||
|
|
||||||
|
_FORCE_INLINE_ int rand_weighted(const Vector<float> &p_weights) { return randbase.rand_weighted(p_weights); }
|
||||||
|
|
||||||
RandomNumberGenerator() { randbase.randomize(); }
|
RandomNumberGenerator() { randbase.randomize(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "random_pcg.h"
|
#include "random_pcg.h"
|
||||||
|
|
||||||
#include "core/os/os.h"
|
#include "core/os/os.h"
|
||||||
|
#include "core/templates/vector.h"
|
||||||
|
|
||||||
RandomPCG::RandomPCG(uint64_t p_seed, uint64_t p_inc) :
|
RandomPCG::RandomPCG(uint64_t p_seed, uint64_t p_inc) :
|
||||||
pcg(),
|
pcg(),
|
||||||
|
@ -42,6 +43,26 @@ void RandomPCG::randomize() {
|
||||||
seed(((uint64_t)OS::get_singleton()->get_unix_time() + OS::get_singleton()->get_ticks_usec()) * pcg.state + PCG_DEFAULT_INC_64);
|
seed(((uint64_t)OS::get_singleton()->get_unix_time() + OS::get_singleton()->get_ticks_usec()) * pcg.state + PCG_DEFAULT_INC_64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int RandomPCG::rand_weighted(const Vector<float> &p_weights) {
|
||||||
|
ERR_FAIL_COND_V_MSG(p_weights.is_empty(), -1, "Weights array is empty.");
|
||||||
|
int64_t weights_size = p_weights.size();
|
||||||
|
const float *weights = p_weights.ptr();
|
||||||
|
float weights_sum = 0.0;
|
||||||
|
for (int64_t i = 0; i < weights_size; ++i) {
|
||||||
|
weights_sum += weights[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
float remaining_distance = Math::randf() * weights_sum;
|
||||||
|
for (int64_t i = 0; i < weights_size; ++i) {
|
||||||
|
remaining_distance -= weights[i];
|
||||||
|
if (remaining_distance < 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
double RandomPCG::random(double p_from, double p_to) {
|
double RandomPCG::random(double p_from, double p_to) {
|
||||||
return randd() * (p_to - p_from) + p_from;
|
return randd() * (p_to - p_from) + p_from;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,9 @@ static int __bsr_clz32(uint32_t x) {
|
||||||
#define LDEXPF(s, e) ldexp(s, e)
|
#define LDEXPF(s, e) ldexp(s, e)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class Vector;
|
||||||
|
|
||||||
class RandomPCG {
|
class RandomPCG {
|
||||||
pcg32_random_t pcg;
|
pcg32_random_t pcg;
|
||||||
uint64_t current_seed = 0; // The seed the current generator state started from.
|
uint64_t current_seed = 0; // The seed the current generator state started from.
|
||||||
|
@ -87,6 +90,8 @@ public:
|
||||||
return pcg32_boundedrand_r(&pcg, bounds);
|
return pcg32_boundedrand_r(&pcg, bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rand_weighted(const Vector<float> &p_weights);
|
||||||
|
|
||||||
// Obtaining floating point numbers in [0, 1] range with "good enough" uniformity.
|
// 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,
|
// These functions sample the output of rand() as the fraction part of an infinite binary number,
|
||||||
// with some tricks applied to reduce ops and branching:
|
// with some tricks applied to reduce ops and branching:
|
||||||
|
|
|
@ -17,6 +17,25 @@
|
||||||
<link title="Random number generation">$DOCS_URL/tutorials/math/random_number_generation.html</link>
|
<link title="Random number generation">$DOCS_URL/tutorials/math/random_number_generation.html</link>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
<methods>
|
<methods>
|
||||||
|
<method name="rand_weighted">
|
||||||
|
<return type="int" />
|
||||||
|
<param index="0" name="weights" type="PackedFloat32Array" />
|
||||||
|
<description>
|
||||||
|
Returns a random index with non-uniform weights. Prints an error and returns [code]-1[/code] if the array is empty.
|
||||||
|
[codeblocks]
|
||||||
|
[gdscript]
|
||||||
|
var rnd = RandomNumberGenerator.new()
|
||||||
|
|
||||||
|
var my_array = ["one", "two", "three, "four"]
|
||||||
|
var weights = PackedFloat32Array([0.5, 1, 1, 2])
|
||||||
|
|
||||||
|
# Prints one of the four elements in `my_array`.
|
||||||
|
# It is more likely to print "four", and less likely to print "two".
|
||||||
|
print(my_array[rng.rand_weighted(weights)])
|
||||||
|
[/gdscript]
|
||||||
|
[/codeblocks]
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="randf">
|
<method name="randf">
|
||||||
<return type="float" />
|
<return type="float" />
|
||||||
<description>
|
<description>
|
||||||
|
|
Loading…
Reference in a new issue