forked from SevenChords/CipesAtHome
-
Notifications
You must be signed in to change notification settings - Fork 0
/
thread_local_random.c
137 lines (106 loc) · 3.86 KB
/
thread_local_random.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
* thread_local_random.c
*
* Created on: Jun 26, 2021
* Author: TechSY730
*/
#include "thread_local_random.h"
#include "base.h"
#include "openmp_once.h"
openmp_once_t _listed_rng_selection_state = OPENMP_ONCE_INIT;
bool _local_listed_rng_selection_state = false;
#pragma omp threadprivate(_local_listed_rng_selection_state)
void _printRNGImplementation();
#if _USING_SYSTEM_RAND && _HAS_RANDR
unsigned int _threadlocal_seed;
#pragma omp threadprivate(_threadlocal_seed)
#endif
#if !_NEED_EXTERN_DEF
ABSL_ATTRIBUTE_UNUSED
extern inline void threadlocal_rand_init();
ABSL_ATTRIBUTE_UNUSED
extern inline void threadlocal_srand(random_seed_t seed);
ABSL_ATTRIBUTE_UNUSED
extern inline u_random_output_t threadlocal_rand();
ABSL_ATTRIBUTE_UNUSED
extern inline random_output_t threadlocal_randint(random_output_t low, random_output_t high);
ABSL_ATTRIBUTE_UNUSED
extern inline void threadlocal_rand_destroy();
#else
#if _USE_lehmer_RANDOM
#include "internal/random_headers/lehmer64_cipes.h"
void threadlocal_srand(random_seed_t seed) {
lehmer64_seed(seed);
}
ABSL_ATTRIBUTE_HOT
random_output_t threadlocal_rand() {
return lehmer64();
}
#elif _USE_wyhash_RANDOM
#include "internal/random_headers/wyrand_cipes.h"
#include "splitmix64.h"
void threadlocal_srand(random_seed_t seed) {
wyrand_seed(splitmix64_stateless(seed));
}
ABSL_ATTRIBUTE_HOT
random_output_t threadlocal_rand() {
return wyrand();
}
#elif _USE_pcg_RANDOM
#include "pcg-c-basic/pcg_basic.h"
#include "splitmix64.h"
#include "rotate.h"
static pcg32_random_t _threadlocal_rng_state;
#pragma omp threadprivate(_threadlocal_rng_state)
void threadlocal_srand(random_seed_t seed) {
#if _CIPES_SUPPORTS_INT128 && !_RNG_ALWAYS_USE_32_BIT_CHOICE
// We need to somehow get 128 bits of scrambled-ness from a source likely far less bit randomness then this.
// A reasonable-ish approach is to rotate quarter of the way through, splitmix64 each half,
// combine back together, rotate back but now with scrambled parity, and splitmix64 scramble each half again.
__uint128 current = cipes_rotl_u128(seed, 64+32);
uint64_t first_half = current & UINT64_MAX;
first_half = splitmix64_stateless(first_half);
uint64_t second_half = (current >> 64) & (UINT64_MAX);
second_half = splitmix64_stateless(second_half);
current = first_half | ((__uint128)second_half) << 64;
current = cipes_rotr_u128(current, 64+23);
first_half = current & UINT64_MAX;
first_half = splitmix64_stateless(first_half);
second_half = (current >> 64) & (UINT64_MAX);
second_half = splitmix64_stateless(second_half);
pcg32_srandom_r(&_threadlocal_rng_state, first_half, second_half);
#else
// With a lack of better options being given a 64 bit seed for 128 bit total seeds initialization, we will just scramble the seed for the first half.
pcg32_srandom_r(&_threadlocal_rng_state, splitmix64_stateless(seed), seed);
#endif
}
ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_ATTRIBUTE_HOT
inline u_random_output_t threadlocal_rand() {
return pcg32_random_r(&_threadlocal_rng_state);
}
// pcg32 does have a random range function, but it is using trial randomness (roll until one in range), which is ludicrously inefficient for small ranges.
// So use the default
#else
#ifdef _RANDOM_IMPL_STR
_COMPILER_ERROR(Unrecognized _STR(_RANDOM_IMPL_STR) (the RNG implementation) selected. Value: _XSTR(_RANDOM_IMPL_STR)\n See RNG_OPTIONS.md)
#else
#error Unrecognized random implementation selection. See RNG_OPTIONS.md
#endif
#endif
#ifndef _CUSTOM_RANDINIT
ABSL_ATTRIBUTE_ALWAYS_INLINE
inline void threadlocal_rand_init() {
_printRNGImplementation();
}
#endif
#ifndef _CUSTOM_RANDINT
ABSL_ATTRIBUTE_HOT
random_output_t threadlocal_randint(random_output_t low, random_output_t high) {
return _internal_scale_to_bounds(threadlocal_rand(), low, high);
}
#endif
#ifndef _CUSTOM_RANDDESTROY
ABSL_ATTRIBUTE_ALWAYS_INLINE
inline void threadlocal_rand_destroy() {}
#endif
#endif // _USE_LEHMER64_RANDOM