The trouble is, many real-world C implementations *do* have poor
rand() functions, perhaps partly because the C standard provides a
sample implementation. Certainly a rand() implementation should be as
good as possible, but I'm not going to reject an implementation just
because its rand() is poor. Many implementations provide alternate
PRNGs, typically ones that don't fit into the standard's requirements
for rand() and srand().
Disclaimer: I don't actually know what the current state of rand()
implementations is. If I'm wrong, if most or all existing
implementations have been enhanced so the low-order bits are as good
as the high-order bits, then my argument is weakened. Does anyone
know the actual current state of the art? Do any existing
implementations still use the sample implementation given in the C
standard?
Hi, Keith.
I saw last libc sources (
http://sources.redhat.com/glibc/)
/* If we are using the trivial TYPE_0 R.N.G., just do the old linear
congruential bit. Otherwise, we do our fancy trinomial stuff, which
is the same in all the other cases due to all the global variables
that have been set up. The basic operation is to add the number at
the rear pointer into the one at the front pointer. Then both
pointers are advanced to the next location cyclically in the table.
The value returned is the sum generated, reduced to 31 bits by
throwing away the "least random" low bit.
Note: The code takes advantage of the fact that both the front and
rear pointers can't wrap on the same call by not testing the rear
pointer if the front one has wrapped. Returns a 31-bit random
number. */
int
__random_r (buf, result)
struct random_data *buf;
int32_t *result;
{
int32_t *state;
if (buf == NULL || result == NULL)
goto fail;
state = buf->state;
if (buf->rand_type == TYPE_0)
{
int32_t val = state[0];
val = ((state[0] * 1103515245) + 12345) & 0x7fffffff;
state[0] = val;
*result = val;
}
else
{
int32_t *fptr = buf->fptr;
int32_t *rptr = buf->rptr;
int32_t *end_ptr = buf->end_ptr;
int32_t val;
val = *fptr += *rptr;
/* Chucking least random bit. */
*result = (val >> 1) & 0x7fffffff;
++fptr;
if (fptr >= end_ptr)
{
fptr = state;
++rptr;
}
else
{
++rptr;
if (rptr >= end_ptr)
rptr = state;
}
buf->fptr = fptr;
buf->rptr = rptr;
}
return 0;
fail:
__set_errno (EINVAL);
return -1;
}
and by default TYPE_3 is set:
static struct random_data unsafe_state =
{
[snip]
/* The following things are the pointer to the state information
table,
the type of the current generator, the degree of the current
polynomial
being used, and the separation between the two pointers.
Note that for efficiency of random, we remember the first location
of
the state information, not the zeroth. Hence it is valid to access
state[-1], which is used to store the type of the R.N.G.
Also, we remember the last location, since this is more efficient
than
indexing every time to find the address of the last element to see
if
the front and rear pointers have wrapped. */
.state = &randtbl[1],
.rand_type = TYPE_3,
.rand_deg = DEG_3,
.rand_sep = SEP_3,
.end_ptr = &randtbl[sizeof (randtbl) / sizeof (randtbl[0])]
};