diff --git a/include/lol/private/math/rand.h b/include/lol/private/math/rand.h index 13426606..75cc717d 100644 --- a/include/lol/private/math/rand.h +++ b/include/lol/private/math/rand.h @@ -18,18 +18,29 @@ // #include -#include +#include #include namespace lol { -/* Random number generators */ -template [[nodiscard]] static inline T rand(); -template [[nodiscard]] static inline T rand(T a); -template [[nodiscard]] static inline T rand(T a, T b); +// Random number generators +template +[[nodiscard]] static inline T rand(); -/* One-value random number generators */ +template +[[nodiscard]] static inline T rand(T a); + +template +[[nodiscard]] static inline T rand(T a, T b); + +// Two-value random number generator -- no need for specialisation +template [[nodiscard]] static inline T rand(T a, T b) +{ + return a + rand(b - a); +} + +// One-value random number generators template [[nodiscard]] static inline T rand(T a) { return a ? rand() % a : T(0); @@ -38,87 +49,48 @@ template [[nodiscard]] static inline T rand(T a) #if 0 template<> [[nodiscard]] inline half rand(half a) { - float f = (float)std::rand() / (float)RAND_MAX; - return (half)(a * f); + return rand(1 << 13) / float(1 << 13) * a; } #endif template<> [[nodiscard]] inline float rand(float a) { - auto f = (float)std::rand() / (float)RAND_MAX; - return a * f; + return rand(uint32_t(1) << 23) / float(uint32_t(1) << 23) * a; } template<> [[nodiscard]] inline double rand(double a) { - auto f = (double)std::rand() / (double)RAND_MAX; - return a * f; + return rand(uint64_t(1) << 53) / double(uint64_t(1) << 53) * a; } template<> [[nodiscard]] inline long double rand(long double a) { - auto f = (long double)std::rand() / (long double)RAND_MAX; - return a * f; -} - -/* Two-value random number generator -- no need for specialisation */ -template [[nodiscard]] static inline T rand(T a, T b) -{ - return a + rand(b - a); + return rand(uint64_t(1) << 63) / (long double)(uint64_t(1) << 63) * a; } -/* Default random number generator */ +// Default random number generator template [[nodiscard]] static inline T rand() { - switch (sizeof(T)) - { - case 1: - return static_cast(std::rand() & 0x7f); - case 2: - { - uint16_t ret = std::rand(); - if (RAND_MAX < 0x7fff) - ret = (ret << 7) ^ std::rand(); - return static_cast(ret & 0x7fffu); - } - case 4: - { - uint32_t ret = std::rand(); - if (RAND_MAX >= 0xffff) - ret = (ret << 16) ^ std::rand(); - else - { - ret = (ret << 8) ^ std::rand(); - ret = (ret << 8) ^ std::rand(); - ret = (ret << 8) ^ std::rand(); - } - return static_cast(ret & 0x7fffffffu); - } - case 8: + static std::minstd_rand eng { std::random_device{}() }; + + if constexpr (sizeof(T) == 1) + return static_cast(eng() & 0x7fu); + + if constexpr (sizeof(T) == 2) + return static_cast(eng() & 0x7fffu); + + if constexpr (sizeof(T) == 4) + return static_cast(eng() & 0x7fffffffu); + + if constexpr (sizeof(T) == 8) { - uint64_t ret = std::rand(); - if (RAND_MAX >= 0xffff) - { - ret = (ret << 16) ^ std::rand(); - ret = (ret << 16) ^ std::rand(); - ret = (ret << 16) ^ std::rand(); - } - else - { - ret = (ret << 8) ^ std::rand(); - ret = (ret << 8) ^ std::rand(); - ret = (ret << 8) ^ std::rand(); - ret = (ret << 8) ^ std::rand(); - ret = (ret << 8) ^ std::rand(); - ret = (ret << 8) ^ std::rand(); - ret = (ret << 8) ^ std::rand(); - } + uint64_t ret = eng(); + ret = (ret << 16) ^ eng(); + ret = (ret << 16) ^ eng(); return static_cast(ret & (~(uint64_t)0 >> 1)); } - default: - assert(false); - return 0; - } + + assert(false); } #if 0 @@ -128,5 +100,5 @@ template<> [[nodiscard]] inline float rand() { return rand(1.f); } template<> [[nodiscard]] inline double rand() { return rand(1.0); } template<> [[nodiscard]] inline long double rand() { return rand(1.0); } -} /* namespace lol */ +} // namespace lol