Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-26 08:52:44

0001 /* 
0002  * Copyright Sebastiano Vigna 2015.
0003  * Copyright Matt Borland 2022.
0004  * Distributed under the Boost Software License, Version 1.0. (See
0005  * accompanying file LICENSE_1_0.txt or copy at
0006  * http://www.boost.org/LICENSE_1_0.txt)
0007  * 
0008  */
0009 
0010 #ifndef BOOST_RANDOM_SPLITMIX64_HPP
0011 #define BOOST_RANDOM_SPLITMIX64_HPP
0012 
0013 #include <cstdint>
0014 #include <cstdlib>
0015 #include <limits>
0016 #include <array>
0017 #include <string>
0018 #include <ios>
0019 #include <type_traits>
0020 
0021 namespace boost { namespace random {
0022 
0023 /**
0024  *  This is a fixed-increment version of Java 8's SplittableRandom generator
0025  *  See http://dx.doi.org/10.1145/2714064.2660195 and
0026  *  http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html
0027  *  It is a very fast generator passing BigCrush, and it can be useful if
0028  *  for some reason you absolutely want 64 bits of state; otherwise, we
0029  *  rather suggest to use a xoroshiro128+ (for moderately parallel
0030  *  computations) or xorshift1024* (for massively parallel computations)
0031  *  generator.
0032  */
0033 class splitmix64
0034 {
0035 private:
0036     std::uint64_t state_;
0037 
0038     inline std::uint64_t concatenate(std::uint32_t word1, std::uint32_t word2) noexcept
0039     {
0040         return static_cast<std::uint64_t>(word1) << 32 | word2;
0041     }
0042 
0043 public:
0044     using result_type = std::uint64_t;
0045     using seed_type = std::uint64_t;
0046 
0047     // Required for old Boost.Random concept
0048     static constexpr bool has_fixed_range {false};
0049 
0050     /** Seeds the generator with the default seed. */
0051     void seed(result_type value = 0) noexcept
0052     {
0053         if (value == 0)
0054         {
0055             state_ = UINT64_C(0xA164B43C8F634A13);
0056         }
0057         else
0058         {
0059             state_ = value;
0060         }
0061     }
0062 
0063     /**
0064      * Seeds the generator with 32-bit values produced by @c seq.generate().
0065      */
0066     template <typename Sseq, typename std::enable_if<!std::is_convertible<Sseq, std::uint64_t>::value, bool>::type = true>
0067     void seed(Sseq& seq)
0068     {
0069         std::array<std::uint32_t, 2> seeds;
0070         seq.generate(seeds.begin(), seeds.end());
0071 
0072         state_ = concatenate(seeds[0], seeds[1]);
0073     }
0074 
0075     /**
0076      * Seeds the generator with 64-bit values produced by @c seq.generate().
0077      */
0078     template <typename Sseq, typename std::enable_if<!std::is_convertible<Sseq, splitmix64>::value, bool>::type = true>
0079     explicit splitmix64(Sseq& seq)
0080     {
0081         seed(seq);
0082     }
0083 
0084     /** Seeds the generator with a user provided seed. */
0085     template <typename T, typename std::enable_if<std::is_convertible<T, std::uint64_t>::value, bool>::type = true>
0086     void seed(T value = 0) noexcept
0087     {
0088         seed(static_cast<std::uint64_t>(value));
0089     }
0090 
0091     /** Seeds the generator with a user provided seed. */
0092     explicit splitmix64(std::uint64_t state = 0) noexcept
0093     {
0094         seed(state);
0095     }
0096 
0097     splitmix64(const splitmix64& other) = default;
0098     splitmix64& operator=(const splitmix64& other) = default;
0099 
0100     /**  Returns the next value of the generator. */
0101     inline result_type next() noexcept
0102     {
0103         std::uint64_t z {state_ += UINT64_C(0x9E3779B97F4A7C15)};
0104         z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9);
0105         z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB);
0106         
0107         return z ^ (z >> 31);
0108     }
0109 
0110     /**  Returns the next value of the generator. */
0111     inline result_type operator()() noexcept
0112     {
0113         return next();
0114     }
0115 
0116     /** Advances the state of the generator by @c z. */
0117     inline void discard(std::uint64_t z) noexcept
0118     {
0119         for (std::uint64_t i {}; i < z; ++i)
0120         {
0121             next();
0122         }
0123     }
0124 
0125     /**
0126      * Returns true if the two generators will produce identical
0127      * sequences of values.
0128      */
0129     inline friend bool operator==(const splitmix64& lhs, const splitmix64& rhs) noexcept
0130     {
0131         return lhs.state_ == rhs.state_;
0132     }
0133 
0134     /**
0135      * Returns true if the two generators will produce different
0136      * sequences of values.
0137      */
0138     inline friend bool operator!=(const splitmix64& lhs, const splitmix64& rhs) noexcept
0139     {
0140         return !(lhs == rhs);
0141     }
0142 
0143     /**  Writes a @c splitmix64 to a @c std::ostream. */
0144     template <typename CharT, typename Traits>
0145     inline friend std::basic_ostream<CharT,Traits>& operator<<(std::basic_ostream<CharT,Traits>& ost, 
0146                                                                const splitmix64& e)
0147     {
0148         ost << e.state_;
0149         return ost;
0150     }
0151 
0152     /**  Writes a @c splitmix64 to a @c std::istream. */
0153     template <typename CharT, typename Traits>
0154     inline friend std::basic_istream<CharT,Traits>& operator>>(std::basic_istream<CharT,Traits>& ist,
0155                                                                splitmix64& e)
0156     {
0157         std::string sstate;
0158         CharT val;
0159         while (ist >> val)
0160         {
0161             if (std::isdigit(val))
0162             {
0163                 sstate.push_back(val);
0164             }
0165         }
0166         
0167         e.state_ = std::strtoull(sstate.c_str(), nullptr, 10);
0168 
0169         return ist;
0170     }
0171 
0172     /** Fills a range with random values */
0173     template <typename FIter>
0174     inline void generate(FIter first, FIter last) noexcept
0175     {
0176         while (first != last)
0177         {
0178             *first++ = next();
0179         }
0180     }
0181 
0182     /**
0183      * Returns the largest value that the @c splitmix64
0184      * can produce.
0185      */
0186     static constexpr result_type (max)() noexcept
0187     {
0188         return (std::numeric_limits<std::uint64_t>::max)();
0189     }
0190 
0191     /**
0192      * Returns the smallest value that the @c splitmix64
0193      * can produce.
0194      */
0195     static constexpr result_type (min)() noexcept
0196     {
0197         return (std::numeric_limits<std::uint64_t>::min)();
0198     }
0199 };
0200 
0201 }} // Namespace boost::random
0202 
0203 #endif // BOOST_RANDOM_SPLITMIX64_HPP