summaryrefslogtreecommitdiff
path: root/texmf-dist/source/latex/rangen/rangen.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'texmf-dist/source/latex/rangen/rangen.dtx')
-rw-r--r--texmf-dist/source/latex/rangen/rangen.dtx1988
1 files changed, 1988 insertions, 0 deletions
diff --git a/texmf-dist/source/latex/rangen/rangen.dtx b/texmf-dist/source/latex/rangen/rangen.dtx
new file mode 100644
index 00000000..637775f9
--- /dev/null
+++ b/texmf-dist/source/latex/rangen/rangen.dtx
@@ -0,0 +1,1988 @@
+%\iffalse
+%<*copyright>
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Rangen.sty package, 2016-02-19 %%
+%% Copyright (C) 1999-2016 D. P. Story %%
+%% dpstory@uakron.edu %%
+%% %%
+%% This program can redistributed and/or modified under %%
+%% the terms of the LaTeX Project Public License %%
+%% Distributed from CTAN archives in directory %%
+%% macros/latex/base/lppl.txt; either version 1 of the %%
+%% License, or (at your option) any later version. %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%</copyright>
+%<package>\NeedsTeXFormat{LaTeX2e}[1997/12/01]
+%<package>\ProvidesPackage{rangen}
+%<package> [2014/10/17 v1.4 Rangen: Generate Random Questions (dps)]
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage[colorlinks,hyperindex]{hyperref}
+%\pdfstringdefDisableCommands{\let\\\textbackslash}
+%\EnableCrossrefs \CodelineIndex
+\begin{document}
+ \GetFileInfo{rangen.sty}
+% \settowidth{\oddsidemargin}{0pt}%
+% \setlength{\evensidemargin}{0pt}
+% \setlength{\marginparsep}{0pt}
+% \setlength{\marginparwidth}{0pt}
+% \setlength\textwidth{6in}
+% \hoffset=.5in
+% \hsize = 6in
+ \title{\textsf{Rangen}\texorpdfstring{\\}{:} Random Generation of Integer, Rational, and Real Numbers with
+ Applications to the \texttt{exercise}, \texttt{quiz}, and \texttt{shortquiz} environments of \textsf{Exerquiz}}
+ \author{D. P. Story\\
+ Email: \texttt{dpstory@uakron.edu}}
+ \date{processed \today}
+ \maketitle
+ \tableofcontents
+ \let\Email\texttt
+ \DocInput{rangen.dtx}
+ \PrintIndex
+\end{document}
+%</driver>
+% \fi
+% \MakeShortVerb{|}
+% \StopEventually{}
+%
+% \DoNotIndex{\def,\edef,\gdef,\xdef,\global,\long,\let}
+% \DoNotIndex{\expandafter,\string,\the,\ifx,\else,\fi}
+% \DoNotIndex{\csname,\endcsname,\relax,\begingroup,\endgroup}
+% \DoNotIndex{\DeclareTextCommand,\DeclareTextCompositeCommand}
+% \DoNotIndex{\space,\@empty,\special}
+%
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+% \section{Introduction}
+%
+% This package provides some commands for creating randomly generated integers, rational,
+% and real numbers. There are options for specifying constraints on the generation of the numbers.
+% Companion JavaScript functions are developed to use these random numbers as part of a
+% question in a \texttt{shortquiz} or \texttt{quiz}. The syntax of this package can be used
+% to pose number-related questions, the JavaScript can be used to create the answer to the
+% question based on a formula. You'll have to see it to believe it.
+%
+% \section{The Main Code}
+%
+% \subsection{Declare Options}
+%
+% This package has one option, other options are passed to the really nice \textsf{lcg} Package,
+% by Erich Janka (\texttt{janka@utanet.at}).
+% \begin{macrocode}
+\newcount\seedCnt
+\DeclareOption{testmode}{%
+ \InputIfFileExists{\jobname.seed}{}{\def\thisseed{1}}%
+ \PassOptionsToPackage{seed=\thisseed}{lcg}%
+ \AtEndOfPackage{\reseedEachRun}%
+}
+\def\reseedEachRun{%
+ \seedCnt=\thisseed
+ \advance\seedCnt1\relax
+ \newwrite \rngWrite
+ \immediate\openout\rngWrite \jobname.seed
+ \immediate\write\rngWrite{\string\def\string\thisseed{\the\seedCnt}}
+ \immediate\closeout\rngWrite
+}
+\def\RNG@Dec{.}
+\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{lcg}}
+\ProcessOptions
+\RequirePackage{lcg}[2008/09/10]
+% \end{macrocode}
+% Save the seed value so we can reproduce the same pseudo-random number sequence.
+% \begin{macrocode}
+\edef\rng@saveSeed{\the\cr@nd}
+% \end{macrocode}
+% There are three data types: Integer, Rational, and Real. The following macros
+% gives each of these types a numerical value, 0, 1 and 2, respectively.
+% \begin{macrocode}
+\newcount\loopCnt
+\def\maxLoopLimit{10}
+\def\typeCodeForz{0}
+\def\typeCodeForq{1}
+\def\typeCodeForr{2}
+% \end{macrocode}
+% Some scratch count registers
+% \begin{macrocode}
+\newcount\rng@cnta
+\newcount\rng@cntb
+% \end{macrocode}
+% A random variable is specified using a control sequence, e.g. \cs{a}. The following macro
+% extracts the underlying name of the command, e.g. \verb+\@gtVarName{\a}+ expands to \texttt{a},
+% and returns the name as the expansion of the macro \cs{@varName}.
+% \begin{macrocode}
+\def\@getVarName#1{%
+ \edef\@varName{\expandafter\@gobble\string#1}%
+}
+% \end{macrocode}
+% The command \cs{@getVarType} takes one argument, a random variable, e.g., \cs{a}. This
+% command defines a macro \cs{varType} which expands to the data type the random variable is.
+% \begin{macrocode}
+\def\@getVarType#1{%
+ \@getVarName{#1}\edef\varType{\csname typeof@\@varName\endcsname}}
+% \end{macrocode}
+% \subsection{GCD and Rational Reduction Commands}
+% \begin{macro}{\gcd}
+% Here we use Euclid's Algorithm to find the greatest common divisor of two integers.
+% \begin{macrocode}
+\def\gcd#1#2{{% #1 = a, #2 = b
+ \ifnum#2=0 \edef\next{#1}\else
+ \@tempcnta=#1 \@tempcntb=#2 \divide\@tempcnta by\@tempcntb
+ \multiply\@tempcnta by\@tempcntb % q*b
+ \@tempcntb=#1
+ \advance\@tempcntb by-\@tempcnta % remainder in \@tempcntb
+ \ifnum\@tempcntb=0
+ \@tempcnta=#2
+ \ifnum\@tempcnta < 0 \@tempcnta=-\@tempcnta\fi
+ \xdef\gcd@next{\noexpand%
+ \def\noexpand\thegcd{\the\@tempcnta}}%
+ \else
+ \xdef\gcd@next{\noexpand\gcd{#2}{\the\@tempcntb}}%
+ \fi
+ \fi}\gcd@next
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\lcm}
+% Now compute the least common multiple
+% \begin{macrocode}
+\def\lcm#1#2{% #1 = a, #2 = b
+ \gcd{#1}{#2}%
+ {\@tempcnta=#1
+ \multiply\@tempcnta by#2
+ \divide\@tempcnta by\thegcd
+ \xdef\thelcm{\the\@tempcnta}}%
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\amodb}
+% Modular arithmetic \texttt{a mod b}, returns its results
+% as a macro \cs{retnmod}.
+% \begin{macrocode}
+\def\amodb#1#2{% #1 = a, #2 = b
+ {\@tempcnta=#1
+ \divide\@tempcnta by#2
+ \multiply\@tempcnta by#2
+ \@tempcntb=#1
+ \advance\@tempcntb by-\@tempcnta
+ \xdef\retnmod{\the\@tempcntb}}%
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\reduceFrac}
+% Reduce a fraction to lowest terms. The first argument is the numerator and the second
+% argument is the denominator. This command computes the \texttt{gcd} of the two integers,
+% divides each by the \texttt{gcd}, and returns the results in the two scratch count
+% registers \cs{@tempcnta} and \cs{@tempcntb}.
+% \begin{macrocode}
+\newcommand\reduceFrac[2]
+{%
+ \gcd{#1}{#2}{\@tempcnta=#1 \divide\@tempcnta by\thegcd
+ \@tempcntb=#2 \divide\@tempcntb by\thegcd
+ \ifnum\@tempcntb<0\relax
+% \end{macrocode}
+% Always have the denominator as positive.
+% \begin{macrocode}
+ \@tempcntb=-\@tempcntb
+ \@tempcnta=-\@tempcnta
+ \fi
+ \xdef\rfNumer{\the\@tempcnta}\xdef\rfDenom{\the\@tempcntb}}%
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\convertRatTo}
+% Converts a fraction \texttt{a/b} (\texttt{\#1/\#2}) to a denominator of \texttt{\#3}. Will return
+% new numerator in \cs{rnd@Cnta} register. This will be exact if
+% \texttt{\#2} divides \texttt{\#3}.
+% \begin{macrocode}
+\def\convertRatTo#1#2#3{{%
+ \@tempcnta=#3
+ \multiply\@tempcnta by#1
+ \divide\@tempcnta by#2
+ \xdef\rng@retn@num{\the\@tempcnta}%
+}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\RNGadd}
+% This is the support for rational arithmetic (addition and subtraction).
+% Adds two rational numbers, \texttt{\#1} and \texttt{\#2} together. These two rational numbers must have been defined
+% already, possibly by \cs{defineQ}. Usage: \verb+\RNGadd\a\b+. This macro returns a rational number:
+% the numerator in the \cs{rfNumer} command, and the denominator in the \cs{rfDenom} command.
+% For example,
+%\begin{verbatim}
+%\defineQ\a{1}{3}\defineQ\b{3}{5}\RNGadd\a\b
+%\makeatletter
+%The sum of $\frac{\nOf\a}{\dOf\a} + \frac{\nOf\b}{\dOf\b}
+% = \frac{\rfNumer}{\rfDenom}$
+%\makeatother
+%\end{verbatim}
+%This code typesets as $\frac{1}{3}+\frac{3}{5}=\frac{14}{15}$.
+% \begin{macrocode}
+\newcommand\RNGadd[2]{%
+ \rng@cnta=\nOf#1 \multiply\rng@cnta by\dOf#2
+ \rng@cntb=\nOf#2 \multiply\rng@cntb by\dOf#1
+ \advance\rng@cnta by\the\rng@cntb
+ \rng@cntb=\dOf#1 \multiply\rng@cntb by\dOf#2
+ \reduceFrac{\the\rng@cnta}{\the\rng@cntb}
+}
+% \end{macrocode}
+% \end{macro}
+% This is a simple macro for detecting if the argument \texttt{\#1}
+% is a macro or not. Used when interval definitions of the
+% \cs{RandomZ/Q/R} macros.
+% \begin{macrocode}
+\def\rng@isControl#1{\@ifundefined{\expandafter\@gobble\string#1}%
+ {\let\rng@isC@ntrol=0}{\let\rng@isC@ntrol=1}}
+% \end{macrocode}
+% This command determines if its argument has an \texttt{*}
+% prefixed or post-fixed to its argument.
+% If \cs{rng@isStariii} equals \texttt{*}, then an \texttt{*} exists.
+% \begin{itemize}
+% \item If there is no \texttt{*}, then the argument is \texttt{\#1}
+% \item \cs{rng@isStariii} equals \texttt{*}, there is \texttt{*},
+% If the argument has the form \cs{*a}, then \cs{rng@isStari} is \cs{@empty}
+% and the argument, stripped of the \texttt{*}, is given as \cs{rng@isStarii}
+% \item \cs{rng@isStariii} equals \texttt{*}, there is \texttt{*},
+% If the argument has the form \cs{a*}, then \cs{rng@isStarii} is \cs{@empty}
+% and the argument, stripped of the \texttt{*}, is given as \cs{rng@isStari}
+%\end{itemize}
+% \begin{macrocode}
+\def\rng@existStar#1{\rng@existSt@r#1**\@nil}
+\def\rng@existSt@r#1*#2*#3\@nil{\def\rng@isStari{#1}%
+ \def\rng@isStarii{#2}\def\rng@isStariii{#3}%
+}
+\def\rng@NameEndpoint#1{%
+ \ifx\rng@isStari\@empty
+ \edef#1{\expandafter\noexpand\rng@isStarii}%
+ \else\ifx\rng@isStarii\@empty
+ \edef#1{\expandafter\noexpand\rng@isStari}%
+ \fi\fi
+}
+% \end{macrocode}
+% \subsection{Define an Integer and a Rational}
+% \begin{macro}{\defineZ}
+% Define a integer for use in other macros.
+% \begin{macrocode}
+\newcommand\defineZ[2]
+{%
+ \@getVarName#1\relax
+ \expandafter\def\csname typeof@\@varName\endcsname{0}%
+ \expandafter\edef\csname n@\@varName\endcsname{#2}%
+ \expandafter\edef\csname d@\@varName\endcsname{1}%
+ \edef\display@TeXfmt{#2}\edef\inline@TeXfmt{#2}%
+ \ifnum#2=1\relax\rng@makeOneFmtDefns
+ \else\ifnum#2=-1\relax\rng@makeMinusOneFmtDefns
+ \else\rng@makeOtherFmtDefns\fi\fi
+ \expandafter\let\csname\@varName*\endcsname\display@TeXfmt
+ \expandafter\let\csname\@varName!\endcsname\inline@TeXfmt
+ \expandafter\edef\csname\@varName\endcsname{#2}%
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\defineQ}
+% The following macro defines a rational number. Usage
+% \verb+\defineQ\a{1}{2}+. This defines the rational number 1/2 and
+% gives it a name, \cs{a}.
+% \begin{macrocode}
+\newcommand\defineQ[3]
+{%
+ \@getVarName#1\relax
+ \expandafter\def\csname typeof@\@varName\endcsname{1}%
+ \expandafter\edef\csname n@\@varName\endcsname{#2}%
+ \expandafter\edef\csname d@\@varName\endcsname{#3}%
+ \edef\display@TeXfmt{\frac{#2}{#3}}\edef\inline@TeXfmt{#2/#3}%
+ \ifnum#2=#3\relax\rng@makeOneFmtDefns
+ \else\ifnum#2=-#3\relax\rng@makeMinusOneFmtDefns
+ \else\rng@makeOtherFmtDefns\fi\fi
+ \expandafter\let\csname\@varName*\endcsname\display@TeXfmt
+ \expandafter\let\csname\@varName!\endcsname\inline@TeXfmt
+ \expandafter\edef\csname\@varName\endcsname{#2/#3}%
+ \simplifyCurrentQ
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\defineR}
+% This macro computes: (1) \cs{rng@intpart}; (2) \cs{rng@fracpart};
+% (3) \cs{rndnDec} (the number of decimals of the fractional part);
+% (4) \cs{rndPower} (the power of ten determined by \cs{rndnDec}).
+% \begin{macrocode}
+\newcommand{\defineR}[2]{%
+ \@getVarName{#1}\RNGparseDec{#2}%
+ \expandafter\def\csname typeof@\@varName\endcsname{2}%
+ \reduceFrac{\rng@intpart\rng@fracpart}{\rndPower}%
+ \expandafter\edef\csname n@\@varName\endcsname{\rfNumer}%
+ \expandafter\edef\csname d@\@varName\endcsname{\rfDenom}%
+ \edef\display@TeXfmt{#2}\edef\inline@TeXfmt{#2}%
+ \ifnum\rfNumer=1\relax\rng@makeOneFmtDefns
+ \else\ifnum\rfNumer=-1\relax\rng@makeMinusOneFmtDefns
+ \else\rng@makeOtherFmtDefns\fi\fi
+ \expandafter\let\csname\@varName*\endcsname\display@TeXfmt
+ \expandafter\let\csname\@varName!\endcsname\inline@TeXfmt
+ \expandafter\edef\csname\@varName\endcsname{#2}%
+ \simplifyCurrentR
+}
+\newcommand{\simplifyCurrentR}{%
+ \ifnum\csname d@\@varName\endcsname=1
+ \expandafter\defineZ
+ \csname\@varName\endcsname{\csname n@\@varName\endcsname}\fi
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+\def\rng@makeOneFmtDefns{%
+% inline
+ \expandafter\def\csname\@varName!e\endcsname{}%
+ \expandafter\def\csname\@varName!c\endcsname{}%
+% display
+ \expandafter\def\csname\@varName*e\endcsname{}%
+ \expandafter\def\csname\@varName*c\endcsname{}%
+}
+\def\rng@makeMinusOneFmtDefns{%
+% inline
+ \expandafter\def\csname\@varName!e\endcsname{-1}%
+ \expandafter\def\csname\@varName!c\endcsname{-}%
+% display
+ \expandafter\def\csname\@varName*e\endcsname{-1}%
+ \expandafter\def\csname\@varName*c\endcsname{-}%
+}
+\def\rng@makeOtherFmtDefns{%
+% inline
+ \expandafter\let\csname\@varName!e\endcsname\inline@TeXfmt
+ \expandafter\let\csname\@varName!c\endcsname\inline@TeXfmt
+% display
+ \expandafter\let\csname\@varName*e\endcsname\display@TeXfmt
+ \expandafter\let\csname\@varName*c\endcsname\display@TeXfmt
+}
+% \end{macrocode}
+%
+% \subsection{Parse a Number}
+%
+% \subsubsection{Parsing a Rational}
+%
+% \begin{macro}{\RNGparseRat}
+% \begin{macrocode}
+\def\RNGparseRat#1{\expandafter\@chkslash#1//\@nil}
+\def\@chkslash#1/#2/#3\@nil{%
+ \def\rng@num{#1}\def\rng@denom{#2}%
+ \def\rng@parseQ@iii{#3}%
+ \ifx\rng@denom\@empty\def\rng@denom{1}\fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Parsing a Real}
+%
+% \begin{macro}{\RNGparseDec}
+% The argument \texttt{\#1} is a decimal number (or integer)
+% This macro computes: (1) \cs{rng@intpart}; (2) \cs{rng@fracpart};
+% (3) \cs{rndnDec} (the number of decimals of the fractional part);
+% (4) \cs{rndPower} (the power of ten determined by \cs{rndnDec}).
+% These variables will be overwritten the next time this command
+% is executed.
+% \begin{macrocode}
+\newcommand{\RNGparseDec}[1]{\edef\parse@argi{#1}%
+ \expandafter\@chkdec\parse@argi..\@nil}
+\def\@chkdec#1.#2.#3\@nil{%
+ \def\rng@intpart{#1}\def\rng@fracpart{#2}%
+ \def\rng@parseR@iii{#3}\rng@getnDec}
+\def\rng@getnDec{%
+ \begingroup
+ \ifx\rng@fracpart\@empty\gdef\rndnDec{0}\gdef\rndPower{1}\else
+ \count0=0\relax\count2=1\relax
+ \expandafter\cntNumDec\rng@fracpart\end\fi
+ \endgroup}
+\def\cntNumDec#1#2\end{%
+ \advance\count0by1
+ \def\rng@arg{#2}%
+ \ifx\rng@arg\@empty
+ \xdef\rndnDec{\the\count0}%
+ \xdef\rndPower{1\@nameuse{rng@tz\the\count0}}%
+ \let\rng@next\relax
+ \else
+ \def\rng@next{\cntNumDec#2\end}%
+ \fi\rng@next
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\nDivisionsPowerOfTen}
+% This is a control of how many nodes to create in an interval
+% of real numbers, as defined by \cs{RandomR}. The argument is
+% an integer between 1 and 4 inclusive.
+% \begin{macrocode}
+\newcommand{\nDivisionsPowerOfTen}[1]{%
+ \begingroup
+ \count0=#1\relax
+ \ifnum\count0>4\relax
+ \PackageError{rangen}{Number of subdivisions too large}%
+ {Reduce the argument of \string\nDivisionsPowerOfTen.}%
+ \else
+ \ifnum\count0<1\relax
+ \PackageError{rangen}{Number of subdivisions too large}%
+ {Increase the argument of \string\nDivisionsPowerOfTen.}%
+ \fi\fi
+ \xdef\RNGpowerOfTen{1\@nameuse{rng@tz#1}}%
+ \endgroup
+}
+\nDivisionsPowerOfTen{2}
+% \end{macrocode}
+% \end{macro}
+%\subsection{Creating Random Things}
+%\subsubsection{Random Integer}
+% \begin{macro}{\RandomZ}
+% Randomly generates an integer in the specified range of values.
+%\begin{verbatim}
+%[#1] Optional parameter to modify the variable.
+% #2 The random variable being defined, e.g., \a
+% #3 lower limit of random integer
+% #4 upper limit of random integer
+%\end{verbatim}
+% \begin{macrocode}
+\newcommand\RandomZ[4][]
+{%
+ \def\rng@ne@values{}%
+ \setkeys{rangen}{ne,#1}%
+% \end{macrocode}
+% Now see if there is an \texttt{*}, and get un-stripped
+% argument.
+%
+% The \cs{rng@isControl} lets \cs{rng@isC@ntrol} to 0 if the arg is undefined,
+% and lets \cs{rng@isC@ntrol} to 1 if it is defined.
+% Check the left endpoint:
+% \begin{macrocode}
+ \let\rng@CtrlLEP=0\let\rng@CtrlUEP=0%
+ \let\rng@makeLEPStrict=0\let\rng@makeUEPStrict=0%
+% \end{macrocode}
+% \paragraph*{Left endpoint.}
+% \begin{macrocode}
+ \rng@existStar{#3}\rng@NameEndpoint{\rng@LEP}%
+ \if\rng@isStariii*\edef\tmp@exp{%
+ \noexpand\rng@isControl{\expandafter\noexpand\rng@LEP}}\tmp@exp
+ \if\rng@isC@ntrol1% a control sequence
+ \let\rng@CtrlLEP=1\let\rng@makeLEPStrict=1%
+% \end{macrocode}
+% The LEP is a control sequence with a star, we need to increment the value
+% of \cs{rng@LEP} to the next largest integer.
+% \begin{macrocode}
+ \edef\tmp@exp{\noexpand%
+ \@getVarType{\expandafter\noexpand\rng@LEP}}\tmp@exp
+ \ifcase\varType % integer
+ \rng@cnta=\rng@LEP
+ \or % rational
+ \rng@dima=\expandafter\nOf\rng@LEP pt
+ \divide\rng@dima by\expandafter\dOf\rng@LEP
+ \defineR{\rng@LEP}{\strip@pt\rng@dima}%
+ \RNGparseDec{\rng@LEP}%
+ \rng@cnta=\rng@intpart
+ \or % real
+ \defineR{\rng@LEP}{\rng@LEP}%
+ \RNGparseDec{\rng@LEP}%
+ \rng@cnta=\rng@intpart
+ \fi
+ \advance\rng@cnta by1\relax
+ \defineZ{\rng@LEP}{\the\rng@cnta}%
+ \else
+% \end{macrocode}
+% Not a control sequence but has a star
+% \begin{macrocode}
+ \defineZ{\rng@LEP}{\rng@LEP}%
+ \fi
+ \else
+% \end{macrocode}
+% No star, control sequence or not?
+% \begin{macrocode}
+ \rng@isControl{#3}%
+ \if\rng@isC@ntrol1% control sequence
+ \let\rng@CtrlLEP=1%
+ \def\rng@LEP{#3}%
+ \@getVarType{#3}%
+ \ifcase\varType % integer
+ \defineZ{\rng@LEP}{#3}%
+ \or % rational
+ \rng@dima=\nOf{#3}pt
+ \divide\rng@dima by\dOf{#3}%
+ \defineR{\rng@LEP}{\strip@pt\rng@dima}%
+ \RNGparseDec{\rng@LEP}%
+ \defineZ{\rng@LEP}{\rng@intpart}%
+ \or % real
+ \defineR{\rng@LEP}{\rng@LEP}%
+ \RNGparseDec{\rng@LEP}%
+ \defineZ{\rng@LEP}{\rng@intpart}%
+ \fi
+ \else
+% \end{macrocode}
+% A number, no star
+% \begin{macrocode}
+ \defineZ{\rng@LEP}{#3}%
+ \fi
+ \fi
+% \end{macrocode}
+% \paragraph*{Right endpoint.}
+% \begin{macrocode}
+ \rng@existStar{#4}\rng@NameEndpoint{\rng@UEP}%
+ \if\rng@isStariii*\edef\tmp@exp{%
+ \noexpand\rng@isControl{\expandafter\noexpand\rng@UEP}}\tmp@exp
+ \if\rng@isC@ntrol1% a control sequence
+ \let\rng@CtrlUEP=1\let\rng@makeUEPStrict=1%
+% \end{macrocode}
+% The UEP is a control sequence with a star, we need to increment the value
+% of \cs{rng@UEP} to the next largest integer.
+% \begin{macrocode}
+ \edef\tmp@exp{\noexpand%
+ \@getVarType{\expandafter\noexpand\rng@UEP}}\tmp@exp
+ \ifcase\varType % integer
+ \rng@cnta=\rng@UEP
+ \or % rational
+ \rng@dima=\expandafter\nOf\rng@UEP pt
+ \divide\rng@dima by\expandafter\dOf\rng@UEP
+ \defineR{\rng@UEP}{\strip@pt\rng@dima}%
+ \RNGparseDec{\rng@UEP}%
+ \rng@cnta=\rng@intpart
+ \or % real
+ \defineR{\rng@UEP}{\rng@UEP}%
+ \RNGparseDec{\rng@UEP}%
+ \rng@cnta=\rng@intpart
+ \fi
+ \advance\rng@cnta by-1\relax
+ \defineZ{\rng@UEP}{\the\rng@cnta}%
+ \else
+% \end{macrocode}
+% Not a control sequence but has a star
+% \begin{macrocode}
+ \defineZ{\rng@UEP}{\rng@UEP}%
+ \fi
+ \else
+% \end{macrocode}
+% No star, control sequence or not?
+% \begin{macrocode}
+ \rng@isControl{#4}%
+ \if\rng@isC@ntrol1% control sequence
+ \let\rng@CtrlUEP=1%
+ \def\rng@UEP{#4}%
+ \@getVarType{#4}%
+ \ifcase\varType % integer
+ \defineZ{\rng@UEP}{#4}%
+ \or % rational
+ \rng@dima=\nOf{#4}pt
+ \divide\rng@dima by\dOf{#4}%
+ \defineR{\rng@UEP}{\strip@pt\rng@dima}%
+ \RNGparseDec{\rng@UEP}%
+ \defineZ{\rng@UEP}{\rng@intpart}%
+ \or % real
+ \defineR{\rng@UEP}{\rng@UEP}%
+ \RNGparseDec{\rng@UEP}%
+ \defineZ{\rng@UEP}{\rng@intpart}%
+ \fi
+ \else
+% \end{macrocode}
+% A number, no star, assume it is an integer
+% \begin{macrocode}
+ \defineZ{\rng@UEP}{#4}%
+ \fi
+ \fi
+% \end{macrocode}
+% \textbf{To Do.} Check if LEP is less than UEP, if not, notify user.
+% Save the random variable, e.g., \cs{a}
+% \begin{macrocode}
+ \def\@currentName{#2}%
+% \end{macrocode}
+% Record the variable type
+% \begin{macrocode}
+ \@getVarName{#2}%
+ \expandafter\def\csname typeof@\@varName\endcsname{0}%
+% \end{macrocode}
+% Save the range of this variable
+% \begin{macrocode}
+ \expandafter\edef\csname first@\@varName\endcsname{\rng@LEP}%
+ \expandafter\edef\csname last@\@varName\endcsname{\rng@UEP}%
+% \end{macrocode}
+% Now get a value for the variable using \cs{rand}, defined in \texttt{lcg}
+% \begin{macrocode}
+ \rng@chgrand[first=\rng@LEP,last=\rng@UEP]\rand
+% \end{macrocode}
+% Now define the integer.
+% \begin{macrocode}
+ \defineZ{#2}{\arabic{rand}}%
+% \end{macrocode}
+% \paragraph*{Constraints}
+% We have a random Z, we now try to satisfy the \texttt{ne} condition.
+%
+% The macro \cs{rangen@ne} can be of the form \verb!{1,3,4,5}!. We try to
+% satisfy all the conditions specified by \cs{rangen@ne}
+% \begin{macrocode}
+ \ifx\rangen@ne\@empty\else\loopCnt=0\relax
+% \end{macrocode}
+% We will try a total number of \cs{maxLoopLimit} to meet the required
+% conditions.
+% \begin{macrocode}
+ \@whilenum\loopCnt<\maxLoopLimit\do{%
+% \end{macrocode}
+% Set \cs{rng@cnta=1}, if \cs{rng@cnta} is still 1 at the end of this
+% loop, the condition is satisfied.
+% conditions.
+% \begin{macrocode}
+ \rng@cnta=1\relax
+% \end{macrocode}
+% We use a \cs{@for} loop to run through all the NE values
+% \begin{macrocode}
+ \@for\ne@@tmp:=\rangen@ne\do{%
+% \end{macrocode}
+% If the current RV is equal to the current NE value, we fail, so we
+% ``and'' a zero into the \cs{rng@cnta} register.
+% \begin{macrocode}
+ \ifnum\value{rand}=\ne@@tmp\relax
+ \multiply\rng@cnta0\relax
+ \else
+% \end{macrocode}
+% \dots otherwise, we ``and'' a one.
+% \begin{macrocode}
+ \multiply\rng@cnta1\relax
+ \fi
+ }%
+% \end{macrocode}
+% If \cs{rng@cnt} is still equal to 1, all conditions have been met,
+% in this case we set \verb!\loopCnt=\maxLoopLimit! so we can exit the outer loop.
+% \begin{macrocode}
+ \ifnum\rng@cnta=1\relax % all conditions met
+ \loopCnt=\maxLoopLimit
+ \else % if \rng@cnta \ne 1, try again
+% \end{macrocode}
+% Otherwise, we increment the loop, see if we have gone the limit, if
+% not, loop back with a new random choice.
+% \begin{macrocode}
+ \advance\loopCnt1\relax
+ \ifnum\loopCnt=\maxLoopLimit
+ \PackageWarning{rangen}{Not all conditions met
+ after \maxLoopLimit\space tries}%
+ \else
+ \rng@chgrand[first=\rng@LEP,last=\rng@UEP]\rand
+ \fi
+ \fi
+ }%
+ \fi
+% \end{macrocode}
+% Whether we fail or succeed, we'll go with the last RV. Hopefully, the
+% author is aware of the log file, and re-compile, possibly with a
+% wider range for the variable, or with a larger value of \cs{maxLoopLimit}.
+%
+% \begin{macrocode}
+ \defineZ{#2}{\arabic{rand}}%
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+\def\updateZ#1#2{%
+ \@getVarName#1\relax
+ \expandafter\edef\csname\@varName\endcsname{#2}%
+ \expandafter\edef\csname n@\@varName\endcsname{#2}%
+ \expandafter\edef\csname d@\@varName\endcsname{1}%
+}
+% \end{macrocode}
+%\subsubsection{Random Rational}
+% \begin{macro}{\RandomQ}
+% Randomly generate a rational number. The parameters for \cs{RandomQ} are
+%\begin{verbatim}
+%[#1] Optional parameter to modify the variable.
+% #2 The random variable being defined, e.g., \a
+%[#3] maximum denominator permitted (optional)
+% #4 rational number for lower endpoint of range
+% #5 rational number for upper endpoint of range
+%\end{verbatim}
+% Here, it is assume that the first rational number is less than the second. This macro
+% will randomly generate a rational number between rat1 and rat2, with a maximum denominator
+% specified in \texttt{\#3}.
+%
+% \medskip\noindent\textbf{Note: }To allow for random endpoints, if one or both are real numbers, we convert
+% them to rational numbers in \cs{@RandomQ}.
+%
+% We begin by getting the first two parameters:
+%\begin{verbatim}
+%[#1] Optional parameter to modify the variable.
+% #2 The random variable being defined, e.g., \a
+%\end{verbatim}
+% \begin{macrocode}
+\newcommand{\RandomQ}[2][]
+{%
+ \setkeys{rangen}{ne,#1}%
+ \def\rq@currentName{#2}%
+ \@RandomQ
+}
+% \end{macrocode}
+% We use \cs{@RandomQ} to get the last three parameters of \cs{RandomQ}.
+% If the endpoints are not rational, they are converted to rationals.
+%\begin{verbatim}
+%[#1] maximum denominator permitted (optional)
+% #2 rational number for lower endpoint of range
+% #3 rational number for upper endpoint of range
+%\end{verbatim}
+% \begin{macrocode}
+\newcommand{\@RandomQ}[3][]
+{%
+% \end{macrocode}
+% Now see if there is an \texttt{*}, and get un-stripped
+% argument.
+%
+% The \cs{rng@isControl} lets \cs{rng@isC@ntrol} to 0 if the arg is undefined,
+% and lets \cs{rng@isC@ntrol} to 1 if it is defined.
+% Check the left endpoint:
+% \begin{macrocode}
+ \let\rng@CtrlLEP=0\let\rng@CtrlUEP=0%
+ \let\rng@makeLEPStrict=0\let\rng@makeUEPStrict=0%
+% \end{macrocode}
+% \paragraph*{Left endpoint}
+% \begin{macrocode}
+ \rng@existStar{#2}\rng@NameEndpoint{\rng@LEP}%
+ \if\rng@isStariii*\edef\tmp@exp{\noexpand%
+ \rng@isControl{\expandafter\noexpand\rng@LEP}}\tmp@exp
+ \if\rng@isC@ntrol1% a control sequence
+ \let\rng@CtrlLEP=1\let\rng@makeLEPStrict=1%
+% \end{macrocode}
+% The LEP is a control sequence we get its type and convert to rational
+% \begin{macrocode}
+ \edef\tmp@exp{\noexpand%
+ \@getVarType{\expandafter\noexpand\rng@LEP}}\tmp@exp
+ \ifcase\varType % integer
+ \defineQ{\rng@LEP}{\rng@LEP}{1}%
+ \or % rational
+ \edef\tmp@exp{\noexpand%
+ \defineQ{\noexpand\rng@LEP}{\expandafter\nOf\rng@LEP}%
+ {\expandafter\dOf\rng@LEP}}\tmp@exp
+ \or % real
+ \defineR{\rng@LEP}{\rng@LEP}%
+ \RNGparseDec{\rng@LEP}%
+ \defineQ{\rng@LEP}{\rng@intpart}{\rng@fracpart}%
+ \fi
+ \else
+% \end{macrocode}
+% Not a control sequence but has a star, a number, we assume rational
+% \begin{macrocode}
+ \RNGparseRat{\rng@LEP}%
+ \defineQ{\rng@UEP}{\rng@intpart}{\rng@fracpart}%
+ \fi
+ \else
+% \end{macrocode}
+% No star, is it a control sequence or not?
+% \begin{macrocode}
+ \rng@isControl{#2}%
+ \if\rng@isC@ntrol1% a control sequence
+ \@getVarType{#2}%
+ \ifcase\varType % integer
+ \defineQ{\rng@LEP}{#2}{1}%
+ \or % rational
+ \defineQ{\rng@LEP}{\nOf{#2}}{\dOf{#2}}%
+ \or % real
+ \defineR{\rng@LEP}{#2}%
+ \RNGparseDec{\rng@LEP}%
+ \defineQ{\rng@LEP}{\rng@intpart}{\rng@fracpart}%
+ \fi
+ \else % a number, required to be rational
+ \RNGparseRat{#2}%
+ \defineQ{\rng@LEP}{\rng@num}{\rng@denom}%
+ \fi
+ \fi
+% \end{macrocode}
+% \paragraph*{Right endpoint}
+% \begin{macrocode}
+ \rng@existStar{#3}\rng@NameEndpoint{\rng@UEP}%%
+ \if\rng@isStariii*%
+ \edef\tmp@exp{\noexpand%
+ \rng@isControl{\expandafter\noexpand\rng@UEP}}\tmp@exp
+ \if\rng@isC@ntrol1% a control sequence
+ \let\rng@CtrlUEP=1\let\rng@makeUEPStrict=1%
+% \end{macrocode}
+% The UEP is a control sequence we get its type and convert to rational
+% \begin{macrocode}
+ \edef\tmp@exp{\noexpand%
+ \@getVarType{\expandafter\noexpand\rng@UEP}}\tmp@exp
+ \ifcase\varType % integer
+ \defineQ{\rng@UEP}{\rng@UEP}{1}%
+ \or % rational
+ \edef\tmp@exp{\noexpand%
+ \defineQ{\noexpand\rng@UEP}{\expandafter\nOf\rng@UEP}%
+ {\expandafter\dOf\rng@UEP}}\tmp@exp
+ \or % real
+ \defineR{\rng@UEP}{\rng@UEP}%
+ \RNGparseDec{\rng@UEP}%
+ \defineQ{\rng@UEP}{\rng@intpart}{\rng@fracpart}%
+ \fi
+ \else
+% \end{macrocode}
+% Not a control sequence but has a star, a number, we assume rational
+% \begin{macrocode}
+ \RNGparseRat{\rng@UEP}%
+ \defineQ{\rng@UEP}{\rng@intpart}{\rng@fracpart}%
+ \fi
+ \else
+% \end{macrocode}
+% No star, is it a control sequence or not?
+% \begin{macrocode}
+ \rng@isControl{#3}%
+ \if\rng@isC@ntrol1% a control sequence
+ \@getVarType{#3}%
+ \ifcase\varType % integer
+ \defineQ{\rng@UEP}{#3}{1}%
+ \or % rational
+ \defineQ{\rng@UEP}{\nOf{#3}}{\dOf{#3}}%
+ \or % real
+ \defineR{\rng@UEP}{#3}%
+ \RNGparseDec{\rng@UEP}%
+ \defineQ{\rng@UEP}{\rng@intpart}{\rng@fracpart}%
+ \fi
+ \else % a number, required to be rational
+ \RNGparseRat{#3}%
+ \defineQ{\rng@UEP}{\rng@num}{\rng@denom}%
+ \fi
+ \fi
+ \@@RandomQ{#1}{\nOf{\rng@LEP}}{\dOf{\rng@LEP}}%
+ {\nOf{\rng@UEP}}{\dOf{\rng@UEP}}%
+}
+% \end{macrocode}
+% Once all the parameters have been acquired, and
+% any needed conversions are made, we call \cs{@@RandomQ} which
+% actually generates the random rational.
+%\begin{verbatim}
+% #1 maximum denominator permitted
+% #2 numerator of first rational
+% #3 denominator of first rational
+% #4 numerator of second rational
+% #5 denominator of second rational
+%\end{verbatim}
+% \begin{macrocode}
+\newcommand{\@@RandomQ}[5]
+{%
+% \end{macrocode}
+% Now take parameters \texttt{\#2}--\texttt{\#5}, and make into two rationals
+% \begin{macrocode}
+ \updateQ\@rqi{#2}{#3}\updateQ\@rqii{#4}{#5}%
+% \end{macrocode}
+% Find least common multiple between \texttt{\#3}, \texttt{\#5} and \texttt{\#1}
+% \begin{macrocode}
+ \lcm{#3}{#5}\edef\@thelcm{\thelcm}%
+ \def\@maxDenom{#1}%
+ \ifx\@maxDenom\@empty\edef\@maxDenom{\@thelcm}\else
+ \lcm{\@thelcm}{#1}\edef\@thelcm{\thelcm}\fi
+% \end{macrocode}
+% Now convert all rationals to have a denominator of \cs{@thelcm}
+% \begin{macrocode}
+ \convertRatTo{\nOf\@rqi}{\dOf\@rqi}{\@thelcm}%
+ \updateQ\@@rqi{\rng@retn@num}{\@thelcm}%
+ \convertRatTo{\nOf\@rqii}{\dOf\@rqii}{\@thelcm}%
+ \updateQ\@@rqii{\rng@retn@num}{\@thelcm}%
+% \end{macrocode}
+% get divisor
+% \begin{macrocode}
+ \rng@cnta=\@thelcm \divide\rng@cnta by\@maxDenom
+ \edef\@divisor{\the\rng@cnta}%
+% \end{macrocode}
+% Round up lower limit
+% \begin{macrocode}
+ \rng@cnta=\nOf\@@rqi
+ \divide\rng@cnta by\@divisor
+ \advance\rng@cnta by1
+% \end{macrocode}
+% Round down the upper limit
+% \begin{macrocode}
+ \rng@cntb=\nOf\@@rqii\divide\rng@cntb by\@divisor
+% \end{macrocode}
+% If a strict inequality is requested, we creep in a little.
+% \begin{macrocode}
+ \if\rng@makeLEPStrict1\advance\rng@cnta1\relax\fi
+ \if\rng@makeUEPStrict1\advance\rng@cntb-1\relax\fi
+% \end{macrocode}
+% construct numerator
+% \begin{macrocode}
+ \expandafter\@getVarName\rq@currentName
+ \let\save@varName\@varName
+ \expandafter\edef\csname first@n@\@varName\endcsname{\the\rng@cnta}%
+ \expandafter\edef\csname last@n@\@varName\endcsname{\the\rng@cntb}%
+ \expandafter\edef\csname first@d@\@varName\endcsname{\@maxDenom}%
+ \expandafter\edef\csname last@d@\@varName\endcsname{\@maxDenom}%
+ \edef\rng@LEP{\csname first@n@\@varName\endcsname}%
+ \edef\rng@UEP{\csname last@n@\@varName\endcsname}%
+%\typeout{\@varName: first=\rng@LEP,last=\rng@UEP}%
+ \rng@chgrand[first=\rng@LEP,last=\rng@UEP]\rand
+% \end{macrocode}
+% Record the random variable name, e.g., \cs{a}, ...
+% \begin{macrocode}
+ \let\@currentName\rq@currentName
+ \expandafter\@getVarName\rq@currentName
+ \expandafter\defineQ\@currentName{\arabic{rand}}{\@maxDenom}%
+ \simplifyCurrentQ
+ \expandafter\defineQ\@currentName{\expandafter\nOf\@currentName}%
+ {\expandafter\dOf\@currentName}%
+% \end{macrocode}
+%
+% \paragraph*{Constraints}
+%
+% We now attempt to satisfy the NE constraints.
+% \begin{macrocode}
+ \ifx\rangen@ne\@empty\else\loopCnt=0\relax
+ \@whilenum\loopCnt<\maxLoopLimit\do{%
+ \rng@cnta=1\relax
+ \@for\ne@@tmp:=\rangen@ne\do{%
+% \end{macrocode}
+% Define a rational by the name of \cs{cmp@Name}, then make it have
+% the same denominator as \cs{@currentName}.
+% \begin{macrocode}
+ \let\save@currentName\rq@currentName
+ \RNGparseRat{\ne@@tmp}%
+ \defineQ{\cmp@Name}{\rng@num}{\rng@denom}%
+ \let\@varName\save@varName
+ \syncronizeQs{\@varName}%
+ \ifnum\csname n@\@varName\endcsname=\n@cmp@Name
+ \multiply\rng@cnta0\relax
+ \else
+ \multiply\rng@cnta1\relax
+ \fi
+ }%
+ \ifnum\rng@cnta=1\relax % all conditions met
+ \loopCnt=\maxLoopLimit
+ \else % if \rng@cnta \ne 1, try again
+ \advance\loopCnt1\relax
+ \ifnum\loopCnt=\maxLoopLimit
+ \PackageWarning{rangen}{Not all conditions met
+ after \maxLoopLimit\space tries}%
+ \else
+ \rng@chgrand[first=\rng@LEP,last=\rng@UEP]\rand
+ \expandafter\@getVarName\rq@currentName
+ \expandafter\defineQ\@currentName{\arabic{rand}}%
+ {\@maxDenom}%
+ \fi
+ \fi
+ }%
+ \fi
+ \simplifyCurrentQ
+ \expandafter\defineQ\@currentName{\expandafter\nOf\@currentName}%
+ {\expandafter\dOf\@currentName}%
+% \end{macrocode}
+% If the denominator is equal to 1, let's change the data type to an integer.
+% \begin{macrocode}
+ \let\@currentName\rq@currentName
+ \expandafter\@getVarName\rq@currentName
+ \ifnum\csname d@\@varName\endcsname=1\relax\expandafter
+ \defineZ\@currentName{\expandafter\nOf\@currentName}%
+ \fi
+ \simplifyCurrentQ
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\updateQ}
+% Updates the value of a rational number, its numerator and denominator
+% without changing any of the format macros.
+% \begin{macrocode}
+\newcommand\updateQ[3]
+{%
+ \@getVarName#1\relax
+ \expandafter\edef\csname\@varName\endcsname{#2/#3}%
+ \expandafter\edef\csname n@\@varName\endcsname{#2}%
+ \expandafter\edef\csname d@\@varName\endcsname{#3}%
+}
+% \end{macrocode}
+% \end{macro}
+% A macro for performing routine adjustments on a rational number.
+% \begin{macrocode}
+\def\simplifyCurrentQ
+{%
+% \end{macrocode}
+% Reduce fraction: Reduce the fraction to its lowest terms.
+% \begin{macrocode}
+ \reduceFrac{\csname n@\@varName\endcsname}%
+ {\csname d@\@varName\endcsname}%
+% \end{macrocode}
+% \cs{reduceFrac} returns results in \cs{@tempcnta} and \cs{@tempcntb}, now
+% update the numerator and denominator
+% \begin{macrocode}
+ \expandafter\edef\csname n@\@varName\endcsname{\rfNumer}%
+ \expandafter\edef\csname d@\@varName\endcsname{\rfDenom}%
+% \end{macrocode}
+% If the numerator is zero, then zero out \cs{@varName} and special format
+% \begin{macrocode}
+ \ifnum\csname n@\@varName\endcsname=0
+ \expandafter\edef\csname\@varName\endcsname{0}%
+ \edef\display@TeXfmt{0}\edef\inline@TeXfmt{0}%
+ \else
+% \end{macrocode}
+% If numerator equals denominator, just replace by 1
+% \begin{macrocode}
+ \ifnum\csname n@\@varName\endcsname=\csname d@\@varName\endcsname
+ \expandafter\defineZ\csname\@varName\endcsname{1}%
+ \else
+% \end{macrocode}
+% If numerator equals -denominator, just replace by -1
+% \begin{macrocode}
+ \ifnum\csname n@\@varName\endcsname
+ =-\csname d@\@varName\endcsname
+ \expandafter\defineZ\csname\@varName\endcsname{-1}%
+ \else
+% \end{macrocode}
+% If denominator equals 1, modify value; otherwise, ok.
+% \begin{macrocode}
+ \ifnum\csname d@\@varName\endcsname=1
+ \expandafter\defineZ\csname\@varName\endcsname
+ {\csname n@\@varName\endcsname}%
+ \else
+ \expandafter\edef\csname \@varName\endcsname{%
+ \csname n@\@varName\endcsname/%
+ \csname d@\@varName\endcsname}%
+ \edef\display@TeXfmt{%
+ \frac{\csname n@\@varName\endcsname}
+ {\csname d@\@varName\endcsname}}%
+ \edef\inline@TeXfmt{%
+ \csname n@\@varName\endcsname/%
+ \csname d@\@varName\endcsname}%
+ \expandafter\let
+ \csname\@varName*\endcsname\display@TeXfmt
+ \fi
+ \fi
+ \fi
+ \fi
+}
+% \end{macrocode}
+% \begin{macro}{\nOf}
+% \begin{macro}{\dOf}
+% \begin{macro}{\iOf}
+% \begin{macro}{\typeOf}
+% User access to numerator and denominator of random variables.
+% \begin{macrocode}
+\newcommand\nOf[1]{\csname n@\expandafter\@gobble\string#1\endcsname}
+\newcommand\dOf[1]{\csname d@\expandafter\@gobble\string#1\endcsname}
+% \end{macrocode}
+% For a variable created by \cs{RandomL}, the index of the number chosen (1-based)
+% can be accessed through the \cs{iOf} command.
+% \begin{macrocode}
+\newcommand{\iOf}[1]{\csname i@\expandafter\@gobble\string#1\endcsname}
+% \end{macrocode}
+% Get the type of a RV, \cs{ifnum}\cs{typeOf}\cs{a}=0 (integer), 1 (rational), 2 (real),
+% 3 (literal, created by \cs{RandomP}).
+% \begin{macrocode}
+\newcommand\typeOf[1]{%
+ \csname typeof@\expandafter\@gobble\string#1\endcsname}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%\subsubsection{Random Real}
+%
+% We attempt to generate a random real number, in a given interval of real numbers.
+%
+% The following are some data and switches used by \cs{RandomReal}.
+% \begin{macrocode}
+\newif\iftrailingzeros\trailingzerosfalse
+\@namedef{rng@tz1}{0}
+\@namedef{rng@tz2}{00}
+\@namedef{rng@tz3}{000}
+\@namedef{rng@tz4}{0000}
+\@namedef{rng@tz5}{00000}
+\@namedef{rng@tz6}{000000}
+\@namedef{rng@tz7}{0000000}
+\@namedef{rng@tz8}{00000000}
+\def\rng@true{true}\def\rng@false{false}
+\newdimen\rng@dima
+\newdimen\rng@dimb
+\newdimen\rng@dimc
+% \end{macrocode}
+% \begin{macro}{\RandomR}
+% Create a real number at random within the given interval. For example,
+%\begin{verbatim}
+% \RandomR[<key-values>]{\a}{3.45}{6.45}
+%\end{verbatim}
+% \begin{macro}{round}
+% \begin{macro}{showzeros}
+% The key-value pairs recognized by \cs{RandomZ|Q|R}.
+% \begin{macrocode}
+\define@key{rangen}{ne}[]{\edef\rangen@ne{#1}}
+\define@key{rangen}{round}[]{\def\rangen@round{#1}}
+\define@key{rangen}{showzeros}[]{\def\rangen@showzeros{#1}%
+ \ifx\rangen@showzeros\@empty\global\trailingzerostrue\else
+ \ifx\rangen@showzeros\rng@true\global\trailingzerostrue\else
+ \global\trailingzerosfalse\fi\fi}
+\define@key{rangen}{index}[]{\edef\rangen@index{#1}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%\begin{verbatim}
+%[#1] = options
+% #2 = name of real to correct
+% #3 = lower endpoint of interval
+% #4 = upper endpoint of interval
+%\end{verbatim}
+% \begin{macrocode}
+\newcommand{\RandomR}[4][]{%
+ \setkeys{rangen}{ne,round,showzeros=false,#1}%
+% \end{macrocode}
+% Now see if there is an \texttt{*}, and get un-stripped
+% argument.
+%
+% The \cs{rng@isControl} lets \cs{rng@isC@ntrol} to 0 if the arg is undefined,
+% and lets \cs{rng@isC@ntrol} to 1 if it is defined.
+% Check the left endpoint:
+% \begin{macrocode}
+ \let\rng@CtrlLEP=0\let\rng@CtrlUEP=0%
+ \let\rng@makeLEPStrict=0\let\rng@makeUEPStrict=0%
+ \def\rng@lcg@first{0}\edef\rng@lcg@last{\RNGpowerOfTen}%
+% \end{macrocode}
+% \paragraph{Left endpoint.} Check the left endpoint:
+% \begin{macrocode}
+ \rng@existStar{#3}\rng@NameEndpoint{\rng@LEP}%
+ \if\rng@isStariii*\edef\tmp@exp{\noexpand%
+ \rng@isControl{\expandafter\noexpand\rng@LEP}}\tmp@exp
+ \if\rng@isC@ntrol1% a control sequence
+ \let\rng@CtrlLEP=1\let\rng@makeLEPStrict=1%
+ \def\rng@lcg@first{1}%
+% \end{macrocode}
+% The LEP is a control sequence with a star. Convert LEP to a real
+% number as needed.
+% \begin{macrocode}
+ \edef\tmp@exp{\noexpand%
+ \@getVarType{\expandafter\noexpand\rng@LEP}}\tmp@exp
+ \ifcase\varType % integer
+ \defineR{\rng@LEP}{\rng@LEP\RNG@Dec}%
+ \or % rational
+ \rng@dima=\expandafter\nOf\rng@LEP pt
+ \divide\rng@dima by\expandafter\dOf\rng@LEP
+ \defineR{\rng@LEP}{\strip@pt\rng@dima}%
+ \or % real
+ \defineR{\rng@LEP}{\rng@LEP}%
+ \fi
+% \end{macrocode}
+% Not a control sequence, but has a star
+% \begin{macrocode}
+ \else
+ \defineR{\rng@LEP}{\rng@LEP}%
+ \fi
+ \else
+% \end{macrocode}
+% No star, control sequence or not?
+% \begin{macrocode}
+ \rng@isControl{#3}%
+ \if\rng@isC@ntrol1% control sequence
+ \let\rng@CtrlLEP=1\def\rng@LEP{#3}%
+ \@getVarType{#3}%
+ \ifcase\varType % integer
+ \defineR{\rng@LEP}{\rng@LEP\RNG@Dec}%
+ \or % rational
+ \rng@dima=\nOf{#3}pt
+ \divide\rng@dima by\dOf{#3}%
+ \defineR{\rng@LEP}{\strip@pt\rng@dima}%
+ \or % real
+ \defineR{\rng@LEP}{\rng@LEP}%
+ \fi
+ \else
+% \end{macrocode}
+% A number, no star, number is required to be real
+% \begin{macrocode}
+ \defineR{\rng@LEP}{#3}%
+ \fi
+ \fi
+% \end{macrocode}
+% \paragraph{Right endpoint.} Check the right endpoint:
+% \begin{macrocode}
+ \rng@existStar{#4}\rng@NameEndpoint{\rng@UEP}%
+ \if\rng@isStariii*\edef\tmp@exp{\noexpand%
+ \rng@isControl{\expandafter\noexpand\rng@UEP}}\tmp@exp
+ \if\rng@isC@ntrol1% a control sequence
+ \let\rng@CtrlUEP=1\let\rng@makeUEPStrict=1%
+ \rng@cnta=\rng@lcg@last\advance\rng@cnta-1\relax
+ \edef\rng@lcg@last{\the\rng@cnta}%
+% \end{macrocode}
+% The UEP is a control sequence with a star. Convert UEP to a real
+% number as needed.
+% \begin{macrocode}
+ \edef\tmp@exp{\noexpand%
+ \@getVarType{\expandafter\noexpand\rng@UEP}}\tmp@exp
+ \ifcase\varType % integer
+ \defineR{\rng@UEP}{\rng@UEP\RNG@Dec}%
+ \or % rational
+ \rng@dima=\expandafter\nOf\rng@UEP pt
+ \divide\rng@dima by\expandafter\dOf\rng@UEP
+ \defineR{\rng@UEP}{\strip@pt\rng@dima}%
+ \or % real
+ \defineR{\rng@UEP}{\rng@UEP}%
+ \fi
+% \end{macrocode}
+% Not a control sequence, but has a star
+% \begin{macrocode}
+ \else
+ \defineR{\rng@UEP}{\rng@UEP}%
+ \fi
+ \else
+% \end{macrocode}
+% No star, control sequence or not?
+% \begin{macrocode}
+ \rng@isControl{#4}%
+ \if\rng@isC@ntrol1% control sequence
+ \let\rng@CtrlUEP=1\def\rng@UEP{#4}%
+ \@getVarType{#4}%
+ \ifcase\varType % integer
+ \defineR{\rng@UEP}{\rng@UEP\RNG@Dec}%
+ \or % rational
+ \rng@dima=\nOf{#4}pt
+ \divide\rng@dima by\dOf{#4}%
+ \defineR{\rng@UEP}{\strip@pt\rng@dima}%
+ \or % real
+ \defineR{\rng@UEP}{\rng@UEP}%
+ \fi
+ \else
+% \end{macrocode}
+% A number, no star, number is required to be real
+% \begin{macrocode}
+ \defineR{\rng@UEP}{#4}%
+ \fi
+ \fi
+% \end{macrocode}
+% Prepare to generate the random real
+% \begin{macrocode}
+ \def\@currentName{#2}\@getVarName{#2}%
+% \end{macrocode}
+% Save upper and lower endpoints where they are expected to be.
+% \begin{macrocode}
+ \expandafter\edef\csname first@\@varName\endcsname{\rng@LEP}%
+ \expandafter\edef\csname last@\@varName\endcsname{\rng@UEP}%
+% \end{macrocode}
+% Get a random real, and declare it to be a real number using \cs{defineR}.
+% \begin{macrocode}
+ \rng@getRandomR
+ \defineR{#2}{\strip@pt\rng@dima}%
+% \end{macrocode}
+% Round and remove trailing zeros.
+% \begin{macrocode}
+ \ifx\rangen@round\@empty\else
+ \RNGround{#2}{#2}{\rangen@round}%
+ \rng@dima=#2pt\relax
+ \defineR{#2}{\strip@pt\rng@dima}%
+ \fi
+% \end{macrocode}
+% \paragraph{Constraints.} Let's try to apply constraints. We only allow one constraint.
+% \begin{macrocode}
+ \ifx\rangen@ne\@empty\else\loopCnt=0\relax
+ \@whilenum\loopCnt<\maxLoopLimit\do{%
+ \rng@cnta=1\relax
+ \@for\ne@@tmp:=\rangen@ne\do{%
+ \rng@dima=#2pt
+ \ifdim\rng@dima=\ne@@tmp pt\relax
+ \multiply\rng@cnta0\relax\else
+ \multiply\rng@cnta1\relax\fi
+ }%
+ \ifnum\rng@cnta=1\relax % all conditions met
+ \loopCnt=\maxLoopLimit
+ \else % if \rng@cnta \ne 1, try again
+ \advance\loopCnt1\relax
+ \ifnum\loopCnt=\maxLoopLimit
+ \PackageWarning{rangen}{Not all conditions met
+ after \maxLoopLimit\space tries}%
+ \else
+ \rng@getRandomR
+ \defineR{#2}{\strip@pt\rng@dima}%
+% \end{macrocode}
+% Round and remove trailing zeros.
+% \begin{macrocode}
+ \ifx\rangen@round\@empty\else
+ \RNGround{#2}{#2}{\rangen@round}%
+ \rng@dima=#2pt\relax
+ \defineR{#2}{\strip@pt\rng@dima}%
+ \fi
+ \fi
+ \fi
+ }%
+ \fi
+% \end{macrocode}
+% \paragraph{Formatting.} Begin formatting of the real, keys recognized are
+% \texttt{round} and \texttt{showzeros}.
+% \begin{macrocode}
+ \rnd@ProcessRealFormat{#2}%
+% \end{macrocode}
+% We declare our number.
+% \begin{macrocode}
+ \def\@currentName{#2}%
+ \defineR{#2}{#2}%
+}
+% \end{macrocode}
+% Get a new random real and return it in the \cs{rng@dima}
+% \begin{macrocode}
+\def\rng@getRandomR{%
+% \end{macrocode}
+% Put the endpoints in dimension registers so we can subtract them.
+% \begin{macrocode}
+ \rng@dima=\rng@LEP pt
+ \rng@dimb=\rng@UEP pt
+% \end{macrocode}
+% Compute the difference between upper and lower, then strip off the \texttt{pt},
+% to make it a decimal number.
+% \begin{macrocode}
+ \advance\rng@dimb-\rng@dima
+% \edef\r@getDiff{\strip@pt\rng@dimb}%
+% \end{macrocode}
+% Get a random integer from the interval 0 to \cs{RNGpowerOfTen}.
+% the default value of the latter command is 100, and it can be changed
+% using \cs{nDivisionsPowerOfTen}. The idea is to divide the interval
+% from the lower bound to the upper bound into \cs{RNGpowerOfTen} nodes,
+% and we choose one of these nodes are random.
+%
+% If the endpoints where strict, then we changed \cs{rng@lcg@first}
+% from 0 to 1 (if the lower endpoint is strict); and changed
+% \cs{rng@lcg@last} from \cs{RNGpowerOfTen} to \texttt{\string\RNGpowerOfTen-1}
+% (if the upper end point is strict).
+% \begin{macrocode}
+ \rng@chgrand[first=\rng@lcg@first,last=\rng@lcg@last]\rand
+% \end{macrocode}
+% Divide the length of the interval by \cs{RNGpowerOfTen},
+% and store the result in \cs{rng@dimb}, then multiply
+% that by \verb!\arabic{rand}!.
+% \begin{macrocode}
+ \divide\rng@dimb by\RNGpowerOfTen\relax
+ \rng@dimb=\arabic{rand}\rng@dimb
+% \end{macrocode}
+% Finally, the left-end point is still in \cs{rng@dima}
+% we add the result in \cs{rng@dimb} to \cs{rng@dima}
+% to compute our random rational.
+% \begin{macrocode}
+ \advance\rng@dima by\rng@dimb
+}
+\def\rnd@ProcessRealFormat#1{%
+ \ifx\rangen@round\@empty
+ \rng@dima=#1pt\relax
+ \defineR{#1}{\strip@pt\rng@dima}%
+ \else
+ \RNGround{#1}{#1}{\rangen@round}%
+ \rng@dima=#1pt\relax
+ \defineR{#1}{\strip@pt\rng@dima}%
+ \iftrailingzeros
+ {\RNGparseDec{#1}\count0=\decPls\relax
+ \advance\count0-\rndnDec\relax
+ \ifnum\count0>0\relax\xdef#1{%
+ \rng@intpart\RNG@Dec\rng@fracpart%
+\@nameuse{rng@tz\the\count0}}%
+ \fi}%
+ \defineR{#1}{#1}%
+ \fi
+ \fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Random Sign}
+% \begin{macro}{\RandomS}
+% We randomly generate a \texttt{+} or \texttt{-} sign
+% for addition and subtraction. The first optional argument
+% is a rational number between 0 and 1. The default is \texttt{1/2}.
+% This number represents the probably of a \texttt{+} sign.
+% \begin{macrocode}
+\newcommand{\RandomS}[2][1/2]{%
+ \RNGparseRat{#1}%
+ \ifnum\rng@num<0\relax
+ \PackageError{rangen}{A positive numerator is required}%
+ {The rational number must be between 0 and 1}\fi
+ \ifnum\rng@denom<0\relax
+ \PackageError{rangen}{A positive denominator is required}%
+ {The rational number must be between 0 and 1}\fi
+ \ifnum\rng@num>\rng@denom\relax
+ \PackageError{rangen}{The rational must be between 0 and 1}%
+ {The rational number must be between 0 and 1}\fi
+ \rng@chgrand[first=1,last=\rng@denom]\rand
+ \@getVarName{#2}%
+ \ifnum\value{rand}>\rng@num\relax\def#2{-}%
+ \rng@makeMinusOneFmtDefns
+ \def\display@TeXfmt{-}\def\inline@TeXfmt{-}%
+ \else\def#2{+}\rng@makeOneFmtDefns
+ \def\display@TeXfmt{}\def\inline@TeXfmt{}\fi
+ \expandafter\let\csname\@varName*\endcsname\display@TeXfmt
+ \expandafter\let\csname\@varName!\endcsname\inline@TeXfmt
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Random Number from a List}
+%
+% \begin{macro}{\RandomL}
+% Select a number of any type from a comma-delimited list.
+%\begin{verbatim}
+% \RandomL[key-values]{\RV}{<comma-delimited list>}
+%\end{verbatim}
+% Currently, the only key recognized is the \texttt{index} key.
+% If the \texttt{index} key is specified, the number whose index is specified
+% is retrieved from the list.
+% \begin{macrocode}
+\newcommand{\RandomL}[3][]{%
+ \let\rangen@index\@empty
+ \setkeys{rangen}{#1}%
+ \rng@cnta=0\relax\@for\@@tmp:=#3\do{%
+ \advance\rng@cnta1\relax}\edef\n@rng@listItems{\the\rng@cnta}%
+ \ifx\rangen@index\@empty
+ \rng@chgrand[first=1,last=\n@rng@listItems]\rand
+ \else
+ \rng@cnta=\rangen@index
+ \advance\rng@cnta-1\relax
+ \amodb{\rng@cnta}{\n@rng@listItems}%
+ \rng@cnta=\retnmod
+ \advance\rng@cnta1\relax
+ \value{rand}=\rng@cnta
+ \fi
+ \@getVarName{#2}%
+ \expandafter\edef\csname i@\@varName\endcsname{\arabic{rand}}%
+ \rng@cnta=0\relax\@for\@@tmp:=#3\do{%
+ \advance\rng@cnta1\relax\ifnum\rng@cnta=\arabic{rand}%
+ \edef\rng@choice{\@@tmp}\fi}%
+ \def\@currentName{#2}%
+% \end{macrocode}
+% Now, determine the type of this choice, and make appropriate
+% data type definition.
+% \begin{macrocode}
+ \RNGparseDec{\rng@choice}%
+ \if\rng@parseR@iii\RNG@Dec\defineR{#2}{\rng@choice}%
+ \else\RNGparseRat{\rng@choice}%
+ \if\rng@parseQ@iii/\defineQ{#2}{\rng@num}{\rng@denom}%
+ \else\defineZ{#2}{\rng@choice}\fi\fi
+}
+% \end{macrocode}
+% \end{macro}
+
+% \subsubsection{Random Problem from a List}
+%
+% \begin{macro}{\RandomP}
+% Select a literal from a comma-delimited list of literals.
+%\begin{verbatim}
+% \RandomP[key-values]{\RV}{<comma-delimited list>}
+%\end{verbatim}
+% Currently, the only key recognized is the \texttt{index} key.
+% If the \texttt{index} key is specified, the number whose index is specified
+% is retrieved from the list.
+% \begin{macrocode}
+\newcommand{\RandomP}[3][]{%
+ \let\rangen@index\@empty
+ \setkeys{rangen}{#1}%
+ \rng@cnta=0\relax\@for\@@tmp:=#3\do{%
+ \advance\rng@cnta1\relax}\edef\n@rng@listItems{\the\rng@cnta}%
+ \ifx\rangen@index\@empty
+ \rng@chgrand[first=1,last=\n@rng@listItems]\rand
+ \else
+ \rng@cnta=\rangen@index
+ \advance\rng@cnta-1\relax
+ \amodb{\rng@cnta}{\n@rng@listItems}%
+ \rng@cnta=\retnmod
+ \advance\rng@cnta1\relax
+ \value{rand}=\rng@cnta
+ \fi
+ \@getVarName{#2}%
+ \expandafter\edef\csname i@\@varName\endcsname{\arabic{rand}}%
+ \rng@cnta=0\relax\@for\@@tmp:=#3\do{%
+ \advance\rng@cnta1\relax\ifnum\rng@cnta=\arabic{rand}%
+ \rng@toks=\expandafter{\@@tmp}\edef#2{\the\rng@toks}%
+ \expandafter\def\csname typeof@\@varName\endcsname{3}\fi}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Random Index}
+%
+% \begin{macro}{\RandomI}
+% This command creates an implied list of \verb!{1, 2, 3,...,n}!,
+% and randomly selects a number from this list. The result is
+% defined as an integer, and held in the macro \texttt{\#1}.
+%\begin{verbatim}
+% \Random{\i}{n} --> select \i from {1, 2, 3,...,n} at random
+%\end{verbatim}
+%A random index, \cs{i}, created by \cs{RandomI}, can be used
+%in the \cs{RandomL} command; for example,
+%\begin{verbatim}
+% \RandomL[index=\i]{\a}{17,\rPI,3/4,\rE,88,1/2}
+%\end{verbatim}
+%The value of \cs{a} is determined by the index \cs{i}.
+% \begin{macrocode}
+\newcommand{\RandomI}[2]{%
+ \rng@chgrand[first=1,last=#2]\rand
+ \defineZ{#1}{\arabic{rand}}%
+ \expandafter\edef\csname i@\@varName\endcsname{\arabic{rand}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Some Constants}
+%
+% \begin{macro}{\zZero}
+% \begin{macro}{\zOne}
+% \begin{macro}{\zMinusOne}
+% \begin{macro}{\rPI}
+% \begin{macro}{\rE}
+% Define three convenience integers corresponding to $0$, $1$, and $-1$.
+% \begin{macrocode}
+\defineZ{\zZero}{0}
+\defineZ{\zOne}{1}
+\defineZ{\zMinusOne}{-1}
+\defineR{\rPI}{3.1415927}
+\defineR{\rE}{2.7182818}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% This macro takes \cs{@varName} and \cs{cmp@Name} and converts to the same common
+% denominator. This makes it easy to make comparisons between two rational numbers.
+% \begin{macrocode}
+\def\syncronizeQs#1{\edef\sync@arg{#1}%
+ \lcm{\csname d@\sync@arg\endcsname}{\d@cmp@Name}%
+ \edef\@thelcm{\thelcm}%
+ \convertRatTo{\n@cmp@Name}{\d@cmp@Name}{\@thelcm}%
+ \updateQ\cmp@Name{\rng@retn@num}{\@thelcm}%
+ \convertRatTo{\csname n@\sync@arg\endcsname}%
+ {\csname d@\sync@arg\endcsname}{\@thelcm}\expandafter
+ \defineQ\csname\sync@arg\endcsname{\rng@retn@num}{\@thelcm}%
+}
+% \end{macrocode}
+% \subsection{Formatting Commands}
+% \begin{macro}{\ds}
+% \begin{macro}{\eds}
+% \begin{macro}{\cds}
+% Displays an alternate representation (\textbf display\textbf style) of the random variable. Usage \cs{ds}\cs{a}.
+% This displays the contents of \cs{display@TeXfmt} for this variable. The value of \cs{display@TeXfmt}
+% is effected by the formatting commands above.
+%
+% For a rational number \cs{a}, the expression \cs{ds}\cs{a} expands either to the special format representation, or
+% to a rational of the form $\frac{p}{q}$.
+% \begin{macrocode}
+\newcommand\ds[1]{%
+ \expandafter\csname\expandafter\@gobble\string#1*\endcsname
+}
+\newcommand\eds[1]{%
+ \expandafter\csname\expandafter\@gobble\string#1*e\endcsname
+}
+\newcommand\cds[1]{%
+ \expandafter\csname\expandafter\@gobble\string#1*c\endcsname
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \begin{macro}{\fmt}
+% \begin{macro}{\efmt}
+% \begin{macro}{\cfmt}
+% Displays a special format for the random variable. Usage \cs{ds}\cs{a}.
+% This displays the contents of \cs{display@TeXfmt} for this variable.
+% Same as \cs{ds}, but does not display a display style if there is not
+% special formatting.
+%
+% For a rational number \cs{a}, the expression \cs{ds}\cs{a} expands either to the special format representation, or
+% to a rational of the form $p/q$.
+% \begin{macrocode}
+\newcommand\fmt[1]{%
+ \expandafter\csname\expandafter\@gobble\string#1!\endcsname
+}
+\newcommand\efmt[1]{%
+ \expandafter\csname\expandafter\@gobble\string#1!e\endcsname
+}
+\newcommand\cfmt[1]{%
+ \expandafter\csname\expandafter\@gobble\string#1!c\endcsname
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \begin{macro}{\js}
+% Used within \cs{CorrAnsButton} to get a more precise expansion of a variable. Used with variables
+% that have been defined using \cs{defineDepVar}. When you say \verb+\js\m+, for example,
+% the \cs{eval@JSfmt} is expanded.
+% \par\medskip\noindent
+% \textbf{Usage:} \verb+\CorrAnsButton*{y = \js\m\space x }+
+% \begin{macrocode}
+\newcommand\js[1]{%
+ \expandafter\csname\expandafter\@gobble\string#1!*\endcsname
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Commands specialized to Reals}
+
+% \begin{macro}{\RNGround}
+% Round \texttt{\#1} to \texttt{\#3} decimal places, and leave result in \texttt{\#2}.
+% \begin{macrocode}
+\def\RNGround#1#2#3{%
+ \begingroup
+ \def\rng@ctrlName{#1}%
+ \def\rng@sourceName{#2}%
+ \def\rng@nDecPl{#3}%
+ \RNGparseDec{#2}%
+ \ifnum\rndnDec<#3\relax
+ \xdef\theseDigits{\rng@fracpart}%
+ \let\rng@next\relax
+ \else
+ \count0=0\relax
+ \gdef\theseDigits{}%
+ \def\rng@next{\expandafter\@rng@round\rng@fracpart\end}%
+ \fi
+ \rng@next
+ \xdef\decPls{\@ifundefined{save@rng@nDecPl}%
+ {\rng@nDecPl}{\save@rng@nDecPl}}%
+ \ifx\theseDigits\@empty
+ \xdef#1{\rng@intpart}\else
+ \xdef#1{\rng@intpart\RNG@Dec\theseDigits}\fi
+ \endgroup
+}
+\def\@rng@round#1{%
+ \ifx#1\end\let\rng@next\relax
+ \else
+ \ifnum\rng@nDecPl=0\relax
+ \ifnum#1>4\relax
+ \count0=\rng@intpart\relax
+ \ifnum\rng@intpart<0\relax
+ \advance\count0by-1\relax
+ \else
+ \advance\count0by1\relax
+ \fi
+ \xdef\rng@intpart{\the\count0}%
+ \fi
+ \gdef\theseDigits{}%
+ \let\rng@next\rng@gobbletoend
+ \else
+ \advance\count0by1\relax
+ \ifnum\count0=\rng@nDecPl\relax
+ \def\rng@next{\@@rng@round#1}%
+ \else
+ \xdef\theseDigits{\theseDigits#1}%
+ \let\rng@next\@rng@round
+ \fi
+ \fi
+ \fi
+ \rng@next
+}
+\def\rng@gobbletoend#1\end{}
+\def\@@rng@round#1#2{%
+ \ifx#2\end%
+ \xdef\theseDigits{\theseDigits#1}%
+ \let\rng@next\relax
+ \else
+ \ifnum#2>4\relax\count2=#1\relax
+ \ifnum\count2=9\relax
+ \count0=\rng@nDecPl\relax
+ \ifnum\count0=1\relax
+ \count0=\rng@intpart\relax
+ \ifnum\rng@intpart<0\relax
+ \advance\count0by-1\relax
+ \else
+ \advance\count0by1\relax
+ \fi
+ \xdef\rng@intpart{\the\count0}%
+ \let\rng@next\rng@gobbletoend
+ \else
+ \advance\count0by-1\relax\expandafter
+ \xdef\rng@sourceName{%
+ \rng@intpart\RNG@Dec\theseDigits#1}%
+ \edef\save@rng@nDecPl{\rng@nDecPl}%
+ \edef\rng@next{\noexpand\RNGround{%
+ \expandafter\noexpand\rng@ctrlName}%
+ {\expandafter\noexpand\rng@sourceName}%
+ {\the\count0}\noexpand\rng@gobbletoend}%
+ \fi
+ \else
+ \advance\count2by1\relax
+ \xdef\theseDigits{\theseDigits\the\count2}%
+ \let\rng@next\rng@gobbletoend
+ \fi
+ \else % \ifnum#2<=4
+ \xdef\theseDigits{\theseDigits#1}%
+ \let\rng@next\rng@gobbletoend
+ \fi
+ \fi
+ \rng@next
+}
+% \end{macrocode}
+% \end{macro}
+% Used with \cs{CorrAnsButton} and \texttt{rngCorrAnsButton}, like so,
+%\begin{verbatim}
+% \CorrAnsButton{rEval(\strAns)}*{rngCorrAnsButton\RNGprintf{\%.2f}}
+%\end{verbatim}
+% \begin{macrocode}
+\def\RNGprintf#1{("#1",\@gobble}
+% \end{macrocode}
+%
+% \subsection{User Defined Dependent Variables for JavaScript}
+% \begin{macro}{\defineDepQJS}
+% Define a rational as a function of other integers. This macro defines
+% \cs{fmt} and \cs{ds} for the variable, but its primary use it
+% for \cs{js}. This command is aimed at the JavaScript side of things
+%\begin{verbatim}
+%#1 = name of rational to be defined, e.g., \a
+%#2 = numerator
+%#3 = denominator
+%#4 = \js expression for #1
+%\end{verbatim}
+% Usage:
+%\begin{verbatim}
+% \defineDepQJS{\m}{\d-\b}{\c-\a}
+% {rFrac(rEval(\nOf\m)/rEval(\dOf\m))}
+% ...
+% \CorrAnsButton{y = \js\m\space x}*{rngCorrAnsButton}%
+%\end{verbatim}
+% The above example would calculate equation of the line passing through
+% the two points \verb!P(\a,\b)! and \verb!Q(\c,\d)!. The code is used
+% in the \cs{CorrAnsButton} to have the answer appear.
+% \begin{macrocode}
+\newcommand\defineDepQJS[4]{%
+ \@getVarName#1
+ \expandafter\edef\csname\@varName\endcsname{(#2)/(#3)}%
+ \expandafter\edef\csname n@\@varName\endcsname{(#2)}%
+ \expandafter\edef\csname d@\@varName\endcsname{(#3)}%
+ \edef\display@TeXfmt{\csname\@varName\endcsname}%
+ \edef\inline@TeXfmt{\csname\@varName\endcsname}%
+ \def\dv@argiv{#4}\ifx\dv@argiv\@empty
+ \edef\eval@JSfmt{\csname\@varName\endcsname}\else
+ \edef\eval@JSfmt{#4}\fi
+ \expandafter\let\csname\@varName!*\endcsname\eval@JSfmt
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Writing RVs to Solution Files}
+% \begin{macrocode}
+\def\rng@writeCurrentSeed#1{\immediate\write#1{\string\makeatletter
+ \string\global\string\cr@nd=\the\cr@nd\string\relax
+ \string\makeatother}}
+% \end{macrocode}
+% Token register to hold the verbatim contents of the \texttt{writeRVsTo} environment.
+% \begin{macrocode}
+\newtoks\rng@toks
+\def\wrv@ex@solns{exercises}%
+\def\wrv@ex@quiz{quizzes}%
+% \end{macrocode}
+% \begin{environment}{writeRVsTo}
+% This environment takes its environment contents and writes it to
+% two files, one file is \cs{jobname\_rvs.cut} which is input back
+% into the source file immediately. The second parameter
+% accepts the string \texttt{exercises} or \texttt{quizzes}, or a write
+% handle to write to an auxiliary file. The environment was designed for
+% use with the \texttt{exercise}, \texttt{quiz}, and \texttt{shortquiz} environments
+% of \textsf{exerquiz}.
+% \begin{macrocode}
+\newenvironment{writeRVsTo}[2][]
+{%
+ \def\wrv@argii{#2}%
+ \ifx\wrv@argii\wrv@ex@quiz\let\wrv@out\quiz@solns
+ \else\ifx\wrv@argii\wrv@ex@solns\let\wrv@out\ex@solns\else
+ \let\wrv@out#2\fi\fi
+ \rng@writeCurrentSeed\wrv@out
+ \rng@toks={}%
+ \def\verbatim@processline{%
+ \xdef\rng@temp{\the\rng@toks\the\verbatim@line}%
+ \global\rng@toks=\expandafter{\rng@temp}}%
+ \let\do\@makeother\dospecials\catcode`\^^M\active
+ #1%
+ \verbatim@start
+}{ \immediate\write\wrv@out{\the\rng@toks}%
+ \newwrite\rng@writeRVs
+ \immediate\openout\rng@writeRVs\jobname_rvs.cut
+ \immediate\write\rng@writeRVs{\the\rng@toks}%
+ \immediate\closeout\rng@writeRVs
+ \aftergroup\rng@Input@RVs
+}
+% \end{macrocode}
+% \end{environment}
+% After the \texttt{writeRVsTo} environment writes the RVs to
+% \cs{jobname\_rvs.cut}. The environment executes
+% \cs{rng@Input@RVs} to input the file back into the source file.
+% \begin{macrocode}
+\def\rng@Input@RVs{\InputIfFileExists{\jobname_rvs.cut}{}{}}
+% \end{macrocode}
+% \subsection{Redefine lcg Package Macro}
+% \begin{macrocode}
+\def\rng@p@stkeysr@nd{%
+ \@rderr@nd% last < first -> swap
+ \cutr@nger@nd% range too big -> cut
+} % end of \def\p@stkeysr@nd
+\def\rng@chgrand{\@ifnextchar[\rng@chgr@nd{\rng@chgr@nd[]}}
+\def\rng@chgr@nd[#1]{%
+ \@tempcnta=\z@
+ \@tempcntb=\z@
+ \setkeys{Init}{#1}%
+ \rng@p@stkeysr@nd%
+ \@utputr@nd%
+} % end of \def\rng@chgrand
+% \end{macrocode}
+% \subsection{DLJS Support}
+% \begin{macrocode}
+\begin{insDLJS}[partialExpand]{partial}{Rangen}
+var partre = /rEval|rFrac/;
+% \end{macrocode}
+% The arguments for this function take two forms
+% (1) \texttt{fieldname}, \texttt{theanswer} (the default); (2)
+% \texttt{theformat}, \texttt{fieldname}, \texttt{theanswer}. The later case
+% is created by using the \cs{RNGprintf} command that inserts allows the
+% document author to insert a \texttt{printf} formatting template. For example,
+%\begin{verbatim}
+% \CorrAnsButton{rEval(\strAns)}*{rngCorrAnsButton\RNGprintf{\%.4f}}
+%\end{verbatim}
+% \begin{macrocode}
+function rngCorrAnsButton()
+{
+ var theprecision,fieldname,theanswer;
+ if (arguments.length==4) {
+ var theformat=arguments[0];
+ var fieldname=arguments[1];
+ var theanswer=arguments[2];
+ var thequiz=arguments[3];
+ } else {
+ var fieldname=arguments[0];
+ var theanswer=arguments[1];
+ var thequiz=arguments[2];
+ }
+ theanswer = partialExpand(0,theanswer);
+ if (arguments.length==4)
+ theanswer=util.printf(theformat,eval(theanswer));
+ DisplayAnswer(fieldname,theanswer,thequiz);
+}
+% \end{macrocode}
+% The JavaScript function \texttt{partialExpand} searches through \texttt{Ans} in search of
+% \texttt{rEval} and \texttt{rFrac}. It calls itself recursively to search for the inner most
+% appearances of these two functions. It evaluates these two functions starting with the inner
+% most and working its way outward.
+% \begin{macrocode}
+function partialExpand(level,Ans)
+{
+ Ans = correctPlusMinus(Ans)
+ level += 1;
+\db console.println("Enter level = " + level +": Ans: " + Ans);\db%
+ var n=0, m, bP, eP, subExp;
+ while ( true ) {
+\db console.println("Searching a level " + level);\db%
+ try { m = Ans.match(partre); }
+ catch (e) { break; }
+ if ( m != null ) {
+ bP = m.index + m[0].length;
+ eP = FindBalP(Ans, bP, true);
+\db console.println("bP = " + bP + " : eP = " + eP);\db%
+ var subExp = Ans.substring(bP+1, eP);
+\db console.println("Found \'" + subExp%
+ + "\' at level = " + level);\db%
+% subExp = partialExpand(level, subExp);
+ // n = beginning of "rEval",
+ // eP = beginning of balanced parens,
+ // bP = end of balanced parens
+ Ans = Ans.substring(0, m.index)
+ + eval(m[0]+"(level,subExp)") + Ans.substring(eP+1);
+\db console.println("level = " + level%
+ +": New Ans: " + Ans);\db %
+ } else {
+ if ( level == 1 ) {
+\db console.println("Level 1 break");\db %
+ break;
+ }
+ }
+ }
+\db console.println("Return Ans: " + Ans);\db%
+ Ans = correctPlusMinus(Ans);
+ return Ans;
+}
+% \end{macrocode}
+% Evaluates the value of \texttt{Ans}.
+% \begin{macrocode}
+function rEval(level, Ans)
+{
+ level += 1;
+\db console.println("Enter rEval: level = "%
+ + level +": Ans: " + Ans);\db%
+ var n=0, m, bP, eP, subExp;
+ while ( true )
+ {
+\db console.println("Searching a level " + level);\db%
+ try { m = Ans.match(partre); }
+ catch (e) { break; }
+ if ( m != null ) {
+ bP = m.index + m[0].length;
+ eP = FindBalP(Ans, bP, true);
+\db console.println("bP = " + bP + " : eP = " + eP);\db%
+ var subExp = Ans.substring(bP+1, eP);
+\db console.println("Found \'" + subExp%
+ + "\' at level = " + level);\db%
+ // n = beginning of "rEval",
+ // eP = beginning of balanced parens,
+ // bP = end of balanced parens
+ Ans = Ans.substring(0, m.index)
+ +eval(m[0]+"(level,subExp)")+Ans.substring(eP+1);
+\db console.println("level = "%
+ + level +": New Ans: " + Ans);\db %
+ } else {
+ Ans = ParseInput(Ans);
+\db console.println("Ready to eval at level = "%
+ + level + ": Ans = " + Ans);\db%
+ with(Math) { Ans = eval( Ans ) };
+\db console.println("After eval at level = "%
+ + level + ": Ans = " + Ans);\db%
+ break;
+ }
+ }
+\db console.println("Return Ans: " + Ans);\db%
+ return Ans;
+}
+% \end{macrocode}
+% Evaluates an rational number by evaluating the value of the numerator and denominator separately.
+% \begin{macrocode}
+function rFrac(level, Ans)
+{
+ level += 1;
+\db console.println("Enter rFrac level = "%
+ + level +": Ans: " + Ans);\db%
+ var n=0, m, bP, eP, subExp;
+ while ( true ) {
+\db console.println("Searching a level " + level);\db%
+ try { m = Ans.match(partre); }
+ catch (e) { break; }
+ if ( m != null ) {
+ bP = m.index + m[0].length;
+ eP = FindBalP(Ans, bP, true);
+\db console.println("bP = "%
+ + bP + " : eP = " + eP);\db%
+ var subExp = Ans.substring(bP+1, eP);
+\db console.println("Found \'" + subExp%
+ + "\' at level = " + level);\db%
+ // n = beginning of "rEval",
+ // eP = beginning of balanced parens,
+ // bP = end of balanced parens
+ Ans = Ans.substring(0, m.index)
+ + eval(m[0]+"(level,subExp)") + Ans.substring(eP+1);
+\db console.println("level = " + level%
+ +": New Ans: " + Ans);\db %
+ } else {
+ var numDenom = Ans.split("/");
+ numDenom[0] = eval(numDenom[0]);
+ numDenom[1] = eval(numDenom[1]);
+ var g = gcd(numDenom[0], numDenom[1]);
+ numDenom[0] /= g;
+ numDenom[1] /= g;
+ if ( numDenom[1] == 1)
+ Ans = numDenom[0];
+ else
+ Ans = numDenom.join("/");
+\db console.println("Reduce: " + numDenom.join("/"));\db%
+ break;
+ }
+ }
+\db console.println("Return Ans: " + Ans);\db%
+ return Ans;
+}
+function correctPlusMinus(Ans)
+{
+ Ans = "" + Ans;
+ Ans = Ans.replace(/\s*([\+-])\s*\1\s*/g, " + ");
+ Ans = Ans.replace(/\s*\+\s*-\s*/g, " - ");
+% Ans = Ans.replace(/\s*\+\s*\+\s*/g, " + ");
+% Ans = Ans.replace(/\s*-\s*-\s*/g, " + ");
+ Ans = Ans.replace(/\s*-\s*\+\s*/g, " - ");
+ return Ans;
+}
+function gcd(a,b)
+{
+ var x = a, y = b, r;
+ while (true)
+ {
+ r = x \% y;
+ if ( r == 0 ) break;
+ x = y;
+ y = r;
+ }
+ return Math.abs(y);
+}
+function lcm (a,b) { return (a*b)/gcd(a,b); }
+\end{insDLJS}
+%</package>
+% \end{macrocode}
+\endinput