home *** CD-ROM | disk | FTP | other *** search
- -- ++
- -- A superior Random Number Generator.
- -- This generator is one of the class discovered by Marsaglia and Zaman
- -- and printed in .EXE (Nov.1992).
- -- The generator uses the subtractive method and has a period of just
- -- under 2^1178 or 10^354. The generator is
- -- Xn = X[n-24] - X[n-37] - b) MOD 2^32
- -- where b is the borrow from the previous iteration.
- -- --
-
- with Calendar;
- package body Random is
-
- -- constants alternatives
- NK : constant := 37; -- 21
- NJ : constant := 24; -- 6
- NV : constant := 14; -- 8
-
- -- random number array and pointer
- type Cache_Range is range 0 .. NK - 1;
- Cache : array ( Cache_Range ) of Integer;
- Cache_Ptr : Cache_Range := Cache_Range'First;
- Borrow : Integer := 0;
-
- function Random return Integer is
- K : Cache_Range := NK - NJ;
- Temp, Diff : Integer;
- begin
-
- if Cache_Ptr < Cache_Range'Last then
- Cache_Ptr := Cache_Ptr + 1;
- return Cache(Cache_Ptr);
- end if;
-
- Cache_Ptr := Cache_Range'First;
-
- for I in Cache_Range loop
- Temp := Cache(K);
- Diff := Cache(I);
- if Cache(I) > 0 then
- if Integer'First + Cache(I) + Borrow > Temp then -- catch -ve overflow
- Temp := Temp + Integer'Last;
- end if;
- elsif Cache(I) < 0 then
- if Integer'Last + Cache(I) + Borrow < Temp then -- catch +ve overflow
- Temp := Temp + Integer'First;
- end if;
- end if;
- Diff := Temp - Cache(I) - Borrow;
- if Diff < Temp then
- Borrow := 0;
- elsif Diff > Temp then
- Borrow := 1;
- end if;
- Cache(I) := Diff;
- if K < Cache_Range'Last then
- K := K + 1;
- else
- K := 0;
- end if;
- end loop;
-
- return Cache(Cache_Ptr);
- end Random;
-
- procedure Initialise is
- Seed : Integer := Integer(Calendar.Seconds ( Calendar.Clock ));
- Index : Cache_Range;
- M : Integer := 1;
- begin
-
- Borrow := 0;
- Cache_Ptr := Cache_Range'First;
- Cache(Cache_Ptr) := Seed;
-
- -- fill initialisation vector
- for I in 1 .. Cache_Range'Last loop
- Index := (NV * I ) mod NK;
- Cache(Index) := M;
- if M > 0 then
- if Integer'First + M > Seed then -- catch -ve overflow
- Seed := Seed + Integer'Last;
- end if;
- elsif M < 0 then
- if Integer'Last + M < Seed then -- catch +ve overflow
- Seed := Seed + Integer'First;
- end if;
- end if;
- M := Seed - M;
- Seed := Cache(Index);
- end loop;
-
- -- warm up the generator
- for I in 1 .. 1000 loop
- M := Random;
- end loop;
-
- end Initialise;
-
- begin
-
- -- initialise the random numbers
- Initialise;
-
- end Random;
-