thrd-ran.mkii / last modification: 2020-01-30 14:15
% Since we cannot be sure that this file is available at any
% system, we have copied the original in this file. These
% macros are encapsulates and extended in supp-ran.tex.
%
% This module is slightly recoded to bring it more in tune
% with \CONTEXT's scratch registers and protection mechanisms.

% RANDOM.TEX v.1 (Donald Arseneau)
% Generating "random" numbers in TeX.
%
% Random integers are generated in the range 1 to 2147483646 by the
% macro \nextrandom.  The result is returned in the counter \randomi.
% Do not change \randomi except, perhaps, to initialize it at some
% random value.  If you do not initialize it, it will be initialized
% using the time and date.  (This is a sparse initialization, giving
% fewer than a million different starting values, but you should use
% other sources of numbers if they are available--just remember that
% most of the numbers available to TeX are not at all random.)
%
% The \nextrandom command is not very useful by itself, unless you
% have exactly 2147483646 things to choose from.  Much more useful
% is the \setrannum command which sets a given counter to a random
% value within a specified range.  There are three parameters:
% \setrannum {<counter>} {<minimum>} {<maximum>}.  For example, to
% simulate a die-roll: \setrannum{\die}{1}{6} \ifcase\die... .
%
% If you need random numbers that are not integers, you will have to
% use dimen registers and \setrandimen.  For example, to set a random
% page width: \setrandimen \hsize{3in}{6.5in}.  The "\pointless" macro
% will remove the "pt" that TeX gives so you can use the dimensions
% as pure `real' numbers.  In that case, specify the range in pt units.
% For example,
%
%   \setrandimen\answer{2.71828pt}{3.14159pt}
%   The answer is \pointless\answer.
%
% The random number generator is the one by Lewis, Goodman, and Miller
% (1969) and used as "ran0" in "Numerical Recipies" using Schrage's
% method for avoiding overflows.  The multiplier is 16807 (7^5), the
% added constant is 0, and the modulus is 2147483647 (2^{31}-1).  The
% range of integers generated is 1 - 2147483646.  A smaller range would
% reduce the complexity of the macros a bit, but not much--most of the
% code deals with initialization and type-conversion.  On the other hand,
% the large range may be wasted due to the sparse seed initialization.

% original code
%
% \newcount\randomi % the random number seed (while executing)
% \global\randomi\catcode`\@  % scratch variable during definitions
% \catcode`\@=11
%
% \def\nextrandom{\begingroup
%  \ifnum\randomi<\plusone % then initialize with time
%     \global\randomi\time
%     \global\multiply\randomi388 \global\advance\randomi\year
%     \global\multiply\randomi31 \global\advance\randomi\day
%     \global\multiply\randomi97 \global\advance\randomi\month
%     \message{Randomizer initialized to \the\randomi.}%
%     \nextrandom \nextrandom \nextrandom
%  \fi
%  \count@ii\randomi
%  \divide\count@ii 127773 % modulus = multiplier * 127773 + 2836
%  \count@\count@ii
%  \multiply\count@ii 127773
%  \global\advance\randomi-\count@ii % random mod 127773
%  \global\multiply\randomi 16807
%  \multiply\count@ 2836
%  \global\advance\randomi-\count@
%  \ifnum\randomi<\z@ \global\advance\randomi 2147483647\relax\fi
%  \endgroup
% }
%
% \countdef\count@ii=2 % use only in boxes!
% \ifx\@tempcnta\undefined \csname newcount\endcsname \@tempcnta \fi
% \ifx\@tempcntb\undefined \csname newcount\endcsname \@tempcntb \fi
%
% \def\setrannum#1#2#3{% count register, minimum, maximum
%  \@tempcnta#3\advance\@tempcnta-#2\advance\@tempcnta\@ne
%  \@tempcntb 2147483645 %  =  m - 2  =  2^{31} - 3
%  \divide\@tempcntb\@tempcnta
%  \getr@nval
%  \advance\ranval#2\relax
%  #1\ranval
% }
%
% \def\setrandim#1#2#3{% dimen register, minimum length, maximum length
%  \dimen@#2\dimen@ii#3\relax
%  \setrannum\ranval\dimen@\dimen@ii
%  #1\ranval sp\relax
% }
%
% \def\getr@nval{% The values in \@tempcnta and \@tempcntb are parameters
%  \nextrandom
%  \ranval\randomi \advance\ranval\m@ne \divide\ranval\@tempcntb
%  \ifnum\ranval<\@tempcnta\else \expandafter\getr@nval \fi
% }
%
% %D The next macro is not needed in \CONTEXT, which provides
% %D the \type {\withoutpt} macro.
% %D
% %D \starttyping
% %D \def\pointless{\expandafter\PoinTless\the}
% %D {\catcode`p=12 \catcode`t=12 \gdef\PoinTless#1pt{#1}}
% %D \stoptyping
%
% \catcode`\@=\randomi
% \global\randomi=0
% \newcount\ranval

% the recoded version, using \CONTEXT\ methods and variables;
% the magic is kept untouched

\unprotect

\newcount\randomi % the random number seed (while executing)
\newcount\ranval

\ifx\m!systems\undefined \def\m!systems{systems} \fi

\def\nextrandom
  {\begingroup
   \ifnum\randomi<\plusone % then initialize with time
     \global\randomi\time
     \global\multiply\randomi388 \global\advance\randomi\year
     \global\multiply\randomi 31 \global\advance\randomi\day
     \global\multiply\randomi 97 \global\advance\randomi\month
     \writestatus\m!systems{randomizer starts with \the\randomi}%
     \nextrandom \nextrandom \nextrandom
   \fi
   \!!countd\randomi
   \divide\!!countd 127773 % modulus = multiplier * 127773 + 2836
   \!!countc\!!countd
   \multiply\!!countd 127773
   \global\advance\randomi-\!!countd % random mod 127773
   \global\multiply\randomi 16807
   \multiply\!!countc 2836
   \global\advance\randomi-\!!countc\relax
   \ifnum\randomi<\zerocount
     \global\advance\randomi 2147483647
   \fi
   \endgroup}

\def\setrannum#1#2#3% count register, minimum, maximum
  {\!!counta#3%
   \advance\!!counta-#2%
   \advance\!!counta\plusone
   \!!countb 2147483645 %  =  m - 2  =  2^{31} - 3
   \divide\!!countb\!!counta
   \getr@nval
   \advance\ranval#2%
   #1\ranval}

\def\setrandim#1#2#3% dimen register, minimum length, maximum length
  {\!!dimenc#2%
   \!!dimend#3%
   \setrannum\ranval\!!dimenc\!!dimend
   #1\ranval\s!sp\relax} % \s!sp not needed

\def\getr@nval % The values in \!!counta and \!!countb are parameters
  {\nextrandom
   \ranval\randomi
   \advance\ranval\minusone
   \divide\ranval\!!countb
   \ifnum\ranval<\!!counta \else
     \expandafter\getr@nval
   \fi}

\protect \endinput