Skip to content

Instantly share code, notes, and snippets.

@sjolsen
Last active December 31, 2015 08:19
Show Gist options
  • Save sjolsen/7960058 to your computer and use it in GitHub Desktop.
Save sjolsen/7960058 to your computer and use it in GitHub Desktop.
Basic uniform int distribution for C
#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