home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
modula2
/
library
/
queuem2
/
unifrng.mod
< prev
next >
Wrap
Text File
|
1989-08-02
|
8KB
|
223 lines
(* source: h:\modula\code\random\UnifRNG.MOD v1.0b revised: 88.06.16
author: G.Greene, AGCS D/429 (NS/TS), 312/681-7783 created: 88.06.09
function:
This is the implementation code for a module which provides generators of
uniformly-distributed pseudo-random variates. The primary procedure --
invoked, directly or indirectly, by all other random number generators --
provides reals in the half-open interval [0,1). A specialized variant of
this generates values in the interval (0, 1), for applications wherein
zero values are not acceptable. There are also discrete-uniform, general
continuous rectangular, and Pareto random number generators. Procedures
are provided for reading and setting the random number seed value.
history:
88.06.09 1.0a initial release.
88.06.16 1.0b added general continuous rectangular distribution.
*)
IMPLEMENTATION MODULE UnifRNG;
FROM SYSTEM IMPORT (*PROC*) WORD;
FROM MATHLIB IMPORT (*PROC*) Log, Exp;
VAR
RandomInteger: LONGINT;
(* Return as the function value a REAL equivalent of the parameter value,
which is expected to be a double-word value (such as LONGCARD).
*)
PROCEDURE Convert (
Value: ARRAY OF WORD ): LONGREAL;
BEGIN
RETURN LONGREAL ( CARDINAL ( Value [ 1 ] ) ) * 65536.0 +
LONGREAL ( CARDINAL ( Value [ 0 ] ) );
END Convert;
(* Return as the function value a LONGREAL value, uniformly distributed in
the interval [0,1).
*)
PROCEDURE UniformVariate ( ): LONGREAL;
CONST
MultFactor = 1566083941;
TwoTo32nd = 4294967296.0;
BEGIN
RandomInteger := RandomInteger * MultFactor + 1;
RETURN Convert ( RandomInteger ) / TwoTo32nd;
END UniformVariate;
(* [2]
source: h:\modula\code\random\UnifRNG.MOD v1.0b revised: 88.06.16 *)
(* Since there is a chance, albeit minute, that the standard uniform random-
number generator will return a zero value, and since a zero value will
result in an error when used in some applications (particularly other
random variate generators), we provide this function that is guaranteed
not to yield a zero value. Resulting values are in the interval ( 0, 1 ).
*)
PROCEDURE NonzeroUniformVariate ( ): LONGREAL;
VAR
UniformValue: LONGREAL;
BEGIN
REPEAT (* nearly always once, never more than twice *)
UniformValue := UniformVariate ( )
UNTIL UniformValue > 0.0;
RETURN UniformValue
END NonzeroUniformVariate;
(* Return as the function value a discrete uniform variate in the range
specified by the parameters. The parameters are supposed to be the low
and high ends of the range of possible values, respectively, but the
range limits can be presented in either order. (Reversing the order
results in an inverting of the returned values, but the distribution
will still be in the proper range, and no less random.) The maximum
number of discrete values that can be generated is MaxInt (32767), thus
the value abs ( HighValue - LowValue + 1 ) must not exceed MaxInt
(for example, parameters ( -20000, 20000 ) would not be acceptable).
Implementation note: The value of Range will "normally" be positive
(i.e., when the parameters are presented in the "proper" order). Its
value is number of discrete values that may be generated (an inclusive
count of the range). If the parameter order is inverted, Range will be
negative, but its absolute value will remain the same. The absolute
value of UniformVariate ( ) * Range will be in the interval [0, Range).
The result of the trunc function will be a integer with absolute value
in the interval [0, Range-1]. This means that for the normal case, the
interval will be [0, HighValue-LowValue]; for the reverse case, it will
be [HighValue-LowValue, 0]. We thus have, for the two possible orders
of parameter, the function range:
normal: [ LowValue + 0 , LowValue + ( HighValue - LowValue )] ==
[ LowValue, HighValue ]
reverse: [ LowValue + ( HighValue - LowValue ) , LowValue + 0 ] ==
[ HighValue, LowValue ]
*)
(* [3]
source: h:\modula\code\random\UnifRNG.MOD v1.0b revised: 88.06.16 *)
PROCEDURE DiscreteVariate (
(*in*) LowValue,
(*in*) HighValue: INTEGER ): INTEGER;
VAR
LoReal,
HiReal,
Range: LONGREAL;
BEGIN
LoReal := LONGREAL ( LowValue );
HiReal := LONGREAL ( HighValue );
IF HighValue >= LowValue
THEN Range := HiReal - LoReal + 1.0;
ELSE Range := HiReal - LoReal - 1.0;
END;
RETURN LowValue + INTEGER ( UniformVariate ( ) * Range );
END DiscreteVariate;
(* Return as the function value a general continuous rectangular variate in
the range specified by the parameters. The parameters are supposed to be
the low and high ends of the range of possible values, respectively, but
the range limits can be presented in either order. (Reversing the order
results in an inverting of the returned values, but the distribution will
be no less random.) Resulting values are confined to the interval
[ LowValue, HighValue ) for the case of parameters in normal order, and
to ( HighValue, LowValue ] for inverted parameters. This can be used to
get special cases: for uniform variates in the interval ( 0, 1 ] invoke
this procedure as RectangularVariate ( 1.0, 0.0 ).
*)
PROCEDURE RectangularVariate (
(*in*) LowValue,
(*in*) HighValue: REAL ): LONGREAL;
BEGIN
RETURN LONGREAL ( LowValue ) +
UniformVariate ( ) * LONGREAL ( HighValue - LowValue );
END RectangularVariate;
(* [4]
source: h:\modula\code\random\UnifRNG.MOD v1.0b revised: 88.06.16 *)
(* Return as the function value a Pareto variate with strictly positive
shape parameter specified by the function parameter. A negative actual
parameter is taken as its absolute value; a zero actual parameter is
taken as 1. The formula for the Pareto variate is (1/U) ** (1/Shape),
where U is a (non-zero) uniform variate, and ** is the FORTRAN
exponentiation operator.
*)
PROCEDURE ParetoVariate (
(*in*) Shape: REAL ): LONGREAL;
VAR
Exponent: LONGREAL;
BEGIN
IF Shape = 0.0
THEN Exponent := 1.0
ELSE Exponent := LONGREAL ( 1.0 / ABS ( Shape ) );
END;
RETURN Exp ( Log ( 1.0 / LONGREAL ( NonzeroUniformVariate ( ) ) ) * Exponent )
END ParetoVariate;
(* Set the initial value of the seed to use for generating random variates.
*)
PROCEDURE SetSeedValue (
(*in*) ValueToSet: LONGCARD );
BEGIN
RandomInteger := ValueToSet
END SetSeedValue;
(* Get the current value of the seed to use for generating random variates.
This value can be saved to continue a sequence, and later restored using
the SetSeedValue procedure, above.
*)
PROCEDURE GetSeedValue (
(*out*) VAR CurrentSeed: LONGCARD );
BEGIN
CurrentSeed := RandomInteger
END GetSeedValue;
BEGIN (* initialization *)
RandomInteger := 314159265;
END UnifRNG.