#include #include #include #include #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; } crand::crand(_opaque* raw) :_state(mem::aligned_ptr<_opaque, _deleter>(raw)){} crand::crand(u64 seed) : crand(reinterpret_cast<_opaque*>(_jr_new(seed))){} crand::crand() : crand(0xabad1dea){} i64 crand::_sample_raw() { return _jr_proc(reinterpret_cast(_state.get_ptr())); } //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() & 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. } void rng_test() { rng::crand r(123); printf("%lu %lu %lu\n", r.next_u64(), r.next_u64(), r.next_u64()); }