diff options
author | Shauren <shauren.trinity@gmail.com> | 2019-11-09 13:32:58 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-12-19 00:13:11 +0100 |
commit | b93bf95f2e76eca8be12ba07828387ab8529c050 (patch) | |
tree | 3cce522959f5a57ed2c57aca2d0b339ad79bce4e /src/common/Utilities | |
parent | 08b40733a58da23ced34915cb67c0ef24e6e9059 (diff) |
Core/Random: Refactor random number generation to use std::uniform_*_distribution to restrict result range instead of doing that ourselves
* Seed SFMTRand with more values for its state
(cherry picked from commit 73bc3d8ea49a4793b14976e86010a36f19c1d18b)
Diffstat (limited to 'src/common/Utilities')
-rw-r--r-- | src/common/Utilities/Containers.h | 2 | ||||
-rw-r--r-- | src/common/Utilities/Random.cpp | 26 | ||||
-rw-r--r-- | src/common/Utilities/Random.h | 6 | ||||
-rw-r--r-- | src/common/Utilities/SFMTRand.cpp | 65 | ||||
-rw-r--r-- | src/common/Utilities/SFMTRand.h | 9 |
5 files changed, 36 insertions, 72 deletions
diff --git a/src/common/Utilities/Containers.h b/src/common/Utilities/Containers.h index 9c2f7849923..d7103d32e37 100644 --- a/src/common/Utilities/Containers.h +++ b/src/common/Utilities/Containers.h @@ -176,7 +176,7 @@ namespace Trinity template<class C> inline void RandomShuffle(C& container) { - std::shuffle(std::begin(container), std::end(container), SFMTEngine::Instance()); + std::shuffle(std::begin(container), std::end(container), RandomEngine::Instance()); } /** diff --git a/src/common/Utilities/Random.cpp b/src/common/Utilities/Random.cpp index 974f13db0be..5a4004b41bd 100644 --- a/src/common/Utilities/Random.cpp +++ b/src/common/Utilities/Random.cpp @@ -22,7 +22,7 @@ #include <random> static boost::thread_specific_ptr<SFMTRand> sfmtRand; -static SFMTEngine engine; +static RandomEngine engine; static SFMTRand* GetRng() { @@ -40,26 +40,28 @@ static SFMTRand* GetRng() int32 irand(int32 min, int32 max) { ASSERT(max >= min); - return int32(GetRng()->IRandom(min, max)); + std::uniform_int_distribution<int32> uid(min, max); + return uid(engine); } uint32 urand(uint32 min, uint32 max) { ASSERT(max >= min); - return GetRng()->URandom(min, max); + std::uniform_int_distribution<uint32> uid(min, max); + return uid(engine); } uint32 urandms(uint32 min, uint32 max) { - ASSERT(max >= min); ASSERT(std::numeric_limits<uint32>::max() / Milliseconds::period::den >= max); - return GetRng()->URandom(min * Milliseconds::period::den, max * Milliseconds::period::den); + return urand(min * Milliseconds::period::den, max * Milliseconds::period::den); } float frand(float min, float max) { ASSERT(max >= min); - return float(GetRng()->Random() * (max - min) + min); + std::uniform_real_distribution<float> urd(min, max); + return urd(engine); } Milliseconds randtime(Milliseconds min, Milliseconds max) @@ -72,26 +74,28 @@ Milliseconds randtime(Milliseconds min, Milliseconds max) uint32 rand32() { - return GetRng()->BRandom(); + return GetRng()->RandomUInt32(); } double rand_norm() { - return GetRng()->Random(); + std::uniform_real_distribution<double> urd; + return urd(engine); } double rand_chance() { - return GetRng()->Random() * 100.0; + std::uniform_real_distribution<double> urd(0.0, 100.0); + return urd(engine); } uint32 urandweighted(size_t count, double const* chances) { std::discrete_distribution<uint32> dd(chances, chances + count); - return dd(SFMTEngine::Instance()); + return dd(engine); } -SFMTEngine& SFMTEngine::Instance() +RandomEngine& RandomEngine::Instance() { return engine; } diff --git a/src/common/Utilities/Random.h b/src/common/Utilities/Random.h index 2f6d105fad1..82a498e42eb 100644 --- a/src/common/Utilities/Random.h +++ b/src/common/Utilities/Random.h @@ -62,9 +62,9 @@ inline bool roll_chance_i(int chance) } /* -* SFMT wrapper satisfying UniformRandomNumberGenerator concept for use in <random> algorithms +* Wrapper satisfying UniformRandomNumberGenerator concept for use in <random> algorithms */ -class TC_COMMON_API SFMTEngine +class TC_COMMON_API RandomEngine { public: typedef uint32 result_type; @@ -73,7 +73,7 @@ public: static constexpr result_type max() { return std::numeric_limits<result_type>::max(); } result_type operator()() const { return rand32(); } - static SFMTEngine& Instance(); + static RandomEngine& Instance(); }; #endif // Random_h__ diff --git a/src/common/Utilities/SFMTRand.cpp b/src/common/Utilities/SFMTRand.cpp index ddc65c8a772..2c472f2364a 100644 --- a/src/common/Utilities/SFMTRand.cpp +++ b/src/common/Utilities/SFMTRand.cpp @@ -16,67 +16,30 @@ */ #include "SFMTRand.h" - -#include <exception> +#include <algorithm> +#include <array> +#include <functional> +#include <random> #include <emmintrin.h> #include <ctime> SFMTRand::SFMTRand() { - RandomInit((uint32_t)(time(0))); -} - -void SFMTRand::RandomInit(uint32_t seed) // Re-seed -{ - sfmt_init_gen_rand(&state, seed); -} + std::random_device dev; + if (dev.entropy() > 0) + { + std::array<uint32, SFMT_N32> seed; + std::generate(seed.begin(), seed.end(), std::ref(dev)); -int32_t SFMTRand::IRandom(int32_t min, int32_t max) // Output random integer -{ - // Output random integer in the interval min <= x <= max - // Slightly inaccurate if (max-min+1) is not a power of 2 - if (max <= min) { - if (max == min) return min; else return 0x80000000; + sfmt_init_by_array(&_state, seed.data(), seed.size()); } - // Assume 64 bit integers supported. Use multiply and shift method - uint32_t interval; // Length of interval - uint64_t longran; // Random bits * interval - uint32_t iran; // Longran / 2^32 - - interval = (uint32_t)(max - min + 1); - longran = (uint64_t)BRandom() * interval; - iran = (uint32_t)(longran >> 32); - // Convert back to signed and return result - return (int32_t)iran + min; -} - -uint32_t SFMTRand::URandom(uint32_t min, uint32_t max) -{ - // Output random integer in the interval min <= x <= max - // Slightly inaccurate if (max-min+1) is not a power of 2 - if (max <= min) { - if (max == min) return min; else return 0; - } - // Assume 64 bit integers supported. Use multiply and shift method - uint32_t interval; // Length of interval - uint64_t longran; // Random bits * interval - uint32_t iran; // Longran / 2^32 - - interval = (uint32_t)(max - min + 1); - longran = (uint64_t)BRandom() * interval; - iran = (uint32_t)(longran >> 32); - // Convert back to signed and return result - return iran + min; -} - -double SFMTRand::Random() // Output random floating point number -{ - return sfmt_genrand_real1(&state); + else + sfmt_init_gen_rand(&_state, uint32(time(nullptr))); } -uint32_t SFMTRand::BRandom() // Output random bits +uint32 SFMTRand::RandomUInt32() // Output random bits { - return sfmt_genrand_uint32(&state); + return sfmt_genrand_uint32(&_state); } void* SFMTRand::operator new(size_t size, std::nothrow_t const&) diff --git a/src/common/Utilities/SFMTRand.h b/src/common/Utilities/SFMTRand.h index 1189accae2f..7d9a820c487 100644 --- a/src/common/Utilities/SFMTRand.h +++ b/src/common/Utilities/SFMTRand.h @@ -18,6 +18,7 @@ #ifndef SFMTRand_h__ #define SFMTRand_h__ +#include "Define.h" #include <SFMT.h> #include <new> @@ -27,11 +28,7 @@ class SFMTRand { public: SFMTRand(); - void RandomInit(uint32_t seed); // Re-seed - int32_t IRandom(int32_t min, int32_t max); // Output random integer - uint32_t URandom(uint32_t min, uint32_t max); - double Random(); // Output random floating point number - uint32_t BRandom(); // Output random bits + uint32 RandomUInt32(); // Output random bits void* operator new(size_t size, std::nothrow_t const&); void operator delete(void* ptr, std::nothrow_t const&); void* operator new(size_t size); @@ -41,7 +38,7 @@ public: void* operator new[](size_t size); void operator delete[](void* ptr); private: - sfmt_t state; + sfmt_t _state; }; #endif // SFMTRand_h__ |