MCKL
Monte Carlo Kernel Library
philox_common.hpp
Go to the documentation of this file.
1 //============================================================================
2 // MCKL/include/mckl/random/internal/philox_common.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_INTERNAL_PHILOX_COMMON_HPP
33 #define MCKL_RANDOM_INTERNAL_PHILOX_COMMON_HPP
34 
38 
39 namespace mckl {
40 
41 namespace internal {
42 
43 template <typename T, int = std::numeric_limits<T>::digits>
44 class PhiloxHiLo;
45 
46 template <typename T>
47 class PhiloxHiLo<T, 32>
48 {
49  public:
50  static T eval(T a, T b, T &h)
51  {
52  union {
53  std::uint64_t p;
54  std::array<T, 2> r;
55  } buf;
56 
57  buf.p = static_cast<std::uint64_t>(a) * static_cast<std::uint64_t>(b);
58 
59 #if MCKL_HAS_LITTLE_ENDIAN
60  h = std::get<1>(buf.r);
61 
62  return std::get<0>(buf.r);
63 #elif MCKL_HAS_BIG_ENDIAN
64  h = std::get<0>(buf.r);
65 
66  return std::get<1>(buf.r);
67 #else
68  h = static_cast<T>(buf.p >> 32);
69 
70  return static_cast<T>(buf.p);
71 #endif
72  }
73 }; // class PhiloxHiLo
74 
75 template <typename T>
76 class PhiloxHiLo<T, 64>
77 {
78  public:
79  static T eval(T a, T b, T &h)
80  {
81 #if MCKL_USE_BMI2 && MCKL_HAS_X86_64
82  return eval_bmi2(a, b, h);
83 #elif MCKL_HAS_INT128
84  return eval_int128(a, b, h);
85 #else
86  return eval_generic(a, b, h);
87 #endif
88  }
89 
90  private:
91  static T eval_generic(T a, T b, T &h)
92  {
93  const T mask = (const_one<T>() << 32) - 1;
94  const T ah = a >> 32;
95  const T al = a & mask;
96  const T bh = b >> 32;
97  const T bl = b & mask;
98  const T ahbl = ah * bl;
99  const T albh = al * bh;
100  const T ahbl_albh = ((ahbl & mask) + (albh & mask));
101  const T l = a * b;
102  h = ah * bh + (ahbl >> 32) + (albh >> 32);
103  h += ahbl_albh >> 32;
104  h += (l >> 32) < (ahbl_albh & mask) ? 1 : 0;
105 
106  return l;
107  }
108 
109 #if MCKL_USE_BMI2 && MCKL_HAS_X86_64
110  static T eval_bmi2(T a, T b, T &h)
111  {
112  unsigned MCKL_INT64 t = 0;
113  unsigned MCKL_INT64 l =
114  static_cast<T>(_mulx_u64(static_cast<unsigned MCKL_INT64>(a),
115  static_cast<unsigned MCKL_INT64>(b), &t));
116  h = static_cast<T>(t);
117 
118  return l;
119  }
120 #endif
121 
122 #if MCKL_HAS_INT128
123  static T eval_int128(T a, T b, T &h)
124  {
125  MCKL_PUSH_GCC_WARNING("-Wpedantic")
126  union {
127  unsigned MCKL_INT128 p;
128  std::array<T, 2> r;
129  } buf;
130 
131  buf.p = static_cast<unsigned MCKL_INT128>(a) *
132  static_cast<unsigned MCKL_INT128>(b);
134 
135 #if MCKL_HAS_LITTLE_ENDIAN
136  h = std::get<1>(buf.r);
137  return std::get<0>(buf.r);
138 #elif MCKL_HAS_BIG_ENDIAN
139  h = std::get<0>(buf.r);
140  return std::get<1>(buf.r);
141 #else
142  h = static_cast<T>(buf.p >> 64);
143  return static_cast<T>(buf.p);
144 #endif
145  }
146 #endif
147 }; // class PhiloxHiLo
148 
149 #if MCKL_USE_BMI2 && MCKL_HAS_X86_64
150 
151 template <>
152 class PhiloxHiLo<unsigned MCKL_INT64, 64>
153 {
154  public:
155  static unsigned MCKL_INT64 eval(
156  unsigned MCKL_INT64 a, unsigned MCKL_INT64 b, unsigned MCKL_INT64 &h)
157  {
158  return _mulx_u64(a, b, &h);
159  }
160 }; // class PhiloxHiLo
161 
162 #endif // MCKL_USE_BMI2 && MCKL_HAS_X86_64
163 
164 template <typename T, std::size_t K, std::size_t N, typename Constants>
166 {
167  public:
168  static void eval(std::array<T, K> &s, const std::array<T, K / 2> &k)
169  {
170  std::array<T, K> t;
171  pbox<0>(s, t, std::integral_constant<bool, 0 < K>());
172  sbox<0>(s, t, k, std::integral_constant<bool, 0 < K / 2>());
173  }
174 
175  private:
176  template <std::size_t>
177  static void sbox(std::array<T, K> &, const std::array<T, K> &,
178  const std::array<T, K / 2> &, std::false_type)
179  {
180  }
181 
182  template <std::size_t I>
183  static void sbox(std::array<T, K> &s, const std::array<T, K> &t,
184  const std::array<T, K / 2> &k, std::true_type)
185  {
186  constexpr std::size_t I0 = I * 2;
187  constexpr std::size_t I1 = I * 2 + 1;
188  constexpr T w = Constants::weyl::value[I] * static_cast<T>(N - 1);
189  constexpr T m = Constants::multiplier::value[I];
190 
191  T h;
192  std::get<I1>(s) = PhiloxHiLo<T>::eval(std::get<I0>(t), m, h);
193  std::get<I0>(s) = (std::get<I>(k) + w) ^ (std::get<I1>(t) ^ h);
194  sbox<I + 1>(s, t, k, std::integral_constant<bool, I + 1 < K / 2>());
195  }
196 
197  template <std::size_t>
198  static void pbox(
199  const std::array<T, K> &, std::array<T, K> &, std::false_type)
200  {
201  }
202 
203  template <std::size_t I>
204  static void pbox(
205  const std::array<T, K> &s, std::array<T, K> &t, std::true_type)
206  {
207  constexpr std::size_t P =
209  constexpr std::size_t J = K - P - 1;
210 
211  std::get<I>(t) = std::get<J>(s);
212  pbox<I + 1>(s, t, std::integral_constant<bool, I + 1 < K>());
213  }
214 }; // class PhiloxRBox
215 
216 template <typename T, std::size_t N, typename Constants>
217 class PhiloxRBox<T, 2, N, Constants>
218 {
219  public:
220  static void eval(std::array<T, 2> &s, const std::array<T, 1> &k)
221  {
222  constexpr T w0 = Constants::weyl::value[0] * static_cast<T>(N - 1);
223  constexpr T m0 = Constants::multiplier::value[0];
224 
225  T s1 = std::get<1>(s);
226  T h0;
227  std::get<1>(s) = PhiloxHiLo<T>::eval(std::get<0>(s), m0, h0);
228  std::get<0>(s) = (std::get<0>(k) + w0) ^ (s1 ^ h0);
229  }
230 }; // class PhiloxRBox
231 
232 template <typename T, std::size_t N, typename Constants>
233 class PhiloxRBox<T, 4, N, Constants>
234 {
235  public:
236  static void eval(std::array<T, 4> &s, const std::array<T, 2> &k)
237  {
238  constexpr T w0 = Constants::weyl::value[0] * static_cast<T>(N - 1);
239  constexpr T w1 = Constants::weyl::value[1] * static_cast<T>(N - 1);
240  constexpr T m2 = Constants::multiplier::value[0];
241  constexpr T m0 = Constants::multiplier::value[1];
242 
243  T s1 = std::get<1>(s);
244  T s3 = std::get<3>(s);
245  T h2;
246  T h0;
247  std::get<1>(s) = PhiloxHiLo<T>::eval(std::get<2>(s), m2, h2);
248  std::get<3>(s) = PhiloxHiLo<T>::eval(std::get<0>(s), m0, h0);
249  std::get<0>(s) = (std::get<0>(k) + w0) ^ (s1 ^ h2);
250  std::get<2>(s) = (std::get<1>(k) + w1) ^ (s3 ^ h0);
251  }
252 }; // class PhiloxRBox
253 
254 } // namespace internal
255 
256 } // namespace mckl
257 
258 #endif // MCKL_RANDOM_INTERNAL_PHILOX_COMMON_HPP
static void eval(std::array< T, 4 > &s, const std::array< T, 2 > &k)
#define MCKL_PUSH_GCC_WARNING(warning)
Definition: compiler.h:78
static void eval(std::array< T, K > &s, const std::array< T, K/2 > &k)
#define MCKL_INT64
Definition: clang.h:134
ulong uint64_t
Definition: opencl.h:42
static T eval(T a, T b, T &h)
static void eval(std::array< T, 2 > &s, const std::array< T, 1 > &k)
Default Threefry constants.
static T eval(T a, T b, T &h)
Definition: mcmc.hpp:40
static unsigned long long eval(unsigned long long a, unsigned long long b, unsigned long long &h)
#define MCKL_POP_GCC_WARNING
Definition: compiler.h:79