You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
73 lines
2.3 KiB
73 lines
2.3 KiB
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
|
|
|
#include <bit>
|
|
|
|
#include <climits>
|
|
#include <cmath>
|
|
|
|
#include <rngxx.hpp>
|
|
#include <mem.h>
|
|
|
|
#include <rngxx/crand.h>
|
|
#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<typename T>
|
|
inline void setinc(u8* &ptr, auto val)
|
|
{
|
|
*reinterpret_cast<T*>(ptr) = T(val);
|
|
ptr += sizeof(T);
|
|
}
|
|
}
|
|
namespace rng
|
|
{
|
|
void crand::_deleter::delete_object(_opaque** state) { _jr_free(reinterpret_cast<jr_state*>(*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<jr_state*>(&_state)); } //RANGE_MIN..=RANGE_MAX
|
|
f64 crand::_sample() { return _jr_procf(reinterpret_cast<jr_state*>(&_state)); } //0..1
|
|
|
|
// Overrides //
|
|
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
|
|
i32 crand::next_i32() { return (i32)next_i64(); }
|
|
u32 crand::next_u32() { return std::bit_cast<u32>((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<u32>(b, std::bit_cast<u64>(_sample_int() & _J_RANGE_MAX)); n-=4; break;
|
|
case 3: setinc<u8>(b, std::bit_cast<u64>(_sample_int()) & 0xff); n -= 1;
|
|
case 2: setinc<u16>(b, std::bit_cast<u64>(_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);
|
|
}
|
|
|
|
}
|
|
|