previous next top contents index framed top this page unframed
The standard MAINSAIL pseudorandom number generator is the MODULE $ranMod of the CLASS $ranCls. The declarations of $ranCls and $ranMod are shown in Figure 29–1.
Figure 29–1. $ranCls and $ranMod
CLASS $ranCls (
LONG INTEGER
PROCEDURE $rand (OPTIONAL LONG INTEGER
loBound,hiBound);
INTEGER
PROCEDURE $rand (INTEGER loBound,hiBound);
PROCEDURE $initRand (LONG INTEGER newX;
OPTIONAL LONG INTEGER newX2);
LONG INTEGER
PROCEDURE $sRand (OPTIONAL LONG INTEGER
loBound,hiBound);
INTEGER
PROCEDURE $sRand (INTEGER loBound,hiBound);
PROCEDURE $initsRand (LONG INTEGER ix);
);
MODULE($ranCls) $ranMod;
Each of the PROCEDUREs $rand and $sRand returns the next value produced by a pseudorandom number generator. The two generators are different. $initRand specifies a seed for the $rand generator, and $initsRand specifies a seed for the $sRand generator. Both pseudorandom number generators are derived from Volume 2 of Donald Knuth's The Art of Computer Programming (second edition. Reading, Massachusetts: Addison-Wesley Publishing Company, 1973).
The $rand generator uses a linear congruence algorithm:
xn + 1 = (xn * a + c) MOD m
c = 6364136223846793005
m = 264
where the xi are successive values computed by $rand; $rand returns the high-order (most random) 31 bits of xi on each call. When loBound and hiBound are unspecified, the values returned by $rand range from 0L to 2147483647L. The generator has a period of 264.
The $srand generator uses the “subtractive method” generator algorithm presented in Section 3.6 of The Art of Computer Programming. When loBound and hiBound are unspecified, it returns values in the range 0L to 999999999L (109 - 1). The period is probably quite long.
The properties of the $rand generator are somewhat better understood mathematically than those of the $sRand generator. The $rand generator is therefore, in some sense, “more certainly” random than the $sRand generator; however, it executes more slowly. For most practical purposes, either generator is satisfactorily random.
The OPTIONAL parameters to $rand and $sRand, loBound and hiBound, specify lower and upper bounds (inclusive) on the pseudorandom numbers to return. If hiBound is less than or equal to loBound, the bounds are ignored, and $rand and $sRand return numbers in the ranges 0L to 2147483647L and 0L to 999999999L, respectively. Note that it is possible to get a similar effect to ${s}Rand(lb,ub) by doing:
lb + ${s}Rand MOD (ub - lb + 1L)
However, the values returned by this expression will not be evenly distributed (although where ub - lb is small, the deviation from an even distribution is also small). The numbers produced by $rand and $sRand where the bounds are specified do not have this problem.
Example 29–2. Use of $rand and $sRand
| INTEGER i; LONG INTEGER ii; ii := $rand; # Return 0L LEQ $rand LEQ 2147483647L ii := $sRand; # Return 0L LEQ $sRand LEQ 999999999L ii := $rand(1L,5L); # Return 1L LEQ $rand LEQ 5L ii := $sRand(-10L,10L); # Return -10L LEQ $sRand LEQ 10L i := $rand(0,2); # Return 0 LEQ $rand LEQ 2 i := $sRand(1,6); # Return 1 LEQ $sRand LEQ 6 |
The parameters to $initRand may be any nonnegative LONG INTEGERs (although only the low-order 28 bits of each are examined; i.e., the numbers are taken modulo 228). The two parameters together constitute a single 56-bit seed.
A convenient way to use $initRand to set the seed depending on the current second is:
$initRand($date,$time)
The single parameter to $initsRand may be any number. The seed is coerced to the range 0L to 999999999L with:
ix := abs(ix) MOD 1000000000L;
This makes it convenient to initialize the $sRand generator with a value that could possibly be negative, e.g.:
$initsRand($date - $time);
Applications that require that the same sequence of pseudorandom numbers always be produced from a given seed (perhaps for debugging purposes) should create a private copy of the pseudorandom number generator by declaring a POINTER to $ranCls and initializing the POINTER by calling new:
POINTER($ranCls) p;
.
.
.
p := new($ranMod);
The POINTER p may then be used to call PROCEDUREs in the private copy of $ranMod, e.g.:
li := p.$rand
or:
li := p.$sRand
The common (bound) copy of $ranMod may be in use simultaneously by a number of MODULEs. If it is not important to an application that the same sequence of pseudorandom numbers be produced on each execution, then it may share the bound copy of $ranMod, and need not use a direct POINTER to call the PROCEDUREs in $ranMod, e.g.:
li := $rand
or:
li := $sRand
XIDAK reserves the right to add new fields to $ranCls or to add new OPTIONAL parameters to the PROCEDUREs in $ranCls.
MAINSAIL Utilities User's Guide, Chapter 29