% \iffalse meta-comment % %% File: l3int.dtx % % Copyright (C) 1990-2024 The LaTeX Project % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this % license or (at your option) any later version. The latest version % of this license is in the file % % https://www.latex-project.org/lppl.txt % % This file is part of the "l3kernel bundle" (The Work in LPPL) % and all files in that bundle must be distributed together. % % ----------------------------------------------------------------------- % % The development version of the bundle can be found at % % https://github.com/latex3/latex3 % % for those people who are interested. % %<*driver> \documentclass[full,kernel]{l3doc} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{^^A % The \pkg{l3int} module\\ Integers^^A % } % % \author{^^A % The \LaTeX{} Project\thanks % {^^A % E-mail: % \href{mailto:latex-team@latex-project.org} % {latex-team@latex-project.org}^^A % }^^A % } % % \date{Released 2024-11-02} % % \maketitle % % \begin{documentation} % % Calculation and comparison of integer values can be carried out % using literal numbers, \texttt{int} registers, constants and % integers stored in token list variables. The standard operators % \texttt{+}, \texttt{-}, \texttt{/} and \texttt{*} and % parentheses can be used within such expressions to carry % arithmetic operations. This module carries out these functions % on \emph{integer expressions} (\enquote{\meta{int expr}}). % % \section{Integer expressions} % % Throughout this module, (almost) all \texttt{n}-type argument allow % for an \meta{intexpr} argument with the following syntax. The % \meta{integer expression} should consist, % after expansion, of \texttt{+}, \texttt{-}, \texttt{*}, \texttt{/}, % \texttt{(}, \texttt{)} and of course integer operands. The result % is calculated by applying standard mathematical rules with the % following peculiarities: % \begin{itemize} % \item \texttt{/} denotes division rounded to the closest integer with % ties rounded away from zero; % \item there is an error and the overall expression evaluates to zero % whenever the absolute value of any intermediate result exceeds % $2^{31}-1$, except in the case of scaling operations % $a$\texttt{*}$b$\texttt{/}$c$, for which $a$\texttt{*}$b$ may be % arbitrarily large (but the operands $a$, $b$, $c$ are still % constrained to an absolute value at most $2^{31}-1$); % \item parentheses may not appear after unary \texttt{+} or % \texttt{-}, namely placing \texttt{+(} or \texttt{-(} at the start % of an expression or after \texttt{+}, \texttt{-}, \texttt{*}, % \texttt{/} or~\texttt{(} leads to an error. % \end{itemize} % Each integer operand can be either an integer variable (with no need % for \cs{int_use:N}) or an integer denotation. For example both % \begin{verbatim} % \int_show:n { 5 + 4 * 3 - ( 3 + 4 * 5 ) } % \end{verbatim} % and % \begin{verbatim} % \tl_new:N \l_my_tl % \tl_set:Nn \l_my_tl { 5 } % \int_new:N \l_my_int % \int_set:Nn \l_my_int { 4 } % \int_show:n { \l_my_tl + \l_my_int * 3 - ( 3 + 4 * 5 ) } % \end{verbatim} % show the same result $-6$ because \cs[no-index]{l_my_tl} expands to % the integer denotation~|5| while the integer variable \cs[no-index]{l_my_int} % takes the value~$4$. As the \meta{integer expression} is fully % expanded from left to right during evaluation, fully expandable and % restricted-expandable functions can both be used, and \cs{exp_not:n} % and its variants have no effect while \cs{exp_not:N} may incorrectly % interrupt the expression. % % \begin{function}[EXP]{\int_eval:n} % \begin{syntax} % \cs{int_eval:n} \Arg{int expr} % \end{syntax} % Evaluates the \meta{int expr} and leaves the result in the % input stream as an integer denotation: for positive results an % explicit sequence of decimal digits not starting with~\texttt{0}, % for negative results \texttt{-}~followed by such a sequence, and % \texttt{0}~for zero. % \begin{texnote} % Exactly two expansions are needed to evaluate \cs{int_eval:n}. % The result is \emph{not} an \meta{internal integer}, and therefore % requires suitable termination if used in a \TeX{}-style integer % assignment. % % As all \TeX{} integers, integer operands can also be dimension or % skip variables, converted to integers in~\texttt{sp}, or octal % numbers given as \texttt{'} followed by digits other than % \texttt{8} and \texttt{9}, or hexadecimal numbers given as % |"| followed by digits or upper case letters from % \texttt{A} to~\texttt{F}, or the character code of some character % or one-character control sequence, given as \texttt{`}\meta{char}. % \end{texnote} % \end{function} % % \begin{function}[EXP, added = 2018-03-30]{\int_eval:w} % \begin{syntax} % \cs{int_eval:w} \meta{int expr} % \end{syntax} % Evaluates the \meta{int expr} as described for % \cs{int_eval:n}. The end of the expression is the first token % encountered that cannot form part of such an expression. If that % token is \cs{scan_stop:} it is removed, otherwise not. Spaces do % \emph{not} terminate the expression. However, spaces terminate % explicit integers, and this may terminate the expression: for % instance, \cs{int_eval:w} \verb*|1 + 1 9| (with explicit space % tokens inserted using |~| in a code setting) expands to \texttt{29} % since the digit~\texttt{9} is not part of the expression. Expansion % details, etc., are as given for \cs{int_eval:n}. % \end{function} % % \begin{function}[EXP, added = 2018-11-03]{\int_sign:n} % \begin{syntax} % \cs{int_sign:n} \Arg{int expr} % \end{syntax} % Evaluates the \meta{int expr} then leaves $1$ or $0$ or % $-1$ in the input stream according to the sign of the result. % \end{function} % % \begin{function}[EXP, updated = 2012-09-26]{\int_abs:n} % \begin{syntax} % \cs{int_abs:n} \Arg{int expr} % \end{syntax} % Evaluates the \meta{int expr} as described for % \cs{int_eval:n} and leaves the absolute value of the result in % the input stream as an \meta{integer denotation} after two % expansions. % \end{function} % % \begin{function}[EXP, updated = 2012-09-26]{\int_div_round:nn} % \begin{syntax} % \cs{int_div_round:nn} \Arg{int expr_1} \Arg{int expr_2} % \end{syntax} % Evaluates the two \meta{int expr}s as described earlier, % then divides the first value by the second, and rounds the result % to the closest integer. Ties are rounded away from zero. % Note that this is identical to using % |/| directly in an \meta{int expr}. The result is left in % the input stream as an \meta{integer denotation} after two expansions. % \end{function} % % \begin{function}[EXP, updated = 2012-02-09]{\int_div_truncate:nn} % \begin{syntax} % \cs{int_div_truncate:nn} \Arg{int expr_1} \Arg{int expr_2} % \end{syntax} % Evaluates the two \meta{int expr}s as described earlier, % then divides the first value by the second, and rounds the result % towards zero. Note that division using |/| % rounds to the closest integer instead. % The result is left in the input stream as an % \meta{integer denotation} after two expansions. % \end{function} % % \begin{function}[EXP, updated = 2012-09-26]{\int_max:nn, \int_min:nn} % \begin{syntax} % \cs{int_max:nn} \Arg{int expr_1} \Arg{int expr_2} % \cs{int_min:nn} \Arg{int expr_1} \Arg{int expr_2} % \end{syntax} % Evaluates the \meta{int expr}s as described for % \cs{int_eval:n} and leaves either the larger or smaller value % in the input stream as an \meta{integer denotation} after two % expansions. % \end{function} % % \begin{function}[EXP, updated = 2012-09-26]{\int_mod:nn} % \begin{syntax} % \cs{int_mod:nn} \Arg{int expr_1} \Arg{int expr_2} % \end{syntax} % Evaluates the two \meta{int expr}s as described earlier, % then calculates the integer remainder of dividing the first % expression by the second. This is obtained by subtracting % \cs{int_div_truncate:nn} \Arg{int expr_1} \Arg{int expr_2} times % \meta{int expr_2} from \meta{int expr_1}. Thus, the result has the % same sign as \meta{int expr_1} and its absolute value is strictly % less than that of \meta{int expr_2}. The result is left in the input % stream as an \meta{integer denotation} after two expansions. % \end{function} % % \section{Creating and initialising integers} % % \begin{function}{\int_new:N, \int_new:c} % \begin{syntax} % \cs{int_new:N} \meta{integer} % \end{syntax} % Creates a new \meta{integer} or raises an error if the name is % already taken. The declaration is global. The \meta{integer} is % initially equal to $0$. % \end{function} % % \begin{function}[updated = 2011-10-22]{\int_const:Nn, \int_const:cn} % \begin{syntax} % \cs{int_const:Nn} \meta{integer} \Arg{int expr} % \end{syntax} % Creates a new constant \meta{integer} or raises an error if the name % is already taken. The value of the \meta{integer} is set % globally to the \meta{int expr}. % \end{function} % % \begin{function}{\int_zero:N, \int_zero:c, \int_gzero:N, \int_gzero:c} % \begin{syntax} % \cs{int_zero:N} \meta{integer} % \end{syntax} % Sets \meta{integer} to $0$. % \end{function} % % \begin{function}[added = 2011-12-13] % {\int_zero_new:N, \int_zero_new:c, \int_gzero_new:N, \int_gzero_new:c} % \begin{syntax} % \cs{int_zero_new:N} \meta{integer} % \end{syntax} % Ensures that the \meta{integer} exists globally by applying % \cs{int_new:N} if necessary, then applies % \cs[index=int_zero:N]{int_(g)zero:N} to leave % the \meta{integer} set to zero. % \end{function} % % \begin{function} % { % \int_set_eq:NN, \int_set_eq:cN, \int_set_eq:Nc, \int_set_eq:cc, % \int_gset_eq:NN, \int_gset_eq:cN, \int_gset_eq:Nc, \int_gset_eq:cc % } % \begin{syntax} % \cs{int_set_eq:NN} \meta{integer_1} \meta{integer_2} % \end{syntax} % Sets the content of \meta{integer_1} equal to that of % \meta{integer_2}. % \end{function} % % \begin{function}[EXP, pTF, added=2012-03-03] % {\int_if_exist:N, \int_if_exist:c} % \begin{syntax} % \cs{int_if_exist_p:N} \meta{integer} % \cs{int_if_exist:NTF} \meta{integer} \Arg{true code} \Arg{false code} % \end{syntax} % Tests whether the \meta{integer} is currently defined. This does not % check that the \meta{integer} really is an integer variable. % \end{function} % % \section{Setting and incrementing integers} % % \begin{function}[updated = 2011-10-22] % {\int_add:Nn, \int_add:cn, \int_gadd:Nn, \int_gadd:cn} % \begin{syntax} % \cs{int_add:Nn} \meta{integer} \Arg{int expr} % \end{syntax} % Adds the result of the \meta{int expr} to the current % content of the \meta{integer}. % \end{function} % % \begin{function}{\int_decr:N, \int_decr:c, \int_gdecr:N, \int_gdecr:c} % \begin{syntax} % \cs{int_decr:N} \meta{integer} % \end{syntax} % Decreases the value stored in \meta{integer} by $1$. % \end{function} % % \begin{function}{\int_incr:N, \int_incr:c, \int_gincr:N, \int_gincr:c} % \begin{syntax} % \cs{int_incr:N} \meta{integer} % \end{syntax} % Increases the value stored in \meta{integer} by $1$. % \end{function} % % \begin{function}[updated = 2011-10-22] % { % \int_set:Nn, \int_set:cn, \int_set:NV, \int_set:cV, % \int_gset:Nn, \int_gset:cn, \int_gset:MV, \int_gset:cV % } % \begin{syntax} % \cs{int_set:Nn} \meta{integer} \Arg{int expr} % \end{syntax} % Sets \meta{integer} to the value of \meta{int expr}, % which must evaluate to an integer (as described for % \cs{int_eval:n}). % \end{function} % % \begin{function}[updated = 2011-10-22] % {\int_sub:Nn, \int_sub:cn, \int_gsub:Nn, \int_gsub:cn} % \begin{syntax} % \cs{int_sub:Nn} \meta{integer} \Arg{int expr} % \end{syntax} % Subtracts the result of the \meta{int expr} from the % current content of the \meta{integer}. % \end{function} % % \section{Using integers} % % \begin{function}[updated = 2011-10-22, EXP]{\int_use:N, \int_use:c} % \begin{syntax} % \cs{int_use:N} \meta{integer} % \end{syntax} % Recovers the content of an \meta{integer} and places it directly % in the input stream. An error is raised if the variable does % not exist or if it is invalid. Can be omitted in places where an % \meta{integer} is required (such as in the first and third arguments % of \cs{int_compare:nNnTF}). % \begin{texnote} % \cs{int_use:N} is the \TeX{} primitive \tn{the}: this is one of % several \LaTeX3 names for this primitive. % \end{texnote} % \end{function} % % \section{Integer expression conditionals} % % \begin{function}[EXP,pTF]{\int_compare:nNn} % \begin{syntax} % \cs{int_compare_p:nNn} \Arg{int expr_1} \meta{relation} \Arg{int expr_2} \\ % \cs{int_compare:nNnTF} % ~~\Arg{int expr_1} \meta{relation} \Arg{int expr_2} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % This function first evaluates each of the \meta{int expr}s % as described for \cs{int_eval:n}. The two results are then % compared using the \meta{relation}: % \begin{center} % \begin{tabular}{ll} % Equal & |=| \\ % Greater than & |>| \\ % Less than & |<| \\ % \end{tabular} % \end{center} % This function is less flexible than \cs{int_compare:nTF} but around % $5$~times faster. % \end{function} % % \begin{function}[updated = 2013-01-13, EXP, pTF]{\int_compare:n} % \begin{syntax} % \cs{int_compare_p:n} \\ % ~~\{ \\ % ~~~~\meta{int expr_1} \meta{relation_1} \\ % ~~~~\ldots{} \\ % ~~~~\meta{int expr_N} \meta{relation_N} \\ % ~~~~\meta{int expr_{N+1}} \\ % ~~\} \\ % \cs{int_compare:nTF} % ~~\{ \\ % ~~~~\meta{int expr_1} \meta{relation_1} \\ % ~~~~\ldots{} \\ % ~~~~\meta{int expr_N} \meta{relation_N} \\ % ~~~~\meta{int expr_{N+1}} \\ % ~~\} \\ % ~~\Arg{true code} \Arg{false code} % \end{syntax} % This function evaluates the \meta{int expr}s as described % for \cs{int_eval:n} and compares consecutive result using the % corresponding \meta{relation}, namely it compares \meta{int expr_1} % and \meta{int expr_2} using the \meta{relation_1}, then % \meta{int expr_2} and \meta{int expr_3} using the \meta{relation_2}, % until finally comparing \meta{int expr_N} and \meta{int expr_{N+1}} % using the \meta{relation_N}. The test yields \texttt{true} if all % comparisons are \texttt{true}. Each \meta{int expr} is % evaluated only once, and the evaluation is lazy, in the sense that % if one comparison is \texttt{false}, then no other \meta{integer % expression} is evaluated and no other comparison is performed. % The \meta{relations} can be any of the following: % \begin{center} % \begin{tabular}{ll} % Equal & |=| or |==| \\ % Greater than or equal to & |>=| \\ % Greater than & |>| \\ % Less than or equal to & |<=| \\ % Less than & |<| \\ % Not equal & |!=| \\ % \end{tabular} % \end{center} % This function is more flexible than \cs{int_compare:nNnTF} but % around $5$~times slower. % \end{function} % % \begin{function}[added = 2013-07-24, EXP, noTF]{\int_case:nn} % \begin{syntax} % \cs{int_case:nnTF} \Arg{test int expr} \\ % ~~|{| \\ % ~~~~\Arg{int expr case_1} \Arg{code case_1} \\ % ~~~~\Arg{int expr case_2} \Arg{code case_2} \\ % ~~~~\ldots \\ % ~~~~\Arg{int expr case_n} \Arg{code case_n} \\ % ~~|}| \\ % ~~\Arg{true code} % ~~\Arg{false code} % \end{syntax} % This function evaluates the \meta{test int expr} and % compares this in turn to each of the % \meta{int expr case}s until a match is found. % If the two are equal then the % associated \meta{code} is left in the input stream % and other cases are discarded. If any of the % cases are matched, the \meta{true code} is also inserted into the % input stream (after the code for the appropriate case), while if none % match then the \meta{false code} is inserted. The function % \cs{int_case:nn}, which does nothing if there is no match, is also % available. For example % \begin{verbatim} % \int_case:nnF % { 2 * 5 } % { % { 5 } { Small } % { 4 + 6 } { Medium } % { -2 * 10 } { Negative } % } % { No idea! } % \end{verbatim} % leaves \enquote{\texttt{Medium}} in the input stream. % Since evaluation of the test expressions stops at the first % successful case, the order of possible matches should normally % be that the most likely are earlier: this will reduce the average % steps required to complete expansion. % \end{function} % % \begin{function}[EXP,pTF]{\int_if_even:n, \int_if_odd:n} % \begin{syntax} % \cs{int_if_odd_p:n} \Arg{int expr} % \cs{int_if_odd:nTF} \Arg{int expr} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % This function first evaluates the \meta{int expr} % as described for \cs{int_eval:n}. It then evaluates if this % is odd or even, as appropriate. % \end{function} % % \begin{function}[EXP,pTF, added = 2023-05-17]{\int_if_zero:n} % \begin{syntax} % \cs{int_if_zero_p:n} \Arg{int expr} % \cs{int_if_zero:nTF} \Arg{int expr} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % This function first evaluates the \meta{int expr} % as described for \cs{int_eval:n}. It then evaluates if this % is zero or not. % \end{function} % % \section{Integer expression loops} % % \begin{function}[rEXP]{\int_do_until:nNnn} % \begin{syntax} % \cs{int_do_until:nNnn} \Arg{int expr_1} \meta{relation} \Arg{int expr_2} \Arg{code} % \end{syntax} % Places the \meta{code} in the input stream for \TeX{} to process, and % then evaluates the relationship between the two % \meta{int expr}s as described for \cs{int_compare:nNnTF}. % If the test is \texttt{false} then the \meta{code} is inserted % into the input stream again and a loop occurs until the % \meta{relation} is \texttt{true}. % \end{function} % % \begin{function}[rEXP]{\int_do_while:nNnn} % \begin{syntax} % \cs{int_do_while:nNnn} \Arg{int expr_1} \meta{relation} \Arg{int expr_2} \Arg{code} % \end{syntax} % Places the \meta{code} in the input stream for \TeX{} to process, and % then evaluates the relationship between the two % \meta{int expr}s as described for \cs{int_compare:nNnTF}. % If the test is \texttt{true} then the \meta{code} is inserted % into the input stream again and a loop occurs until the % \meta{relation} is \texttt{false}. % \end{function} % % \begin{function}[rEXP]{\int_until_do:nNnn} % \begin{syntax} % \cs{int_until_do:nNnn} \Arg{int expr_1} \meta{relation} \Arg{int expr_2} \Arg{code} % \end{syntax} % Evaluates the relationship between the two \meta{int expr}s % as described for \cs{int_compare:nNnTF}, and then places the % \meta{code} in the input stream if the \meta{relation} is % \texttt{false}. After the \meta{code} has been processed by \TeX{} the % test is repeated, and a loop occurs until the test is % \texttt{true}. % \end{function} % % \begin{function}[rEXP]{\int_while_do:nNnn} % \begin{syntax} % \cs{int_while_do:nNnn} \Arg{int expr_1} \meta{relation} \Arg{int expr_2} \Arg{code} % \end{syntax} % Evaluates the relationship between the two \meta{int expr}s % as described for \cs{int_compare:nNnTF}, and then places the % \meta{code} in the input stream if the \meta{relation} is % \texttt{true}. After the \meta{code} has been processed by \TeX{} the % test is repeated, and a loop occurs until the test is % \texttt{false}. % \end{function} % % \begin{function}[updated = 2013-01-13, rEXP]{\int_do_until:nn} % \begin{syntax} % \cs{int_do_until:nn} \Arg{integer relation} \Arg{code} % \end{syntax} % Places the \meta{code} in the input stream for \TeX{} to process, and % then evaluates the \meta{integer relation} % as described for \cs{int_compare:nTF}. % If the test is \texttt{false} then the \meta{code} is inserted % into the input stream again and a loop occurs until the % \meta{relation} is \texttt{true}. % \end{function} % % \begin{function}[updated = 2013-01-13, rEXP]{\int_do_while:nn} % \begin{syntax} % \cs{int_do_while:nn} \Arg{integer relation} \Arg{code} % \end{syntax} % Places the \meta{code} in the input stream for \TeX{} to process, and % then evaluates the \meta{integer relation} % as described for \cs{int_compare:nTF}. % If the test is \texttt{true} then the \meta{code} is inserted % into the input stream again and a loop occurs until the % \meta{relation} is \texttt{false}. % \end{function} % % \begin{function}[updated = 2013-01-13, rEXP]{\int_until_do:nn} % \begin{syntax} % \cs{int_until_do:nn} \Arg{integer relation} \Arg{code} % \end{syntax} % Evaluates the \meta{integer relation} % as described for \cs{int_compare:nTF}, and then places the % \meta{code} in the input stream if the \meta{relation} is % \texttt{false}. After the \meta{code} has been processed by \TeX{} the % test is repeated, and a loop occurs until the test is % \texttt{true}. % \end{function} % % \begin{function}[updated = 2013-01-13, rEXP]{\int_while_do:nn} % \begin{syntax} % \cs{int_while_do:nn} \Arg{integer relation} \Arg{code} % \end{syntax} % Evaluates the \meta{integer relation} % as described for \cs{int_compare:nTF}, and then places the % \meta{code} in the input stream if the \meta{relation} is % \texttt{true}. After the \meta{code} has been processed by \TeX{} the % test is repeated, and a loop occurs until the test is % \texttt{false}. % \end{function} % % \section{Integer step functions} % % \begin{function}[added = 2012-06-04, updated = 2018-04-22, rEXP] % {\int_step_function:nN, \int_step_function:nnN, \int_step_function:nnnN} % \begin{syntax} % \cs{int_step_function:nN} \Arg{final value} \meta{function} % \cs{int_step_function:nnN} \Arg{initial value} \Arg{final value} \meta{function} % \cs{int_step_function:nnnN} \Arg{initial value} \Arg{step} \Arg{final value} \meta{function} % \end{syntax} % This function first evaluates the \meta{initial value}, \meta{step} % and \meta{final value}, all of which should be integer expressions. % The \meta{function} is then placed in front of each \meta{value} % from the \meta{initial value} to the \meta{final value} in turn % (using \meta{step} between each \meta{value}). The \meta{step} must % be non-zero. If the \meta{step} is positive, the loop stops when % the \meta{value} becomes larger than the \meta{final value}. If the % \meta{step} is negative, the loop stops when the \meta{value} % becomes smaller than the \meta{final value}. The \meta{function} % should absorb one numerical argument. For example % \begin{verbatim} % \cs_set:Npn \my_func:n #1 { [I~saw~#1] \quad } % \int_step_function:nnnN { 1 } { 1 } { 5 } \my_func:n % \end{verbatim} % would print % \begin{quote} % [I saw 1] \quad % [I saw 2] \quad % [I saw 3] \quad % [I saw 4] \quad % [I saw 5] \quad % \end{quote} % % The functions \cs{int_step_function:nN} and \cs{int_step_function:nnN} % both use a fixed \meta{step} of $1$, and in the case of % \cs{int_step_function:nN} the \meta{initial value} is also fixed as % $1$. These functions are provided as simple short-cuts for code clarity. % \end{function} % % \begin{function}[added = 2012-06-04, updated = 2018-04-22] % {\int_step_inline:nn, \int_step_inline:nnn, \int_step_inline:nnnn} % \begin{syntax} % \cs{int_step_inline:nn} \Arg{final value} \Arg{code} % \cs{int_step_inline:nnn} \Arg{initial value} \Arg{final value} \Arg{code} % \cs{int_step_inline:nnnn} \Arg{initial value} \Arg{step} \Arg{final value} \Arg{code} % \end{syntax} % This function first evaluates the \meta{initial value}, \meta{step} % and \meta{final value}, all of which should be integer expressions. % Then for each \meta{value} from the \meta{initial value} to the % \meta{final value} in turn (using \meta{step} between each % \meta{value}), the \meta{code} is inserted into the input stream % with |#1| replaced by the current \meta{value}. Thus the % \meta{code} should define a function of one argument~(|#1|). % % The functions \cs{int_step_inline:nn} and \cs{int_step_inline:nnn} % both use a fixed \meta{step} of $1$, and in the case of % \cs{int_step_inline:nn} the \meta{initial value} is also fixed as % $1$. These functions are provided as simple short-cuts for code clarity. % \end{function} % % \begin{function}[added = 2012-06-04, updated = 2018-04-22] % {\int_step_variable:nNn, \int_step_variable:nnNn, \int_step_variable:nnnNn} % \begin{syntax} % \cs{int_step_variable:nNn} \Arg{final value} \meta{tl~var} \Arg{code} % \cs{int_step_variable:nnNn} \Arg{initial value} \Arg{final value} \meta{tl~var} \Arg{code} % \cs{int_step_variable:nnnNn} \Arg{initial value} \Arg{step} \Arg{final value} \meta{tl~var} \Arg{code} % \end{syntax} % This function first evaluates the \meta{initial value}, \meta{step} % and \meta{final value}, all of which should be integer expressions. % Then for each \meta{value} from the \meta{initial value} to the % \meta{final value} in turn (using \meta{step} between each % \meta{value}), the \meta{code} is inserted into the input stream, % with the \meta{tl~var} defined as the current \meta{value}. Thus % the \meta{code} should make use of the \meta{tl~var}. % % The functions \cs{int_step_variable:nNn} and \cs{int_step_variable:nnNn} % both use a fixed \meta{step} of $1$, and in the case of % \cs{int_step_variable:nNn} the \meta{initial value} is also fixed as % $1$. These functions are provided as simple short-cuts for code clarity. % \end{function} % % \section{Formatting integers} % % Integers can be placed into the output stream with formatting. These % conversions apply to any integer expressions. % % \begin{function}[updated = 2011-10-22, EXP]{\int_to_arabic:n, \int_to_arabic:v} % \begin{syntax} % \cs{int_to_arabic:n} \Arg{int expr} % \end{syntax} % Places the value of the \meta{int expr} in the input % stream as digits, with category code $12$ (other). % \end{function} % % \begin{function}[updated = 2011-09-17, EXP]{\int_to_alph:n, \int_to_Alph:n} % \begin{syntax} % \cs{int_to_alph:n} \Arg{int expr} % \end{syntax} % Evaluates the \meta{int expr} and converts the result % into a series of letters, which are then left in the input stream. % The conversion rule uses the $26$ letters of the English % alphabet, in order, adding letters when necessary to increase the total % possible range of representable numbers. Thus % \begin{verbatim} % \int_to_alph:n { 1 } % \end{verbatim} % places |a| in the input stream, % \begin{verbatim} % \int_to_alph:n { 26 } % \end{verbatim} % is represented as |z| and % \begin{verbatim} % \int_to_alph:n { 27 } % \end{verbatim} % is converted to |aa|. For conversions using other alphabets, use % \cs{int_to_symbols:nnn} to define an alphabet-specific % function. The basic \cs{int_to_alph:n} and \cs{int_to_Alph:n} % functions should not be modified. % The resulting tokens are digits with category code $12$ (other) and % letters with category code $11$ (letter). % \end{function} % % \begin{function}[updated = 2011-09-17, EXP]{\int_to_symbols:nnn} % \begin{syntax} % \cs{int_to_symbols:nnn} % ~~\Arg{int expr} \Arg{total symbols} % ~~\Arg{value to symbol mapping} % \end{syntax} % This is the low-level function for conversion of an % \meta{int expr} into a symbolic form (often % letters). The \meta{total symbols} available should be given % as an integer expression. Values are actually converted to symbols % according to the \meta{value to symbol mapping}. This should be given % as \meta{total symbols} pairs of entries, a number and the % appropriate symbol. Thus the \cs{int_to_alph:n} function is defined % as % \begin{verbatim} % \cs_new:Npn \int_to_alph:n #1 % { % \int_to_symbols:nnn {#1} { 26 } % { % { 1 } { a } % { 2 } { b } % ... % { 26 } { z } % } % } % \end{verbatim} % \end{function} % % \begin{function}[added = 2014-02-11, EXP]{\int_to_bin:n} % \begin{syntax} % \cs{int_to_bin:n} \Arg{int expr} % \end{syntax} % Calculates the value of the \meta{int expr} and places % the binary representation of the result in the input stream. % \end{function} % % \begin{function}[added = 2014-02-11, EXP]{\int_to_hex:n, \int_to_Hex:n} % \begin{syntax} % \cs{int_to_hex:n} \Arg{int expr} % \end{syntax} % Calculates the value of the \meta{int expr} and places % the hexadecimal (base~$16$) representation of the result in the % input stream. Letters are used for digits beyond~$9$: lower % case letters for \cs{int_to_hex:n} and upper case ones for % \cs{int_to_Hex:n}. % The resulting tokens are digits with category code $12$ (other) and % letters with category code $11$ (letter). % \end{function} % % \begin{function}[added = 2014-02-11, EXP]{\int_to_oct:n} % \begin{syntax} % \cs{int_to_oct:n} \Arg{int expr} % \end{syntax} % Calculates the value of the \meta{int expr} and places % the octal (base~$8$) representation of the result in the input % stream. % The resulting tokens are digits with category code $12$ (other) and % letters with category code $11$ (letter). % \end{function} % % \begin{function}[updated = 2014-02-11, EXP] % {\int_to_base:nn, \int_to_Base:nn} % \begin{syntax} % \cs{int_to_base:nn} \Arg{int expr} \Arg{base} % \end{syntax} % Calculates the value of the \meta{int expr} and % converts it into the appropriate representation in the \meta{base}; % the later may be given as an integer expression. For bases greater % than $10$ the higher \enquote{digits} are represented by % letters from the English alphabet: lower % case letters for \cs{int_to_base:n} and upper case ones for % \cs{int_to_Base:n}. % The maximum \meta{base} value is $36$. % The resulting tokens are digits with category code $12$ (other) and % letters with category code $11$ (letter). % \begin{texnote} % This is a generic version of \cs{int_to_bin:n}, \emph{etc.} % \end{texnote} % \end{function} % % \begin{function}[updated = 2011-10-22, rEXP]{\int_to_roman:n, \int_to_Roman:n} % \begin{syntax} % \cs{int_to_roman:n} \Arg{int expr} % \end{syntax} % Places the value of the \meta{int expr} in the input % stream as Roman numerals, either lower case (\cs{int_to_roman:n}) or % upper case (\cs{int_to_Roman:n}). If the value is negative or zero, % the output is empty. The Roman numerals are letters with category % code $11$ (letter). The letters used are |mdclxvi|, repeated as % needed: the notation with bars (such as $\bar{\mbox{v}}$ for $5000$) % is \emph{not} used. For instance \cs{int_to_roman:n} |{| 8249 |}| % expands to |mmmmmmmmccxlix|. % \end{function} % % \section{Converting from other formats to integers} % % \begin{function}[updated = 2014-08-25, EXP]{\int_from_alph:n} % \begin{syntax} % \cs{int_from_alph:n} \Arg{letters} % \end{syntax} % Converts the \meta{letters} into the integer (base~$10$) % representation and leaves this in the input stream. The % \meta{letters} are first converted to a string, with no expansion. % Lower and upper case letters from the English alphabet may be used, % with \enquote{a} equal to $1$ through to \enquote{z} equal to $26$. % The function also accepts a leading sign, made of |+| and~|-|. This % is the inverse function of \cs{int_to_alph:n} and % \cs{int_to_Alph:n}. % \end{function} % % \begin{function}[added = 2014-02-11, updated = 2014-08-25, EXP] % {\int_from_bin:n} % \begin{syntax} % \cs{int_from_bin:n} \Arg{binary number} % \end{syntax} % Converts the \meta{binary number} into the integer (base~$10$) % representation and leaves this in the input stream. % The \meta{binary number} is first converted to a string, with no % expansion. The function accepts a leading sign, made of |+| % and~|-|, followed by binary digits. This is the inverse function % of \cs{int_to_bin:n}. % \end{function} % % \begin{function}[added = 2014-02-11, updated = 2014-08-25, EXP] % {\int_from_hex:n} % \begin{syntax} % \cs{int_from_hex:n} \Arg{hexadecimal number} % \end{syntax} % Converts the \meta{hexadecimal number} into the integer (base~$10$) % representation and leaves this in the input stream. Digits greater % than $9$ may be represented in the \meta{hexadecimal number} by % upper or lower case letters. The \meta{hexadecimal number} is first % converted to a string, with no expansion. The function also accepts % a leading sign, made of |+| and~|-|. This is the inverse function % of \cs{int_to_hex:n} and \cs{int_to_Hex:n}. % \end{function} % % \begin{function}[added = 2014-02-11, updated = 2014-08-25, EXP] % {\int_from_oct:n} % \begin{syntax} % \cs{int_from_oct:n} \Arg{octal number} % \end{syntax} % Converts the \meta{octal number} into the integer (base~$10$) % representation and leaves this in the input stream. % The \meta{octal number} is first converted to a string, with no % expansion. The function accepts a leading sign, made of |+| % and~|-|, followed by octal digits. This is the inverse function % of \cs{int_to_oct:n}. % \end{function} % % \begin{function}[updated = 2014-08-25, updated = 2014-08-25, EXP] % {\int_from_roman:n} % \begin{syntax} % \cs{int_from_roman:n} \Arg{roman numeral} % \end{syntax} % Converts the \meta{roman numeral} into the integer (base~$10$) % representation and leaves this in the input stream. The \meta{roman % numeral} is first converted to a string, with no expansion. The % \meta{roman numeral} may be in upper or lower case; if the numeral % contains characters besides |mdclxvi| or |MDCLXVI| then the % resulting value is $-1$. This is the inverse function of % \cs{int_to_roman:n} and \cs{int_to_Roman:n}. % \end{function} % % \begin{function}[updated = 2014-08-25, EXP]{\int_from_base:nn} % \begin{syntax} % \cs{int_from_base:nn} \Arg{number} \Arg{base} % \end{syntax} % Converts the \meta{number} expressed in \meta{base} into the % appropriate value in base $10$. The \meta{number} is first % converted to a string, with no expansion. The \meta{number} should % consist of digits and letters (either lower or upper case), plus % optionally a leading sign. The maximum \meta{base} value is $36$. % This is the inverse function of \cs{int_to_base:nn} and % \cs{int_to_Base:nn}. % \end{function} % % \section{Random integers} % % \begin{function}[EXP, added = 2016-12-06, updated = 2018-04-27]{\int_rand:nn} % \begin{syntax} % \cs{int_rand:nn} \Arg{int expr_1} \Arg{int expr_2} % \end{syntax} % Evaluates the two \meta{int expr}s and produces a % pseudo-random number between the two (with bounds included). % \end{function} % % \begin{function}[EXP, added = 2018-05-05]{\int_rand:n} % \begin{syntax} % \cs{int_rand:n} \Arg{int expr} % \end{syntax} % Evaluates the \meta{int expr} then produces a % pseudo-random number between $1$ and the \meta{int expr} (included). % \end{function} % % \section{Viewing integers} % % \begin{function}{\int_show:N, \int_show:c} % \begin{syntax} % \cs{int_show:N} \meta{integer} % \end{syntax} % Displays the value of the \meta{integer} on the terminal. % \end{function} % % \begin{function}[added = 2011-11-22, updated = 2015-08-07]{\int_show:n} % \begin{syntax} % \cs{int_show:n} \Arg{int expr} % \end{syntax} % Displays the result of evaluating the \meta{int expr} % on the terminal. % \end{function} % % \begin{function}[added = 2014-08-22, updated = 2015-08-03]{\int_log:N, \int_log:c} % \begin{syntax} % \cs{int_log:N} \meta{integer} % \end{syntax} % Writes the value of the \meta{integer} in the log file. % \end{function} % % \begin{function}[added = 2014-08-22, updated = 2015-08-07]{\int_log:n} % \begin{syntax} % \cs{int_log:n} \Arg{int expr} % \end{syntax} % Writes the result of evaluating the \meta{int expr} % in the log file. % \end{function} % % \section{Constant integers} % % \begin{variable}[added = 2018-05-07]{\c_zero_int, \c_one_int} % Integer values used with primitive tests and assignments: their % self-terminating nature makes these more convenient and faster than % literal numbers. % \end{variable} % % \begin{variable}[module = int]{\c_max_int} % The maximum value that can be stored as an integer. % \end{variable} % % \begin{variable}[module = int]{\c_max_register_int} % Maximum number of registers. % \end{variable} % % \begin{variable}[module = int]{\c_max_char_int} % Maximum character code completely supported by the engine. % \end{variable} % % \section{Scratch integers} % % \begin{variable}{\l_tmpa_int, \l_tmpb_int} % Scratch integer for local assignment. These are never used by % the kernel code, and so are safe for use with any \LaTeX3-defined % function. However, they may be overwritten by other non-kernel % code and so should only be used for short-term storage. % \end{variable} % % \begin{variable}{\g_tmpa_int, \g_tmpb_int} % Scratch integer for global assignment. These are never used by % the kernel code, and so are safe for use with any \LaTeX3-defined % function. However, they may be overwritten by other non-kernel % code and so should only be used for short-term storage. % \end{variable} % % \section{Direct number expansion} % % \begin{function}[EXP, added = 2018-03-27]{\int_value:w} % \begin{syntax} % \cs{int_value:w} \meta{integer} % \cs{int_value:w} \meta{integer denotation} \meta{optional space} % \end{syntax} % Expands the following tokens until an \meta{integer} is formed, and % leaves a normalized form (no leading sign except for negative % numbers, no leading digit~|0| except for zero) in the input stream % as category code $12$ (other) characters. The \meta{integer} can % consist of any number of signs (with intervening spaces) followed % by % \begin{itemize} % \item an integer variable (in fact, any \TeX{} register except % \tn{toks}) or % \item explicit digits (or by |'|\meta{octal digits} or |"|\meta{hexadecimal digits} or |`|\meta{character}). % \end{itemize} % In this last case expansion stops once a non-digit is found; if that is a % space it is removed as in \texttt{f}-expansion, and so \cs{exp_stop_f:} % may be employed as an end marker. Note that protected functions % \emph{are} expanded by this process. % % This function requires exactly one expansion to produce a value, and so % is suitable for use in cases where a number is required \enquote{directly}. % In general, \cs{int_eval:n} is the preferred approach to generating % numbers. % \begin{texnote} % This is the \TeX{} primitive \tn{number}. % \end{texnote} % \end{function} % % \section{Primitive conditionals} % % \begin{function}[EXP]{\if_int_compare:w} % \begin{syntax} % \cs{if_int_compare:w} \meta{integer_1} \meta{relation} \meta{integer_2} % ~~\meta{true code} % \cs{else:} % ~~\meta{false code} % \cs{fi:} % \end{syntax} % Compare two integers using \meta{relation}, which must be one of % |=|, |<| or |>| with category code $12$. % The \cs{else:} branch is optional. % \begin{texnote} % This is the \TeX{} primitive \tn{ifnum}. % \end{texnote} % \end{function} % % \begin{function}[EXP]{\if_case:w, \or:} % \begin{syntax} % \cs{if_case:w} \meta{integer} \meta{case_0} % ~~\cs{or:} \meta{case_1} % ~~\cs{or:} |...| % ~~\cs{else:} \meta{default} % \cs{fi:} % \end{syntax} % Selects a case to execute based on the value of the \meta{integer}. The % first case (\meta{case_0}) is executed if \meta{integer} is $0$, the second % (\meta{case_1}) if the \meta{integer} is $1$, \emph{etc.} The % \meta{integer} may be a literal, a constant or an integer % expression (\emph{e.g.}~using \cs{int_eval:n}). % \begin{texnote} % These are the \TeX{} primitives \tn{ifcase} and \tn{or}. % \end{texnote} % \end{function} % % \begin{function}[EXP]{\if_int_odd:w} % \begin{syntax} % \cs{if_int_odd:w} \meta{tokens} \meta{optional space} % ~~\meta{true code} % \cs{else:} % ~~\meta{true code} % \cs{fi:} % \end{syntax} % Expands \meta{tokens} until a non-numeric token or a space is found, and % tests whether the resulting \meta{integer} is odd. If so, \meta{true code} % is executed. The \cs{else:} branch is optional. % \begin{texnote} % This is the \TeX{} primitive \tn{ifodd}. % \end{texnote} % \end{function} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3int} implementation} % % \begin{macrocode} %<*package> % \end{macrocode} % % \begin{macrocode} %<@@=int> % \end{macrocode} % % \TestFiles{m3int001,m3int002,m3int03} % % \begin{variable}{\c_max_register_int} % Done in \pkg{l3basics}. % \end{variable} % % \begin{macro}{\@@_to_roman:w} % \begin{macro}{\if_int_compare:w} % Done in \pkg{l3basics}. % \end{macro} % \end{macro} % % \begin{macro}{\or:} % Done in \pkg{l3basics}. % \end{macro} % % \begin{macro}{\int_value:w} % \begin{macro}{\@@_eval:w} % \begin{macro}{\@@_eval_end:} % \begin{macro}{\if_int_odd:w} % \begin{macro}{\if_case:w} % Here are the remaining primitives for number comparisons and % expressions. % \begin{macrocode} \cs_new_eq:NN \int_value:w \tex_number:D \cs_new_eq:NN \@@_eval:w \tex_numexpr:D \cs_new_eq:NN \@@_eval_end: \tex_relax:D \cs_new_eq:NN \if_int_odd:w \tex_ifodd:D \cs_new_eq:NN \if_case:w \tex_ifcase:D % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{variable}{\s_@@_mark,\s_@@_stop} % Scan marks used throughout the module. % \begin{macrocode} \scan_new:N \s_@@_mark \scan_new:N \s_@@_stop % \end{macrocode} % \end{variable} % % \begin{macro}[EXP]{\@@_use_none_delimit_by_s_stop:w} % Function to gobble until a scan mark. % \begin{macrocode} \cs_new:Npn \@@_use_none_delimit_by_s_stop:w #1 \s_@@_stop { } % \end{macrocode} % \end{macro} % % \begin{variable}{\q_@@_recursion_tail,\q_@@_recursion_stop} % Quarks for recursion. % \begin{macrocode} \quark_new:N \q_@@_recursion_tail \quark_new:N \q_@@_recursion_stop % \end{macrocode} % \end{variable} % % \begin{macro}[EXP]{\@@_if_recursion_tail_stop_do:Nn,\@@_if_recursion_tail_stop:N} % Functions to query quarks. % \begin{macrocode} \__kernel_quark_new_test:N \@@_if_recursion_tail_stop_do:Nn \__kernel_quark_new_test:N \@@_if_recursion_tail_stop:N % \end{macrocode} % \end{macro} % % \subsection{Integer expressions} % % \begin{macro}{\int_eval:n} % \begin{macro}{\int_eval:w} % Wrapper for \cs{@@_eval:w}: can be used in an integer expression or % directly in the input stream. It is very slightly faster to use % \tn{the} rather than \tn{number} to turn the expression to a number. % When debugging, we introduce parentheses to catch early termination (see \pkg{l3debug}). % \begin{macrocode} \cs_new:Npn \int_eval:n #1 { \tex_the:D \@@_eval:w #1 \@@_eval_end: } \cs_new:Npn \int_eval:w { \tex_the:D \@@_eval:w } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\int_sign:n, \@@_sign:Nw} % See \cs{int_abs:n}. Evaluate the expression once (and when % debugging is enabled, check that the expression is well-formed), % then test the first character to determine the sign. This is % wrapped in \cs{int_value:w} \ldots{} \cs{exp_stop_f:} to ensure a % fixed number of expansions and to avoid dealing with closing the % conditionals. % \begin{macrocode} \cs_new:Npn \int_sign:n #1 { \int_value:w \exp_after:wN \@@_sign:Nw \int_value:w \@@_eval:w #1 \@@_eval_end: ; \exp_stop_f: } \cs_new:Npn \@@_sign:Nw #1#2 ; { \if_meaning:w 0 #1 0 \else: \if_meaning:w - #1 - \fi: 1 \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\int_abs:n} % \begin{macro}[EXP]{\@@_abs:N} % \UnitTested % \begin{macro}[EXP]{\int_max:nn} % \begin{macro}[EXP]{\int_min:nn} % \begin{macro}[EXP]{\@@_maxmin:wwN} % \UnitTested % \UnitTested % Functions for $\min$, $\max$, and absolute value with only one % evaluation. The absolute value is obtained by removing a leading % sign if any. All three functions expand in two steps. % \begin{macrocode} \cs_new:Npn \int_abs:n #1 { \int_value:w \exp_after:wN \@@_abs:N \int_value:w \@@_eval:w #1 \@@_eval_end: \exp_stop_f: } \cs_new:Npn \@@_abs:N #1 { \if_meaning:w - #1 \else: \exp_after:wN #1 \fi: } \cs_new:Npn \int_max:nn #1#2 { \int_value:w \exp_after:wN \@@_maxmin:wwN \int_value:w \@@_eval:w #1 \exp_after:wN ; \int_value:w \@@_eval:w #2 ; > \exp_stop_f: } \cs_new:Npn \int_min:nn #1#2 { \int_value:w \exp_after:wN \@@_maxmin:wwN \int_value:w \@@_eval:w #1 \exp_after:wN ; \int_value:w \@@_eval:w #2 ; < \exp_stop_f: } \cs_new:Npn \@@_maxmin:wwN #1 ; #2 ; #3 { \if_int_compare:w #1 #3 #2 ~ #1 \else: #2 \fi: } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\int_div_truncate:nn} % \UnitTested % \begin{macro}[EXP]{\int_div_round:nn} % \UnitTested % \begin{macro}[EXP]{\int_mod:nn} % \UnitTested % \begin{macro}[EXP]{\@@_div_truncate:NwNw} % \begin{macro}[EXP]{\@@_mod:ww} % As \cs{@@_eval:w} rounds the result of a division we also provide a % version that truncates the result. We use an auxiliary to make sure % numerator and denominator are only evaluated once: this comes in % handy when those are more expressions are expensive to evaluate % (\emph{e.g.}, \cs{tl_count:n}). If the numerator |#1#2| is $0$, % then we divide $0$ by the denominator (this ensures that $0/0$ is % correctly reported as an error). Otherwise, shift the numerator % |#1#2| towards $0$ by $(\left\vert\texttt{\#3\#4}\right\vert-1)/2$, which we % round away from zero. It turns out that this quantity exactly % compensates the difference between \eTeX{}'s rounding and the % truncating behaviour that we want. The details are thanks to Heiko % Oberdiek: getting things right in all cases is not so easy. % \begin{macrocode} \cs_new:Npn \int_div_truncate:nn #1#2 { \int_value:w \@@_eval:w \exp_after:wN \@@_div_truncate:NwNw \int_value:w \@@_eval:w #1 \exp_after:wN ; \int_value:w \@@_eval:w #2 ; \@@_eval_end: } \cs_new:Npn \@@_div_truncate:NwNw #1#2; #3#4; { \if_meaning:w 0 #1 0 \else: ( #1#2 \if_meaning:w - #1 + \else: - \fi: ( \if_meaning:w - #3 - \fi: #3#4 - 1 ) / 2 ) \fi: / #3#4 } % \end{macrocode} % For the sake of completeness: % \begin{macrocode} \cs_new:Npn \int_div_round:nn #1#2 { \int_value:w \@@_eval:w ( #1 ) / ( #2 ) \@@_eval_end: } % \end{macrocode} % Finally there's the modulus operation. % \begin{macrocode} \cs_new:Npn \int_mod:nn #1#2 { \int_value:w \@@_eval:w \exp_after:wN \@@_mod:ww \int_value:w \@@_eval:w #1 \exp_after:wN ; \int_value:w \@@_eval:w #2 ; \@@_eval_end: } \cs_new:Npn \@@_mod:ww #1; #2; { #1 - ( \@@_div_truncate:NwNw #1 ; #2 ; ) * #2 } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\__kernel_int_add:nnn} % Equivalent to \cs{int_eval:n} |{#1+#2+#3}| except that overflow only % occurs if the final result overflows $[-2^{31}+1,2^{31}-1]$. The % idea is to choose the order in which the three numbers are added % together. If |#1| and |#2| have opposite signs (one is in % $[-2^{31}+1,-1]$ and the other in $[0,2^{31}-1]$) then |#1+#2| % cannot overflow so we compute the result as |#1+#2+#3|. If they % have the same sign, then either |#3| has the same sign and the order % does not matter, or |#3| has the opposite sign and any order in % which |#3| is not last will work. We use |#1+#3+#2|. % \begin{macrocode} \cs_new:Npn \__kernel_int_add:nnn #1#2#3 { \int_value:w \@@_eval:w #1 \if_int_compare:w #2 < \c_zero_int \exp_after:wN \reverse_if:N \fi: \if_int_compare:w #1 < \c_zero_int + #2 + #3 \else: + #3 + #2 \fi: \@@_eval_end: } % \end{macrocode} % \end{macro} % % \subsection{Creating and initialising integers} % % \begin{macro}{\int_new:N, \int_new:c} % \UnitTested % Two ways to do this: one for the format and one for the \LaTeXe{} % package. In plain \TeX{}, \cs{newcount} (and other allocators) are % \cs{outer}: to allow the code here to work in \enquote{generic} mode % this is therefore accessed by name. (The same applies to \cs{newbox}, % \cs{newdimen} and so on.) % \begin{macrocode} \cs_new_protected:Npn \int_new:N #1 { \__kernel_chk_if_free_cs:N #1 \cs:w newcount \cs_end: #1 } \cs_generate_variant:Nn \int_new:N { c } % \end{macrocode} % \end{macro} % % \begin{macro}{\int_const:Nn, \int_const:cn} % \begin{macro}{\@@_const:nN, \@@_const:eN} % \begin{macro}{\@@_constdef:Nw} % \begin{variable}{\c_@@_max_constdef_int} % \UnitTested % As stated, most constants can be defined as \tn{chardef} or % \tn{mathchardef} but that's engine dependent. As a result, there is some % set up code to determine what can be done. No full engine testing just yet % so everything is a little awkward. % We cannot use \cs{int_gset:Nn} because (when |check-declarations| is % enabled) this runs some checks that constants would fail. % \begin{macrocode} \cs_new_protected:Npn \int_const:Nn #1#2 { \@@_const:eN { \int_eval:n {#2} } #1 } \cs_generate_variant:Nn \int_const:Nn { c } \cs_new_protected:Npn \@@_const:nN #1#2 { \int_compare:nNnTF {#1} < \c_zero_int { \int_new:N #2 \tex_global:D } { \int_compare:nNnTF {#1} > \c_@@_max_constdef_int { \int_new:N #2 \tex_global:D } { \__kernel_chk_if_free_cs:N #2 \tex_global:D \@@_constdef:Nw } } #2 = \@@_eval:w #1 \@@_eval_end: } \cs_generate_variant:Nn \@@_const:nN { e } \if_int_odd:w 0 \cs_if_exist:NT \tex_luatexversion:D { 1 } \cs_if_exist:NT \tex_omathchardef:D { 1 } \cs_if_exist:NT \tex_XeTeXversion:D { 1 } ~ \cs_if_exist:NTF \tex_omathchardef:D { \cs_new_eq:NN \@@_constdef:Nw \tex_omathchardef:D } { \cs_new_eq:NN \@@_constdef:Nw \tex_chardef:D } \tex_global:D \@@_constdef:Nw \c_@@_max_constdef_int 1114111 ~ \else: \cs_new_eq:NN \@@_constdef:Nw \tex_mathchardef:D \tex_global:D \@@_constdef:Nw \c_@@_max_constdef_int 32767 ~ \fi: % \end{macrocode} % \end{variable} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\int_zero:N, \int_zero:c} % \UnitTested % \begin{macro}{\int_gzero:N, \int_gzero:c} % \UnitTested % Functions that reset an \meta{integer} register to zero. % \begin{macrocode} \cs_new_protected:Npn \int_zero:N #1 { #1 = \c_zero_int } \cs_new_protected:Npn \int_gzero:N #1 { \tex_global:D #1 = \c_zero_int } \cs_generate_variant:Nn \int_zero:N { c } \cs_generate_variant:Nn \int_gzero:N { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro} % {\int_zero_new:N, \int_zero_new:c, \int_gzero_new:N, \int_gzero_new:c} % Create a register if needed, otherwise clear it. % \begin{macrocode} \cs_new_protected:Npn \int_zero_new:N #1 { \int_if_exist:NTF #1 { \int_zero:N #1 } { \int_new:N #1 } } \cs_new_protected:Npn \int_gzero_new:N #1 { \int_if_exist:NTF #1 { \int_gzero:N #1 } { \int_new:N #1 } } \cs_generate_variant:Nn \int_zero_new:N { c } \cs_generate_variant:Nn \int_gzero_new:N { c } % \end{macrocode} % \end{macro} % % \begin{macro}{\int_set_eq:NN, \int_set_eq:cN, \int_set_eq:Nc, \int_set_eq:cc} % \UnitTested % \begin{macro} % {\int_gset_eq:NN, \int_gset_eq:cN, \int_gset_eq:Nc, \int_gset_eq:cc} % \UnitTested % Setting equal means using one integer inside the set function of % another. Check that assigned integer is local/global. No need to % check that the other one is defined as \TeX{} does it for us. % \begin{macrocode} \cs_new_protected:Npn \int_set_eq:NN #1#2 { #1 = #2 } \cs_generate_variant:Nn \int_set_eq:NN { c , Nc , cc } \cs_new_protected:Npn \int_gset_eq:NN #1#2 { \tex_global:D #1 = #2 } \cs_generate_variant:Nn \int_gset_eq:NN { c , Nc , cc } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[pTF]{\int_if_exist:N, \int_if_exist:c} % Copies of the \texttt{cs} functions defined in \pkg{l3basics}. % \begin{macrocode} \prg_new_eq_conditional:NNn \int_if_exist:N \cs_if_exist:N { TF , T , F , p } \prg_new_eq_conditional:NNn \int_if_exist:c \cs_if_exist:c { TF , T , F , p } % \end{macrocode} % \end{macro} % % \subsection{Setting and incrementing integers} % % \begin{macro}{\int_add:Nn, \int_add:cn} % \UnitTested % \begin{macro}{\int_gadd:Nn, \int_gadd:cn} % \UnitTested % \begin{macro}{\int_sub:Nn, \int_sub:cn} % \UnitTested % \begin{macro}{\int_gsub:Nn, \int_gsub:cn} % \UnitTested % Adding and subtracting to and from a counter. % Including here the optional |by| would slow down these operations % by a few percent. % \begin{macrocode} \cs_new_protected:Npn \int_add:Nn #1#2 { \tex_advance:D #1 \@@_eval:w #2 \@@_eval_end: } \cs_new_protected:Npn \int_sub:Nn #1#2 { \tex_advance:D #1 - \@@_eval:w #2 \@@_eval_end: } \cs_new_protected:Npn \int_gadd:Nn #1#2 { \tex_global:D \tex_advance:D #1 \@@_eval:w #2 \@@_eval_end: } \cs_new_protected:Npn \int_gsub:Nn #1#2 { \tex_global:D \tex_advance:D #1 - \@@_eval:w #2 \@@_eval_end: } \cs_generate_variant:Nn \int_add:Nn { c } \cs_generate_variant:Nn \int_gadd:Nn { c } \cs_generate_variant:Nn \int_sub:Nn { c } \cs_generate_variant:Nn \int_gsub:Nn { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\int_incr:N, \int_incr:c} % \UnitTested % \begin{macro}{\int_gincr:N, \int_gincr:c} % \UnitTested % \begin{macro}{\int_decr:N, \int_decr:c} % \UnitTested % \begin{macro}{\int_gdecr:N, \int_gdecr:c} % \UnitTested % Incrementing and decrementing of integer registers is done with % the following functions. % \begin{macrocode} \cs_new_protected:Npn \int_incr:N #1 { \tex_advance:D #1 \c_one_int } \cs_new_protected:Npn \int_decr:N #1 { \tex_advance:D #1 - \c_one_int } \cs_new_protected:Npn \int_gincr:N #1 { \tex_global:D \tex_advance:D #1 \c_one_int } \cs_new_protected:Npn \int_gdecr:N #1 { \tex_global:D \tex_advance:D #1 - \c_one_int } \cs_generate_variant:Nn \int_incr:N { c } \cs_generate_variant:Nn \int_decr:N { c } \cs_generate_variant:Nn \int_gincr:N { c } \cs_generate_variant:Nn \int_gdecr:N { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\int_set:Nn, \int_set:cn, \int_set:NV, \int_set:cV} % \UnitTested % \begin{macro}{\int_gset:Nn, \int_gset:cn, \int_gset:NV, \int_gset:cV} % \UnitTested % As integers are register-based \TeX{} issues an error % if they are not defined. While the |=| sign is optional, this % version with |=| is slightly quicker than without, while adding the % optional space after |=| slows things down minutely. % \begin{macrocode} \cs_new_protected:Npn \int_set:Nn #1#2 { #1 = \@@_eval:w #2 \@@_eval_end: } \cs_new_protected:Npn \int_gset:Nn #1#2 { \tex_global:D #1 = \@@_eval:w #2 \@@_eval_end: } \cs_generate_variant:Nn \int_set:Nn { NV , c , cV } \cs_generate_variant:Nn \int_gset:Nn { NV , c , cV } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Using integers} % % \begin{macro}{\int_use:N, \int_use:c} % \UnitTested % Here is how counters are accessed. % We hand-code the |c| variant for some speed gain. % \begin{macrocode} \cs_new_eq:NN \int_use:N \tex_the:D \cs_new:Npn \int_use:c #1 { \tex_the:D \cs:w #1 \cs_end: } % \end{macrocode} % \end{macro} % % \subsection{Integer expression conditionals} % % \begin{macro}[EXP]{\@@_compare_error:, \@@_compare_error:Nw} % Those functions are used for comparison tests which use a simple % syntax where only one set of braces is required and additional % operators such as |!=| and |>=| are supported. The tests first % evaluate their left-hand side, with a trailing % \cs{@@_compare_error:}. This marker is normally not expanded, % but if the relation symbol is missing from the test's argument, then % the marker inserts |=| (and itself) after triggering the relevant % \TeX{} error. If the first token which appears after evaluating and % removing the left-hand side is not a known relation symbol, then a % judiciously placed \cs{@@_compare_error:Nw} gets expanded, % cleaning up the end of the test and telling the user what the % problem was. % \begin{macrocode} \cs_new_protected:Npn \@@_compare_error: { \if_int_compare:w \c_zero_int \c_zero_int \fi: = \@@_compare_error: } \cs_new:Npn \@@_compare_error:Nw #1#2 \s_@@_stop { { } \c_zero_int \fi: \msg_expandable_error:nnn { kernel } { unknown-comparison } {#1} \prg_return_false: } % \end{macrocode} % \end{macro} % % \begin{macro}[pTF, EXP]{\int_compare:n} % \begin{macro}[EXP] % {\@@_compare:w, \@@_compare:Nw, \@@_compare:NNw, \@@_compare:nnN} % \begin{macro}[EXP] % { % \@@_compare_end_=:NNw, % \@@_compare_=:NNw, % \@@_compare_<:NNw, % \@@_compare_>:NNw, % \@@_compare_==:NNw, % \@@_compare_!=:NNw, % \@@_compare_<=:NNw, % \@@_compare_>=:NNw % } % Comparison tests using a simple syntax where only one set of braces % is required, additional operators such as |!=| and |>=| are % supported, and multiple comparisons can be performed at once, for % instance |0 < 5 <= 1|. The idea is to loop through the argument, % finding one operand at a time, and comparing it to the previous one. % The looping auxiliary \cs{@@_compare:Nw} reads one \meta{operand} % and one \meta{comparison} symbol, and leaves roughly % \begin{quote} % \meta{operand} \cs{prg_return_false:} \cs{fi:} \\ % \cs{reverse_if:N} \cs{if_int_compare:w} \meta{operand} \meta{comparison} \\ % \cs{@@_compare:Nw} % \end{quote} % in the input stream. Each call to this auxiliary provides the % second operand of the last call's \cs{if_int_compare:w}. If one of % the \meta{comparisons} is \texttt{false}, the \texttt{true} branch % of the \TeX{} conditional is taken (because of \cs{reverse_if:N}), % immediately returning \texttt{false} as the result of the test. % There is no \TeX{} conditional waiting the first operand, so we add % an \cs{if_false:} and expand by hand with \cs{int_value:w}, thus % skipping \cs{prg_return_false:} on the first iteration. % % Before starting the loop, the first step is to make sure that there % is at least one relation symbol. We first let \TeX{} evaluate this % left hand side of the (in)equality using \cs{@@_eval:w}. Since the % relation symbols |<|, |>|, |=| and |!| are not allowed in integer % expressions, they would terminate the expression. If the argument contains no % relation symbol, \cs{@@_compare_error:} is expanded, % inserting~|=| and itself after an error. In all cases, % \cs{@@_compare:w} receives as its argument an integer, a relation % symbol, and some more tokens. We then setup the loop, which is % ended by the two odd-looking items |e| and |{=nd_}|, with a trailing % \cs{s_@@_stop} used to grab the entire argument when necessary. % \begin{macrocode} \prg_new_conditional:Npnn \int_compare:n #1 { p , T , F , TF } { \exp_after:wN \@@_compare:w \int_value:w \@@_eval:w #1 \@@_compare_error: } \cs_new:Npn \@@_compare:w #1 \@@_compare_error: { \exp_after:wN \if_false: \int_value:w \@@_compare:Nw #1 e { = nd_ } \s_@@_stop } % \end{macrocode} % The goal here is to find an \meta{operand} and a \meta{comparison}. % The \meta{operand} is already evaluated, but we cannot yet grab it % as an argument. To access the following relation symbol, we remove % the number by applying \cs{@@_to_roman:w}, after making sure that % the argument becomes non-positive: its roman numeral representation % is then empty. Then probe the first two tokens with % \cs{@@_compare:NNw} to determine the relation symbol, building a % control sequence from it (\cs{token_to_str:N} gives better errors if % |#1| is not a character). All the extended forms have an extra |=| % hence the test for that as a second token. If the relation symbol % is unknown, then the control sequence is turned by \TeX{} into % \cs{scan_stop:}, ignored thanks to \tn{unexpanded}, and % \cs{@@_compare_error:Nw} raises an error. % \begin{macrocode} \cs_new:Npn \@@_compare:Nw #1#2 \s_@@_stop { \exp_after:wN \@@_compare:NNw \@@_to_roman:w - 0 #2 \s_@@_mark #1#2 \s_@@_stop } \cs_new:Npn \@@_compare:NNw #1#2#3 \s_@@_mark { \__kernel_exp_not:w \use:c { @@_compare_ \token_to_str:N #1 \if_meaning:w = #2 = \fi: :NNw } \@@_compare_error:Nw #1 } % \end{macrocode} % When the last \meta{operand} is seen, \cs{@@_compare:NNw} receives % |e| and |=nd_| as arguments, hence calling % \cs{@@_compare_end_=:NNw} to end the loop: return the result of the % last comparison (involving the operand that we just found). When a % normal relation is found, the appropriate auxiliary calls % \cs{@@_compare:nnN} where |#1| is \cs{if_int_compare:w} or % \cs{reverse_if:N} \cs{if_int_compare:w}, |#2| is the \meta{operand}, % and |#3| is one of |<|, |=|, or~|>|. As announced earlier, we leave % the \meta{operand} for the previous conditional. If this % conditional is true the result of the test is known, so we remove % all tokens and return \texttt{false}. Otherwise, we apply the % conditional |#1| to the \meta{operand} |#2| and the comparison |#3|, % and call \cs{@@_compare:Nw} to look for additional operands, after % evaluating the following expression. % \begin{macrocode} \cs_new:cpn { @@_compare_end_=:NNw } #1#2#3 e #4 \s_@@_stop { {#3} \exp_stop_f: \prg_return_false: \else: \prg_return_true: \fi: } \cs_new:Npn \@@_compare:nnN #1#2#3 { {#2} \exp_stop_f: \prg_return_false: \exp_after:wN \@@_use_none_delimit_by_s_stop:w \fi: #1 #2 #3 \exp_after:wN \@@_compare:Nw \int_value:w \@@_eval:w } % \end{macrocode} % The actual comparisons are then simple function calls, using the % relation as delimiter for a delimited argument and discarding % \cs{@@_compare_error:Nw} \meta{token} responsible for error % detection. % \begin{macrocode} \cs_new:cpn { @@_compare_=:NNw } #1#2#3 = { \@@_compare:nnN { \reverse_if:N \if_int_compare:w } {#3} = } \cs_new:cpn { @@_compare_<:NNw } #1#2#3 < { \@@_compare:nnN { \reverse_if:N \if_int_compare:w } {#3} < } \cs_new:cpn { @@_compare_>:NNw } #1#2#3 > { \@@_compare:nnN { \reverse_if:N \if_int_compare:w } {#3} > } \cs_new:cpn { @@_compare_==:NNw } #1#2#3 == { \@@_compare:nnN { \reverse_if:N \if_int_compare:w } {#3} = } \cs_new:cpn { @@_compare_!=:NNw } #1#2#3 != { \@@_compare:nnN { \if_int_compare:w } {#3} = } \cs_new:cpn { @@_compare_<=:NNw } #1#2#3 <= { \@@_compare:nnN { \if_int_compare:w } {#3} > } \cs_new:cpn { @@_compare_>=:NNw } #1#2#3 >= { \@@_compare:nnN { \if_int_compare:w } {#3} < } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[pTF]{\int_compare:nNn} % \UnitTested % More efficient but less natural in typing. % \begin{macrocode} \prg_new_conditional:Npnn \int_compare:nNn #1#2#3 { p , T , F , TF } { \if_int_compare:w \@@_eval:w #1 #2 \@@_eval:w #3 \@@_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[pTF]{\int_if_zero:n} % \begin{macrocode} \prg_new_conditional:Npnn \int_if_zero:n #1 { p , T , F , TF } { \if_int_compare:w \@@_eval:w #1 = \c_zero_int \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP, noTF]{\int_case:nn} % \begin{macro}{\@@_case:nnTF} % \begin{macro}{\@@_case:nw, \@@_case_end:nw} % For integer cases, the first task to fully expand the check % condition. The over all idea is then much the same as for % \cs{str_case:nnTF} as described in \pkg{l3str}. % \begin{macrocode} \cs_new:Npn \int_case:nnTF #1 { \exp:w \exp_args:Nf \@@_case:nnTF { \int_eval:n {#1} } } \cs_new:Npn \int_case:nnT #1#2#3 { \exp:w \exp_args:Nf \@@_case:nnTF { \int_eval:n {#1} } {#2} {#3} { } } \cs_new:Npn \int_case:nnF #1#2 { \exp:w \exp_args:Nf \@@_case:nnTF { \int_eval:n {#1} } {#2} { } } \cs_new:Npn \int_case:nn #1#2 { \exp:w \exp_args:Nf \@@_case:nnTF { \int_eval:n {#1} } {#2} { } { } } \cs_new:Npn \@@_case:nnTF #1#2#3#4 { \@@_case:nw {#1} #2 {#1} { } \s_@@_mark {#3} \s_@@_mark {#4} \s_@@_stop } \cs_new:Npn \@@_case:nw #1#2#3 { \int_compare:nNnTF {#1} = {#2} { \@@_case_end:nw {#3} } { \@@_case:nw {#1} } } \cs_new:Npn \@@_case_end:nw #1#2#3 \s_@@_mark #4#5 \s_@@_stop { \exp_end: #1 #4 } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[pTF]{\int_if_odd:n} % \UnitTested % \begin{macro}[pTF]{\int_if_even:n} % \UnitTested % A predicate function. % \begin{macrocode} \prg_new_conditional:Npnn \int_if_odd:n #1 { p , T , F , TF} { \if_int_odd:w \@@_eval:w #1 \@@_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } \prg_new_conditional:Npnn \int_if_even:n #1 { p , T , F , TF} { \reverse_if:N \if_int_odd:w \@@_eval:w #1 \@@_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Integer expression loops} % % \begin{macro}{\int_while_do:nn} % \UnitTested % \TestMissing{Boundary cases} % \begin{macro}{\int_until_do:nn} % \UnitTested % \TestMissing{Boundary cases} % \begin{macro}{\int_do_while:nn} % \UnitTested % \TestMissing{Boundary cases} % \begin{macro}{\int_do_until:nn} % \UnitTested % \TestMissing{Boundary cases} % These are quite easy given the above functions. The |while| versions % test first and then execute the body. The |do_while| does it the % other way round. % \begin{macrocode} \cs_new:Npn \int_while_do:nn #1#2 { \int_compare:nT {#1} { #2 \int_while_do:nn {#1} {#2} } } \cs_new:Npn \int_until_do:nn #1#2 { \int_compare:nF {#1} { #2 \int_until_do:nn {#1} {#2} } } \cs_new:Npn \int_do_while:nn #1#2 { #2 \int_compare:nT {#1} { \int_do_while:nn {#1} {#2} } } \cs_new:Npn \int_do_until:nn #1#2 { #2 \int_compare:nF {#1} { \int_do_until:nn {#1} {#2} } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\int_while_do:nNnn} % \begin{macro}{\int_until_do:nNnn} % \begin{macro}{\int_do_while:nNnn} % \begin{macro}{\int_do_until:nNnn} % As above but not using the more natural syntax. % \begin{macrocode} \cs_new:Npn \int_while_do:nNnn #1#2#3#4 { \int_compare:nNnT {#1} #2 {#3} { #4 \int_while_do:nNnn {#1} #2 {#3} {#4} } } \cs_new:Npn \int_until_do:nNnn #1#2#3#4 { \int_compare:nNnF {#1} #2 {#3} { #4 \int_until_do:nNnn {#1} #2 {#3} {#4} } } \cs_new:Npn \int_do_while:nNnn #1#2#3#4 { #4 \int_compare:nNnT {#1} #2 {#3} { \int_do_while:nNnn {#1} #2 {#3} {#4} } } \cs_new:Npn \int_do_until:nNnn #1#2#3#4 { #4 \int_compare:nNnF {#1} #2 {#3} { \int_do_until:nNnn {#1} #2 {#3} {#4} } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Integer step functions} % % \begin{macro}{\int_step_function:nnnN} % \begin{macro}{\@@_step:wwwN, \@@_step:NwnnN} % \begin{macro}{\int_step_function:nN} % \begin{macro}{\int_step_function:nnN} % Before all else, evaluate the initial value, step, and final value. % Repeating a function by steps first needs a check on the direction % of the steps. After that, do the function for the start value then % step and loop around. It would be more symmetrical to test for a % step size of zero before checking the sign, but we optimize for the % most frequent case (positive step). % \begin{macrocode} \cs_new:Npn \int_step_function:nnnN #1#2#3 { \exp_after:wN \@@_step:wwwN \int_value:w \@@_eval:w #1 \exp_after:wN ; \int_value:w \@@_eval:w #2 \exp_after:wN ; \int_value:w \@@_eval:w #3 ; } \cs_new:Npn \@@_step:wwwN #1; #2; #3; #4 { \int_compare:nNnTF {#2} > \c_zero_int { \@@_step:NwnnN > } { \int_compare:nNnTF {#2} = \c_zero_int { \msg_expandable_error:nnn { kernel } { zero-step } {#4} \prg_break: } { \@@_step:NwnnN < } } #1 ; {#2} {#3} #4 \prg_break_point: } \cs_new:Npn \@@_step:NwnnN #1#2 ; #3#4#5 { \if_int_compare:w #2 #1 #4 \exp_stop_f: \prg_break:n \fi: #5 {#2} \exp_after:wN \@@_step:NwnnN \exp_after:wN #1 \int_value:w \@@_eval:w #2 + #3 ; {#3} {#4} #5 } \cs_new:Npn \int_step_function:nN { \int_step_function:nnnN { 1 } { 1 } } \cs_new:Npn \int_step_function:nnN #1 { \int_step_function:nnnN {#1} { 1 } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\int_step_inline:nn, \int_step_inline:nnn, \int_step_inline:nnnn} % \begin{macro}{\int_step_variable:nNn, \int_step_variable:nnNn, \int_step_variable:nnnNn} % \UnitTested % \begin{macro}{\@@_step:NNnnnn} % The approach here is to build a function, with a global integer % required to make the nesting safe (as seen in other in line % functions), and map that function using \cs{int_step_function:nnnN}. % We put a \cs{prg_break_point:Nn} so that \texttt{map_break} % functions from other modules correctly decrement \cs{g__kernel_prg_map_int} % before looking for their own break point. The first argument is % \cs{scan_stop:}, so that no breaking function recognizes this break % point as its own. % \begin{macrocode} \cs_new_protected:Npn \int_step_inline:nn { \int_step_inline:nnnn { 1 } { 1 } } \cs_new_protected:Npn \int_step_inline:nnn #1 { \int_step_inline:nnnn {#1} { 1 } } \cs_new_protected:Npn \int_step_inline:nnnn { \int_gincr:N \g__kernel_prg_map_int \exp_args:NNc \@@_step:NNnnnn \cs_gset_protected:Npn { @@_map_ \int_use:N \g__kernel_prg_map_int :w } } \cs_new_protected:Npn \int_step_variable:nNn { \int_step_variable:nnnNn { 1 } { 1 } } \cs_new_protected:Npn \int_step_variable:nnNn #1 { \int_step_variable:nnnNn {#1} { 1 } } \cs_new_protected:Npn \int_step_variable:nnnNn #1#2#3#4#5 { \int_gincr:N \g__kernel_prg_map_int \exp_args:NNc \@@_step:NNnnnn \cs_gset_protected:Npe { @@_map_ \int_use:N \g__kernel_prg_map_int :w } {#1}{#2}{#3} { \tl_set:Nn \exp_not:N #4 {##1} \exp_not:n {#5} } } \cs_new_protected:Npn \@@_step:NNnnnn #1#2#3#4#5#6 { #1 #2 ##1 {#6} \int_step_function:nnnN {#3} {#4} {#5} #2 \prg_break_point:Nn \scan_stop: { \int_gdecr:N \g__kernel_prg_map_int } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Formatting integers} % % \begin{macro}{\int_to_arabic:n, \int_to_arabic:v} % \UnitTested % Nothing exciting here. % \begin{macrocode} \cs_new_eq:NN \int_to_arabic:n \int_eval:n \cs_generate_variant:Nn \int_to_arabic:n { v } % \end{macrocode} % \end{macro} % % \begin{macro}{\int_to_symbols:nnn} % \UnitTested % \begin{macro}{\@@_to_symbols:nnnn, \@@_to_symbols:ennn} % For conversion of integers to arbitrary symbols the method is in % general as follows. The input number (|#1|) is compared to the total % number of symbols available at each place (|#2|). If the input is larger % than the total number of symbols available then the modulus is needed, % with one added so that the positions don't have to number from % zero. Using an \texttt{f}-type expansion, this is done so that the system % is recursive. The actual conversion function therefore gets a `nice' % number at each stage. Of course, if the initial input was small enough % then there is no problem and everything is easy. % \begin{macrocode} \cs_new:Npn \int_to_symbols:nnn #1#2#3 { \int_compare:nNnTF {#1} > {#2} { \@@_to_symbols:ennn { \int_case:nn { 1 + \int_mod:nn { #1 - 1 } {#2} } {#3} } {#1} {#2} {#3} } { \int_case:nn {#1} {#3} } } \cs_new:Npn \@@_to_symbols:nnnn #1#2#3#4 { \exp_args:Nf \int_to_symbols:nnn { \int_div_truncate:nn { #2 - 1 } {#3} } {#3} {#4} #1 } \cs_generate_variant:Nn \@@_to_symbols:nnnn { e } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\int_to_alph:n, \int_to_Alph:n} % \UnitTested % These both use the above function with input functions that make sense % for the alphabet in English. % \begin{macrocode} \cs_new:Npn \int_to_alph:n #1 { \int_to_symbols:nnn {#1} { 26 } { { 1 } { a } { 2 } { b } { 3 } { c } { 4 } { d } { 5 } { e } { 6 } { f } { 7 } { g } { 8 } { h } { 9 } { i } { 10 } { j } { 11 } { k } { 12 } { l } { 13 } { m } { 14 } { n } { 15 } { o } { 16 } { p } { 17 } { q } { 18 } { r } { 19 } { s } { 20 } { t } { 21 } { u } { 22 } { v } { 23 } { w } { 24 } { x } { 25 } { y } { 26 } { z } } } \cs_new:Npn \int_to_Alph:n #1 { \int_to_symbols:nnn {#1} { 26 } { { 1 } { A } { 2 } { B } { 3 } { C } { 4 } { D } { 5 } { E } { 6 } { F } { 7 } { G } { 8 } { H } { 9 } { I } { 10 } { J } { 11 } { K } { 12 } { L } { 13 } { M } { 14 } { N } { 15 } { O } { 16 } { P } { 17 } { Q } { 18 } { R } { 19 } { S } { 20 } { T } { 21 } { U } { 22 } { V } { 23 } { W } { 24 } { X } { 25 } { Y } { 26 } { Z } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\int_to_base:nn, \int_to_Base:nn} % \UnitTested % \begin{macro}{\@@_to_base:nn, \@@_to_Base:nn, % \@@_to_base:nnN, \@@_to_Base:nnN, \@@_to_base:nnnN, \@@_to_Base:nnnN} % \begin{macro}{\@@_to_letter:n, \@@_to_Letter:n} % \UnitTested % Converting from base ten (|#1|) to a second base (|#2|) starts with % computing |#1|: if it is a complicated calculation, we shouldn't % perform it twice. Then check the sign, store it, either \texttt{-} % or \cs{c_empty_tl}, and feed the absolute value to the next auxiliary % function. % \begin{macrocode} \cs_new:Npn \int_to_base:nn #1 { \exp_args:Nf \@@_to_base:nn { \int_eval:n {#1} } } \cs_new:Npn \int_to_Base:nn #1 { \exp_args:Nf \@@_to_Base:nn { \int_eval:n {#1} } } \cs_new:Npn \@@_to_base:nn #1#2 { \int_compare:nNnTF {#1} < 0 { \exp_args:No \@@_to_base:nnN { \use_none:n #1 } {#2} - } { \@@_to_base:nnN {#1} {#2} \c_empty_tl } } \cs_new:Npn \@@_to_Base:nn #1#2 { \int_compare:nNnTF {#1} < 0 { \exp_args:No \@@_to_Base:nnN { \use_none:n #1 } {#2} - } { \@@_to_Base:nnN {#1} {#2} \c_empty_tl } } % \end{macrocode} % Here, the idea is to provide a recursive system to deal with the % input. The output is built up after the end of the function. % At each pass, the value in |#1| is checked to see if it is less % than the new base (|#2|). If it is, then it is converted directly, % putting the sign back in front. % On the other hand, if the value to convert is greater than or equal % to the new base then the modulus and remainder values are found. The % modulus is converted to a symbol and put on the right, % and the remainder is carried forward to the next round. % \begin{macrocode} \cs_new:Npn \@@_to_base:nnN #1#2#3 { \int_compare:nNnTF {#1} < {#2} { \exp_last_unbraced:Nf #3 { \@@_to_letter:n {#1} } } { \exp_args:Nf \@@_to_base:nnnN { \@@_to_letter:n { \int_mod:nn {#1} {#2} } } {#1} {#2} #3 } } \cs_new:Npn \@@_to_base:nnnN #1#2#3#4 { \exp_args:Nf \@@_to_base:nnN { \int_div_truncate:nn {#2} {#3} } {#3} #4 #1 } \cs_new:Npn \@@_to_Base:nnN #1#2#3 { \int_compare:nNnTF {#1} < {#2} { \exp_last_unbraced:Nf #3 { \@@_to_Letter:n {#1} } } { \exp_args:Nf \@@_to_Base:nnnN { \@@_to_Letter:n { \int_mod:nn {#1} {#2} } } {#1} {#2} #3 } } \cs_new:Npn \@@_to_Base:nnnN #1#2#3#4 { \exp_args:Nf \@@_to_Base:nnN { \int_div_truncate:nn {#2} {#3} } {#3} #4 #1 } % \end{macrocode} % Convert to a letter only if necessary, otherwise simply return the % value unchanged. It would be cleaner to use \cs{int_case:nn}, % but in our case, the cases are contiguous, so it is forty times faster % to use the \cs{if_case:w} primitive. The first \cs{exp_after:wN} % expands the conditional, jumping to the correct case, the second one % expands after the resulting character to close the conditional. % Since |#1| might be an expression, and not directly a single digit, % we need to evaluate it properly, and expand the trailing \cs{fi:}. % \begin{macrocode} \cs_new:Npn \@@_to_letter:n #1 { \exp_after:wN \exp_after:wN \if_case:w \@@_eval:w #1 - 10 \@@_eval_end: a \or: b \or: c \or: d \or: e \or: f \or: g \or: h \or: i \or: j \or: k \or: l \or: m \or: n \or: o \or: p \or: q \or: r \or: s \or: t \or: u \or: v \or: w \or: x \or: y \or: z \else: \int_value:w \@@_eval:w #1 \exp_after:wN \@@_eval_end: \fi: } \cs_new:Npn \@@_to_Letter:n #1 { \exp_after:wN \exp_after:wN \if_case:w \@@_eval:w #1 - 10 \@@_eval_end: A \or: B \or: C \or: D \or: E \or: F \or: G \or: H \or: I \or: J \or: K \or: L \or: M \or: N \or: O \or: P \or: Q \or: R \or: S \or: T \or: U \or: V \or: W \or: X \or: Y \or: Z \else: \int_value:w \@@_eval:w #1 \exp_after:wN \@@_eval_end: \fi: } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} % % \begin{macro}{\int_to_bin:n, \int_to_hex:n, \int_to_Hex:n, \int_to_oct:n} % \UnitTested % Wrappers around the generic function. % \begin{macrocode} \cs_new:Npn \int_to_bin:n #1 { \int_to_base:nn {#1} { 2 } } \cs_new:Npn \int_to_hex:n #1 { \int_to_base:nn {#1} { 16 } } \cs_new:Npn \int_to_Hex:n #1 { \int_to_Base:nn {#1} { 16 } } \cs_new:Npn \int_to_oct:n #1 { \int_to_base:nn {#1} { 8 } } % \end{macrocode} % \end{macro} % % \begin{macro}{\int_to_roman:n, \int_to_Roman:n} % \UnitTested % \begin{macro}{\@@_to_roman:N, \@@_to_roman:N} % \begin{macro} % { % \@@_to_roman_i:w, \@@_to_roman_v:w, \@@_to_roman_x:w, % \@@_to_roman_l:w, \@@_to_roman_c:w, \@@_to_roman_d:w, % \@@_to_roman_m:w, \@@_to_roman_Q:w, % \@@_to_Roman_i:w, \@@_to_Roman_v:w, \@@_to_Roman_x:w, % \@@_to_Roman_l:w, \@@_to_Roman_c:w, \@@_to_Roman_d:w, % \@@_to_Roman_m:w, \@@_to_Roman_Q:w, % } % The \cs{@@_to_roman:w} primitive creates tokens of category % code $12$ (other). Usually, what is actually wanted is letters. % The approach here is to convert the output of the primitive into % letters using appropriate control sequence names. That keeps % everything expandable. The loop is terminated by the conversion % of the |Q|. % \begin{macrocode} \cs_new:Npn \int_to_roman:n #1 { \exp_after:wN \@@_to_roman:N \@@_to_roman:w \int_eval:n {#1} Q } \cs_new:Npn \@@_to_roman:N #1 { \use:c { @@_to_roman_ #1 :w } \@@_to_roman:N } \cs_new:Npn \int_to_Roman:n #1 { \exp_after:wN \@@_to_Roman_aux:N \@@_to_roman:w \int_eval:n {#1} Q } \cs_new:Npn \@@_to_Roman_aux:N #1 { \use:c { @@_to_Roman_ #1 :w } \@@_to_Roman_aux:N } \cs_new:Npn \@@_to_roman_i:w { i } \cs_new:Npn \@@_to_roman_v:w { v } \cs_new:Npn \@@_to_roman_x:w { x } \cs_new:Npn \@@_to_roman_l:w { l } \cs_new:Npn \@@_to_roman_c:w { c } \cs_new:Npn \@@_to_roman_d:w { d } \cs_new:Npn \@@_to_roman_m:w { m } \cs_new:Npn \@@_to_roman_Q:w #1 { } \cs_new:Npn \@@_to_Roman_i:w { I } \cs_new:Npn \@@_to_Roman_v:w { V } \cs_new:Npn \@@_to_Roman_x:w { X } \cs_new:Npn \@@_to_Roman_l:w { L } \cs_new:Npn \@@_to_Roman_c:w { C } \cs_new:Npn \@@_to_Roman_d:w { D } \cs_new:Npn \@@_to_Roman_m:w { M } \cs_new:Npn \@@_to_Roman_Q:w #1 { } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Converting from other formats to integers} % % \begin{macro}[rEXP]{\@@_pass_signs:wn, \@@_pass_signs_end:wn} % Called as \cs{@@_pass_signs:wn} \meta{signs and digits} \cs{s_@@_stop} % \Arg{code}, this function leaves in the input stream any sign it % finds, then inserts the \meta{code} before the first non-sign token % (and removes \cs{s_@@_stop}). More precisely, it deletes any~|+| and % passes any~|-| to the input stream, hence should be called in an % integer expression. % \begin{macrocode} \cs_new:Npn \@@_pass_signs:wn #1 { \if:w + \if:w - \exp_not:N #1 + \fi: \exp_not:N #1 \exp_after:wN \@@_pass_signs:wn \else: \exp_after:wN \@@_pass_signs_end:wn \exp_after:wN #1 \fi: } \cs_new:Npn \@@_pass_signs_end:wn #1 \s_@@_stop #2 { #2 #1 } % \end{macrocode} % \end{macro} % % \begin{macro}{\int_from_alph:n} % \UnitTested % \begin{macro}{\@@_from_alph:nN, \@@_from_alph:N} % First take care of signs then loop through the input using the % \texttt{recursion} quarks. The \cs{@@_from_alph:nN} auxiliary % collects in its first argument the value obtained so far, and the % auxiliary \cs{@@_from_alph:N} converts one letter to an expression % which evaluates to the correct number. % \begin{macrocode} \cs_new:Npn \int_from_alph:n #1 { \int_eval:n { \exp_after:wN \@@_pass_signs:wn \tl_to_str:n {#1} \s_@@_stop { \@@_from_alph:nN { 0 } } \q_@@_recursion_tail \q_@@_recursion_stop } } \cs_new:Npn \@@_from_alph:nN #1#2 { \@@_if_recursion_tail_stop_do:Nn #2 {#1} \exp_args:Nf \@@_from_alph:nN { \int_eval:n { #1 * 26 + \@@_from_alph:N #2 } } } \cs_new:Npn \@@_from_alph:N #1 { `#1 - \int_compare:nNnTF { `#1 } < { 91 } { 64 } { 96 } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\int_from_base:nn} % \UnitTested % \begin{macro}{\@@_from_base:nnN, \@@_from_base:N} % Leave the signs into the integer expression, then loop through % characters, collecting the value found so far in the first argument % of \cs{@@_from_base:nnN}. To convert a single character, % \cs{@@_from_base:N} checks first for digits, then distinguishes % lower from upper case letters, turning them into the appropriate % number. Note that this auxiliary does not use \cs{int_eval:n}, % hence is not safe for general use. % \begin{macrocode} \cs_new:Npn \int_from_base:nn #1#2 { \int_eval:n { \exp_after:wN \@@_pass_signs:wn \tl_to_str:n {#1} \s_@@_stop { \@@_from_base:nnN { 0 } {#2} } \q_@@_recursion_tail \q_@@_recursion_stop } } \cs_new:Npn \@@_from_base:nnN #1#2#3 { \@@_if_recursion_tail_stop_do:Nn #3 {#1} \exp_args:Nf \@@_from_base:nnN { \int_eval:n { #1 * #2 + \@@_from_base:N #3 } } {#2} } \cs_new:Npn \@@_from_base:N #1 { \int_compare:nNnTF { `#1 } < { 58 } {#1} { `#1 - \int_compare:nNnTF { `#1 } < { 91 } { 55 } { 87 } } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\int_from_bin:n, \int_from_hex:n, \int_from_oct:n} % \UnitTested % Wrappers around the generic function. % \begin{macrocode} \cs_new:Npn \int_from_bin:n #1 { \int_from_base:nn {#1} { 2 } } \cs_new:Npn \int_from_hex:n #1 { \int_from_base:nn {#1} { 16 } } \cs_new:Npn \int_from_oct:n #1 { \int_from_base:nn {#1} { 8 } } % \end{macrocode} % \end{macro} % % \begin{variable} % { % \c_@@_from_roman_i_int, \c_@@_from_roman_v_int, % \c_@@_from_roman_x_int, \c_@@_from_roman_l_int, % \c_@@_from_roman_c_int, \c_@@_from_roman_d_int, % \c_@@_from_roman_m_int, % \c_@@_from_roman_I_int, \c_@@_from_roman_V_int, % \c_@@_from_roman_X_int, \c_@@_from_roman_L_int, % \c_@@_from_roman_C_int, \c_@@_from_roman_D_int, % \c_@@_from_roman_M_int % } % Constants used to convert from Roman numerals to integers. % \begin{macrocode} \int_const:cn { c_@@_from_roman_i_int } { 1 } \int_const:cn { c_@@_from_roman_v_int } { 5 } \int_const:cn { c_@@_from_roman_x_int } { 10 } \int_const:cn { c_@@_from_roman_l_int } { 50 } \int_const:cn { c_@@_from_roman_c_int } { 100 } \int_const:cn { c_@@_from_roman_d_int } { 500 } \int_const:cn { c_@@_from_roman_m_int } { 1000 } \int_const:cn { c_@@_from_roman_I_int } { 1 } \int_const:cn { c_@@_from_roman_V_int } { 5 } \int_const:cn { c_@@_from_roman_X_int } { 10 } \int_const:cn { c_@@_from_roman_L_int } { 50 } \int_const:cn { c_@@_from_roman_C_int } { 100 } \int_const:cn { c_@@_from_roman_D_int } { 500 } \int_const:cn { c_@@_from_roman_M_int } { 1000 } % \end{macrocode} % \end{variable} % % \begin{macro}{\int_from_roman:n} % \UnitTested % \TestMissing{boundary cases / wrong input?} % \begin{macro}{\@@_from_roman:NN} % \begin{macro}{\@@_from_roman_error:w} % The method here is to iterate through the input, finding the % appropriate value for each letter and building up a sum. This is % then evaluated by \TeX{}. If any unknown letter is found, skip to % the closing parenthesis and insert |*0-1| afterwards, to replace the % value by $-1$. % \begin{macrocode} \cs_new:Npn \int_from_roman:n #1 { \int_eval:n { ( 0 \exp_after:wN \@@_from_roman:NN \tl_to_str:n {#1} \q_@@_recursion_tail \q_@@_recursion_tail \q_@@_recursion_stop ) } } \cs_new:Npn \@@_from_roman:NN #1#2 { \@@_if_recursion_tail_stop:N #1 \int_if_exist:cF { c_@@_from_roman_ #1 _int } { \@@_from_roman_error:w } \@@_if_recursion_tail_stop_do:Nn #2 { + \use:c { c_@@_from_roman_ #1 _int } } \int_if_exist:cF { c_@@_from_roman_ #2 _int } { \@@_from_roman_error:w } \int_compare:nNnTF { \use:c { c_@@_from_roman_ #1 _int } } < { \use:c { c_@@_from_roman_ #2 _int } } { + \use:c { c_@@_from_roman_ #2 _int } - \use:c { c_@@_from_roman_ #1 _int } \@@_from_roman:NN } { + \use:c { c_@@_from_roman_ #1 _int } \@@_from_roman:NN #2 } } \cs_new:Npn \@@_from_roman_error:w #1 \q_@@_recursion_stop #2 { #2 * 0 - 1 } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Viewing integer} % % \begin{macro}{\int_show:N, \int_show:c} % \UnitTested % \begin{macro}{\@@_show:nN} % Diagnostics. % \begin{macrocode} \cs_new_eq:NN \int_show:N \__kernel_register_show:N \cs_generate_variant:Nn \int_show:N { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\int_show:n} % \UnitTested % We don't use the \TeX{} primitive \tn{showthe} to show integer % expressions: this gives a more unified output. % \begin{macrocode} \cs_new_protected:Npn \int_show:n { \__kernel_msg_show_eval:Nn \int_eval:n } % \end{macrocode} % \end{macro} % % \begin{macro}{\int_log:N, \int_log:c} % Diagnostics. % \begin{macrocode} \cs_new_eq:NN \int_log:N \__kernel_register_log:N \cs_generate_variant:Nn \int_log:N { c } % \end{macrocode} % \end{macro} % % \begin{macro}{\int_log:n} % Similar to \cs{int_show:n}. % \begin{macrocode} \cs_new_protected:Npn \int_log:n { \__kernel_msg_log_eval:Nn \int_eval:n } % \end{macrocode} % \end{macro} % %\subsection{Random integers} % % \begin{macro}{\int_rand:nn} % Defined in \pkg{l3fp-random}. % \end{macro} % % \subsection{Constant integers} % % \begin{variable}{\c_zero_int, \c_one_int} % The zero is defined in \pkg{l3basics}. % \begin{macrocode} \int_const:Nn \c_one_int { 1 } % \end{macrocode} % \end{variable} % % \begin{variable}{\c_max_int} % The largest number allowed is $2^{31}-1$ % \begin{macrocode} \int_const:Nn \c_max_int { 2 147 483 647 } % \end{macrocode} % \end{variable} % % \begin{variable}{\c_max_char_int} % The largest character code is $1114111$ (hexadecimal |10FFFF|) in % \XeTeX{} and \LuaTeX{} and $255$ in other engines. In many places % \pTeX{} and \upTeX{} support larger character codes but for instance % the values of \tn{lccode} are restricted to $[0,255]$. % \begin{macrocode} \int_const:Nn \c_max_char_int { \if_int_odd:w 0 \cs_if_exist:NT \tex_luatexversion:D { 1 } \cs_if_exist:NT \tex_XeTeXversion:D { 1 } ~ "10FFFF \else: "FF \fi: } % \end{macrocode} % \end{variable} % % \subsection{Scratch integers} % % \begin{variable}{\l_tmpa_int, \l_tmpb_int} % \begin{variable}{\g_tmpa_int, \g_tmpb_int} % We provide two local and two global scratch counters, maybe we % need more or less. % \begin{macrocode} \int_new:N \l_tmpa_int \int_new:N \l_tmpb_int \int_new:N \g_tmpa_int \int_new:N \g_tmpb_int % \end{macrocode} % \end{variable} % \end{variable} % % \subsection{Integers for earlier modules} % %<@@=seq> % % \begin{variable}{\l_@@_internal_a_int, \l_@@_internal_b_int} % \begin{macrocode} \int_new:N \l_@@_internal_a_int \int_new:N \l_@@_internal_b_int % \end{macrocode} % \end{variable} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex