aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2019-11-09 13:32:58 +0100
committerShauren <shauren.trinity@gmail.com>2019-11-09 15:09:22 +0100
commit73bc3d8ea49a4793b14976e86010a36f19c1d18b (patch)
tree4d24a1bbbc757175633eaab2d65012570efa6a67 /src/common
parent4e0279b0e48c9992842010b9f3f132e54a460128 (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
Diffstat (limited to 'src/common')
-rw-r--r--src/common/Utilities/Containers.h2
-rw-r--r--src/common/Utilities/Random.cpp26
-rw-r--r--src/common/Utilities/Random.h6
-rw-r--r--src/common/Utilities/SFMTRand.cpp75
-rw-r--r--src/common/Utilities/SFMTRand.h11
5 files changed, 42 insertions, 78 deletions
diff --git a/src/common/Utilities/Containers.h b/src/common/Utilities/Containers.h
index 845ac173fec..edd7be3ea7c 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 df55901dccf..3e1623ee8df 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 bc1bf26e890..45d7457eb02 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 ca88ad88559..c3eb947e9e5 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);
-}
-
-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;
- }
- // 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
+ std::random_device dev;
+ if (dev.entropy() > 0)
+ {
+ std::array<uint32, SFMT_N32> seed;
+ std::generate(seed.begin(), seed.end(), std::ref(dev));
- 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;
+ 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 iran + min;
+ else
+ sfmt_init_gen_rand(&_state, uint32(time(nullptr)));
}
-double SFMTRand::Random() // Output random floating point number
+uint32 SFMTRand::RandomUInt32() // Output random bits
{
- return sfmt_genrand_real1(&state);
-}
-
-uint32_t SFMTRand::BRandom() // Output random bits
-{
- return sfmt_genrand_uint32(&state);
+ return sfmt_genrand_uint32(&_state);
}
void* SFMTRand::operator new(size_t size, std::nothrow_t const&)
@@ -84,7 +47,7 @@ void* SFMTRand::operator new(size_t size, std::nothrow_t const&)
return _mm_malloc(size, 16);
}
- void SFMTRand::operator delete(void* ptr, std::nothrow_t const&)
+void SFMTRand::operator delete(void* ptr, std::nothrow_t const&)
{
_mm_free(ptr);
}
@@ -104,17 +67,17 @@ void* SFMTRand::operator new[](size_t size, std::nothrow_t const&)
return _mm_malloc(size, 16);
}
- void SFMTRand::operator delete[](void* ptr, std::nothrow_t const&)
+void SFMTRand::operator delete[](void* ptr, std::nothrow_t const&)
{
_mm_free(ptr);
}
- void* SFMTRand::operator new[](size_t size)
+void* SFMTRand::operator new[](size_t size)
{
return _mm_malloc(size, 16);
}
- void SFMTRand::operator delete[](void* ptr)
+void SFMTRand::operator delete[](void* ptr)
{
_mm_free(ptr);
-} \ No newline at end of file
+}
diff --git a/src/common/Utilities/SFMTRand.h b/src/common/Utilities/SFMTRand.h
index 2ed60d9a565..ec1cfb0bc6a 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__ \ No newline at end of file
+#endif // SFMTRand_h__