[net.sources] Random number generator in C

duane@anasazi.UUCP (Duane Morse) (07/30/85)

For those of you experimenting with random number generators, here's one
I wrote some time ago in Z80 assembler and then recoded in C. If you want
efficiency, you'll most likely want to put this back into assembler.

By the way, I've run a variety of statistical tests to see if the floating
point routine (frand32) in this software generates a decent uniform
distribution, and it seems satisfactory.
---------------------------Software follows----------------------------

/*TITLE rand32.c - 32-bit random number routines 1/8/85 15:45:40 */
/*SUBTTL Declarations */
static char *version = "@(#)rand32.c	1.1 1/8/85 15:45:40";

/*
** This file contains three routines.
**
**  srand32(val) - sets the random number seed to long val.
**  irand32() - returns a long from 0 to 2^31 -1 (2147483647)
**  frand32() - returns random float in the range (0.0, 1.0)
**
** The linear congruential method is used with modulus 2^32, no
** increment, and a 23-bit multiplier (7401715). The length of the sequence
** generated is 2^30.
**

/* Define the multiplier, one byte at a time */
static unsigned char mult_0 = 0xf3;
static unsigned char mult_8 = 0xf0;
static unsigned char mult_16 = 0x70;

/* Define the default seed */
static unsigned char seed_0 = 0x83;
static unsigned char seed_8 = 0x85;
static unsigned char seed_16 = 0x86;
static unsigned char seed_24 = 0x87;
/*SUBTTL srand32 - reset the seed */
/*
** void srand32(val)
**
**  Reset the random number seed to val unless val is 0.
**
** Parameters:
**  val = long integer which is to be the new seed.
**
** Returns:
**  Nothing.
*/

void srand32(val)

long val;

{
  if (val == 0)
    return;
  seed_24 = val >> 24;
  seed_16 = val >> 16;
  seed_8 = val >> 8;
  seed_0 = val;
}
/*SUBTTL irand32 - return random integer from 0 to 2^31 - 1 */
/*
** unsigned long irand32()
**
**  Return a random integer from 0 to 2^31 - 1.
**
** Parameters:
**  None.
**
**  seed = previous value returned.
**
** Returns:
**  Pseudo random integer.
**
**  seed = replaced with the new value.
*/

unsigned long irand32()

{
  register unsigned long x;

  x = ((mult_0 * seed_24 + mult_8 * seed_16 + mult_16 * seed_8) << 24)
      + ((mult_0 * seed_16 + mult_8 * seed_8 + mult_16 * seed_0) << 16)
      + ((mult_0 * seed_8 + mult_8 * seed_0) << 8)
      + mult_0 * seed_0;
  seed_24 = x >> 24;
  seed_16 = x >> 16;
  seed_8 = x >> 8;
  seed_0 = x;
  return (x >> 1) & 0x7fffffff;
}
/*SUBTTL frand32 - return random float in the interval [0.0, 1.0) */
/*
** float frand32()
**
**  Return a random floating point value between 0.0 and 1.0.
**
** Parameters:
**  None.
**
**  seed = previous random number seed.
**
** Returns:
**  Value from 0.0 to 1.0 (but not equal to 1.0).
**
**  seed = reset to new random number.
*/

float frand32()

{
  return ((float) irand32()) / 2147483648.0;
}
--------------------------My name probably follows this line ----------------
-- 

Duane Morse	...!noao!terak!anasazi!duane
(602) 275-0302