Why not keep this simple. You are not, obviously, interested in a cryptographically secure RNG, so LCG, Mersene Twister, Xorshift128 or any other PRNG is suitable. A thread safe LCG is easy enough to be implemented. For example:
Code:
unsigned int myrand( unsigned int *state )
{
unsigned int r;
/* LCG: Stolen from glibc (changed to unsigned int). */
r = ( *state * 1103515245 ) + 12345;
*state = r;
return r;
}
This "state" is your initial seed and the values 1103515245 and 12345 are good enough for an LCG...
If you want to use RDRAND for Intel/AMD processors, you can do something like this:
Code:
/* rand.c */
#include <cpuid.h>
/* Interface pointers to proper functions. */
void (*SRAND)( unsigned int *, unsigned int );
unsigned int (*RAND)( unsigned int * );
/* Because RDRAND don't need a seed! */
static void empty( unsigned int *state, unsigned int seed ) {}
/* mysrand() & myrand() are thread safe. You need only to provide
A pointer to the initial seed */
static void mysrand( unsigned int *state, unsigned int seed )
{
*state = seed;
}
static unsigned int myrand( unsigned int *state )
{
unsigned int r;
/* LCG: Stolen from glibc (changed to unsigned int). */
r = ( *state * 1103515245 ) + 12345;
*state = r;
return r;
}
#if defined(__i386) || defined(__x86_64)
static unsigned int rdrand( unsigned int *state )
/* state pointer is ignored! */
{
unsigned int r;
/* Need to save EBX/RBX because of SysV calling convention. */
__asm__ __volatile__(
"1:\n\t"
" rdrand %0\n\t"
" jnc 1b" : "=c" (r) ::
#ifdef __i386
"ebx"
#else
"rbx"
#endif
);
// NOTE: There is an intrinsic called _rdrand32_step(), but it created worse code
// than this one...
return r;
}
#endif
/* The default behavior is to use LCG, unless we are dealing with
Intel/AMD processors which have RDRAND instruction. */
void (*SRAND)( unsigned int *, unsigned int ) = mysrand;
unsigned int (*RAND)( unsigned int * ) = myrand;
#if defined(__i386) || defined(__x86_64)
/* You can change this to a simple RAND_init() function which must be called before any
use of SRAND() or RAND(). I prefer to use the GCC extension. */
static void __attribute__((constructor)) RAND_ctor( void )
{
int a, b, c, d;
__cpuid( 1, a, b, c, d ); // Yep, this is an intrinsic @ cpuid.h.
// You can do this in asm, if you wish...
if ( c & bit_RDRND ) // bit_RDRND also defined in cpuid.h
{
SRAND = empty;
RAND = rdrand;
}
}
#endif
A small test code:
Code:
/* test.c */
#include <stdio.h>
#include <time.h>
#include <limits.h>
#define scale2rgb(n) \
( unsigned int ) ( ( (n) * 16777215.0 ) / UINT_MAX )
extern void (*SRAND)( unsigned int *, unsigned int );
extern unsigned int (*RAND)( unsigned int * );
int main ( void )
{
int i;
unsigned int rnd_state, r;
SRAND( &rnd_state, time(NULL) );
puts("P6\n1024 1024\n255");
for ( i = 0; i < 1024*1024; i++ )
{
r = scale2rgb(RAND(&rnd_state));
fwrite( &r, 3, 1, stdout );
}
}
Compiling and linking:
Code:
$ cc -O2 -c rand.c test.c
$ cc -O2 -s -o test test.o rand.o
$ ./test > pic.ppm