| #include <cassert> | |
| #include <cstdint> | |
| #include <random> | |
| class Rand | |
| { | |
| public: | |
| void seed(uint64_t x) { m_impl.seed(x); } | |
| uint64_t u64() { return m_impl(); } | |
| uint32_t u32() { return static_cast<uint32_t>(m_impl()); } | |
| float f32(float start, float end) | |
| { | |
| // 24-bit mantissa drawn from the top bits of u64. Not strictly | |
| // unbiased: the affine map onto [start, end] introduces tiny | |
| // rounding non-uniformity when (end - start) isn't a dyadic | |
| // fraction, and for very wide intervals the result can round up | |
| // to exactly `end`. Acceptable for tests — the bias is below | |
| // float epsilon, and std::uniform_real_distribution had the same | |
| // boundary quirk anyway. | |
| float u = (m_impl() >> 40) * (1.0f / (1 << 24)); | |
| return start + u * (end - start); | |
| } | |
| float f32(float end = 1) { return f32(0, end); } | |
| bool boolean() { return m_impl() & 1; } | |
| // This is based on Lemire's nearly-divisonless unbiased bounded random | |
| // integer algorithm: | |
| // https://lemire.me/blog/2019/06/06/nearly-divisionless-random-integer-generation-on-various-systems/ | |
| uint32_t u32(uint32_t start, uint32_t end) | |
| { | |
| assert(start <= end); | |
| if (start == 0 && end == UINT32_MAX) | |
| { | |
| return u32(); | |
| } | |
| uint32_t range = end - start + 1; | |
| uint64_t m = uint64_t(u32()) * range; | |
| uint32_t l = uint32_t(m); | |
| if (l < range) | |
| { | |
| uint32_t threshold = | |
| (0u - range) % range; // == (1ull << 32) % range | |
| while (l < threshold) | |
| { | |
| m = uint64_t(u32()) * range; | |
| l = uint32_t(m); | |
| } | |
| } | |
| return start + uint32_t(m >> 32); | |
| } | |
| private: | |
| std::mt19937_64 m_impl; | |
| }; |