% \iffalse meta-comment
%
%% File: l3int.dtx
%
% Copyright (C) 1990-2026 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}
%</driver>
% \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 2026-08-10}
%
% \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 initializing 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:NV, \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}[added = 2024-12-08]
%   {
%     \int_set_regex_count:Nnn, \int_set_regex_count:cnn,
%     \int_set_regex_count:NNn, \int_set_regex_count:cNn,
%     \int_gset_regex_count:Nnn, \int_gset_regex_count:cnn,
%     \int_gset_regex_count:NNn, \int_gset_regex_count:cNn,
%   }
%   \begin{syntax}
%     \cs{int_set_regex_count:Nnn} \meta{integer} \Arg{regex} \Arg{token list}
%     \cs{int_set_regex_count:NNn} \meta{integer} \meta{regex~var} \Arg{token list}
%   \end{syntax}
%   Sets \meta{integer} equal to the number of times
%   \meta{regular expression} appears in \meta{token list}.
%   The search starts by finding the left-most longest match,
%   respecting greedy and lazy (non-greedy) operators. Then the search
%   starts again from the character following the last character
%   of the previous match, until reaching the end of the token list.
%   Infinite loops are prevented in the case where the regular expression
%   can match an empty token list: then we count one match between each
%   pair of characters.
%   For instance,
%   \begin{verbatim}
%     \int_set_regex_count:Nnn \l_foo_int { (b+|c) } { abbababcbb }
%   \end{verbatim}
%   results in \cs[no-index]{l_foo_int} taking the value $5$.
%   Theses are alternative names for \cs{regex_count:nnN} and friends,
%   with arguments re-ordered for \meta{integer} setting;
%   see \pkg{l3regex} chapter for more details of the \meta{regex}
%   format.
% \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,
%     \int_compare:vNn, \int_compare:nNv, \int_compare:vNv
%   }
%   \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.
%
%   Variables may be used directly in the \meta{int exprs} here: as a result,
%   there is no need for |V|- (or |e|-) type variants. The |v|-type
%   variants are provided for convenience.
% \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 = 2025-01-13, rEXP]
%   {\int_step_tokens:nn, \int_step_tokens:nnn, \int_step_tokens:nnnn} 
%   \begin{syntax}
%     \cs{int_step_tokens:nn} \Arg{final value} \Arg{code}
%     \cs{int_step_tokens:nnn} \Arg{initial value} \Arg{final value} \Arg{code}
%     \cs{int_step_tokens:nnnn} \Arg{initial value} \Arg{step} \Arg{final value} \Arg{code}
%   \end{syntax}
%   This function works just like \cs{int_step_function:nnnN} but
%   instead of mapping a single function to each stepped \meta{value}
%   between \meta{initial value} and \meta{final value} this maps
%   the multiple tokens in \meta{code}, so that it gets the current
%   \meta{value} as a braced argument following it.  For instance
%   \begin{verbatim}
%     \cs_set:Npn \my_product:nn #1#2
%       { $#1 \times #2 = \int_eval:n { #1 * #2 }$ \quad }
%     \int_step_tokens:nnnn { 1 } { 1 } { 4 } { \my_product:nn { 2 } }
%   \end{verbatim}
%   would print
%   \begin{quote}
%     $2 \times 1 = 2$ \quad
%     $2 \times 2 = 4$ \quad
%     $2 \times 3 = 6$ \quad
%     $2 \times 4 = 8$ \quad
%   \end{quote}
% \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}, 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}
%
% \begin{function}[EXP, added = 2025-06-09]{\int_format:nn}
%   \begin{syntax}
%     \cs{int_format:nn} \Arg{int expr} \Arg{format specification}
%   \end{syntax}
%   Evaluates the \meta{int expr} and converts the result to a
%   string according to the \meta{format specification}.  The
%   \meta{precision} argument is not allowed.  The \meta{style} can be
%   |b| for binary output, |d| for decimal output (this is the default),
%   |o| for octal output, |X| for hexadecimal output (using capital
%   letters). The details of the \meta{format specification} are described
%   in Section~\ref{sec:l3str-format:spec}.
% \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}
%
% \begin{variable}[module = int, added = 2026-04-22]{\c_max_intarray_int}
%   The maximum value that can be stored in an \texttt{intarray}.
%   \begin{texnote}
%     Due to the implementation, in \LuaTeX{} larger values could be
%     assigned if the programmer does not check values: this is
%     \emph{not} supported as part of the API.
%     \end{texnote}
% \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$, etc. The
%   \meta{integer} may be a literal, a constant or an integer
%   expression (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}
%<*code>
%    \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}{\@@_sep:}
%    \begin{macrocode}
\cs_new_eq:NN \@@_sep: \__kernel_int_sep:
%    \end{macrocode}
% \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: \@@_sep:
    \exp_stop_f:
  }
\cs_new:Npn \@@_sign:Nw #1#2 \@@_sep:
  {
    \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 \@@_sep:
      \int_value:w \@@_eval:w #2 \@@_sep:
      >
    \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 \@@_sep:
      \int_value:w \@@_eval:w #2 \@@_sep:
      <
    \exp_stop_f:
  }
\cs_new:Npn \@@_maxmin:wwN #1 \@@_sep: #2 \@@_sep: #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
%   (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 behavior 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 \@@_sep:
      \int_value:w \@@_eval:w #2 \@@_sep:
    \@@_eval_end:
  }
\cs_new:Npn \@@_div_truncate:NwNw #1#2 \@@_sep: #3#4 \@@_sep:
  {
    \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 \@@_sep:
      \int_value:w \@@_eval:w #2 \@@_sep:
    \@@_eval_end:
  }
\cs_new:Npn \@@_mod:ww #1 \@@_sep: #2 \@@_sep:
  { #1 - ( \@@_div_truncate:NwNw #1 \@@_sep: #2 \@@_sep: ) * #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 initializing 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}
%
% \begin{macro}
%   {
%     \int_set_regex_count:Nnn, \int_set_regex_count:cnn,
%     \int_gset_regex_count:Nnn, \int_gset_regex_count:cnn
%   }
% \begin{macro}
%   {
%     \int_set_regex_count:NNn, \int_set_regex_count:cNn,
%     \int_gset_regex_count:NNn, \int_set_gregex_count:cNn
%   }
%    \begin{macrocode}
\cs_new_protected:Npn \int_set_regex_count:Nnn #1#2#3
  { \regex_count:nnN {#2} {#3} #1 }
\cs_generate_variant:Nn \int_set_regex_count:Nnn { c }
\cs_new_protected:Npn \int_gset_regex_count:Nnn #1#2#3
  {
    \group_begin:
      \int_set_eq:NN \l_@@_tmpa_int #1
      \regex_count:nnN {#2} {#3} \l_@@_tmpa_int
      \int_gset_eq:NN #1 \l_@@_tmpa_int
    \group_end:
  }
\cs_generate_variant:Nn \int_gset_regex_count:Nnn { c }
\cs_new_protected:Npn \int_set_regex_count:NNn #1#2#3
  { \regex_count:NnN #2 {#3} #1 }
\cs_generate_variant:Nn \int_set_regex_count:Nnn { c }
\cs_new_protected:Npn \int_gset_regex_count:NNn #1#2#3
  {
    \group_begin:
      \int_set_eq:NN \l_@@_tmpa_int #1
      \regex_count:NnN #2 {#3} \l_@@_tmpa_int
      \int_gset_eq:NN #1 \l_@@_tmpa_int
    \group_end:
  }
\cs_generate_variant:Nn \int_gset_regex_count:NNn { c }
%    \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 ,
%     \int_compare:vNn ,
%     \int_compare:nNv ,
%     \int_compare:vNv
%   }
% \UnitTested
%   More efficient but less natural in typing; we add hand-tuned variants as
%   the build-in behavior makes this much more efficient. No mappings yet
%   so the setup has to be written out in full.
%    \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:
  }
\cs_new:Npn \int_compare_p:vNn #1#2#3
  { \int_compare_p:nNn { \use:c {#1} } #2 {#3} }
\cs_new:Npn \int_compare_p:nNv #1#2#3
  { \int_compare_p:nNn {#1} #2 { \use:c {#3} } }
\cs_new:Npn \int_compare_p:vNv #1#2#3
  { \int_compare_p:nNn { \use:c {#1} } #2 { \use:c {#3} } }
\cs_new:Npn \int_compare:vNnT #1#2#3
  { \int_compare:nNnT { \use:c {#1} } #2 {#3} }
\cs_new:Npn \int_compare:nNvT #1#2#3
  { \int_compare:nNnT {#1} #2 { \use:c {#3} } }
\cs_new:Npn \int_compare:vNvT #1#2#3
  { \int_compare:nNnT { \use:c {#1} } #2 { \use:c {#3} } }
\cs_new:Npn \int_compare:vNnF #1#2#3
  { \int_compare:nNnF { \use:c {#1} } #2 {#3} }
\cs_new:Npn \int_compare:nNvF #1#2#3
  { \int_compare:nNnF {#1} #2 { \use:c {#3} } }
\cs_new:Npn \int_compare:vNvF #1#2#3
  { \int_compare:nNnF { \use:c {#1} } #2 { \use:c {#3} } }
\cs_new:Npn \int_compare:vNnTF #1#2#3
  { \int_compare:nNnTF { \use:c {#1} } #2 {#3} }
\cs_new:Npn \int_compare:nNvTF #1#2#3
  { \int_compare:nNnTF {#1} #2 { \use:c {#3} } }
\cs_new:Npn \int_compare:vNvTF #1#2#3
  { \int_compare:nNnTF { \use:c {#1} } #2 { \use:c {#3} } }
%    \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:w, \@@_step:Nw}
% \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). And since when we're doing the
%   test the step size is the result of \cs{@@_eval:w} we know that only
%   the value $0$ has a leading token |0| which we can use for a faster
%   test than \cs{int_compare:nNnTF}.
%    \begin{macrocode}
\cs_new:Npn \int_step_function:nnnN #1#2#3
  {
    \exp_after:wN \@@_step:w
    \int_value:w \@@_eval:w #1 \exp_after:wN \@@_sep:
    \int_value:w \@@_eval:w #2 \exp_after:wN \@@_sep:
    \int_value:w \@@_eval:w #3 \@@_sep:
  }
\cs_new:Npn \@@_step:w #1 \@@_sep: #2 \@@_sep: #3 \@@_sep: #4
  {
    \int_compare:nNnTF {#2} > \c_zero_int
      { \@@_step:Nw > }
      {
        \if_meaning:w 0 #2
          \exp_after:wN \use_ii:nn
        \fi:
        \use_none:n
          {
            \msg_expandable_error:nnn
              { kernel } { zero-step } {#4}
            \prg_break:
          }
        \@@_step:Nw <
      }
      #1 \@@_sep: {#2} {#3} {#4}
    \prg_break_point:
  }
\cs_new:Npn \@@_step:Nw #1#2 \@@_sep: #3#4#5
  {
    \if_int_compare:w #2 #1 #4 \exp_stop_f:
      \prg_break:n
    \fi:
    #5 {#2}
    \exp_after:wN \@@_step:Nw
    \exp_after:wN #1
    \int_value:w \@@_eval:w #2 + #3 \@@_sep: {#3} {#4} {#5}
  }
\cs_new:Npn \int_step_function:nN
  { \int_step_function:nnnN \c_one_int \c_one_int }
\cs_new:Npn \int_step_function:nnN #1
  { \int_step_function:nnnN {#1} \c_one_int }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {\int_step_tokens:nn, \int_step_tokens:nnn, \int_step_tokens:nnnn} 
%   Because the internals \cs{@@_step:wwwn} and \cs{@@_step:Nwnnn} are
%   defined in such a way that they work with both a single token or a
%   braced group of tokens these are really the same as the |function|
%   variants.
%    \begin{macrocode}
\cs_new_eq:NN \int_step_tokens:nn   \int_step_function:nN
\cs_new_eq:NN \int_step_tokens:nnn  \int_step_function:nnN
\cs_new_eq:NN \int_step_tokens:nnnn \int_step_function:nnnN
%    \end{macrocode}
% \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
%   Unicode engines 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_cs_exist:N \tex_Uchar:D
      \if_cs_exist:N \tex_kanjiskip:D
        "FF
      \else:
        "10FFFF
      \fi:
    \else:
      "FF
    \fi:
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\c_max_intarray_int}
%   The largest number allowed is $2^{30}-1$.
%    \begin{macrocode}
\int_const:Nn \c_max_intarrray_int { 1 073 741 823 }
%    \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_@@_tmpa_int, \l_@@_tmpb_int}
%    \begin{macrocode}
\int_new:N \l_@@_tmpa_int
\int_new:N \l_@@_tmpb_int
%    \end{macrocode}
% \end{variable}
%
%    \begin{macrocode}
%</code>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
