#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" #include #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 { template inline void setinc(u8* &ptr, auto val) { *reinterpret_cast(ptr) = T(val); ptr += sizeof(T); } } namespace rng { void crand::_deleter::delete_object(_opaque** state) { _jr_free(reinterpret_cast(*state)); *state = nullptr; } crand::crand(_opaque* raw) : Random(), _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_int() { return _jr_proc(reinterpret_cast(&_state)); } //RANGE_MIN..=RANGE_MAX f64 crand::_sample() { return _jr_procf(reinterpret_cast(&_state)); } //0..1 // Overrides // u64 crand::next_u64() { return std::bit_cast(std::abs(_sample_int()) & INT32_MAX); } // next_i/u64(max) overrides not nessicary, the impl would be same as base. same with array next_*(p, n) overrides i32 crand::next_i32() { return (i32)next_i64(); } u32 crand::next_u32() { return std::bit_cast((i32)_sample_int()); } // I think keeping the sign bit in the transmute here doesn't violate the distribution, since it's between int32's min and max value... // next_bytes(), next_v*() void crand::next_bytes(u8* b, usize n) { while(n) switch (n % 4) // this is soo dogy... { case 0: setinc(b, std::bit_cast(_sample_int() & _J_RANGE_MAX)); n-=4; break; case 3: setinc(b, std::bit_cast(_sample_int()) & 0xff); n -= 1; case 2: setinc(b, std::bit_cast(_sample_int()) & 0xffff); n -= 2; break; case 1: *b++ = u8(_sample_int() & 0xff); n -= 1; break; } } void crand::next_v32(u32* p, usize n) { while( n --> 0 ) *p++ = (u32)(_sample_int() & INT32_MAX); } void crand::next_v64(u64* p, usize n) { while( n --> 0 ) *p++ = u64(_sample_int() & INT32_MAX) + (u64(_sample_int() & INT32_MAX) << 32); } }