For anyone who stumbles upon this thread in the future:
Since the Xoshiro256** PRNG relies on the SplitMix64 PRNG anyway,
I merged the source files
xoshiro256ss.c
and
splitmix64.c
into
prng.c
,
and also created a corresponding header file
prng.h
.
To use, just copy
prng.c
and
prng.h
into your project directory
and include the header file in your
main.c
with
#include "prng.h"
main.c
source file:
#include <stdio.h>
#include <time.h>
#include "prng.h"
int main(void)
{
uint64_t seed_splitmix64 = time(NULL);
PRNG_SetState_splitmix64(seed_splitmix64);
uint64_t seed_xoshiro256ss[4] = {0};
for(int i = 0; i < 4; ++i)
{
seed_xoshiro256ss[i] = PRNG_GenerateNumber_splitmix64();
}
PRNG_SetState_xoshiro256ss(seed_xoshiro256ss);
uint64_t num_xoshiro256ss = PRNG_GenerateNumber_xoshiro256ss();
printf("%lu\n", num_xoshiro256ss);
uint64_t seed = time(NULL);
PRNG_SetState(seed);
uint64_t num = PRNG_GenerateNumber();
printf("%lu\n", num);
return 0;
}
prng.h
header file:
#ifndef SPLITMIX64_H
#define SPLITMIX64_H
#include <stdint.h>
void PRNG_SetState_splitmix64(uint64_t state);
void PRNG_SetState_xoshiro256ss(uint64_t state[4]);
void PRNG_SetState(uint64_t state);
uint64_t PRNG_GenerateNumber_splitmix64(void);
uint64_t PRNG_GenerateNumber_xoshiro256ss(void);
typedef uint64_t (*generate_number)(void);
extern generate_number PRNG_GenerateNumber;
#endif
I don't understand the algorithm logic. But because of the compiler warning:
"comparison of integer expressions of different signedness:
‘int’ and ‘long unsigned int’ [-Wsign-compare]"
I replaced
for(int i = 0; i < sizeof JUMP / sizeof *JUMP; i++)
with
for(uint64_t i = 0; i < sizeof JUMP / sizeof *JUMP; i++)
and also
for(int i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++)
with
for(uint64_t i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++)
I'm not sure if it breaks the algorithm in any way but that's what I did.
prng.c
source file:
#include "prng.h"
static uint64_t x;
uint64_t PRNG_GenerateNumber_splitmix64(void)
{
uint64_t z = (x += 0x9e3779b97f4a7c15);
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
return z ^ (z >> 31);
}
static inline uint64_t rotl(const uint64_t xl, int k)
{
return (xl << k) | (xl >> (64 - k));
}
static uint64_t s[4];
uint64_t PRNG_GenerateNumber_xoshiro256ss(void)
{
const uint64_t result = rotl(s[1] * 5, 7) * 9;
const uint64_t t = s[1] << 17;
s[2] ^= s[0];
s[3] ^= s[1];
s[1] ^= s[2];
s[0] ^= s[3];
s[2] ^= t;
s[3] = rotl(s[3], 45);
return result;
}
void jump(void)
{
static const uint64_t JUMP[] = { 0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa, 0x39abdc4529b1661c };
uint64_t s0 = 0;
uint64_t s1 = 0;
uint64_t s2 = 0;
uint64_t s3 = 0;
for(uint64_t i = 0; i < sizeof JUMP / sizeof *JUMP; i++)
{
for(int b = 0; b < 64; b++)
{
if (JUMP[i] & UINT64_C(1) << b)
{
s0 ^= s[0];
s1 ^= s[1];
s2 ^= s[2];
s3 ^= s[3];
}
PRNG_GenerateNumber_xoshiro256ss();
}
}
s[0] = s0;
s[1] = s1;
s[2] = s2;
s[3] = s3;
}
void long_jump(void)
{
static const uint64_t LONG_JUMP[] = { 0x76e15d3efefdcbbf, 0xc5004e441c522fb3, 0x77710069854ee241, 0x39109bb02acbe635 };
uint64_t s0 = 0;
uint64_t s1 = 0;
uint64_t s2 = 0;
uint64_t s3 = 0;
for(uint64_t i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++)
{
for(int b = 0; b < 64; b++)
{
if (LONG_JUMP[i] & UINT64_C(1) << b)
{
s0 ^= s[0];
s1 ^= s[1];
s2 ^= s[2];
s3 ^= s[3];
}
PRNG_GenerateNumber_xoshiro256ss();
}
}
s[0] = s0;
s[1] = s1;
s[2] = s2;
s[3] = s3;
}
void PRNG_SetState_splitmix64(uint64_t state)
{
x = state;
}
void PRNG_SetState_xoshiro256ss(uint64_t state[4])
{
for(int i = 0; i < 4; ++i)
{
s[i] = state[i];
}
}
void PRNG_SetState(uint64_t state)
{
x = state;
for(int i = 0; i < 4; ++i)
{
s[i] = PRNG_GenerateNumber_splitmix64();
}
}
generate_number PRNG_GenerateNumber = PRNG_GenerateNumber_xoshiro256ss;