Belle II Software light-2607-kasei
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, reinterpret_cast<UInt_t*>(array)); }
145
151 void RndmArray(Int_t n, Long64_t* array) { RndmArray(n, reinterpret_cast<ULong64_t*>(array)); }
152
157 void RndmArray(Int_t n, unsigned char* array);
158 private:
162 // cppcheck-suppress functionStatic
163 void SetSeed(UInt_t) {}
165 void SetSeed(ULong_t) override {}
166
181 void setState(int barrier);
182
184 uint64_t m_state[16];
186 unsigned int m_index;
192 std::vector<unsigned char> m_seed;
199#if defined(__clang__)
200#pragma clang diagnostic push
201#pragma clang diagnostic ignored "-Winconsistent-missing-override"
202#endif
204#if defined(__clang__)
205#pragma clang diagnostic pop
206#endif
207 };
208
210 {
211 //Generate random number using magic, taken from [arXiv:1402.6246] and only
212 //changed to conform to naming scheme
213 uint64_t s0 = m_state[ m_index ];
214 uint64_t s1 = m_state[ m_index = (m_index + 1) & 15 ];
215 s1 ^= s1 << 31;
216 s1 ^= s1 >> 11;
217 s0 ^= s0 >> 30;
218 return (m_state[ m_index ] = s0 ^ s1) * 1181783497276652981LL;
219 }
220
221 inline void RandomGenerator::RndmArray(Int_t n, Float_t* array)
222 {
223 //We could optimize this more thoroughly since one 64bit random int is
224 //enough to generate two floats but this would probably be rather academic
225 for (int i = 0; i < n; ++i) array[i] = random01();
226 }
227
228 inline void RandomGenerator::RndmArray(Int_t n, Double_t* array)
229 {
230 //Fill the array, no optimization whatsoever necessary
231 for (int i = 0; i < n; ++i) array[i] = random01();
232 }
233
234 inline void RandomGenerator::RndmArray(Int_t n, ULong64_t* array)
235 {
236 //Fill the array, no optimization whatsoever necessary
237 for (int i = 0; i < n; ++i) array[i] = random64();
238 }
239
240 inline void RandomGenerator::RndmArray(Int_t n, UInt_t* array)
241 {
242 //Fill the most part of the array using 64bit numbers
243 RndmArray(n / 2, reinterpret_cast<ULong64_t*>(array));
244 //Only for uneven number of elements we need to fill the last one using a
245 //32bit number
246 if (n % 2) array[n - 1] = random32();
247 }
248
250 {
251 // There are two possibilities to generate a uniform double between 0 and
252 // 1: multiply the integer by a constant or exploit the double
253 // representation and use some bit shift magic. We have both implementation
254 // here and they seem to produce the exact same output so we stick with the
255 // more readable one but leave the bitshift solution just in case
256#ifdef RANDOM_IEEE754
257 //Generate a double in (0,1) using magic bit hackery with doubles: The
258 //memory layout of a IEEE754 double precision floating point variable
259 //is [sign(1)|exponent(11)|fraction(52)] with values in parentheses
260 //being the number of bits. The actual value is then
261 //-1^{sign} * (1.fraction) * 2^{exponent-1023}. Setting sign to 0 the
262 //exponent to 1023 will thus return a value between 1 (inclusive) and 2
263 //(exclusive). So we shift the 64bit integer to the right by 12 bits
264 //(which gives as zeros for sign and exponent) and logical or this with
265 //the correct binary representation of the exponent
266
267 //To do this we use a union to modify the binary representation using
268 //an integer and then return the double value
269 union { uint64_t i; double d; } x;
270 x.i = random64() >> 12;
271 //This is a bit academic but we want (0,1) so if we happen to get
272 //exactly zero we try again. Chance is 1 in 2^52
273 if (x.i == 0) return random01();
274 x.i |= 0x3FF0000000000000ULL;
275 return x.d - 1.0;
276#else
277 //Generate a double (0,1) the traditional way by multiplying it with a
278 //constant. As doubles only have a precision of 52 bits we need to
279 //remove the 12 leading bits from our random int value
280 const uint64_t x = random64() >> 12;
281 //This is a bit academic but we want (0,1) so if we happen to get
282 //exactly zero we try again. Chance is 1 in 2^52
283 if (!x) return random01();
284 //return x / 2^{52};
285 return x * 2.220446049250313080847263336181640625e-16;
286#endif
287 }
288
289}
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.
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(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.
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.