Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-10 09:10:47

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         state_ += z * UINT64_C(0x9E3779B97F4A7C15);
0120     }
0121 
0122     /**
0123      * Returns true if the two generators will produce identical
0124      * sequences of values.
0125      */
0126     inline friend bool operator==(const splitmix64& lhs, const splitmix64& rhs) noexcept
0127     {
0128         return lhs.state_ == rhs.state_;
0129     }
0130 
0131     /**
0132      * Returns true if the two generators will produce different
0133      * sequences of values.
0134      */
0135     inline friend bool operator!=(const splitmix64& lhs, const splitmix64& rhs) noexcept
0136     {
0137         return !(lhs == rhs);
0138     }
0139 
0140     /**  Writes a @c splitmix64 to a @c std::ostream. */
0141     template <typename CharT, typename Traits>
0142     inline friend std::basic_ostream<CharT,Traits>& operator<<(std::basic_ostream<CharT,Traits>& ost, 
0143                                                                const splitmix64& e)
0144     {
0145         ost << e.state_;
0146         return ost;
0147     }
0148 
0149     /**  Writes a @c splitmix64 to a @c std::istream. */
0150     template <typename CharT, typename Traits>
0151     inline friend std::basic_istream<CharT,Traits>& operator>>(std::basic_istream<CharT,Traits>& ist,
0152                                                                splitmix64& e)
0153     {
0154         std::string sstate;
0155         CharT val;
0156         while (ist >> val)
0157         {
0158             if (std::isdigit(val))
0159             {
0160                 sstate.push_back(val);
0161             }
0162         }
0163         
0164         e.state_ = std::strtoull(sstate.c_str(), nullptr, 10);
0165 
0166         return ist;
0167     }
0168 
0169     /** Fills a range with random values */
0170     template <typename FIter>
0171     inline void generate(FIter first, FIter last) noexcept
0172     {
0173         while (first != last)
0174         {
0175             *first++ = next();
0176         }
0177     }
0178 
0179     /**
0180      * Returns the largest value that the @c splitmix64
0181      * can produce.
0182      */
0183     static constexpr result_type (max)() noexcept
0184     {
0185         return (std::numeric_limits<std::uint64_t>::max)();
0186     }
0187 
0188     /**
0189      * Returns the smallest value that the @c splitmix64
0190      * can produce.
0191      */
0192     static constexpr result_type (min)() noexcept
0193     {
0194         return (std::numeric_limits<std::uint64_t>::min)();
0195     }
0196 };
0197 
0198 }} // Namespace boost::random
0199 
0200 #endif // BOOST_RANDOM_SPLITMIX64_HPP