summaryrefslogtreecommitdiff
path: root/tex/context/base/mkii/thrd-ran.mkii
blob: 276a4f6249fdc5261e13e5858328ddc65c50a354 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
% 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