%\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. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %\NeedsTeXFormat{LaTeX2e}[1997/12/01] %\ProvidesPackage{rangen} % [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} % % \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[]{\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}{} %\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}{} %\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} % % \end{macrocode} \endinput