% File : RANDOM.PL
% Author : Allen Van Gelder, Stanford
% Updated: 21 February 1984
% Purpose: Random number package.
% rannum produces a random non-negative integer whose low bits are not
% all that random, so it should be scaled to a smaller range in general.
% The integer is in the range 0 .. 2^w - 1,
% where w is the word size less the sign bit, e.g., 17 for DEC-10,
% and 15 or 31 for VAX and most IBM.
%
% ranunif produces a uniformly distributed non-negative random integer over
% a caller-specified range. If range is R, the result is in 0 .. R-1.
%
% ranstart must be called before the first use of rannum or ranunif,
% and may be called later to redefine the seed.
% ranstart/0 causes a built-in seed to be used.
% ranstart(N), N an integer, varies this, but the same N always
% produces the same sequence of numbers.
%
% According to my reading of Knuth, Vol. 2, this generator has period
% 2^(w+1) and potency (w+1)/2, i.e., 8, 9, or 16 in practice. Knuth says
% potency should be at least 5, so this looks more than adequate.
% Its drawback is the lack of randomness of low-order bits.
:- public
ranstart/0,
ranstart/1,
rannum/1,
ranunif/2.
:- mode
ranstart(+),
rannum(-),
ranunif(+, -).
ranstart :-
ranstart(245).
ranstart(N) :-
Wsize is 17, % bits available other than sign-bit
Incr is (108 << (Wsize-8)) + 1, % per Knuth, v.2 p.78
Mult is 1965, % OK for 15-17 Wsize
Prev is Mult * (8 * N + 5) + Incr,
recorda(ranState, ranState(Mult,Prev,Wsize,Incr), _).
rannum(Raw) :-
recorded(ranState, ranState(Mult,Prev,Wsize,Incr), Ref),
Curr is Mult * Prev + Incr,
erase(Ref),
recorda(ranState, ranState(Mult,Curr,Wsize,Incr), _),
( Curr > 0, Raw = Curr
| Curr < 0, Raw is Curr + (1< 0,
recorded(ranState, ranState(Mult,Prev,Wsize,Incr), Ref),
Curr is Mult * Prev + Incr,
erase(Ref),
recorda(ranState, ranState(Mult,Curr,Wsize,Incr), _),
( Curr > 0, Raw = Curr
| Curr < 0, Raw is Curr + (1<> Wsize.