<> <> <> <> <> DIRECTORY Basics USING [CARD], Random USING [RandomStream, RandomStreamRep], PrincOpsUtils USING [GetClockPulses]; RandomImpl: CEDAR MONITOR LOCKS pd USING pd: PrivateData IMPORTS PrincOpsUtils EXPORTS Random = { OPEN Basics, Random; BadInterval: PUBLIC ERROR = CODE; <> defaultSeed: INT = 1354117939; <> numCalls: INTEGER = 3; <> <> <<>> PrivateData: TYPE = REF PrivateDataRep; PrivateDataRep: TYPE = MONITORED RECORD [ a: ARRAY Index OF INT, <> p: Index, <> maxRand: CARD <> ]; Index: TYPE = CARDINAL [0..HighLimit]; LowIndex: TYPE = CARDINAL [1..LowLimit]; HighIndex: TYPE = CARDINAL (LowLimit..HighLimit]; HighLimit: CARDINAL = 55; LowLimit: CARDINAL = 24; <> Create: PUBLIC PROC [range, seed: INT] RETURNS [rs: RandomStream] = { <0, seed is scaled if necessary and then used; if seed<0, a seed value is derived from the system clock. In any case, the seed value actually used (after scaling) is the INT value returned by Init. Avoid small values of the range parameter; the intent of range is to allow the same sequence to be produced different machines.>> pd: PrivateData _ NEW[PrivateDataRep]; rs _ NEW[RandomStreamRep _ [seed: seed, data: pd]]; { minSeed: INT; maxSeed: INT; IF range <= 0 THEN pd.maxRand _ LOOPHOLE[range _ LAST[INT], CARD] + 1 ELSE pd.maxRand _ range; minSeed _ range/10; maxSeed _ range - minSeed; IF seed<0 THEN seed _ PickSeed[]; IF seed=0 THEN seed _ defaultSeed; <> WHILE seedmaxSeed DO seed _ seed/3 ENDLOOP; rs.seed _ seed; <> }; { <> <<(-1)**(i-1) * (F(i) - seed*F(i-1)) MOD pd.maxRand, 0> <<(where F(i) denotes the i-th Fibonacci number) throughout the rest of a. Then the generating procedure RandomGen is called, numCalls times, to make things sufficiently random.>> g: INT _ 1; gPrev: INT _ pd.a[HighLimit] _ seed; FOR i: CARDINAL IN [1..HighLimit) DO p: Index _ (21*i) MOD HighLimit; gSave: INT _ pd.a[p] _ g; g _ gPrev-g; gPrev _ gSave; IF g<0 THEN g _ g + pd.maxRand; ENDLOOP; THROUGH [1..numCalls) DO RandomGen[pd]; ENDLOOP; <> pd.p _ 1; }; }; NextInt: PUBLIC PROC [rs: RandomStream] RETURNS [INT] = { <> IF rs = NIL THEN rs _ defaultStream; WITH rs.data SELECT FROM pd: PrivateData => RETURN [NextIntEntry[pd]]; ENDCASE => ERROR; }; NextIntEntry: ENTRY PROC [pd: PrivateData] RETURNS [INT] = { <> p: Index _ pd.p - 1; IF p=0 THEN { RandomGen[pd]; p _ HighLimit }; RETURN[pd.a[pd.p _ p]]; }; RandomGen: PROC [pd: PrivateData] = { <> maxRand: CARD _ pd.maxRand; FOR i: LowIndex IN LowIndex DO g: INT _ pd.a[i] - pd.a[i+(HighLimit-LowLimit)]; IF g<0 THEN g _ g + maxRand; pd.a[i] _ g; ENDLOOP; FOR i: HighIndex IN HighIndex DO g: INT _ pd.a[i] - pd.a[i-LowLimit]; IF g<0 THEN g _ g + maxRand; pd.a[i] _ g; ENDLOOP; }; ChooseInt: PUBLIC PROC [rs: RandomStream, min, max: INT] RETURNS [INT--[min..max]--] = { intervalLen: CARD; IF min > max THEN ERROR BadInterval; intervalLen _ LOOPHOLE[max - min, CARD] + 1; IF rs = NIL THEN rs _ defaultStream; WITH rs.data SELECT FROM pd: PrivateData => { IF (intervalLen <= 0) OR (intervalLen > pd.maxRand) THEN ERROR BadInterval; DO <> r: CARD _ NextIntEntry[pd]; rem: CARD _ r; IF rem >= intervalLen THEN { <> rem _ r MOD intervalLen; IF (r - rem) > (pd.maxRand-intervalLen) THEN LOOP; }; RETURN[min + rem]; ENDLOOP; }; ENDCASE => ERROR; }; PickSeed: PROC [] RETURNS [INT] = TRUSTED { <> RETURN[ABS[LOOPHOLE[PrincOpsUtils.GetClockPulses[],INT]]]; }; defaultStream: RandomStream _ Create[range: 0, seed: 0]; }. CHANGE LOG Created by MBrown on July 2, 1979 Changed by MBrown on May 2, 1980 11:07 PM <> <> <> Changed by MBrown on September 25, 1980 9:41 AM <> Changed by MBrown on December 6, 1980 9:59 PM <> Changed by MBrown on March 9, 1982 10:37 am <> Changed by MBrown on June 8, 1982 10:59 am <> <> Changed by MBrown on August 27, 1982 3:09 pm <> Changed by Taft on June 9, 1983 3:48 pm <> <> <> <<, }>> <<>> <<>> <<>> <<>>