From fde275feb2d0c87133c8c1507438367c15b9d38f Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Mon, 17 Aug 2020 14:30:55 +1000 Subject: [PATCH] rand: add xoshiro256plusplus generator --- CMakeLists.txt | 6 +- rand/xoshiro.cpp | 128 ++++++++++++++++++++++++++++++++++++++++++ rand/xoshiro.hpp | 51 +++++++++++++++++ test/rand/buckets.cpp | 2 + 4 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 rand/xoshiro.cpp create mode 100644 rand/xoshiro.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cccdd947..04fb862c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -479,8 +479,6 @@ list ( quaternion.hpp rand/lcg.cpp rand/lcg.hpp - rand/xorshift.cpp - rand/xorshift.hpp rand/mwc64x.cpp rand/mwc64x.hpp rand/pcg.cpp @@ -489,6 +487,10 @@ list ( rand/rdrand.hpp rand/splitmix64.hpp rand/system.hpp + rand/xoshiro.cpp + rand/xoshiro.hpp + rand/xorshift.cpp + rand/xorshift.hpp random.cpp random.hpp range.cpp diff --git a/rand/xoshiro.cpp b/rand/xoshiro.cpp new file mode 100644 index 00000000..de35a65f --- /dev/null +++ b/rand/xoshiro.cpp @@ -0,0 +1,128 @@ +/* + * Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org) + * + * To the extent possible under law, the author has dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + */ + +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2020, Danny Robson + */ + +#include "xoshiro.hpp" +#include "splitmix64.hpp" + +#include "../bitwise.hpp" + +#include + +using cruft::rand::xoshiro256plusplus; + + +/////////////////////////////////////////////////////////////////////////////// +xoshiro256plusplus::xoshiro256plusplus (u64 _seed) +{ + splitmix64 gen (_seed); + std::generate ( + std::begin (m_state), + std::end (m_state), + gen + ); +} + + +/////////////////////////////////////////////////////////////////////////////// +u64 +xoshiro256plusplus::operator() (void) +{ + u64 const result = rotatel (m_state[0] + m_state[3], 23) + m_state[0]; + + u64 const t = m_state[1] << 17; + + m_state[2] ^= m_state[0]; + m_state[3] ^= m_state[1]; + m_state[1] ^= m_state[2]; + m_state[0] ^= m_state[3]; + + m_state[2] ^= t; + + m_state[3] = rotatel (m_state[3], 45); + + return result; +} + + +/////////////////////////////////////////////////////////////////////////////// +void +xoshiro256plusplus::jump (void) +{ + static u64 constinit JUMP[] = { + 0x180ec6d33cfd0aba, + 0xd5a61266f0c9392c, + 0xa9582618e03fc9aa, + 0x39abdc4529b1661c + }; + + u64 s0 = 0; + u64 s1 = 0; + u64 s2 = 0; + u64 s3 = 0; + + for (std::size_t i = 0; i < std::size (JUMP); ++i) { + for (int b = 0; b < 64; b++) { + if (JUMP[i] & u64 (1) << b) { + s0 ^= m_state[0]; + s1 ^= m_state[1]; + s2 ^= m_state[2]; + s3 ^= m_state[3]; + } + (*this) (); + } + } + + m_state[0] = s0; + m_state[1] = s1; + m_state[2] = s2; + m_state[3] = s3; +} + + +//----------------------------------------------------------------------------- +void +xoshiro256plusplus::long_jump (void) +{ + static constinit u64 LONG_JUMP[] = { + 0x76e15d3efefdcbbf, + 0xc5004e441c522fb3, + 0x77710069854ee241, + 0x39109bb02acbe635 + }; + + u64 s0 = 0; + u64 s1 = 0; + u64 s2 = 0; + u64 s3 = 0; + + for (std::size_t i = 0; i < std::size (LONG_JUMP); ++i) { + for (int b = 0; b < 64; b++) { + if (LONG_JUMP[i] & u64{1} << b) { + s0 ^= m_state[0]; + s1 ^= m_state[1]; + s2 ^= m_state[2]; + s3 ^= m_state[3]; + } + + (*this) (); + } + } + + m_state[0] = s0; + m_state[1] = s1; + m_state[2] = s2; + m_state[3] = s3; +} \ No newline at end of file diff --git a/rand/xoshiro.hpp b/rand/xoshiro.hpp new file mode 100644 index 00000000..1344c057 --- /dev/null +++ b/rand/xoshiro.hpp @@ -0,0 +1,51 @@ +/* + * Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org) + * + * To the extent possible under law, the author has dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + */ + +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2020, Danny Robson + */ + + +#pragma once + +#include "../std.hpp" + +#include + + +/////////////////////////////////////////////////////////////////////////////// +namespace cruft::rand { + class xoshiro256plusplus { + public: + using result_type = u64; + + xoshiro256plusplus (u64 seed); + + static constexpr result_type min (void) + { + return std::numeric_limits::min (); + } + + static constexpr result_type max (void) + { + return std::numeric_limits::max (); + } + + result_type operator() (void); + + void jump (void); + void long_jump (void); + + private: + u64 m_state[4]; + }; +} \ No newline at end of file diff --git a/test/rand/buckets.cpp b/test/rand/buckets.cpp index 7e50d751..a136aa5e 100644 --- a/test/rand/buckets.cpp +++ b/test/rand/buckets.cpp @@ -4,6 +4,7 @@ #include "rand/pcg.hpp" #include "rand/rdrand.hpp" #include "rand/system.hpp" +#include "rand/xoshiro.hpp" #include "rand/splitmix64.hpp" #include "tap.hpp" @@ -51,6 +52,7 @@ main (int,char**) cruft::TAP::logger tap; test_buckets (tap, 0x1234u); + test_buckets (tap, 0x1234u); test_buckets> (tap, 0x1234u); test_buckets> (tap, 0x1234u); test_buckets (tap, 0x1234u);