It might be an idea to provide a thread_safe version: Append '_r' to
the function names and add an extra parameter (a struct containing
the current static variables). The current function names would be
an interface to it, with their own static struct.
Ben Pfaff wrote:
About prng_seed:
/* If KEY is non-null and SIZE is nonzero, seeds the
pseudo-random number generator based on the SIZE bytes in BUF.
At most the first 256 bytes of BUF are used. If KEY is a null
pointer and SIZE is zero, seeds the pseudo-random number
generator based on the current time.
I think it would be both cleaner and simpler to base the choice of
whether or not to use time() on just one parameter:
Seeds the pseudo-random number generator.
If KEY is null, the seed is based on the current time.
Otherwise, SIZE must be nonzero and the seed is based on the SIZE
bytes in KEY. At most the first 256 bytes of KEY are used.
prng_get_byte (void)
{
if (UCHAR_MAX == 255)
`#if UCHAR_MAX == 255' avoids warnings about the if() test always being
true/false.
/* Handle oversize bytes. */
unsigned byte = prng_get_octet ();
unsigned done = 255;
while ((unsigned char) done != UCHAR_MAX)
{
byte = (byte << 8) | prng_get_octet ();
done = (done << 8) | 255;
}
You don't need to shift 'done'. done++ should be a bit faster:
unsigned done = 1;
do {
byte = (byte << 8) | prng_get_octet ();
} while (++done < (CHAR_BIT+7)/8);
The same applies to prng_get_ulong() and prng_get_uint().
#if CHAR_BIT % 8 != 0, you could avoid some calls to prng_get_octet() by
saving the unused bits and use them in the next prng_get_byte() call.
(If you do, remember to reset this value in prng_seed().)
prng_get_long (void)
{
for (;
{
unsigned ulng = prng_get_ulong ();
if (ulng <= LONG_MAX)
return ulng;
This should be enough:
return prng_get_ulong () & LONG_MAX;
Similar for prng_get_int().
/* Returns a pseudo-random floating-point number from the uniform
distribution with range [0,1). */
double
prng_get_double (void)
{
for (;
{
unsigned long ulng = prng_get_ulong ();
if (ulng != ULONG_MAX)
return (double) ulng / ULONG_MAX;
This can return 1, since floating point arithmetic is not exact.
double ret = (double) prng_get_ulong () / ULONG_MAX;
if (ret < 1)
return ret;