• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 ///////////////////////////////////////////////////////////////
2 //  Copyright 2018 John Maddock. Distributed under the Boost
3 //  Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
5 
6 // Contains Quickbook snippets used by boost/libs/multiprecision/doc/multiprecision.qbk,
7 // used in section Literal Types and constexpr Support, last example on constexpr randoms.
8 
9 // A implementation and demonstration of the Keep It Simple Stupid random number generator algorithm https://en.wikipedia.org/wiki/KISS_(algorithm) for cpp_int integers.
10 // b2 --abbreviate-paths toolset=clang-9.0.0 address-model=64 cxxstd=2a release misc > multiprecision_clang_misc.log
11 
12 #include <boost/multiprecision/cpp_int.hpp>
13 
14 #include <iostream>
15 
16 struct kiss_rand
17 {
18    typedef std::uint64_t result_type;
19 
kiss_randkiss_rand20    constexpr kiss_rand() : x(0x8207ebe160468b32uLL), y(0x2871283e01d45bbduLL), z(0x9c80bfd5db9680c9uLL), c(0x2e2683c2abb878b8uLL) {}
kiss_randkiss_rand21    constexpr kiss_rand(std::uint64_t seed) : x(seed), y(0x2871283e01d45bbduLL), z(0x9c80bfd5db9680c9uLL), c(0x2e2683c2abb878b8uLL) {}
kiss_randkiss_rand22    constexpr kiss_rand(std::uint64_t seed_x, std::uint64_t seed_y) : x(seed_x), y(seed_y), z(0x9c80bfd5db9680c9uLL), c(0x2e2683c2abb878b8uLL) {}
kiss_randkiss_rand23    constexpr kiss_rand(std::uint64_t seed_x, std::uint64_t seed_y, std::uint64_t seed_z) : x(seed_x), y(seed_y), z(seed_z), c(0x2e2683c2abb878b8uLL) {}
24 
operator ()kiss_rand25    constexpr std::uint64_t operator()()
26    {
27       return MWC() + XSH() + CNG();
28    }
29 
30  private:
MWCkiss_rand31    constexpr std::uint64_t MWC()
32    {
33       std::uint64_t t = (x << 58) + c;
34       c               = (x >> 6);
35       x += t;
36       c += (x < t);
37       return x;
38    }
XSHkiss_rand39    constexpr std::uint64_t XSH()
40    {
41       y ^= (y << 13);
42       y ^= (y >> 17);
43       return y ^= (y << 43);
44    }
CNGkiss_rand45    constexpr std::uint64_t CNG()
46    {
47       return z = 6906969069LL * z + 1234567;
48    }
49    std::uint64_t x, y, z, c;
50 };
51 
hash_combine(std::uint64_t & h,std::uint64_t k)52 inline constexpr void hash_combine(std::uint64_t& h, std::uint64_t k)
53 {
54    constexpr const std::uint64_t m = 0xc6a4a7935bd1e995uLL;
55    constexpr const int           r = 47;
56 
57    k *= m;
58    k ^= k >> r;
59    k *= m;
60 
61    h ^= k;
62    h *= m;
63 
64    // Completely arbitrary number, to prevent 0's from hashing to 0.
65    h += 0xe6546b64;
66 }
67 
68 template <std::size_t N>
string_to_hash(const char (& s)[N])69 inline constexpr std::uint64_t string_to_hash(const char (&s)[N])
70 {
71    std::uint64_t hash(0);
72    for (unsigned i = 0; i < N; ++i)
73       hash_combine(hash, s[i]);
74    return hash;
75 }
76 
77 template <class UnsignedInteger>
78 struct multiprecision_generator
79 {
80    typedef UnsignedInteger result_type;
multiprecision_generatormultiprecision_generator81    constexpr               multiprecision_generator(std::uint64_t seed1) : m_gen64(seed1) {}
multiprecision_generatormultiprecision_generator82    constexpr               multiprecision_generator(std::uint64_t seed1, std::uint64_t seed2) : m_gen64(seed1, seed2) {}
multiprecision_generatormultiprecision_generator83    constexpr               multiprecision_generator(std::uint64_t seed1, std::uint64_t seed2, std::uint64_t seed3) : m_gen64(seed1, seed2, seed3) {}
84 
result_typemultiprecision_generator85    static constexpr result_type (min)()
86    {
87       return 0u;
88    }
result_typemultiprecision_generator89    static constexpr result_type (max)()
90    {
91       return ~result_type(0u);
92    }
operator ()multiprecision_generator93    constexpr result_type operator()()
94    {
95       result_type result(m_gen64());
96       unsigned    digits = 64;
97       while (digits < std::numeric_limits<result_type>::digits)
98       {
99          result <<= 64;
100          result |= m_gen64();
101          digits += 64;
102       }
103       return result;
104    }
105 
106  private:
107    kiss_rand m_gen64;
108 };
109 
110 template <class UnsignedInteger>
nth_random_value(unsigned count=0)111 constexpr UnsignedInteger nth_random_value(unsigned count = 0)
112 {
113    std::uint64_t                             date_hash = string_to_hash(__DATE__);
114    std::uint64_t                             time_hash = string_to_hash(__TIME__);
115    multiprecision_generator<UnsignedInteger> big_gen(date_hash, time_hash);
116    for (unsigned i = 0; i < count; ++i)
117       big_gen();
118    return big_gen();
119 }
120 
main()121 int main()
122 {
123    using namespace boost::multiprecision;
124 
125 //[random_constexpr_cppint
126    constexpr uint1024_t rand = nth_random_value<uint1024_t>(1000);
127    std::cout << std::hex << rand << std::endl;
128 //] [/random_constexpr_cppint]
129    return 0;
130 }
131