Rework of Random class. Now ensures better randomness, is more performant, and has function for retrieving seed.
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
4f563e6e67
commit
6f60cd7c96
|
@ -1,76 +1,83 @@
|
||||||
#ifndef ARBUTILS_RANDOM_HPP
|
#ifndef ARBUTILS_RANDOM_HPP
|
||||||
#define ARBUTILS_RANDOM_HPP
|
#define ARBUTILS_RANDOM_HPP
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
namespace Arbutils {
|
namespace Arbutils {
|
||||||
|
|
||||||
template <class RandomT> class BaseRandom {
|
template <class RandomT> class BaseRandom {
|
||||||
private:
|
private:
|
||||||
|
uint32_t _seed;
|
||||||
RandomT _rng;
|
RandomT _rng;
|
||||||
|
std::uniform_real_distribution<double> _distribution;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline constexpr BaseRandom()
|
inline constexpr BaseRandom() noexcept
|
||||||
: _rng(RandomT(
|
: _seed(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch())
|
std::chrono::system_clock::now().time_since_epoch())
|
||||||
.count())) {}
|
.count()),
|
||||||
|
_rng(_seed), _distribution(0.0, 1.0) {}
|
||||||
|
|
||||||
explicit inline constexpr BaseRandom(int32_t seed) : _rng(seed){};
|
explicit inline constexpr BaseRandom(uint64_t seed) noexcept
|
||||||
|
: _seed(seed), _rng(seed), _distribution(0.0, 1.0){};
|
||||||
|
|
||||||
/// Gets a random float between 0.0 and 1.0.
|
/// Gets a random float between 0.0 and 1.0.
|
||||||
[[nodiscard]] inline constexpr float GetFloat() {
|
[[nodiscard]] inline constexpr float GetFloat() noexcept {
|
||||||
return static_cast<float>(_rng()) / (static_cast<float>(std::mt19937::max() - std::mt19937::min()) - 0.5f);
|
return static_cast<float>(GetDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a random double between 0.0 and 1.0.
|
/// Gets a random double between 0.0 and 1.0.
|
||||||
[[nodiscard]] inline constexpr double GetDouble() {
|
[[nodiscard]] inline constexpr double GetDouble() noexcept {
|
||||||
return static_cast<double>(_rng()) /
|
return (double) _distribution(_rng);
|
||||||
((static_cast<double>(std::mt19937::max()) - std::mt19937::min()) - 0.5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a random 32 bit integer between 0 and max int.
|
/// Gets a random 32 bit integer
|
||||||
[[nodiscard]] inline constexpr int32_t Get() {
|
[[nodiscard]] inline constexpr int32_t Get() noexcept { return (int32_t)_rng(); }
|
||||||
return static_cast<int32_t>(GetDouble() * static_cast<float>(std::numeric_limits<int32_t>::max()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets a random 32 bit integer between 0, and given max parameter.
|
/// Gets a random 32 bit integer between 0, and given max parameter.
|
||||||
/// \param max The exclusive max value the random value should be.
|
/// \param max The exclusive max value the random value should be.
|
||||||
[[nodiscard]] inline constexpr int32_t Get(int32_t max) {
|
[[nodiscard]] inline int32_t Get(int32_t max) noexcept {
|
||||||
return static_cast<int32_t>(GetDouble() * static_cast<float>(max));
|
std::uniform_int_distribution<int32_t > distribution(0, max - 1);
|
||||||
|
return distribution(_rng);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a random 32 bit integer between given min and max parameters.
|
/// Gets a random 32 bit integer between given min and max parameters.
|
||||||
/// \param min The inclusive min value the random value should be.
|
/// \param min The inclusive min value the random value should be.
|
||||||
/// \param max The exclusive max value the random value should be.
|
/// \param max The exclusive max value the random value should be.
|
||||||
[[nodiscard]] inline constexpr int32_t Get(int32_t min, int32_t max) {
|
[[nodiscard]] inline int32_t Get(int32_t min, int32_t max) noexcept {
|
||||||
return static_cast<int32_t>(GetDouble() * static_cast<float>(max - min) + min);
|
std::uniform_int_distribution<int32_t > distribution(min, max - 1);
|
||||||
|
return distribution(_rng);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a random 32 bit unsigned integer between 0 and max unsigned int.
|
/// Gets a random 32 bit unsigned integer between 0 and max unsigned int.
|
||||||
[[nodiscard]] inline constexpr uint32_t GetUnsigned() {
|
[[nodiscard]] inline constexpr uint32_t GetUnsigned() noexcept {
|
||||||
return static_cast<int32_t>(GetDouble() * static_cast<float>(std::numeric_limits<uint32_t>::max()));
|
return _rng();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a random 32 bit unsigned integer between 0, and given max parameter.
|
/// Gets a random 32 bit unsigned integer between 0, and given max parameter.
|
||||||
/// \param max The exclusive max value the random value should be.
|
/// \param max The exclusive max value the random value should be.
|
||||||
[[nodiscard]] inline constexpr uint32_t GetUnsigned(uint32_t max) {
|
[[nodiscard]] inline uint32_t GetUnsigned(uint32_t max) noexcept {
|
||||||
return static_cast<int32_t>(GetDouble() * static_cast<float>(max));
|
std::uniform_int_distribution<uint32_t > distribution(0, max - 1);
|
||||||
|
return distribution(_rng);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a random 32 bit unsigned integer between given min and max parameters.
|
/// Gets a random 32 bit unsigned integer between given min and max parameters.
|
||||||
/// \param min The inclusive min value the random value should be.
|
/// \param min The inclusive min value the random value should be.
|
||||||
/// \param max The exclusive max value the random value should be.
|
/// \param max The exclusive max value the random value should be.
|
||||||
[[nodiscard]] inline constexpr uint32_t GetUnsigned(uint32_t min, uint32_t max) {
|
[[nodiscard]] inline uint32_t GetUnsigned(uint32_t min, uint32_t max) noexcept {
|
||||||
return static_cast<int32_t>(GetDouble() * static_cast<float>(max - min) + min);
|
std::uniform_int_distribution<uint32_t > distribution(min, max - 1);
|
||||||
|
return distribution(_rng);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline constexpr uint32_t GetSeed() const noexcept { return _seed; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Random : public BaseRandom<std::mt19937> {
|
class Random : public BaseRandom<std::mt19937> {
|
||||||
public:
|
public:
|
||||||
Random() : BaseRandom() {}
|
constexpr Random() : BaseRandom() {}
|
||||||
Random(int32_t seed) : BaseRandom(seed) {}
|
constexpr Random(int32_t seed) : BaseRandom(seed) {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif // ARBUTILS_RANDOM_HPP
|
#endif // ARBUTILS_RANDOM_HPP
|
||||||
|
|
|
@ -6,16 +6,16 @@
|
||||||
|
|
||||||
TEST_CASE("Random ints", "[Utilities]") {
|
TEST_CASE("Random ints", "[Utilities]") {
|
||||||
auto rand = Arbutils::Random(10);
|
auto rand = Arbutils::Random(10);
|
||||||
CHECK(rand.Get() == 1656398469);
|
CHECK(rand.Get() == -982170359);
|
||||||
CHECK(rand.Get() == 641584702);
|
CHECK(rand.Get() == 1283169405);
|
||||||
CHECK(rand.Get() == 44564466);
|
CHECK(rand.Get() == 89128932);
|
||||||
CHECK(rand.Get() == 1062123783);
|
CHECK(rand.Get() == 2124247567);
|
||||||
CHECK(rand.Get() == 1360749216);
|
CHECK(rand.Get() == -1573468864);
|
||||||
CHECK(rand.Get() == 951367352);
|
CHECK(rand.Get() == 1902734705);
|
||||||
CHECK(rand.Get() == 1608044094);
|
CHECK(rand.Get() == -1078879109);
|
||||||
CHECK(rand.Get() == 1786516046);
|
CHECK(rand.Get() == -721935204);
|
||||||
CHECK(rand.Get() == 1070535660);
|
CHECK(rand.Get() == 2141071321);
|
||||||
CHECK(rand.Get() == 1252673902);
|
CHECK(rand.Get() == -1789619491);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Random ints with limit", "[Utilities]") {
|
TEST_CASE("Random ints with limit", "[Utilities]") {
|
||||||
|
@ -93,7 +93,7 @@ TEST_CASE("Random distribution (max 0, min 2)", "[Utilities]") {
|
||||||
|
|
||||||
TEST_CASE("Random distribution (max 0, min 3)", "[Utilities]") {
|
TEST_CASE("Random distribution (max 0, min 3)", "[Utilities]") {
|
||||||
auto rand = Arbutils::Random(10);
|
auto rand = Arbutils::Random(10);
|
||||||
const int size = 100000;
|
const int size = 500000;
|
||||||
int arr[size];
|
int arr[size];
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
arr[i] = rand.Get(0, 3);
|
arr[i] = rand.Get(0, 3);
|
||||||
|
|
Loading…
Reference in New Issue