summaryrefslogtreecommitdiff
path: root/xorshift.c
blob: ac4d08703bbb04eebc2e19932deed90c8fb41e08 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include <limits.h>
#include <sys/random.h>
#include <string.h>
#include "structs.h"

static struct rng_state global_rng_state;

__attribute__((visibility("default"))) bool initialize_states(){
	assert( (sizeof(uint32_t) * CHAR_BIT) == 32 );
	memset( (void*)&global_rng_state, 0, sizeof(struct rng_state) );
	ssize_t state_bytes_read = 0;
	if ( (state_bytes_read = getrandom((void*)&global_rng_state.states, 16 * sizeof(uint32_t), GRND_NONBLOCK)) == -1 )
		return false;
	if ( (size_t)state_bytes_read < (16 * sizeof(uint32_t)) ){
		errno = EIO;
		return false;
	}
	global_rng_state.state_idx = global_rng_state.states[7] >> 28;
	errno = 0;
	return true;
}

__attribute__((visibility("default"))) uint32_t get_random_output(){
	size_t use_state = global_rng_state.state_idx;
	global_rng_state.state_idx = global_rng_state.states[use_state] >> 28;
	if ( global_rng_state.gen_period_ctr >= 0xffffffff ){
		global_rng_state.period_end_ctr++;
		if ( global_rng_state.period_end_ctr >= 16 ){
			assert( initialize_states() == true );
			global_rng_state.period_end_ctr = 0;
		}
		global_rng_state.gen_period_ctr = 0;
	}
	global_rng_state.gen_period_ctr++;
	global_rng_state.states[use_state] ^= global_rng_state.states[use_state] >> 11;
	global_rng_state.states[use_state] ^= global_rng_state.states[use_state] << 7;
	global_rng_state.states[use_state] ^= global_rng_state.states[use_state] >> 16;
	return global_rng_state.states[use_state] * OUTPUT_MULTIPLIER;
}

__attribute__((visibility("default"))) uint32_t get_uniform_uint( uint32_t min, uint32_t max ){
	if ( max <= min )
		return min;
	uint32_t ncount = (max - min) + 1;
	uint32_t upper_bound = 0xffffffff - (0xffffffff % ncount);
	uint32_t gen_output = get_random_output();
	if ( gen_output > upper_bound ){
		while ( gen_output > upper_bound )
			gen_output = get_random_output();
	}
	return (gen_output % max) + min;
}

__attribute__((visibility("default"))) void clear_rng_state(){
	memset( (void*)&global_rng_state, 0, sizeof(struct rng_state) );
	return;
}