% -*- coding: iso-latin-1; time-stamp-format: "%02d-%02m-%:y at %02H:%02M:%02S %Z" -*- %<*dtx> \def\bnedtxtimestamp {Time-stamp: <08-01-2019 at 13:04:43 CET>} \iffalse % %<*drv> %% --------------------------------------------------------------- \def\bnedocdate {2019/01/08}% package bnumexpr documentation date \def\bnepackdate{2019/01/08}% package bnumexpr date \def\bneversion {1.2e} % package bnumexpr version % %<*readme>-------------------------------------------------------- | Source: bnumexpr.dtx | Version: v1.2e, 2019/01/08 (doc: 2019/01/08) | Author: Jean-Francois Burnol | Info: Expressions with big integers | License: LPPL 1.3c README: [Usage], [Installation], [License] ========================================== Usage ----- The package `bnumexpr` allows _expandable_ computations with big integers and the four infix operators `+`, `-`, `*`, `/` familiar from the `\numexpr` e-TeX parser. Besides extending the scope to arbitrarily big numbers (and having a more complete syntax, for example `-(1)` is legal input), it adds the (by default) floored division operator `//`, and its associated modulo `/:`, the power operator `^` (or equivalently `**`), and the factorial post-fix operator `!`. The space character as well as the underscore character `_` both may serve to optionally separate digits in long numbers, for better readability of the input. For example: \bnumeval{( 92_874_927_979^5 - 31_9792_7979^6 ) / 30!} The above expands (in two steps) to `-4006240736596543944035189` (the `/` does rounded division to match the `\numexpr` behaviour). The expression parser is scaled-down from the `\xinttheiiexpr...\relax` parser as provided by package xintexpr[^1]: it does not handle hexadecimal input, boolean operators, dummy or user defined variables, functions, etc... By default, the package loads xintcore[^1] (release 1.3d is then required) but it is possible via option _custom_ and macro `\bnumexprsetup` to map the operators to macros of one's own choice. It is the responsability of the user to load the packages providing these custom macros. Notice that the possibility not to use the xintcore macros might be removed in the future: perhaps a future release will maintain during computations a private internal representation (especially tailored either for the xintcore macros or new ones which would be included within `bnumexpr.sty` itself) and the constraints this implies may render optional use of other macros impossible. [^1]: Installation ------------ Obtain `bnumexpr.dtx` (and possibly, `bnumexpr.ins` and the `README`) from CTAN: > Both `"tex bnumexpr.ins"` and `"tex bnumexpr.dtx"` extract from `bnumexpr.dtx` the following files: `bnumexpr.sty` : this is the style file. `README.md` : reconstitutes this README. `bnumexprchanges.tex` : lists changes from the initial version. `bnumexpr.tex` : can be used to generate the documentation: : - with latex+dvipdfmx: `"latex bnumexpr.tex"` (thrice) then `"dvipdfmx bnumexpr.dvi"`. : Ignore dvipdfmx warnings, but if the pdf file has problems with fonts (possibly from an old dvipdfmx), use then rather pdflatex. : - with pdflatex: `"pdflatex bnumexpr.tex"` (thrice). : In both cases files `README.md` and `bnumexprchanges.tex` must be present in the same repertory. without `bnumexpr.tex`: : `"pdflatex bnumexpr.dtx"` (thrice) extracts all files and simultaneously generates the pdf documentation. Finishing the installation: bnumexpr.sty --> TDS:tex/latex/bnumexpr/ bnumexpr.dtx --> TDS:source/latex/bnumexpr/ bnumexpr.ins --> TDS:source/latex/bnumexpr/ bnumexpr.pdf --> TDS:doc/latex/bnumexpr/ README --> TDS:doc/latex/bnumexpr/ Files `bnumexpr.tex`, `bnumexprchanges.tex`, `README.md` may be discarded. License ------- Copyright (C) 2014-2019 by Jean-Francois Burnol | This Work may be distributed and/or modified under the | conditions of the LaTeX Project Public License 1.3c. | This version of this license is in > | and version 1.3 or later is part of all distributions of | LaTeX version 2005/12/01 or later. This Work has the LPPL maintenance status "author-maintained". The Author and Maintainer of this Work is Jean-Francois Burnol. This Work consists of the main source file `bnumexpr.dtx` and the derived files bnumexpr.sty, bnumexpr.pdf, bnumexpr.ins, bnumexpr.tex, bnumexprchanges.tex, README.md %-------------------------------------------------------- %<*!readme> %% --------------------------------------------------------------- %% The bnumexpr package: Expressions with big integers %% Copyright (C) 2014-2019 by Jean-Francois Burnol %% % %<*changes>------------------------------------------------------- \item[1.2e (2019/01/08)] Fixes a documentation glitch (extra braces when mentioning |\the\numexpr| or |\thebnumexpr|). \item[1.2d (2019/01/07)] \begin{itemize} \item requires \xintcorename |1.3d| or later (if not using option |custom|). \item adds |\bnumeval|\marg{expression} user interface. \end{itemize} \item[1.2c (2017/12/05)] \textbf{Breaking changes:} \begin{itemize} \item requires \xintcorename |1.2p| or later (if not using option |custom|). \item |divtrunc| key of |\bnumexprsetup| is renamed to |div|. \item the |//| and |/:| operators are now by default associated to the \emph{floored} division. This is to keep in sync with the change of \xintcorename at |1.2p|. \item for backwards compatibility, one may add to existing document:\newline \string\bnumexprsetup\{div=\string\xintiiDivTrunc, mod=\string\xintiiModTrunc\} \end{itemize} \item[1.2b (2017/07/09)] \begin{itemize} \item the |_| may be used to separate visually blocks of digits in long numbers. \end{itemize} \item[1.2a (2015/10/14)] \begin{itemize} \item requires \xintcorename |1.2| or later (if not using option |custom|). \item additions to the syntax: factorial |!|, truncated division |//|, its associated modulo |/:| and |**| as alternative to |^|. \item all options removed except |custom|. \item new command |\bnumexprsetup| which replaces the commands such as |\bnumexprusesbigintcalc|. \item the parser is no more limited to numbers with at most 5000 digits. \end{itemize} \item[1.1b (2014/10/28)] \begin{itemize} \item README converted to |markdown/pandoc| syntax, \item the package now loads only |xintcore|, which belongs to |xint| bundle version |1.1| and extracts from the earlier |xint| package the core arithmetic operations as used by |bnumexpr|. \end{itemize} \item[1.1a (2014/09/22)] \begin{itemize} \item added |l3bigint| option to use experimental \LaTeX3 package of the same name, \item added Changes and Readme sections to the documentation, \item better |\BNE_protect| mechanism for use of |\bnumexpr...\relax| inside an |\edef| (without |\bnethe|). Previous one, inherited from |xintexpr.sty 1.09n|, assumed that the |\.=| dummy control sequence encapsulating the computation result had |\relax| meaning. But removing this assumption was only a matter of letting |\BNE_protect| protect two, not one, tokens. This will be backported to next version of \xintexprname, naturally (done with |xintexpr.sty 1.1|). \end{itemize} \item[1.1 (2014/09/21)] First release. This is down-scaled from the (development version of) \xintexprname. Motivation came the previous day from a chat with \textsc{Joseph Wright} over big int status in \LaTeX3. The |\bnumexpr...\relax| parser can be used on top of big int macros of one's choice. Functionalities limited to the basic operations. I leave the power operator |^| as an option. %------------------------------------------------------- %<*drv>----------------------------------------------------------- %% latex bnumexpr.tex (thrice) && dvipdfmx bnumexpr.dvi %% to produce bnumexpr.pdf %% %% or pdflatex bnumexpr.tex (no need to change \Withdvipdfmx toggle, %% pdf engine will be detected automatically) %% \NeedsTeXFormat{LaTeX2e} \ProvidesFile{bnumexpr.tex}% [\bnepackdate\space v\bneversion\space driver file for % bnumexpr documentation (JFB)]% \PassOptionsToClass{a4paper,fontsize=11pt}{scrdoc} \chardef\Withdvipdfmx 1 % \chardef\NoSourceCode 0 % replace 0 by 1 for not including source code \input bnumexpr.dtx %%% Local Variables: %%% mode: latex %%% End: %----------------------------------------------------------- %<*ins>----------------------------------------------------------- %% tex bnumexpr.ins will extract bnumexpr.sty from bnumexpr.dtx %% \input docstrip.tex \askforoverwritefalse \generate{\nopreamble\nopostamble \file{README.md}{\from{bnumexpr.dtx}{readme}} \usepreamble\defaultpreamble \usepostamble\defaultpostamble \file{bnumexprchanges.tex}{\from{bnumexpr.dtx}{changes}} \file{bnumexpr.tex}{\from{bnumexpr.dtx}{drv}} \file{bnumexpr.sty}{\from{bnumexpr.dtx}{package}}} \catcode32=13\relax% active space \let =\space% \Msg{************************************************************************} \Msg{*} \Msg{* To finish the installation you have to move the following} \Msg{* files into a directory searched by TeX:} \Msg{*} \Msg{* bnumexpr.sty} \Msg{*} \Msg{* To produce the documentation run latex thrice on bnumexpr.tex} \Msg{* then dvipdfmx on bnumexpr.dvi. (ignore the dvipdfmx warnings)} \Msg{*} \Msg{* Happy TeXing!} \Msg{*} \Msg{************************************************************************} \endbatchfile %----------------------------------------------------------- %<*dtx> \fi % end of \iffalse block around generated files \chardef\noetex 0 \ifx\numexpr\undefined \chardef\noetex 1 \fi \ifnum\noetex=1 \chardef\extractfiles 0 % extract files, then stop \else \ifx\ProvidesFile\undefined \chardef\extractfiles 0 % no LaTeX2e; etex, ... on bnumexpr.dtx \else % latex/pdflatex on bnumexpr.tex or on bnumexpr.dtx \ifx\Withdvipdfmx\undefined % latex run is on bnumexpr.dtx, we will extract all files \chardef\extractfiles 1 % 1 = extract and typeset, 2=only typeset \chardef\Withdvipdfmx 0 % 0 = pdflatex or latex+dvips, 1 = dvipdfmx \chardef\NoSourceCode 0 % 0 = include source code, 1 = do not \NeedsTeXFormat{LaTeX2e}% \PassOptionsToClass{a4paper,fontsize=11pt}{scrdoc}% \else % latex run is on bnumexpr.tex, \chardef\extractfiles 2 % no extractions \fi \ProvidesFile{bnumexpr.dtx}[bundle source (\bnedtxtimestamp)]% \fi \fi \ifnum\extractfiles<2 % extract files \def\MessageDeFin{\newlinechar10 \let\Msg\message \Msg{^^J}% \Msg{********************************************************************^^J}% \Msg{*^^J}% \Msg{* To finish the installation you have to move the following^^J}% \Msg{* files into a directory searched by TeX:^^J}% \Msg{*^^J}% \Msg{*\space\space\space\space bnumexpr.sty^^J}% \Msg{*^^J}% \Msg{* To produce the documentation run latex thrice on bnumexpr.tex^^J}% \Msg{* then dvipdfmx on bnumexpr.dvi. (ignore the dvipdfmx warnings)^^J}% \Msg{*^^J}% \Msg{* Happy TeXing!^^J}% \Msg{*^^J}% \Msg{********************************************************************^^J}% }% \begingroup \input docstrip.tex \askforoverwritefalse \generate{\nopreamble\nopostamble \file{README.md}{\from{bnumexpr.dtx}{readme}} \usepreamble\defaultpreamble \usepostamble\defaultpostamble \file{bnumexprchanges.tex}{\from{bnumexpr.dtx}{changes}} \file{bnumexpr.ins}{\from{bnumexpr.dtx}{ins}} \file{bnumexpr.tex}{\from{bnumexpr.dtx}{drv}} \file{bnumexpr.sty}{\from{bnumexpr.dtx}{package}}} \endgroup \fi % end of file extraction \ifnum\extractfiles=0 % direct tex/etex/xetex on bnumexpr.dtx, files now extracted, stop \MessageDeFin\expandafter\end \fi % no use of docstrip to extract files if latex compilation was on bnumexpr.tex \ifdefined\MessageDeFin\AtEndDocument{\MessageDeFin}\fi %------------------------------------------------------------------------------- \documentclass {scrdoc} \ifnum\NoSourceCode=1 \OnlyDescription\fi \usepackage{ifpdf} \ifpdf\chardef\Withdvipdfmx 0 \fi \makeatletter \ifnum\Withdvipdfmx=1 \@for\@tempa:=hyperref,bookmark,graphicx,xcolor,pict2e\do {\PassOptionsToPackage{dvipdfmx}\@tempa} % \PassOptionsToPackage{dvipdfm}{geometry} \PassOptionsToPackage{bookmarks=true}{hyperref} \PassOptionsToPackage{dvipdfmx-outline-open}{hyperref} \PassOptionsToPackage{dvipdfmx-outline-open}{bookmark} % \def\pgfsysdriver{pgfsys-dvipdfm.def} \else \PassOptionsToPackage{bookmarks=true}{hyperref} \fi \makeatother \pagestyle{headings} \usepackage[T1]{fontenc} \usepackage[latin1]{inputenc} \usepackage[hscale=0.66,vscale=0.75]{geometry} % requires newtxtt 1.05 or later \usepackage[zerostyle=a,scaled=0.95,straightquotes]{newtxtt} \renewcommand\familydefault\ttdefault \usepackage[noendash]{mathastext} \renewcommand\familydefault\sfdefault \usepackage{graphicx} \usepackage[dvipsnames]{xcolor} \definecolor{joli}{RGB}{225,95,0} \definecolor{JOLI}{RGB}{225,95,0} \definecolor{BLUE}{RGB}{0,0,255} %\definecolor{niceone}{RGB}{38,128,192}% utilisé avant pour urlcolor %\colorlet{smallverbcolor}{RoyalPurple}% \colorlet{jfverbcolor}{yellow!5} \colorlet{smallverbcolor}{NavyBlue}% \colorlet{softwrapcolor}{blue} \colorlet{digitscolor}{OrangeRed} % transféré de xint-manual.tex (maintenant dans xint.dtx) \DeclareFontFamily{U}{MdSymbolC}{} \DeclareFontShape {U}{MdSymbolC}{m}{n}{<-> MdSymbolC-Regular}{} \makeatletter \newbox\cdbx@SoftWrapIcon \def\cdbx@SetSoftWrapBox{% \setbox\cdbx@SoftWrapIcon\hb@xt@\z@ {\hb@xt@\fontdimen2\font {\hss{\color{softwrapcolor}\usefont{U}{MdSymbolC}{m}{n}\char"97}\hss}% \hss}% } \makeatother \usepackage[english]{babel} \usepackage[pdfencoding=pdfdoc]{hyperref} \hypersetup{% %linktoc=all,% breaklinks=true,% colorlinks=true,% urlcolor=SkyBlue,% linkcolor=PineGreen,% pdfauthor={Jean-Fran\c cois Burnol},% pdftitle={The bnumexpr package},% pdfsubject={Arithmetic with TeX},% pdfkeywords={Expansion, arithmetic, TeX},% pdfstartview=FitH,% pdfpagemode=UseOutlines} \usepackage{bookmark} %---- \verb, and verbatim like `environments'. \MicroFont et \MacroFont \makeatletter \def\MicroFont {\ttfamily\cdbx@SetSoftWrapBox\color{smallverbcolor}} %\def\MicroFont {\ttfamily \color[named]{OrangeRed}\cdbx@SetSoftWrapBox } % \MacroFont est utilisé par macrocode, mais sa définition est figée dans % \macro@font au \begin{document} \def\MacroFont {\ttfamily \baselineskip12pt\relax } %--- November 4, 2014 making quotes straight. (maintenu pour *) % % there is no hook in \macrocode after \dospecials etc. Thus I will need to % take the risk that some future evolution of doc.sty (or perhaps scrdoc) % invalidates the following. % % Actually, I should not at all rely on the doc class, I should do it all by % myself. \def\macrocode{\macro@code \frenchspacing \@vobeyspaces \makestarlowast % \makequotesstraight (obsolète) \xmacro@code } %--- lower * symbol in text \def\lowast{\raisebox{-.25\height}{*}} \catcode`* \active \def\makestarlowast {\let*\lowast\catcode`\*\active}% \catcode`* 12 %------------obsolete------------ %--- straight quotes, added (finally...) Nov 4, 2014 % \begingroup\makeatletter % \catcode`\'\active % \catcode`\`\active % \@firstofone {\endgroup % \def\makequotesstraight {% textcomp package has been loaded by newtxtt % \let`\textasciigrave % \let'\textquotesingle % \catcode39\active % \catcode96\active }% % } %------------ % Tentative, mardi 09 septembre 2014 à 22:41:28 % Modifié mardi 13 octobre 2015 à 15:24:00 pour utilisable en % argument, et en particulier dans un \footnote{}. Mais utilise % \scantokens et macro délimitée maintenant. %\def\jf@makeletter #1{\catcode`#111\relax } \def\verb #1% {% \relax\leavevmode\null \begingroup \MicroFont \catcode`_ 11 \catcode`! 11 \catcode`: 11 \catcode`< 11 \catcode`> 11 % \scantokens will have a result of inserting a space after cs's. % hence the need to have the catcodes of things like _ right. % I also need < for > for one occasion in code comments % naturally won't work in footnotes though. % this code is truly not satisfying, but enough for my needs here. \def\@jfverb ##1#1{\let\do\@makeother \dospecials \makestarlowast %\let\do\do@noligs \verbatim@nolig@list % not needed here \@vobeyspaces\everyeof{\noexpand}% \expandafter\@@jfverb\scantokens{##1}\relax}% \@jfverb }% % Pour v1.2 je laisse tomber les colorbox. À la place je change la couleur % du texte. J'utilise le violet de xint. (mis dans \Microfont) % \def\@@@jfverb #1{\ifcat\noexpand#1$% $ % \endgroup\else % % \penalty\z@ % \discretionary{\copy\cdbx@SoftWrapIcon}{}{}% % % \colorbox{jfverbcolor}{\strut #1}% unfortunately, impacts pdf size % #1% % \expandafter\@@@jfverb\fi } \def\@@jfverb #1{\ifcat\noexpand#1\relax\endgroup\else \discretionary{\copy\cdbx@SoftWrapIcon}{}{}% #1\expandafter\@@jfverb\fi } \makeatother % mardi 13 octobre 2015 à 15:32:51 % le | n'est pas encore actif ici! \catcode`| \active \def\bneshow #1% {|\thebnumexpr#1\relax|$$\color{digitscolor}\thebnumexpr#1\relax$$} \def\bneshoweval #1% {|\bnumeval{#1}|$$\color{digitscolor}\bnumeval{#1}$$} \catcode`| 12 \DeclareRobustCommand\csa [1]{{\char92\detokenize{#1}}} \newcommand\csh[1]{\texorpdfstring{\csa{#1}}{\textbackslash\detokenize{#1}}} \usepackage{xspace} \def\bnumname {\href{http://www.ctan.org/pkg/bnumexpr}{bnumexpr}\xspace }% \def\bnumnameimp {\texorpdfstring {\hyperref[sec:bnumexprcode]{{\color{smallverbcolor}\ttzfamily bnumexpr}}} {bnumexpr}% \xspace }% \def\xintname {\href{http://www.ctan.org/pkg/xint}{xint}\xspace }% \def\xintcorename {\href{http://www.ctan.org/pkg/xint}{xintcore}\xspace }% \def\xintexprname {\href{http://www.ctan.org/pkg/xint}{xintexpr}\xspace }% \def\xintbinhexname {\href{http://www.ctan.org/pkg/xint}{xintbinhex}\xspace }% % \centeredline: OUR OWN LITTLE MACRO FOR CENTERING LINES % ======================================================= % 7 mars 2013 % ----------- % % This macro allows to conveniently center a line inside a paragraph and still % allow use therein of \verb or other macros changing catcodes. % A proposito, the \LaTeX \centerline uses \hsize and not \linewidth ! % (which in my humble opinion is bad) % Actually my \centeredline works nicely in list environments. % \ignorespaces ajouté le 9 juin 2013. % Note: \centeredline creates a group \makeatletter \newcommand*\centeredline {% \ifhmode \\\relax \def\centeredline@{\hss\egroup\hskip\z@skip\ignorespaces }% \else \def\centeredline@{\hss\egroup }% \fi \afterassignment\@centeredline \let\next=} \def\@centeredline {\hbox to \linewidth \bgroup \hss \bgroup \aftergroup\centeredline@ } \frenchspacing \usepackage{bnumexpr} \usepackage{etoc} \usepackage{framed} \makeatletter\let\check@percent\relax\makeatother \begin{document} \thispagestyle{empty} \ttzfamily \pdfbookmark[1]{Title page}{TOP} {% \normalfont\Large\parindent0pt \parfillskip 0pt\relax \leftskip 2cm plus 1fil \rightskip 2cm plus 1fil The \bnumname package\par } {\centering \textsc{Jean-François Burnol}\par \footnotesize jfbu (at) free (dot) fr\par Package version: \bneversion\ (\bnepackdate); documentation date: \bnedocdate.\par {From source file \texttt{bnumexpr.dtx}. \bnedtxtimestamp.}\par } \etocsetnexttocdepth{section} \tableofcontents \section{Examples} \label{sec:bnumexpr} Package \bnumname provides |\thebnumexpr|\meta{expression}|\relax| which is analogous to |\the\numexpr|\meta{expression}|\relax|, with these extensions: \begin{itemize} \item it allows arbitrarily big integers, \item it computes powers (with either |**| or |^| as infix operator), \item it computes factorials (with |!| as postfix operator), \item it has an operator |//| for floored division and |/:| for the associated modulo, \item the space character can be used to separate in the source blocks of digits for better readability of long numbers, \item since |1.2b| the underscore |_| may also be used as visual digit separator, \item comma separated expressions are allowed. \end{itemize} It expands completely, but in two steps (whereas |\the\numexpr|\meta{expression}|\relax| expands in one step only, and |\numexpr| by itself is not expandable). |1.2d| adds a |\bnumeval|\marg{expression} interface. The |\bnumeval| macro also expands completely in two steps. Examples: \noindent\bneshow {1 208 637 867 * (2 187 917 891 + 3 109 197 072)}% \bneshoweval {(13_8089_1090-300_1890_2902)*(1083_1908_3901-109_8290_3890)}% \bneshow{(92_874_927_979**5-31_9792_7979**6)/30!}% \bneshoweval {30!/20!/21/22/23/24/25/(26*27*28*29)}% \bneshow {13^50//12^50, 13^50/:12^50}% \bneshoweval {13^50/12^50, 12^50}% \bneshow {(1^10+2^10+3^10+4^10+5^10+6^10+7^10+8^10+9^10)^3}% \bneshoweval {100!/36^100}% \section{Differences from \csh{numexpr}} Apart from the extension to big integers (i.e. exceeding the \TeX{} limit at \number"7FFFFFFF), and the added operators, there are a number of important differences between |\bnumexpr| and |\numexpr|: \begin{enumerate} \item one must use either |\thebnumexpr| or |\bnethe\bnumexpr| to get a printable result, as |\bnumexpr...\relax| expands to a private format (using |\number| as prefix to |\bnumexpr| would only serve to trigger the expansion to the \bnumname private format, hence will raise a \TeX\ error), \item one may embed directly (without |\bnethe|) a |\bnumexpr...\relax| in another one (or in a |\xintexpr...\relax|), but not in a |\numexpr...\relax|; on the other hand a |\numexpr...\relax| does not need to be prefixed by |\the| or |\number| inside |\bnethe\bnumexpr| or |\thebnumexpr|, \item contrarily to |\numexpr|, the |\bnumexpr| parser stops only after having found (and swallowed) a mandatory ending |\relax| token, \item in particular spaces between digits do not stop |\bnumexpr|, in contrast with |\numexpr|: |\the\numexpr 3 5+79\relax| expands (in one step) to \expandafter|\the\numexpr 3 5+79\relax| |\thebnumexpr 3 5+79\relax| expands (in two steps) to \expandafter\expandafter\expandafter|\thebnumexpr 3 5+79\relax| \item one may do |\edef\tmp{\bnumexpr 1+2\relax}|, and then either use |\tmp| in another |\bnumexpr...\relax|, or print it via |\bnethe\tmp|. The computation is done at the time of the |\edef| (and two expansion steps suffice). This is again in contrast with |\numexpr...\relax| which, without |\the| (or |\number| or |\romannumeral|) as prefix would not expand inside an |\edef|, \item expressions may be comma separated. On input, spaces are ignored, naturally, and on output the values are comma separated with a space after each comma, \item |\bnumexpr -(1+1)\relax| is legal contrarily to |\numexpr -(1+1)\relax| which raises an error, \item |\numexpr 2\cnta\relax| is illegal (with |\cnta| a |\count|-variable.) But |\bnumexpr 2\cnta\relax| is perfectly legal and will do the tacit multiplication, % \newcount\cnta % \cnta 1111 % \thebnumexpr 2\cnta\relax \item more generally, tacit multiplication applies in front of parenthesized sub-expressions, or sub |\bnumexpr...\relax| (or |\numexpr...\relax|), \item the underscore |_| is accepted within the digits composing a number and is silently ignored by |\bnumexpr|, \item |\numexpr| accepts \TeX\ syntax for hexadecimal input |"EF| (or octal input |'377|), but currently |\bnumexpr| does not. This could possibly be added in future% % \footnote{It is only a matter of copying pasting relevant code from \xintexprname, so depends upon user demands addressed to the author |;-)|.} % (hexadecimal prefix |"| is part of the recognized |\xintiiexpr| syntax from \xintexprname if \xintbinhexname is loaded.) In the meantime, one may encapsulate such inputs (obeying \TeX's bound on numbers) into a sub |\numexpr...\relax|. \end{enumerate} An important thing to keep in mind is that if one has a calculation whose result is a small integer, acceptable by \TeX{} in |\ifnum| or count assignments, this integer produced by |\thebnumexpr| is not self-delimiting, contrarily to a |\numexpr...\relax| construct: the situation is exactly as with a |\the\numexpr...\relax|, thus one may need to terminate the number to avoid premature expansion of following tokens; for example with the |\space| token. The parser |\bnumexpr| is a scaled-down version of parser |\xintiiexpr| from package \xintexprname. It lacks in particular boolean operators, square roots and other functions, variables, hexadecimal inputs, etc... it may be slightly faster when handling complicated expressions as it does not have to check so many things. The documentation of \xintexprname explains that there is an impact on the memory of \TeX{} (the string pool, the hash table) as each intermediate number is stored as a dummy control sequence name during processing. After thousands of evaluations with numbers having hundreds of digits, parts of the \TeX{} memory can become saturated and end the \verb?latex|pdflatex? run, but the problem can be avoided via enlarged memory parameters for |pdftex|, as made possible by modern TeX installations. Anyhow, computations with thousands of digits take time, and this is probably a more stringent constraint. If the same operations need to be repeated again and again tens of thousands of times on varying (big) numbers, the memory problem mentioned above may be avoided by using nested macros rather than |\bnumexpr| or |\xintexpr| expressions. Utility |\xintNewIIExpr| from package \xintexprname can be used to construct the possibly very complicated nested macro from a given expression with the needed operators and usual {\catcode`# 12 |#1, #2, #3, ...|} placeholders. % je voulais dire qu'une telle macro pouvait être préparée séparément, mais il % faudrait expliquer qu'il faut récupérer son \meaning, et j'ai le problème de % mes \romannumeral`&&@ maintenant... note 2015/10/27. Donc je laisse tomber. The \eTeX{} extensions are required (this is the default on all modern installations for \verb?latex|pdflatex? and also for \verb?xelatex|lualatex?). \section{Printing big numbers} \LaTeX{} will not split long numbers at the end of lines. I personally often use helper macros (not in the package) of the following type: \begin{verbatim} \def\allowsplits #1{\ifx #1\relax \else #1\hskip 0pt plus 1pt\relax \expandafter\allowsplits\fi}% \def\printnumber #1{\expandafter\allowsplits \romannumeral-`0#1\relax }% % \printnumber thus first ``fully'' expands its argument. \end{verbatim} \def\allowsplits #1{\ifx #1\relax \else #1\hskip 0pt plus 1pt\relax \expandafter\allowsplits\fi}% \def\printnumber #1{\expandafter\allowsplits \romannumeral-`0#1\relax }% \noindent|\thebnumexpr 1000!\relax=|\phantom{0}{\color{digitscolor}\printnumber{\thebnumexpr 1000!\relax}}\par \section{Expression syntax} It is the expected one with infix operators and parentheses, the recognized operators being |+|, |-|, |*|, |/| (rounded division), |^| (power), |**| (power), |//| (by default floored division), |/:| (the associated modulo) and |!| (factorial).% % \footnote{Releases |1.2b| and earlier associated in the default configuration truncated division to |//|. This was changed at |1.2c| to stay in sync with \xintcorename |1.2p|. For backwards compatibility, one may add to existing document \string\bnumexprsetup\{div=\string\xintiiDivTrunc, mod=\string\xintiiModTrunc\}.} The modulo |/:| is by default associated with the floored division |//|, but using |\bnumexprsetup{mod=...}| it can, like the other operators, be remapped to any macro of one's choice. Different computations may be separated by commas. The whole expression is handled token by token, any component (digit, operator, parenthesis... even the ending |\relax|) may arise on the spot from macro expansions. The precedence rules are the expected ones. There is currently no user interface to change precedence levels. The three operators |/|, |//|, |/:| are at the same level of precedence as the multiplication |*|. The factorial postfix |!| has highest precedence. The minus signs inherit the precedence level of the previously encountered infix operators. In case of equal precedence the operations are left-associative, hence:\newline \bneshoweval{2^3^4, (2^3)^4, 2^(3^4)} The underscore |_| can be used to separate digits in long numbers, for readability of the input. \section{Options} The sole package option is |custom|: it tells \bnumname not to load package \xintcorename. \section{\csh{bnumexprsetup}} Package \bnumname needs that some big integer engine provides the macros doing the actual computations. By default, it loads package \xintcorename (a subset of \href{http://www.ctan.org/pkg/xint}{xint}; version |1.3d| is required) and uses \csa{bnumexprsetup} in the following way: \begin{verbatim} \usepackage{xintcore} \bnumexprsetup{add=\xintiiAdd, sub=\xintiiSub, mul=\xintiiMul, divround=\xintiiDivRound, div=\xintiiDivFloor, mod=\xintiiMod, pow=\xintiiPow, fac=\xintiiFac} \end{verbatim} If using \csa{bnumexprsetup}, it is not necessary to specify all keys, for example one can do |\bnumexprsetup{mul=\MyFasterMul}|, and only multiplication will be changed. Naturally it is up to the user to load the appropriate package for the alternative macros. As per the macros which are the key values, they must have the following properties: \begin{enumerate} \item they must be completely expandable (in the sense of an |\edef| or a |\csname...\endcsname|.) \item they must fully expand their arguments first (in the sense of |\romannumeral-`0|.) \item they must output a number with no leading zeros, at most one minus sign and no plus sign. \end{enumerate} The first two items are truly mandatory, the last one may be not obeyed if the extra key |opp| is used with \csa{bnumexprsetup} to specify a suitable macro for the opposite of a number. This macro will be presented not with a braced argument but directly with a sequence of digits (either as gathered by the parser which skips leading zeros, or as produced by the other arithmetic macros and then there could be a minus, or even a plus if macros others than the ones from \xintcorename have been used). Thus, |opp| could identify a plus sign |+| upfront and then act adequately.\footnote{see \csa{BNE_Op_opp} in the code for the default.} Macro |\bnumexprsetup| can be used multiple times in the same document, thus allowing to switch math engines or to remap operators to some other arithmetic macros of the same math engine. Its effect obeys the local scope. \section{Readme} \begingroup \makeatletter\def\x{\baselineskip10pt \ttfamily\settowidth\dimen@{X}% %\parindent \dimexpr.5\linewidth-34\dimen@\relax \parindent\z@ \let\do\do@noligs\verbatim@nolig@list \let\do\@makeother\dospecials \makestarlowast %\def\par{\leavevmode\null\@@par\penalty\interlinepenalty}% \def\par{\leavevmode\null\@@par\pagebreak[1]}% \@vobeyspaces\obeylines \noindent\kern\parindent\input README.md \endgroup }\x \section{Changes} %\small \begin{description} \input bnumexprchanges.tex \end{description} \StopEventually{\end{document}\endinput} \newgeometry{hscale=0.75,vscale=0.75}% ATTENTION \newgeometry fait % un reset de vscale si on ne le % précise pas ici !!! \MakePercentIgnore % % \catcode`\<=0 \catcode`\>=11 \catcode`\*=11 \catcode`\/=11 % \let\relax % \def<*package>{\catcode`\<=12 \catcode`\>=12 \catcode`\*=12 \catcode`\/=12 } % %<*package> % % \section{Package \bnumnameimp implementation} % \label{sec:bnumexprcode} % % \localtableofcontents \bigskip % % Comments are sparse. Error handling by the parser is kept to a minimum; if % something goes wrong, the offensive token gets discarded, and some undefined % control sequence attempts to trigger writing to the log of some sort of % informative message. It is recommended to set |\errorcontextlines| to at % least |2| for more meaningful context. % % \subsection{Package identification and catcode setup} % |v1.2c| forgot to identify itself as such |:(|. Fixed (of course) at |v1.2d|. % \begin{macrocode} \NeedsTeXFormat{LaTeX2e}% \ProvidesPackage{bnumexpr}[2019/01/08 v1.2e Expressions with big integers (JFB)]% \edef\BNErestorecatcodes {\catcode`\noexpand\!\the\catcode`\! \catcode`\noexpand\?\the\catcode`\? \catcode`\noexpand\_\the\catcode`\_ \catcode`\noexpand\:\the\catcode`\: \catcode`\noexpand\(\the\catcode`\( \catcode`\noexpand\)\the\catcode`\) \catcode`\noexpand\*\the\catcode`\* \catcode`\noexpand\,\the\catcode`\,\relax }% \catcode`\! 11 \catcode`\? 11 \catcode`\_ 11 \catcode`\: 11 \catcode`\, 12 \catcode`\* 12 \catcode`\( 12 % \end{macrocode} % \subsection{Some helper macros and constants from xint} % These macros from xint should not change, hence overwriting them here should % not be cause for alarm. I opted against renaming everything with |\BNE_| % prefix rather than |\xint_|. The |\xint_dothis|/|\xint_orthat| thing is a new % style I have adopted for expandably forking. The least probable branches % should be specified first, for better efficiency. See examples of uses in the % present code. % \begin{macrocode} \chardef\xint_c_ 0 \chardef\xint_c_i 1 \chardef\xint_c_ii 2 \chardef\xint_c_vi 6 \chardef\xint_c_vii 7 \chardef\xint_c_viii 8 \chardef\xint_c_ix 9 \chardef\xint_c_x 10 \long\def\xint_gobble_i #1{}% \long\def\xint_gobble_iii #1#2#3{}% \long\def\xint_firstofone #1{#1}% \long\def\xint_firstoftwo #1#2{#1}% \long\def\xint_secondoftwo #1#2{#2}% \long\def\xint_firstofthree #1#2#3{#1}% \long\def\xint_secondofthree #1#2#3{#2}% \long\def\xint_thirdofthree #1#2#3{#3}% \def\xint_gob_til_! #1!{}% this ! has catcode 11 \long\def\xint_UDsignfork #1-#2#3\krof {#2}% \long\def\xint_afterfi #1#2\fi {\fi #1}% \long\def\xint_dothis #1#2\xint_orthat #3{\fi #1}% \let\xint_orthat \xint_firstofone \long\def\xint_zapspaces #1 #2{#1#2\xint_zapspaces }% % \end{macrocode} % \subsection{\csh{bnumexprsetup}} % New with |v1.2a|. Replaces removed |\bnumexprUsesbigintcalc| etc... % \begin{macrocode} \catcode`! 3 \def\bnumexprsetup #1{\BNE_parsekeys #1,=!,}% \def\BNE_parsekeys #1=#2#3,{\ifx!#2\expandafter\BNE_parsedone\fi \expandafter \let\csname BNE_Op_\xint_zapspaces #1 \xint_gobble_i\endcsname=#2\BNE_parsekeys }% \catcode`! 11 \def\BNE_parsedone #1\BNE_parsekeys {}% % \end{macrocode} % \subsection{Package options} % |v1.2c| replaces former key |divtrunc| by |div|. |v1.2d| requires (by % default) |xintcore 1.3d|. % \begin{macrocode} \def\BNE_tmpa {0}% \DeclareOption {custom}{\def\BNE_tmpa {1}}% \ProcessOptions\relax \if0\BNE_tmpa % Default is to load xintcore.sty \RequirePackage{xintcore}[2019/01/06]% xintcore 1.3d \bnumexprsetup{add=\xintiiAdd, sub=\xintiiSub, mul=\xintiiMul, divround=\xintiiDivRound, div=\xintiiDivFloor, mod=\xintiiMod, pow=\xintiiPow, fac=\xintiiFac}% \fi % \end{macrocode} % \subsection{\csh{bnumexpr}, \csh{thebnumexpr}, \csh{bnethe}, \csh{bnumeval}} % In the full |\xintexpr|, the final unlocking may involve post-treatment of % the comma separated values, hence there are |_print| macros to handle the % possibly comma separated values. Here we may just identify |_print| with % |_unlock|. % % With |v1.2a| the gathering of numbers happens directly inside % |\csname...\endcsname|. There is no more a ``locking'' macro. % % Attention |v1.2d| gives new meaning to |\bnumeval|, the former meaning is % now named |\bnumexpro|. The leading space in |\BNE_wrap| is removed at it % served to nothing. % \begin{macrocode} \def\bnumexpr {\romannumeral0\bnumexpro }% \def\bnumexpro{\expandafter\BNE_wrap\romannumeral0\BNE_eval }% \def\BNE_eval {\expandafter\BNE_until_end_a\romannumeral-`0\BNE_getnext }% \def\BNE_wrap {!\BNE_usethe\BNE_protect\BNE_unlock }% \protected\def\BNE_usethe\BNE_protect {\BNE:missing_bnethe!}% \def\BNE_protect\BNE_unlock {\noexpand\BNE_protect\noexpand\BNE_unlock\noexpand }% \let\BNE_done\space \def\thebnumexpr {\romannumeral-`0\expandafter\BNE_unlock\romannumeral0\BNE_eval }% \def\bnethe #1{\romannumeral-`0\expandafter\xint_gobble_iii\romannumeral-`0#1}% \def\bnumeval#1% {\romannumeral-`0\expandafter\BNE_unlock\romannumeral0\BNE_eval#1\relax}% \def\BNE_unlock {\expandafter\BNE_unlock_a\string }% \def\BNE_unlock_a #1.={}% % \end{macrocode} % \subsection{\csh{BNE_getnext}} % The getnext scans forward to find a number: after expansion of what comes % next, an opening parenthesis signals a parenthesized sub-expression, a |!| % with catcode 11 signals there was there a sub |\bnumexpr...\relax| (now % evaluated), a minus sign is treated as a prefix operator inheriting its % precedence level from the previous operator, a plus sign is swallowed, a % |\count| or |\dimen| will get fetched to |\number| (in case of a count % variable, this provides a full locked number but |\count0 1| for example is % like |1231| if |\count0|'s value is |123|); a digit triggers the % number scanner. With |v1.2a| the gathering of digits happens directly inside % |\csname .=...\endcsname|. Leading zeroes are trimmed directly. % The flow then proceeds with |\BNE_getop| which looks for the next operator % or possibly the end of the expression. Note: |\bnumexpr\relax| is % illegal. % % Extended in v1.2a to recognize |\ht|, etc... % \begin{macrocode} \def\BNE_getnext #1% {% \expandafter\BNE_getnext_a\romannumeral-`0#1% }% \def\BNE_getnext_a #1% {% \xint_gob_til_! #1\BNE_gn_foundexpr !% this ! has catcode 11 \ifcat\relax#1% \count or \numexpr etc... token or count, dimen, skip cs \expandafter\BNE_gn_countetc \else \expandafter\expandafter\expandafter\BNE_gn_fork\expandafter\string \fi #1% }% \def\BNE_gn_foundexpr !#1\fi !{\expandafter\BNE_getop\xint_gobble_iii }% \def\BNE_gn_countetc #1% {% \ifx\count#1\else\ifx\dimen#1\else\ifx\numexpr#1\else\ifx\dimexpr#1\else \ifx\skip#1\else\ifx\glueexpr#1\else\ifx\fontdimen#1\else\ifx\ht#1\else \ifx\dp#1\else\ifx\wd#1\else\ifx\fontcharht#1\else\ifx\fontcharwd#1\else \ifx\fontchardp#1\else\ifx\fontcharic#1\else \BNE_gn_unpackvar \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \expandafter\BNE_getnext\number #1% }% \def\BNE_gn_unpackvar\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \expandafter\BNE_getnext\number #1% {% \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \expandafter\BNE_getop\csname .=\number#1\endcsname }% % \end{macrocode} % This is quite simplified here compared to |\xintexpr|, for various reasons: we % have dropped the |\xintNewExpr| thing, and we can treat the |(| directly as we % don't have to get back to check if we are in an |\xintexpr|, % |\xintfloatexpr|, etc.. % \begin{macrocode} \def\BNE_gn_fork #1{% \if#1+\xint_dothis \BNE_getnext\fi \if#1-\xint_dothis -\fi \if#1(\xint_dothis \BNE_oparen \fi \xint_orthat {\BNE_scan_number #1}% }% % \end{macrocode} % \subsection{Parsing an integer} % We gather a string of digits, plus and minus prefixes have already been % swallowed. There might be some leading string of zeros which will have to be % removed. In the full |\xintexpr| the situation is more involved as it % has to recognize and accept decimal numbers, numbers in scientific notation, % also hexadecimal numbers, function names, variable names\dots % \begin{macrocode} \def\BNE_scan_number #1% this #1 has necessarily here catcode 12 {% \ifnum \xint_c_ix<1#1 \else\expandafter\BNE_notadigit\fi \BNE_scan_nbr #1% }% \def\BNE_notadigit\BNE_scan_nbr #1{\BNE:not_a_digit!\BNE_getnext }% % \end{macrocode} % Scanning for a number. We gather it directly inside csname. earlier % version did a chain of romannumeral. No limit on number of digits % anymore from the maximal expansion depth. We only have to be careful % about leading zeros. % % If we hit against some catcode eleven |!|, this means there was a % sub |\bnumexpr..\relax|. We then apply tacit multiplication. % \begin{macrocode} \def\BNE_scan_nbr #1% {% the #1 here is a catcode 12 digit \if#10\expandafter\BNE_scan_nbr_gobzeroes \else \expandafter\BNE_scan_nbr_start \fi #1% }% \def\BNE_scan_nbr_start #1#2% {% \expandafter\BNE_getop\csname.=#1% \expandafter\BNE_scanint_b\romannumeral-`0#2% }% \def\BNE_scan_nbr_gobzeroes #1% {% \expandafter\BNE_getop\csname.=% \expandafter\BNE_gobz_scanint_b\romannumeral-`0#1% }% \def\BNE_scanint_b #1% {% \ifcat \relax #1\expandafter\BNE_scanint_endbycs\expandafter #1\fi \ifnum\xint_c_ix<1\string#1 \else\expandafter\BNE_scanint_c\fi \string#1\BNE_scanint_d }% \def\BNE_scanint_endbycs#1#2\BNE_scanint_d{\endcsname #1}% \def\BNE_scanint_c\string #1\BNE_scanint_d {% \if _#1\xint_dothis{\expandafter\BNE_scanint_d\xint_gobble_i}\fi \ifcat a#1\xint_dothis{\endcsname*}\fi % tacit multiplication \xint_orthat {\expandafter\endcsname \string}#1% }% \def\BNE_scanint_d #1% {% \expandafter\BNE_scanint_b\romannumeral-`0#1% }% \def\BNE_gobz_scanint_b #1% {% \ifcat \relax #1\expandafter\BNE_gobz_scanint_endbycs\expandafter #1\fi \ifnum\xint_c_x<1\string#1 \else\expandafter\BNE_gobz_scanint_c\fi \string#1\BNE_scanint_d }% \def\BNE_gobz_scanint_endbycs#1#2\BNE_scanint_d{0\endcsname #1}% \def\BNE_gobz_scanint_c\string #1\BNE_scanint_d {% \if _#1\xint_dothis\BNE_gobz_scanint_d\fi \ifcat a#1\xint_dothis{0\endcsname*#1}\fi % tacit multiplication \if 0#1\xint_dothis\BNE_gobz_scanint_d\fi \xint_orthat {0\expandafter\endcsname \string#1}% }% \def\BNE_gobz_scanint_d #1% {% \expandafter\BNE_gobz_scanint_b\romannumeral-`0#1% }% % \end{macrocode} % \begin{macrocode} % \end{macrocode} % \subsection{\csh{BNE_getop}} % This finds the next infix operator or closing parenthesis or expression end. % It then leaves in the token flow . % The stops expansion and ultimately gives back control to a % |\BNE_until_| command. The code here is derived from more involved % context where the actual macro associated to the operator may vary, % depending if we are in |\xintexpr|, |\xintfloatexpr| or |\xintiiexpr|. Here % things are simpler but I have kept the general scheme, thus the actual macro % to be used for the is not decided immediately. % % |v1.2a| adds a technique for allowing two-letters operators, for % |//|, |/:| and |**|. % \begin{macrocode} \def\BNE_getop #1#2% this #1 is the current locked computed value {% \expandafter\BNE_getop_a\expandafter #1\romannumeral-`0#2% }% \catcode`* 11 \def\BNE_getop_a #1#2% {% if a control sequence is found, must be \relax, or possibly register or % variable if tacit multiplication is allowed \ifx \relax #2\xint_dothis\xint_firstofthree\fi % tacit multiplications: \ifcat \relax #2\xint_dothis\xint_secondofthree\fi \if (#2\xint_dothis \xint_secondofthree\fi \ifx !#2\xint_dothis \xint_secondofthree\fi \xint_orthat \xint_thirdofthree {\BNE_foundend #1}% {\BNE_precedence_* *#1#2}% tacit multiplication {\BNE_scanop_a #2#1}% }% \catcode`* 12 \def\BNE_foundend {\xint_c_ \relax }% \relax is only a place-holder here. \def\BNE_scanop_a #1#2#3% {\expandafter\BNE_scanop_b\expandafter #1\expandafter #2\romannumeral-`0#3}% \def\BNE_scanop_b #1#2#3% {% \ifcat#3\relax\xint_dothis{\BNE_foundop #1#2#3}\fi \ifcsname BNE_itself_#1#3\endcsname \xint_dothis {\expandafter\BNE_foundop\csname BNE_itself_#1#3\endcsname #2}\fi \xint_orthat {\BNE_foundop #1#2#3}% }% \def\BNE_foundop #1% {% \ifcsname BNE_precedence_#1\endcsname \csname BNE_precedence_#1\expandafter\endcsname \expandafter #1% \else \BNE_notanoperator {#1}\expandafter\BNE_getop \fi }% \def\BNE_notanoperator #1{\BNE:not_an_operator! \xint_gobble_i {#1}}% % \end{macrocode} % \subsection{Until macros for global expression and parenthesized sub-ones} % The minus sign as prefix is treated here. % \begin{macrocode} \catcode`) 11 \def\BNE_tmpa #1{% \def\BNE_until_end_a ##1% {% \xint_UDsignfork ##1{\expandafter\BNE_until_end_a\romannumeral-`0#1}% -{\BNE_until_end_b ##1}% \krof }% }\expandafter\BNE_tmpa\csname BNE_op_-vi\endcsname \def\BNE_until_end_b #1#2% {% \ifcase #1\expandafter\BNE_done \or \xint_afterfi{\BNE:extra_)_?\expandafter \BNE_until_end_a\romannumeral-`0\BNE_getop }% \else \xint_afterfi{\expandafter\BNE_until_end_a \romannumeral-`0\csname BNE_op_#2\endcsname }% \fi }% \catcode`( 11 \def\BNE_op_( {\expandafter\BNE_until_)_a\romannumeral-`0\BNE_getnext }% \let\BNE_oparen\BNE_op_( \catcode`( 12 \def\BNE_tmpa #1{% \def\BNE_until_)_a ##1{\xint_UDsignfork ##1{\expandafter \BNE_until_)_a\romannumeral-`0#1}% -{\BNE_until_)_b ##1}% \krof }% }\expandafter\BNE_tmpa\csname BNE_op_-vi\endcsname \def \BNE_until_)_b #1#2% {% \ifcase #1\expandafter \BNE_missing_)_? % missing ) ? \or\expandafter \BNE_getop % found closing ) \else \xint_afterfi {\expandafter \BNE_until_)_a\romannumeral-`0\csname BNE_op_#2\endcsname }% \fi }% \def\BNE_missing_)_? {\BNE:missing_)_inserted \xint_c_ \BNE_done }% \let\BNE_precedence_) \xint_c_i \let\BNE_op_) \BNE_getop \catcode`) 12 % \end{macrocode} % \subsection{The arithmetic operators.} % This is where the infix operators are mapped to actual macros. These macros % must ``f-expand'' their arguments, and know how to handle then big integers % having no leading zeros and at most a minus sign. % % |v1.2a| adds |//| for truncated division, |/:| for modulo operations % and |**| for powers (synonym to |^|). % % |v1.2c| has |//| and |/:| per default associated to floored division. % \begin{macrocode} \def\BNE_tmpc #1#2#3#4#5#6#7% {% \def #1##1% \BNE_op_ {% keep value, get next number and operator, then do until \expandafter #2\expandafter ##1\romannumeral-`0\expandafter\BNE_getnext }% \def #2##1##2% \BNE_until__a {\xint_UDsignfork ##2{\expandafter #2\expandafter ##1\romannumeral-`0#4}% -{#3##1##2}% \krof }% \def #3##1##2##3##4% \BNE_until__b {% either execute next operation now, or first do next (possibly unary) \ifnum ##2>#5% \xint_afterfi {\expandafter #2\expandafter ##1\romannumeral-`0% \csname BNE_op_##3\endcsname {##4}}% \else \xint_afterfi {\expandafter ##2\expandafter ##3% \csname .=#6{\BNE_unlock ##1}{\BNE_unlock ##4}\endcsname }% \fi }% \let #7#5% }% \def\BNE_tmpb #1#2#3% {% \expandafter\BNE_tmpc \csname BNE_op_#1\expandafter\endcsname \csname BNE_until_#1_a\expandafter\endcsname \csname BNE_until_#1_b\expandafter\endcsname \csname BNE_op_-#2\expandafter\endcsname \csname xint_c_#2\expandafter\endcsname \csname #3\expandafter\endcsname \csname BNE_precedence_#1\endcsname }% \BNE_tmpb +{vi}{BNE_Op_add}% \BNE_tmpb -{vi}{BNE_Op_sub}% \BNE_tmpb *{vii}{BNE_Op_mul}% \BNE_tmpb /{vii}{BNE_Op_divround}% \BNE_tmpb ^{viii}{BNE_Op_pow}% \expandafter\def\csname BNE_itself_**\endcsname {^}% shortcut for alias \expandafter\def\csname BNE_itself_//\endcsname {//}% \expandafter\def\csname BNE_itself_/:\endcsname {/:}% \BNE_tmpb {//}{vii}{BNE_Op_div}% \BNE_tmpb {/:}{vii}{BNE_Op_mod}% % \end{macrocode} % \subsection{! as postfix factorial operator} % New with |v1.2a|. % \begin{macrocode} \let\BNE_precedence_! \xint_c_x \def\BNE_op_! #1% {\expandafter\BNE_getop\csname .=\BNE_Op_fac{\BNE_unlock #1}\endcsname }% % \end{macrocode} % \subsection{The minus as prefix operator of variable precedence level} % It inherits the level of precedence of the previous operator. % \begin{macrocode} \def\BNE_tmpa #1% {% \expandafter\BNE_tmpb \csname BNE_op_-#1\expandafter\endcsname \csname BNE_until_-#1_a\expandafter\endcsname \csname BNE_until_-#1_b\expandafter\endcsname \csname xint_c_#1\endcsname }% \def\BNE_tmpb #1#2#3#4% {% \def #1% \BNE_op_- {% get next number+operator then switch to _until macro \expandafter #2\romannumeral-`0\BNE_getnext }% \def #2##1% \BNE_until_-_a {\xint_UDsignfork ##1{\expandafter #2\romannumeral-`0#1}% -{#3##1}% \krof }% \def #3##1##2##3% \BNE_until_-_b {% \ifnum ##1>#4% \xint_afterfi {\expandafter #2\romannumeral-`0% \csname BNE_op_##2\endcsname {##3}}% \else \xint_afterfi {\expandafter ##1\expandafter ##2% \csname .=\expandafter\BNE_Op_opp \romannumeral-`0\BNE_unlock ##3\endcsname }% \fi }% }% \BNE_tmpa {vi}% \BNE_tmpa {vii}% \BNE_tmpa {viii}% \def\BNE_Op_opp #1{\if-#1\else\if0#10\else-#1\fi\fi }% % \end{macrocode} % \subsection{The comma may separate expressions.} % It suffices to treat the comma as a binary operator of precedence |ii|. We % insert a space after the comma. The current code in |\xintexpr| does not do % it at this stage, but only later during the final unlocking, as there is % anyhow need for some processing for final formatting and was considered to % be as well the opportunity to insert the space. Here, let's do it % immediately. These spaces are not an issue when |\bnumexpr| is % identified as a sub-expression in |\xintexpr|, for example in: % |\xinttheiiexpr lcm(\bnumexpr 175-12,123+34,56*31\relax)\relax| (this % example requires package |xintgcd|). % \begin{macrocode} \catcode`, 11 \def\BNE_op_, #1% {% \expandafter \BNE_until_,_a\expandafter #1\romannumeral-`0\BNE_getnext }% \def\BNE_tmpa #1{% #1 = \BNE_op_-vi \def\BNE_until_,_a ##1##2% {% \xint_UDsignfork ##2{\expandafter \BNE_until_,_a\expandafter ##1\romannumeral-`0#1}% -{\BNE_until_,_b ##1##2}% \krof }% }\expandafter\BNE_tmpa\csname BNE_op_-vi\endcsname \def\BNE_until_,_b #1#2#3#4% {% \ifnum #2>\xint_c_ii \xint_afterfi {\expandafter \BNE_until_,_a \expandafter #1\romannumeral-`0% \csname BNE_op_#3\endcsname {#4}}% \else \xint_afterfi {\expandafter #2\expandafter #3% \csname .=\BNE_unlock #1, \BNE_unlock #4\endcsname }% \fi }% \let \BNE_precedence_, \xint_c_ii % \end{macrocode} % \subsection{Cleanup} % \begin{macrocode} \let\BNE_tmpa\relax \let\BNE_tmpb\relax \let\BNE_tmpc\relax \BNErestorecatcodes % \end{macrocode} % \MakePercentComment % %<*dtx> \DeleteShortVerb{\|} \CharacterTable {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z Digits \0\1\2\3\4\5\6\7\8\9 Exclamation \! Double quote \" Hash (number) \# Dollar \$ Percent \% Ampersand \& Acute accent \' Left paren \( Right paren \) Asterisk \* Plus \+ Comma \, Minus \- Point \. Solidus \/ Colon \: Semicolon \; Less than \< Equals \= Greater than \> Question mark \? Commercial at \@ Left bracket \[ Backslash \\ Right bracket \] Circumflex \^ Underscore \_ Grave accent \` Left brace \{ Vertical bar \| Right brace \} Tilde \~} \CheckSum {881} \makeatletter\check@checksum\makeatother \Finale %% End of file xint.dtx