// vim:fileencoding=utf-8:foldmethod=marker #include "xorshift.h" #include "../../common/aliases/aliases.h" #include "../../common/assert/assert.h" #include "../../common/platform/platform.h" #include #include typedef struct SplitMix64State SplitMix64State; struct SplitMix64State { u64 seed; }; wp_intern u64 rol64(u64 x, u64 bits); wp_intern u64 split_mix_64(SplitMix64State *state); wp_intern void seed_os_generator(void); wp_intern u64 generate_random_number(void); WpXor256State wpPrngXorshiftInit(void) { wp_persist b8 seeded = false; if (!seeded) { seeded = true; seed_os_generator(); } SplitMix64State sm64 = {.seed = generate_random_number()}; return (WpXor256State){ .x = split_mix_64(&sm64), .y = split_mix_64(&sm64), .z = split_mix_64(&sm64), .w = split_mix_64(&sm64), }; } u64 wpPrngXorshift256(WpXor256State *state) { u64 t = state->x ^ (state->x << 11); state->x = state->y; state->y = state->z; state->z = state->w; state->w = (state->w ^ (state->w >> 19)) ^ (t ^ (t >> 8)); return state->w; } u64 wpPrngXorshift256ss(WpXor256State *state) { const u64 result = rol64(state->z * 5, 7) * 9; const u64 t = state->z << 17; state->y ^= state->w; state->x ^= state->z; state->z ^= state->y; state->w ^= state->x; state->y ^= t; state->x = rol64(state->x, 45); return result; } u64 wpPrngXorshift256p(WpXor256State *state) { const u64 result = state->w + state->x; const u64 t = state->z << 17; state->y ^= state->w; state->x ^= state->z; state->z ^= state->y; state->w ^= state->x; state->y ^= t; state->x = rol64(state->x, 45); return result; } wp_intern u64 rol64(u64 x, u64 bits) { return (x << bits) | (x >> (64 - bits)); } wp_intern u64 split_mix_64(SplitMix64State *state) { state->seed += 0x9E3779B97f4A7C15; u64 result = state->seed; result = (result ^ (result >> 30)) * 0xBF58476D1CE4E5B9; result = (result ^ (result >> 27)) * 0x94D049BB133111EB; return result ^ (result >> 31); } #if defined(WP_PLATFORM_C) && WP_PLATFORM_C_VERSION >= WP_PLATFORM_C11_VERSION #ifdef WP_PLATFORM_POSIX wp_intern void seed_os_generator(void) { struct timespec ts = {0}; int result = clock_gettime(CLOCK_MONOTONIC_RAW, &ts); wpRuntimeAssert(result == 0, "Invalid seed value"); srand48(ts.tv_nsec); } wp_intern u64 generate_random_number(void) { return lrand48(); } #else wp_intern void seed_os_generator(void) { struct timespec ts = {0}; int result = timespec_get(&ts, TIME_UTC); wpRuntimeAssert(result != 0, "Invalid seed value"); srand(ts.tv_nsec); } wp_intern u64 generate_random_number(void) { i32 n1 = rand(); i32 n2 = rand(); return (((u64)n1) << 32 | (u64)n2); } #endif // !WP_PLATFORM_POSIX #else wp_intern void seed_os_generator(void) { time_t result = time(NULL); wpRuntimeAssert(result != (time_t)(-1), "Invalid seed value"); srand(result); } wp_intern u64 generate_random_number(void) { i32 n1 = rand(); i32 n2 = rand(); return (((u64)n1) << 32 | (u64)n2); } #endif // !WP_PLATFORM_C