IMPLEMENTATION MODULE RndBox;
FROM SYSTEM IMPORT TSIZE;
FROM Storage IMPORT ALLOCATE, DEALLOCATE;
FROM RndUniform IMPORT RndUniform,
NewRndUniform, DisposeRndUniform,
RndUniformNext, LastUniform;
FROM MathLib IMPORT sqrt, ln;
TYPE
RndBox = POINTER TO RndBoxRecord;
RndBoxRecord = RECORD
random : RndUniform;
x, y, product, first, second : REAL;
available : BOOLEAN;
END;
PROCEDURE NewRndBox() : RndBox;
VAR Result : RndBox;
BEGIN
ALLOCATE(Result, TSIZE(RndBoxRecord));
Result^.random := NewRndUniform();
Result^.available := FALSE;
RETURN(Result);
END NewRndBox;
PROCEDURE DisposeRndBox(self: RndBox);
BEGIN
DisposeRndUniform(self^.random);
DISPOSE(self);
END DisposeRndBox;
PROCEDURE RandUniv(self: RndBox) : REAL;
VAR
Result : REAL;
BEGIN
RndUniformNext(self^.random);
Result := LastUniform(self^.random);
RETURN(Result);
END RandUniv;
PROCEDURE RandPoint(self: RndBox);
VAR
x, y : REAL;
BEGIN
REPEAT
x := RandUniv(self) * 2.0 - 1.0;
y := RandUniv(self) * 2.0 - 1.0 ;
self^.product := x * x + y * y;
UNTIL self^.product <= 1.0;
self^.x := x;
self^.y := y;
END RandPoint;
PROCEDURE Generate(self: RndBox);
VAR
p : REAL;
BEGIN
RandPoint(self);
p := sqrt((-2.0 * ln(self^.product))/
self^.product);
self^.available := TRUE;
self^.first := p * self^.x;
self^.second := p * self^.y;
END Generate;
PROCEDURE RndBoxNext(self: RndBox);
BEGIN
IF self^.available
THEN self^.available := FALSE;
ELSE Generate(self);
END;
END RndBoxNext;
PROCEDURE LastGaussian(self: RndBox) : REAL;
VAR
Result : REAL;
BEGIN
IF self^.available
THEN Result := self^.first;
ELSE Result := self^.second;
END;
RETURN(Result);
END LastGaussian;
END RndBox. |