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:
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() override { return random01(); }
114 Double_t Rndm(Int_t) override { return Rndm(); }
119 void RndmArray(Int_t n, Float_t* array) override;
124 void RndmArray(Int_t n, Double_t* array) override;
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) override {}
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 }
279
280}
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.
void initialize()
set the State from event meta information like experiment, run, and event number.
int getBarrier() const
obtain the currently active barrier id
Double_t Rndm(Int_t) override
Generate a random value in (0,1), both limits excluded (backward compatibility with root < 6....
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.
void SetSeed(ULong_t) override
argument type was changed in root 6.08.
unsigned int m_index
currently active index in the internal state
int m_barrier
current barrier index.
EGeneratorMode m_mode
Current generator mode.
Double_t Rndm() override
Generate a random value in (0,1), both limits excluded.
EGeneratorMode getMode() const
Get the generator mode.
void setSeed(const unsigned char *seed, unsigned int n)
Set the seed information.
ClassDefOverride(RandomGenerator, 2)
and the root dictionary macro needs to be documented as well :) Version 2: merge m_eventDependent and...
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)
RandomGenerator(const std::string &name="Belle2 Random Generator")
Default constructor, does not initialize the generator.
virtual ~RandomGenerator()
Destructor to free the seed information.
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) override
Fill an array of floats with random values in (0,1), both limits excluded.
Abstract base class for different kinds of events.