| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- /*
- * Copyright Matt Borland 2022 - 2025.
- * Distributed under the Boost Software License, Version 1.0. (See
- * accompanying file LICENSE_1_0.txt or copy at
- * http://www.boost.org/LICENSE_1_0.txt)
- *
- * See http://www.boost.org for most recent version including documentation.
- *
- * $Id$
- */
- #ifndef BOOST_RANDOM_XOSHIRO_HPP
- #define BOOST_RANDOM_XOSHIRO_HPP
- #include <boost/random/detail/config.hpp>
- #include <boost/random/detail/xoshiro_base.hpp>
- #include <boost/core/bit.hpp>
- #include <array>
- #include <cstdint>
- namespace boost {
- namespace random {
- /**
- * This is xoshiro256++ 1.0, one of our all-purpose, rock-solid generators.
- * It has excellent (sub-ns) speed, a state (256 bits) that is large
- * enough for any parallel application, and it passes all tests we are
- * aware of.
- *
- * For generating just floating-point numbers, xoshiro256+ is even faster.
- */
- class xoshiro256pp final : public detail::xoshiro_base<xoshiro256pp, 4>
- {
- private:
- using Base = detail::xoshiro_base<xoshiro256pp, 4>;
- public:
- using Base::Base;
- inline result_type next() noexcept
- {
- const std::uint64_t result = boost::core::rotl(state_[0] + state_[3], 23) + state_[0];
- const std::uint64_t t = state_[1] << 17;
- state_[2] ^= state_[0];
- state_[3] ^= state_[1];
- state_[1] ^= state_[2];
- state_[0] ^= state_[3];
- state_[2] ^= t;
- state_[3] = boost::core::rotl(state_[3], 45);
- return result;
- }
- };
- /**
- * This is xoshiro256+ 1.0, our best and fastest generator for floating-point
- * numbers. We suggest to use its upper bits for floating-point
- * generation, as it is slightly faster than xoshiro256++/xoshiro256**. It
- * passes all tests we are aware of except for the lowest three bits,
- * which might fail linearity tests (and just those), so if low linear
- * complexity is not considered an issue (as it is usually the case) it
- * can be used to generate 64-bit outputs, too.
- */
- class xoshiro256d final : public detail::xoshiro_base<xoshiro256d, 4, double>
- {
- private:
- using Base = detail::xoshiro_base<xoshiro256d, 4, double>;
- public:
- using Base::Base;
- inline std::uint64_t next_int() noexcept
- {
- const std::uint64_t result = state_[0] + state_[3];
- const std::uint64_t t = state_[1] << 17;
- state_[2] ^= state_[0];
- state_[3] ^= state_[1];
- state_[1] ^= state_[2];
- state_[0] ^= state_[3];
- state_[2] ^= t;
- state_[3] = boost::core::rotl(state_[3], 45);
- return result;
- }
- inline result_type next() noexcept
- {
- #ifdef BOOST_RANDOM_HAS_HEX_FLOAT
- return static_cast<double>((next_int() >> 11)) * 0x1.0p-53;
- #else
- return static_cast<double>((next_int() >> 11)) * 1.11022302462515654e-16;
- #endif
- }
- static constexpr result_type (min)() noexcept
- {
- #ifdef BOOST_RANDOM_HAS_HEX_FLOAT
- return static_cast<double>((std::numeric_limits<std::uint64_t>::min)() >> 11) * 0x1.0p-53;
- #else
- return static_cast<double>((std::numeric_limits<std::uint64_t>::min)() >> 11) * 1.11022302462515654e-16;
- #endif
- }
- static constexpr result_type (max)() noexcept
- {
- #ifdef BOOST_RANDOM_HAS_HEX_FLOAT
- return static_cast<double>((std::numeric_limits<std::uint64_t>::max)()) * 0x1.0p-53;
- #else
- return static_cast<double>((std::numeric_limits<std::uint64_t>::max)()) * 1.11022302462515654e-16;
- #endif
- }
- };
- /**
- * This is xoshiro256** 1.0, one of our all-purpose, rock-solid
- * generators. It has excellent (sub-ns) speed, a state (256 bits) that is
- * large enough for any parallel application, and it passes all tests we
- * are aware of.
- *
- * For generating just floating-point numbers, xoshiro256+ is even faster.
- */
- class xoshiro256mm final : public detail::xoshiro_base<xoshiro256mm, 4>
- {
- private:
- using Base = detail::xoshiro_base<xoshiro256mm, 4>;
- public:
- using Base::Base;
- inline result_type next() noexcept
- {
- const std::uint64_t result = boost::core::rotl(state_[1] * 5, 7) * 9U;
- const std::uint64_t t = state_[1] << 17;
- state_[2] ^= state_[0];
- state_[3] ^= state_[1];
- state_[1] ^= state_[2];
- state_[0] ^= state_[3];
- state_[2] ^= t;
- state_[3] = boost::core::rotl(state_[3], 45);
- return result;
- }
- };
- /**
- * This is xoshiro512++ 1.0, one of our all-purpose, rock-solid
- * generators. It has excellent (about 1ns) speed, a state (512 bits) that
- * is large enough for any parallel application, and it passes all tests
- * we are aware of.
- *
- * For generating just floating-point numbers, xoshiro512+ is even faster.
- *
- * The state must be seeded so that it is not everywhere zero. If you have
- * a 64-bit seed, we suggest to seed a splitmix64 generator and use its
- * output to fill s.
- */
- class xoshiro512pp final : public detail::xoshiro_base<xoshiro512pp, 8>
- {
- private:
- using Base = detail::xoshiro_base<xoshiro512pp, 8>;
- public:
- using Base::Base;
- inline result_type next() noexcept
- {
- const std::uint64_t result = boost::core::rotl(state_[0] + state_[2], 17) + state_[2];
- const std::uint64_t t = state_[1] << 11;
- state_[2] ^= state_[0];
- state_[5] ^= state_[1];
- state_[1] ^= state_[2];
- state_[7] ^= state_[3];
- state_[3] ^= state_[4];
- state_[4] ^= state_[5];
- state_[0] ^= state_[6];
- state_[6] ^= state_[7];
- state_[6] ^= t;
- state_[7] = boost::core::rotl(state_[7], 21);
- return result;
- }
- };
- /**
- * This is xoshiro512** 1.0, one of our all-purpose, rock-solid generators
- * with increased state size. It has excellent (about 1ns) speed, a state
- * (512 bits) that is large enough for any parallel application, and it
- * passes all tests we are aware of.
- *
- * For generating just floating-point numbers, xoshiro512+ is even faster.
- *
- * The state must be seeded so that it is not everywhere zero. If you have
- * a 64-bit seed, we suggest to seed a splitmix64 generator and use its
- * output to fill s.
- */
- class xoshiro512mm final : public detail::xoshiro_base<xoshiro512mm, 8>
- {
- private:
- using Base = detail::xoshiro_base<xoshiro512mm, 8>;
- public:
- using Base::Base;
- inline result_type next() noexcept
- {
- const std::uint64_t result = boost::core::rotl(state_[1] * 5, 7) * 9;
- const std::uint64_t t = state_[1] << 11;
- state_[2] ^= state_[0];
- state_[5] ^= state_[1];
- state_[1] ^= state_[2];
- state_[7] ^= state_[3];
- state_[3] ^= state_[4];
- state_[4] ^= state_[5];
- state_[0] ^= state_[6];
- state_[6] ^= state_[7];
- state_[6] ^= t;
- state_[7] = boost::core::rotl(state_[7], 21);
- return result;
- }
- };
- /**
- * This is xoshiro512+ 1.0, our generator for floating-point numbers with
- * increased state size. We suggest to use its upper bits for
- * floating-point generation, as it is slightly faster than xoshiro512**.
- * It passes all tests we are aware of except for the lowest three bits,
- * which might fail linearity tests (and just those), so if low linear
- * complexity is not considered an issue (as it is usually the case) it
- * can be used to generate 64-bit outputs, too.
- *
- * We suggest to use a sign test to extract a random Boolean value, and
- * right shifts to extract subsets of bits.
- *
- * The state must be seeded so that it is not everywhere zero. If you have
- * a 64-bit seed, we suggest to seed a splitmix64 generator and use its
- * output to fill s.
- */
- class xoshiro512d final : public detail::xoshiro_base<xoshiro512d, 8, double>
- {
- private:
- using Base = detail::xoshiro_base<xoshiro512d, 8, double>;
- public:
- using Base::Base;
- inline std::uint64_t next_int() noexcept
- {
- const std::uint64_t result = state_[0] + state_[2];
- const std::uint64_t t = state_[1] << 11;
- state_[2] ^= state_[0];
- state_[5] ^= state_[1];
- state_[1] ^= state_[2];
- state_[7] ^= state_[3];
- state_[3] ^= state_[4];
- state_[4] ^= state_[5];
- state_[0] ^= state_[6];
- state_[6] ^= state_[7];
- state_[6] ^= t;
- state_[7] = boost::core::rotl(state_[7], 21);
- return result;
- }
- inline result_type next() noexcept
- {
- #ifdef BOOST_RANDOM_HAS_HEX_FLOAT
- return static_cast<double>((next_int() >> 11)) * 0x1.0p-53;
- #else
- return static_cast<double>((next_int() >> 11)) * 1.11022302462515654e-16;
- #endif
- }
- static constexpr result_type (min)() noexcept
- {
- #ifdef BOOST_RANDOM_HAS_HEX_FLOAT
- return static_cast<double>((std::numeric_limits<std::uint64_t>::min)() >> 11) * 0x1.0p-53;
- #else
- return static_cast<double>((std::numeric_limits<std::uint64_t>::min)() >> 11) * 1.11022302462515654e-16;
- #endif
- }
- static constexpr result_type (max)() noexcept
- {
- #ifdef BOOST_RANDOM_HAS_HEX_FLOAT
- return static_cast<double>((std::numeric_limits<std::uint64_t>::max)() >> 11) * 0x1.0p-53;
- #else
- return static_cast<double>((std::numeric_limits<std::uint64_t>::max)() >> 11) * 1.11022302462515654e-16;
- #endif
- }
- };
- /**
- * This is xoshiro128++ 1.0, one of our 32-bit all-purpose, rock-solid
- * generators. It has excellent speed, a state size (128 bits) that is
- * large enough for mild parallelism, and it passes all tests we are aware
- * of.
- *
- * For generating just single-precision (i.e., 32-bit) floating-point
- * numbers, xoshiro128+ is even faster.
- *
- * The state must be seeded so that it is not everywhere zero.
- */
- class xoshiro128pp final : public detail::xoshiro_base<xoshiro128pp, 4, std::uint32_t, std::uint32_t>
- {
- private:
- using Base = detail::xoshiro_base<xoshiro128pp, 4, std::uint32_t, std::uint32_t>;
- public:
- using Base::Base;
- inline result_type next() noexcept
- {
- const std::uint32_t result = boost::core::rotl(state_[0] + state_[3], 7) + state_[0];
- const std::uint32_t t = state_[1] << 9;
- state_[2] ^= state_[0];
- state_[3] ^= state_[1];
- state_[1] ^= state_[2];
- state_[0] ^= state_[3];
- state_[2] ^= t;
- state_[3] = boost::core::rotl(state_[3], 11);
- return result;
- }
- };
- /**
- * This is xoshiro128** 1.1, one of our 32-bit all-purpose, rock-solid
- * generators. It has excellent speed, a state size (128 bits) that is
- * large enough for mild parallelism, and it passes all tests we are aware
- * of.
- *
- * Note that version 1.0 had mistakenly state_[0] instead of state_[1] as state
- * word passed to the scrambler.
- *
- * For generating just single-precision (i.e., 32-bit) floating-point
- * numbers, xoshiro128+ is even faster.
- *
- * The state must be seeded so that it is not everywhere zero.
- */
- class xoshiro128mm final : public detail::xoshiro_base<xoshiro128mm, 4, std::uint32_t, std::uint32_t>
- {
- private:
- using Base = detail::xoshiro_base<xoshiro128mm, 4, std::uint32_t, std::uint32_t>;
- public:
- using Base::Base;
- inline result_type next() noexcept
- {
- const std::uint32_t result = boost::core::rotl(state_[1] * 5, 7) * 9;
- const std::uint32_t t = state_[1] << 9;
- state_[2] ^= state_[0];
- state_[3] ^= state_[1];
- state_[1] ^= state_[2];
- state_[0] ^= state_[3];
- state_[2] ^= t;
- state_[3] = boost::core::rotl(state_[3], 11);
- return result;
- }
- };
- /**
- * This is xoshiro128+ 1.0, our best and fastest 32-bit generator for 32-bit
- * floating-point numbers. We suggest to use its upper bits for
- * floating-point generation, as it is slightly faster than xoshiro128**.
- * It passes all tests we are aware of except for
- * linearity tests, as the lowest four bits have low linear complexity, so
- * if low linear complexity is not considered an issue (as it is usually
- * the case) it can be used to generate 32-bit outputs, too.
- *
- * We suggest to use a sign test to extract a random Boolean value, and
- * right shifts to extract subsets of bits.
- *
- * The state must be seeded so that it is not everywhere zero.
- */
- class xoshiro128f final : public detail::xoshiro_base<xoshiro128f, 4, float, std::uint32_t>
- {
- private:
- using Base = detail::xoshiro_base<xoshiro128f, 4, float, std::uint32_t>;
- public:
- using Base::Base;
- inline std::uint32_t next_int() noexcept
- {
- const std::uint32_t result = state_[0] + state_[3];
- const std::uint32_t t = state_[1] << 9;
- state_[2] ^= state_[0];
- state_[3] ^= state_[1];
- state_[1] ^= state_[2];
- state_[0] ^= state_[3];
- state_[2] ^= t;
- state_[3] = boost::core::rotl(state_[3], 11);
- return result;
- }
- inline result_type next() noexcept
- {
- #ifdef BOOST_RANDOM_HAS_HEX_FLOAT
- return static_cast<float>((next_int() >> 8)) * 0x1.0p-24f;
- #else
- return static_cast<float>((next_int() >> 8)) * 5.9604645e-08f;
- #endif
- }
- static constexpr result_type (min)() noexcept
- {
- #ifdef BOOST_RANDOM_HAS_HEX_FLOAT
- return static_cast<float>((std::numeric_limits<std::uint32_t>::min)() >> 8) * 0x1.0p-24f;
- #else
- return static_cast<float>((std::numeric_limits<std::uint64_t>::min)() >> 8) * 5.9604645e-08f;
- #endif
- }
- static constexpr result_type (max)() noexcept
- {
- #ifdef BOOST_RANDOM_HAS_HEX_FLOAT
- return static_cast<float>((std::numeric_limits<std::uint32_t>::max)() >> 8) * 0x1.0p-24f;
- #else
- return static_cast<float>((std::numeric_limits<std::uint64_t>::max)() >> 8) * 5.9604645e-08f;
- #endif
- }
- };
- } // namespace random
- } // namespace boost
- #endif //BOOST_RANDOM_XOSHIRO_HPP
|