Line |
Branch |
Exec |
Source |
1 |
|
|
/** |
2 |
|
|
* This file is part of the CernVM File System. |
3 |
|
|
* |
4 |
|
|
* A simple linear congruential pseudo number generator. Thread-safe since |
5 |
|
|
* there is no global state like with random(). |
6 |
|
|
*/ |
7 |
|
|
|
8 |
|
|
#ifndef CVMFS_UTIL_PRNG_H_ |
9 |
|
|
#define CVMFS_UTIL_PRNG_H_ |
10 |
|
|
|
11 |
|
|
#include <stdint.h> |
12 |
|
|
#include <sys/time.h> |
13 |
|
|
|
14 |
|
|
#include <limits> // NOLINT |
15 |
|
|
|
16 |
|
|
#include <cassert> |
17 |
|
|
#include <cmath> |
18 |
|
|
#include <cstdlib> |
19 |
|
|
|
20 |
|
|
|
21 |
|
|
#ifdef CVMFS_NAMESPACE_GUARD |
22 |
|
|
namespace CVMFS_NAMESPACE_GUARD { |
23 |
|
|
#endif |
24 |
|
|
|
25 |
|
|
/** |
26 |
|
|
* Pseudo Random Number Generator. See: TAoCP, volume 2 |
27 |
|
|
*/ |
28 |
|
|
class Prng { |
29 |
|
|
public: |
30 |
|
|
// Cannot throw an exception |
31 |
|
2251891 |
Prng() throw() { |
32 |
|
2251891 |
state_ = 0; |
33 |
|
2251891 |
} |
34 |
|
|
|
35 |
|
2000591 |
void InitSeed(const uint64_t seed) { |
36 |
|
2000591 |
state_ = seed; |
37 |
|
2000591 |
} |
38 |
|
|
|
39 |
|
251281 |
void InitLocaltime() { |
40 |
|
|
struct timeval tv_now; |
41 |
|
251281 |
int retval = gettimeofday(&tv_now, NULL); |
42 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 251312 times.
|
251312 |
assert(retval == 0); |
43 |
|
251312 |
state_ = tv_now.tv_usec; |
44 |
|
251312 |
} |
45 |
|
|
|
46 |
|
|
/** |
47 |
|
|
* Returns random number in [0..boundary-1] |
48 |
|
|
*/ |
49 |
|
2173986452 |
uint32_t Next(const uint64_t boundary) { |
50 |
|
2173986452 |
state_ = a*state_ + c; |
51 |
|
2173986452 |
double scaled_val = |
52 |
|
2173986452 |
static_cast<double>(state_) * static_cast<double>(boundary) / |
53 |
|
|
static_cast<double>(18446744073709551616.0); |
54 |
|
2173986452 |
return static_cast<uint32_t>(static_cast<uint64_t>(scaled_val) % boundary); |
55 |
|
|
} |
56 |
|
|
|
57 |
|
|
/** |
58 |
|
|
* Returns random double in range [0, 1] |
59 |
|
|
*/ |
60 |
|
200000 |
double NextDouble() { |
61 |
|
200000 |
state_ = a*state_ + c; |
62 |
|
200000 |
double unit_val = static_cast<double>(state_) / |
63 |
|
|
static_cast<double>(18446744073709551616.0); |
64 |
|
200000 |
return unit_val; |
65 |
|
|
} |
66 |
|
|
/** |
67 |
|
|
* Returns normally distributed random numbers |
68 |
|
|
* with mean 0 and variance 1 using the |
69 |
|
|
* Box-Muller transform algorithm |
70 |
|
|
*/ |
71 |
|
100000 |
double NextNormal() { |
72 |
|
|
double z, u1, u2; |
73 |
|
100000 |
double pi = atan(1) * 4; |
74 |
|
100000 |
u1 = NextDouble(); |
75 |
|
100000 |
u2 = NextDouble(); |
76 |
|
100000 |
z = sqrt(-2.0 * log(u1)) * cos(2 * pi * u2); |
77 |
|
100000 |
return z; |
78 |
|
|
} |
79 |
|
|
|
80 |
|
|
|
81 |
|
|
private: |
82 |
|
|
// Magic numbers from MMIX |
83 |
|
|
// static const uint64_t m = 2^64; |
84 |
|
|
static const uint64_t a = 6364136223846793005LLU; |
85 |
|
|
static const uint64_t c = 1442695040888963407LLU; |
86 |
|
|
uint64_t state_; |
87 |
|
|
}; // class Prng |
88 |
|
|
|
89 |
|
|
#ifdef CVMFS_NAMESPACE_GUARD |
90 |
|
|
} // namespace CVMFS_NAMESPACE_GUARD |
91 |
|
|
#endif |
92 |
|
|
|
93 |
|
|
#endif // CVMFS_UTIL_PRNG_H_ |
94 |
|
|
|