Skip to content

Instantly share code, notes, and snippets.

@cloudwu
Last active July 2, 2021 06:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cloudwu/e68fd3c33f85d34b509a85de2db861d9 to your computer and use it in GitHub Desktop.
Save cloudwu/e68fd3c33f85d34b509a85de2db861d9 to your computer and use it in GitHub Desktop.
xoshiro256 from lua 5.4
// 'xoshiro256**' algorithm from lua 5.4 implementation
#include "random.h"
#include <stdint.h>
#include <assert.h>
static inline uint64_t *
state(struct prn_state *P) {
assert(sizeof(*P) == sizeof(uint64_t) * 4);
return (uint64_t *)P;
}
static inline uint64_t
rotl(uint64_t x, int n) {
return (x << n) | (x >> (64 - n));
}
static inline uint64_t
nextrand(uint64_t *state) {
uint64_t state0 = state[0];
uint64_t state1 = state[1];
uint64_t state2 = state[2] ^ state0;
uint64_t state3 = state[3] ^ state1;
uint64_t res = rotl(state1 * 5, 7) * 9;
state[0] = state0 ^ state3;
state[1] = state1 ^ state2;
state[2] = state2 ^ (state1 << 17);
state[3] = rotl(state3, 45);
return res;
}
void
prn_init(struct prn_state *P, unsigned int seed1, unsigned int seed2) {
int i;
uint64_t *s = state(P);
s[0] = seed1;
s[1] = 0xff;
s[2] = seed2;
s[3] = 0;
for (i = 0; i < 16; i++)
nextrand(s);
}
static unsigned int
project(uint64_t ran, unsigned int n, uint64_t *state) {
--n;
if ((n & (n + 1)) == 0) // is 'n + 1' a power of 2?
return ran & n; // no bias
else if (n < 256) {
// small n ( 0, 255 )
int i = 0;
unsigned int lim = n;
unsigned result;
lim |= (lim >> 1);
lim |= (lim >> 2);
lim |= (lim >> 4);
while ((result = (ran & lim)) > n) {
if (i >= 7) {
i = 0;
ran = nextrand(state);
} else {
ran >>= 8;
++i;
}
}
return result;
} else {
unsigned int lim = n;
// compute the smallest (2^b - 1) not smaller than 'n'
lim |= (lim >> 1);
lim |= (lim >> 2);
lim |= (lim >> 4);
lim |= (lim >> 8);
lim |= (lim >> 16);
while ((ran &= lim) > n) // project 'ran' into [0..lim]
ran = nextrand(state); // not inside [0..n]? try again
return ran;
}
}
unsigned int
prn_gen(struct prn_state *P, int n) {
uint64_t *s = state(P);
uint64_t rv = nextrand(s);
return project(rv, n, s);
}
#ifndef pseduo_random_number_h
#define pseduo_random_number_h
struct prn_state {
char s[32];
};
void prn_init(struct prn_state *P, unsigned int seed1, unsigned int seed2);
unsigned int prn_gen(struct prn_state *P, int n); // random number [0,n)
#endif
#include "random.h"
#include <stdio.h>
// Dice 6
#define N 6
int
main() {
struct prn_state P;
prn_init(&P, 1, 0);
int i=0;
int c[N] = { 0 };
for (i=0;i<100000;i++) {
int v = prn_gen(&P, N);
c[v]++;
}
for (i=0;i<N;i++) {
printf("%d:%d\n", i+1, c[i]);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment