137 lines
3.1 KiB
C
137 lines
3.1 KiB
C
// 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 <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
|
|
typedef struct split_mix_64_state SplitMix64State;
|
|
struct split_mix_64_state {
|
|
u64 seed;
|
|
};
|
|
|
|
internal u64 rol64(u64 x, u64 bits);
|
|
internal u64 split_mix_64(SplitMix64State *state);
|
|
internal void seed_os_generator(void);
|
|
internal u64 generate_random_number(void);
|
|
|
|
XOR256State wapp_prng_xorshift_init_state(void) {
|
|
persistent bool seeded = false;
|
|
if (!seeded) {
|
|
seeded = true;
|
|
seed_os_generator();
|
|
}
|
|
|
|
SplitMix64State sm64 = {.seed = generate_random_number()};
|
|
|
|
return (XOR256State){
|
|
.x = split_mix_64(&sm64),
|
|
.y = split_mix_64(&sm64),
|
|
.z = split_mix_64(&sm64),
|
|
.w = split_mix_64(&sm64),
|
|
};
|
|
}
|
|
|
|
u64 wapp_prng_xorshift_256(XOR256State *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 wapp_prng_xorshift_256ss(XOR256State *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 wapp_prng_xorshift_256p(XOR256State *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;
|
|
}
|
|
|
|
internal u64 rol64(u64 x, u64 bits) {
|
|
return (x << bits) | (x >> (64 - bits));
|
|
}
|
|
|
|
internal 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(WAPP_PLATFORM_C) && WAPP_PLATFORM_C_VERSION >= WAPP_PLATFORM_C11_VERSION
|
|
#ifdef WAPP_PLATFORM_POSIX
|
|
internal void seed_os_generator(void) {
|
|
struct timespec ts = {0};
|
|
int result = clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
|
wapp_runtime_assert(result == 0, "Invalid seed value");
|
|
|
|
srand48(ts.tv_nsec);
|
|
}
|
|
|
|
internal u64 generate_random_number(void) {
|
|
return lrand48();
|
|
}
|
|
#else
|
|
internal void seed_os_generator(void) {
|
|
struct timespec ts = {0};
|
|
int result = timespec_get(&ts, TIME_UTC);
|
|
wapp_runtime_assert(result != 0, "Invalid seed value");
|
|
|
|
srand(ts.tv_nsec);
|
|
}
|
|
|
|
internal u64 generate_random_number(void) {
|
|
i32 n1 = rand();
|
|
i32 n2 = rand();
|
|
|
|
return (((u64)n1) << 32 | (u64)n2);
|
|
}
|
|
#endif // !WAPP_PLATFORM_POSIX
|
|
#else
|
|
internal void seed_os_generator(void) {
|
|
time_t result = time(NULL);
|
|
wapp_runtime_assert(result != (time_t)(-1), "Invalid seed value");
|
|
|
|
srand(result);
|
|
}
|
|
|
|
internal u64 generate_random_number(void) {
|
|
i32 n1 = rand();
|
|
i32 n2 = rand();
|
|
|
|
return (((u64)n1) << 32 | (u64)n2);
|
|
}
|
|
#endif // !WAPP_PLATFORM_C
|