From b59c0671d287a9552295c980680f005ee77786ec Mon Sep 17 00:00:00 2001 From: Avril Date: Fri, 1 Oct 2021 15:58:52 +0100 Subject: [PATCH] Added ranges to Random base. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added crand::RANGE_MIN/MAX, overriden required base ranges to point to them. crand::next_u64() returns within this range but discards the negative result Fortune for cpprng's current commit: Small blessing − 小吉 --- include/rng.h | 13 +++++++++++-- include/rng/crand.h | 7 +++++++ src/rng.cpp | 2 ++ src/rng/crand.cpp | 11 ++++++++++- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/include/rng.h b/include/rng.h index 06c6eb7..0741886 100644 --- a/include/rng.h +++ b/include/rng.h @@ -78,8 +78,8 @@ struct Random virtual bool next_bool(); -#define NDEF(t, M) inline virtual t next_ ## t() { return next_ ## t(M); } -#define NDEFF(n) NDEF(i ## n, INT ## n ## _MAX) NDEF(u ## n, UINT ## n ## _MAX) +#define NDEF(t) inline virtual t next_ ## t() { return next_ ## t(_max_ ## t()); } +#define NDEFF(n) NDEF(i ## n) NDEF(u ## n) NDEFF(8) NDEFF(16) NDEFF(32) @@ -151,6 +151,15 @@ struct Random template inline iterator iter() { return iterator(*this); } //TODO: An iterator that yields `next()` forever. protected: + //TODO: Should we have _min_* functions too? or just continue to use 0 as the lower bound for next_*(..max)? I think use 0... +#define MAX(T, M) constexpr inline virtual T _max_ ## T() const { return M; } +#define MAXX(n) MAX(u ## n, UINT ## n ## _MAX) MAX(i ## n, INT ## n ## _MAX) + MAXX(8) + MAXX(16) + MAXX(32) + MAXX(64) +#undef MAXX +#undef MAX //constexpr inline virtual i8 _max() const { return 100; } // use limits.h stuff instead. // Vectorised versions of `next_bytes()`. These will fall back to that if they are not overriden, but if the implementation has a more efficient way of generating 4/8 bytes of random data it should override these. diff --git a/include/rng/crand.h b/include/rng/crand.h index 8ad60d0..21034ef 100644 --- a/include/rng/crand.h +++ b/include/rng/crand.h @@ -9,6 +9,10 @@ namespace rng { struct crand final : public Random { + // This range is inclusive + constexpr static inline i64 RANGE_MIN = - (1L << 31); + constexpr static inline i64 RANGE_MAX = (1L << 31) - 1; + crand(); crand(u64 seed); @@ -17,6 +21,9 @@ namespace rng inline i64 next_i64() override { return _sample_raw(); } u64 next_u64() override; protected: + inline constexpr i64 _max_i64() const override { return RANGE_MAX; } + inline constexpr u64 _max_u64() const override { return (u64)RANGE_MAX; } + // the rest of the base `_max_*` functions are valid, as they will always be equal to or less than INT32_MAX (the upper bound of dr48.) f64 _sample() override; private: struct _opaque; diff --git a/src/rng.cpp b/src/rng.cpp index 7e523ee..d5cf204 100644 --- a/src/rng.cpp +++ b/src/rng.cpp @@ -46,3 +46,5 @@ N_INTS #undef NEXTT #undef NEXT + +//TODO: next_*(min, max) diff --git a/src/rng/crand.cpp b/src/rng/crand.cpp index 6c8e382..ef0fb39 100644 --- a/src/rng/crand.cpp +++ b/src/rng/crand.cpp @@ -8,6 +8,14 @@ #include #include "crand.h" +// Note: the output of drand48 is uniform between INT32_MIN..=INT32_MAX (inclusive) + +constexpr const i64 _J_RANGE_MIN = (i64)INT32_MIN; +constexpr const i64 _J_RANGE_MAX = (i64)INT32_MAX; + +static_assert(_J_RANGE_MIN == rng::crand::RANGE_MIN); +static_assert(_J_RANGE_MAX == rng::crand::RANGE_MAX); + namespace rng { void crand::_deleter::delete_object(_opaque** state) { _jr_free(reinterpret_cast(*state)); *state = nullptr; } @@ -22,7 +30,8 @@ namespace rng //TODO: properly implemet this f64 crand::_sample() { return (f64)std::bit_cast(_sample_raw()) / (f64)UINT64_MAX; } // Overrides // - u64 crand::next_u64() { return std::bit_cast(_sample_raw()); } + u64 crand::next_u64() { return std::bit_cast(_sample_raw() & INT32_MAX); } // remove sign bit because it messes with the range. + //TODO: Implementing next_i64(i64 max) should be trivial. the man page for drand48 shows its output range, just map that range to `0..=max` //TODO: make the default range for all non-bounded `next_i/u*` the same range as drand48's. If that's too big for the integer type, scale it down. }