/*----------------------------------------------------------------------------*
RANDOM NUMBERS
Here is a short collection of functions to generate random numbers. These
functions may be used when standard library functions for random numbers are not
available or when precise characteristics of the numbers are important. With
these functions, the random sequences should not vary with the machine, with the
operating system, or with the compiler. The collection comprises seven
functions:
1. Rand Generate random number on the unit interval.
2. RandStart Start the sequence at a specified point.
3. RandStartArb Start the sequence at an arbitrary point.
4. RandStartNext Start the sequence where it left off last.
5. RandStopNext Record the ending random seed for the next run.
6. RandEndingSeed Return the ending random seed.
7. RandInteger Generate a random integer (the inner function).
/*
/*----------------------------------------------------------------------------*
RETURN RANDOM NUMBER IN UNIT INTERVAL
The first function in the collection is the most common in scientific
programming. It merely generates a series of pseudo-random numbers on the
interval 0<=X<1. If it is the only function called, it will generate the same
sequence of numbers each time the program is run, thus providing repeatability
in numerical experiments. A simple program that uses it to list ten random
numbers looks like this and prints the list that follows.
main()
{
int n;
for (n = 0; n < 10; n++)
printf("%f\n", Rand());
}
0.211325
0.544479
0.220742
0.111617
0.893342
0.290086
0.212657
0.105951
0.686732
0.749347
ENTRY: No significant conditions.
EXIT: 'Rand' contains the next random number in the sequence, uniformly
distributed with '0<=Rand<1'. Only the first 32 bits are significant;
the remainder are zero (if the machine's arithmetic hardware is
accurate).
*/
static unsigned long seed;
double Rand()
{
unsigned long RandInteger();
return((double)RandInteger() / 4294967296.);
}
/*----------------------------------------------------------------------------*
INITIALIZE TO A KNOWN STARTING POINT
By default, the function 'Rand' starts at the beginning of a long deterministic
sequence, continues for 4,294,967,296 steps, then repeats. 'Rand' can be
started at any point within the sequence using the function 'RandStart'. The
function is passed a ``seed," which is an integer in the range 0 to
4,294,967,295. The default seed is zero. With a seed of one, the following
program produces a different sequence.
main()
{
int n;
RandStart((unsigned long) 1);
for (n = 0; n < 10; n++)
printf("%f\n", Rand());
}
0.215868
0.177158
0.910775
0.598857
0.739466
0.119943
0.829061
0.617727
0.337687
0.408679
ENTRY: 'k' contains a starting random number seed.
EXIT: The random sequence is initialized to 'k'.
*/
unsigned long RandStart(unsigned long k)
{
seed = k;
return(seed);
}
/*----------------------------------------------------------------------------*
INITIALIZE TO AN ARBITRARY STARTING POINT
A series of arbitrary starting points is taken from the time of day. Function
'RandStartArb' sets the random number seed to a value that will change from
time to time, so the sequence will likely start at a different point each time
its program is run (if enough time elapses). The function returns the
beginning seed, which can be used with function 'RandStart' to repeat the
sequence.
main()
{
unsigned long start;
int n;
start = RandStartArb(0);
for (n = 0; n < 10; n++)
printf("%f\n", Rand());
printf("\n");
RandStart(start);
for (n = 0; n < 10; n++)
printf("%f\n", Rand());
}
0.302036
0.718284
0.199497
0.233959
0.267500
0.025543
0.451980
0.901616
0.583625
0.535184
0.302036
0.718284
0.199497
0.233959
0.267500
0.025543
0.451980
0.901616
0.583625
0.535184
ENTRY: 'offset' contains a value to be added to the initial seed derived from
the time of day. For a series of jobs starting in parallel at
essentially the same time, this can be a job number to make each seed
different.
EXIT: The random number sequence has been set to an arbitrary point.
'RandStartArb' returns the random number seed, which can be
used to restart the sequence.
*/
static unsigned long reverse();
unsigned long time();
unsigned long RandStartArb(unsigned long offset)
{
static unsigned long base = 1234567;
base = base*5 + 1;
seed = base + offset + reverse(time((long*)0));
return(seed);
}
/*----------------------------------------------------------------------------*
SAVE AND RESTORE RANDOM NUMBER SEEDS
When a large simulation is divided into many parts, run in sequence, it may be
important that the random numbers remain independent from run to run. The way
to assure that is to recording the ending random number seed at the end of one
run and reload it at the beginning of the next. Routines in this section are
provided for that purpose.
Note that it is not safe to start any independent run except the first with a
call to 'RandStartArb'. The clock values obtained by that routine are not
random, but are related to one another, and will be identical if separate runs
occur in rapid succession.
LOAD BEGINNING SEED
This routine looks for a file containing the next seed and, if one is present
in the current directory, starts with that seed. If none is present, then an
arbitrary seed is taken via 'RandStartArb'.
ENTRY: 's' points to a file name containing the starting seed, or is null if
the default file name is to be used.
EXIT: 'RandStartNext' contains a result code.
0 No starting seed was on file. An arbitrary seed has been used instead.
1 A starting seed was retrieved from the file.
*/
#include
static char rnd[] = "nextseed.rnd";
static char *file = rnd;
int RandStartNext(char *s)
{
unsigned long randseed; FILE *pf;
if(s) file = s; //Retrieve any passed file name.
pf = fopen(file, "r"); //If no previous seed exists,
if(pf==0) //start with an arbitrary one.
{ RandStartArb(0); return(0); }
fscanf(pf, "%lu", &randseed); fclose(pf); //Otherwise resume the sequence
RandStart(randseed); return(1); //where it left off.
}
/*
SAVE ENDING SEED
This routine saves the ending random number seed in a file that will be picked
upon a call to 'RandStartNext' the next time the program runs.
ENTRY: 's' points to a file name to receive the ending seed, or is null if
the default file name is to be used.
EXIT: The ending seed has been saved.
*/
RandStopNext(char *s)
{
unsigned long randseed, RandEndingSeed(); FILE *pf;
if(s) file = s; //Retrieve any passed file name.
unlink(file); //Delete any existing file.
pf = fopen(file, "w"); //Record the seed for the next
if(pf) //time the program runs.
{ fprintf(pf, "%lu\n", RandEndingSeed());
fclose(pf); }
}
/*----------------------------------------------------------------------------*
GENERATE INTEGER SEQUENCE
The actual random numbers are generated here as integers of 32 bits each,
created according to a certain nonlinear difference equation (a linear
congruential scheme). Each successive number 'x(n+1)' in the series is
generated from the preceding number 'x(n)' by the relation
'x(n+1)=a x(n)+c (mod m)'. The starting point 'x(0)' is called the seed. The
multiplier 'a' is chosen so that '0>= 1; }
return(h);
}
/* CLARENCE LEHMAN, JULY 1972 [Originally on the IBM System 360].
This code has been placed in the public domain by its author. If you distribute
it, please include all the comments. If you make any changes, please note them
below with your name or initials.
Modifications
1. Converted to 8080 language, May 1976 [CLL].
2. Converted to document format, December 1987 [CLL].
3. Converted to C, April 1988 [CLL].
4. Expanded for scientific use, June 1991 [CLL].
5. Ending random seed, March 1994 [CLL].
6. Description of the method modernized slightly, October 1994 [CLL].
7. Saving and restoring of ending seed, October 2001 [CLL].
8. Converted to ANSI C, January 2010 [CLL].
9. Multiple arbitrary starting seeds, April 2011 [CLL].
*/