diff options
Diffstat (limited to 'tex/context/base/thrd-ran.tex')
-rw-r--r-- | tex/context/base/thrd-ran.tex | 149 |
1 files changed, 87 insertions, 62 deletions
diff --git a/tex/context/base/thrd-ran.tex b/tex/context/base/thrd-ran.tex index 9372de5a1..ee3a7f6ac 100644 --- a/tex/context/base/thrd-ran.tex +++ b/tex/context/base/thrd-ran.tex @@ -1,70 +1,95 @@ -%D \module -%D [ file=thrd-ran, -%D version=1998.01.21, -%D title=\CONTEXT\ Support Macros, -%D subtitle=Random Number Generation, -%D author=Hans Hagen, -%D date=\currentdate, -%D copyright={PRAGMA / Hans Hagen \& Ton Otten}] -%C -%C This module is part of the \CONTEXT\ macro||package and is -%C therefore copyrighted by \PRAGMA. See licen-en.pdf for -%C details. +% 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. -\writestatus{loading}{Third Party Macros / Random Number Generation} +\newcount\randomi % the random number seed (while executing) +\global\randomi\catcode`\@ % scratch variable during definitions +\catcode`\@=11 -%D \macros -%D {getrandomcount, getrandomdimen, -%D getrandomfloat, getrandomnumber} -%D -%D This module load Donald Arseneau's generic file -%D \type{random.tex}. A small shell is needed because we -%D redefine some \TEX\ primitives. We also use different names -%D for the two generators and add an extra one. -%D -%D \starttypen -%D \getrandomcount \countregister {minimum} {maximum} -%D \getrandomdimen \dimenregister {minimum} {maximum} -%D \getrandomnumber \macroname {minimum} {maximum} -%D \getrandomfloat \macroname {minimum} {maximum} -%D \stoptypen -%D -%D Of course the file \type{random.tex} needs to be present. +\def\nextrandom{\begingroup + \ifnum\randomi<\@ne % 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 +} -\readfile{random.tex} - {\writestatus{loading}{Donald Arseneau's 'random.tex' (found)}} - {\writestatus{loading}{Donald Arseneau's 'random.tex' (not found)}} +\countdef\count@ii=2 % use only in boxes! +\ifx\@tempcnta\undefined \csname newcount\endcsname \@tempcnta \fi +\ifx\@tempcntb\undefined \csname newcount\endcsname \@tempcntb \fi -\ifx\nextrandom\undefined +\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\setrannum#1#2#3{#1=1 } - \def\setrandim#1#2#3{#1=1pt} +\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 +} -\else +\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 +} - \let\normalnextrandom=\nextrandom +\def\pointless{\expandafter\PoinTless\the} +{\catcode`p=12 \catcode`t=12 +\gdef\PoinTless#1pt{#1}} - \def\nextrandom% - {\bgroup - \let\time =\normaltime - \let\day =\normalday - \let\month=\normalmonth - \let\year =\normalyear - \normalnextrandom - \global\let\nextrandom=\normalnextrandom - \egroup} - -\fi - -\let\getrandomcount = \setrannum -\let\getrandomdimen = \setrandim - -\def\getrandomnumber#1#2#3% - {\getrandomcount{\scratchcounter}{#2}{#3}% - \edef#1{\the\scratchcounter}} - -\def\getrandomfloat#1#2#3% - {\getrandomdimen{\scratchdimen}{#2pt}{#3pt}% - \edef#1{\withoutpt\the\scratchdimen}} - -\endinput +\catcode`\@=\randomi +\global\randomi=0 +\newcount\ranval |