19static _Thread_local
struct lmmc_rng_t lmmc_default_rng;
20static _Thread_local
int lmmc_default_rng_initialized = 0;
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);
37static uint64_t generate_default_seed(
void) {
38 static _Atomic uint64_t seed_counter = 0;
40 uint64_t t = (uint64_t)time(NULL);
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);
47 uint64_t mixed = t ^ addr ^ counter;
48 return splitmix64_next(&mixed);
51 if (!lmmc_default_rng_initialized) {
53 lmmc_default_rng_initialized = 1;
55 return &lmmc_default_rng;
59 memset(&lmmc_default_rng, 0,
sizeof(lmmc_default_rng));
60 lmmc_default_rng_initialized = 0;
65static uint64_t rng_bounded_u64(uint64_t*
state, uint64_t bound) {
66 const uint64_t threshold = (uint64_t)(-bound) % bound;
69 value = xoshiro256ss_next(
state);
70 }
while (value < threshold);
79 if (out_rng == NULL) {
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);
123 if (src == NULL || out_rng == NULL) {
144static const uint64_t JUMP_POLY[4] = {
145 UINT64_C(0x180ec6d33cfd0aba),
146 UINT64_C(0xd5a61266f0c9392c),
147 UINT64_C(0xa9582618e03fc9aa),
148 UINT64_C(0x39abdc4529b1661c)
156static const uint64_t LONG_JUMP_POLY[4] = {
157 UINT64_C(0x76e15d3efefdcbbf),
158 UINT64_C(0xc5004e441c522fb3),
159 UINT64_C(0x77710069854ee241),
160 UINT64_C(0x39109bb02acbe635)
167static void rng_apply_jump_poly(uint64_t* s,
const uint64_t* poly) {
168 uint64_t s0 = 0, s1 = 0, s2 = 0, s3 = 0;
171 for (i = 0; i < 4; i++) {
172 for (b = 0; b < 64; b++) {
173 if (poly[i] & (UINT64_C(1) << b)) {
179 xoshiro256ss_next(s);
195 rng_apply_jump_poly(rng->
state, JUMP_POLY);
205 rng_apply_jump_poly(rng->
state, LONG_JUMP_POLY);
214 return xoshiro256ss_next(rng->
state);
228 if (rng == NULL || out_value == NULL) {
231 if (!isfinite(a) || !isfinite(b) || a >= b) {
235 u = u64_to_double01(xoshiro256ss_next(rng->
state));
236 *out_value = fma(b, u, a * (1.0 - u));
247 if (rng == NULL || out_value == NULL) {
250 if (!isfinite(rate) || rate <= 0.0) {
255 u = u64_to_double01(xoshiro256ss_next(rng->
state));
258 *out_value = -log(1.0 - u) / rate;
273 if (rng == NULL || array == NULL) {
276 if (!isfinite(a) || !isfinite(b) || a >= b) {
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));
298 if (rng == NULL || array == NULL) {
301 if (elem_size == 0) {
309 arr = (
unsigned char*)array;
315 for (i = count - 1; i > 0; i--) {
316 j = (size_t)rng_bounded_u64(rng->
state, (uint64_t)i + UINT64_C(1));
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);
335 uint64_t span, offset, bits;
337 if (rng == NULL || out == NULL) {
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;
355 *out = INT64_MIN + (int64_t)(bits - (UINT64_C(1) << 63));
LMMC binary real type and arithmetic spelling.
double lmmc_real_t
Public and internal LMMC real type.
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)
重新设定种子。
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT