SUNphi  1.0
SFMT.hpp
Go to the documentation of this file.
1 #ifndef _SFMT_HPP
2 #define _SFMT_HPP
3 
4 /// \file SFMT.hpp
5 ///
6 /// \brief Implements the SIMD-oriented Fast Mersenne Twister
7 ///
8 /// http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/
9 ///
10 /// Copyright (c) 2006,2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima
11 /// University.
12 /// Copyright (c) 2012 Mutsuo Saito, Makoto Matsumoto, Hiroshima University
13 /// and The University of Tokyo.
14 /// All rights reserved.
15 ///
16 /// Redistribution and use in source and binary forms, with or without
17 /// modification, are permitted provided that the following conditions are
18 /// met:
19 ///
20 /// * Redistributions of source code must retain the above copyright
21 /// notice, this list of conditions and the following disclaimer.
22 /// * Redistributions in binary form must reproduce the above
23 /// copyright notice, this list of conditions and the following
24 /// disclaimer in the documentation and/or other materials provided
25 /// with the distribution.
26 /// * Neither the names of Hiroshima University, The University of
27 /// Tokyo nor the names of its contributors may be used to endorse
28 /// or promote products derived from this software without specific
29 /// prior written permission.
30 ///
31 /// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 /// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 /// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34 /// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 /// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36 /// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
37 /// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
38 /// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
39 /// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 /// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
41 /// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 
43 #ifdef HAVE_CONFIG_H
44  #include "config.hpp"
45 #endif
46 
47 #include <stdint.h>
48 
49 #ifdef USE_SSE2
50  #include <immintrin.h>
51 #endif
52 
53 namespace SUNphi
54 {
55  /// SIMD Fast Mersenne Twister
57  {
58  /// 128-bit data structure
59  union w128_t
60  {
61  /// Inner access
62  uint32_t u[4];
63 
64 #ifdef USE_SSE2
65  /// Packed access
66  __m128i si;
67 #endif
68  };
69 
70  /// Used to shift left or right
71  enum LEFT_RIGHT_T{LEFT,RIGHT};
72 
73  /// Emulates the SIMD implementation
74  template <LEFT_RIGHT_T LeftRight>
75  w128_t shift128(const w128_t& in,
76  const int& shift)
77  {
78  const uint64_t th=
79  ((uint64_t)in.u[3]<<32)|((uint64_t)in.u[2]);
80 
81  const uint64_t tl=
82  ((uint64_t)in.u[1]<<32)|((uint64_t)in.u[0]);
83 
84  uint64_t oh,ol;
85 
86  if constexpr(LeftRight==RIGHT)
87  {
88  oh=
89  th>>(shift*8);
90 
91  ol=
92  (tl>>(shift*8))|
93  (th<<(64-shift*8));
94  }
95  else
96  {
97  oh=
98  (th<<(shift*8))|
99  (tl>>(64-shift*8));
100 
101  ol=
102  tl<<(shift*8);
103  }
104 
105  return
106  {{(uint32_t)ol,
107  (uint32_t)(ol>>32),
108  (uint32_t)oh,
109  (uint32_t)(oh>>32)}};
110  }
111 
112  /// Exponent of the period
113  static constexpr int MEXP=
114  19937;
115 
116  /// Number of 128-bit words
117  static constexpr int N=
118  MEXP/128+1;
119 
120  /// Number of 32-bit words
121  static constexpr int N32=
122  N*4;
123 
124  /// State array
126 
127  /// Counter to the 32-bit internal state array
128  int idx;
129 
130  /// Performs the recursion
131  void recursion(w128_t& r,
132  w128_t& a,
133  w128_t& b,
134  w128_t& c,
135  w128_t& d)
136  {
137  static constexpr uint32_t SL1=
138  14;
139 
140  static constexpr uint32_t SL2=
141  1;
142 
143  static constexpr uint32_t SR1=
144  11;
145 
146  static constexpr uint32_t SR2=
147  1;
148 
149  static constexpr w128_t MSK=
150  {{0xdfffffefU,
151  0xddfecb7fU,
152  0xbffaffffU,
153  0xbffffff6U}};
154 
156 
157  const w128_t x=
158  shift128<LEFT>(a,SL2);
159  const w128_t y=
160  shift128<RIGHT>(c,SR2);
161 
162  for(int i=0;i<4;i++)
163  r.u[i]=
164  a.u[i]^x.u[i]^((b.u[i]>>SR1)&MSK.u[i])
165  ^y.u[i]^(d.u[i]<<SL1);
166 
167 #else
168 
169  r.si=
170  _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_srli_si128(c.si,
171  SR2),
172  a.si),
173  _mm_slli_epi32(d.si,
174  SL1)),
175  _mm_slli_si128(a.si,
176  SL2)),
177  _mm_and_si128(_mm_srli_epi32(b.si,
178  SR1),
179  MSK.si));
180 
181 #endif
182  }
183 
184  public:
185 
186  /// Certificate the period of 2^MEXP
188  {
189  uint32_t inner=0;
190  uint32_t *psfmt32=&state[0].u[0];
191 
192  constexpr uint32_t parity[4]=
193  {0x00000001U,
194  0x00000000U,
195  0x00000000U,
196  0x13c9e684U};
197 
198  for(int i=0;i<4;i++)
199  inner^=
200  psfmt32[i]&parity[i];
201 
202  for(int i=16;i>0;i>>=1)
203  inner^=
204  inner>>i;
205 
206  inner&=
207  1;
208 
209  /// Check
210  bool fixed=
211  inner==1;
212 
213  int i=
214  0;
215 
216  while((not fixed) and (i<4))
217  {
218  uint32_t work=
219  1;
220 
221  int j=
222  0;
223 
224  while((not fixed) and (j<32))
225  {
226  if((work&parity[i])!=0)
227  {
228  psfmt32[i]^=
229  work;
230 
231  fixed=
232  true;
233  }
234 
235  work=
236  work<<1;
237 
238  j++;
239  }
240 
241  i++;
242  }
243  }
244 
245  /// Generates a new state
247  {
248  static constexpr int POS1=
249  122;
250 
251  w128_t &r1=
252  state[N-2];
253 
254  w128_t &r2=
255  state[N-1];
256 
257  for(int i=0;i<N;i++)
258  {
259  recursion(state[i],state[i],
260  state[(i+POS1)%N],r1,r2);
261  r1=
262  r2;
263 
264  r2=
265  state[i];
266  }
267  }
268 
269  /// Gets the next random number in the stream
270  uint32_t operator()()
271  {
272  /// Proxy to he first element of the state
273  uint32_t* psfmt32=
274  &state[0].u[0];
275 
276  if(idx>=N32)
277  {
279 
280  idx=
281  0;
282  }
283 
284  return
285  psfmt32[idx++];
286  }
287 
288  /// Seed the state with a 32-bit integer seed
289  void seed(const uint32_t& seed)
290  {
291  uint32_t *psfmt32=
292  &state[0].u[0];
293 
294  psfmt32[0]=
295  seed;
296 
297  for(int i=1;i<N32;i++)
298  psfmt32[i]=
299  1812433253UL*
300  (psfmt32[i-1]^
301  (psfmt32[i-1]>>30))
302  +i;
303 
304  idx=
305  N32;
306 
308  }
309  };
310 }
311 
312 #endif
void periodCertification()
Certificate the period of 2^MEXP.
Definition: SFMT.hpp:187
w128_t shift128(const w128_t &in, const int &shift)
Emulates the SIMD implementation.
Definition: SFMT.hpp:75
#define USE_SSE2
Definition: config.hpp:107
uint32_t operator()()
Gets the next random number in the stream.
Definition: SFMT.hpp:270
int idx
Counter to the 32-bit internal state array.
Definition: SFMT.hpp:128
LEFT_RIGHT_T
Used to shift left or right.
Definition: SFMT.hpp:71
w128_t state[N]
State array.
Definition: SFMT.hpp:125
128-bit data structure
Definition: SFMT.hpp:59
static constexpr int N32
Number of 32-bit words.
Definition: SFMT.hpp:121
uint32_t u[4]
Inner access.
Definition: SFMT.hpp:62
void seed(const uint32_t &seed)
Seed the state with a 32-bit integer seed.
Definition: SFMT.hpp:289
decltype(auto) operator+(T1 &&smet1, T2 &&smet2)
Implement smet1+smet2.
Definition: Add.hpp:87
#define USE_SIMD_MERSENNE_TWISTER
Definition: config.hpp:104
void randomizeAll()
Generates a new state.
Definition: SFMT.hpp:246
void recursion(w128_t &r, w128_t &a, w128_t &b, w128_t &c, w128_t &d)
Performs the recursion.
Definition: SFMT.hpp:131