Last active
December 31, 2015 08:19
-
-
Save sjolsen/7960058 to your computer and use it in GitHub Desktop.
Basic uniform int distribution for C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef UNIFORM_INT_H | |
#define UNIFORM_INT_H | |
#ifndef _POSIX_C_SOURCE | |
# define _POSIX_C_SOURCE 200112L | |
#elif _POSIX_C_SOURCE < 200112L | |
# undef _POSIX_C_SOURCE | |
# define _POSIX_C_SOURCE 200112L | |
#endif | |
#include <math.h> | |
#include <limits.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
struct int_rng | |
{ | |
int32_t low; | |
int32_t high; | |
int32_t (*gen) (void*); | |
void* state; | |
}; | |
uint32_t nbit_mask (uint32_t nbits) | |
{ | |
return ((uint32_t) (~0)) >> ((sizeof (uint32_t) * CHAR_BIT) - nbits); | |
} | |
/* Returns an int32_t uniformly distributed on [low, high], using rng.gen(rng.state) | |
to obtain entropy */ | |
int32_t uniform_int (int32_t low, int32_t high, struct int_rng rng) | |
{ | |
uint64_t dest_range = ((uint64_t)high - (uint64_t)low) + 1; | |
uint32_t dest_bits = ceil (log2 (dest_range)); | |
uint32_t dest_mask = nbit_mask (dest_bits); | |
uint64_t src_range = ((uint64_t)rng.high - (uint64_t)rng.low) + 1; | |
uint32_t src_bits = floor (log2 (src_range)); | |
uint32_t src_mask = nbit_mask (src_bits); | |
uint32_t value_offset; | |
do | |
{ | |
value_offset = 0; | |
{ | |
uint32_t val_bits; | |
for (val_bits = 0; val_bits < dest_bits; val_bits += src_bits) | |
{ | |
uint32_t src_val; | |
do | |
{ | |
src_val = rng.gen (rng.state) - rng.low; | |
} | |
while (src_val >= src_range); | |
value_offset <<= src_bits; | |
value_offset |= src_val & src_mask; | |
} | |
} | |
value_offset &= dest_mask; | |
} | |
while (value_offset >= dest_range); | |
return low + value_offset; | |
} | |
int32_t rand_r_wrapper (void* state) | |
{ | |
return rand_r ((uint32_t*) state); | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment