| @@ -18,18 +18,29 @@ | |||||
| // | // | ||||
| #include <cassert> | #include <cassert> | ||||
| #include <cstdlib> | |||||
| #include <random> | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| /* Random number generators */ | |||||
| template<typename T> [[nodiscard]] static inline T rand(); | |||||
| template<typename T> [[nodiscard]] static inline T rand(T a); | |||||
| template<typename T> [[nodiscard]] static inline T rand(T a, T b); | |||||
| // Random number generators | |||||
| template<typename T = int> | |||||
| [[nodiscard]] static inline T rand(); | |||||
| /* One-value random number generators */ | |||||
| template<typename T> | |||||
| [[nodiscard]] static inline T rand(T a); | |||||
| template<typename T> | |||||
| [[nodiscard]] static inline T rand(T a, T b); | |||||
| // Two-value random number generator -- no need for specialisation | |||||
| template<typename T> [[nodiscard]] static inline T rand(T a, T b) | |||||
| { | |||||
| return a + rand<T>(b - a); | |||||
| } | |||||
| // One-value random number generators | |||||
| template<typename T> [[nodiscard]] static inline T rand(T a) | template<typename T> [[nodiscard]] static inline T rand(T a) | ||||
| { | { | ||||
| return a ? rand<T>() % a : T(0); | return a ? rand<T>() % a : T(0); | ||||
| @@ -38,87 +49,48 @@ template<typename T> [[nodiscard]] static inline T rand(T a) | |||||
| #if 0 | #if 0 | ||||
| template<> [[nodiscard]] inline half rand<half>(half a) | template<> [[nodiscard]] inline half rand<half>(half a) | ||||
| { | { | ||||
| float f = (float)std::rand() / (float)RAND_MAX; | |||||
| return (half)(a * f); | |||||
| return rand(1 << 13) / float(1 << 13) * a; | |||||
| } | } | ||||
| #endif | #endif | ||||
| template<> [[nodiscard]] inline float rand<float>(float a) | template<> [[nodiscard]] inline float rand<float>(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>(double a) | template<> [[nodiscard]] inline double rand<double>(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>(long double a) | template<> [[nodiscard]] inline long double rand<long double>(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<typename T> [[nodiscard]] static inline T rand(T a, T b) | |||||
| { | |||||
| return a + rand<T>(b - a); | |||||
| return rand(uint64_t(1) << 63) / (long double)(uint64_t(1) << 63) * a; | |||||
| } | } | ||||
| /* Default random number generator */ | |||||
| // Default random number generator | |||||
| template<typename T> [[nodiscard]] static inline T rand() | template<typename T> [[nodiscard]] static inline T rand() | ||||
| { | { | ||||
| switch (sizeof(T)) | |||||
| { | |||||
| case 1: | |||||
| return static_cast<T>(std::rand() & 0x7f); | |||||
| case 2: | |||||
| { | |||||
| uint16_t ret = std::rand(); | |||||
| if (RAND_MAX < 0x7fff) | |||||
| ret = (ret << 7) ^ std::rand(); | |||||
| return static_cast<T>(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<T>(ret & 0x7fffffffu); | |||||
| } | |||||
| case 8: | |||||
| static std::minstd_rand eng { std::random_device{}() }; | |||||
| if constexpr (sizeof(T) == 1) | |||||
| return static_cast<T>(eng() & 0x7fu); | |||||
| if constexpr (sizeof(T) == 2) | |||||
| return static_cast<T>(eng() & 0x7fffu); | |||||
| if constexpr (sizeof(T) == 4) | |||||
| return static_cast<T>(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<T>(ret & (~(uint64_t)0 >> 1)); | return static_cast<T>(ret & (~(uint64_t)0 >> 1)); | ||||
| } | } | ||||
| default: | |||||
| assert(false); | |||||
| return 0; | |||||
| } | |||||
| assert(false); | |||||
| } | } | ||||
| #if 0 | #if 0 | ||||
| @@ -128,5 +100,5 @@ template<> [[nodiscard]] inline float rand<float>() { return rand<float>(1.f); } | |||||
| template<> [[nodiscard]] inline double rand<double>() { return rand<double>(1.0); } | template<> [[nodiscard]] inline double rand<double>() { return rand<double>(1.0); } | ||||
| template<> [[nodiscard]] inline long double rand<long double>() { return rand<long double>(1.0); } | template<> [[nodiscard]] inline long double rand<long double>() { return rand<long double>(1.0); } | ||||
| } /* namespace lol */ | |||||
| } // namespace lol | |||||