diff options
Diffstat (limited to 'lib/libc/stdlib/random.c')
-rw-r--r-- | lib/libc/stdlib/random.c | 159 |
1 files changed, 86 insertions, 73 deletions
diff --git a/lib/libc/stdlib/random.c b/lib/libc/stdlib/random.c index 7c76158..d1ec971 100644 --- a/lib/libc/stdlib/random.c +++ b/lib/libc/stdlib/random.c @@ -32,9 +32,17 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)random.c 8.2 (Berkeley) 5/19/95"; +static char sccsid[] = "@(#)random.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ +#ifdef COMPAT_WEAK_SEEDING +#define USE_WEAK_SEEDING +#define random orandom +#define srandom osrandom +#define initstate oinitstate +#define setstate osetstate +#endif + #include <stdio.h> #include <stdlib.h> @@ -61,7 +69,7 @@ static char sccsid[] = "@(#)random.c 8.2 (Berkeley) 5/19/95"; * state information, which will allow a degree seven polynomial. (Note: * the zeroeth word of state information also has some other information * stored in it -- see setstate() for details). - * + * * The random number generation technique is a linear feedback shift register * approach, employing trinomials (since there are fewer terms to sum up that * way). In this approach, the least significant bit of all the numbers in @@ -76,25 +84,6 @@ static char sccsid[] = "@(#)random.c 8.2 (Berkeley) 5/19/95"; * large deg, when the period of the shift register is the dominant factor. * With deg equal to seven, the period is actually much longer than the * 7*(2**7 - 1) predicted by this formula. - * - * Modified 28 December 1994 by Jacob S. Rosenberg. - * The following changes have been made: - * All references to the type u_int have been changed to unsigned long. - * All references to type int have been changed to type long. Other - * cleanups have been made as well. A warning for both initstate and - * setstate has been inserted to the effect that on Sparc platforms - * the 'arg_state' variable must be forced to begin on word boundaries. - * This can be easily done by casting a long integer array to char *. - * The overall logic has been left STRICTLY alone. This software was - * tested on both a VAX and Sun SpacsStation with exactly the same - * results. The new version and the original give IDENTICAL results. - * The new version is somewhat faster than the original. As the - * documentation says: "By default, the package runs with 128 bytes of - * state information and generates far better random numbers than a linear - * congruential generator. If the amount of state information is less than - * 32 bytes, a simple linear congruential R.N.G. is used." For a buffer of - * 128 bytes, this new version runs about 19 percent faster and for a 16 - * byte buffer it is about 5 percent faster. */ /* @@ -135,13 +124,13 @@ static char sccsid[] = "@(#)random.c 8.2 (Berkeley) 5/19/95"; */ #define MAX_TYPES 5 /* max number of types above */ -static long degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; -static long seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; +static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; +static int seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; /* * Initially, everything is set up as if from: * - * initstate(1, &randtbl, 128); + * initstate(1, randtbl, 128); * * Note that this initialization takes advantage of the fact that srandom() * advances the front and rear pointers 10*rand_deg times, and hence the @@ -154,12 +143,23 @@ static long seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; static long randtbl[DEG_3 + 1] = { TYPE_3, +#ifdef USE_WEAK_SEEDING +/* Historic implementation compatibility */ +/* The random sequences do not vary much with the seed */ 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b, 0x27fb47b9, +#else /* !USE_WEAK_SEEDING */ + 0x991539b1, 0x16a5bce3, 0x6774a4cd, 0x3e01511e, 0x4e508aaa, 0x61048c05, + 0xf5500617, 0x846b7115, 0x6a19892c, 0x896a97af, 0xdb48f936, 0x14898454, + 0x37ffd106, 0xb58bff9c, 0x59e17104, 0xcf918a49, 0x09378c83, 0x52c7a471, + 0x8d293ea9, 0x1f4fc301, 0xc3db71be, 0x39b44e1c, 0xf8a44ef9, 0x4c8b80b1, + 0x19edc328, 0x87bf4bdd, 0xc9b240e5, 0xe9ee4b1b, 0x4382aee7, 0x535b6b41, + 0xf3bec5da +#endif /* !USE_WEAK_SEEDING */ }; /* @@ -190,11 +190,43 @@ static long *rptr = &randtbl[1]; * the last element to see if the front and rear pointers have wrapped. */ static long *state = &randtbl[1]; -static long rand_type = TYPE_3; -static long rand_deg = DEG_3; -static long rand_sep = SEP_3; +static int rand_type = TYPE_3; +static int rand_deg = DEG_3; +static int rand_sep = SEP_3; static long *end_ptr = &randtbl[DEG_3 + 1]; +static inline long good_rand __P((long)); + +static inline long good_rand (x) + register long x; +{ +#ifdef USE_WEAK_SEEDING +/* + * Historic implementation compatibility. + * The random sequences do not vary much with the seed, + * even with overflowing. + */ + return (1103515245 * x + 12345); +#else /* !USE_WEAK_SEEDING */ +/* + * Compute x = (7^5 * x) mod (2^31 - 1) + * wihout overflowing 31 bits: + * (2^31 - 1) = 127773 * (7^5) + 2836 + * From "Random number generators: good ones are hard to find", + * Park and Miller, Communications of the ACM, vol. 31, no. 10, + * October 1988, p. 1195. + */ + register long hi, lo; + + hi = x / 127773; + lo = x % 127773; + x = 16807 * lo - 2836 * hi; + if (x <= 0) + x += 0x7fffffff; + return (x); +#endif /* !USE_WEAK_SEEDING */ +} + /* * srandom: * @@ -209,16 +241,16 @@ static long *end_ptr = &randtbl[DEG_3 + 1]; */ void srandom(x) - unsigned long x; + unsigned int x; { - register long i; + register int i; if (rand_type == TYPE_0) state[0] = x; else { state[0] = x; for (i = 1; i < rand_deg; i++) - state[i] = 1103515245 * state[i - 1] + 12345; + state[i] = good_rand(state[i - 1]); fptr = &state[rand_sep]; rptr = &state[0]; for (i = 0; i < 10 * rand_deg; i++) @@ -234,29 +266,24 @@ srandom(x) * the break values for the different R.N.G.'s, we choose the best (largest) * one we can and set things up for it. srandom() is then called to * initialize the state information. - * + * * Note that on return from srandom(), we set state[-1] to be the type * multiplexed with the current value of the rear pointer; this is so * successive calls to initstate() won't lose this information and will be * able to restart with setstate(). - * + * * Note: the first thing we do is save the current state, if any, just like * setstate() so that it doesn't matter when initstate is called. * * Returns a pointer to the old state. - * - * Note: The Sparc platform requires that arg_state begin on a long - * word boundary; otherwise a bus error will occur. Even so, lint will - * complain about mis-alignment, but you should disregard these messages. */ char * initstate(seed, arg_state, n) - unsigned long seed; /* seed for R.N.G. */ + unsigned int seed; /* seed for R.N.G. */ char *arg_state; /* pointer to state array */ - long n; /* # bytes of state info */ + int n; /* # bytes of state info */ { register char *ostate = (char *)(&state[-1]); - register long *long_arg_state = (long *) arg_state; if (rand_type == TYPE_0) state[-1] = rand_type; @@ -264,7 +291,7 @@ initstate(seed, arg_state, n) state[-1] = MAX_TYPES * (rptr - state) + rand_type; if (n < BREAK_0) { (void)fprintf(stderr, - "random: not enough state (%ld bytes); ignored.\n", n); + "random: not enough state (%d bytes); ignored.\n", n); return(0); } if (n < BREAK_1) { @@ -288,13 +315,13 @@ initstate(seed, arg_state, n) rand_deg = DEG_4; rand_sep = SEP_4; } - state = (long *) (long_arg_state + 1); /* first location */ + state = &(((long *)arg_state)[1]); /* first location */ end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */ srandom(seed); if (rand_type == TYPE_0) - long_arg_state[0] = rand_type; + state[-1] = rand_type; else - long_arg_state[0] = MAX_TYPES * (rptr - state) + rand_type; + state[-1] = MAX_TYPES*(rptr - state) + rand_type; return(ostate); } @@ -312,18 +339,14 @@ initstate(seed, arg_state, n) * setstate() with the same state as the current state. * * Returns a pointer to the old state information. - * - * Note: The Sparc platform requires that arg_state begin on a long - * word boundary; otherwise a bus error will occur. Even so, lint will - * complain about mis-alignment, but you should disregard these messages. */ char * setstate(arg_state) - char *arg_state; /* pointer to state array */ + char *arg_state; { - register long *new_state = (long *) arg_state; - register long type = new_state[0] % MAX_TYPES; - register long rear = new_state[0] / MAX_TYPES; + register long *new_state = (long *)arg_state; + register int type = new_state[0] % MAX_TYPES; + register int rear = new_state[0] / MAX_TYPES; char *ostate = (char *)(&state[-1]); if (rand_type == TYPE_0) @@ -344,7 +367,7 @@ setstate(arg_state) (void)fprintf(stderr, "random: state info corrupted; not changed.\n"); } - state = (long *) (new_state + 1); + state = &new_state[1]; if (rand_type != TYPE_0) { rptr = &state[rear]; fptr = &state[(rear + rand_sep) % rand_deg]; @@ -373,28 +396,18 @@ setstate(arg_state) long random() { - register long i; - register long *f, *r; - - if (rand_type == TYPE_0) { - i = state[0]; - state[0] = i = (i * 1103515245 + 12345) & 0x7fffffff; - } else { - /* - * Use local variables rather than static variables for speed. - */ - f = fptr; r = rptr; - *f += *r; - i = (*f >> 1) & 0x7fffffff; /* chucking least random bit */ - if (++f >= end_ptr) { - f = state; - ++r; - } - else if (++r >= end_ptr) { - r = state; - } + long i; - fptr = f; rptr = r; + if (rand_type == TYPE_0) + i = state[0] = good_rand(state[0]) & 0x7fffffff; + else { + *fptr += *rptr; + i = (*fptr >> 1) & 0x7fffffff; /* chucking least random bit */ + if (++fptr >= end_ptr) { + fptr = state; + ++rptr; + } else if (++rptr >= end_ptr) + rptr = state; } return(i); } |