diff --git a/lean/include/rng.h b/lean/include/rng.h index 7535119..57852a7 100644 --- a/lean/include/rng.h +++ b/lean/include/rng.h @@ -7,10 +7,13 @@ extern "C" { // Tests void frng_test(); +void xorng_test(); +void drng_test(); #ifdef __cplusplus } // RNG interfaces #include +#include #endif diff --git a/lean/include/rng/drng.h b/lean/include/rng/drng.h new file mode 100644 index 0000000..56cf6a0 --- /dev/null +++ b/lean/include/rng/drng.h @@ -0,0 +1,19 @@ + +#include "impl.hpp" + +namespace rng +{ + struct drng : public RNG + { + inline drng(std::uint32_t seed) : state(seed){sample();} + inline drng() : drng(1){} + + static drng from_time(); + + int rand(); + protected: + double sample() override; + private: + std::uint32_t state; + }; +} diff --git a/lean/include/rng/impl.hpp b/lean/include/rng/impl.hpp index 5cf223d..04aeef5 100644 --- a/lean/include/rng/impl.hpp +++ b/lean/include/rng/impl.hpp @@ -23,7 +23,6 @@ struct RNG { std::int32_t next_int(std::int32_t min, std::int32_t max); virtual std::int64_t next_long(); - inline std::int64_t next_long(std::int64_t max) { return next_long(0, max); } std::int64_t next_long(std::int64_t min, std::int64_t max); diff --git a/lean/include/rng/xoroshiro128plus.hpp b/lean/include/rng/xoroshiro128plus.hpp new file mode 100644 index 0000000..d5553d7 --- /dev/null +++ b/lean/include/rng/xoroshiro128plus.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "impl.hpp" + +namespace rng +{ + struct xoroshiro128plus : public RNG + { + using State = std::array; + inline constexpr xoroshiro128plus(std::uint64_t s0, std::uint64_t s1) : state({s0, s1}){} + inline constexpr xoroshiro128plus(std::array&& ar) : state(ar){} + inline constexpr xoroshiro128plus(const std::array& ar) : state(ar){} + inline constexpr xoroshiro128plus(const std::uint64_t (&ar)[2]) : state({ar[0], ar[1]}){} + + std::uint64_t next_ulong(); + using RNG::next_long; + std::int64_t next_long() override; + + void jump(); + void long_jump(); + protected: + double sample() override; + private: + State state; + }; +} diff --git a/lean/src/main.c b/lean/src/main.c index b603a48..255cc61 100644 --- a/lean/src/main.c +++ b/lean/src/main.c @@ -44,6 +44,8 @@ int main(int argc, char** argv) struct prog_args args = {.argc = argc, .argv = argv}; frng_test(); + xorng_test(); + drng_test(); if( argv[1] ) { map_and_then(argv[1], &map_callback, &args); diff --git a/lean/src/rng/drng.cpp b/lean/src/rng/drng.cpp new file mode 100644 index 0000000..40e7934 --- /dev/null +++ b/lean/src/rng/drng.cpp @@ -0,0 +1,46 @@ +#include +#include +#include + +#include + +namespace rng +{ + static inline void d_test() + { + using namespace std; + drng rng(100); + + for(int i=0;i<10;i++) { + double d = rng.next_double(); + long l = rng.next_long(-10, 10); + + std::array ar; + for(auto& i : ar) i = rng.chance(); + + cout << "D Sampled: " << d << endl; + cout << "D Long: " << l << endl; + cout << "D Bools: [ "; + for(const auto& i : ar) cout << i << " "; + cout << "]" << endl; + } + } + + drng drng::from_time() { return drng(time(NULL)); } + + int drng::rand() + { + return rand_r(&state); + } + + double drng::sample() + { + int val = rand_r(&state); + return (double)val / (double)RAND_MAX; + } +} + +extern "C" void drng_test() +{ + return rng::d_test(); +} diff --git a/lean/src/rng/frng.cpp b/lean/src/rng/frng.cpp index c9b85fe..63a128d 100644 --- a/lean/src/rng/frng.cpp +++ b/lean/src/rng/frng.cpp @@ -4,7 +4,7 @@ namespace rng { using namespace std; - inline void test() + static inline void f_test() { frng rng(1.0, 2.0); @@ -22,11 +22,10 @@ namespace rng { cout << "]" << endl; } } - } extern "C" void frng_test() { - rng::test(); + rng::f_test(); } diff --git a/lean/src/rng/xoroshiro128plus.cpp b/lean/src/rng/xoroshiro128plus.cpp new file mode 100644 index 0000000..ddab95a --- /dev/null +++ b/lean/src/rng/xoroshiro128plus.cpp @@ -0,0 +1,111 @@ +#include +#include + +using u64 = std::uint64_t; + +#define XO xoroshiro128plus + +static inline constexpr u64 rotl(u64 x, int k) +{ + return (x << k) | (x >> (64 - k)); +} + +namespace rng +{ + static inline void xo_test() + { + using namespace std; + XO rng(100ul, 123123123ul); + + for(int i=0;i<10;i++) { + double d = rng.next_double(); + long l = rng.next_long(-10, 10); + + std::array ar; + for(auto& i : ar) i = rng.chance(); + + cout << "XO Sampled: " << d << endl; + cout << "XO Long: " << l << endl; + cout << "XO Bools: [ "; + for(const auto& i : ar) cout << i << " "; + cout << "]" << endl; + } + } + + inline constexpr u64 next(XO::State& s) + { + u64 s0 = s[0]; + u64 s1 = s[1]; + u64 result = s0 + s1; + + s1 ^= s0; + s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); + s[1] = rotl(s1, 37); + + return result; + } + inline constexpr void xo_jump(XO::State& s) + { + constexpr const std::uint64_t JUMP[] = { 0xdf900294d8f554a5, 0x170865df4b3201fc }; + + std::uint64_t s0 = 0; + std::uint64_t s1 = 0; + for(u64 i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for(int b = 0; b < 64; b++) { + if (JUMP[i] & UINT64_C(1) << b) { + s0 ^= s[0]; + s1 ^= s[1]; + } + next(s); + } + + s[0] = s0; + s[1] = s1; + } + + inline constexpr void xo_long_jump(XO::State& s) + { + constexpr const uint64_t LONG_JUMP[] = { 0xd2a98b26625eee7b, 0xdddf9b1090aa7ac1 }; + + std::uint64_t s0 = 0; + std::uint64_t s1 = 0; + for(u64 i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++) + for(int b = 0; b < 64; b++) { + if (LONG_JUMP[i] & UINT64_C(1) << b) { + s0 ^= s[0]; + s1 ^= s[1]; + } + next(s); + } + + s[0] = s0; + s[1] = s1; + } + + + void XO::jump() { xo_jump(state); } + void XO::long_jump() { xo_long_jump(state); } + + std::uint64_t XO::next_ulong() + { + return next(state); + } + std:: int64_t XO::next_long() + { + const u64 v = next_ulong(); + static_assert(sizeof(v) == sizeof(decltype(next_long()))); + + return *(const std::int64_t*)&v; + } + + + double XO::sample() + { + return (next(state) & ((INT64_C(1) << 53) - 1)) * (1.00 / (INT64_C(1) << 53)); + } +} + +extern "C" void xorng_test() +{ + return rng::xo_test(); +}