random.h#

#include <sif/utils/random.h>
SIF_UTILS_RANDOM_H#

xoshiro256+ pseudo-random generator.

Header-only and state-passing: there is no global generator, so each thread or task holds its own sif_prng_state_t and draws from it without synchronization. Seed the states from distinct seeds – the SplitMix64 expansion below decorrelates even adjacent ones.

Note

xoshiro256+ is fast and statistically sound for simulation, but it is not cryptographically secure and its lowest bits are the weakest; the conversions here take from the top.

struct sif_prng_state_t#

Generator state: the four 64-bit words of xoshiro256+.

static inline uint64_t sif__splitmix64(uint64_t *state)#

SplitMix64 step. Not part of the API.

Used to expand a single seed into the four state words. Seeding xoshiro directly from a small integer leaves it correlated for the first outputs; SplitMix64 has a different structure and breaks that.

static inline uint64_t sif__rotl(uint64_t x, int k)#

64-bit rotate left. Not part of the API.

static inline void sif_prng_init(sif_prng_state_t *state, uint64_t seed)#

Seed a generator state.

Parameters:
  • state – State to initialize.

  • seed – Any 64-bit value, including 0; it is expanded through SplitMix64 into the 256 bits xoshiro needs.

static inline uint64_t sif_prng_next_u64(sif_prng_state_t *state)#

Next raw 64-bit draw, advancing the state.

static inline sif_real sif_prng_next_real(sif_prng_state_t *state)#

Next draw as a sif_real in [0, 1).

Takes 53 bits in a double build and 24 in a float build, matching what the type can represent.

static inline double sif_prng_next_double(sif_prng_state_t *state)#

Next draw as a double in [0, 1), always with the full 53 bits.

Deliberately does not follow sif_real. At 24 bits the smallest non-zero draw is 6e-8, which puts a hard floor of about 5.7 sigma on the tail any Gaussian built on it can reach.

static inline void sif_prng_next_gaussian_pair(sif_prng_state_t *state, double *z0, double *z1)#

Two independent standard normal deviates, by the Box-Muller transform.

Returned as a pair because one logarithm, one square root and one sine-cosine serve both, so a caller that keeps only the first pays twice per normal.

Parameters:
  • state – PRNG state, advanced by two draws.

  • z0 – First deviate, written.

  • z1 – Second deviate, written.