crand::_sample() uniformly distributes between 0..1

Fortune for cpprng's current commit: Blessing − 吉
lib
Avril 3 years ago
parent c21c7e77e9
commit 8e20b86365

@ -18,7 +18,7 @@ namespace rng
inline ~crand(){} inline ~crand(){}
inline i64 next_i64() override { return _sample_raw(); } inline i64 next_i64() override { return _sample_int(); }
u64 next_u64() override; u64 next_u64() override;
protected: protected:
inline constexpr i64 _max_i64() const override { return RANGE_MAX; } inline constexpr i64 _max_i64() const override { return RANGE_MAX; }
@ -31,6 +31,6 @@ namespace rng
mem::aligned_ptr<_opaque, _deleter> _state; mem::aligned_ptr<_opaque, _deleter> _state;
explicit crand(_opaque* raw); explicit crand(_opaque* raw);
i64 _sample_raw(); i64 _sample_int();
}; };
} }

@ -11,7 +11,10 @@ typedef unsigned short uint48_t[3];
struct jr_state struct jr_state
{ {
long result; union {
long result;
double fresult;
};
struct drand48_data data; struct drand48_data data;
union { union {
unsigned short xsubi[3]; unsigned short xsubi[3];
@ -59,6 +62,14 @@ long _jr_proc(struct jr_state* restrict state)
return state->result; return state->result;
} }
//TODO: a version of _jr_proc that uses use `erand48_r()` to return between 0..1.0 for _sample()
double _jr_procf(struct jr_state* restrict state)
{
erand48_r(_jr_st_resolv(state), &state->data, &state->fresult);
return state->fresult;
}
struct jr_state* _jr_alloc() struct jr_state* _jr_alloc()
{ {
struct jr_state* bx = aligned_alloc(_Alignof(struct jr_state), sizeof(struct jr_state)); struct jr_state* bx = aligned_alloc(_Alignof(struct jr_state), sizeof(struct jr_state));

@ -26,15 +26,14 @@ namespace rng
crand::crand(u64 seed) : crand(reinterpret_cast<_opaque*>(_jr_new(seed))){} crand::crand(u64 seed) : crand(reinterpret_cast<_opaque*>(_jr_new(seed))){}
crand::crand() : crand(0xabad1dea){} crand::crand() : crand(0xabad1dea){}
i64 crand::_sample_raw() { return _jr_proc(reinterpret_cast<jr_state*>(_state.get_ptr())); } i64 crand::_sample_int() { return _jr_proc(reinterpret_cast<jr_state*>(_state.get_ptr())); } //RANGE_MIN..=RANGE_MAX
f64 crand::_sample() { return _jr_procf(reinterpret_cast<jr_state*>(_state.get_ptr())); } //0..1
//TODO: properly implemet this f64 crand::_sample() { return (f64)std::bit_cast<u64>(_sample_raw()) / (f64)UINT64_MAX; }
// Overrides // // Overrides //
u64 crand::next_u64() { return std::bit_cast<u64>(std::abs(_sample_raw()) & INT32_MAX); } // remove sign bit because it messes with the range. u64 crand::next_u64() { return std::bit_cast<u64>(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
//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: next_bytes(), next_v*()
//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() void rng_test()

@ -15,6 +15,7 @@ struct jr_state;
void _jr_seed(struct jr_state* restrict state, unsigned long with); void _jr_seed(struct jr_state* restrict state, unsigned long with);
long _jr_proc(struct jr_state* restrict state); long _jr_proc(struct jr_state* restrict state);
double _jr_procf(struct jr_state* restrict state);
struct jr_state* _jr_alloc(); struct jr_state* _jr_alloc();
void _jr_free(struct jr_state* restrict state); void _jr_free(struct jr_state* restrict state);

Loading…
Cancel
Save