home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C!T ROM 2
/
ctrom_ii_b.zip
/
ctrom_ii_b
/
PROGRAM
/
PASCAL
/
PAS_0593
/
CYC-RAND.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1993-05-30
|
3KB
|
79 lines
{─ Fido Pascal Conference ────────────────────────────────────────────── PASCAL ─
Msg : 220 of 288
From : Dj Murdoch 1:221/177.40 23 Feb 92 19:06
To : All
Subj : Running random numbers backwards
────────────────────────────────────────────────────────────────────────────────
I've often thought that it would be handy to make the TP random number generator
back up. For example, if you call randomize, and then your program bombs, it's
sometimes hard to make the error repeat itself. If you could just back up to
just before the error, you might be able to figure out what's going wrong.
If you can predict the problem, probably the best way is just to save Randseed
every now and then. If you restore it to an earlier value, then the sequence of
random numbers that are generated will repeat exactly.
However, just for fun, I decided today to work out the method of actually
running it backwards. That is, given no saved information, the routine below
can back up the random number generator any number of steps.
I also wrote down the forward algorithm, for completeness and to show it
explicitly. It would be faster just to call Random(2) several times, but
perhaps less enlightening.
Anyways, the first procedure below is the result. It lets you cycle the random
number generator either forwards or backwards. A demonstration follows, in
which 5 random numbers are generated, then generated again in reverse order.}
{ Demonstration program to show how the TP 6.0 random number generator
updates System.Randseed. Allows the seed to be cycled backwards. }
{ Written for the public domain by D.J. Murdoch, February 1992. }
procedure CycleRandseed(cycles:integer);
{ For cycles > 0, mimics cycles calls to the TP random number generator.
For cycles < 0, backs it up the given number of calls. }
var
i : integer;
begin
if cycles > 0 then
for i := 1 to cycles do
system.randseed := system.randseed*134775813 + 1
else
for i := -1 downto cycles do
system.randseed := (system.randseed-1)*(-649090867);
end;
var
i : integer;
begin
randomize;
writeln('Forwards:');
for i:=1 to 5 do
writeln(random);
writeln('Backwards:');
for i:=1 to 5 do
begin
CycleRandseed(-1); { Back to previous value }
writeln(random); { Show it }
CycleRandseed(-1); { Back up over it again }
end;
end.
By the way, the magic numbers in the CycleRandseed routine were kind of fun to
work out. The TP RTL includes code optimized for multiplying by 134775813, but
doesn't give the -649090867 number required to go backwards.
To get that, I had a race with my 486-33. I set it trying all possible longint
values until it found one which, when multiplied by 134775813 would give 1. In
the meantime, I tried to work out a smarter way of solving the equation
134775813 * X = 1 mod 2^32
for X.
I managed to work out a neat way to do it in a spreadsheet, so I won the race.
Anyone interested in puzzles should try it.