MCKL
Monte Carlo Kernel Library
uniform_bits_distribution.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/random/uniform_bits_distribution.hpp
3 //----------------------------------------------------------------------------
4 // MCKL: Monte Carlo Kernel Library
5 //----------------------------------------------------------------------------
6 // Copyright (c) 2013-2018, Yan Zhou
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimer.
14 //
15 // Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimer in the documentation
17 // and/or other materials provided with the distribution.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //============================================================================
31 
32 #ifndef MCKL_RANDOM_UNIFORM_BITS_DISTRIBUTION_HPP
33 #define MCKL_RANDOM_UNIFORM_BITS_DISTRIBUTION_HPP
34 
36 
37 namespace mckl {
38 
39 namespace internal {
40 
41 template <typename UIntType, typename RNGType>
43  RNGType &rng, std::size_t n, UIntType *r, std::false_type, std::false_type)
44 {
46  for (std::size_t i = 0; i != n; ++i) {
47  r[i] = ubits(rng);
48  }
49 }
50 
51 template <typename UIntType, typename RNGType, bool DownCast>
52 inline void uniform_bits_distribution_impl(RNGType &rng, std::size_t n,
53  UIntType *r, std::true_type, std::integral_constant<bool, DownCast>)
54 {
55  constexpr int rbits = RNGTraits<RNGType>::bits;
56  constexpr int ubits = std::numeric_limits<UIntType>::digits;
57  constexpr std::size_t rate = ubits / rbits;
58  const std::size_t m = n * rate;
59  rand(rng, m, reinterpret_cast<typename RNGType::result_type *>(r));
60 }
61 
62 template <typename UIntType, typename RNGType>
64  RNGType &rng, std::size_t n, UIntType *r, std::false_type, std::true_type)
65 {
66  const std::size_t k = BufferSize<UIntType>::value;
67  alignas(MCKL_ALIGNMENT) std::array<typename RNGType::result_type, k> s;
68  while (n >= k) {
69  rand(rng, k, s.data());
70  std::copy_n(s.data(), k, r);
71  n -= k;
72  r += k;
73  }
74  rand(rng, n, s.data());
75  std::copy_n(s.data(), n, r);
76 }
77 
78 } // namespace internal
79 
80 template <typename UIntType, typename RNGType>
81 inline void uniform_bits_distribution(RNGType &rng, std::size_t n, UIntType *r)
82 {
83  constexpr int rbits = RNGTraits<RNGType>::bits;
84  constexpr int ubits = std::numeric_limits<UIntType>::digits;
85  constexpr int tbits =
86  std::numeric_limits<typename RNGType::result_type>::digits;
87  constexpr std::size_t ualign = alignof(UIntType);
88  constexpr std::size_t talign = alignof(UIntType);
89  constexpr bool direct =
90  // Full range, range is [0, 2^W - 1]
92  // All ouptut of rng() are random bits
93  rbits == tbits &&
94  // One or multiple rng() can fill exactly one output integer
95  ubits >= tbits && ubits % tbits == 0 &&
96  // Alignment requirement
97  ualign >= talign && ualign % talign == 0;
98  constexpr bool downcast =
99  // Full range, range is [0, 2^W - 1]
101  // down cast
102  ubits <= rbits;
103 
105  std::integral_constant<bool, direct>(),
106  std::integral_constant<bool, downcast>());
107 }
108 
109 template <typename UIntType, typename RNGType>
110 inline void uniform_bits_distribution(RNGType &rng, std::size_t n, UIntType *r,
112 {
113  uniform_bits_distribution(rng, n, r);
114 }
115 
123 template <typename UIntType>
125 {
127  MCKL_DEFINE_RANDOM_DISTRIBUTION_0(UniformBits, uniform_bits, UIntType)
129 
130  public:
131  result_type min() const { return std::numeric_limits<result_type>::min(); }
132 
133  result_type max() const { return std::numeric_limits<result_type>::max(); }
134 
135  void reset() {}
136 
137  private:
138  template <typename RNGType>
139  result_type generate(RNGType &rng, const param_type &)
140  {
141  constexpr bool patch = RNGTraits<RNGType>::is_full_range;
142 
143  return generate(rng, std::integral_constant<bool, patch>());
144  }
145 
146  template <typename RNGType>
147  static UIntType generate(RNGType &rng, std::false_type)
148  {
149  std::independent_bits_engine<RNGType,
150  std::numeric_limits<UIntType>::digits, UIntType>
151  eng(std::move(rng));
152  UIntType u = eng();
153  rng = std::move(eng.base());
154 
155  return u;
156  }
157 
158  template <typename RNGType>
159  static UIntType generate(RNGType &rng, std::true_type)
160  {
161  constexpr int w = std::numeric_limits<UIntType>::digits;
162  constexpr int r = RNGTraits<RNGType>::bits;
163 
164  return generate_patch(rng, std::integral_constant<bool, (w <= r)>());
165  }
166 
167  template <typename RNGType>
168  static UIntType generate_patch(RNGType &rng, std::true_type)
169  {
170  return static_cast<UIntType>(rng() - RNGType::min());
171  }
172 
173  template <typename RNGType>
174  static UIntType generate_patch(RNGType &rng, std::false_type)
175  {
176 #if MCKL_HAS_LITTLE_ENDIAN || !MCKL_REQUIRE_ENDIANNESS_NEUTURAL
177  return patch_le<0>(rng, std::true_type());
178 #elif MCKL_HAS_BIG_ENDIAN
179  return patch_be<0>(rng, std::true_type());
180 #else
181  return internal::is_big_endian() ? patch_be<0>(rng, std::true_type()) :
182  patch_le<0>(rng, std::true_type());
183 #endif
184  }
185 
186  template <int, typename RNGType>
187  static UIntType patch_le(RNGType &, std::false_type)
188  {
189  return 0;
190  }
191 
192  template <int N, typename RNGType>
193  static UIntType patch_le(RNGType &rng, std::true_type)
194  {
195  constexpr int w = std::numeric_limits<UIntType>::digits;
196  constexpr int r = RNGTraits<RNGType>::bits;
197  constexpr int p = r * N;
198  constexpr int q = r * N + r;
199 
200  UIntType u = static_cast<UIntType>(rng() - RNGType::min())
201  << static_cast<UIntType>(p);
202 
203  return u |
204  patch_le<N + 1>(rng, std::integral_constant<bool, (q < w)>());
205  }
206 
207  template <int N, typename RNGType>
208  static UIntType patch_be(RNGType &, std::false_type)
209  {
210  return 0;
211  }
212 
213  template <int N, typename RNGType>
214  static UIntType patch_be(RNGType &rng, std::true_type)
215  {
216  constexpr int w = std::numeric_limits<UIntType>::digits;
217  constexpr int r = RNGTraits<RNGType>::bits;
218  constexpr int q = r * N + r;
219  constexpr int pl = q < w ? w - q : 0;
220  constexpr int pr = q < w ? 0 : q - w;
221 
222  UIntType u = static_cast<UIntType>(rng() - RNGType::min());
223  u <<= static_cast<UIntType>(pl);
224  u >>= static_cast<UIntType>(pr);
225 
226  return u |
227  patch_be<N + 1>(rng, std::integral_constant<bool, (q < w)>());
228  }
229 }; // class UniformBitsDistribution
230 
232 
233 } // namespace mckl
234 
235 #endif // MCKL_RANDOM_UNIFORM_BITS_DISTRIBUTION_HPP
Traits of RNG engines.
void uniform_bits_distribution_impl(RNGType &rng, std::size_t n, UIntType *r, std::false_type, std::false_type)
void uniform_bits_distribution(RNGType &rng, std::size_t n, UIntType *r)
#define MCKL_DEFINE_RANDOM_DISTRIBUTION_RAND(Name, T)
#define MCKL_DEFINE_RANDOM_DISTRIBUTION_0(Name, name, T)
Definition: mcmc.hpp:40
void rand(RNGType &rng, ArcsineDistribution< RealType > &distribution, std::size_t N, RealType *r)
#define MCKL_ALIGNMENT
The default alignment for scalar type.
Definition: config.h:187
#define MCKL_DEFINE_RANDOM_DISTRIBUTION_MEMBER_0
bool is_big_endian()
Definition: byte_order.hpp:56
#define MCKL_DEFINE_RANDOM_DISTRIBUTION_ASSERT_UINT_TYPE(Name, MinBits)