[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

(fwd) BSD random() - any good (source included)?



Path: bga.com!news.sprintlink.net!news.onramp.net!convex!cs.utexas.edu!bcm!news.tamu.edu!henrik
From: [email protected] (Henrik Schmiediche)
Newsgroups: sci.math,sci.stat.math
Subject: BSD random() - any good (source included)?
Date: 22 Jun 1994 21:15:35 GMT
Organization: Department of Statistics, Texas A&M University
Lines: 140
Message-ID: <[email protected]>
NNTP-Posting-Host: picard.tamu.edu
Xref: bga.com sci.math:14740 sci.stat.math:1193

     Hello,
the BSD random() function returns a pseudo random number. I would like
to know if anyone knows how good this random number generator is and
if it has been thouroughly tested. Below are two descriptions of the
generator for two different sources. Looking at the source code it is
obvious that this generator is seeded using a linear congruetial
generator that leaves much to be desired (low bits alternate). I
remember reading somewhere that the trinomials used by random() are
not optimal but I can't remember the source. The generator does have
some great advantages like being very fast and having a very long
period, but both these advantages are meaningless if the random
numbers it produces are not very good. Anyone know more about random()
and if it is any good?

I have include a source code implementation below (I wrote it
originally so I could inline the code into my own application which
spend a significant amount of time generating random numbers).

   - henrik


According to the SunOS doc's:

"random () uses a non-linear additive feedback random number
generator employing a default table of size 31 long integers
to return successive pseudo-random numbers in the range from
0  to (2**31)-1.  The period of this random number generator
is very large, approximately 16*((2**31)-1)."

The BSD source code (from glibc) says:

"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 the state table will act as a linear feedback shift
register, and will have period 2^deg - 1 (where deg is the degree of
the polynomial being used, assuming that the polynomial is irreducible
and primitive).  The higher order bits will have longer periods, since
their values are also influenced by pseudo-random carries out of the
lower bits.  The total period of the generator is approximately
deg*(2**deg - 1); thus doubling the amount of state information has a
vast influence on the period of the generator."

For table size of 31 long ints random() use the trinomial: x**31 +
x**3 + 1. For 63 long ints it uses the trinomial x**63 + x + 1.

*****************************************************************************

/***
   Code to implement random() & srandom() of BSD Unix. It was taken
   (though coded somewhat differently) from the Gnu BSD implementation.
 ***/

#include <stdio.h>
#include <stdlib.h>

#ifdef LONG31  /* x^31 + x^3 + 1 */
#define SIZE  31
#define SIZE1 30
#define P1 3
#define P2 0
#else  /* LONG63: x^63 + x + 1 */
#define SIZE  63
#define SIZE1 62
#define P1 1
#define P2 0
#endif

#define LONG_MAX  0x7fffffff


int p1=P1, p2=P2;  
long table[SIZE];

/*** return a "random" number in range [0, LONG_MAX] */

long xrand ()
{
  int r;

  table[p1] = table[p1] + table[p2]; /* add two table elements */
  r = (table[p1] >> 1) & LONG_MAX;   /* throw least significant bit away */

  if (p1 == SIZE1) { /* increment the table indexes */
    p1 = 0; 
    p2 = p2 + 1; 
  }
  else if (p2 == SIZE1) {
    p1 = p1 + 1;    
    p2 = 0;
  }
  else {
    p1 = p1 + 1;    
    p2 = p2 + 1;
  }

  return (r);
}


/*** use a linear congruential type generator to seed the 
     state table & cycle the entire table 10 times */

void sxrand (seed)
long seed;
{
  int i;

  table[0] = seed;
  for (i=1; i<SIZE; ++i)
    table[i] = (table[i-1] * 1103515145) + 12345;  /* lousy */

  for (i=0; i<10*SIZE; ++i)
    (void) xrand();
}


/*** a small test program */

void main ()
{
  int i;

  sxrand (1);  /* BSD default */

  for (i=1; i<=40; ++i)
    printf ("%ld", xrand() % 10 ); /* least random bits ? */

  /* 6714066113586447326208220248220881760069 (cc -DLONG63) */
  /* 9418752338157675324663485137890734831064 (cc -DLONG31) */

  printf ("\n");
}



--
Henrik Schmiediche, Dept. of Statistics, Texas A&M, College Station, TX 77843
E-mail: [email protected]  |  Tel: (409) 862-1764   |  Fax: (409) 845-3144
Finger for pgp 2.5 key, fingerprint: CE8F BD6C 59FC DA85  376A BB96 2E83 FF5E