Belle II Software development
RandomGenerator.h
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#pragma once
10
11#include <stdint.h>
12#include <TRandom.h>
13#include <vector>
14
15namespace Belle2 {
37 class RandomGenerator: public TRandom {
38 public:
48 };
49
51 explicit RandomGenerator(const std::string& name = "Belle2 Random Generator");
52
54 virtual ~RandomGenerator() {}
55
65 void setSeed(const unsigned char* seed, unsigned int n);
66
68 void setMode(EGeneratorMode mode) { m_mode = mode; }
69
71 EGeneratorMode getMode() const { return m_mode; }
72
74 const std::vector<unsigned char>& getSeed() const { return m_seed; }
75
80 void initialize() { setState(0); }
81
86 void barrier() { setState(m_barrier + 1); }
87
89 void setBarrier(int barrierIndex) { setState(barrierIndex); }
90
92 int getBarrier() const { return m_barrier; }
93
98 uint64_t random64();
99
104 uint32_t random32() { return random64() >> 32; }
105
109 double random01();
110
112 Double_t Rndm() { return random01(); }
114 Double_t Rndm(Int_t) { return Rndm(); }
119 void RndmArray(Int_t n, Float_t* array);
124 void RndmArray(Int_t n, Double_t* array);
130 void RndmArray(Int_t n, ULong64_t* array);
131
137 void RndmArray(Int_t n, UInt_t* array);
138
144 void RndmArray(Int_t n, Int_t* array) { RndmArray(n, (UInt_t*) array); }
145
151 void RndmArray(Int_t n, Long64_t* array) { RndmArray(n, (ULong64_t*) array); }
152
157 void RndmArray(Int_t n, unsigned char* array);
158 private:
161 void SetSeed(UInt_t) {}
163 void SetSeed(ULong_t) {}
164
179 void setState(int barrier);
180
182 uint64_t m_state[16];
184 unsigned int m_index;
190 std::vector<unsigned char> m_seed;
198 };
199
201 {
202 //Generate random number using magic, taken from [arXiv:1402.6246] and only
203 //changed to conform to naming scheme
204 uint64_t s0 = m_state[ m_index ];
205 uint64_t s1 = m_state[ m_index = (m_index + 1) & 15 ];
206 s1 ^= s1 << 31;
207 s1 ^= s1 >> 11;
208 s0 ^= s0 >> 30;
209 return (m_state[ m_index ] = s0 ^ s1) * 1181783497276652981LL;
210 }
211
212 inline void RandomGenerator::RndmArray(Int_t n, Float_t* array)
213 {
214 //We could optimize this more thoroughly since one 64bit random int is
215 //enough to generate two floats but this would probably be rather academic
216 for (int i = 0; i < n; ++i) array[i] = random01();
217 }
218
219 inline void RandomGenerator::RndmArray(Int_t n, Double_t* array)
220 {
221 //Fill the array, no optimization whatsoever necessary
222 for (int i = 0; i < n; ++i) array[i] = random01();
223 }
224
225 inline void RandomGenerator::RndmArray(Int_t n, ULong64_t* array)
226 {
227 //Fill the array, no optimization whatsoever necessary
228 for (int i = 0; i < n; ++i) array[i] = random64();
229 }
230
231 inline void RandomGenerator::RndmArray(Int_t n, UInt_t* array)
232 {
233 //Fill the most part of the array using 64bit numbers
234 RndmArray(n / 2, (ULong64_t*)array);
235 //Only for uneven number of elements we need to fill the last one using a
236 //32bit number
237 if (n % 2) array[n - 1] = random32();
238 }
239
241 {
242 // There are two possibilities to generate a uniform double between 0 and
243 // 1: multiply the integer by a constant or exploit the double
244 // representation and use some bit shift magic. We have both implementation
245 // here and they seem to produce the exact same output so we stick with the
246 // more readable one but leave the bitshift solution just in case
247#ifdef RANDOM_IEEE754
248 //Generate a double in (0,1) using magic bit hackery with doubles: The
249 //memory layout of a IEEE754 double precision floating point variable
250 //is [sign(1)|exponent(11)|fraction(52)] with values in parentheses
251 //being the number of bits. The actual value is then
252 //-1^{sign} * (1.fraction) * 2^{exponent-1023}. Setting sign to 0 the
253 //exponent to 1023 will thus return a value between 1 (inclusive) and 2
254 //(exclusive). So we shift the 64bit integer to the right by 12 bits
255 //(which gives as zeros for sign and exponent) and logical or this with
256 //the correct binary representation of the exponent
257
258 //To do this we use a union to modify the binary representation using
259 //an integer and then return the double value
260 union { uint64_t i; double d; } x;
261 x.i = random64() >> 12;
262 //This is a bit academic but we want (0,1) so if we happen to get
263 //exactly zero we try again. Chance is 1 in 2^52
264 if (x.i == 0) return random01();
265 x.i |= 0x3FF0000000000000ULL;
266 return x.d - 1.0;
267#else
268 //Generate a double (0,1) the traditional way by multiplying it with a
269 //constant. As doubles only have a precision of 52 bits we need to
270 //remove the 12 leading bits from our random int value
271 const uint64_t x = random64() >> 12;
272 //This is a bit academic but we want (0,1) so if we happen to get
273 //exactly zero we try again. Chance is 1 in 2^52
274 if (!x) return random01();
275 //return x / 2^{52};
276 return x * 2.220446049250313080847263336181640625e-16;
277#endif
278 }
280}
Fast Random number Generator using on xorshift1024* [arXiv:1402.6246].
void RndmArray(Int_t n, Long64_t *array)
Fill an array of 64bit integers with random values in [INT64_MIN, INT64_MAX], both limits included.
void setState(int barrier)
Set the state of the random number generator.
void setBarrier(int barrierIndex)
manually set the barrier index to a fixed value
const std::vector< unsigned char > & getSeed() const
return the seed object
EGeneratorMode
Generator mode: determines which information is used to generate the internal state.
@ c_runDependent
Use experiment and run number to generate state.
@ c_eventDependent
Use experiment, run and event number to generate state.
@ c_independent
Don't use event info to generate state.
uint64_t m_state[16]
Internal state of the random number generator.
Double_t Rndm(Int_t)
Generate a random value in (0,1), both limits excluded (backward compatibility with root < 6....
void initialize()
set the State from event meta information like experiment, run, and event number.
ClassDef(RandomGenerator, 2)
and the root dictionary macro needs to be documented as well :) Version 2: merge m_eventDependent and...
int getBarrier() const
obtain the currently active barrier id
Double_t Rndm()
Generate a random value in (0,1), both limits excluded.
void RndmArray(Int_t n, Int_t *array)
Fill an array of 32bit integers with random values in [INT32_MIN, INT32_MAX], both limits included.
unsigned int m_index
currently active index in the internal state
int m_barrier
current barrier index.
EGeneratorMode m_mode
Current generator mode.
EGeneratorMode getMode() const
Get the generator mode.
void setSeed(const unsigned char *seed, unsigned int n)
Set the seed information.
std::vector< unsigned char > m_seed
seed information
void setMode(EGeneratorMode mode)
Set the generator mode.
void SetSeed(UInt_t)
override base class SetSeed to do nothing, we don't need it but it gets called by parent constructor
uint32_t random32()
Generate one 32bit unsigned integer between 0 and UINT32_MAX (both inclusive)
virtual ~RandomGenerator()
Destructor to free the seed information.
void SetSeed(ULong_t)
argument type was changed in root 6.08.
void barrier()
increase the barrier index.
double random01()
Generate a random double value between 0 and 1, both limits excluded.
uint64_t random64()
Generate one 64bit unsigned integer between 0 and UINT64_MAX (both inclusive).
void RndmArray(Int_t n, Float_t *array)
Fill an array of floats with random values in (0,1), both limits excluded.
Abstract base class for different kinds of events.