diff --git a/Makefile.am b/Makefile.am index dbcdd166..a8742402 100644 --- a/Makefile.am +++ b/Makefile.am @@ -210,6 +210,8 @@ UTIL_FILES = \ rand/lcg.hpp \ rand/xorshift.cpp \ rand/xorshift.hpp \ + rand/mwc64x.cpp \ + rand/mwc64x.hpp \ random.cpp \ random.hpp \ random.ipp \ diff --git a/rand/mwc64x.cpp b/rand/mwc64x.cpp new file mode 100644 index 00000000..07aaaf3c --- /dev/null +++ b/rand/mwc64x.cpp @@ -0,0 +1,45 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2016 Danny Robson + */ + + +#include "./mwc64x.hpp" + +#include "../debug.hpp" + +using util::rand::mwc64x; + + +/////////////////////////////////////////////////////////////////////////////// +mwc64x::mwc64x (seed_type _seed): + m_state (_seed) +{ + CHECK_NEZ (m_state); +} + + +/////////////////////////////////////////////////////////////////////////////// +mwc64x::value_type +mwc64x::operator() (void) +{ + CHECK_NEZ (m_state); + + uint32_t c = m_state >> 32u; + uint32_t x = m_state & 0xFFFFFFFFu; + + m_state = x * 4294883355ULL + c; + + return x ^ c; +} diff --git a/rand/mwc64x.hpp b/rand/mwc64x.hpp new file mode 100644 index 00000000..12ef5441 --- /dev/null +++ b/rand/mwc64x.hpp @@ -0,0 +1,43 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2016 Danny Robson + */ + +#ifndef __UTIL_RAND_MWC64X_HPP +#define __UTIL_RAND_MWC64X_HPP + +#include + +namespace util { namespace rand { + // multiply-with-carry style generator suitable for rapid seeking and + // GPU generation. + // + // as with all such style generators, the seed value is very important. + // don't allow either half of the uint64_t to be zero. + struct mwc64x { + public: + using value_type = uint32_t; + using seed_type = uint64_t; + + mwc64x (seed_type); + + value_type operator() (void); + + private: + uint64_t m_state; + }; +} } + + +#endif diff --git a/test/rand/buckets.cpp b/test/rand/buckets.cpp index d5d15efe..2afb309a 100644 --- a/test/rand/buckets.cpp +++ b/test/rand/buckets.cpp @@ -1,5 +1,6 @@ #include "rand/xorshift.hpp" #include "rand/lcg.hpp" +#include "rand/mwc64x.hpp" #include "tap.hpp" #include "maths.hpp" @@ -15,9 +16,9 @@ template <> std::string type_to_string> (void) { return "xorshift"; } -template <> -std::string -type_to_string (void) { return "lcg_t"; } +template <> std::string type_to_string (void) { return "lcg_t"; } + +template <> std::string type_to_string (void) { return "mwc64x"; } /////////////////////////////////////////////////////////////////////////////// @@ -43,10 +44,11 @@ test_buckets (util::TAP::logger &tap, Args&& ...args) for (unsigned i = 0; i < ITERATIONS; ++i) ++buckets[gen () & BUCKET_MASK]; - tap.expect (std::find_if (std::cbegin (buckets), - std::cend (buckets), - [] (auto v) { return v < EXPECTED * 3 / 4; }) == std::cend (buckets), - "bucket counts for %s", type_to_string ()); + tap.expect ( + std::find_if (std::cbegin (buckets), + std::cend (buckets), + [] (auto v) { return v < EXPECTED * 7 / 8; }) == std::cend (buckets), + "bucket counts for %s", type_to_string ()); } @@ -59,6 +61,7 @@ main (int,char**) test_buckets> (tap, 0x1234u); test_buckets> (tap, 0x1234u); test_buckets (tap, 0x1234u); + test_buckets (tap, 0x1234u); return tap.status (); }