summaryrefslogtreecommitdiffstats
path: root/lib/libc/stdlib/random.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/stdlib/random.c')
-rw-r--r--lib/libc/stdlib/random.c159
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);
}
OpenPOWER on IntegriCloud