/src/duckdb/src/common/random_engine.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "duckdb/common/random_engine.hpp" |
2 | | #include "duckdb/common/numeric_utils.hpp" |
3 | | #include "pcg_random.hpp" |
4 | | |
5 | | #ifdef __linux__ |
6 | | #include <sys/syscall.h> |
7 | | #include <unistd.h> |
8 | | #else |
9 | | #include <random> |
10 | | #endif |
11 | | namespace duckdb { |
12 | | |
13 | | struct RandomState { |
14 | 25.1k | RandomState() { |
15 | 25.1k | } |
16 | | |
17 | | pcg32 pcg; |
18 | | }; |
19 | | |
20 | 25.1k | RandomEngine::RandomEngine(int64_t seed) : random_state(make_uniq<RandomState>()) { |
21 | 25.1k | if (seed < 0) { |
22 | 24.3k | #ifdef __linux__ |
23 | 24.3k | idx_t random_seed = 0; |
24 | 24.3k | int result = -1; |
25 | 24.3k | #if defined(SYS_getrandom) |
26 | 24.3k | result = static_cast<int>(syscall(SYS_getrandom, &random_seed, sizeof(random_seed), 0)); |
27 | 24.3k | #endif |
28 | 24.3k | if (result == -1) { |
29 | | // Something went wrong with the syscall, we use chrono |
30 | 0 | const auto now = std::chrono::high_resolution_clock::now(); |
31 | 0 | random_seed = now.time_since_epoch().count(); |
32 | 0 | } |
33 | 24.3k | random_state->pcg.seed(random_seed); |
34 | | #else |
35 | | random_state->pcg.seed(pcg_extras::seed_seq_from<std::random_device>()); |
36 | | #endif |
37 | 24.3k | } else { |
38 | 809 | random_state->pcg.seed(NumericCast<uint64_t>(seed)); |
39 | 809 | } |
40 | 25.1k | } |
41 | | |
42 | 25.1k | RandomEngine::~RandomEngine() { |
43 | 25.1k | } |
44 | | |
45 | 0 | double RandomEngine::NextRandom(double min, double max) { |
46 | 0 | D_ASSERT(max >= min); |
47 | 0 | return min + (NextRandom() * (max - min)); |
48 | 0 | } |
49 | | |
50 | 25 | double RandomEngine::NextRandom() { |
51 | 25 | auto uint64 = NextRandomInteger64(); |
52 | 25 | return std::ldexp(uint64, -64); |
53 | 25 | } |
54 | | |
55 | 0 | double RandomEngine::NextRandom32(double min, double max) { |
56 | 0 | D_ASSERT(max >= min); |
57 | 0 | return min + (NextRandom32() * (max - min)); |
58 | 0 | } |
59 | | |
60 | 0 | double RandomEngine::NextRandom32() { |
61 | 0 | auto uint32 = NextRandomInteger(); |
62 | 0 | return std::ldexp(uint32, -32); |
63 | 0 | } |
64 | | |
65 | 208 | uint32_t RandomEngine::NextRandomInteger() { |
66 | 208 | return random_state->pcg(); |
67 | 208 | } |
68 | | |
69 | 50 | uint64_t RandomEngine::NextRandomInteger64() { |
70 | 50 | return (static_cast<uint64_t>(NextRandomInteger()) << UINT64_C(32)) | static_cast<uint64_t>(NextRandomInteger()); |
71 | 50 | } |
72 | | |
73 | 0 | uint32_t RandomEngine::NextRandomInteger(uint32_t min, uint32_t max) { |
74 | 0 | return min + static_cast<uint32_t>(NextRandom() * double(max - min)); |
75 | 0 | } |
76 | | |
77 | 0 | uint32_t RandomEngine::NextRandomInteger32(uint32_t min, uint32_t max) { |
78 | 0 | return min + static_cast<uint32_t>(NextRandom32() * double(max - min)); |
79 | 0 | } |
80 | | |
81 | 25 | void RandomEngine::SetSeed(uint64_t seed) { |
82 | 25 | random_state->pcg.seed(seed); |
83 | 25 | } |
84 | | |
85 | | } // namespace duckdb |