LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
random.c
浏览该文件的文档.
1
5#include <string.h>
6#include <math.h>
7#include <stdlib.h>
8#include <time.h>
9#include <stdatomic.h>
10#include "memory_bridge.h"
11#include "internal.h"
12#include "lmmc/config.h"
13#include "lmmc/random.h"
14#include "lmmc/status.h"
15
16
17#include "random_internal.h"
18
19static _Thread_local struct lmmc_rng_t lmmc_default_rng;
20static _Thread_local int lmmc_default_rng_initialized = 0;
21
22
23
24
25static inline uint64_t splitmix64_next(uint64_t* state) {
26 uint64_t z = (*state += UINT64_C(0x9e3779b97f4a7c15));
27 z = (z ^ (z >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
28 z = (z ^ (z >> 27)) * UINT64_C(0x94d049bb133111eb);
29 return z ^ (z >> 31);
30}
31
32
37static uint64_t generate_default_seed(void) {
38 static _Atomic uint64_t seed_counter = 0;
39
40 uint64_t t = (uint64_t)time(NULL);
41 /* Use address of a local variable for ASLR entropy */
42 volatile int stack_var = 0;
43 uint64_t addr = (uint64_t)(uintptr_t)&stack_var;
44 uint64_t counter = atomic_fetch_add(&seed_counter, 1);
45
46 /* Mix all sources via SplitMix64 finalizer */
47 uint64_t mixed = t ^ addr ^ counter;
48 return splitmix64_next(&mixed);
49}
51 if (!lmmc_default_rng_initialized) {
52 lmmc_rng_seed(&lmmc_default_rng, generate_default_seed());
53 lmmc_default_rng_initialized = 1;
54 }
55 return &lmmc_default_rng;
56}
57
59 memset(&lmmc_default_rng, 0, sizeof(lmmc_default_rng));
60 lmmc_default_rng_initialized = 0;
61}
62
63
64
65static uint64_t rng_bounded_u64(uint64_t* state, uint64_t bound) {
66 const uint64_t threshold = (uint64_t)(-bound) % bound;
67 uint64_t value;
68 do {
69 value = xoshiro256ss_next(state);
70 } while (value < threshold);
71 return value % bound;
72}
73
74
75
77 lmmc_rng_t* rng;
78
79 if (out_rng == NULL) {
81 }
82
84 if (rng == NULL) {
85 *out_rng = NULL;
87 }
88
90 lmmc_rng_seed(rng, generate_default_seed());
91
92 *out_rng = rng;
93 return LMMC_STATUS_OK;
94}
95
97 uint64_t sm_state;
98
99 if (rng == NULL) {
101 }
102
103 sm_state = seed;
104 rng->state[0] = splitmix64_next(&sm_state);
105 rng->state[1] = splitmix64_next(&sm_state);
106 rng->state[2] = splitmix64_next(&sm_state);
107 rng->state[3] = splitmix64_next(&sm_state);
108
109 return LMMC_STATUS_OK;
110}
111
113 if (rng != NULL) {
114 memset(rng->state, 0, sizeof(rng->state));
115 lmmc_memory_free(rng);
116 }
117}
118
119
121 lmmc_rng_t* copy;
122
123 if (src == NULL || out_rng == NULL) {
125 }
126
127 copy = (lmmc_rng_t*)lmmc_memory_alloc(sizeof(lmmc_rng_t));
128 if (copy == NULL) {
129 *out_rng = NULL;
131 }
132
133 memcpy(copy->state, src->state, sizeof(src->state));
134 *out_rng = copy;
135 return LMMC_STATUS_OK;
136}
137
138
139/*
140 * xoshiro256** jump polynomial constants.
141 * Advances the state by 2^128 steps.
142 * Reference: https://prng.di.unimi.it/xoshiro256starstar.c
143 */
144static const uint64_t JUMP_POLY[4] = {
145 UINT64_C(0x180ec6d33cfd0aba),
146 UINT64_C(0xd5a61266f0c9392c),
147 UINT64_C(0xa9582618e03fc9aa),
148 UINT64_C(0x39abdc4529b1661c)
149};
150
151/*
152 * xoshiro256** long_jump polynomial constants.
153 * Advances the state by 2^192 steps.
154 * Reference: https://prng.di.unimi.it/xoshiro256starstar.c
155 */
156static const uint64_t LONG_JUMP_POLY[4] = {
157 UINT64_C(0x76e15d3efefdcbbf),
158 UINT64_C(0xc5004e441c522fb3),
159 UINT64_C(0x77710069854ee241),
160 UINT64_C(0x39109bb02acbe635)
161};
162
163
167static void rng_apply_jump_poly(uint64_t* s, const uint64_t* poly) {
168 uint64_t s0 = 0, s1 = 0, s2 = 0, s3 = 0;
169 int i, b;
170
171 for (i = 0; i < 4; i++) {
172 for (b = 0; b < 64; b++) {
173 if (poly[i] & (UINT64_C(1) << b)) {
174 s0 ^= s[0];
175 s1 ^= s[1];
176 s2 ^= s[2];
177 s3 ^= s[3];
178 }
179 xoshiro256ss_next(s);
180 }
181 }
182
183 s[0] = s0;
184 s[1] = s1;
185 s[2] = s2;
186 s[3] = s3;
187}
188
189
191 if (rng == NULL) {
193 }
194
195 rng_apply_jump_poly(rng->state, JUMP_POLY);
196 return LMMC_STATUS_OK;
197}
198
199
201 if (rng == NULL) {
203 }
204
205 rng_apply_jump_poly(rng->state, LONG_JUMP_POLY);
206 return LMMC_STATUS_OK;
207}
208
209
211 if (rng == NULL) {
212 return 0;
213 }
214 return xoshiro256ss_next(rng->state);
215}
216
217
218
219
221 lmmc_rng_t* rng,
222 lmmc_real_t a,
223 lmmc_real_t b,
224 lmmc_real_t* out_value)
225{
226 double u;
227
228 if (rng == NULL || out_value == NULL) {
230 }
231 if (!isfinite(a) || !isfinite(b) || a >= b) {
233 }
234
235 u = u64_to_double01(xoshiro256ss_next(rng->state));
236 *out_value = fma(b, u, a * (1.0 - u));
237 return LMMC_STATUS_OK;
238}
239
241 lmmc_rng_t* rng,
242 lmmc_real_t rate,
243 lmmc_real_t* out_value)
244{
245 double u;
246
247 if (rng == NULL || out_value == NULL) {
249 }
250 if (!isfinite(rate) || rate <= 0.0) {
252 }
253
254 do {
255 u = u64_to_double01(xoshiro256ss_next(rng->state));
256 } while (u == 1.0);
257
258 *out_value = -log(1.0 - u) / rate;
259 return LMMC_STATUS_OK;
260}
261
262
264 lmmc_rng_t* rng,
265 lmmc_real_t a,
266 lmmc_real_t b,
267 lmmc_real_t* array,
268 size_t count)
269{
270 size_t i;
271 double u;
272
273 if (rng == NULL || array == NULL) {
275 }
276 if (!isfinite(a) || !isfinite(b) || a >= b) {
278 }
279
280 for (i = 0; i < count; i++) {
281 u = u64_to_double01(xoshiro256ss_next(rng->state));
282 array[i] = fma(b, u, a * (1.0 - u));
283 }
284
285 return LMMC_STATUS_OK;
286}
287
289 lmmc_rng_t* rng,
290 void* array,
291 size_t count,
292 size_t elem_size)
293{
294 size_t i, j;
295 unsigned char* arr;
296 unsigned char* tmp;
297
298 if (rng == NULL || array == NULL) {
300 }
301 if (elem_size == 0) {
303 }
304
305 if (count <= 1) {
306 return LMMC_STATUS_OK;
307 }
308
309 arr = (unsigned char*)array;
310 tmp = (unsigned char*)lmmc_memory_alloc(elem_size);
311 if (tmp == NULL) {
313 }
314
315 for (i = count - 1; i > 0; i--) {
316 j = (size_t)rng_bounded_u64(rng->state, (uint64_t)i + UINT64_C(1));
317
318 if (i != j) {
319 memcpy(tmp, arr + i * elem_size, elem_size);
320 memcpy(arr + i * elem_size, arr + j * elem_size, elem_size);
321 memcpy(arr + j * elem_size, tmp, elem_size);
322 }
323 }
324
325 lmmc_memory_free(tmp);
326 return LMMC_STATUS_OK;
327}
328
330 lmmc_rng_t* rng,
331 int64_t lo,
332 int64_t hi,
333 int64_t* out)
334{
335 uint64_t span, offset, bits;
336
337 if (rng == NULL || out == NULL) {
339 }
340 if (lo > hi) {
342 }
343 if (lo == hi) {
344 *out = lo;
345 return LMMC_STATUS_OK;
346 }
347
348 span = (uint64_t)hi - (uint64_t)lo + UINT64_C(1);
349 offset = span == 0 ? xoshiro256ss_next(rng->state)
350 : rng_bounded_u64(rng->state, span);
351 bits = (uint64_t)lo + offset;
352 if (bits <= (uint64_t)INT64_MAX) {
353 *out = (int64_t)bits;
354 } else {
355 *out = INT64_MIN + (int64_t)(bits - (UINT64_C(1) << 63));
356 }
357 return LMMC_STATUS_OK;
358}
LMMC binary real type and arithmetic spelling.
double lmmc_real_t
Public and internal LMMC real type.
LMMC 内部使用的公共工具(仅源文件可见).
void lmmc_rng_default_reset(void)
lmmc_rng_t * lmmc_rng_default_get(void)
void * lmmc_memory_alloc(size_t size)
void lmmc_memory_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
伪随机数发生器与常用分布。
lmmc_status_t lmmc_rng_long_jump(lmmc_rng_t *rng)
将 RNG 状态前进 2^192 步(xoshiro256** long_jump 多项式)。
lmmc_status_t lmmc_rng_jump(lmmc_rng_t *rng)
将 RNG 状态前进 2^128 步(xoshiro256** jump 多项式)。
lmmc_status_t lmmc_rng_clone(const lmmc_rng_t *src, lmmc_rng_t **out_rng)
深拷贝 RNG 状态。
lmmc_status_t lmmc_rng_exponential(lmmc_rng_t *rng, lmmc_real_t rate, lmmc_real_t *out_value)
生成参数为 rate 的指数分布样本。
lmmc_status_t lmmc_rng_int_uniform(lmmc_rng_t *rng, int64_t lo, int64_t hi, int64_t *out)
在 [lo, hi] 闭区间内生成无偏均匀整数分布样本。
lmmc_status_t lmmc_rng_create(lmmc_rng_t **out_rng)
创建随机数发生器实例。
lmmc_status_t lmmc_rng_uniform(lmmc_rng_t *rng, lmmc_real_t a, lmmc_real_t b, lmmc_real_t *out_value)
实数分布参数的公共约束。
lmmc_status_t lmmc_rng_shuffle(lmmc_rng_t *rng, void *array, size_t count, size_t elem_size)
Fisher-Yates 洗牌:就地随机重排 array 中的 count 个元素。 每次 Fisher-Yates 选择均使用无偏的拒绝采样。
lmmc_status_t lmmc_rng_fill_uniform(lmmc_rng_t *rng, lmmc_real_t a, lmmc_real_t b, lmmc_real_t *array, size_t count)
批量填充均匀分布样本到 array 。
uint64_t lmmc_rng_next_u64(lmmc_rng_t *rng)
直接获取下一个 64 位均匀整数。
void lmmc_rng_destroy(lmmc_rng_t *rng)
销毁发生器,释放内部分配的所有内存。
lmmc_status_t lmmc_rng_seed(lmmc_rng_t *rng, uint64_t seed)
重新设定种子。
uint64_t state[4]
随机数发生器(不透明类型)。
LMMC 通用状态码定义.
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT