diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/generic/xint/xint.dtx |
Initial commit
Diffstat (limited to 'macros/generic/xint/xint.dtx')
-rw-r--r-- | macros/generic/xint/xint.dtx | 40510 |
1 files changed, 40510 insertions, 0 deletions
diff --git a/macros/generic/xint/xint.dtx b/macros/generic/xint/xint.dtx new file mode 100644 index 0000000000..f5312323f1 --- /dev/null +++ b/macros/generic/xint/xint.dtx @@ -0,0 +1,40510 @@ +% -*- coding: utf-8; time-stamp-format: "%02d-%02m-%:y at %02H:%02M:%02S %Z" -*- +% This file: xint.dtx. Proudly produced by xint-dtxbuild.sh. +% Extract all files via "etex xint.dtx" and do "make help" +% or follow instructions from extracted README.md. +%<*dtx> +\def\xintdtxtimestamp {Time-stamp: <06-04-2019 at 18:55:58 CEST>} +%</dtx> +%<*drv> +%% --------------------------------------------------------------- +\def\xintdocdate {2019/04/05} +\def\xintbndldate{2019/04/05} +\def\xintbndlversion {1.3e} +%</drv> +%<readme>% README +%<changes>% CHANGE LOG +%<readme|changes>% xint 1.3e +%<readme|changes>% 2019/04/05 +%<readme|changes> +%<readme|changes> Source: xint.dtx 1.3e 2019/04/05 (doc 2019/04/05) +%<readme|changes> Author: Jean-Francois Burnol +%<readme|changes> Info: Expandable operations on big integers, decimals, fractions +%<readme|changes> License: LPPL 1.3e +%<readme|changes> +%<*!readme&!changes&!dohtmlsh&!dopdfsh&!makefile> +%% --------------------------------------------------------------- +%% The xint bundle 1.3e 2019/04/05 +%% Copyright (C) 2013-2019 by Jean-Francois Burnol +%<xintkernel>%% xintkernel: Paraphernalia for the xint packages +%<xinttools>%% xinttools: Expandable and non-expandable utilities +%<xintcore>%% xintcore: Expandable arithmetic on big integers +%<xint>%% xint: Expandable operations on big integers +%<xintfrac>%% xintfrac: Expandable operations on fractions +%<xintexpr>%% xintexpr: Expandable expression parser +%<xintbinhex>%% xintbinhex: Expandable binary and hexadecimal conversions +%<xintgcd>%% xintgcd: Euclidean algorithm with xint package +%<xintseries>%% xintseries: Expandable partial sums with xint package +%<xintcfrac>%% xintcfrac: Expandable continued fractions with xint package +%<xinttrig>%% xinttrig: Trigonometry for the xintexpr package +%<xintlog>%% xintlog: Logarithms and exponentials for xintexpr +%% --------------------------------------------------------------- +%</!readme&!changes&!dohtmlsh&!dopdfsh&!makefile> +%<*dtx> +\bgroup\catcode2 0 \catcode`\\ 12 ^^Biffalse +%</dtx> +%<*readme>-------------------------------------------------------- +This `README` is also available as `README.pdf` and `README.html`. + +Change log is to be found in `CHANGES.pdf` or `CHANGES.html`. + +The user manual is `xint.pdf`, and the commented source code is +available as `sourcexint.pdf`. + +Aim +=== + +The basic aim is provide *expandable* computations on integers, +fractions, and floating point numbers. For example + + \xinttheexpr reduce(37189719/183618963+11390170/17310720)^17\relax + +will evaluate exactly the fraction; the result has 462 characters +(including the fraction slash.) One can also work with dummy variables: + + \xinttheexpr mul(add(x(x+1)(x+2), x=y..y+15), y=171286,98762,9296)\relax + +evaluates to `15979066346135829902328007959448563667099190784`. + +Float computations are possible at an adjustable precision (default 16). + + \xintDigits:=48;\xintthefloatexpr 123_456_789^1_000.5\relax + ->3.63692761822782679930738270515740797370813691938e8095 + +(as this example shows the underscore character can be used to separate +visually digits, one can also use the space character for that purpose). + +Square-root and the four operations achieve correct rounding in the +given arbitrary precision. + +Trigonometric functions (direct and inverse) are available with a +maximal precision of 60 digits. + +Logarithms and exponentials are available using the +[poormanlog](http://www.ctan.org/pkg/poormanlog) package which provides +only 8 or 9 digits of precision. This will be increased in future. + +Usage +===== + +It is possible to use the package both with Plain +(`\input xintexpr.sty`) or with LaTeX (`\usepackage{xintexpr}`). + +## With LaTeX + + \usepackage{xint} % expandable arithmetic with big integers + \usepackage{xintfrac} % decimal numbers, fractions, floats + \usepackage{xinttools} % expandable and non expandable loops + \usepackage{xintexpr} % expressions with infix operators + +The `xinttrig` and `xintlog` packages are loaded automatically by +`xintexpr` and will refuse to be loaded directly. + +Further packages: `xintbinhex`, `xintgcd`, `xintseries` and `xintcfrac`. + +Main dependencies are handled automatically. For example `xintexpr` +automatically loads `xinttools` and `xintfrac` (which itself loads +`xint`). Hexadecimal input requires explicit loading of `xintbinhex`. + +Package `xintcore` is the subset of `xint` providing only the five +operations on big integers: `\xintiiAdd`, `\xintiiMul`, ... + +The LaTeX package [bnumexpr](http://www.ctan.org/pkg/bnumexpr) defines a +more light-weight parser of arithmetical expressions using big integers, +which supports only the four operations, the modulo operation, the power +operation, and the factorial. By default it uses the macros from +`xintcore` but this can be customized. + +The LaTeX package [polexpr](http://www.ctan.org/pkg/polexpr) is based +upon `xintexpr` and allows formal algebra with polynomials, and finding +all real roots with arbitrary precision. + +## With TeX + +One does for example: + + \input xintexpr.sty + +This will automatically load `xintfrac.sty`, `xinttrig.sty`, +`xintlog.sty` and `xinttools.sty`. The packages may be loaded in any +catcode context such that letters, digits, `\` and `%` have their +standard catcodes. + +`xintcore.sty` and `xinttools.sty` both import `xintkernel.sty` +which has the catcode handler and package identifier and defines a +few utilities such as `\oodef/\fdef`, `\xint_dothis/\xint_orthat`, +or `\xintLength`. + +Since `1.3b`, `xintkernel.sty` also provides `\xintUniformDeviate` which +is a wrapper of the engine `\pdfuniformdeviate` or `\uniformdeviate` +done to guarantee more uniformity of the pseudo-random integers. + +Installation +============ + +## Method A: using the package manager of your TeX distribution + +`xint` is included in [TeXLive](http://tug.org/texlive/) (hence also +[MacTeX](http://tug.org/mactex/)) and [MikTeX](http://www.miktex.org/). + +There can be a few days of delay between apparition of a new version on +[CTAN](http://www.ctan.org/pkg/xint) and availability via the distribution +package manager. + +## Method B: manual installation using `xint.tds.zip` and `unzip` + +Assumes a GNU/Linux-like system (or Mac OS X). + +1. obtain `xint.tds.zip` from CTAN: + <http://mirror.ctan.org/install/macros/generic/xint.tds.zip> + +2. cd to the download repertory and issue: + + unzip xint.tds.zip -d <TEXMF> + + where `<TEXMF>` is a suitable TDS-compliant destination repertory. + For example, with TeXLive: + + - Linux, standard access rights, hence sudo is needed, installation + into the "local" tree: + + sudo unzip xint.tds.zip -d /usr/local/texlive/texmf-local + sudo texhash /usr/local/texlive/texmf-local + + - Mac OS X, installation into user home folder (no sudo needed, + and it is recommended to not have a ls-R file there, hence no texhash): + + unzip xint.tds.zip -d ~/Library/texmf + +## Method C: manual installation using `Makefile` and `xint.dtx` + +The Makefile automatizes rebuilding from `xint.dtx` all documentation +files as well as `xint.tds.zip`. It is for GNU/Linux-like (inc. Mac OS +X) systems, with a teTeX like installation such as TeXLive. The +[Latexmk](http://personal.psu.edu/jcc8/software/latexmk/) +and [Pandoc](http://johnmacfarlane.net/pandoc/) softwares +are required to build all the documentation. + +1. obtain `xint.dtx` and `Makefile` from + <http://mirror.ctan.org/macros/generic/xint>. + +2. put them in an otherwise empty working repertory, run `make` or + equivalently `make help` for further instructions. + +## Method D: installation starting with only `xint.dtx` + +Run `etex xint.dtx` to extract from `xint.dtx` all macro files as well +as auxiliary files needed for building the documentation. Among them +there is `Makefile.mk`. If you are on a GNU/Linux-type system, rename +the file to `Makefile` and execute `make` on command line for further +help. If you can't use `make` read the contents of the `Makefile` for +instructions. + +Finishing the installation in a TDS hierarchy: + +- move the style files to `TDS:tex/generic/xint/` + +- `xint.dtx` goes to `TDS:source/generic/xint/` + +- The documentation (xint.pdf, README.md,...) goes to `TDS:doc/generic/xint/` + +Depending on the destination, it may then be necessary to refresh a +filename database. + +License +======= + +<div class="mono"> +Copyright (C) 2013-2019 by Jean-Francois Burnol + +This Work may be distributed and/or modified under the +conditions of the LaTeX Project Public License version 1.3c. +This version of this license is in + +> <http://www.latex-project.org/lppl/lppl-1-3c.txt> + +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 of this Work is Jean-Francois Burnol. + +This Work consists of the source file xint.dtx and of its derived +files: xintkernel.sty, xintcore.sty, xint.sty, xintfrac.sty, +xintexpr.sty, xinttrig.sty, xintlog.sty, xintbinhex.sty, +xintgcd.sty, xintseries.sty, +xintcfrac.sty, xinttools.sty, xint.ins, xint.tex, README, README.md, +README.html, README.pdf, CHANGES.md, CHANGES.html, CHANGES.pdf, +pandoctpl.latex, doHTMLs.sh, doPDFs.sh, xint.dvi, xint.pdf, +and Makefile.mk.</div> +%</readme>-------------------------------------------------------- +%<*changes>------------------------------------------------------- + +`1.3e (2019/04/05)` +---- + +### Incompatible changes + + - When defining functions, sub-expressions can only use the + `\xint(float)expr...\relax` syntax. One can *not* use there the + `\xint(float)eval` wrappers (anyhow they add overhead and can be + replaced with the lower level syntax). + +### Improvements and new features + + - The **xinttrig** library is automatically loaded by **xintexpr**. It + provides direct and inverse trigonometrical functions using either + degrees or radians with a precision of up to (a bit less than) 60 + digits. It is for the most part implemented using high level user + interface, but will probably get some optimizations in future (and + perhaps extension to more digits). + - The **xintlog** library is automatically loaded by **xintexpr**. It + uses [poormanlog](http://ctan.org/pkg/poormanlog) to provide + logarithms and exponentials with almost 9 digits of precision. + Extended precision is for a future release. + - **xintexpr**: `\xintdefefunc`, `\xintdeffloatefunc`, `\xintdefiiefunc` + define functions which are not protected against expansion in the + definition of other functions; refer to `xint.pdf` for the related + explanations. + + Notice that whole area of `\xintdef(e)func`, `\xintNewExpr`, + `\xintNewFunction` is complex and to be considered still as work in + progress as it has a number of shortcomings. + - **xintexpr**: `inv()`, `ilog10()`, `sfloat()`, behaviour of + `qfloat()` slightly modified. + - **xintexpr**: `\xintensuredummy`, `\xintrestorelettervar`. + - The optional argument of `\xintfloatexpr` or `\xintfloateval` (it + must be at start of braced argument) can be negative; it then means + to trim (and round) from the output at float precision that many + least significant digits. + +### Bug fixes + + - Some bugfixes related to user functions with no variables at all; + they were dysfunctional. + +`1.3d (2019/01/06)` +---- + +### Incompatible changes + + - **xintexpr**: the `gcd()` and `lcm()` functions formerly converted + their arguments to integers via `\xintNum`. They now handle general + input with no such modification. + + - **xintexpr**: former `\xinteval`, `\xintieval`, `\xintiieval`, and + `\xintfloateval` renamed to `\xintexpro`, `\xintiexpro`, + `\xintiiexpro`, and `\xintfloatexpro`. + +### Improvements and new features + + - **xintexpr**: the `gcd()` and `lcm()` multi-arguments functions have + been refactored to handle general fractions. The dependency on + **xintgcd** is removed. + + - **xintexpr**: three-way branching `\xintifsgnexpr`, + `\xintifsgnfloatexpr`, `\xintifsgniiexpr` conditional macros. + + - **xintexpr**: `\xintunassignexprfunc`, `\xintunassigniiexprfunc`, + `\xintunassignfloatexprfunc` to "undefine" functions. + + - **xintexpr**: `\xintunassignvar` really makes the (multi-letter) variable + unknown (formerly, it only gave it value zero), + + - **xintexpr**: functions `isone()` and `isint()`. + + - **xintexpr**: `\xinteval`, `\xintieval`, `\xintiieval`, and + `\xintfloateval` as synonyms to `\xinttheexpr...\relax` etc..., but + with the (comma-separated) expression as a usual braced macro + argument. + +### Bug fixes + + - **xintcore**, **xintexpr** : division in `\xintiiexpr` was broken for + a zero dividend and a one-digit divisor (e.g. ``0//7``) since `1.2p` + due to a bug in `\xintiiDivMod` for such arguments. The bug was + signaled (thanks to Kpym for report) and fixed shortly after `1.3c` + release but I then completely forgot to upload a bugfix release to + CTAN at that time, apologies for that. + +`1.3c (2018/06/17)` +---- + +### Improvements and new features + + - **xintexpr**: with `\xintglobaldefstrue`, `\xintdefvar`, + `\xintdeffunc`, `\xintNewExpr` et al. make definitions with global + scope. + + - **xintexpr**: `qraw()` for fast input of (very many) comma separated + numbers (in suitable raw format). + + - **xintexpr**: the colon in the `:=` part of the syntax for + `\xintdefvar` and variants is now optional; and if present it may be + an active character or have any (reasonable) catcode. + + - **xintexpr**: `\xintdefvar`, `\xintdeffunc` and their variants try to + set the catcode of the semi-colon which delimits their arguments; of + course this will not work if that catcode is already frozen. + + - `\xintUniformDeviate` is better documented and `sourcexint.pdf` is better + hyperlinked and includes indices for the macros defined by each package. + +### Bug fixes + + - **xintfrac**: since `1.3` release, it loaded **xintgcd** in + contradiction to what the documentation says (hence also **xintexpr** + loaded **xintgcd** automatically). There is no actual dependency so + the loading is removed for now. + +`1.3b (2018/05/18)` +---- + +### Improvements and new features + +All additions related to randomness are marked as work-in-progress. They +require an engine providing the `\(pdf)uniformdeviate` primitive. + + - **xintkernel**: `\xintUniformDeviate`. + + - **xint**: `\xintRandomDigits`, `\xintXRandomDigits`, `\xintiiRandRange`, + `\xintiiRandRangeAtoB`. + + - **xintfrac**: support macros (not public, mainly because internal + format for floats is surely not final) for `random()` and `qrand()`. + + - **xintexpr**: `random()`, `qrand()`, and `randrange(A[, B])`. + + - **xintexpr**: when a function `foo()` is declared via `\xintdeffunc` + (et al.) to be parameter-less, it can be used as `foo()`; formerly + `foo(nil)` syntax was required. + + - The usual provision of user manual "improvements". + + +`1.3a (2018/03/07)` +---- + +### Removed + + - **xintcore**, **xint**, **xintfrac**: removal of the internal macros + which were used at `1.2o` to add a deprecation mechanism; all + deprecated macros have been removed at `1.3` so there was no reason + to keep the code used for deprecating them. + +### Improvements and new features + + - **xintexpr**: new conditionals `ifone()` and `ifint()`. + + - **xintfrac**: `\xintREZ` is faster on inputs having one hundred + digits or more. + + - Added to the user manual mention of macros such as `\xintDivFloor`, + `\xintMod`, `\xintModTrunc`, which had been left out so far. + +### Bug fixes + + - **xintexpr**: the mechanism for adjunction to the expression parsers + of user defined functions was refactored and improved at previous + release `1.3`: in particular recursive definitions became possible. + But an oversight made these recursive functions quite inefficient (to + remain polite.) This release fixes the problem. + + +`1.3 (2018/03/01)` +---- + +### Incompatible changes + + - **xintcore**, **xint**, **xintfrac**: all macros deprecated at `1.2o` + got removed. + + - **xintfrac**: addition and subtraction of `a/b` and `c/d` now use the + l.c.m. of the denominators. Similarly the macro supporting the modulo + operator `/:` uses a l.c.m. for the denominator of the result. + + - **xintexpr**: the addition, subtraction, modulo `/:`, and the + `mod()` and `divmod()` functions produce generally smaller denominators + (see previous item). + + - **xintexpr**: formerly, the internal macros which are internally + associated to user-declared functions were using comma separated + parameter texts. They now do not use such commas (their meanings, + which may again change in future, are written for information to the + log under `\xintverbosetrue`). + +### Improvements and new features + + - **xintexpr**: user-defined functions may now be of a recursive + nature. This was made possible by a refactoring of the `\xintNewExpr` + mechanism. It became both leaner and more extensive than formerly. + + - **xintfrac**: new macros `\xintPIrr` and `\xintDecToString`. The + latter is a backport of a `polexpr 0.4` utility, and it is to be + considered unstable. + + - **xintexpr**: new function `preduce()` associated with `\xintPIrr`. + + +`1.2q (2018/02/06)` +---- + +### Improvements and new features + + - **xintexpr**: tacit multiplication extended to cases such as `3!4!5!` + or `(1+2)3`. + +### Bug fixes + + - **xintcore**: sadly, refactoring at `1.2l` of subtraction left an + extra character in an inner macro causing breakage in some rare + circumstances. This should not have escaped our test suite! + + +`1.2p (2017/12/05)` +---- + +### Incompatible changes + + - **xintgcd**: `\xintBezout{a}{b}`'s output consists of `{u}{v}{d}` + with `u*a+v*b==d`, with `d` the GCD. Formerly it was + `{a}{b}{u}{v}{d}`, and with `u*a-v*b==d`. + + - **xintgcd**: `\xintBezout{0}{0}` expands to `{0}{0}{0}`. Formerly + (since `1.2l`) it raised `InvalidOperation`. + + - **xintcore**: `\xintiiMod` is now associated with floored division. + The former meaning (associated with truncated division) is available + as `\xintiiModTrunc`. + + - **xintfrac**: `\xintMod` is now associated with floored division. The + former meaning is available as `\xintModTrunc`. + + - **xintexpr**: the ``//`` operator and its associated modulo ``'mod'`` + (or ``/:``) now correspond to floored division, like the Python + language `//`, `%`, and `divmod(x, y)`. Formerly they had been + associated to truncated division. This is breaking change for + operands of opposite signs. + +### Improvements and new features + + - **xinttools**: `\xintListWithSep`, which had remained unchanged since + its introduction at `1.04 (2013/04/25)`, was rewritten for increased + speed. + + - **xintexpr**: `\xintdefvar`'s syntax is extended to allow + simultaneous assignments. Examples: + `\xintdefvar x1, x2, x3 := 1, 3**10, 3**20;` or + `\xintdefiivar A, B := B, A 'mod' B;` + for already defined variables `A` and `B`. + + - **xintexpr**: added `divmod()` to the built-in functions. It is + associated with floored division, like the Python language `divmod()`. + Related support macros added to **xintcore**, and **xintfrac**. + +### Bug fixes + + - **xintgcd**: `\xintBezout{6}{3}` (for example) expanded to + `{6}{3}{-0}{-1}{3}`, but the `-0` should have been `0`. + + - **xintgcd**: it still used macro `\xintiAbs` although the latter had + been deprecated from **xintcore**. + + - **xintexpr**: in float expressions the `//` and `/:` (aka `'mod'`) + operators did not round their operands to the float precision prior + to computing with them, contrarily to other infix arithmetic + operators and to the `mod(f,g)` function; thus, `mod(f,g)` and + `f 'mod' g` were not completely equivalent. + + - various documentation fixes; in particular, the partial dependency of + **xintcfrac** on **xinttools** had not been mentioned. + + +`1.2o (2017/08/29)` +---- + +### Incompatible changes + + - **xint**: `\xintAND`, `\xintOR`, ... and similar Boolean logic macros do + not apply anymore `\xintNum` (or `\xintRaw` if **xintfrac** is loaded), to + their arguments (often, from internal usage of `\xintSgn`), but only + f-expand them (using e.g. `\xintiiSgn`). This is kept un-modified even if + loading **xintfrac**. + +### Deprecated + +Deprecated macros raise an error but, generally, then expand as in former +releases. They will all get removed at some future release. + + - **xintcore**: `\xintiOpp`, `\xintiAbs`, `\xintiAdd`, `\xintiSub`, + `\xintiMul`, `\xintiDivision`, `\xintiQuo`, `\xintiRem`, `\xintiDivRound`, + `\xintiDivTrunc`, `\xintiMod`, `\xintiSqr`, `\xintiPow`, and `\xintiFac` + are deprecated. Only the `ii`-named variants get defined. + + - **xintcore**: `\xintCmp` and `\xintSgn` are deprecated from **xintcore** + (which only defines `\xintiiCmp` and `\xintiiSgn`) as they actually belong + to **xintfrac**. + + - **xintcore**: `\xintiiFDg`, resp. `\xintiiLDg`, are renamed `\xintFDg`, + resp. `\xintLDg`. Former denominations are deprecated. + + - **xint**: `\xintMON`, `\xintMMON`, `\xintiMax`, + `\xintiMin`, `\xintiMaxof`, `\xintiMinof`, `\xintiSquareRoot`, + `\xintiSqrt`, `\xintiSqrtR`, `\xintiBinomial`, and `\xintiPFactorial` are + deprecated. Only `ii`-named variants get defined. + + - **xint**: `\xintEq`, `\xintGeq`, `\xintGt`, `\xintLt`, `\xintGtorEq`, + `\xintLtorEq`, `\xintIsZero`, `\xintIsNotZero`, `\xintIsOne`, + `\xintOdd`, `\xintEven`, `\xintifSgn`, + `\xintifCmp`, `\xintifEq`, `\xintifGt`, `\xintifLt`, `\xintifZero`, + `\xintifNotZero`, `\xintifOne`, `\xintifOdd`, are deprecated. These macros + belong to **xintfrac**. Package **xint** defines only the `ii`-named + variants. + + - **xint**: `\xintNeq` was renamed to `\xintNotEq` which however is only + provided by **xintfrac**. Package **xint** defines `\xintiiNotEq`, and + `\xintNeq` is deprecated. + + - **xint**: `\xintNot` was renamed to `\xintNOT`, former denomination is + deprecated. See also item about Boolean logic macros in the *Incompatible + Changes* section. + + +`1.2n (2017/08/06)` +---- + +### Incompatible changes + + - **xintbinhex** does not load package **xintcore** anymore, but only + **xintkernel**. + +### Improvements and new features + + - **xintbinhex** has only **xintkernel** as dependency. + + - Macros of **xintbinhex** have been improved for speed and increased maximal + sizes of allowable inputs. + + +`1.2m (2017/07/31)` +---- + +### Incompatible changes + + - **xintbinhex**: the length of the input is now limited. The maximum + size depends on the macro and ranges from about `4000` to about + `19900` digits. + + - **xintbinhex**: `\xintCHexToBin` is now the variant of + `\xintHexToBin` which does not remove leading binary zeroes: `N` + hex-digits give on output exactly `4N` binary digits. + +### Improvements and new features + + - **xintbinhex**: all macros have been rewritten using techniques from + the 1.2 release (they had remained unmodified since `1.08` of + `2013/06/07`.) The new macros are faster but limited to a few + thousand digits. The `1.08` routines could handle tens of thousands + of digits, but not in a reasonable time. + +### Bug fixes + + - user manual: the `Changes` section wrongly stated at `1.2l` that the + macros of **xintbinhex** had been made robust against non terminated + input such as ``\number\mathcode`\-``. Unfortunately the author fell + into the trap of believing his own documentation and he forgot to + actually implement the change. Now done. + + - user manual: the PDF bookmarks were messed up. + + - **xint**, **xintfrac**: `\xintGeq`, `\xintMax`, `\xintMin`, suffered + from some extra overhead. This was caused by use of some auxiliaries + from the very early days which got redefined at some stage. This is + fixed here with some additional efficiency improvements and pruning + of old code. + + +`1.2l (2017/07/26)` +---- + +### Removed + + - `\xintiiSumExpr`, `\xintiiPrdExpr` (**xint**) and `\xintSumExpr`, + `\xintPrdExpr` (**xintfrac**). They had not been formally deprecated, + but had been left un-documented since `1.09d (2013/10/22)`. + + - internal macro `\xint_gob_til_xint_relax` removed. + +### Improvements and new features + + - the underscore character `_` is accepted by the **xintexpr** parsers + as a digit separator (the space character already could be used for + improved readability of big numbers). It is not allowed as *first* + character of a number, as it would then be mis-interpreted as the + start of a possible variable name. + + - some refactoring in **xintcore** auxiliary routines and in + `\xintiiSub` and `\xintiiCmp` for some small efficiency gains. + + - code comments in **xintcore** are better formatted, but remain + sparse. + + - **xintcore**, **xint**, **xintfrac**, ... : some macros were not + robust against arguments whose expansion looks forward for some + termination (e.g. ``\number\mathcode`\-``), and particularly, most + were fragile against inputs using non-terminated ``\numexpr`` (such + as `\xintiiAdd{\the\numexpr1}{2}` or `\xintRaw{\numexpr1}`). This was + not a bug per se, as the user manual did not claim such inputs were + legal, but it was slightly inconvenient. Most macros (particularly + those of **xintfrac**) have now been made robust against such inputs. + Some macros from **xintcore** primarily destined to internal usage + still accept only properly terminated arguments such as + ``\the\mathcode`\-<space>`` or ``\the\numexpr1\relax``. + + The situation with expressions is unchanged: syntax such as + `\xintexpr \numexpr1+2\relax` is illegal as the ending `\relax` token + will get swallowed by the `\numexpr`; but it is needed by the + ``xintexpr``-ession parser, hence the parser will expand forward and + presumably end with in an "illegal token" error, or provoke some + low-level TeX error (N.B.: a closing brace `}` for example can not + terminate an ``xintexpr``-ession, the parser must find a `\relax` + token at some point). Thus there must be in this example a second + `\relax`. + + - experimental code for error conditions; there is no complete user + interface yet, it is done in preparation for next major release and + is completely unstable and undocumented. + +### Bug fixes + + - **xintbinhex**: since `1.2 (2015/10/10)`, `\xintHexToDec` was + broken due to an undefined macro (it was in `xint.sty`, but the + module by itself is supposedly dependent only upon `xintcore.sty`). + + - **xintgcd**: macro `\xintBezout` produced partially wrong output if + one of its two arguments was zero. + + - **xintfrac**: the manual said one could use directly `\numexpr` + compatible expressions in arithmetic macros (without even a + `\numexpr` encapsulation) if they were expressed with up to 8 tokens. + There was a bug if these 8 tokens evaluated to zero. The bug has been + fixed, and up to 9 tokens are now accepted. But it is simpler to use + `\the\numexpr` prefix and not to worry about the token count... The + ending `\relax` is now un-needed. + + +`1.2k (2017/01/06)` +---- + +### Incompatible changes + + - macro `\xintFloat` which rounds its input to a floating point number + does _not_ print anymore `10.0...0eN` to signal an upwards rounding + to the next power of ten. The mantissa has in all cases except the + zero input exactly one digit before the decimal mark. + + - some floating point computations may differ in the least significant + digits, due to a change in the rounding algorithm applied to macro + arguments expressed as fractions and to an improvement in precision + regarding half-integer powers in expressions. See next. + +### Improvements and new features + + - the initial rounding to the target precision `P` which is applied by + the floating point macros from **xintfrac** to their arguments + achieves the _exact (aka correct) rounding_ even for inputs which are + fractions with more than `P+2` digits in their numerators and + denominators (`>1`.) Hence the computed values depend only on the + arguments as rational numbers and not upon their representatives. + This is not relevant to _expressions_ (**xintexpr**), because the + `\xintfloatexpr` parser sees there `/` as an operator and does not + (apart from special constructs) get to manipulate fractions as such. + + - `\xintnewdummy` is public interface to a `1.2e` macro which serves to + declare any given catcode 11 character as a dummy variable for + expressions (**xintexpr**). This is useful for Unicode engines (the + Latin letters being already all pre-declared as dummy variables.) + + - added `\xintiSqrtR`, there was only `\xintiiSqrtR` alongside + `\xintiSqrt` and `\xintiiSqrt` (**xint**). + + - added non public `\xintLastItem:f:csv` to **xinttools** for faster + `last()` function, and improved `\xintNewExpr` compatibility. Also + `\xintFirstItem:f:csv`. + +### Bug fixes + + - the `1.2f` half-integer powers computed within `\xintfloatexpr` had a + silly rounding to the target precision just _before_ the final + square-root extraction, thus possibly losing some precision. The + `1.2k` implementation keeps guard digits for this final square root + extraction. As for integer exponents, it is guaranteed that the + computed value differs from the exact one by less than `0.52 ulp` + (for inputs having at most `\xinttheDigits` digits.) + + - more regressions from `1.2i` were fixed: `\xintLen` (**xint**, + **xintfrac**) and `\xintDouble` (**xintcore**) had forgotten that + their argument was allowed to be negative. A regression test suite is + now in place and is being slowly expanded to cover more macros. + + - `\xintiiSquareRoot{0}` now produces `{1}{1}`, which fits better the + general documented behaviour of this macro than `11`. + + +`1.2j (2016/12/22)` +---- + +### Improvements and new features + + - **xinttools** and **xintexpr**: + + 1. slightly improves the speed of `\xintTrim`. + + 2. speed gains for the handlers of comma separated lists + implementing Python-like slicing and item extraction. Relevant + non (user) documented macros better documented in + `sourcexint.pdf`. + + - significant documentations tweaks (inclusive of suppressing things!), + and among them two beautiful hyperlinked tables with both horizontal + and vertical rules which bring the documentation of the **xintexpr** + syntax to a kind of awe-inspiring perfection... except that + implementation of some math functions is still lacking. + +### Bug fixes + + - fix two `1.2i` regressions caused by undefined macros (`\xintNthElt` + in certain branches and `[list][N]` item extraction in certain + cases.) The test files existed but were not executed prior to + release. Automation in progress. + + +`1.2i (2016/12/13)` +---- + +### Incompatible changes + + - `\xintDecSplit` second argument must have no sign (former code + replaced it with its absolute value, a sign now may cause an error.) + +### Removed + + - deprecated macros `\xintifTrue`, `\xintifTrueFalse`, `\xintQuo`, + `\xintRem`, `\xintquo`, `\xintrem`. + +### Improvements and new features + + - **xintkernel**: `\xintLength` is faster. New macros: + + - `\xintLastItem` to fetch the last item from its argument, + + - `\romannumeral\xintgobble` for gobbling many (up to 531440) + upstream braced items or tokens. + + - `\romannumeral\xintreplicate` which is copied over from the expl3 + `\prg_replicate:nn` with some minor changes. + + - **xinttools**: general token list handling routines `\xintKeep`, + `\xintTrim` and `\xintNthElt` are faster; but the novel `\xintTrim` + can only remove up to a maximum of 531440 items. + + + Also, `\xintFor` partially improves on some issues which are + reported upon in the documentation. + + - some old macros have been rewritten entirely or partially using + techniques which **xint** started using in release `1.2`: + + - **xintcore**: `\xintDouble`, `\xintHalf`, `\xintInc`, `\xintDec`, + `\xintiiLDg`, `\xintDSR` (originally from **xint**), a novel + `\xintDSRr`. + + - **xint**: `\xintDSH`, `\xintDSx`, `\xintDecSplit`, `\xintiiE`. + + - **xintfrac**: as a result of the above `\xintTrunc`, `\xintRound` + and `\xintXTrunc` got faster. But the main improvement for them is + with decimal inputs which formerly had not been treated separately + from the general fraction case. Also, `\xintXTrunc` does not + anymore create a dependency of **xintfrac** on **xinttools**. + + - the documentation has again been (slightly) re-organized; it has a + new sub-section on the Miller-Rabin primality test, to illustrate + some use of `\xintNewFunction` for recursive definitions. + + - the documentation has dropped the LaTeX "command" terminology (which + had been used initially in 2013 for some forgotten reasons and should + have been removed long ago) and uses only the more apt "macro", as + after all, all of **xint** is about expansion of macros (plus the use + of `\numexpr`). + +### Bug fixes + + - `\xintDecSplitL` and `\xintDecSplitR` from **xint** produced their + output in a spurious brace pair (bug introduced in `1.2f`). + + +`1.2h (2016/11/20)` +---- + +### Improvements and new features + + - new macro `\xintNewFunction` in **xintexpr** which allows to extend + the parser syntax with functions in situations where `\xintdeffunc` + is not usable (typically, because dummy variables are used over a not + yet determined range of values because it depends on the variables). + + - after three years of strict obedience to `xint` prefix, now + `\thexintexpr`, `\thexintiexpr`, `\thexintfloatexpr`, and + `\thexintiiexpr` are provided as synonyms to `\xinttheexpr`, etc... + +### Bug fixes + + - the `(cond)?{foo}{bar}` operator from **xintexpr** mis-behaved in + certain circumstances (such as an empty `foo`). + + - the **xintexpr** `1.2f` `binomial` function (which uses + `\xintiiBinomial` from **xint.sty** or `\xintFloatBinomial` from + **xintfrac.sty**) deliberately raised an error for `binomial(x,y)` + with `y<0` or `x<y`. This was unfortunate, and it now simply + evaluates to zero in such cases. + + - similarly the `pfactorial` function was very strict and + `pfactorial(x,y)` deliberately raised an out-of-range error if not + used with non-negative integers with `x` less than `y`. It now avoids + doing that and allows negative arguments. + + - the `add` and `mul` from **xintexpr**, which work with dummy + variables since `1.1`, raised an error since `1.2c 2015/11/16` when + the dummy variable was given an empty range (or list) of values, + rather than producing respectively `0` and `1` as formerly. + + +`1.2g (2016/03/19)` +---- + +### Incompatible changes + + - inside expressions, list item selector `[L][n]` counts starting at + zero, not at one. This is more coherent with `[L][a:b]` which was + already exactly like in Python since its introduction. A function + len(L) replaces earlier `[L][0]`. + + - former `iter` keyword now called `iterr`. Indeed it matched with + `rrseq`, the new `iter` (which was somehow missing from `1.1`) is the + one matching `rseq`. Allows to iterate more easily with a "list" + variable. + +### Improvements and new features + + - in **xintexpr.sty**: list selectors `[L][n]` and `[L][a:b]` are more + efficient: the earlier `1.1` routines did back and forth conversions + from comma separated values to braced tokens, the `1.2g` routines use + macros from **xinttools.sty** handling directly the encountered lists + of comma separated values. + + - in **xinttools.sty**: slight improvements in the efficiency of the + `\xintNthElt`, `\xintKeep`, `\xintTrim` routines and new routines + handling directly comma separated values. The latter are not included + in the user manual (they are not `\long`, they don't make efforts to + preserve some braces, do not worry about spaces, all those worries + being irrelevant to the use in expressions for list selectors). + + - a slight speed improvement to `\xintFloatSqrt` in its quest of + correct rounding. + + - float multiplication and division handle more swiftly operands + (non-fractional) with few digits, when the float precision is large. + + - the syntax of expressions is described in a devoted chapter of the + documentation; an example shows how to implement (expandably) the + Brent-Salamin algorithm for computation of Pi using `iter` in a float + expression. + + +`1.2f (2016/03/12)` +---- + +### Incompatible changes + + - no more `\xintFac` macro but `\xintiFac/\xintiiFac/\xintFloatFac`. + +### Improvements and new features + + - functions `binomial`, `pfactorial` and `factorial` in both integer + and float versions. + + - macros `\xintiiBinomial`, `\xintiiPFactorial` + (**xint.sty**) and `\xintFloatBinomial`, `\xintFloatPFactorial` + (**xintfrac.sty**). Improvements to `\xintFloatFac`. + + - faster implementation and increased accuracy of float power macros. + Half-integer exponents are now accepted inside float expressions. + + - faster implementation of both integral and float square root macros. + + - the float square root achieves + *correct* (aka *exact*) rounding in arbitrary precision. + + - modified behaviour for the `\xintPFloat` macro, used by + `\xintthefloatexpr` to prettify its output. It now opts for decimal + notation if and only if scientific notation would use an exponent between + `-5` and `5` inclusive. The zero value is printed `0.` with a dot. + + - the float macros for addition, subtraction, multiplication, division now + first round their two operands to P, not P+2, significant places before + doing the actual computation (P being the target precision). The same + applies to the power macros and to the square root macro. + + - the documentation offers a more precise (and accurate) discussion of + floating point issues. + + - various under-the-hood code improvements; the floatexpr operations are + chained in a faster way, from skipping some unneeded parsing on results of + earlier computations. The absence of a real inner data structure for floats + (incorporating their precisions, for one) is however still a bit hair + raising: currently the lengths of the mantissas of the operands are computed + again by each float macro or expression operation. + + - (TeXperts only) the macros defined (internally) from `\xintdeffunc` et al. + constructs do not incorporate an initial `\romannumeral` anymore. + + - renewed desperate efforts at improving the documentation by random + shuffling of sections and well thought additions; cuts were considered and + even performed. + +### Bug fixes + + - squaring macro `\xintSqr` from **xintfrac.sty** was broken due to a + misspelled sub-macro name. Dates back to `1.1` release of `2014/10/28` + `:-((`. + + - `1.2c`'s fix to the subtraction bug from `1.2` introduced another bug, + which in some cases could create leading zeroes in the output, or even + worse. This could invalidate other routines using subtractions, like + `\xintiiSquareRoot`. + + - the comparison operators were not recognized by `\xintNewIIExpr` and + `\xintdefiifunc` constructs. + + +`1.2e (2015/11/22)` +---- + +### Improvements and new features + + - macro `\xintunassignvar`. + + - slight modifications of the logged messages in case of `\xintverbosetrue`. + + - a space in `\xintdeffunc f(x)<space>:= expression ;` is now accepted. + + - documentation enhancements: the _Quick Sort_ section with its included + code samples has been entirely re-written; the _Commands of the xintexpr + package_ section has been extended and reviewed entirely. + +### Bug fixes + + - in **xintfrac**: the `\xintFloatFac` from release `1.2` parsed its + argument only through `\numexpr` but it should have used `\xintNum`. + + - in **xintexpr**: release `1.2d` had broken the recognition of + sub-expressions immediately after variable names (with tacit + multiplication). + + - in **xintexpr**: contrarily to what `1.2d` documentation said, tacit + multiplication was not yet always done with enhanced precedence. Now + yes. + + +`1.2d (2015/11/18)` +---- + +### Improvements and new features + + - the function definitions done by `\xintdeffunc` et al., as well as + the macro declarations by `\xintNewExpr` et al. now have only local + scope. + + - tacit multiplication applies to more cases, for example (x+y)z, and + always ties more than standard * infix operator, e.g. x/2y is like + x/(2*y). + + - some documentation enhancements, particularly in the chapter on + xintexpr.sty, and also in the code source comments. + +### Bug fixes + + - in **xintcore**: release `1.2c` had inadvertently broken the + `\xintiiDivRound` macro. + + +`1.2c (2015/11/16)` +---- + +### Improvements and new features + + - macros `\xintdeffunc`, `\xintdefiifunc`, `\xintdeffloatfunc` and + boolean `\ifxintverbose`. + + - on-going code improvements and documentation enhancements, but + stopped in order to issue this bugfix release. + +### Bug fixes + + - in **xintcore**: recent release `1.2` introduced a bug in the + subtraction (happened when 00000001 was found under certain + circumstances at certain mod 8 locations). + + +`1.2b (2015/10/29)` +---- + +### Bug fixes + + - in **xintcore**: recent release `1.2` introduced a bug in the division + macros, causing a crash when the divisor started with 99999999 (it was + attempted to use with 1+99999999 a subroutine expecting only 8-digits + numbers). + + +`1.2a (2015/10/19)` +---- + +### Improvements and new features + + - added `\xintKeepUnbraced`, `\xintTrimUnbraced` (**xinttools**) and fixed + documentation of `\xintKeep` and `\xintTrim` regarding brace stripping. + + - added `\xintiiMaxof/\xintiiMinof` (**xint**). + + - TeX hackers only: replaced all code uses of ``\romannumeral-`0`` + by the quicker ``\romannumeral`&&@`` (`^` being used as letter, + had to find another character usable with catcode 7). + +### Bug fixes + + - in **xintexpr**: recent release `1.2` introduced a bad bug in the + parsing of decimal numbers and as a result `\xinttheexpr 0.01\relax` + expanded to `0` ! (sigh...) + + +`1.2 (2015/10/10)` +---- + +### Removed + + - the macros `\xintAdd`, `\xintSub`, `\xintMul`, `\xintMax`, + `\xintMin`, `\xintMaxof`, `\xintMinof` are removed from package + **xint**, and only exist in the versions from **xintfrac**. With only + **xintcore** or **xint** loaded, one _must_ use `\xintiiAdd`, + `\xintiiSub`, ..., or `\xintiAdd`, `\xintiSub`, etc... + +### Improvements and new features + + - the basic arithmetic implemented in **xintcore** has been entirely + rewritten. The mathematics remains the elementary school one, but the + `TeX` implementation achieves higher speed (except, regarding + addition/subtraction, for numbers up to about thirty digits), the + gains becoming quite significant for numbers with hundreds of digits. + + - the inputs must have less than 19959 digits. But computations with + thousands of digits take time. + + - a previously standing limitation of `\xintexpr`, `\xintiiexpr`, and + of `\xintfloatexpr` to numbers of less than 5000 digits has been + lifted. + + - a *qint* function is provided to help the parser gather huge integers + in one-go, as an exception to its normal mode of operation which + expands token by token. + + - `\xintFloatFac` macro for computing the factorials of integers as + floating point numbers to a given precision. The `!` postfix operator + inside `\xintfloatexpr` maps to this new macro rather than to the + exact factorial as used by `\xintexpr` and `\xintiiexpr`. + + - there is more flexibility in the parsing done by the macros from + **xintfrac** on fractional input: the decimal parts of both the + numerator and the denominator may arise from a separate expansion via + ``\romannumeral-`0``. Also the strict `A/B[N]` format is a bit + relaxed: `N` may be anything understood by `\numexpr` (it could even + be empty but that possibility has been removed by later `1.2f` + release.) + + - on the other hand an isolated dot `.` is not legal syntax anymore + inside the expression parsers: there must be digits either before or + after. It remains legal input for the macros of **xintfrac**. + + - added `\ht`, `\dp`, `\wd`, `\fontcharht`, etc... to the tokens + recognized by the parsers and expanded by `\number`. + + - an obscure bug in package **xintkernel** has been fixed, regarding + the sanitization of catcodes: under certain circumstances (which + could not occur in a normal `LaTeX` context), unusual catcodes could + end up being propagated to the external world. + + - an effort at randomly shuffling around various pieces of the + documentation has been done. + + +`1.1c (2015/09/12)` +---- + + - bugfix regarding macro `\xintAssign` from **xinttools** which did + not behave correctly in some circumstances (if there was a space + before `\to`, in particular). + + - very minor code improvements, and correction of some issues + regarding the source code formatting in `sourcexint.pdf`, and + minor issues in `Makefile.mk`. + + +`1.1b (2015/08/31)` +---- + + - bugfix: some macros needed by the integer division routine from + **xintcore** had been left in **xint.sty** since release `1.1`. This + for example broke the `\xintGCD` from **xintgcd** if package **xint** + was not loaded. + + - Slight enhancements to the documentation, particularly in the + `Read this first` section. + + +`1.1a (2014/11/07)` +---- + + - fixed a bug which prevented `\xintNewExpr` from producing correctly working + macros from a comma separated replacement text. + + - `\xintiiSqrtR` for rounded integer square root; former `\xintiiSqrt` + already produced truncated integer square root; corresponding function + `sqrtr` added to `\xintiiexpr..\relax` syntax. + + - use of straight quotes in the documentation for better legibility. + + - added `\xintiiIsOne`, `\xintiiifOne`, `\xintiiifCmp`, `\xintiiifEq`, + `\xintiiifGt`, `\xintiiifLt`, `\xintiiifOdd`, `\xintiiCmp`, `\xintiiEq`, + `\xintiiGt`, `\xintiiLt`, `\xintiiLtorEq`, `\xintiiGtorEq`, `\xintiiNeq`, + mainly for efficiency of `\xintiiexpr`. + + - for the same reason, added `\xintiiGCD` and `\xintiiLCM`. + + - added the previously mentioned `ii` macros, and some others from `1.1`, to + the user manual. But their main usage is internal to `\xintiiexpr`, to skip + unnecessary overheads. + + - various typographical fixes throughout the documentation, and a bit + of clean up of the code comments. Improved `\Factors` example of nested + `subs`, `rseq`, `iter` in `\xintiiexpr`. + + +`1.1 (2014/10/28)` +---- + +### Incompatible changes + + - in `\xintiiexpr`, `/` does _rounded_ division, rather than the + Euclidean division (for positive arguments, this is truncated division). + The `//` operator does truncated division, + + - the `:` operator for three-way branching is gone, replaced with `??`, + + - `1e(3+5)` is now illegal. The number parser identifies `e` and `E` + in the same way it does for the decimal mark, earlier versions treated + `e` as `E` rather as infix operators of highest precedence, + + - the `add` and `mul` have a new syntax, old syntax is with `` `+` `` and + `` `*` `` (left quotes mandatory), `sum` and `prd` are gone, + + - no more special treatment for encountered brace pairs `{..}` by the + number scanner, `a/b[N]` notation can be used without use of braces (the + `N` will end up as is in a `\numexpr`, it is not parsed by the + `\xintexpr`-ession scanner), + + - in earlier releases, place holders for `\xintNewExpr` could either + be denoted `#1`, `#2`, ... or also `$1`, `$2`, ... + Only the usual `#` form is now accepted and the special cases previously + treated via the second form are now managed via a `protect(...)` function. + + - **xintfrac**: `\xintFloor` and `\xintCeil` add a trailing `/1[0]` to their + (integer) output. New `\xintiFloor` and `\xintiCeil` do not. + +### Removed + + - `\xintnumexpr`, `\xintthenumexpr`, `\xintNewNumExpr`: use + `\xintiexpr`, `\xinttheiexpr`, `\xintNewIExpr`. + +### Deprecated + + - `\xintDivision`, `\xintQuo`, `\xintRem`: use `\xintiDivision`, + `\xintiQuo`, `\xintiRem`. + + - `\xintMax`, `\xintMin`, `\xintAdd`, `\xintSub`, `\xintMul` + (**xint**): their usage without **xintfrac** is deprecated; use + `\xintiMax`, `\xintiMin`, `\xintiAdd`, `\xintiSub`, `\xintiMul`. + + - the `&` and `|` as Boolean operators in `xintexpr`-essions are + deprecated in favour of `&&` and `||`. The single letter operators + might be assigned some other meaning in some later release (bitwise + operations, perhaps). Do not use them. + +### Improvements and new features + + * new package **xintcore** has been split off **xint**. It contains the + core arithmetic macros (it is loaded by LaTeX package **bnumexpr**), + + * neither **xint** nor **xintfrac** load **xinttools**. Only + **xintexpr** does, + + * whenever some portion of code has been revised, often use has been made of + the `\xint_dothis` and `\xint_orthat` pair of macros for expandably + branching, + + * these tiny helpful macros, and a few others are in package + **xintkernel** which contains also the catcode and loading order + management code, initially inspired by code found in Heiko Oberdiek's + packages, + + * the source code, which was suppressed from `xint.pdf` in release + `1.09n`, is now compiled into a separate file `sourcexint.pdf`, + + * faster handling by `\xintAdd`, `\xintSub`, `\xintMul`, ... of the case + where one of the arguments is zero, + + * the `\xintAdd` and `\xintSub` macros from package **xintfrac** check if + one of the denominators is a multiple of the other, and only if this is + not the case do they multiply the denominators. But systematic reduction + would be too costly, + + * this naturally will be also the case for the `+` and `-` operations + in `\xintexpr`, + + * **xint** added `\xintiiDivRound`, `\xintiiDivTrunc`, `\xintiiMod` + for rounded and truncated division of big integers (next to + `\xintiiQuo` and `\xintiiRem`), + + * with **xintfrac** loaded, the `\xintNum` macro does `\xintTTrunc` + (which is truncation to an integer, same as `\xintiTrunc {0}`), + + * added `\xintMod` to **xintfrac** for modulo operation with + fractional numbers, + + * added `\xintiFloor` and `\xintiCeil` to **xintfrac**, + + * `\xintiexpr`, `\xinttheiexpr` admit an optional argument within brackets + `[d]`, they round the computation result (or results, if comma separated) + to `d` digits after decimal mark, (the whole computation is done exactly, + as in `xintexpr`), + + * `\xintfloatexpr`, `\xintthefloatexpr` similarly admit an optional + argument which serves to keep only `d` digits of precision, getting rid + of cumulated uncertainties in the last digits (the whole computation is + done according to the precision set via `\xintDigits`), + + * `\xinttheexpr` and `\xintthefloatexpr` _pretty-print_ if possible, the + former removing unit denominator or `[0]` brackets, the latter avoiding + scientific notation if decimal notation is practical, + + * the `//` does truncated division and `/:` is the associated modulo, + + * multi-character operators `&&`, `||`, `==`, `<=`, `>=`, `!=`, + `**`, + + * multi-letter infix binary words `'and'`, `'or'`, `'xor'`, `'mod'` + (straight quotes mandatory), + + * functions `even`, `odd`, + + * `\xintdefvar A3:=3.1415;` for variable definitions (non expandable, + naturally), usable in subsequent expressions; variable names may contain + letters, digits, underscores. They should not start with a digit, the `@` + is reserved, and single lowercase and uppercase Latin letters are + predefined to work as dummy variables (see next), + + * generation of comma separated lists `a..b`, `a..[d]..b`, + + * Python syntax-like list extractors `[list][n:]`, `[list][:n]`, + `[list][a:b]` allowing negative indices, but no optional step argument, + and `[list][n]` (`n=0` for the number of items in the list), + + * functions `first`, `last`, `reversed`, + + * itemwise operations on comma separated lists `a*[list]`, etc.., possible + on both sides `a*[list]^b`, and obeying the same precedence rules as with + numbers, + + * `add` and `mul` must use a dummy variable: `add(x(x+1)(x-1), x=-10..10)`, + + * variable substitutions with `subs`: + `subs(subs(add(x^2+y^2,x=1..y),y=t),t=20)`, + + * sequence generation using `seq` with a dummy variable: `seq(x^3, + x=-10..10)`, + + * simple recursive lists with `rseq`, with `@` given the last value, + `rseq(1;2@+1,i=1..10)`, + + * higher recursion with `rrseq`, `@1`, `@2`, `@3`, `@4`, and `@@(n)` + for earlier values, up to `n=K` where `K` is the number of terms of the + initial stretch `rrseq(0,1;@1+@2,i=2..100)`, + + * iteration with `iter` which is like `rrseq` but outputs only the + last `K` terms, where `K` was the number of initial terms, + + * inside `seq`, `rseq`, `rrseq`, `iter`, possibility to use `omit`, + `abort` and `break` to control termination, + + * `n++` potentially infinite index generation for `seq`, `rseq`, + `rrseq`, and `iter`, it is advised to use `abort` or `break(..)` at + some point, + + * the `add`, `mul`, `seq`, ... are nestable, + + * `\xintthecoords` converts a comma separated list of an even number + of items to the format expected by the `TikZ` `coordinates` syntax, + + * completely new version `\xintNewExpr`, `protect` function to handle + external macros. The dollar sign + `$` for place holders is not accepted anymore, only the standard macro + parameter `#`. Not all constructs are compatible with `\xintNewExpr`. +% $ this docstripped line for emacs buffer fontification issues in doctex-mode + +### Bug fixes + + - `\xintZapFirstSpaces` hence also `\xintZapSpaces` from package **xinttools** + were buggy when used with an argument either empty or containing only + space tokens. + + - `\xintiiexpr` did not strip leading zeroes, hence + `\xinttheiiexpr 001+1\relax` did not obtain the expected result ... + + - `\xinttheexpr \xintiexpr 1.23\relax\relax` should have produced `1`, + but it produced `1.23` + + - the catcode of `;` was not set at package launching time. + + - the `\XINTinFloatPrd:csv` macro name had a typo, hence `prd` was + non-functional in `\xintfloatexpr`. + + +`1.09n (2014/04/01)` +---- + + * the user manual does not include by default the source code + anymore: the `\NoSourceCode` toggle in file `xint.tex` has to + be set to 0 before compilation to get source code inclusion + (later release `1.1` made source code available as `sourcexint.pdf`). + + * bug fix (**xinttools**) in `\XINT_nthelt_finish` (this bug was + introduced in `1.09i` of `2013/12/18` and showed up when the index + `N` was larger than the number of elements of the list). + + +`1.09m (2014/02/26)` +---- + + * new in **xinttools**: `\xintKeep` keeps the first `N` or last + `N` elements of a list (sequence of braced items); `\xintTrim` + cuts out either the first `N` or the last `N` elements from a + list. + + * new in **xintcfrac**: `\xintFGtoC` finds the initial partial + quotients common to two numbers or fractions `f` and `g`; + `\xintGGCFrac` is a clone of `\xintGCFrac` which however does not + assume that the coefficients of the generalized continued + fraction are numeric quantities. Some other minor changes. + + +`1.09kb (2014/02/13)` +---- + + * bug fix (**xintexpr**): an aloof modification done by `1.09i` to + `\xintNewExpr` had resulted in a spurious trailing space present + in the outputs of all macros created by `\xintNewExpr`, making + nesting of such macros impossible. + + * bug fix (**xinttools**): `\xintBreakFor` and `\xintBreakForAndDo` + were buggy when used in the last iteration of an `\xintFor` loop. + + * bug fix (**xinttools**): `\xintSeq` from `1.09k` needed a `\chardef` + which was missing from `xinttools.sty`, it was in `xint.sty`. + + +`1.09k (2014/01/21)` +---- + + * inside `\xintexpr..\relax` (and its variants) tacit multiplication is + implied when a number or operand is followed directly with an + opening parenthesis, + + * the `"` for denoting (arbitrarily big) hexadecimal numbers is + recognized by `\xintexpr` and its variants (package + **xintbinhex** is required); a fractional hexadecimal part + introduced by a dot `.` is allowed. + + * re-organization of the first sections of the user manual. + + * bug fix (**xinttools**, **xint**, ...): forgotten catcode check of + `"` at loading time has been added. + + +`1.09j (2014/01/09)` +---- + + * (**xint**) the core division routines have been re-written for some + (limited) efficiency gain, more pronounced for small divisors. As a + result the *computation of one thousand digits of $\pi$* is close + to three times faster than with earlier releases. + + * some various other small improvements, particularly in the power + routines. + + * (**xintfrac**) a macro `\xintXTrunc` is designed to produce + thousands or even tens of thousands of digits of the decimal + expansion of a fraction. Although completely expandable it has its + use limited to inside an `\edef`, `\write`, `\message`, \dots. It + can thus not be nested as argument to another package macro. + + * (**xintexpr**) the tacit multiplication done in `\xintexpr..\relax` + on encountering a count register or variable, or a `\numexpr`, + while scanning a (decimal) number, is extended to the case of a sub + `\xintexpr`-ession. + + * `\xintexpr` can now be used in an `\edef` with no `\xintthe` prefix; + it will execute completely the computation, and the error message + about a missing `\xintthe` will be inhibited. Previously, in the + absence of `\xintthe`, expansion could only be a full one (with + ``\romannumeral-`0``), not a complete one (with `\edef`). Note + that this differs from the behavior of the non-expandable + `\numexpr`: `\the` or `\number` (or `\romannumeral`) are needed + not only to print but + also to trigger the computation, whereas `\xintthe` is mandatory + only for the printing step. + + * the default behavior of `\xintAssign` is changed, it now does not + do any further expansion beyond the initial full-expansion which + provided the list of items to be assigned to macros. + + * bug fix (**xintfrac**): `1.09i` did an unexplainable change to + `\XINT_infloat_zero` which broke the floating point routines for + vanishing operands =:((( + + * bug fix: the `1.09i` `xint.ins` file produced a buggy `xint.tex` file. + + +`1.09i (2013/12/18)` +---- + + * (**xintexpr**) `\xintiiexpr` is a variant of `\xintexpr` which is + optimized to deal only with (long) integers, `/` does a euclidean + quotient. + + * *deprecated*: `\xintnumexpr`, `\xintthenumexpr`, `\xintNewNumExpr` are + renamed, respectively, `\xintiexpr`, `\xinttheiexpr`, `\xintNewIExpr`. The + earlier denominations are kept but are to be removed at some point. + + * it is now possible within `\xintexpr...\relax` and its variants to + use count, dimen, and skip registers or variables without + explicit `\the/\number`: the parser inserts automatically + `\number` and a tacit multiplication is implied when a register + or variable immediately follows a number or fraction. Regarding + dimensions and `\number`, see the further discussion in + *Dimensions*. + + * (**xintfrac**) conditional `\xintifOne`; `\xintifTrueFalse` + renamed to `\xintifTrueAelseB`; macros `\xintTFrac` + (`fractional part`, mapped to function `frac` in + `\xintexpr`-essions), `\xintFloatE`. + + * (**xinttools**) `\xintAssign` admits an optional argument to + specify the expansion type to be used: `[]` (none, default), `[o]` + (once), `[oo]` (twice), `[f]` (full), `[e]` (`\edef`),... to define + the macros + + * **xinttools** defines `\odef`, `\oodef`, `\fdef` (if the names have + already been assigned, it uses `\xintoodef` etc...). These tools are + provided for the case one uses the package macros in a non-expandable + context. `\oodef` expands twice the macro replacement text, and `\fdef` + applies full expansion. They are useful in situations where one does not + want a full `\edef`. `\fdef` appears to be faster than `\oodef` in almost + all cases (with less than thousand digits in the result), and even faster + than `\edef` for expanding the package macros when the result has a few + dozens of digits. `\oodef` needs that expansion ends up in thousands of + digits to become competitive with the other two. + + * some across the board slight efficiency improvement as a result of + modifications of various types to *fork macros* and *branching + conditionals* which are used internally. + + * bug fix (**xint**): `\xintAND` and `\xintOR` inserted a space token + in some cases and did not expand as promised in two steps `:-((` + (bug dating back to `1.09a` I think; this bug was without + consequences when using `&` and `|` in `\xintexpr-essions`, it + affected only the macro form). + + * bug fix (**xintcfrac**): `\xintFtoCCv` still ended fractions with + the `[0]`'s which were supposed to have been removed since release + `1.09b`. + + * *deprecated*: `\xintifTrueFalse`, `\xintifTrue`; use `\xintifTrueAelseB`. + + +`1.09h (2013/11/28)` +---- + + * parts of the documentation have been re-written or re-organized, + particularly the discussion of expansion issues and of input and + output formats. + + * the expansion types of macro arguments are documented in the margin + of the macro descriptions, with conventions mainly taken over + from those in the `LaTeX3` documentation. + + * a dependency of **xinttools** on **xint** (inside `\xintSeq`) has + been removed. + + * (**xintgcd**) `\xintTypesetEuclideAlgorithm` and + `\xintTypesetBezoutAlgorithm` have been slightly modified + (regarding indentation). + + * (**xint**) macros `xintiSum` and `xintiPrd` are renamed to + `\xintiiSum` and `\xintiiPrd`. + + * (**xinttools**) a count register used in `1.09g` in the `\xintFor` + loops for parsing purposes has been removed and replaced by use of + a `\numexpr`. + + * the few uses of `\loop` have been replaced by `\xintloop/\xintiloop`. + + * all macros of **xinttools** for which it makes sense are now declared + `\long`. + + +`1.09g (2013/11/22)` +---- + + * a package **xinttools** is detached from **xint**, to make tools such + as `\xintFor`, `\xintApplyUnbraced`, and `\xintiloop` available + without the **xint** overhead. + + * expandable nestable loops `\xintloop` and `\xintiloop`. + + * bugfix: `\xintFor` and `\xintFor*` do not modify anymore the value of + `\count 255`. + + +`1.09f (2013/11/04)` +---- + + * (**xint**) `\xintZapFirstSpaces`, `\xintZapLastSpaces`, + `\xintZapSpaces`, `\xintZapSpacesB`, for expandably stripping away + leading and/or ending spaces. + + * `\xintCSVtoList` by default uses `\xintZapSpacesB` to strip away + spaces around commas (or at the start and end of the comma + separated list). + + * also the `\xintFor` loop will strip out all spaces around commas and + at the start and the end of its list argument; and similarly for + `\xintForpair`, `\xintForthree`, `\xintForfour`. + + * `\xintFor` *et al.* accept all macro parameters from `#1` to + `#9`. + + * for reasons of inner coherence some macros previously with one extra + `i` in their names (e.g. `\xintiMON`) now have a doubled + `ii` (`\xintiiMON`) to indicate that they skip the overhead of + parsing their inputs via `\xintNum`. Macros with a *single* + `i` such as `\xintiAdd` are those which maintain the + non-**xintfrac** output format for big integers, but do parse + their inputs via `\xintNum` (since release `1.09a`). They too may + have doubled-`i` variants for matters of programming optimization + when working only with (big) integers and not fractions or + decimal numbers. + + +`1.09e (2013/10/29)` +---- + + * (**xint**) `\xintintegers`, `\xintdimensions`, `\xintrationals` + for infinite `\xintFor` loops, interrupted with `\xintBreakFor` and + `\xintBreakForAndDo`. + + * `\xintifForFirst`, `\xintifForLast` for the `\xintFor` and + `\xintFor*` loops, + + * the `\xintFor` and `xintFor*` loops are now `\long`, the + replacement text and the items may contain explicit `\par`'s. + + * conditionals `\xintifCmp`, `\xintifInt`, `\xintifOdd`. + + * bug fix (**xint**): the `\xintFor` loop (not `\xintFor*`) did + not correctly detect an empty list. + + * bug fix (**xint**): `\xintiSqrt {0}` crashed. `:-((` + + * the documentation has been enriched with various additional examples, + such as the *the quick sort algorithm + illustrated* or the various ways of *computing prime numbers*. + + * the documentation explains with more details various expansion + related issues, particularly in relation to conditionals. + + +`1.09d (2013/10/22)` +---- + + * bug fix (**xint**): `\xintFor*` is modified to gracefully + handle a space token (or more than one) located at the very end of + its list argument (as the space before `\do` in `\xintFor* #1 in + {{a}{b}{c}<space>} \do {stuff}`; spaces at other locations were + already harmless). Furthermore this new version _f-expands_ the + un-braced list items. After `\def\x{{1}{2}}` and `\def\y{{a}\x + {b}{c}\x }`, `\y` will appear to `\xintFor*` exactly as if it had + been defined as `\def\y{{a}{1}{2}{b}{c}{1}{2}}`. + + * same bug fix for `\xintApplyInline`. + + +`1.09c (2013/10/09)` +---- + + * (**xintexpr**) added `bool` and `togl` to the `\xintexpr` syntax; + also added `\xintboolexpr` and `\xintifboolexpr`. + + * added `\xintNewNumExpr`. + + * the factorial `!` and branching `?`, `:`, operators (in + `\xintexpr...\relax`) have now less precedence than a function + name located just before, + + * (**xint**) `\xintFor` is a new type of loop, whose replacement text + inserts the comma separated values or list items via macro + parameters, rather than encapsulated in macros; the loops are + nestable up to four levels (nine levels since `1.09f`) and their + replacement texts are allowed to close groups as happens with the + tabulation in alignments, + + * `\xintForpair`, `\xintForthree`, `\xintForfour` are experimental + variants of `\xintFor`, + + * `\xintApplyInline` has been enhanced in order to be usable for + generating rows (partially or completely) in an alignment, + + * command `\xintSeq` to generate (expandably) arithmetic sequences + of (short) integers, + + * again various improvements and changes in the documentation. + + +`1.09b (2013/10/03)` +---- + + * various improvements in the documentation, + + * more economical catcode management and re-loading handling, + + * removal of all those `[0]`'s previously forcefully added at the end + of fractions by various macros of **xintcfrac**, + + * `\xintNthElt` with a negative index returns from the tail of the + list, + + * macro `\xintPRaw` to have something like what `\xintFrac` does in + math mode; i.e. a `\xintRaw` which does not print the denominator + if it is one. + + +`1.09a (2013/09/24)` +---- + + * (**xintexpr**) `\xintexpr..\relax` and `\xintfloatexpr..\relax` + admit functions in their syntax, with comma separated values as + arguments, among them `reduce, sqr, sqrt, abs, sgn, floor, ceil, + quo, rem, round, trunc, float, gcd, lcm, max, min, sum, prd, add, + mul, not, all, any, xor`. + + * comparison (`<`, `>`, `=`) and logical (`|`, `&`) operators. + + * the command `\xintthe` which converts `\xintexpr`essions into + printable format (like `\the` with `\numexpr`) is more efficient, + for example one can do `\xintthe\x` if `\x` was defined to be an + `\xintexpr..\relax`: + + \def\x{\xintexpr 3^57\relax} + \def\y{\xintexpr \x^(-2)\relax} + \def\z{\xintexpr \y-3^-114\relax} + \xintthe\z + + * `\xintnumexpr .. \relax` (now renamed `\xintiexpr`) is `\xintexpr + round( .. ) \relax`. + + * `\xintNewExpr` now works with the standard macro parameter character + `#`. + + * both regular `\xintexpr`-essions and commands defined by + `\xintNewExpr` will work with comma separated lists of + expressions, + + * commands `\xintFloor`, `\xintCeil`, `\xintMaxof`, `\xintMinof` + (package **xintfrac**), `\xintGCDof`, `\xintLCM`, `\xintLCMof` + (package **xintgcd**), `\xintifLt`, `\xintifGt`, `\xintifSgn`, + `\xintANDof`, ... + + * The arithmetic macros from package **xint** now filter their operands + via `\xintNum` which means that they may use directly count + registers and `\numexpr`-essions without having to prefix them by + `\the`. This is thus similar to the situation holding previously + already when **xintfrac** was loaded. + + * a bug (**xintfrac**) introduced in `1.08b` made `\xintCmp` crash + when one of its arguments was zero. `:-((` + + +`1.08b (2013/06/14)` +---- + + * (**xintexpr**) Correction of a problem with spaces inside + `\xintexpr`-essions. + + * (**xintfrac**) Additional improvements to the handling of floating + point numbers. + + * section *Use of count registers* documenting how count + registers may be directly used in arguments to the macros of + **xintfrac**. + + +`1.08a (2013/06/11)` +---- + + * (**xintfrac**) Improved efficiency of the basic conversion from + exact fractions to floating point numbers, with ensuing speed gains + especially for the power function macros `\xintFloatPow` and + `\xintFloatPower`, + + * Better management by `\xintCmp`, `\xintMax`, `\xintMin` and + `\xintGeq` of inputs having big powers of ten in them. + + * Macros for floating point numbers added to the **xintseries** + package. + + +`1.08 (2013/06/07)` +---- + + * (**xint** and **xintfrac**) Macros for extraction of square roots, + for floating point numbers (`\xintFloatSqrt`), and integers + (`\xintiSqrt`). + + * new package **xintbinhex** providing *conversion routines* to and from + binary and hexadecimal bases. + + +`1.07 (2013/05/25)` +---- + + * The **xintexpr** package is a new core constituent (which loads + automatically **xintfrac** and **xint**) and implements the + expandable expanding parser + + \xintexpr . . . \relax, + + and its variant + + \xintfloatexpr . . . \relax + + allowing on input formulas using the infix operators `+`, `-`, `*`, + `/`, and `^`, and arbitrary levels of parenthesizing. Within a + float expression the operations are executed according to the + current value set by `\xintDigits`. Within an `\xintexpr`-ession the + binary operators are computed exactly. + + To write the `\xintexpr` parser I benefited from the commented + source of the `l3fp` parser; the `\xintexpr` parser has its own + features and peculiarities. *See its documentation*. + + * The floating point precision `D` is set (this is a local assignment + to a `\mathchar` variable) with `\xintDigits := D;` and queried + with `\xinttheDigits`. It may be set to anything up to + `32767`.[^1] The macro incarnations of the binary operations + admit an optional argument which will replace pointwise `D`; this + argument may exceed the `32767` bound. + + * The **xintfrac** macros now accept numbers written in scientific + notation, the `\xintFloat` command serves to output its argument + with a given number `D` of significant figures. The value of `D` + is either given as optional argument to `\xintFloat` or set with + `\xintDigits := D;`. The default value is `16`. + +[^1]: but values higher than 100 or 200 will presumably give too slow +evaluations. + + +`1.06b (2013/05/14)` +---- + + * Minor code and documentation improvements. Everywhere in the source + code, a more modern underscore has replaced the @ sign. + + +`1.06 (2013/05/07)` +---- + + * Some code improvements, particularly for macros of **xint** doing loops. + + * New utilities in **xint** for expandable manipulations of lists: + + \xintNthElt, \xintCSVtoList, \xintRevWithBraces + + * The macros did only a double expansion of their arguments. They now + fully expand them (using ``\romannumeral-`0``). Furthermore, in the + case of arguments constrained to obey the TeX bounds they will be + inserted inside a `\numexpr..\relax`, hence completely expanded, one + may use count registers, even infix arithmetic operations, etc... + + +`1.05 (2013/05/01)` +---- + +Minor changes and additions to **xintfrac** and **xintcfrac**. + + +`1.04 (2013/04/25)` +---- + + * New component **xintcfrac** devoted to continued fractions. + + * **xint**: faster division. + + * **xint**: added expandable macros `\xintListWithSep` and `\xintApply` to + handle token lists. + + * **xintfrac**: added `\xintRound`. + + * **xintseries** has a new implementation of `\xintPowerSeries` based + on a Horner scheme, and new macro `\xintRationalSeries`. Both to + help deal with the *denominator buildup* plague. + + * `tex xint.dtx` extracts style files (no need for a `xint.ins`). + + * Bug fix (**xintfrac**): `\xintIrr {0}` crashed. + + +`1.03 (2013/04/14)` +---- + + * New modules **xintfrac** (expandable operations on fractions) and + **xintseries** (expandable partial sums with xint package). + + * Slightly improved division and faster multiplication (the best + ordering of the arguments is chosen automatically). + + * Added illustration of Machin algorithm to the documentation. + + +`1.0 (2013/03/28)` +---- + +Initial announcement: + +> The **xint** package implements with expandable TeX macros the basic + arithmetic operations of addition, subtraction, multiplication + and division, as applied to arbitrarily long numbers represented + as chains of digits with an optional minus sign. + +> The **xintgcd** package provides implementations of the Euclidean + algorithm and of its typesetting. + +> The packages may be used with Plain and with LaTeX. + +%</changes>------------------------------------------------------ +%<*makefile>------------------------------------------------------ +# This file: Makefile.mk (generated from xint.dtx) +# Rename the file as Makefile, or keep is named as Makefile.mk +# and download master Makefile from +# http://mirror.ctan.org/macros/generic/xint +# then run "make help" + +# Starting with xint 1.3c, uses Latexmk for easier compilation of +# sourcexint.pdf as it includes indices. These indices for +# source code were actually removed at 1.3e but usage of Latexmk +# is maintained for the build (despite it being simpler now). + +# Originally tested on Mac OS X Mavericks with GNU Make 3.81, +# TeXLive 2014 and Pandoc 1.13.1. + +# Note to myself: I wanted to use .RECIPEPREFIX = > but it is +# supported only with GNU Make 3.82 and later. + +# this crazyness is to circumvent a problem with docstrip generation +# of the Makefile; we do not want two empty lines becoming only one +nullstring := +define newline +$(nullstring) + +endef +# will speed-up a little, I think. +newline := $(newline) + +define helptext +==== INSTRUCTIONS + +The Makefile is to automatize the extraction and compilation from +xint.dtx of package files and documentation files, and for producing +xint.tds.zip. It is for GNU/Linux like systems, with a teTeX like +installation such as TeXLive. Tested on Mac OS X Mavericks with TL2014. + +For compiling the PDF files, packages newtx, newtxtt, etoc,... are used +and should be up-to-date (as of 2014/10). Conversion to plain, html and +pdf format of README.md and CHANGES.md (make PanPDF, make PanHTML) +require Pandoc software. (tested with Pandoc 1.13.1). + +It is recommended to work with xint.dtx and Makefile in an otherwise +initially empty temporary repertory. + +make help + prints this help (using more). It will also have already extracted + all files from xint.dtx. + +make helpless + prints this help (using less). + +make xint.pdf + extracts files and produces xint.pdf, using latex and dvipdfmx. + Uses Latexmk. No Pandoc needed. To get xint.pdf to include + the source code and indices, refer to instructions in xint.tex. + +make sourcexint.pdf + extracts files and produces sourcexint.pdf, using latex, makeindex + and dvipdfmx. Uses Latexmk. No Pandoc needed. + +make PanPDF + produces README.pdf and CHANGES.pdf, requires Pandoc. + +make PanHTML + produces README.html and CHANGES.html, requires Pandoc. + +make doc + produces all documentation. + +make all + produces all documentation, and creates xint.tds.zip. + +make xint.tds.zip + same as "make all" + +make clean + removes auxiliary files and repertories. + +make cleanall + removes all files, leaving only xint.dtx (and Makefile). If no + Makefile, use "etex xint.dtx" to regenerate Makefile.mk, rename + it as Makefile and run "make help". + +==== INSTALLING + +The following has been tested on a TeXLive installation: + +make installhome + creates xint.tds.zip, and unzips it in <TEXMFHOME> + (it assumes there is no ls-R file there) + +make installlocal + creates xint.tds.zip, and unzips it in <TEXMFLOCAL> + (and then does texhash <TEXMFLOCAL>) + IT MIGHT BE NEEDED TO RUN IT AS "sudo make installlocal" + This depends on how the access rights are configured. + In case of doubt run first "make doc" and then "make + installlocal". If the latter fails, "sudo make installlocal". + +make uninstallhome + removes all xint files and repertories from <TEXMFHOME> + +make uninstalllocal + removes all xint files and repertories from <TEXMFLOCAL> + (and then does texhash <TEXMFLOCAL>) + IT MIGHT BE NEEDED TO RUN IT AS "sudo make uninstalllocal" + +endef + +.PHONY: help helpless all extract doc PanPDF PanHTML clean cleanall\ + installhome uninstallhome installlocal uninstalllocal + +# for printf with subst and \n, got it from +# http://stackoverflow.com/a/5887751 + +# I could do the trick with := here, for \n substitution, but this would add +# tiny overhead to all other operations of make + +help: + @printf '$(subst $(newline),\n,$(helptext))' | more + +helpless: + @printf '$(subst $(newline),\n,$(helptext))' | less + +# RM = rm -f +JF_tmpdir := $(shell mktemp -d TEMP_XINT_XXX) +TEXMF_local = $(shell kpsewhich -var-value TEXMFLOCAL) +TEXMF_home = $(shell kpsewhich -var-value TEXMFHOME) +packages = xintkernel.sty xintcore.sty xint.sty xintfrac.sty xintexpr.sty\ + xintgcd.sty xintbinhex.sty xintseries.sty xintcfrac.sty\ + xinttools.sty xinttrig.sty xintlog.sty +# Makefile.mk is not included in $(extracted). Its extraction rule is in +# master Makefile file. We can not extract Makefile from xint.dtx via +# docstrip, as .tex is always appended if a filename with no extension is +# specified. If "make -f Makefile.mk" is run, Makefile.mk will not be +# overwritten because tex xint.dtx does not extract it (etex xint.dtx does). +extracted = $(packages) xint.tex xint.ins README.md CHANGES.md\ + doHTMLs.sh doPDFs.sh pandoctpl.latex +doc_pdf = README.pdf CHANGES.pdf +doc_html = README.html CHANGES.html +filesfortex = $(packages) +filesforsource = xint.dtx Makefile +filesfordoc = xint.pdf sourcexint.pdf README $(doc_pdf) $(doc_html) +auxiliaryfiles = xint.dvi xint.aux xint.toc xint.log\ + sourcexint.dvi sourcexint.aux sourcexint.toc sourcexint.log\ + README.dvi README.aux README.toc README.out README.log\ + CHANGES.dvi CHANGES.aux CHANGES.toc CHANGES.out CHANGES.log +xint_cmd = latexmk xint +sourcexint_cmd = latexmk -jobname=sourcexint\ + -latex='latex %O "\chardef\dosourcexint=1 \input{%S}"' xint.tex + +all: $(extracted) doc xint.tds.zip + @echo 'make all done.' + +extract: $(extracted) + +$(extracted): xint.dtx + tex xint.dtx + +doc: xint.pdf sourcexint.pdf README PanPDF PanHTML + @echo 'make doc done.' + +xint.pdf: xint.dtx xint.tex + $(xint_cmd) + dvipdfmx xint.dvi + +sourcexint.pdf: xint.dtx xint.tex + $(sourcexint_cmd) + dvipdfmx sourcexint.dvi + +README: README.md + pandoc -t plain -o README README.md + +PanPDF: $(doc_pdf) + +$(doc_pdf): doPDFs.sh + chmod u+x doPDFs.sh && ./doPDFs.sh + +PanHTML: $(doc_html) + +$(doc_html): doHTMLs.sh + chmod u+x doHTMLs.sh && ./doHTMLs.sh + +xint.tds.zip: $(filesfordoc) $(filesforsource) $(filesfortex) + rm -fr $(JF_tmpdir) + mkdir -p $(JF_tmpdir)/doc/generic/xint + mkdir -p $(JF_tmpdir)/source/generic/xint + mkdir -p $(JF_tmpdir)/tex/generic/xint + chmod -R ugo+rwx $(JF_tmpdir) + cp -a $(filesfordoc) $(JF_tmpdir)/doc/generic/xint + cp -a $(filesforsource) $(JF_tmpdir)/source/generic/xint + cp -a $(filesfortex) $(JF_tmpdir)/tex/generic/xint + cd $(JF_tmpdir); chmod -R ugo+r doc source tex + umask 0022 && cd $(JF_tmpdir) &&\ + zip -r xint.tds.zip doc source tex &&\ + mv -f xint.tds.zip ../ + rm -fr $(JF_tmpdir) + @echo 'make xint.tds.zip done.' + +xint.zip: $(filesfordoc) $(filesforsource) $(filesfortex) xint.tds.zip + mkdir -p $(JF_tmpdir)/xint + chmod ugo+rwx $(JF_tmpdir)/xint + cp -a $(filesfordoc) $(JF_tmpdir)/xint + cp -a $(filesforsource) $(JF_tmpdir)/xint + chmod -R ugo+r $(JF_tmpdir)/xint + mv xint.tds.zip $(JF_tmpdir)/ + umask 0022 && cd $(JF_tmpdir) && zip -r xint.zip xint.tds.zip xint + mv $(JF_tmpdir)/xint.tds.zip ./ + mv -f $(JF_tmpdir)/xint.zip ./ + rm -fr $(JF_tmpdir) + @echo 'make xint.zip done.' + +installhome: xint.tds.zip + unzip xint.tds.zip -d $(TEXMF_home) + +uninstallhome: + cd $(TEXMF_home) && rm -fr doc/generic/xint \ + source/generic/xint \ + tex/generic/xint + +# cf http://stackoverflow.com/a/1909390 +# as kpsewhich is very slow (.5s) I want to evaluate once only. +installlocal: xint.tds.zip + $(eval $@_tmp := $(TEXMF_local)) + unzip xint.tds.zip -d $($@_tmp) && texhash $($@_tmp) + +uninstalllocal: + cd $(TEXMF_local) && rm -fr doc/generic/xint \ + source/generic/xint \ + tex/generic/xint && texhash . +clean: + rm -fr auto/ TEMP*/ + rm -f $(auxiliaryfiles)\ + sourcexint.fls sourcexint.fdb_latexmk\ + xint.fls xint.fdb_latexmk + +cleanall: clean + rm -f $(extracted) $(doc_pdf) $(doc_html)\ + README README.tex CHANGES.tex\ + xint.pdf sourcexint.pdf xint.tds.zip xint.zip Makefile.mk +%</makefile>$----------------------------------------------------- +%<*pandoctpl>----------------------------------------------------- +\newcommand{\tightlist}{% + \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}} +$if(dvipdfmx)$ +{\csname @for\endcsname\x:=hyperref,graphicx,color,xcolor\do + {\PassOptionsToPackage{dvipdfmx}\x}} + \PassOptionsToPackage{dvipdfmx-outline-open}{hyperref} + \PassOptionsToPackage{dvipdfm}{geometry} +$endif$ +\documentclass[$papersize$,fontsize=$fontsize$]{scrartcl} +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage[english]{babel} + +\usepackage{newtxtext} +\usepackage{newtxtt} +\usepackage{newtxmath} + +\usepackage{upquote} + +% pour les \texttt venant de la conversion par pandoc des `...`: +\begingroup\makeatletter + \catcode`\'\active + \catcode`\*\active + \catcode`\`\active +\@firstofone {\endgroup + \def\dostraightquotesandstar{% textcomp package is loaded by newtxtext + \let`\textasciigrave + \let'\textquotesingle + \edef*{\noexpand\raisebox{-.25\noexpand\height}{\string*}}% + \catcode39\active % ' + \catcode96\active % ` + \catcode42\active }% * +}% for \texttt, let's just forget about math and italic correction things +\DeclareRobustCommand\texttt {\bgroup + \dostraightquotesandstar\afterassignment\ttfamily\let\next=} + +$if(geometry)$ +\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry} +$endif$ +$if(tables)$ +\usepackage{longtable,booktabs} +$endif$ +\usepackage[unicode=true,bookmarks]{hyperref} +\hypersetup{breaklinks=true,% + pdfauthor={Jean-Fran\c cois Burnol},% + pdftitle={$title$ $author$ $date$},% + colorlinks=true,% + citecolor=$if(citecolor)$$citecolor$$else$blue$endif$,% + urlcolor=$if(urlcolor)$$urlcolor$$else$blue$endif$,% + linkcolor=$if(linkcolor)$$linkcolor$$else$magenta$endif$,% + pdfborder={0 0 0},% + pdfstartview=FitH,% + pdfpagemode=UseOutlines} +%%\urlstyle{same} % don't use monospace font for urls + +\setlength{\parindent}{0pt} +\setlength{\emergencystretch}{3em} % prevent overfull lines +\usepackage{enumitem} +%% reduce LaTeX's insane vertical spacing around verbatim blocks +\setlength{\parskip}{\medskipamount} +\setlist[trivlist]{topsep=0pt,partopsep=0pt,itemsep=0pt,parsep=0pt} + +$if(numbersections)$ +\setcounter{secnumdepth}{5} +$else$ +\setcounter{secnumdepth}{0} +$endif$ + +$if(etoc)$\usepackage{etoc}$endif$ + +\title{$title$} +\author{$author$} +\date{$date$} + +$for(header-includes)$ +$header-includes$ +$endfor$ + +\begin{document} +$if(title)$ +\maketitle +$endif$ + +$for(include-before)$ +$include-before$ + +$endfor$ + +$if(toc)$ +\setcounter{tocdepth}{$toc-depth$} +$if(etoc)$ +\etocdefaultlines +\etocmulticolstyle[$etoc$]{} +$endif$ +\tableofcontents +$endif$ + +$body$ + +$for(include-after)$ +$include-after$ + +$endfor$ +\end{document} +%</pandoctpl>----------------------------------------------------- +%<*dohtmlsh>------------------------------------------------------ +#! /bin/sh +# produces README.html and CHANGES.html from README.md and CHANGES.md +# tested with pandoc 1.13.1 + +pandoc -o README.html -s --toc -V highlighting-css=' body{margin-left : 10%; margin-right : 15%; margin-top: 4ex; font-size: 12pt;} + pre {white-space: pre-wrap; } + code {white-space: pre-wrap; } + .mono {font-family: monospace;}' README.md + +pandoc -o CHANGES.html -s --toc -V highlighting-css=' body{margin-left : 10%; margin-right : 15%; margin-top: 4ex; font-size: 12pt;} + pre {white-space: pre-wrap;} + code {white-space: pre-wrap;} + #TOC {float: right; position: relative; top: 100px; margin-bottom: 100px;}' CHANGES.md + +%</dohtmlsh>------------------------------------------------------ +%<*dopdfsh>------------------------------------------------------- +#! /bin/sh +# produces README.pdf and CHANGES.pdf from README.md and CHANGES.md +# via latex+dvipdfmx and custom pandoc latex template + +pandoc -o README.tex --template=pandoctpl --toc -V papersize=a4paper -V fontsize=11pt -V dvipdfmx --variable=geometry:footskip=1cm,left=2.5cm,right=2.5cm,top=2cm,bottom=3cm -V etoc=1 README.md +rm -f README.aux README.toc README.out +latex -interaction=nonstopmode README +latex -interaction=nonstopmode README +latex -interaction=nonstopmode README +dvipdfmx README.dvi + +pandoc -o CHANGES.tex --template=pandoctpl --toc -V 'toc-depth'=2 -V papersize=a4paper -V fontsize=11pt -V dvipdfmx --variable=geometry:footskip=1cm,left=2.5cm,right=2.5cm,top=2cm,bottom=3cm -V etoc=2 CHANGES.md +rm -f CHANGES.aux CHANGES.toc CHANGES.out +latex -interaction=nonstopmode CHANGES +latex -interaction=nonstopmode CHANGES +latex -interaction=nonstopmode CHANGES +dvipdfmx CHANGES.dvi +%</dopdfsh>------------------------------------------------------- +%<*drv>----------------------------------------------------------- +%% +%% To produce manually xint.pdf from xint.tex: +%% - latex (thrice) then dvipdfmx, +%% - or xelatex/pdflatex thrice. +%% +%% To produce manually sourcexint.pdf from xint.tex: +%% latexmk -jobname=sourcexint\ +%% -latex="latex %O \\\\chardef\\\\dosourcexint=1 \\\\input{%S}"\ +%% xint.tex +%% (quoting may differ, depending on the shell) +%% dvipdfmx sourcexint.dvi +%% +%% It is naturally possible to replace latexmk by suitable latex +%% and makeindex calls, but details are left out here. +%% +%% To get xint.pdf to include the source code and indices: +%% - etex xint.dtx (this will regenerate this file), +%% - replace 1 by 0 in \chardef line below, +%% - make clean +%% - make xint.pdf +%% This will use latexmk. Without it execute latex thrice then dvipdfmx. +\NeedsTeXFormat{LaTeX2e} +\ProvidesFile{xint.tex}% +[\xintbndldate\space v\xintbndlversion\space driver file for xint documentation (JFB)]% +\PassOptionsToClass{a4paper,fontsize=10pt}{scrdoc} +\chardef\NoSourceCode 1 % set it to 0 if source code inclusion desired +\input xint.dtx +%%% Local Variables: +%%% mode: latex +%%% TeX-PDF-from-DVI: "Dvipdfmx" +%%% End: +%</drv>----------------------------------------------------------- +%<*ins>----------------------------------------------------------- +%% +%% `tex xint.ins' extracts all package files from xint.dtx, as well as +%% xint.tex, README.md, CHANGES.md, doPDFs.sh, doHTMLs.sh, .latexmkrc +%% and xint-gind.ist +%% +%% `etex xint.ins' additionally extracts Makefile.mk, which is needed +%% for building documentation using `make'. +%% +\input docstrip.tex +\askforoverwritefalse +\generate{\nopreamble\nopostamble +\file{README.md}{\from{xint.dtx}{readme}} +\file{CHANGES.md}{\from{xint.dtx}{changes}} +\file{doHTMLs.sh}{\from{xint.dtx}{dohtmlsh}} +\file{doPDFs.sh}{\from{xint.dtx}{dopdfsh}} +\ifx\numexpr\undefined\else\catcode9 11 + \file{Makefile.mk}{\from{xint.dtx}{makefile}}\fi +\usepreamble\defaultpreamble +\usepostamble\defaultpostamble +\file{pandoctpl.latex}{\from{xint.dtx}{pandoctpl}} +\file{xint.tex}{\from{xint.dtx}{drv}} +\file{xintkernel.sty}{\from{xint.dtx}{xintkernel}} +\file{xinttools.sty}{\from{xint.dtx}{xinttools}} +\file{xintcore.sty}{\from{xint.dtx}{xintcore}} +\file{xint.sty}{\from{xint.dtx}{xint}} +\file{xintbinhex.sty}{\from{xint.dtx}{xintbinhex}} +\file{xintgcd.sty}{\from{xint.dtx}{xintgcd}} +\file{xintfrac.sty}{\from{xint.dtx}{xintfrac}} +\file{xintseries.sty}{\from{xint.dtx}{xintseries}} +\file{xintcfrac.sty}{\from{xint.dtx}{xintcfrac}} +\file{xintexpr.sty}{\from{xint.dtx}{xintexpr}} +\file{xinttrig.sty}{\from{xint.dtx}{xinttrig}} +\file{xintlog.sty}{\from{xint.dtx}{xintlog}}} +\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{* xintkernel.sty} +\Msg{* xintcore.sty} +\Msg{* xint.sty} +\Msg{* xintbinhex.sty} +\Msg{* xintgcd.sty} +\Msg{* xintfrac.sty} +\Msg{* xintseries.sty} +\Msg{* xintcfrac.sty} +\Msg{* xintexpr.sty} +\Msg{* xinttrig.sty} +\Msg{* xintlog.sty} +\Msg{* xinttools.sty} +\Msg{*} +\Msg{* To produce the user manual run latex thrice on xint.tex} +\Msg{* then dvipdfmx on xint.dvi, or if your system allows,} +\Msg{* execute `make xint.pdf' (this requires Latexmk).} +\Msg{*} +\Msg{* The commented source code is generated from executing} +\Msg{* `make sourcexint.pdf' (this requires Latexmk; if not} +\Msg{* available check the details in Makefile.mk and .latexmkrc)} +\Msg{*} +\Msg{* Happy TeXing!} +\Msg{*} +\Msg{********************************************************************} +\endbatchfile +%</ins>----------------------------------------------------------- +%<*dtx>----------------------------------------------------------- +^^Bfi^^Begroup +\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, xetex, ... on xint.dtx + \else + \ifx\NoSourceCode\undefined + % latex/pdflatex/xelatex on xint.dtx, we will extract all files + \chardef\extractfiles 1 % 1 = extract and typeset, 2 = only typeset + \chardef\NoSourceCode 0 % 0 = include source code, 1 = do not + \NeedsTeXFormat{LaTeX2e}% + \PassOptionsToClass{a4paper,fontsize=10pt}{scrdoc}% + \else + % latex/pdflatex/xelatex on xint.tex + \chardef\extractfiles 2 % no extractions, but typeset + % \NoSourceCode is set-up in xint.tex + \fi + \ProvidesFile{xint.dtx}[bundle source (\xintbndlversion, \xintbndldate) % + and documentation (\xintdocdate)]% + \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 xintkernel.sty^^J}% +\Msg{* \space\space\space\space xintcore.sty^^J}% +\Msg{* \space\space\space\space xint.sty^^J}% +\Msg{* \space\space\space\space xintbinhex.sty^^J}% +\Msg{* \space\space\space\space xintgcd.sty^^J}% +\Msg{* \space\space\space\space xintfrac.sty^^J}% +\Msg{* \space\space\space\space xintseries.sty^^J}% +\Msg{* \space\space\space\space xintcfrac.sty^^J}% +\Msg{* \space\space\space\space xintexpr.sty^^J}% +\Msg{* \space\space\space\space xinttools.sty^^J}% +\Msg{* \space\space\space\space xinttrig.sty^^J}% +\Msg{* \space\space\space\space xintlog.sty^^J}% +\Msg{*^^J}% +\Msg{* To produce the user manual run latex thrice on xint.tex^^J}% +\Msg{* then dvipdfmx on xint.dvi, or if your system allows,^^J}% +\Msg{* execute `make xint.pdf' (this requires Latexmk).^^J}% +\Msg{*^^J}% +\Msg{* The commented source code is generated from executing^^J}% +\Msg{* `make sourcexint.pdf' (this requires Latexmk; if not^^J}% +\Msg{* available check the details in Makefile.mk and .latexmkrc)^^J}% +\Msg{*^^J}% +\Msg{* Happy TeXing!^^J}% +\Msg{*^^J}% +\Msg{********************************************************************^^J}% +}% +\begingroup + \input docstrip.tex + \askforoverwritefalse + \catcode9 11 % do not kill TAB in producing Makefile.mk + \generate{\nopreamble\nopostamble + \file{README.md}{\from{xint.dtx}{readme}} + \file{CHANGES.md}{\from{xint.dtx}{changes}} + % pure tex will use ^^I notation for TAB character, don't want that. + % there is a problem with xelatex, as it generates ^^I also. + \ifnum\noetex=1 \else\ifx\XeTeXinterchartoks\undefined + \file{Makefile.mk}{\from{xint.dtx}{makefile}}\fi\fi + \file{doHTMLs.sh}{\from{xint.dtx}{dohtmlsh}} + \file{doPDFs.sh}{\from{xint.dtx}{dopdfsh}} + \usepreamble\defaultpreamble + \usepostamble\defaultpostamble + \file{pandoctpl.latex}{\from{xint.dtx}{pandoctpl}} + \file{xint.ins}{\from{xint.dtx}{ins}} + \file{xint.tex}{\from{xint.dtx}{drv}} + \file{xintkernel.sty}{\from{xint.dtx}{xintkernel}} + \file{xinttools.sty}{\from{xint.dtx}{xinttools}} + \file{xintcore.sty}{\from{xint.dtx}{xintcore}} + \file{xint.sty}{\from{xint.dtx}{xint}} + \file{xintbinhex.sty}{\from{xint.dtx}{xintbinhex}} + \file{xintgcd.sty}{\from{xint.dtx}{xintgcd}} + \file{xintfrac.sty}{\from{xint.dtx}{xintfrac}} + \file{xintseries.sty}{\from{xint.dtx}{xintseries}} + \file{xintcfrac.sty}{\from{xint.dtx}{xintcfrac}} + \file{xintexpr.sty}{\from{xint.dtx}{xintexpr}} + \file{xinttrig.sty}{\from{xint.dtx}{xinttrig}} + \file{xintlog.sty}{\from{xint.dtx}{xintlog}}} +\endgroup +\fi % end of file extraction (from etex/latex/pdflatex/... run on xint.dtx) +\ifnum\extractfiles=0 % no LaTeX, files now extracted. Stop. + \MessageDeFin\expandafter\end +\fi +% From this point on, run is necessarily with e-TeX. +% Check if \MessageDeFin got defined, if yes put it at end of run. +\ifdefined\MessageDeFin\AtEndDocument{\MessageDeFin}\fi +%----------------------------------------------------------------- +% -*- coding: utf-8; mode: latex, fill-column: 78; -*- +% +\ifdefined\dosourcexint % this toggle is set from make sourcexint.pdf rule + \chardef\NoSourceCode 0 +\else + \chardef\dosourcexint 0 +\fi + +% default is to assume latex + dvipdfmx +\chardef\Withdvipdfmx 1 + +\RequirePackage{ifpdf} +\RequirePackage{ifxetex} + +\ifpdf \chardef\Withdvipdfmx 0 \fi +\ifxetex\chardef\Withdvipdfmx 0 \fi + +\ifnum\Withdvipdfmx=1 +\def\pgfsysdriver{pgfsys-dvipdfm.def} +\documentclass [dvipdfm, dvipdfmx, dvipdfmx-outline-open]{scrdoc} +\else +\documentclass {scrdoc} +\fi +% Revert change to \smash and other macros at LaTeX 2018/12/01 +% https://github.com/latex3/latex2e/issues/108 +\makeatletter +\let\leavevmode@ifvmode\empty % for \smash in \NewWith etc... +\makeatother + +% Remove from sectioning commands insertion of marks, because we +% will do it ourself. +\usepackage{etoolbox} +\makeatletter +\patchcmd{\@sect}% + {\expandafter\csname#1mark\expandafter\endcsname\expandafter{\@currentheadentry}}% + {}{}{} +\patchcmd{\@sect}% + {\expandafter\csname#1mark\expandafter\endcsname\expandafter{\@currentheadentry}}% + {}{}{} +\makeatother + +\PassOptionsToPackage{bookmarks=true}{hyperref} + +\ifnum\NoSourceCode=1 + \OnlyDescription +\fi + + +% counts used in particular in the samples from the documentation of the +% xintseries.sty package +\newcount\cnta +\newcount\cntb +\newcount\cntc + +\pagestyle{headings} + +\ifxetex +\else + \usepackage[T1]{fontenc} + \usepackage[utf8]{inputenc} + \DeclareUnicodeCharacter{03B4}{\ensuremath{\delta}}%δ + \DeclareUnicodeCharacter{03BE}{\ensuremath{\xi}}%ξ + \DeclareUnicodeCharacter{03C0}{\ensuremath{\pi}}%π +\fi + +\usepackage{multicol} +\usepackage{geometry} +\AtBeginDocument {\ttzfamily % package newtxtt loaded in preamble + \newgeometry{textwidth=\dimexpr92\fontcharwd\font`X\relax, + vscale=0.75}} + +\unless\ifnum\dosourcexint=1 +\usepackage{xintexpr} +\usepackage{xintbinhex} +\usepackage{xintgcd} +\usepackage{xintseries} +\usepackage{xintcfrac} +\usepackage{amsmath}% for \cfrac usage +\DeclareMathOperator{\sinc}{sinc} +\usepackage{pifont}% for \ding{73} (hollow star) +\fi + +\usepackage{xinttools} +\xintverbosetrue + +\usepackage{enumitem} +\usepackage{varioref} +\usepackage{xspace} +\usepackage[para]{footmisc} +\usepackage{picture} +\usepackage{graphicx} + +\usepackage[english]{babel} +\usepackage[autolanguage,np]{numprint} +\AtBeginDocument{\npthousandsep{,\hskip .5pt plus .1pt minus .1pt}} + +\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} +\usepackage{eso-pic}% après xcolor sinon Option clash for package xcolor. + +\ifnum\dosourcexint=1 +\else +% Dependency graph done using TikZ (manually) + \usepackage{tikz} + \usetikzlibrary{shapes,arrows.meta} +\fi + +\usepackage{framed} +% SNUGFRAMED +% ========== + +\makeatletter +\newenvironment{snugframed}{% + \fboxsep \dimexpr2\fontcharwd\font`X\relax + \advance\linewidth-2\fboxsep + \advance\csname @totalleftmargin\endcsname \fboxsep + \def\FrameCommand##1{\hskip\@totalleftmargin + \hskip-\fboxsep + \fbox{##1}\hskip-\fboxsep + % There is no \@totalrightmargin, so: + \hskip-\linewidth \hskip-\@totalleftmargin \hskip\columnwidth}% + \MakeFramed {\advance\hsize-\width \@totalleftmargin\z@ \linewidth\hsize + \@setminipage}% + }{\par\unskip\@minipagefalse\endMakeFramed} +\makeatother + +% HYPERREF +% ======== + +\usepackage[pdfencoding=unicode]{hyperref} + +\hypersetup{% +linktoc=all,% +breaklinks=true,% +colorlinks=true,% +urlcolor=niceone,% +linkcolor=blue,% +pdfauthor={Jean-Fran\c cois Burnol},% +pdftitle={The xint bundle},% +pdfsubject={Arithmetic with TeX},% +pdfkeywords={Expansion, arithmetic, TeX},% +pdfstartview=FitH,% +pdfpagemode=UseOutlines} + +\usepackage{hypcap} +\ifnum\dosourcexint=1 +\hypersetup{pdftitle={The xint bundle source code}} +\fi +\usepackage{bookmark} + +% FONTS +% ===== + +\usepackage[zerostyle=a,straightquotes,scaled=0.95]{newtxtt} +\usepackage{newtxmath} + +\makeatletter + + + +\DeclareFontFamily{T1}{newtxttb}{\hyphenchar\font\m@ne} + +\DeclareFontShape{T1}{newtxttb}{m}{n}{ + <-> s*[\newtxtt@scale]newtxttbq +}{} +\DeclareFontShape{T1}{newtxttb}{b}{n}{ + <-> s*[\newtxtt@scale]newtxbttbq +}{} +\DeclareFontShape{T1}{newtxttb}{bx}{n}{ + <-> ssub * newtxttb/b/n +}{} +\DeclareFontShape{T1}{newtxttb}{m}{sl}{ + <-> s*[\newtxtt@scale]newtxttslbq +}{} +\DeclareFontShape{T1}{newtxttb}{m}{it}{ + <-> ssub * newtxttb/m/sl +}{} + +% Ajouté le 9 mars 2016 + +\DeclareFontShape{T1}{newtxttb}{m}{sc}{%cap & small cap + <-> s*[\newtxtt@scale]newtxttscbq +}{} +\DeclareFontShape{T1}{newtxttb}{b}{sc}{%bold cap & small cap + <-> s*[\newtxtt@scale]newtxbttscbq +}{} +\DeclareFontShape{T1}{newtxttb}{b}{sl}{%bold slanted + <-> s*[\newtxtt@scale]newtxbttslbq +}{} +\DeclareFontShape{T1}{newtxttb}{b}{it}{%bold italic + <-> ssub * newtxttb/b/sl% +}{} +\DeclareFontShape{T1}{newtxttb}{bx}{sc}{%bold extended cap & small cap + <-> ssub * newtxttb/b/sc% +}{} +\DeclareFontShape{T1}{newtxttb}{bx}{sl}{%bold extended slanted + <-> ssub * newtxttb/b/sl% +}{} +\DeclareFontShape{T1}{newtxttb}{bx}{it}{%bold extended italic + <-> ssub * newtxttb/b/sl% +}{} + +% Ajouté le 9 mars 2016 +\DeclareEncodingSubset{TS1}{newtxttb}{0} +\DeclareFontFamily{TS1}{newtxttb}{\hyphenchar\font\m@ne} + +\DeclareFontShape{TS1}{newtxttb}{m}{n}{%medium + <-> s*[\newtxtt@scale]tcxtt% +}{} +\DeclareFontShape{TS1}{newtxttb}{m}{sc}{%cap & small cap + <->ssub * newtxttb/m/n% +}{} +\DeclareFontShape{TS1}{newtxttb}{m}{sl}{%slanted + <-> s*[\newtxtt@scale]tcxttsl% +}{} +\DeclareFontShape{TS1}{newtxttb}{m}{it}{%italic + <->ssub * newtxttb/m/sl% +}{} +\DeclareFontShape{TS1}{newtxttb}{b}{n}{%bold + <-> s*[\newtxtt@scale]tcxbtt% +}{} +\DeclareFontShape{TS1}{newtxttb}{b}{sc}{%bold cap & small cap + <->ssub * newtxttb/b/n% +}{} +\DeclareFontShape{TS1}{newtxttb}{b}{sl}{%bold slanted + <-> s*[\newtxtt@scale]tcxbttsl% +}{} +\DeclareFontShape{TS1}{newtxttb}{b}{it}{%bold italic + <->ssub * newtxttb/b/sl% +}{} +\DeclareFontShape{TS1}{newtxttb}{bx}{n}{%bold extended + <->ssub * newtxttb/b/n% +}{} +\DeclareFontShape{TS1}{newtxttb}{bx}{sc}{ %bold extended cap & small cap + <->ssub * newtxttb/b/sc% +}{} +\DeclareFontShape{TS1}{newtxttb}{bx}{sl}{%bold extended slanted + <->ssub * newtxttb/b/sl% +}{} +\DeclareFontShape{TS1}{newtxttb}{bx}{it}{%bold extended italic + <->ssub * newtxttb/b/it% +}{} + + +\makeatother + +% This is with a slashed 0 like the original txtt. +\newcommand\ttbfamily {\fontfamily{newtxttb}\selectfont } + +\ifnum\dosourcexint=1 +\else +\renewcommand\familydefault\ttdefault +\usepackage[noendash]{mathastext}% pas de endash dans newtxtt +\fi +\frenchspacing +% sans-serif in footnotes, TOC, titles, etc... +\renewcommand\familydefault\sfdefault + +% TABLES OF CONTENTS +% ================== + +\usepackage{tocloft} +\usepackage{etoc} + +\def\gobbletodot #1.{} + +\newif\ifinmanualmaintoc +\ifnum\dosourcexint=0 + \inmanualmaintoctrue +\fi +\def\sectioncouleur{{cyan}} + +\def\MARGEPAGENO {1.5em}% changera pour la partie implémentation + + +\def\SKIPSECTIONINTERSPACE{\vskip\bigskipamount} +\etocsetstyle{section}{} + {\normalfont} + {\etociffirst{}{\SKIPSECTIONINTERSPACE}% + \rightskip \MARGEPAGENO\relax + \parfillskip -\MARGEPAGENO\relax + \bfseries + \leftskip \leftmarginii + \noindent\llap % \llap + {\makebox[\leftmarginii][l]% et \leftmargini le 12/10/2014 + {\expandafter\textcolor\sectioncouleur {\etocnumber}}}% + \strut\etocname + \mdseries\nobreak\leaders\etoctoclineleaders\hfill\nobreak\strut + \makebox[\MARGEPAGENO][r]{\etocpage}\par + \let\ETOCsectionnumber\etocthenumber + }% + {}% + +\newdimen\margegauchetoc +\AtBeginDocument{\margegauchetoc \dimexpr 5\fontcharwd\font`X\relax} +\makeatletter +\etocsetstyle{subsection} + {\begingroup\normalfont + \setlength{\premulticols}{0pt}% + \setlength{\multicolsep}{0pt}% + \setlength{\columnsep}{\leftmarginii}% + \setlength{\columnseprule}{.4pt}% n'influence pas séparation colonnes + \parskip\z@skip + \raggedcolumns + \addvspace{\smallskipamount}% + \begin{multicols}{2} + \leftskip \margegauchetoc % 12 octobre 2014 + \ifinmanualmaintoc + \rightskip \MARGEPAGENO + \else + \rightskip \MARGEPAGENO plus 2em minus 1em + \fi + \parfillskip -\MARGEPAGENO\relax + } + {} + {\noindent + \etocifnumbered{\llap{\makebox[\margegauchetoc][l]{\ttzfamily\bfseries\etoclink + {\ifinmanualmaintoc\expandafter\textcolor\sectioncouleur + {\normalfont\bfseries\ETOCsectionnumber}\fi + .\expandafter\gobbletodot\etocthenumber}}}}{\kern-\margegauchetoc}% + \strut\etocname\nobreak + \unless\ifinmanualmaintoc\leaders\etoctoclineleaders\fi + \hfill\nobreak + \strut\makebox[\MARGEPAGENO][r]{\small\etocpage}\endgraf } + {\end{multicols}\endgroup + %\addvspace{\smallskipamount} + }% + +\etocsetstyle{subsubsection} + {\begingroup\normalfont\small + \leftskip \dimexpr\leftmargini+1em\relax } + {} + {\noindent + \llap{\makebox[\dimexpr\leftmargini+1em\relax][l]% + {\ttzfamily\bfseries\etoclink + {\HOOKLOCALTOC.\expandafter\gobbletodot\etocthenumber}}}% + \strut\etocname\nobreak + \leaders\etoctoclineleaders + \hfill\nobreak + \strut\makebox[\MARGEPAGENO][r]{\small\etocpage}\endgraf } + {\endgroup }% + +\let\HOOKLOCALTOC\empty% quick hack to get style I want in User defined functions +\etocsetlevel{table}{6} + +\makeatother + +\addtocontents{toc}{\protect\hypersetup{hidelinks}} + +% ===================== +% MISCELLANEOUS MARK-UP +% ===================== + + +\def\digitstt #1{\begingroup\color[named]{OrangeRed}#1\endgroup} +\let\dtt\digitstt + +% \ctexttt is a remnant of 1.09n manual, don't have time to get rid of it now. +\newcommand\ctexttt [1]{\begingroup\color[named]{DarkOrchid}%\bfseries + #1\endgroup} + +% \fexpan 22 octobre 2013 +\newcommand\fexpan {\hyperref[ssec:expansions]{\textit{f}-expan}} +% Septembre 2015 +% Address updated to github repo's one, May 2018 +\def\liiibigint + {\href{https://github.com/latex3/latex3/tree/master/l3trial/l3bigint}{l3bigint}} + +% \fixmeaning +\makeatletter +\def\fixmeaning {\expandafter\fix@meaning\meaning} +\expandafter\edef\expandafter\fix@meaning + \expandafter #\expandafter1\string\romannumeral#2#3% + {#1\string\romannumeral`\string^\string^@} +\makeatother + +% Margin Notes +% ============ + +\makeatletter +\def\MyMarginNote {\@ifnextchar[\@MyMarginNote{\@MyMarginNote[]}}% +\let\inmarg\MyMarginNote +\def\@MyMarginNote [#1]#2{\@bsphack + \vadjust{\vskip-\dp\strutbox + \smash{\hbox to 0pt + {\color[named]{PineGreen}\normalfont\small + \hsize 1.6cm\rightskip.5cm minus.5cm + \hss\vtop{#2}\ $\to$#1\ }}% + \vskip\dp\strutbox + }\strut\@esphack} +\def\MyMarginNoteWithBrace #1#2{\@bsphack + \vadjust{\vskip-\dp\strutbox + \smash{\hbox to 0pt + {\color[named]{PineGreen}%\normalfont\small + \hss #1\ $\bigg\{$#2}}% + \vskip\dp\strutbox + }\strut\@esphack} +\def\IMPORTANT {\MyMarginNoteWithBrace + {\raisebox{-.5\height}{\resizebox{2\width}{!}{\ding{43}}}}{\ }} +\def\IMPORTANTf {\MyMarginNoteWithBrace + {\raisebox{-.5\height}{\resizebox{2\width}{!}{\ding{43}}}}% + {\kern\dimexpr\FrameSep+\FrameRule\relax\ }} +\def\etype #1{\@bsphack + \vadjust{\vskip-\dp\strutbox + \smash{\hbox to 0pt {\hss\color[named]{PineGreen}% + \itshape \xintListWithSep{\,}{#1}\ $\star$\quad }}% + \vskip\dp\strutbox + }\strut\@esphack} +\def\retype #1{\@bsphack + \vadjust{\vskip-\dp\strutbox + \smash{\hbox to 0pt {\hss\color[named]{PineGreen}% + \itshape \xintListWithSep{\,}{#1}\ \ding{73}\quad }}% + \vskip\dp\strutbox }\strut\@esphack} +\def\ntype #1{\@bsphack + \vadjust{\vskip-\dp\strutbox + \smash{\hbox to 0pt {\hss\color[named]{PineGreen}% + \itshape \xintListWithSep{\,}{#1}\quad }}% + \vskip\dp\strutbox }\strut\@esphack} +% +\def\Numf {{\vbox{\halign{\hfil##\hfil\cr \footnotesize + \upshape Num\cr + \noalign{\hrule height 0pt \vskip1pt\relax} + \itshape f\cr}}}} +\def\Ff {{\vbox{\halign{\hfil##\hfil\cr \footnotesize + \upshape Frac\cr + \noalign{\hrule height 0pt \vskip1pt\relax} + \itshape f\cr}}}} +\def\numx {{\vbox{\halign{\hfil##\hfil\cr \footnotesize + \upshape num\cr + \noalign{\hrule height 0pt \vskip1pt\relax} + \itshape x\cr}}}} +% +\def\NewWith #1{\@bsphack + \vadjust{\vskip-\dp\strutbox + \smash{\hbox to 0pt {\hss\color[named]{PineGreen}% + \normalfont\small\bfseries + \hsize 1.5cm\rightskip.5cm minus.5cm + \vtop{\noindent New with #1}\ }}% + \vskip\dp\strutbox }\strut\@esphack} +% +\def\CHANGED #1{\@bsphack + \vadjust{\vskip-\dp\strutbox + \smash{\hbox to 0pt {\hss\color[named]{Red}% + \normalfont\small\bfseries + \hsize 1.5cm\rightskip.5cm minus.5cm + \vtop{\noindent Changed at #1!}\ }}% + \vskip\dp\strutbox }\strut\@esphack} + +\def\DEPRECATED #1{\@bsphack + \vadjust{\vskip-\dp\strutbox + \smash{\hbox to 0pt {\hss\color[named]{PineGreen}% + \normalfont\small\bfseries + \hsize 2cm\rightskip.5cm minus.5cm + \vtop{\noindent Deprecated! (#1)}\ }}% + \vskip\dp\strutbox }\strut\@esphack} +% +\def\CHANGEDf #1{\@bsphack + \vadjust{\vskip-\dp\strutbox + \smash{\hbox to 0pt {\hss\color[named]{Red}% + \normalfont\small\bfseries + \hsize 1.5cm\rightskip.5cm minus.5cm + \vtop{\noindent Changed at #1!}\ + \kern\dimexpr\FrameSep+\FrameRule\relax}}% + \vskip\dp\strutbox }\strut\@esphack} +% +\def\NewWithf #1{\@bsphack + \vadjust{\vskip-\dp\strutbox + \smash{\hbox to 0pt {\hss\color[named]{PineGreen}% + \normalfont\small\bfseries + \hsize 1.5cm\rightskip.5cm minus.5cm + \vtop{\noindent New with #1}\ + \kern\dimexpr\FrameSep+\FrameRule\relax}}% + \vskip\dp\strutbox }\strut\@esphack} + +\makeatother + +% \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 added June 9, 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@ } + +% \leftedline +% =========== + +% 12 octobre 2014 + +\newif\ifinlefted + +\newcommand*\leftedline {% + \ifhmode \\\relax + \def\leftedline@{\hss\egroup\hskip\z@skip\ignorespaces }% + \else + \def\leftedline@{\hss\egroup }% + \fi + \afterassignment\@leftedline + \let\next=} +\def\@leftedline + {\hbox to \linewidth \bgroup \inleftedtrue + \everbatimeverypar + \bgroup + \aftergroup\leftedline@ } + +\makeatother + +% verbatim macros and environments +% ================================ +% +% June 2013, then October 2014. +% ----------------------------- +% +\makeatletter +\catcode`_ 11 + +% some of my verbatim environments do not make the space active (\lverb e.g.). Then +% \do@noligs must be modified, \char`#1 must be followed by a space token, else, +% the `#1 expansion will swallow one space. +\def\do@noligs #1{% + \catcode`#1\active + \begingroup + \lccode`~`#1\relax + \lowercase{% + \endgroup\def~{\leavevmode\kern\z@\char`#1 }}% +} + +% \lowast +\def\lowast{\raisebox{-.25\height}{*}} +\catcode`* 13 +\def\makestarlowast {\let*\lowast\catcode`\*\active}% +\catcode`* 12 + + + +% \MacroFont and \MicroFont +% ========================= + +\def\restoreMicroFont {\def\MicroFont {\ttbfamily\makestarlowast + \ifinlefted\else\ifineverb\else\color[named]{Blue}\fi\fi}} +\restoreMicroFont + +% Notice that \macrocode uses \macro@font which stores the \MacroFont meaning +% in force at \begin{document}. But doc.sty's verbatim uses current \MacroFont +% not the meaning at \begin{document}. Comprenne qui pourra... + +\def\restoreMacroFont {\def\MacroFont {\ttbfamily + \ifinlefted\else\ifineverb\else\color[named]{Blue}\fi\fi}} +\restoreMacroFont + +% \verb +% ===== + +% Initially, June 2013, then Sep 9, 2014, and Oct 9-12 2014 +% +% Initial motivation was simply that doc.sty and related classes \verb +% macro is with a hard-coded \ttfamily. There were further issues. +% +% 1. With |stuff with space|, paragraph reformatting in the Emacs/AUCTeX +% buffer caused havoc. Thus I wanted the input to accept linebreaks in +% its contents. +% +% 2. Hence I did not want to have obeyed spaces obeyed, (Emacs reflowing +% of paragraph in certain contexts often adds spaces at beginning of a line) +% +% 3. Also I wanted to allow hyphenated output, at least at some +% locations. I did a first version which treated spaces, \, {, and } +% specially. +% +% 4. At some point I wanted to add some colored background (I have +% dropped that since due to pdf file size increase). +% +% 5. And also I got fed up from the non-compatibility with footnotes due +% to catcode freeze. +% +% Because of 5. I opted for a \scantokens approach, hence for a macro +% with delimited argument. Here is what I do now, this is compatible +% with short verbs. + +\def\verb +{% + \relax \ifmmode\else\leavevmode\null\fi + \bgroup + \let\do\@makeother \dospecials + \@ifstar{\@sverb}% \verb* is used in the index (obsolete: no indices at 1.3e), + % leave it using ambient font + {\MicroFont % used to change font (ttbfamily=slashed 0), color, + % will make * active via \makestarlowast + \catcode 32 10 \endlinechar 32 % allows to fetch across line breaks + \frenchspacing % done globally in document + \@@jfverb}% +}% +% Note (Oct 12, 2014): in the improbable situation a newlinechar is +% found in the ##1, \scantokens will convert this to an end of line in +% its "write" phase, which will be then ignored in its "read" phase due +% to \endlinechar-1. This also avoids possible creation of \par which +% would defeat \@@jfverb@@. Thus it is good. +\def\@@jfverb #1{% + \ifcat\noexpand#1\noexpand~\catcode`#1\active\fi +% No problem with the EOL for the line where the short verb delimiter stands. + \def\next ##1#1{% + \@vobeyspaces\everyeof{\relax}\endlinechar\m@ne + \expandafter\@@jfverb_a\scantokens\expandafter{##1}}% +% hack with \@empty to prevent brace stripping if catcodes have been +% frozen earlier, like in footnotes. + \next \@empty +} + +% We don't want a \discretionary at the very start. +% But then an empty argument is forbidden! +\def\@@jfverb_a #1{#1\@@jfverb_b } + +\def\@@jfverb_b #1{\ifx\relax #1% + \egroup + \else +% \penalty\z@, or rather (Oct 11, 2014) but I then adjust the textwidth +% precisely: + \discretionary{\copy\SoftWrapIcon}{}{}% + #1\expandafter\@@jfverb_b\fi +} + +% \SoftWrapIcon box for line-breaking using discretionaries +% ========================================================= + +\DeclareFontFamily{U}{MdSymbolC}{} +\DeclareFontShape {U}{MdSymbolC}{m}{n}{<-> MdSymbolC-Regular}{} + +\newbox\SoftWrapIcon +\colorlet {softwrapicon}{blue} + +% Emacs/AUCTeX uses very strange comment-like highlighting for \usefont{U}... +\def\SetSoftWrapIcon{% + \setbox\SoftWrapIcon\hb@xt@\z@ + {\hb@xt@\fontdimen2\font + {\hss{\color{softwrapicon}\usefont{U}{MdSymbolC}{m}{n}\char"97}\hss}% + \hss}% + } + +\AtBeginDocument {\SetSoftWrapIcon }% ttzfamily déjà fait + +\catcode`_ 8 +\makeatother + +% everbatim environment +% ===================== + +% October 13-14, 2014 +% Verbatim with an \everypar hook, mainly to have background color, followed by +% execution of the contents (not limited by a group-scope) + +\makeatletter +\catcode`_ 11 + +\def\everbatimtop {\MacroFont\small } +\let\everbatimbottom\relax +\let\everbatimhook\relax + +\newif\ifineverb + +\def\everbatim {\s@everbatim\@everbatim } +\@namedef{everbatim*}{\s@everbatim\expandafter\@everbatimx\expandafter + {\the\newlinechar}} + +\def\everbatimeverypar{\strut + {\color{yellow!5}\vrule\@width\linewidth }% + \kern-\linewidth + \kern\everbatimindent } +\def\everbatimindent {\z@} +% voir plus loin atbegindocument + +\def\endeverbatim {\if@newlist \leavevmode\fi\endtrivlist } +\expandafter\let\csname endeverbatim*\endcsname \endeverbatim + +\def\s@everbatim {% + \ineverbtrue + \everbatimtop % put there size changes + \topsep \z@skip + \partopsep \z@skip + \itemsep \z@skip + \parsep \z@skip + \parskip \z@skip + \lineskip \z@skip + \let\do\@makeother \dospecials + \let\do\do@noligs \verbatim@nolig@list + \makestarlowast + \everbatimhook + \trivlist\item\relax + \leftskip \@totalleftmargin + \rightskip \z@skip + \parindent \z@ + \parfillskip\@flushglue + \parskip \z@skip + \@@par + \def\par{\leavevmode\null\@@par\pagebreak[1]}% + \everypar\expandafter{\the\everypar \unpenalty + \everbatimeverypar + \everypar \expandafter{\the\everypar\everbatimeverypar}% + }% + \obeylines \@vobeyspaces +} + +\begingroup +\lccode`X 13 +\catcode`X \active +\lccode`Y `* % this is because of \makestarlowast. +% I have to think whether this is useful: obviously if I were to provide +% everbatim and everbatim* in a package I wouldn't do that. +\catcode`Y \active +\catcode`| 0 \catcode`[ 1 \catcode`] 2 \catcode`* 12 +\catcode`{ 12 \catcode`} 12 |catcode`\\ 12 +|lowercase[|endgroup% both freezes catcodes and converts X to active ^^M +|def|@everbatim #1X#2\end{everbatim}% + [#2|end[everbatim]|everbatimbottom ] +|def|@everbatimx #1#2X#3\end{everbatimY}]% + {#3\end{everbatim*}% + \everbatimbottom + \newlinechar 13 + \everbatimxprehook + \scantokens {#3}% + \newlinechar #1\relax + \everbatimxposthook +}% + +% L'espace venant du endofline final mis par \scantokens sera inhibé si #3 se +% termine par un % ou un \x, etc... + +\def\everbatimxprehook {\colorlet{everbsavedcolor}{.}\color[named]{OrangeRed}} +\def\everbatimxposthook {\color{everbsavedcolor}} +\ifpdf + \def\everbatimxprehook + {\pdfcolorstack\@pdfcolorstack push{0 1 0.5 0 k 0 1 0.5 0 K}\relax} + \def\everbatimxposthook + {\pdfcolorstack\@pdfcolorstack pop\relax} +\else +\ifxetex + \def\everbatimxprehook {\special{color push cmyk 0 1 0.5 0}} + \def\everbatimxposthook {\special{color pop}} +\else +\ifnum\Withdvipdfmx=1 + \def\everbatimxprehook {\special{pdf:bcolor OrangeRed}} + \def\everbatimxposthook {\special{pdf:ecolor}} +\fi\fi\fi + + + +% \everb +% ====== +% +% Original was called \dverb and I did it in June 2013. +% Then after doing everbatim, I transformed \dverb, now called \everb +% for itself being as compatible as standard verbatim with list making +% surrounding environments. +% Supposed to be used as +% \everb|@ this will be ignored +% stuff +% escape character: " +% | not necessarily starting a line. +% I chose @ as comment character, mainly for pretty-formatting of the +% source, this can be changed by \everbhook. + +% " comme caractère d'échappement. Par exemple pour colorier des parties. +\def\restoreeverbhook{\def\everbhook{% + \def\"{\begingroup\catcode123 1 \catcode 125 2 \everbescape }% + \catcode`\" 0 \catcode`\@ 14 +}}\restoreeverbhook + +\def\everbescape #1;!{#1\endgroup } + +\def\everb {% + \bgroup + \let\everbatimhook\everbhook + \s@everbatim + \@everb +} + +\def\@everb #1{\catcode`#1\active + \lccode`\~`#1% + \lowercase{\def~{\if@newlist \leavevmode\fi + \endtrivlist + \egroup + \@doendpe + \everbatimbottom }}% + }% + +\catcode`_8 +\makeatother + + +% \printnumber +% ============ + +\catcode`_ 11 +\makeatletter +\catcode`& 3 +\def\allowsplits_a {\futurelet\printnumber_token\allowsplits_b }% +\def\allowsplits_b{\ifx\printnumber_token\@sptoken\space\fi\allowsplits_c } +\def\allowsplits_c #1{\ifx \xint_dothis\xint_gobble_i\fi + \if ,#1\xint_dothis {\discretionary{\rlap,}{}{,}}\fi + \xint_orthat{\discretionary + {\copy\SoftWrapIcon}% + {}% + {}#1}\allowsplits_a }% + +\def\printnumber #1{\expandafter\allowsplits_a \romannumeral-`0#1&}% +\hyphenpenalty \z@ + +\catcode`& 4 +\makeatother +\catcode`_ 8 + +% Parameters for lists +% ==================== +\AtBeginDocument{% + \leftmargini \dimexpr4\fontcharwd\font`X\relax + \leftmarginii\dimexpr3\fontcharwd\font`X\relax + \leftmarginiii \leftmarginii + \leftmarginiv \leftmarginii + \parindent\dimexpr2\fontcharwd\font`X\relax + \leftmargin\leftmargini % pourquoi pas 0? +% formerly everbatim indent was set to leftmargingi, reduce it (2017/08/26) +% \edef\everbatimindent{\the\dimexpr\leftmargini\relax\space }% +% setting it to \parindent does not work with \everb construct +% \def\everbatimindent{\parindent}% + \edef\everbatimindent{\the\dimexpr2\fontcharwd\font`X\relax\space}% + \cftsubsecnumwidth 2\leftmarginii + \cftsubsubsecnumwidth 2\leftmargini + \cftsubsecindent 0pt + \cftsubsubsecindent \cftsubsecnumwidth +}% + +% ========== +% Hyperlinks +% ========== + +% \csa, \csbxint, \csh etc... +% =========================== + +% These definitions in force both in manual and implementation part +\DeclareRobustCommand\csa[1] + {{\ttzfamily\char92\endlinechar-1 + \makestarlowast \catcode`_ 12 \catcode`^ 12 + \scantokens\expandafter{\detokenize{#1}}}} + +% csan: n means no backslash +\DeclareRobustCommand\csan[1] + {{\ttzfamily\endlinechar-1 + \makestarlowast \catcode`_ 12 \catcode`^ 12 + \scantokens\expandafter{\detokenize{#1}}}} + +\newcommand\csh[1] + {\texorpdfstring{\csa{#1}}{\textbackslash\detokenize{#1}}} +\newcommand\cshn[1] + {\texorpdfstring{\csan{#1}}{\detokenize{#1}}} +% \csh and \cshn will be redefined in implementation section +\let\cshnolabel\csh +\let\cshnnolabel\cshn + +% These definitions will be re-done for implementation part +% Don't bother about underscore and caret for time being. +\DeclareRobustCommand\csb [1] + {\hyperref[\detokenize{#1}]% + {{\char92 \endlinechar-1 \makestarlowast + \scantokens\expandafter{\detokenize{#1}}}}} +\DeclareRobustCommand\csbxint [1] + {\hyperref[\detokenize{xint#1}]% + {{\char92\mbox{xint}\-\endlinechar-1 \makestarlowast + \scantokens\expandafter{\detokenize{#1}}}}} + +% \func, \funcdesc, \keyword, \keyworddesc, \prec, \precdesc +% ========================================================== + +\newcommand\func[1]{\hyperlink{\detokenize{func-#1}}{#1}()} +\newcommand\funcdesc[2][x]{\item[#2({#1})]\hypertarget{\detokenize{func-#2}}{}}% + +\newcommand\keyword[1]{\hyperlink{\detokenize{kwd-#1}}{#1}} +\newcommand\keyworddesc[1]{\item[#1]\hypertarget{\detokenize{kwd-#1}}{}}% + +\let\prec\relax % sinon, c'est \mathchar"321E +\newcommand\prec[1]{\hyperlink{\detokenize{prec-#1}}{#1}} +\newcommand\precdesc[1]{\item[$#1$]\hypertarget{\detokenize{prec-$#1$}}{}}% + +\newcommand\var[1]{\hyperlink{\detokenize{var-#1}}{#1}} +\newcommand\vardesc[1]{\item[#1]\hypertarget{\detokenize{var-#1}}{}}% + +% \xintname, \xintnameimp etc... +% ============================== + + +\xintForpair #1#2 in +{(xintkernel,kernel), + (xinttools,tools), + (xintcore,core),(xint,xint),(xintbinhex,binhex),(xintgcd,gcd),% + (xintfrac,frac),(xintseries,series),(xintcfrac,cfrac),(xintexpr,expr),% + (xinttrig, trig), (xintlog, log)} +\do +{% + \expandafter\def\csname #1name\endcsname + {\texorpdfstring + {\hyperref[sec:#2]% + {\relax{\color{joli}\MakeNameUp{#1}}}}% + {#1}% + \xspace }% + \expandafter\def\csname #1nameimp\endcsname + {\texorpdfstring + {\hyperref[sec:#2imp]% + {\relax{\color{blue}\MakeNameUp{#1}}}}% + {#1}% + \xspace }% +}% + + \def\DOCxintfrontpage + {\texorpdfstring + {\hyperref[frontpage]{\relax{\color{joli}TOC}}}% + {TOC}% + \xspace }% + +\makeatletter +\protected\def\MakeNameUp#1{% + \ifcsname #1nameUp\endcsname + \expandafter\@firstoftwo\else + \expandafter\@secondoftwo + \fi + {\fbox{\textup{#1}}}{#1}} +\makeatother + +% \RaisedLabel +% ============ + +% Samedi 16 juin 2018 à 15:23:22 +% trick to see header of target page +% there is probably better way to use the already in place +% anchor from \section, but no time to go into hyperref source +\newcommand\RaisedLabel[2][6]{% +\vspace*{-#1\baselineskip}% +\begingroup + \let\leavevmode\relax\phantomsection + \label{#2}% +\endgroup +\vspace*{#1\baselineskip}% +} + +% begin{document} +% =============== +% \ttzfamily done at begin document + +\begin{document}\thispagestyle{empty} +\pdfbookmark[1]{Title page}{TOP} + +{% +\normalfont\Large\parindent0pt \parfillskip 0pt\relax + \leftskip 2cm plus 1fil \rightskip 2cm plus 1fil +\ifnum\dosourcexint=1 + The \xintnameimp source code\par + \gdef\DOCxintfrontpage + {\texorpdfstring + {\hyperref[frontpage]{\relax{\color{blue}TOC}}}% + {TOC}% + \xspace }% +\else + The \xintname bundle\par +\fi +\RaisedLabel{frontpage} +} + +{\centering + \textsc{Jean-Fran\c cois Burnol}\par + \footnotesize + jfbu (at) free (dot) fr\par + Package version: \xintbndlversion\ (\xintbndldate); + documentation date: \xintdocdate.\par + {From source file \texttt{xint.dtx}. \xintdtxtimestamp.}\par +} + +\medskip +% Vendredi 15 juin 2018 +% Someone makes the comma active (not me! not sure if doc.sty or KOMA) and +% this derails xspace.sty, in the headers, as it uses \scantokens on a list of +% tokens, so it fails to recognize the commas which of course are of catcode12 +\def\xintRunningHeader{{\catcode`,12\relax + \DOCxintfrontpage, + \xintkernelname, + \xintcorename, + \xintname, + \xintfracname, + \xintexprname, \xinttrigname, \xintlogname, + \xintbinhexname, + \xintgcdname, + \xintseriesname, + \xintcfracname, + \xinttoolsname}} +\markboth{\makebox[0pt]{\xintRunningHeader}}{\makebox[0pt]{\xintRunningHeader}} + +% Skips safely. +\ifnum\dosourcexint=1 +\catcode`+ 0 \catcode0 9 % n'importe quoi sauf 15 (car ^^@) +\catcode`\\ 12 ++expandafter+iffalse+fi +\fi +% + +\newcommand\TeXnote{\par\smallskip\textbf{\TeX hackers note: }} + +\etocsetlevel{toctobookmark}{6} + + + +\etocsetlevel{table}{2}% subsection + +\renewcommand*{\etocbelowtocskip}{0pt} +\renewcommand*{\etocinnertopsep}{0pt} +\renewcommand*{\etoctoclineleaders} + {\hbox{\normalfont\normalsize\hbox to 1ex {\hss.\hss}}} +\etocmulticolstyle [1]{% + \phantomsection\section* {Contents} + \etoctoccontentsline*{toctobookmark}{Contents}{1}% +} + +\etocsettagdepth {description}{subsection} +\etocsettagdepth {macros}{none} +\etocsettagdepth {implementation}{none} + +\etocsettocdepth{subsection} +\tableofcontents + +\renewcommand*\etocabovetocskip{\bigskipamount} +\makeatletter +\etocmulticolstyle [2]{\parskip\z@skip\raggedcolumns + \setlength{\columnsep}{\leftmarginii}% + \setlength{\columnseprule}{0pt}% +}% +\makeatother + \etocsettagdepth {description}{none} + \etocsettagdepth {macros} {section} +\ifnum\NoSourceCode=1 + \etocsettagdepth {implementation}{none} +\else + \etocsettagdepth {implementation}{section} +\fi + +\tableofcontents + + +\etocignoredepthtags + +\etocmulticolstyle [1]{% + \phantomsection% \section* {Contents} + \etoctoccontentsline*{toctobookmark}{Contents}{2}% +} + +\inmanualmaintocfalse + +\clearpage + +% ---- +% Fibonacci code +% December 7, 2013. Expandably computing a big Fibonacci number +% with the help of TeX+\numexpr+\xintexpr, (c) Jean-François Burnol +\catcode`_ 11 +% +% ajouté 7 janvier 2014 au xint.dtx pour 1.07j. +% +% Le 17 janvier je me décide de simplifier l'algorithme car l'original ne tenait +% pas compte de la relation toujours vraie A=B+C dans les matrices symétriques +% utilisées en sous-main [[A,B],[B,C]]. +% +% la version ici est celle avec les * omis: car multiplication tacite devant les +% sous-expressions depuis 1.09j, et aussi devant les parenthèses depuis 1.09k. +\def\Fibonacci #1{% + \expandafter\Fibonacci_a\expandafter + {\the\numexpr #1\expandafter}\expandafter + {\romannumeral0\xintiiexpro 1\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro 1\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro 1\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro 0\relax}} +% +\def\Fibonacci_a #1{% + \ifcase #1 + \expandafter\Fibonacci_end_i + \or + \expandafter\Fibonacci_end_ii + \else + \ifodd #1 + \expandafter\expandafter\expandafter\Fibonacci_b_ii + \else + \expandafter\expandafter\expandafter\Fibonacci_b_i + \fi + \fi {#1}% +}% +\def\Fibonacci_b_i #1#2#3{\expandafter\Fibonacci_a\expandafter + {\the\numexpr #1/2\expandafter}\expandafter + {\romannumeral0\xintiiexpro sqr(#2)+sqr(#3)\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro (2#2-#3)#3\relax}% +}% end of Fibonacci_b_i +\def\Fibonacci_b_ii #1#2#3#4#5{\expandafter\Fibonacci_a\expandafter + {\the\numexpr (#1-1)/2\expandafter}\expandafter + {\romannumeral0\xintiiexpro sqr(#2)+sqr(#3)\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro (2#2-#3)#3\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro #2#4+#3#5\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro #2#5+#3(#4-#5)\relax}% +}% end of Fibonacci_b_ii +\def\Fibonacci_end_i #1#2#3#4#5{\xintthe#5} +\def\Fibonacci_end_ii #1#2#3#4#5{\xinttheiiexpr #2#5+#3(#4-#5)\relax} +\catcode`_ 8 + +\def\Fibo #1.{\Fibonacci {#1}} + +\def\specialprintone #1% +{% + \ifx #1\relax \else \makebox[877496sp]{#1}\hskip 0pt plus 2sp\relax + \expandafter\specialprintone\fi +}% +\def\specialprintnumber #1% first ``fully'' expands its argument. +{\expandafter\specialprintone \romannumeral-`0#1\relax }% + +\AddToShipoutPicture*{% + \put(10.5cm,14.85cm) + {\makebox(0,0) + {\resizebox{17cm}{!}{\vbox + {\hsize 8cm\Huge\baselineskip.8\baselineskip\color{black!10}% + \specialprintnumber{F(1250)=}% + \specialprintnumber{\Fibonacci{1250}}}\par}% + }% + }% +} + + +\pdfbookmark[1]{Dependency graph}{DependencyGraph} + + + + +\tikzstyle{block} = [rectangle, draw, + fill=yellow!10, +% fill opacity=0.5, + draw=black!30, + line width=2pt, + text width=6em, text centered, rounded corners, minimum height=4em] +\tikzstyle{line} = [draw, line width=1pt, color=black!30] + +\vspace*{\stretch{0.3333}} + +\begin{figure}[ht!] + \phantomsection\label{dependencygraph} +\centeredline{% +\begin{tikzpicture}[node distance = 2.5cm] + % Place nodes + \node [block] (kernel) {\xintkernelname}; + \node [left of=kernel] (A) {}; + \node [right of=kernel] (B) {}; + \node [block, below right of=B] (core) {\xintcorename}; + \node [block, below left of=A] (tools) {\xinttoolsname}; + \node [block, right of=core, xshift=1cm] (bnumexpr) {\href{http://www.ctan.org/pkg/bnumexpr}{bnumexpr}}; + \node [block, below of=core] (xint) {\xintname}; + \node [block, left of=xint, xshift=-.5cm] (gcd) {\xintgcdname}; + \node [block, left of=gcd] (binhex) {\xintbinhexname}; + \node [block, below of=xint] (frac) {\xintfracname}; + \node [block, below of=frac, yshift=-.5cm] (expr) {\xintexprname}; + \node [block, below right of=expr, yshift=-.5cm, xshift=2.25cm] (polexpr) {\href{http://www.ctan.org/pkg/polexpr}{polexpr}}; + \node [block, below of=expr, yshift=-.5cm] (trig) {\xinttrigname}; + \node [block, left of=trig] (log) {\xintlogname}; + \node [block, below right of=frac, xshift=1cm] (series) {\xintseriesname}; + \node [block, right of=series] (cfrac) {\xintcfracname}; + % Draw edges + \path [line,-{Stealth[length=5mm]}] (kernel) -- (core); + \path [line,-{Stealth[length=5mm]}] (kernel) -- (tools); + \path [line,-{Stealth[length=5mm]}] (core) -- (bnumexpr); + \path [line,-{Stealth[length=5mm]}] (core) to [out=180,in=90] (gcd.north); + \path [line,-{Stealth[length=5mm]}] (kernel) -- (binhex); + \path [line,-{Stealth[length=5mm]}] (core) -- (xint); + \path [line,-{Stealth[length=5mm]}] (xint) -- (frac); + \path [line,-{Stealth[length=5mm]}] (frac) -- (expr); + \path [line,-{Stealth[length=5mm]}] (expr) -- (polexpr); + \path [line,{Stealth[length=5mm]}-{Stealth[length=5mm]}] (expr) -- (trig); + \path [line,{Stealth[length=5mm]}-{Stealth[length=5mm]}] (expr) -- (log); + \path [line,-{Stealth[length=5mm]}] (expr) -- (polexpr); + \path [line,-{Stealth[length=5mm]}] (frac) to [out=0,in=90] (series.north); + \path [line,-{Stealth[length=5mm]}] (frac) to [out=0,in=90] (cfrac.north); + \path [line,dashed,-{Stealth[length=5mm]}] (binhex.south) -- (expr); +% at 1.3d gcd() and lcm() needs no support from xintgcd +% \path [line,dashed,-{Stealth[length=5mm]}] (gcd.south) -- (expr); + \path [line,dashed,-{Stealth[length=5mm]}] (tools) to [out=0, in=90] + (gcd.north);% je dois positionner mieux mais pas le temps de lire 700 pages + \path [line,dashed,-{Stealth[length=5mm]}] (tools.south west) to [out=270, in=225] + (cfrac.south west);% je dois positionner mieux mais pas le temps de lire 700 pages + \path [line,-{Stealth[length=5mm]}] (tools) to [out=270,in=180] (expr); + \end{tikzpicture}}\bigskip +\end{figure} + +\vspace{2\baselineskip} + +\begin{addmargin}{2cm} +\normalfont\footnotesize Dependency graph for the + \xintname bundle components: modules pointed to by arrows \textbf{automatically} + import the modules originating the continuous line ended by an arrow. + Dashed lines + indicate a partial dependency, and to enable the corresponding + functionalities of the lower module it is thus necessary to use + a suitable |\usepackage| (\LaTeX) or |\input| (Plain \TeX.)\par + + \href{http://ctan.org/pkg/bnumexpr}{bnumexpr} is a + separate (\LaTeX{} only) package by the author which uses (by default) + \xintcorename as its mathematical engine. + + \href{http://ctan.org/pkg/polexpr}{polexpr} is a + separate (\LaTeX{} only) package by the author which requires \xintexprname. + + \xinttrigname and \xintlogname are loaded automatically by \xintexprname; they + will refuse to be loaded directly (but see \csbxint{reloadxinttrig}). +\par +\end{addmargin} + +\vfill + +\clearpage + +\etocdepthtag.toc {description} + +\section{Read this first}\RaisedLabel{sec:quickintro} + +This section provides recommended reading on first discovering the package. + +This is release \expandafter|\xintbndlversion|. +\begin{enumerate} +\item \func{log}, \func{exp}, \func{log10}, \func{pow10}, \func{pow} are implemented via + \href{http://ctan.org/pkg/poormanlog}{poormanlog}: this achieves only \dtt{8} or \dtt{9} + digits of precision.... This situation is provisory, I simply was lacking + the time. See \xintlogname. +\item \func{sin}, \func{cos}, ..., \func{asin}, ... are implemented (using + high level user interface), up to about \dtt{60} digits of + precision, see \xinttrigname. +\item |NaN|, |+Infty|, |-Infty|, etc... and a proper internal data structure + for storing floating point numbers are \emph{yet to be implemented}. +\item \xintname can handle numbers with thousands of digits, but execution + times (and + \hyperref[ssec:memory]{memory considerations}) limit the practical range to + perhaps up to a few hundreds digits. +\item Attention that exact operations with fractions do not reduce to lowest + terms (additions and subtractions use |l.c.m.| of denominators), see + \func{reduce}. +\end{enumerate} + + + + +\begin{addmargin}{1cm} +\makeatletter +\renewenvironment{description} + {\list{}{\topsep\baselineskip\partopsep\z@skip + \parsep\z@ \labelwidth\z@ \itemindent-\leftmargin + \let\makelabel\descriptionlabel}} + {\endlist} +\makeatother + +%\noindent\null\par\kern-\baselineskip +\leavevmode + +\begin{description} +\item[\xinttoolsname] provides utilities of independent interest such as + expandable and non-expandable loops. \xintgcdname and \xintcfracname have a + partial dependency on it but it must be required by user explicitely. + \xintexprname loads it automatically. + +\item[\xintcorename] provides expandable macros implementing addition, + subtraction, multiplication, division, and power with arbitrarily long + numbers. It is loaded automatically by \xintname, and also by \LaTeX\ + package \href{http://ctan.org/pkg/bnumexpr}{bnumexpr} in its default + configuration. + +\item[\xintname] extends \xintcorename with additional operations on big + integers. It loads automatically \xintcorename. + +\item[\xintfracname] extends the scope of \xintname to decimal numbers, to + numbers in scientific notation and also to fractions with arbitrarily + long such numerators and denominators separated by a forward slash. It loads + automatically \xintname. + +\item[\xintexprname] extends \xintfracname with expandable parsers doing + algebra (either exact, float, or limited to big integers) on comma separated + expressions using the standard infix notations and parentheses (or sub + \xintexprname-essions). It implements tacit multiplication, functions with + one or multiple arguments, Python-like slicing of lists, user-definable + variables and user-definable functions, boolean two way or three way + branching. Dummy variables can be used for summing or multiplying an + expression over a range, or for more complicated iterative evaluations + allowing \keyword{omit}, \keyword{abort}, + and \keyword{break} keywords. It loads automatically + \xintfracname (hence \xintname and \xintcorename) and \xinttoolsname. + And \xinttrigname and \xintlogname since |1.3e|. + +\item[\xinttrigname] trigonometrical functions for \xintexprname, + automatically loaded\NewWith{1.3e} by it, can not be used separately. + +\item[\xintlogname] logarithm, exponential, power functions for \xintexprname, + automatically loaded\NewWith{1.3e} by it, can not be used separately. +\end{description} + + +Further modules: + +\begin{description} +\item[\xintbinhexname] is for conversions to and from binary and + hexadecimal bases. Support in \xintexprname of the \TeX\ |"| prefix for + hexadecimal inputs requires this module to be loaded by user. + +\item[\xintgcdname] implements the Euclidean algorithm and its typesetting. + The macro \csbxint{Irr} (hence the \xintexprname function \func{reduce}) is + provided independently in \xintfracname. Also the \xintexprname functions + \func{gcd} and \func{lcm} are implemented directly so loading this + module is not needed for them (since |1.3d|). + +\item[\xintseriesname] provides some basic functionality for computing in an + expandable manner partial sums of series and power series with fractional + coefficients. + +\item[\xintcfracname] is provided to help with the computation and display of + continued fractions. +\end{description} +\end{addmargin} + +\begin{framed} +All macros from the \xintname packages doing computations are +\emph{expandable}, and naturally also the parsers provided by \xintexprname. + + The reasonable range of use of the package arithmetics is with numbers of + \emph{up to a few hundred digits.} + Although numbers up to about \dtt{19950} digits are acceptable + inputs, the package is not at his peak efficiency when confronted with such + really big numbers having thousands of digits.\footnotemark +\end{framed} + +\footnotetext{The maximal handled size for inputs to multiplication is + \dtt{19959} digits. This limit is observed with the current default values + of some parameters of the tex executable (input stack size at 5000, + maximal expansion depth at 10000). Nesting of macros will reduce it and it + is best to restrain numbers to at most \dtt{19900} digits. The output, as + naturally is the case with multiplication, may exceed the bound.} + + + +\subsection{First examples} + +With |\usepackage{xintexpr}| if using \LaTeX, or |\input xintexpr.sty\relax| +for other formats, you can do computations such as the following. +\begin{description} +\item[with floats:]\leavevmode\par +\begin{everbatim*} +\xintfloateval{3.25^100/3.2^100, 2^1000000, sqrt(1000!)}\newline +\xintfloateval{[-1] sind(37), cosd(37)}\newline % trim off last digit (via rounding) +\xintfloateval{[8] log10(12345678), pow10(0.1234)}\newline % only 8 or 9 digits! +\xintfloateval{[8] pow(2,1/3)}\newline % only 8 or 9 digits! +\xintfloateval{[8] log(10), exp(1)}\par % only 8 or 9 digits! +\end{everbatim*} + The \csbxint{floateval} macro using braces was introduced at |1.3d|. + Formerly, one did: +\begin{everbatim} +\thexintfloatexpr 10^-3.5\relax\ or rather \xintthefloatexpr 10^-3.5\relax +\end{everbatim} +Most of the manual is couched using the \csbxint{theexpr}|...\relax| +which is the original one from first release of \xintexprname. + + For powers with fractional exponents, see \hyperref[ssec:poormanloghack]{poormanloghack}. +\item[with fractions:]\leavevmode\par +Here is an example using a dummy a variable: +\begin{everbatim*} +$\sum_{i=1}^{25} (-1)^{i-1}\frac{1}{i^2} = + \xintFrac{\xinteval{reduce(add((-1)^(i-1)/i**2, i=1..25))}}$ +\end{everbatim*} +\item[with integers:]\leavevmode\par +\begin{everbatim*} +\xintiieval{3^159+2^234}\newline +\xintiieval{lcm(seq(n, n=100..110))}\par +\end{everbatim*} +\end{description} + +Float computations are done by default with \dtt{16} digits of precision. +This can be changed via an assignment to |\xintDigits|: +\begin{everbatim*} +% use braces (or a LaTeX environment) to limit the scope of the \xintDigits assignment +{\xintDigits := 88;\xintfloateval{3.25^100-3.2^100}}\par +\end{everbatim*} +Trigonometrical function need a reload after modifying the float precision, +this is done by \csbxint{reloadxinttrig}. + +We can even try daring things:\footnote{The \cs{printnumber} is not part of + the package, see \autoref{ssec:printnumber}.} +\begin{everbatim*} +{\xintDigits:=500;\printnumber{\xintfloateval{sqrt(2)}}} +\end{everbatim*} + +All operations executed by the parsers are based on underlying macros from +packages \xintfracname and \xintname which are loaded automatically by +\xintexprname. With \xintbinhexname loaded the +parsers can handle hexadecimal notation on (even fractional) input. + +All macros doing computations ultimately rely on (and reduce to) the +|\numexpr| primitive from \eTeX{}. These \eTeX{} extensions date back to 1999 +and are by default incorporated into the |pdftex| etc... executables from +major modern \TeX{} installations since more than ten years now. Only the +|tex| binary does not benefit from them, as it has to remain the original +\textsc{D.~Knuth}'s software, but one can then use |etex| on the command line. +PDF\TeX\ (in pdf or dvi output mode), Lua\TeX, Xe\TeX\ all include the \eTeX\ +extensions. + +\subsection{Quick overview (expressions with \xintexprname)} + +This section gives a first few examples of using the expression parsers which +are provided by package \xintexprname. See \autoref{sec:xintexprsyntax} for +a more detailed description, and perhaps read \autoref{ssec:threeparsers} +before coming back here. + +Loading \xintexprname automatically also +loads packages \xinttoolsname and \xintfracname. The latter loads \xintname +which loads \xintcorename. All three provide the macros which ultimately do the +computations associated in expressions with the various symbols like |+, *, ^, +!| and functions such as |max, sqrt, gcd|. The package +\xinttoolsname does not handle computations but provides some useful utilities. + +\begin{framed} + Release |1.2h| defines |\thexintexpr| as synonym to |\xinttheexpr|, + |\thexintfloatexpr| as synonym of |\xintthefloatexpr|, etc... +\end{framed} + +\begin{framed} + Release |1.3d| defines \csbxint{eval}, \csbxint{ieval}, \csbxint{iieval}, + \NewWithf{1.3d} + and \csbxint{floateval} which use braces to delimit their arguments, which + will be more familiar to \LaTeX\ users than the \csbxint{theexpr}|...\relax| + syntax. For example: +\begin{everbatim*} +\xinteval{1+2+3}, \xintfloateval{111/123}, \xintfloateval{[3] 111/123} +\end{everbatim*} + + This documentation however uses systematically |\xinttheexpr...\relax| or + |\thexintexpr...\relax| syntax for legacy reasons. In this input syntax the + |\relax| does not have to be physically present it may arise from pure + expansion (see \autoref{sec:expr}). + + Notice that for the \csbxint{theiexpr} and \csbxint{thefloatexpr} parsers + which admit an optional argument, this optional argument will have to be + located \emph{inside} the braces when using |\xintieval| or |\xintfloateval| + input syntax, as examplified above. + + The main reason is that it is sometimes useful to hide the square brackets, for + example when using the |\num| macro from package + \href{http://ctan.org/pkg/siunitx}{siunitx}. +\end{framed} + +\begin{framed} + The square root extraction \func{sqrt} is allowed in |\xintexpr..\relax| but + naturally can't return an \emph{exact} value, it computes as if it was in + |\xintfloatexpr..\relax|. + + The synonymous power operators |^| and |**| allow only integral exponents + (non-negative in the integer only parser \csbxint{iiexpr}) in \csbxint{expr} + and half-integral exponents in \csbxint{floatexpr}. Since |1.3e| fractional + powers via the \func{pow} function are available, see + \xintlogname.\NewWithf{1.3e} But they achieve currently only about \dtt{8} + digits of precision. +\end{framed} + +Here is a (partial) list of the recognized symbols: +\begin{itemize} +\item the comma (to separate distinct computations or arguments to a + function), +\item parentheses, +\item \hyperref[tab:precedences]{operators}: + \begin{itemize}[nosep] +\item |+|, |-|, |*|, |/|, +\item powers via |^| or equivalently |**|, see \xintlogname for allowing with + them fractional exponents, +\item |//| for floored division and |/:| its associated modulo, +\item branching via |(x)?{x non zero}{x zero}| and |(x)??{x<0}{x=0}{x>0}| + syntax, +\item boolean logic |!|, |&&| or |'and'|, \verb+||+ or |'or'|, +\item comparison operators |=| (or |==|), |<|, |>|, |<=|, |>=|, |!=|, +\item factorial via the post-fix operator |!|. + \end{itemize} +\item the |"| is used to prefix hexadecimal input (uppercase, not lowercase); + but package \xintbinhexname must be loaded additionally to \xintexprname), +%\item |'| for octal input (\emph{not yet}), +\item various \hyperref[tab:functions]{functions}: + \begin{itemize}[nosep] + \item rounding and truncating \func{round}, \func{trunc} to a given fixed + point precision or with \func{float} to a given floating point precision, + \item the square-root \func{sqrt} achieves correct rounding in arbitrary + precision, + \item the \func{binomial} and (also partial) \func{factorial}, + \item \func{gcd} and \func{lcm} for general fractional operands, + \item randomness related functions such as \func{random} and + \func{randrange} for random floats or integers; they require that \TeX\ + engine provides \csa{pdfuniformdeviate} or \csa{uniformdeviate} primitive, + \item trigonometrical functions \xinttrigname, + \item logarithm and exponential \xintlogname. + \end{itemize} +\item the capacity to work with dummy variables using functions or generators + such as \xintFor #1 in {add, mul, seq, subs, rseq, iter, rrseq, iterr}\do + {\func{#1}\xintifForLast{.}{, }} +\end{itemize} +See \autoref{xintexpr} for basic information and \autoref{sec:xintexprsyntax} +for a complete description. + + +The normal mode of operation of the parsers is to unveil the parsed material +token by token. This means (apart from some exceptions) that all tokens may +arise from expansion of encountered macros (or active characters). For example +a closing parenthesis does not have to be immediately visible, it may arise +later from expansion. + +However, this general behaviour has exceptions, in particular constructs with +dummy variables need at some location immediately visible balanced parentheses +and commas. + +The expansion stops only when the ending |\relax| has been found; +it is then removed from the token stream, and the final computation result is +inserted. + +Here is an example of a computation: +\begin{everbatim*} +\xinttheexpr (31.567^2 - 21.56*52)^3/13.52^5\relax +\end{everbatim*}\newline +This illustrates that +|\xinttheexpr..\relax| does its computations \emph{exactly}. The same example +as a floating point evaluation: +\begin{everbatim*} +\xintthefloatexpr (31.567^2 - 21.56*52)^3/13.52^5\relax +\end{everbatim*} + +Again, all computations done by |\xinttheexpr..\relax| are completely exact. +Thus, very quickly very big numbers are created (and computation times +increase, not to say explode if one goes into handling numbers with thousands +of digits). To compute something like |1.23456789^10000| it is thus better to +opt for the floating point version: +\begin{everbatim*} +\xintthefloatexpr 1.23456789^10000\relax +\end{everbatim*} +\newline +(we can deduce that the exact value has |80000+916=80916| digits). +A bigger example (the scope of +the assignment to |\xintDigits| is limited by the braces): +\begin{everbatim*} +{\xintDigits:=24; \xintthefloatexpr 1.23456789123456789^123456789\relax } +\end{everbatim*} +(<- notice the size of the power of ten: this surely largely exceeds your pocket +calculator abilities). + +Some examples with dummy variables: +\begin{everbatim*} +\xinttheiiexpr add(i^5, i=100..200)\relax\par +\noindent\xinttheexpr add(x/(x+1), x = 1000..1014)\relax\par +\noindent\xinttheexpr reduce(add(x/(x+1), x = 1000..1014))\relax +\end{everbatim*} +\newline In this example, the fraction obtained by addition was thus already +irreducible, but this is not always the case: +\begin{framed} + By default, the basic operations on fractions are not followed in an + automatic manner by reduction to smallest terms: |A/B| multiplied by |C/D| + returns |AC/BD|, and |A/B| added to |C/D| uses |lcm(B, D)| as denominator.\CHANGEDf{1.3} +\end{framed} + +Make sure to read \autoref{sec:expr}, \autoref{sec:xintexprsyntax} and +\autoref{ssec:outputs}. + +\subsection{Printing big numbers on the page}\label{ssec:printnumber} +When producing very long numbers there is the question of printing them on + the page, without going beyond the page limits. In this document, I have most + of the time made use of these macros (not provided by the package:) + +% +\everb|@ +\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. +| + +It may be used like this: +% +\leftedline{|\printnumber {\xintiiQuo{\xintiiPow {2}{1000}}{\xintiiFac{100}}}|} +% +or as |\printnumber\mybiginteger| or |\printnumber{\mybiginteger}| if +|\mybiginteger| was previously defined via a |\newcommand|, a |\def| or +an |\edef|. + +An alternative is to suitably configure the thousand +separator with the \href{http://ctan.org/pkg/numprint}{numprint} package +(see \autoref{fn:np}. This will not allow linebreaks when used in math +mode; I also tried \href{http://ctan.org/pkg/siunitx}{siunitx} but even +in text mode could not get it to break numbers accross lines). Recently +I became aware of the \href{http://ctan.org/pkg/seqsplit}{seqsplit} +package% +% +\footnote{\url{http://ctan.org/pkg/seqsplit}} +% +which can be used to achieve this splitting accross lines, and does work +in inline math mode (however it doesn't allow to separate digits by +groups of three, for example).\par + +\subsection{Randomly chosen examples} + +This section is now quite old... + +Here are some examples of use of the package macros. The first one uses only +the base module \xintname, the next one requires the \xintfracname package, +which deals with decimal numbers, scientific numbers (lowercase \dtt{e}), and +also fractions (it loads automatically \xintname). Then some examples with +expressions, which require the \xintexprname package (it loads automatically +\xintfracname). And finally some examples using \xintseriesname, \xintgcdname +which are among the extra packages included in the \xintname distribution. + +The printing of the outputs will either use a custom |\printnumber| macro as +described in the previous section, or sometimes the |\np| macro from the +\href{http://www.ctan.org/pkg/numprint}{numprint} package (see +\autoref{fn:np}). + +\begin{itemize} +\item {$123456^{99}$: }\\ +|\xintiiPow {123456}{99}|: +\dtt{\printnumber{\xintiiPow {123456}{99}}} + +\item {1234/56789 with 1500 digits after the decimal point: }\\ +|\xintTrunc {1500}{1234/56789}\dots|: +\dtt{\printnumber {\xintTrunc {1500}{1234/56789}}\dots } + +\item {$0.99^{-100}$ with 200 (+1) digits after the decimal point.}\\ + |\xinttheiexpr [201] .99^-100\relax|: + \dtt{\printnumber{\xinttheiexpr [201] .99^-100\relax}}\\ + Notice that this is rounded, hence we asked |\xinttheiexpr| for one + additional digit. To get a truncated result with 200 digits after the decimal + mark, we should have issued + |\xinttheexpr trunc(.99^-100,200)\relax|, rather. + +\begin{snugframed} + The fraction |0.99^-100|'s denominator is first evaluated \emph{exactly} + (\emph{i.e.} the integer |99^100| is evaluated exactly and then used to + divide the suitable power of ten to get the requested digits); for + some longer inputs, such as for example |0.7123045678952^-243|, the + exact evaluation before truncation would be costly, and it is more efficient + to use floating point numbers: +% +\leftedline{|\xintDigits:=20; + \np{\xintthefloatexpr .7123045678952^-243\relax}|}% +% +\leftedline{\xintDigits:=20;\dtt{\np{\xintthefloatexpr .7123045678952^-243\relax }}} +% +\xintDigits:=16;% +% +Side note: the exponent |-243| didn't have to be put inside parentheses, +contrarily to what happens with some professional computational +software. |;-)| +% 6.342,022,117,488,416,127,3 10^35 +% maple n'aime pas ^-243 il veut les parenthèses, bon et il donne, en Digits +% = 24: 0.634202211748841612732270 10^36 +\end{snugframed} + +\item {$200!$:}\\ +|\xinttheiiexpr 200!\relax|: +\dtt{\printnumber{\xinttheiiexpr 200!\relax}} + +\item {$2000!$ as a float. As \xintexprname does not handle |exp/log| so far, + the computation is done internally without the Stirling formula, + by repeated multiplications truncated suitably:}\\ + |\xintDigits:=50;|\newline |\xintthefloatexpr 2000!\relax|: + {\xintDigits:=50;\dtt{\printnumber{\xintthefloatexpr 2000!\relax}}} + +\item Just to show off (again), let's print 300 digits (after the decimal + point) of the decimal expansion of $0.7^{-25}$:% +% +\footnote{the |\np| typesetting macro is from the |numprint| package.} +% +\begin{everbatim*} +% % in the preamble: +% \usepackage[english]{babel} +% \usepackage[autolanguage,np]{numprint} +% \npthousandsep{,\hskip 1pt plus .5pt minus .5pt} +% \usepackage{xintexpr} +% in the body: +\np {\xinttheexpr trunc(.7^-25,300)\relax}\dots +\end{everbatim*} + +This computation is with \csbxint{theexpr} from package \xintexprname, which +allows to use standard infix notations and function names to access the package +macros, such as here |trunc| which corresponds to the \xintfracname macro +\csbxint{Trunc}. Regarding this computation, please keep in mind that +\csbxint{theexpr} computes \emph{exactly} the result before truncating. As +powers with fractions lead quickly to very big ones, it is good to know that +\xintexprname also provides \csbxint{thefloatexpr} which does computations +with floating point numbers. + +\item Computation of a Bézout identity with |7^200-3^200| and |2^200-1|: +(with \xintgcdname)\par +\begin{everbatim*} +\xintAssign{\xinttheiiexpr 7^200-3^200\relax} + {\xinttheiiexpr 2^200-1\relax}\to\A\B +\xintAssign\xintBezout{\A}{\B}\to\U\V\D +\printnumber\U${}\times(7^{200}-3^{200})+{}$\printnumber{\V}% +${}\times(2^{200}-1)=\D=\xinttheiiexpr \U*\A+\V*\B\relax$ +\end{everbatim*} + +\item The Euclide algorithm applied to \np{22206980239027589097} and +\np{8169486210102119257}: (with \xintgcdname)% +% +\footnote {this example is computed tremendously faster than the other + ones, but we had to limit the space taken by the output hence picked + up rather small big integers as input.}\par +\noindent\begingroup\parskip0pt\relax +|\xintTypesetEuclideAlgorithm {22206980239027589097}{8169486210102119257}|\par +\dtt +{\xintTypesetEuclideAlgorithm {22206980239027589097}{8169486210102119257}} +\endgroup +\smallskip + +\item $\sum_{n=1}^{500} (4n^2 - 9)^{-2}$ with each term rounded to twelve digits, +and the sum to nine digits: +\begin{everbatim*} +\def\coeff #1{\xintiRound {12}{1/\xintiiSqr{\the\numexpr 4*#1*#1-9\relax }[0]}} +\xintRound {9}{\xintiSeries {1}{500}{\coeff}[-12]} +\end{everbatim*} + +The complete series, extended to +infinity, has value +$\frac{\pi^2}{144}-\frac1{162}={}$% +\dtt{\np{0.06236607994583659534684445}\dots}\,% +% +\footnote{\label{fn:np}This number is typeset using the + \href{http://www.ctan.org/pkg/numprint}{numprint} package, with + |\npthousandsep{,\hskip 1pt plus .5pt minus .5pt}|. But the breaking + across lines works only in text mode. The number itself was (of + course...) computed initially with \xintname, with 30 digits of $\pi$ + as input. See \hyperref[ssec:Machin]{{how {\xintname} may compute + $\pi$ from scratch}}.} +% +I also used (this is a lengthier computation +than the one above) \xintseriesname to evaluate the sum with \np{100000} terms, +obtaining 16 +correct decimal digits for the complete sum. The +coefficient macro must be redefined to avoid a |\numexpr| overflow, as +|\numexpr| inputs must not exceed $2^{31}-1$; my choice +was: +\everb|@ +\def\coeff #1% +{\xintiRound {22}{1/\xintiiSqr{\xintiiMul{\the\numexpr 2*#1-3\relax} + {\the\numexpr 2*#1+3\relax}}[0]}} +| + +\restoreMacroFont +\edef\Temp {\xintFloatPow [24]{2}{999999999}} + +\item {Computation of $2^{\np{999999999}}$ with |24| significant + figures:} +% +\leftedline{|\numprint{\xintFloatPow [24]{2}{999999999}}|} +\leftedline{\dtt{\numprint{\Temp}}} +% +where the \href{http://www.ctan.org/pkg/numprint}{numprint} package was used +(\autoref{fn:np}), directly in text mode (it can also naturally be used from +inside math mode). \xintname provides a simple-minded \csbxint{Frac} +typesetting macro,% +% +\footnote{Plain \TeX{} users of \xintname have \csbxint{FwOver}.} +% +which is math-mode only: +% +\leftedline{|$\xintFrac{\xintFloatPow [24]{2}{999999999}}$|} +\leftedline{\dtt{$\xintFrac{\Temp}$}} +% +The exponent differs, but this is because +|\xintFrac| does not use a decimal mark in the significand of the output. +Admittedly most users will have the need of more powerful (and customizable) +number formatting macros than |\xintFrac|. +% +\footnote{There should be a |\xintFloatFrac|, but it is lacking.} +% +We have already mentioned +|\numprint| which is used above, there is also |\num| from package +\href{http://www.ctan.org/pkg/siunitx}{siunitx}. The raw output from +% +\leftedline{\detokenize{\xintFloatPow[24]{2}{999999999}}} +% +is $\Temp$. + +\edef\x{\xintiiQuo{\xintiiPow {2}{1000}}{\xintiiFac{100}}} +\edef\y{\xintLen{\x}} + +\item As an example of nesting package macros, let us consider the following +code snippet within a file with filename |myfile.tex|: +\everb|@ +\newwrite\outstream +\immediate\openout\outstream \jobname-out\relax +\immediate\write\outstream {\xintiiQuo{\xintiiPow{2}{1000}}{\xintiiFac{100}}} +% \immediate\closeout\outstream +| +\noindent +The tex run creates a file |myfile-out.tex|, and then writes to it the +quotient from the Euclidean division of $2^{1000}$ by $100!$. The number of +digits is |\xintLen{\xintiiQuo{\xintiiPow{2}{1000}}{\xintiiFac{100}}}| which +expands (in two steps) and tells us that $[2^{1000}/100!]$ has \dtt{\y} +digits. This is not so many, let us print them here: +\dtt{\printnumber\x}.% + +\end{itemize} + +\subsection {More examples within this document} +\label{sec:awesome} + +\begin{itemize} +\item The utilities provided by \xinttoolsname (\autoref{sec:tools}), some + completely expandable, others not, are of independent interest. Their use + is illustrated through various examples: among those, it is shown in + \autoref{ssec:quicksort} how to implement in a completely expandable way + the \hyperref[ssec:quicksort]{Quick Sort algorithm} and also how to illustrate + it graphically. Other examples include some dynamically constructed + alignments with automatically computed prime number cells: one using a + completely expandable prime test and \csbxint{ApplyUnbraced} + (\autoref{ssec:primesI}), another one with \csbxint{For*} (\autoref{ssec:primesIII}). + +\item One has also a \hyperref[edefprimes]{computation of primes within an + \csa{edef}} (\autoref{xintiloop}), with the help of \csbxint{iloop}. + Also with \csbxint{iloop} an + \hyperref[ssec:factorizationtable]{automatically generated table of + factorizations} (\autoref{ssec:factorizationtable}). + +\item The code for the title page fun with Fibonacci numbers is given in + \autoref{ssec:fibonacci} with \csbxint{For*} joining the game. + +\item The computations of \hyperref[ssec:Machin]{ $\pi$ and $\log 2$} + (\autoref{ssec:Machin}) using \xintname and the computation of the + \hyperref[ssec:e-convergents]{convergents of $e$} with the further help of + the \xintcfracname package are among further examples. + +\item Also included, + an \hyperlink{BrentSalamin}{expandable implementation of the Brent-Salamin + algorithm} for evaluating $\pi$. + +\item The \autoref{ssec:PrimesIV} implements expandably the Miller-Rabin + pseudo-primality test. + + +\item The functionalities of \xintexprname are illustrated with various + other examples, in \autoref{xintdeffunc}, + \hyperlink{ssec:dummies}{Functions with dummy variables}, + \autoref{ssec:moredummies} or \hyperref[sssec:recursive]{Recursive definitions}. +\end{itemize} +Almost all of the computational results interspersed throughout the +documentation are not hard-coded in the source file of this document but are +obtained via the expansion of the package macros during the \TeX{} +run.% +% + + + + +\subsection{License and installation instructions} + +\label{ssec:install} + +\xintname is made available under the +\href{http://www.latex-project.org/lppl/lppl-1-3c.txt}{LaTeX Project Public + License 1.3c} and is included in the major \TeX\ distributions, thus there +is probably no need for a custom install: just use the package manager to +update if necessary \xintname to the latest version available. + +The |README| files on \href{http://www.ctan.org/pkg/xint}{CTAN} explain how to +proceed with a custom installation. + +On \TeX\ distributions with a |"texdoc"| or similar utility, +\centeredline{|texdoc --list xint|} +will offer to display one of those files: +\begin{itemize}[nosep] +\item |xint.pdf| (this file), +\item |sourcexint.pdf| (source code), +\item |README|, |README.pdf|, |README.html|, +\item |CHANGES.pdf|, and |CHANGES.html|. +\end{itemize} + +% For manual installation, follow the instructions from the |README| file which +% is to be found on \href{http://www.ctan.org/pkg/xint}{CTAN}; it is also +% available there in PDF and HTML formats. The simplest method proposed is to +% use the archive file \href{http://www.ctan.org/pkg/xint}{xint.tds.zip}, +% downloadable from the same location. + +% The next simplest one is to make use of the |Makefile|, which is also +% downloadable from +% \href{http://mirror.ctan.org/macros/generic/xint}{CTAN}. This is +% for GNU/Linux systems and Mac OS X, and necessitates use of the command +% line. If for some reason you have |xint.dtx| but no internet access, +% you can recreate |Makefile| as a file with this name and the following +% contents: + +% {\def\everbatimindent {0pt }% +% \begin{everbatim} +% include Makefile.mk +% Makefile.mk: xint.dtx ; etex xint.dtx +% \end{everbatim}} + +% Then run |make| in a working repertory where there is |xint.dtx| and the file +% named |Makefile| and having only the two lines above. The |make| will extract +% the package files from |xint.dtx| and display some further instructions. + +% If you have |xint.dtx|, no internet access and can not use the Makefile +% method: |etex xint.dtx| extracts all files and among them the |README| as a +% file with name |README.md|. Further help and options will be found therein. + +\subsection {Recent changes} + +This is release \expandafter|\xintbndlversion| of \expandafter|\xintbndldate|. + +For more information see +|CHANGES.html|.\centeredline{Internet: + \url{http://mirrors.ctan.org/macros/generic/xint/CHANGES.html}} + +The formatted source code is available in file |sourcexint.pdf|: +\centeredline{|texdoc sourcexint|} + +\noindent|1.3e| (|2019/04/05|): +\begin{itemize}[nosep] +\item An \xinttrigname library is automatically loaded by \xintexprname and + provides direct and inverse trigonometrical functions using either degrees + or radians (up to \dtt{60} digits). It is for the most part implemented + using high level user interface, but will probably get some optimizations in + future (and perhaps extension to more digits). +\item An \xintlogname library is loaded automatically; it uses + \href{http://ctan.org/pkg/poormanlog}{poormanlog} to provide logarithms and + exponentials. Support for more digits is planned for the future: the + \href{http://ctan.org/pkg/poormanlog}{poormanlog} support achieves only + about \dtt{8} or \dtt{9} digits of precision. On the other hand the + functions are fast. + Perhaps we will keep the current functions achieving limited precision under + some other names in future (they are amply precise enough for plots). +\item Under the hood refactoring of \csbxint{NewExpr} related matters for + support of user-defined functions; fixed bugs related to functions with no + variables. Added \csbxint{defefunc}, \csbxint{deffloatefunc}, + \csbxint{defiiefunc} and documented the ``protected'' nature of the + functions defined by the original variants \csbxint{deffunc} et al. This + whole area is complex and to be still considered work in progress. +\item Breaking change: only the \csbxint{expr}|...\relax| syntax is accepted + for sub-expressions when doing function definitions via \csbxint{deffunc} + and \csbxint{defefunc} et al. One can \textbf{not} use \csbxint{eval}, + \csbxint{ieval}, \csbxint{floateval} for sub-evaluations inside such + definitions (anyway there are not efficient there because the parser will + have to recollect the digits of the value whereas \csbxint{expr} keeps some + private internal format). +\item \func{inv}, \func{ilog10}. +\item \func{sfloat}, slight modification of behaviour of \func{qfloat}. +\item \csbxint{ensuredummy}, \csbxint{restorelettervar}. +\item the optional argument of \csbxint{floatexpr} can be negative, it then + tells to round the result to a (rounded) float with a precision equal to + \csbxint{theDigits} diminished by this argument. +\end{itemize} + +\noindent|1.3d| (|2019/01/06|): +\begin{itemize}[nosep] +\item \func{gcd} and \func{lcm} in \csbxint{expr}|...\relax| now handle + general arguments, without converting them to integers, +\item It is not needed anymore to load package \xintgcdname to benefit from + \func{gcd} and \func{lcm} in the parsers. +\item \csbxint{ifsgnexpr}, \csbxint{ifsgnfloatexpr}, \csbxint{ifsgniiexpr}. +\item \csbxint{unassignexprfunc} and variants for the other parsers. +\item \func{isone} and \func{isint}. +\item \csbxint{eval}, \csbxint{ieval}, \csbxint{iieval}, and + \csbxint{floateval}. Attention: these names were formerly used with some other + (barely documented) meanings, for which |\xintexpro|, |\xintiexpro|, + etc... are now used. +\item Sadly, in \csbxint{iiexpr}|...\relax| division with a zero dividend and + a one-digit divisor got broken at |1.2p|. Fixed. Thanks to \textsc{Kpym} for + report. Sorry for long delay in releasing the bugfix, which was done shortly + after |1.3c| release. +\end{itemize} + +\section{The syntax of \xintexprname expressions} +\label{sec:xintexprsyntax} + +\localtableofcontents + +\subsection{The three parsers}\label{ssec:threeparsers} + +There are three expression parsers and two subsidiary ones. They +all admit comma separated expressions, and will then output a comma +separated list of results. +\begin{itemize}[nosep] +\item \csbxint{theiiexpr}| ... \relax| does exact computations \emph{only on + integers.} The forward slash \dtt{/} does the \emph{rounded} integer + division to match behaviour of |\the\numexpr + <int>/<int>\relax|.\footnote{For floored integer division, see the \dtt{//} + operator.} There are two square root extractors \func{sqrt} and + \func{sqrtr} for truncated and rounded square roots. Scientific notation + |6.02e23| is \emph{not} accepted on input, one needs to wrap it as + |num(6.02e23)| which will convert to an integer notation + \dtt{\printnumber{\xinttheiiexpr num(6.02e23)\relax}}. +\item \csbxint{thefloatexpr}| ... \relax| does computations with a given + precision \dtt{P}, as specified via a prior assignment |\xintDigits:=P;|. + The default is \dtt{P=16} digits. An optional argument controls the + precision for \emph{formatting the output} (this is not the precision of the + computations themselves). The four basic operations and the square root + realize \emph{correct rounding.}\footnote{when the inputs are already + floating point numbers with at most |P|-digits mantissas.} +\item \csbxint{theexpr}| ... \relax| handles integers, decimal numbers, + numbers in scientific notation and fractions. The algebraic computations are + done \emph{exactly.} The \func{sqrt} function is available and obeys + either the |\xintDigits| precision or its second optional + argument. +\end{itemize} + +Two derived parsers: +\begin{itemize}[nosep] +\item \csbxint{theiexpr}| ... \relax| does all computations like |\xinttheexpr + ... \relax| but rounds the result to the nearest integer. With an optional + positive argument |[D]|, the rounding is to the nearest fixed point number + with |D| digits after the decimal mark. +\item \csbxint{theboolexpr}| ... \relax| does all computations like + |\xinttheexpr ... \relax| but converts the result to $1$ if it is not zero + (works also on comma separated expressions). + See also the booleans \csbxint{ifboolexpr}, \csbxint{ifbooliiexpr}, + \csbxint{ifboolfloatexpr}, \csbxint{ifsgnexpr}, \csbxint{ifsgniiexpr}, + \csbxint{ifsgnfloatexpr} (they do not handle comma separated expressions). +\end{itemize} + +Release |1.3d| provides \csbxint{eval}, \csbxint{ieval}, +\NewWith{1.3d} +\csbxint{iieval}, \csbxint{floateval}. + +\subsection{Built-in operators and their precedences} + + +\def\MicroFont{\ttbfamily\makestarlowast\color[named]{DarkOrchid}} + +\makeatletter +\def\@floatboxreset{\@setminipage}% faudra contrôler celui-là +\makeatother +\begin{table}[htbp] +\edef\restorehtdpstrutbox + {\ht\strutbox\the\ht\strutbox\dp\strutbox\the\dp\strutbox} +\ht\strutbox12pt\dp\strutbox5pt +\capstart + \centering\begin{tabular}{|c|p{.5\textwidth}|} + \hline + \multicolumn{2}{|p{.6\textwidth}|}{\prec{$\infty$}: + at this top level the non-operator syntax elements whose parsing + is always done prior to executing operators preceding them: + \begin{itemize}[nosep] + \item + \hyperref[ssec:builtinfunctions]{built-in} or + \hyperref[ssec:userfunctions]{user-defined} functions, + \item \hyperref[ssec:uservariables]{variables}, + \item and the intrinsic constituents of numbers: decimal mark |.|, |e| and |E| of scientific notation, hexadecimal prefix |"|. + \end{itemize}\par\kern-\baselineskip\relax}% + \\\hline\hline + Precedence&``Operators'' at this level\strut\\ + \hline + \prec{$10$}& the factorial (postfix) operator |!| and the conditional branching operators |?| and |??|\strut\\\hline + \prec{$=$}& the minus sign |-| as unary operator acquires the + precedence level of the previous infix operator\strut\\\hline + \prec{$9$}&the power |^|, |**| operators\strut\\\hline + \prec{$8$}&the action of tacit multiplication\strut\\\hline + \prec{$7$}&the multiplication, division, and modulo operators |*|, |/|, + |//|, |/:| (aka |'mod'|)\strut + \\\hline + \prec{$6$}&the addition and subtraction |+|, |-|\strut\\\hline + \prec{$5$}&the comparison operators |<|, |>|, |==|, |<=|, |>=|, |!=|\strut\\\hline + \prec{$4$}&Boolean conjunction |&&| and its alias |'and'|\strut\\\hline + \prec{$3$}&Boolean disjunction \verb+||+ and |'or'|, and |'xor'|; also the + sequence generators |..|, |..[|, |]..|, and the Python slicer |:| have + this precedence\strut\\\hline + \prec{$2$}& the comma |,|\strut\\\hline + \prec{$1$}& the parentheses |(|, |)|, list brackets |[|, |]|, semi-colon |;| in an \func{iter} or + \func{rseq}\strut\\\hline\hline + \multicolumn{2}{|p{.6\textwidth}|}{% + \begin{itemize}[nosep] + \item In case of equal precedence, the rule is left-associativity: the first +encountered operation is executed first. +\hyperref[ssec:tacit multiplication]{Tacit multiplication} has an elevated +precedence level hence seemingly breaks left-associativity: |(1+2)/(3+4)5| +is computed as |(1+2)/((3+4)*5)| and |x/2y| is interpreted as |x/(2*y)| +when using variables. + \item List variants |^[|, |**[|, |]^|, |]**|, + |*[|, |/[|, |]*|, |]/|, |+[|, |-[|, |]+|, |]-|, share the precedence + level of their respective associated operators on numbers. + \item There may + be some evolution in future, perhaps to distinguish some of the constructs + which currently share the same precedence or to make room for added syntax + elements. + \end{itemize} +}\\\hline + \end{tabular} + \caption{Precedence levels} + \label{tab:precedences} +\etoctoccontentsline {table}{\textbf{(table)} \protect\emph{Precedence levels of operators}} +\restorehtdpstrutbox +\end{table} + +The \autoref{tab:precedences} is hyperlinked to the more detailed discussion +at each level. + +\begin{description}[parsep=0pt,align=left,itemindent=0pt, + leftmargin=\leftmarginii, labelwidth=\leftmarginii, labelsep=0pt, + labelindent=0pt, listparindent=\leftmarginiii] + +\precdesc{\infty} At this highest level of precedence, one finds: +\begin{itemize}[parsep=0pt,align=left,itemindent=0pt, + leftmargin=\leftmarginii, labelwidth=\leftmarginii, labelsep=0pt, + labelindent=0pt, listparindent=\leftmarginiii] +\item \hyperref[ssec:builtinfunctions]{functions} and + \hyperref[ssec:uservariables]{variables}: + we approximately describe the situation as + saying they have highest precedence. Functions (even the logic functions + \func{!} and \func{?} whose names consists of a single non-letter character) + must be used with parentheses. These parentheses may arise from expansion + after the function name is parsed (there are exceptions which are documented + at the relevant locations.) +\item the |.| as decimal mark; the number scanner treats it as + an inherent, optional and unique component of a being formed number. One can + do things such as + % + \leftedline{\restoreMicroFont|\xinttheexpr 0.^2+2^.0\relax|} + % + which is |0^2+2^0| and produces \dtt{\xinttheexpr 0.^2+2^.0\relax}. + + Since release |1.2| an isolated decimal mark |"."| is illegal + input in |\xintexpr..\relax|, although it remains legal as argument to the + macros of \xintfracname. +\item the |e| and |E|, for scientific notation are intrinsic constituents of + number denotations, + like the decimal mark. +\item the |"| for hexadecimal numbers: it is allowed only at locations where + the parser expects to start forming a numeric operand, once encountered it + triggers the hexadecimal scanner which looks for successive hexadecimal + digits as usual skipping spaces and expanding forward everything; letters + (only |ABCDEF|, not |abcdef|), an optional dot + (allowed directly in front) and an optional (possibly empty) fractional + part. The |"| functionality + \fbox{requires to load package \xintbinhexname}.% +% +\begin{everbatim*} +\xinttheexpr "FEDCBA9876543210\relax\newline +\xinttheiexpr 16^5-("F75DE.0A8B9+"8A21.F5746+16^-5)\relax +\end{everbatim*} +\end{itemize} + +\precdesc{10} The postfix operators |!| and the branching conditionals |?|, |??|. + \begin{description}[parsep=0pt,align=left,itemindent=0pt, + leftmargin=\leftmarginii, labelwidth=\leftmarginii, labelsep=0pt, + labelindent=0pt, listparindent=\leftmarginiii] + + \item[{\color[named]{DarkOrchid}!}] computes the factorial of an integer. + Attention that the boolean equality test |==| must not follow directly + such a |<digits or variable>!| because the parser will handle |!=| as the + boolean inequality test... the remaining |=| then causes a parsing error. + It is even worse if one uses a single |=| following the |!| because no + error arises but an un-intended interpretation. Use parentheses: + |(3!)==10|. + + \item[{\color[named]{DarkOrchid}?}] is used as |(stuff)?{yes}{no}|. It + evaluates |stuff| and chooses the |yes| branch if the result is + non-zero, else it executes |no|. After evaluation of |stuff| it acts as + a macro with two mandatory arguments within braces, chooses the + correct branch \emph{without evaluating the wrong one}. Once the braces + are removed, the parser scans and expands the uncovered material so for + example + % + \leftedline{|\xinttheiexpr (3>2)?{5+6}{7-1}2^3\relax|} + % + is legal and computes + |5+62^3=|\dtt{\xinttheiexpr(3>2)?{5+(6}{7-(1}2^3)\relax}. It would be + better practice to include here the |2^3| inside the branches. The + contents of the branches may be arbitrary as long as once glued to what is + next the syntax is respected: {|\xintexpr (3>2)?{5+(6}{7-(1}2^3)\relax| + also works.} + + + \item[{\color[named]{DarkOrchid}??}] is used as |(stuff)??{<0}{=0}{>0}|, + where |stuff| is anything, its sign is evaluated and depending on the sign + the correct branch is un-braced, the two others are discarded with no + evaluation of their contents. The un-braced branch will then be parsed as + usual. + % + \leftedline{|\def\x{0.33}\def\y{1/3}|} + % + \leftedline{|\xinttheexpr (\x-\y)??{sqrt}{0}{1/}(\y-\x)\relax|% + \dtt{=\def\x{0.33}\def\y{1/3}% + \xinttheexpr (\x-\y)??{sqrt}{0}{1/}(\y-\x)\relax }} + % + \end{description} + +\precdesc{=} The minus sign |-| as prefix unary operator inherits the + precedence of the infix operator it follows. |\xintexpr -3-4*-5^-7\relax| + evaluates as |(-3)-(4*(-(5^(-7))))| and |-3^-4*-5-7| as + |(-((3^(-4))*(-5)))-7|. + + |2^-10| is perfectly accepted input, no need for parentheses + + + + \precdesc{9} The power operator |^|, or equivalently |**|. It is left + associative: {\restoreMicroFont|\xinttheiexpr 2^2^3\relax|} evaluates to + \xinttheiexpr 2^2^3\relax, not \xinttheiexpr 2^(2^3)\relax. See + \csbxint{FloatPower} for additional information. + + Also at this level the list operators |^[|, |**[|, |]^|, and |]**|. + +\precdesc{8} see \hyperref[ssec:tacit multiplication]{Tacit multiplication}. + +\precdesc{7} Multiplication and division |*|, |/|. The + division is left associative, too: + % + \begingroup\restoreMicroFont + % + |\xinttheiexpr 100/50/2\relax| evaluates to \xinttheiexpr 100/50/2\relax, + not \xinttheiexpr 100/(50/2)\relax. + % + \endgroup + + Also the floored division |//| and its associated modulo |/:| (equivalently |'mod'|, + quotes mandatory). + + Also at this level the list operators |*[|, |/[|, |]*| and |]/|. + + In an \csbxint{iiexpr}-ession, |/| does \emph{rounded} division, to behave + like the |/| of |\numexpr|. + + Infix operators all at the same level of precedence are + left-associative.\footnote{i.e. the first two operands are operated upon + first.} + Apply parentheses for disambiguation. +\begin{everbatim*} +\xinttheexpr 100000//13, 100000/:13, 100000 'mod' 13, trunc(100000/13,10), + trunc(100000/:13/13,10)\relax +\end{everbatim*} + +\precdesc{6} Addition and subtraction |+|, |-|. According to the rule above, |-| + is left associative: + % + \begingroup\restoreMicroFont + % + |\xinttheiexpr 100-50-2\relax| evaluates to \xinttheiexpr 100-50-2\relax, + not \xinttheiexpr 100-(50-2)\relax. + % + \endgroup + + Also the list operators |+[|, |-[|, |]+|, |]-| are at this precedence level. + +\precdesc{5} Comparison operators |<|, |>|, |=| (same as |==|), |<=|, |>=|, |!=| all + at the same level of precedence, use parentheses for disambiguation. + +\precdesc{4} Conjunction (logical and) |&&| or equivalently + |'and'| (quotes mandatory).% +% +\footnote{with releases earlier than |1.1|, only single + character operators |&| and \verb+|+ were available, because the parser + did not handle multi-character operators. Their usage in this rôle is now + deprecated,\IMPORTANT{} and they may be assigned some new meaning in the + future.} + +\precdesc{3} Inclusive disjunction (logical or) \verb+||+ + and equivalently |'or'| (quotes mandatory). + + Also the |'xor'| operator (quotes mandatory) is at this level. + + Also the list generation operators |..|, |..[|, |]..| are at this level. + + Also the |:| for Python slicing of lists. + +\precdesc{2} The comma: {\restoreMicroFont with |\xinttheexpr 2^3,3^4,5^6\relax| + one obtains as output \xinttheexpr 2^3,3^4,5^6\relax{}.}\footnote{The comma + is really like a binary operator, which may be called ``join''. It has + lowest precedence of all (apart the parentheses) because when it is + encountered all postponed operations are executed in order to finalize its + \emph{first} operand; only a new comma or a closing parenthesis or the end + of the expression will finalize its \emph{second} operand.} + +\precdesc{1} The parentheses. The list outer brackets |[|, |]| share the same + functional precedence as parentheses. The semi-colon |;| in an |iter| or + |rseq| has the same precedence as a closing parenthesis.\footnote{It is not + apt to describle the opening parenthesis as an operator, but the closing + parenthesis is more closely like a postfix unary operator. It has lowest + precedence because when it is encountered all postponed operations are + executed to finalize its operand. The start of this operand was decided by + the opening parenthesis.} +\end{description} + + +\restoreMicroFont + +\subsection{Built-in functions}\label{ssec:builtinfunctions} + + +See \autoref{tab:functions} whose elements are hyperlinked to the +corresponding definitions. + + Functions are at the same top level of priority. All functions even + \func{?} and \func{!} require parentheses around their arguments. + +% Table of functions + +\begin{table}[htbp] + \capstart + \centering +\xintAssignArray\xintCSVtoList{!, ?, |`*`|, |`+`|, +abs, add, all, any, acos, acosd, Arg, Argd, asin, asind, atan, atand, +atan2, atan2d, +binomial, bool, +ceil, cos, cosd, cot, cotd, cotg, csc, cscd, +divmod, even, exp, +factorial, first, float, floor, frac, gcd, +if, ifint, ifone, ifsgn, ilog10, isint, isone, iter, iterr, inv, +last, lcm, len, log, log10, max, min, mod, mul, not, num, odd, +pArg, pArgd, pfactorial, pow, pow10, preduce, +qfloat, qfrac, qint, qrand, qraw, quo, +random, randrange, reduce, rem, reversed, round, rrseq, rseq, +sec, secd, seq, sgn, sin, sinc, sind, sqr, sqrt, sqrtr, subs, +tan, tand, tg, togl, trunc, +xor} +\to\Functions + \cnta\Functions{0} + \cntb\xinttheexpr ceil(\cnta/4)\relax\space +\newcommand\builtinfunction[1]{\expandafter\expandafter\expandafter\func + \expandafter\expandafter\expandafter{\Functions{#1}}}% +\begin{tabular}{|*{4}{p{2.5cm}|}} + \hline + \xintFor* #1 in {\xintSeq{1}{\cntb}}\do + {\builtinfunction{#1}& + \builtinfunction{#1+\cntb}&% + \builtinfunction{#1+2*\cntb}&% + \ifnumgreater{#1+3*\cntb}{\cnta} + {} + {\builtinfunction{#1+3*\cntb}}% + \\\hline}% +\end{tabular} +\caption{Functions (click on names)}\label{tab:functions} +\etoctoccontentsline {table}{\textbf{(table)} \protect\emph{Functions in expressions}} +\etocsetnexttocdepth{subsubsection} +\localtableofcontents +\end{table} + + +Miscellaneous notes: +\begin{itemize}[nosep] + \item since release |1.3d| \func{gcd}\NewWith{1.3d} and \func{lcm} are extended to apply + to fractions too, and they do NOT require the loading of \xintgcdname, + + \item The randomness related functions \func{random}, \func{qrand} and + \func{randrange} require that the \TeX\ engine provides the + \csa{uniformdeviate} or \csa{pdfuniformdeviate} primitive. This is + currently the case for |pdftex|, |(u)ptex|, |luatex|, and will be for + |xetex| starting with \TeX Live 2019.\IMPORTANT + + \item \func{togl} is provided for the case |etoolbox| package is loaded, + + \item \func{bool}, \func{togl} use delimited macros to fetch their argument and the + closing parenthesis must be explicit, it can not arise from + on the spot expansion. The same holds for \func{qint}, \func{qfrac}, + \func{qfloat}, \func{qraw}, \func{random} and \func{qrand}. + + \item Also \hyperlink{ssec:dummies}{functions with dummy variables} use + delimited macros for some tasks. See the relevant explanations there. +\end{itemize} + + +% \begin{description}[parsep=0pt,align=left, +% leftmargin=0pt, itemindent=0pt, +% labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, +% %! leftmargin+itemindent="labelindent"+labelwidth+labelsep +% %! leftmargin=labelindent+labelwidth+labelsep* (enumitem) +% %! Utiliser \mbox{} et non pas \noindent\par pour bon display +% %! (enfin c'était nécessaire avant chgt dans keys ci-dessus, ai oublié ancien +% %! attention que listparindent n'est apparemment pas hérité, faut le refaire +% listparindent=\leftmarginiii] +\subsubsection{Functions with no argument} + +\begin{description} +% [parsep=0pt,align=left, +% leftmargin=0pt, itemindent=0pt, +% labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, +% listparindent=\leftmarginiii] + + \funcdesc[]{random} returns a random float |x| verifying |0 <= x < 1|. It obeys + the prevailing precision as set by \csbxint{Digits}: i.e. with |P| being the + precision the random float multiplied by |10^P| is an integer, uniformly + distributed in the |0..10^P-1| range.\NewWith{1.3b} + + This description implies that if |x| turns out to be |<0.1| then + its (normalized) mantissa has |P-1| digits and a trailing zero, if |x<0.01| + it has |P-2| digits and two trailing zeros, etc... This is what is observed + also with Python's |random()|, of course with |10| replaced there by radix + |2|.% +\begin{everbatim*} + \pdfsetrandomseed 12345 + \xintDigits:=37;% + \xintthefloatexpr random()\relax\newline + \xintthefloatexpr random()\relax\par +\end{everbatim*} + + \begin{framed} + Due to the way \csbxint{expr}|...\relax| are handled (see + \autoref{ssec:memory}), Monte-Carlo type simulations using expressions may + relatively easily exhaust \TeX{} memory.\IMPORTANT\ If possible use + \csbxint{NewFloatExpr} to construct from such expressions involving the + \func{random} function macros not creating the memory impact which is + described in \autoref{ssec:memory}. + \end{framed} + + \funcdesc[]{qrand} returns a random float |0 <= x < 1| using \dtt{16} digits of + precision (i.e. |10^{16}x| is an integer). This is provided when speed is a + at premium as it is optimized for precision being precisely \dtt{16}.% + \NewWith{1.3b} +\begin{everbatim*} + % still with 37 digits as prevailing float precision + \xintthefloatexpr qrand(), random()\relax\newline + \xintDigits:=16;% + \xintthefloatexpr qrand(), random()\relax\par +\end{everbatim*} + + One can use both |qrand()| and |random()| inside the |\xintexpr| parser too. + But inside the integer only |\xintiiexpr| parser they will cause some + low-level error as soon as they get involved in any kind of computation as + they use an internal format not recognized by the integer-only parser. + + See further \func{randrange}, which generates random integers. + + Currently there is no |uniform()| function% +% +\footnote{Because I am not sure how to handle rounding issues: should the + computation proceed exactly and a rounding be done only at very end?} +% + but it can be created by user: +\begin{everbatim*} +\xintdeffloatfunc uniform(a, b):= a + (b-a)*random(); +\romannumeral\xintreplicate{10}% +{% + \xintthefloatexpr uniform(123.45678, 123.45679)\relax\newline +}% +\end{everbatim*} + +\end{description} + +\subsubsection{Functions with a single (numeric) argument} + +\begin{description} +% [parsep=0pt,align=left, +% leftmargin=0pt, itemindent=0pt, +% labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, +% listparindent=\leftmarginiii] + + \funcdesc{num} truncates to the nearest integer (truncation towards zero). It + has the same sign as |x|, except of course with |-1<x<1| as then |num(x)| is + zero. +\begin{everbatim*} +\xinttheexpr num(3.1415^20), num(1e20)\relax +\end{everbatim*} + The output is an explicit integer with as many zeros are as necessary. Even + in float expressions, there will be an intermediate stage where all needed digits + are there, but then the integer is immediately reparsed as a float to the target + precision, either because some operation applies to it, or from the output + routine of \csbxint{floatexpr} if it stood there alone. Hence, + inserting something like |num(1e10000)| is costly as it really creates ten + thousand zeros, even though later the whole thing becomes a float again. On + the other hand naturally |1e10000| without |num()| would be simply parsed as + a floating point number and would cause no specific overhead. + + \funcdesc{frac} fractional part. + For all numbers |x=num(x)+frac(x)|, and |frac(x)| has the same sign as |x| + except when |x| is an integer, as then |frac(x)| vanishes. +\begin{everbatim*} +\xintthefloatexpr frac(-355/113), frac(-1129.218921791279)\relax +\end{everbatim*} + + \funcdesc{reduce} reduces a fraction to smallest terms +\begin{everbatim*} +\xinttheexpr reduce(50!/20!/20!/10!)\relax +\end{everbatim*} + +Recall that this is NOT done automatically, for example when adding fractions. + \funcdesc{preduce} internally, fractions may have some power of ten part + (for example when they got input in scientific notation). This function + ignores the decimal part when doing the reduction. See \csbxint{PIrr}. +\begin{everbatim*} +\xinttheexpr preduce(10e3/2), reduce(10e3/2)\relax +\end{everbatim*} + + \funcdesc{abs} absolute value + \funcdesc{sgn} sign. See also \csbxint{ifsgnexpr}. + \funcdesc{inv} inverse.\NewWith{1.3e} + \funcdesc{floor} floor function. + \funcdesc{ceil} ceil function. + \funcdesc{sqr} square. +\item[ilog10(x)]\hypertarget{func:ilog10-ii} + in |\xintiiexpr| the integer exponent $a$ such that $10^a\leq + \mathrm{abs}(x)< 10^{a+1}$;\NewWith{1.3e} returns (this may evolve in future) + \dtt{\xintiieval{ilog10(0)}} if $x$ vanishes (i.e. \dtt{0x7fff8000}). +\begin{everbatim*} +\xintiieval{ilog10(1), ilog10(-1234567), ilog10(-123456789123456789), ilog10(2**31)}\par +\end{everbatim*} + See \func{ilog10} for the behaviour in \csbxint{expr}-essions. + \item[sqrt(x)]\hypertarget{func:sqrt-ii} + in |\xintiiexpr|, truncated square root; in |\xintexpr| or + |\xintfloatexpr| this is the floating point square root, and there is an + optional second argument for the precision. See \func{sqrt}. + \funcdesc{sqrtr} available \emph{only} in |\xintiiexpr|, rounded square root. + \item[factorial(x)]\hypertarget{func:factorial-ii} factorial function (like the + post-fix |!| operator.) When used in |\xintexpr| or + |\xintfloatexpr| there is an optional second argument. See \func{factorial}. + \funcdesc{?} is the truth value, $1$ if non zero, $0$ if zero. Must use parentheses. + \funcdesc{!} is logical not, $0$ if non zero, $1$ if zero. Must use parentheses. + \funcdesc{not} logical not. + \funcdesc{even} is the evenness of the truncation |num(x)|. +\begin{everbatim*} +\xintthefloatexpr [3] seq((x,even(x)), x=-5/2..[1/3]..+5/2)\relax +\end{everbatim*} + + \funcdesc{odd} is the oddness of the truncation |num(x)|. +\begin{everbatim*} +\xintthefloatexpr [3] seq((x,odd(x)), x=-5/2..[1/3]..+5/2)\relax +\end{everbatim*} + + \funcdesc{isint} evaluates to 1 if |x| is an integer, to 0 if + not.\NewWith{1.3d} See \func{ifint}. +\begin{everbatim*} +$\xinttheexpr -5/3..[1/3]..+5/3\relax +\rightarrow \xinttheexpr seq(isint(x), x=-5/3..[1/3]..+5/3)\relax$ +\end{everbatim*} + + \funcdesc{isone} evaluates to 1 if |x| is 1, to 0 if not.\NewWith{1.3d} +See \func{ifone}. +\begin{everbatim*} +$\xintthefloatexpr subs(((x-1)/x, x/x, (x+1)/x), x=2**30)\relax +\rightarrow +\xintthefloatexpr seq(isone(y), y=subs(((x-1)/x, x/x, (x+1)/x), x=2**30))\relax$ +\end{everbatim*} + + \funcdesc{qint} belong with \func{qfrac}, \func{qfloat}, \func{qraw} to a + special category: + \begin{enumerate}[nolistsep] + \item They require the closing parenthesis of their argument to be + immediately visible, it can not arise from expansion. + \item They grab the argument and store it directly; the format must be + compatible with what is expected at macro level. + \item And in particular the argument can not be a variable, it has to be + numerical. + \end{enumerate} + + \func{qint} achieves the same result as |num|, but the argument is grabbed + as a whole without expansion and handed over to the + \csbxint{iNum} macro. The |q| stands for ``quick'', and |qint| is thought + out for use in \csbxint{iiexpr}|...\relax| with integers having dozens of + digits. + + Testing showed that using |qint()| starts getting advantageous for inputs + having more (or \fexpan ding to more) than circa \dtt{20} explicit digits. + But for hundreds of digits the input gain becomes a negligible + proportion of (for example) the cost of a multiplication. + + Leading signs and then + zeroes will be handled appropriately but spaces will not be systematically + stripped. They should cause no harm and will be removed as soon as the + number is used with one of the basic operators. This input mode \emph{does + not accept decimal part or scientific part}. +\begin{everbatim} +\def\x{....many many many ... digits}\def\y{....also many many many digits...} +\xinttheiiexpr qint(\x)*qint(\y)+qint(\y)^2\relax\par +\end{everbatim} + + \funcdesc{qfrac} does the same as \dtt{qint} excepts that it accepts + fractions, decimal numbers, scientific numbers as they are understood by + the macros of package \xintfracname. Thus, it is for use in + \csbxint{expr}|...\relax|. It is not usable within an + |\xintiiexpr|-ession, except if hidden inside functions such as + \dtt{round} or \dtt{trunc} which then produce integers acceptable to the + integer-only parser. It has nothing to do with |frac| (sigh...). + + \funcdesc{qfloat} does the same as \dtt{qfrac} and then converts to a float + with the precision given by the setting of |\xintDigits|. This can be used + in \csbxint{expr} to round a fraction as a float with the same result as + with the |float()| function (whereas using |\xintfloatexpr A/B\relax| + inside \csbxint{expr}|...\relax| would first round |A| and |B| to the + target precision); or it can be used inside + \csbxint{floatexpr}|...\relax| as a faster alternative to wrapping + the fraction in a sub-\csbxint{expr}-ession. + For example, the next two computations done with \dtt{16} digits + of precision do not give the same result: +\begin{everbatim*} +\xintthefloatexpr qfloat(12345678123456785001/12345678123456784999)-0.5\relax\newline +\xintthefloatexpr 12345678123456785001/12345678123456784999-0.5\relax\newline +\xintthefloatexpr 1234567812345679/1234567812345678-0.5\relax\newline +\xintthefloatexpr \xintexpr12345678123456785001/12345678123456784999\relax-0.5\newline +\end{everbatim*}% + because the second is equivalent to the third, whereas the + first one is equivalent to the fourth one. Equivalently one can use + |qfrac| to the same effect (the subtraction provoking the rounding of its + two arguments before further processing.) + + Note that if the input needs no special rounding, the internal form of the + output keeps a short mantissa (it does not add padding zeros to make it of + length equal to the float precision). For example |qfloat(2[20])| would + keep internally the input format.\CHANGED{1.3e} +\end{description} + +\subsubsection{Functions with an alphabetical argument} + +\begin{description} +% [parsep=0pt,align=left, +% leftmargin=0pt, itemindent=0pt, +% labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, +% listparindent=\leftmarginiii] + +\funcdesc[name]{bool} + returns + $1$ if the \TeX{} conditional |\ifname| would act as |\iftrue| and + $0$ otherwise. This works with conditionals defined by |\newif| (in + \TeX{} or \LaTeX{}) or with primitive conditionals such as + |\ifmmode|. For example: + % + \leftedline{|\xintifboolexpr{25*4-if(bool(mmode),100,75)}{YES}{NO}|} + % + will return $\xintifboolexpr{25*4-if(bool(mmode),100,75)}{YES}{NO}$ + if executed in math mode (the computation is then $100-100=0$) and + \xintifboolexpr{25*4-if(bool(mmode),100,75)}{YES}{NO} if not (the + \func{if} conditional is described below; the + \csbxint{ifboolexpr} test automatically encapsulates its first + argument in an |\xintexpr| and follows the first branch if the + result is non-zero (see \autoref{xintifboolexpr})). + + The alternative syntax |25*4-\ifmmode100\else75\fi| could have been + used here, the usefulness of |bool(name)| lies in the availability + in the |\xintexpr| syntax of the logic operators of conjunction + |&&|, inclusive disjunction \verb+||+, negation |!| (or |not|), of + the multi-operands functions |all|, |any|, |xor|, of the two + branching operators |if| and |ifsgn| (see also |?| and |??|), which + allow arbitrarily complicated combinations of various |bool(name)|. +\funcdesc[name]{togl} + returns $1$ + if the \LaTeX{} package \href{http://www.ctan.org/pkg/etoolbox}{etoolbox}% + % + % +% +\footnote{\url{http://www.ctan.org/pkg/etoolbox}} + % + has been used to define a toggle named |name|, and this toggle is + currently set to |true|. Using |togl| in an |\xintexpr..\relax| + without having loaded + \href{http://www.ctan.org/pkg/etoolbox}{etoolbox} will result in an + error from |\iftoggle| being a non-defined macro. If |etoolbox| is + loaded but |togl| is used on a name not recognized by |etoolbox| + the error message will be of the type ``ERROR: Missing |\endcsname| + inserted.'', with further information saying that |\protect| should + have not been encountered (this |\protect| comes from the expansion + of the non-expandable |etoolbox| error message). + + When |bool| or |togl| is encountered by the |\xintexpr| parser, the + argument enclosed in a parenthesis pair is expanded as usual from + left to right, token by token, until the closing parenthesis is + found, but everything is taken literally, no computations are + performed. For example |togl(2+3)| will test the value of a toggle + declared to |etoolbox| with name |2+3|, and not |5|. Spaces are + gobbled in this process. It is impossible to use |togl| on such + names containing spaces, but |\iftoggle{name with spaces}{1}{0}| + will work, naturally, as its expansion will pre-empt the + |\xintexpr| scanner. + + There isn't in |\xintexpr...| a |test| function available analogous + to the |test{\ifsometest}| construct from the |etoolbox| package; + but any \emph{expandable} |\ifsometest| can be inserted directly in + an |\xintexpr|-ession as |\ifsometest10| (or |\ifsometest{1}{0}|), + for example |if(\ifsometest{1}{0},YES,NO)| (see the |if| operator + below) works. + + A straight |\ifsometest{YES}{NO}| would do the same more + efficiently, the point of |\ifsometest10| is to allow arbitrary + boolean combinations using the (described later) \verb+&&+ and + \verb+||+ logic operators: + \verb+\ifsometest10 && \ifsomeothertest10 || \ifsomethirdtest10+, + etc... |YES| or |NO| above stand for material compatible with the + |\xintexpr| parser syntax. + + See also \csbxint{ifboolexpr}, in this context. +\end{description} + +\subsubsection{Functions with one mandatory and a second but optional argument} + +\begin{description} +% [parsep=0pt,align=left, +% leftmargin=0pt, itemindent=0pt, +% labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, +% listparindent=\leftmarginiii] + + \funcdesc[{x[, n]}]{round} Rounds its first argument to a fixed point number, having a + number of digits + after decimal mark given by the second argument. For example + |round(-2^9/3^5,12)=|\dtt{\xinttheexpr round(-2^9/3^5,12)\relax.} + \funcdesc[{x[, n]}]{trunc} Truncates its first argument to a fixed point number, having + a number of digits + after decimal mark given by the second argument. For example + |trunc(-2^9/3^5,12)=|\dtt{\xinttheexpr trunc(-2^9/3^5,12)\relax.} + \funcdesc[{x[, n]}]{float} Rounds its first argument to a floating point number, with a + precision given by the second argument. + |float(-2^9/3^5,12)=|\dtt{\xinttheexpr float(-2^9/3^5,12)\relax.} + + % AUCTeX EXTREMEMENT PENIBLE AVEC L'INDENTATION FORCEE SOUS M-q + + Note for this example and the earlier ones that when the surrounding + parser is \csbxint{floatexpr}|...\relax| the fraction first argument (here + |2^9/3^5|) will already have been computed as floating point number (with + numerator and denominator handled separately first), even before the + second argument is seen and a fortiori before the |round|, |trunc| or + |float| is executed. The general float precision is the one governing + these initial steps. To avoid that, use |\xintexpr2^9/3^5\relax| wrapper. + Then the rounding or truncation will be applied on the exact fraction. + + \funcdesc[{x[, n]}]{sfloat} It is the same as \func{float},\NewWith{1.3e} + but in case of a short (non-fractional) input it gets stored internally + without adding zeros to make the mantissa have the \csbxint{theDigits} + length. One may wonder then what is the utility of \func{sfloat}? See for + an example of use the documentation of \csbxint{deffunc}. Notice however + that this is a bit experimental and may evolve in future when \xintname + gets a proper internal data structure for floating point numbers. The + non-normalized format is useful for multiplication or division, but float + additions and subtractions usually convert their arguments to a normalized + mantissa. + + \funcdesc[{x[, n]}]{ilog10} If there is an optional argument |n|, returns the (relative) integer $a$ such that $10^a\leq + \mathrm{abs}(float(x, n)) < 10^{a+1}$.\NewWith{1.3e} In absence of the + optional argument: + \begin{itemize}[nosep] + \item in \csbxint{expr}, it returns the exponent $a$ such that $10^a\leq + \mathrm{abs}(x) < 10^{a+1}$. + \item in \csbxint{floatexpr}, the input is first rounded to + \csbxint{theDigits} float precision, then the exponent $a$ is evaluated. + \end{itemize} +\begin{everbatim*} +\xintfloateval{ilog10(99999999/10000000, 8), ilog10(-999999995/100000000, 8), + ilog10(-999999995/100000000, 9)}\newline +\xinteval{ilog10(-999999995/100000000), ilog10(-999999995/100000000, 8)} +\end{everbatim*} + + If the input vanishes the function outputs + \dtt{\xinteval{ilog10(0)}} (i.e. |-0x7fff8000| which is near the + minimal TeX number |-0x7fffffff|). This is also subject to change. + + The \hyperlink{func:ilog10-ii}{integer-only} variant for \csbxint{iiexpr} + admits no optional argument. + + \funcdesc[{x[, n]}]{sqrt} in \csa{xintexpr}|...\relax| and \csa{xintfloatexpr}|...\relax| + it achieves the precision given by the optional second argument. For + legacy reasons the |sqrt| function in \csa{xintiiexpr} \emph{truncates} + (to an integer), whereas |sqrt| in \csa{xintfloatexpr}|...\relax| (and in + \csa{xintexpr}|...\relax| which borrows it) \emph{rounds} (in the sense of + floating numbers). There is |sqrtr| in \csa{xintiiexpr} for + \emph{rounding} to nearest integer. +\begin{everbatim*} +\xinttheexpr sqrt(2,31)\relax\ and \xinttheiiexpr sqrt(num(2e60))\relax +\end{everbatim*} + + There is an \hyperlink{func:sqrt-ii}{integer only} variant for + \csbxint{iiexpr}. + + \funcdesc[{x[, n]}]{factorial} when the second optional argument is made + use of inside \csa{xintexpr}|...\relax|, this switches to the use of the + float version, rather than the exact one. +\begin{everbatim*} +\xinttheexpr factorial (100,32)\relax, {\xintDigits:=32;\xintthefloatexpr + factorial (100)\relax}\newline +\xinttheexpr factorial (50)\relax\newline +\xinttheexpr factorial (50, 32)\relax +\end{everbatim*} + + The \hyperlink{func:factorial-ii}{integer only variant} of course has no + optional second argument. + + \funcdesc[{A[, B]}]{randrange} when used with a single argument |A| returns a random + integer |0 <= x < A|, and when used with two arguments |A| and |B| returns + a random integer |A <= x < B|. As in Python it is an «empty range» error + in first case if |A| is zero or negative and in second case if |B <= A|. + \NewWith{1.3b} + + The function can be used in all three parsers. Of course the size is not + limited (but in the float parser, the integer will be rounded if involved + in any operation). +\begin{everbatim*} + \pdfsetrandomseed 12345 + \xinttheiiexpr randrange(10**20)\relax\newline + \xinttheiiexpr randrange(1234*10**16, 1235*10**16)\relax\newline + \printnumber{\xinttheiiexpr randrange(10**199,10**200)\relax}\par +\end{everbatim*} + For the support macros see \csbxint{RandomDigits}, \csbxint{iiRandRange}, + \csbxint{iiRandRangeAtoB}. For some details regarding how \xintname + uses the engine provided generator of pseudo-random numbers, see + \csbxint{UniformDeviate}. + + \end{description} + +\subsubsection{Functions with two arguments} + +\begin{description} +% [parsep=0pt,align=left, +% leftmargin=0pt, itemindent=0pt, +% labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, +% listparindent=\leftmarginiii] + + \funcdesc[f, g]{quo} first truncates the arguments to convert them to integers then + computes the Euclidean quotient. Hence it computes an integer. + \funcdesc[f, g]{rem} first truncates the arguments to convert them to integers then + computes the Euclidean remainder. Hence it computes an integer. + + \funcdesc[f, g]{mod} computes |f - g*floor(f/g)|. Hence its output is a + general fraction or floating point number or integer depending on the parser + where it is used. + + Prior to |1.2p| it computed |f - g*trunc(f/g)|. + + The |/:| and |'mod'| infix operators are both mapped to the same underlying + macro as this |mod(f, g)| function. At |1.3| this macro produces smaller + denominators when handling fractions than formerly.\CHANGED{1.3} +\begin{everbatim*} +\xinttheexpr mod(11/7,1/13), reduce(((11/7)//(1/13))*1/13+mod(11/7,1/13)), +mod(11/7,1/13)- (11/7)/:(1/13), (11/7)//(1/13)\relax\newline +\xintthefloatexpr mod(11/7,1/13)\relax\par +\end{everbatim*} + + Attention! the precedence rules mean that |29/5 /: 3/5| is handled like + |((29/5)/:3)/5|. This is coherent with behaviour of Python language for + example: +\begin{everbatim} +>>> 29/5 % 3/5, 11/3 % 17/19, 11/57 +(0.5599999999999999, 0.19298245614035087, 0.19298245614035087) +>>> (29/5) % (3/5), (11/3) % (17/19), 5/57 +(0.4, 0.08771929824561386, 0.08771929824561403) +\end{everbatim} + For comparison (observe on the last lines how |\xintfloatexpr| is more accurate than + Python!): +\begin{everbatim*} +\noindent\xinttheexpr 29/5 /: 3/5, 11/3 /: 17/19\relax\newline + \xinttheexpr (29/5) /: (3/5), (11/3) /: (17/19)\relax\newline + \xintthefloatexpr 29/5 /: 3/5, 11/3 /: 17/19, 11/57\relax\newline + \xintthefloatexpr (29/5) /: (3/5), (11/3) /: (17/19), 5/57\relax\newline + 5/57 = \xinttheexpr trunc(5/57, 20)\relax\dots\newline +\end{everbatim*}% + Regarding some details of behaviour in |\xintfloatexpr|, see discussion of + |divmod| function next. + + \funcdesc[f, g]{divmod} computes the two mathematical values |floor(f/g)| and + |mod(f,g)=f - g*floor(f/g)| and produces them separated with a comma, in + other terms it is analogous to the Python |divmod| function. Its output is + equivalent to using |f//g, f/:g| but its implementation avoids doing twice + the needed division. + + In |\xintfloatexpr...\relax| the modulo is rounded to the prevailing + precision. The quotient is like in the other parsers an exact integer. It + will be rounded as soon as it is used in further operations, or via the global + output routine of |\xintfloatexpr|. +\begin{everbatim*} +\xintdefvar Q, R := divmod(3.7, 1.2);% +\xinttheexpr Q, R, 1.2Q + R\relax\newline +\xintdefiivar Q, R := divmod(100, 17);% +\xinttheiiexpr Q, R, 17Q + R\relax\newline +\xintdeffloatvar Q, R := divmod(100, 17e-20);% +\xintthefloatexpr Q, R, 17e-20 * Q + R\relax\newline +% show Q exactly, although defined as float it can be used in iiexpr: +\xinttheiiexpr Q\relax\ (we see it has more than 16 digits)\par +\xintunassignvar{Q}\xintunassignvar{R}% +\end{everbatim*} + + Again: |f//g| or the first item output by |divmod(f, g)| is an integer |q| + which when computed inside |\xintfloatexpr..\relax| is not yet rounded to + the prevailing float precision; the second item |f-q*g| is the rounding to + float precision of the exact mathematical value evaluated with this exact + |q|. \emph{This behaviour may change in future major release;\IMPORTANT{} + perhaps |q| will be rounded and |f-q*g| will correspond to usage of this + rounded |q|.} + + As |\xintfloatexpr| rounds its global result, or rounds operands at + each arithmetic operation, it requires special circumstances to show that + the |q| is produced unrounded. Either as in the above example or this one + with comparison operators: +\begin{everbatim*} +\xintDigits := 4;% +\xintthefloatexpr if(12345678//23=537000, 1, 0), 12345678//23\relax\newline +\xintthefloatexpr if(float(12345678//23)=537000, 1, 0)\relax\par +\xintDigits := 16;% +\end{everbatim*} + In the first line, the comparison is done with + |floor(12350000/23)|\dtt{=\xinttheiiexpr12350000/23\relax} (notice in + passing that |12345678//23| was evaluated as |12350000//23| because the + operands are first rounded to prevailing precision), hence the conditional + takes the "False" branch. In the second line the |float| forces rounding of + the output to \dtt{4} digits, and the conditional takes the "True" branch. + +% pour mémoire, Python : +% >>> divmod(100,17e-20) +% (5.88235294117647e+20, 1.4756182441723705e-19) +% mais faudra voir avec le module Decimal + + This example shows also that comparison operators in + |\xintfloatexpr..\relax| act on unrounded operands. + + \funcdesc[x, y]{binomial} computes binomial coefficients. + It returns zero if |y<0| or |x<y| and raises an error if |x<0| (or if + |x>99999999|.) +\begin{everbatim*} +\xinttheexpr seq(binomial(20, i), i=0..20)\relax +\end{everbatim*} +\begin{everbatim*} +\printnumber{\xintthefloatexpr seq(binomial(100, 50+i), i=-5..+5)\relax}% +\end{everbatim*} + +The arguments must be (expand to) short integers. + \funcdesc[a, b]{pfactorial} computes partial factorials i.e. + |pfactorial(a,b)| evaluates the product |(a+1)...b|. +\begin{everbatim*} +\xinttheexpr seq(pfactorial(20, i), i=20..30)\relax +\end{everbatim*} + +The arguments must (expand to) short integers. See \autoref{xintiiPFactorial} +for the behaviour if the arguments are negative. + + \end{description} + +\subsubsection{Functions with 3 or 4 arguments} + +\begin{description} +% [parsep=0pt,align=left, +% leftmargin=0pt, itemindent=0pt, +% labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, +% listparindent=\leftmarginiii] + + \funcdesc[cond,yes,no]{if} (twofold-way conditional)\mbox{} + + checks if |cond| is true or false and takes the corresponding + branch. Any non zero number or fraction is logical true. The zero + value is logical false. Both ``branches'' are evaluated (they are + not really branches but just numbers). See also the |?| operator. + + \funcdesc[x,yes,no]{ifint} (twofold-way conditional)\mbox{} + + checks if |x| is an integer and in that case chooses the ``yes'' branch.% + \NewWith{1.3a} + See also \func{isint}. + + \funcdesc[x,yes,no]{ifone} (twofold-way conditional)\mbox{} + + checks if |x| is equal to one and in that case chooses the ``yes'' branch.% + \NewWith{1.3a} + Slightly more efficient than |if(x==1,..,..)|. See also \func{isone}. + + \funcdesc[cond,<0,=0,>0]{ifsgn} (threefold-way conditional)\mbox{} + + checks the sign of |cond| and + proceeds correspondingly. All three are evaluated. See also the |??| + operator. + + \end{description} + +\subsubsection{Functions with an arbitrary number of arguments} + + Except for \func{qraw}, this argument may be generated by one or many + |a..b| or |a..[d]..b| constructs, separated by commas. + +\begin{description} +% [parsep=0pt,align=left, +% leftmargin=0pt, itemindent=0pt, +% labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, +% listparindent=\leftmarginiii] + + \funcdesc[a,b,c,...,z]{qraw} is provided for comma separated values. The + input must obide by the suitable format depending on the + parser:\NewWith{1.3c} strict integers, or raw fractions, or floats in + internal (non-documented) notation. Also, avoid spaces around the commas. + The usefulness is when some loop generates hundreds of comma separated + values. Without \func{qraw}, each new value means a new usage of a + |\csname..\endcsname| for storage of the growing list, with potential + impact on \TeX{} memory (see \autoref{ssec:memory}). See \func{qint}, + \func{qfrac}, \func{qfloat}, the difference being that \func{qraw} does + no post-processing at all of its input, apart from complete expansion. + This allows it to accept comma separated values, as the internal storage + also uses commas. + +\funcdesc[x, y, ...]{all} inserts a logical |AND| in-between its arguments and evaluates the +resulting logical assertion (as for all functions, all arguments are +evaluated, see the |?| operator for ``lazy'' conditional branching; an example +is to be found in \autoref{ssec:PrimesIV}.) +\funcdesc[x, y, ...]{any} inserts a logical |OR| in-between its arguments and evaluates the +resulting logical assertion, +\funcdesc[x, y, ...]{xor} inserts a logical |XOR| in-between its arguments and evaluates +the resulting logical assertion, +\funcdesc[x, y, ...]{|`+`|} adds (left ticks mandatory): +\begin{everbatim*} +\xinttheexpr `+`(1,3,19), `+`(1*2,3*4,19*20)\relax +\end{everbatim*} +\funcdesc[x, y, ...]{|`*`|} multiplies (left ticks mandatory): +\begin{everbatim*} +\xinttheexpr `*`(1,3,19), `*`(1^2,3^2,19^2), `*`(1*2,3*4,19*20)\relax +\end{everbatim*} +\funcdesc[x, y, ...]{max} maximum of the (arbitrarily many) arguments, + +\funcdesc[x, y, ...]{min} minimum of the (arbitrarily many) arguments, + +\funcdesc[x, y, ...]{gcd} computes the positive generator of the fractional +ideal of rational numbers $x\mathbb Z + y\mathbb Z + ... \subset \mathbb +Q$.\CHANGED{1.3d} When the inputs are integers it is advantageous to use a sub +\csbxint{iiexpr}-ession, as the integer-only macro is more efficient than the +one accepting general fractional inputs. Notice that this may require some +\func{num} wrapper when using variables, as they may well be in fraction +format, and \csbxint{iiexpr} accepts only strict integers. Since |1.3d|, this +function and \func{lcm} are available whether or not package \xintgcdname is +loaded. Note that like other operations with fractions it does not always +produce a fraction in irreducible format. This example shows also how to +reduce an n-uple to its primitive part: +\begin{everbatim*} +\xinttheexpr gcd(7/300, 11/150, 13/60)\relax\newline +$(7/300, 11/150, 13/60)\to +(\xinttheexpr seq(reduce(x), x = [7/300, 11/150, 13/60]/gcd(7/300, 11/150, 13/60))\relax)$ +\end{everbatim*} + +Perhaps a future release will provide a |primpart()| function as built-in +functionality. + +\funcdesc[x, y, ...]{lcm} computes the positive generator of the +fractional ideal of rational numbers $x\mathbb Z \cap y\mathbb Z \cap ... +\subset \mathbb Q$.\CHANGED{1.3d} When the inputs are integers it is +advantageous to use a sub \csbxint{iiexpr}-ession, as the integer-only macro +is more efficient than the one accepting general fractional inputs. +\begin{everbatim*} +\xinttheexpr lcm(7/300, 11/150, 13/60)\relax +\end{everbatim*} + +\funcdesc[x, y, ...]{first} first item of the list argument: +\begin{everbatim*} +\xinttheiiexpr first(last(-7..3), 58, 97..105)\relax +\end{everbatim*} +\funcdesc[x, y, ...]{last} last item of the list argument: +\begin{everbatim*} +\xinttheiiexpr last(-7..3, 58, first(97..105))\relax +\end{everbatim*} +\funcdesc[x, y, ...]{reversed} reverses the order of the comma separated list: +\begin{everbatim*} +\xinttheiiexpr first(reversed(123..150)), last(reversed(123..150))\relax +\end{everbatim*} +\funcdesc[x, y, ...]{len} computes the number of items in a comma separated + list. Earlier syntax was |[a,b,...,z][0]| but since |1.2g| this now returns + the first element of the list. +\begin{everbatim*} +\xinttheiiexpr len(1..50, 101..150, 1001..1050)\relax +\end{everbatim*} + \end{description} + +\subsubsection{Functions requiring dummy variables} +\hypertarget{ssec:dummies}{} + +The ``functions'' \xintFor #1 in {add, mul, seq, subs, rseq, iter, rrseq, + iterr} \do {\func{#1}\xintifForLast{}{, }} use delimited macros to +identify the ``|,<letter>=|'' part.\footnote{In the current implementation any + token can be used rather than a |=|. What is looked for is a comma followed + by two tokens, the first one will be the |<letter>|.} This is done in a way +allowing nesting via correctly balanced parentheses. The |<letter>| must not +have been assigned a value before via \csbxint{defvar}. + +This |,<letter>=| must be visible when the parser has finished absorbing the +function name and the opening parenthesis. For \func{rseq}, \func{iter}, +\func{rrseq} and \func{iterr} this is delayed to after the parser has +assimilated a starting part delimited by a semi-colon; this mandatory segment +may be generated entirely by expansion and the |,<letter>=| may appear during +this expansion. + +After |,<letter>=|, the expansion and parsing will generate a list of values +(for example from an |a..b| specification, there may be multiple ones +themselves separated by commas). After this step is complete the parser will +know the values which will be assigned to |<letter>|. The special +|<letter>=<integer>++| syntax offers a variant not pre-computing the iterated +over list (which currently must thus proceed by steps of one.) + +\func{seq}, \func{rseq}, \func{iter}, \func{rrseq}, +\func{iterr} but not \func{add}, \func{mul}, \func{subs} admit the +\keyword{omit}, \keyword{abort}, and \keyword{break}|()| keywords. In the case +of a potentially infinite list generated by the |<integer>++| syntax, use of +\keyword{abort} or of \keyword{break}|()| is mandatory, naturally. + +Dummy variables are necessarily single-character letters, and all lowercase and +uppercase Latin letters are pre-configured for that usage. + +\begin{description} +% [parsep=0pt,align=left, +% leftmargin=0pt, itemindent=0pt, +% labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, +% listparindent=\leftmarginiii] + +\funcdesc[expr, letter=values]{subs} for variable substitution +\begin{everbatim*} +\xinttheexpr subs(subs(seq(x*z,x=1..10),z=y^2),y=10)\relax\newline +\end{everbatim*}% +Attention that |xz| generates an error, one must use explicitely |x*z|, else +the parser expects a variable with name |xz|. + +|subs| is useful when defining macros for which some argument will be used +more than once but may itself be a complicated expression or macro, and should +be evaluated only once, for matters of efficiency. + +The substituted variable may be a comma separated list (this is impossible +with |seq| which will always pick one item after the other from a list). +\begin{everbatim*} +\xinttheexpr subs([x]^2,x=-123,17,32)\relax +\end{everbatim*} + +See the examples related to the |3x3| determinant in the +\autoref{xintNewExpr} for an illustration of list substitution. + +\funcdesc[expr, letter=values]{add} addition +\begin{everbatim*} +\xinttheiiexpr add(x^3,x=1..50), add(x(x+1), x=1,3,19)\relax\newline +\end{everbatim*}% +See |`+`| for syntax without a dummy variable. + +\funcdesc[expr, letter=values]{mul} multiplication +\begin{everbatim*} +\xinttheiiexpr mul(x^2, x=1,3,19), mul(2n+1,n=1..10)\relax\newline +\end{everbatim*}% +See |`*`| for syntax without a dummy variable. + +\funcdesc[expr, letter=values]{seq} comma separated values generated according to a formula +\begin{everbatim*} +\xinttheiiexpr seq(x(x+1)(x+2)(x+3),x=1..10), `*`(seq(3x+2,x=1..10))\relax +\end{everbatim*} +\begin{everbatim*} +\xinttheiiexpr seq(seq(i^2+j^2, i=0..j), j=0..10)\relax +\end{everbatim*} + +\funcdesc[initial value; expr, letter=values]{rseq} recursive sequence, |@| for the previous value. +\begin{everbatim*} +\printnumber {\xintthefloatexpr subs(rseq (1; @/2+y/2@, i=1..10),y=1000)\relax }\newline +\end{everbatim*}% + Attention: in the example above |y/2@| is interpreted as + |y/(2*@)|.\IMPORTANT{} With versions |1.2c| or earlier it would have been + interpreted as |(y/2)*@|. + +In case the initial stretch is a comma separated list, |@| refers at the first +iteration to the whole list. Use parentheses at each iteration to maintain +this ``nuple''. For example: +\begin{everbatim*} +\printnumber{\xintthefloatexpr rseq(1,10^6; + (sqrt([@][0]*[@][1]),([@][0]+[@][1])/2), i=1..7)\relax } +\end{everbatim*} + +\funcdesc[initial value; expr, letter=values]{iter} is exactly like |rseq|, except that it only prints + the last iteration. Strangely it was lacking from |1.1| release, or rather + what was available from |1.1| to |1.2f| is what is called now \func{iterr} + (described below). + +\hypertarget{BrentSalamin}{} + The new |iter()| is convenient to handle compactly higher order iterations. + We can illustrate its use with an expandable (!) + implementation of the Brent-Salamin algorithm for the computation of $\pi$: +\begin{everbatim*} +\xintDigits:= 91; +\xintdeffloatfunc BS(a, b, t, p):= (a+b)/2, sqrt(a*b), t-p(a-b)^2, \xintiiexpr 2p\relax; +\xintthefloatexpr [88] % use 3 guard digits (output value is *rounded*) + iter(1, 1/sqrt(2), 1, 1; % initial values + ([@][0]-[@][1]<2[-45])? % if a-b is small enough stop iterating and ... + {break(([@][0]+[@][1])^2/[@][2])} % ... do final computation, + {BS(@)}, % else do iteration via pre-defined (for convenience) function BS. + i=1++) % This generates infinite iteration. The i is not used. +\relax +\xintDigits:=16;% +\end{everbatim*}\newline + You can try with |\xintDigits:=1001;| and |2[-501]| in place of + |\xintDigits:=91;| and |2[-45]|, but don't make a final rounding to only + |88| digits of course ... and better wrap the whole thing in |\message| or + |\immediate\write128| because it will run in the right margin (about + \dtt{7}s on my laptop last time I tried). By the way here is how the |BS| + function is defined internally: +\begin{everbatim} + Function BS for \xintfloatexpr parser associated to \XINT_flexpr_userfunc_B +S with meaning macro:#1#2#3#4->\XINTinFloatDiv {\XINTinFloatAdd {#1}{#2}}{2},\X +INTinFloatSqrtdigits {\XINTinFloatMul {#1}{#2}},\XINTinFloatSub {#3}{\XINTinFlo +atMul {#4}{\XINTinFloatPowerH {\XINTinFloatSub {#1}{#2}}{2}}},\xintiiMul {2}{#4 +} +\end{everbatim} + + + +\funcdesc[initial values; expr, letter=values]{rrseq} recursive sequence with multiple initial terms. Say, there are + |K| of them. Then |@1|, ..., |@4| and then |@@(n)| up to |n=K| refer to the + last |K| values. Notice the difference with |rseq| for which |@| refers to + the complete list of all initial terms if there are more than one and may + thus be a ``list'' object. This is impossible with |rrseq|. This construct + is effective for scalar finite order recursions, and may be perhaps a bit + more efficient than using the |rseq| syntax with a ``list'' value. +\begin{everbatim*} +\xinttheiiexpr rrseq(0,1; @1+@2, i=2..30)\relax +\end{everbatim*} +\begin{everbatim*} +\xinttheiiexpr rseq(1; 2@, i=1..10)\relax +\end{everbatim*} +\begin{everbatim*} +\xinttheiiexpr rseq(1; 2@+1, i=1..10)\relax +\end{everbatim*} +\begin{everbatim*} +\xinttheiiexpr rseq(2; @(@+1)/2, i=1..5)\relax +\end{everbatim*} + +\begin{everbatim*} +\xinttheiiexpr rrseq(0,1,2,3,4,5; @1+@2+@3+@4+@@(5)+@@(6), i=1..20)\relax +\end{everbatim*} + +I implemented an |Rseq| which at all times keeps the memory of \emph{all} +previous items, but decided to drop it as the package was becoming big. + +\funcdesc[initial values; expr, letter=values]{iterr} same as |rrseq| but does not print any value until the last |K|. +\begin{everbatim*} +\xinttheiiexpr iterr(0,1; @1+@2, i=2..5, 6..10)\relax +% the iterated over list is allowed to have disjoint defining parts. +\end{everbatim*} +\end{description} + +Recursions may be nested, with |@@@(n)| giving access to the values of the +outer recursion\dots and there is even |@@@@(n)| to access the outer outer +recursion but I never tried it! + +The following keywords may be placed within the generating expression of a +\func{seq}, \func{rseq}, \func{iter}, \func{rrseq}, or +\func{iterr}: : +\begin{description} + \keyworddesc{abort} stop here and now. + + \keyworddesc{omit} omit this value. + + \keyworddesc{break} |break(stuff)| to abort and have |stuff| as last value. + + \keyworddesc{<integer>++} serves to generate a potentially infinite list. In + conjunction with an \keyword{abort} or \keyword{break}|()| this is often + more efficient than iterating over a pre-established list of values. +\begin{everbatim*} +\xinttheiiexpr iter(1;(@>10^40)?{break(@)}{2@},i=1++)\relax +\end{everbatim*} +is the smallest power of 2 with at least fourty one digits. + +The |i=<integer>++| syntax (any letter is allowed in place of |i|) works only +in the form |<letter>=<integer>++|, something like |x=10,17,30++| is not +legal. The |<integer>| must be a \TeX-allowable integer. +\begin{everbatim*} +First Fibonacci number at least |2^31| and its index +% we use iterr to refer via @1 and @2 to the previous and previous to previous. +\xinttheiiexpr iterr(0,1; (@1>=2^31)?{break(i)}{@2+@1}, i=1++)\relax +\end{everbatim*} +\end{description} + +Some additional examples are to be found in \autoref{ssec:moredummies}. + +\subsubsection{Trigonometrical functions} + +See \xinttrigname. + +\subsubsection{Logarithm, exponential and power functions} + +See \xintlogname. + +\subsection{Tacit multiplication} +\label{ssec:tacit multiplication} + +Tacit multiplication (insertion of a |*|) applies when the parser is currently +either scanning the digits of a number (or its decimal part or scientific +part, or hexadecimal input), or is looking for an infix operator, and: +\begin{enumerate}[nosep, label=(\arabic*.)] +\item \relax\emph{encounters a count or dimen or skip register or variable or an + \eTeX{} expression,} or +\item \emph{encounters a sub-\csa{xintexpr}ession}, or +\item \emph{encounters an opening parenthesis}, or +\item \emph{encounters a + letter (which is interpreted as signaling the start of either a variable or + a function name)}, or +\item (of course, only when in state "looking for an operator") \emph{encounters a digit}. +\end{enumerate} + +\begin{framed} + For example, if |x, y, z| are variables all three of |(x+y)z|, |x(y+z)|, + |(x+y)(x+z)| will create a tacit multiplication. + + Furthermore starting with release + |1.2e|, %\MyMarginNote[\kern\dimexpr\FrameSep+\FrameRule\relax]{Changed} + whenever tacit multiplication is applied, in all cases it \emph{always} + ``ties'' more\IMPORTANT{} than normal multiplication or division, but + still less than power. Thus |x/2y| is interpreted as |x/(2y)| and + similarly for |x/2max(3,5)| but |x^2y| is still interpreted as |(x^2)*y| + and |2n!| as |2*n!|. + +\begin{everbatim*} +\xintdefvar x:=30;\xintdefvar y:=5;% +\xinttheexpr (x+y)x, x/2y, x^2y, x!, 2x!, x/2max(x,y)\relax +\end{everbatim*} + + Since |1.2q| tacit multiplication is triggered also in cases such as + |(1+2)5| or |10!20!30!|. + +\begin{everbatim*} +\xinttheexpr (10+7)5, 4!4!, add(i, i=1..10)10, max(x, y)100\relax +\end{everbatim*} + + The ``tie more'' rule applies to all cases of tacit multiplication. It + impacts only situations when a division was the last seen operator, as the + normal rule for the \xintexprname parsers is left-associativity in case of + equal precedence. +\begin{everbatim*} +\xinttheexpr 1/(3)5, (1+2)/(3+4)(5+6), 2/x(10), 2/10x, 3/y\xintiiexpr 5+6\relax, 1/x(y)\relax\ +differ from\newline\xinttheexpr 1/3*5, (1+2)/(3+4)*(5+6), 2/x*(10), 2/10*x, + 3/y*\xintiiexpr 5+6\relax, 1/x*(y)\relax\par +\end{everbatim*} +\end{framed} + + Note that |y|\csbxint{theiiexpr}| 5+6\relax| would have tried to use a variable + with name |y11| rather than doing |y*11|: tacit multiplication works only + in front of sub-\csbxint{expr}essions, not in front of + \csbxint{theexpr}essions which are unlocked into explicit digits. + + +Here is an expression whose meaning is + completely modified by the ``tie more'' property of tacit multiplication: + + +\begin{everbatim} +\xintdeffunc e(z):=1+z(1+z/2(1+z/3(1+z/4))); +\end{everbatim} +will be parsed as +\begin{everbatim} +\xintdeffunc e(z):=1+z*(1+z/(2*(1+z/(3*(1+z/4))))); +\end{everbatim} +which is not at all the presumably hoped for: +\begin{everbatim} +\xintdeffunc e(z):=1+z*(1+(z/2)*(1+(z/3)*(1+(z/4)))); +\end{everbatim} +% This case can be handled this way: +% \begin{everbatim} +% \xintdeffunc e(z):=(((z/4+1)z/3+1)z/2+1)z+1; +% \end{everbatim} + + +\subsection{More examples with dummy variables} +\label{ssec:moredummies} + +These examples were first added to this manual at the time of the |1.1| +release (|2014/10/29|). + +\begin{everbatim*} +Prime numbers are always cool +\xinttheiiexpr seq((seq((subs((x/:m)?{(m*m>x)?{1}{0}}{-1},m=2n+1)) + ??{break(0)}{omit}{break(1)},n=1++))?{x}{omit}, + x=10001..[2]..10200)\relax +\end{everbatim*} + +The syntax in this last example may look a bit involved (... and it is so I +admit). First |x/:m| computes +|x modulo m| (this is the modulo with respect to truncated division, which +here for positive arguments is like Euclidean division; in +|\xintexpr...\relax|, |a/:b| is such that |a = b*(a//b)+a/:b|, with |a//b| the +algebraic quotient |a/b| truncated to an integer.). The |(x)?{yes}{no}| +construct checks if |x| (which \emph{must} be within parentheses) is true or +false, i.e. non zero or zero. It then executes either the |yes| or the |no| +branch, the non chosen branch is \emph{not} evaluated. Thus if |m| divides |x| +we are in the second (``false'') branch. This gives a |-1|. This |-1| is the +argument to a |??| branch which is of the type |(y)??{y<0}{y=0}{y>0}|, thus here +the |y<0|, i.e., |break(0)| is chosen. This |0| is thus given to another |?| +which consequently chooses |omit|, hence the number is not kept in the list. +The numbers which survive are the prime numbers. + +\begin{everbatim*} +The first Fibonacci number beyond |2^64| bound is +\xinttheiiexpr subs(iterr(0,1;(@1>N)?{break(i)}{@1+@2},i=1++),N=2^64)\relax{} +and the previous number was its index. +\end{everbatim*} + +% A006877 In the `3x+1' problem, these values for the starting value set new +% records for number of steps to reach 1. (Formerly M0748) 14 1, 2, 3, 6, 7, +% 9, 18, 25, 27, 54, 73, 97, 129, 171, 231, 313, 327, 649, 703, 871, 1161, +% 2223, 2463, 2919, 3711, 6171, 10971, 13255, 17647, 23529, 26623, 34239, +% 35655, 52527, 77031, 106239, 142587, 156159, 216367, 230631, 410011, 511935, +% 626331, 837799 + +One more recursion: +\begin{everbatim*} +\def\syr #1{\xinttheiiexpr rseq(#1; (@<=1)?{break(i)}{odd(@)?{3@+1}{@//2}},i=0++)\relax} +The 3x+1 problem: \syr{231}\par +\end{everbatim*} + +OK, a final one: +\begin{everbatim*} +\def\syrMax #1{\xinttheiiexpr iterr(#1,#1;even(i)? + {(@2<=1)?{break(i/2)}{odd(@2)?{3@2+1}{@2//2}}} + {(@1>@2)?{@1}{@2}},i=0++)\relax } +With initial value 1161, the maximal number attained is \syrMax{1161} and that latter +number is the number of steps which was needed to reach 1.\par +\end{everbatim*} + +Look at the + \hyperlink{BrentSalamin}{Brent-Salamin algorithm implementation} for a more + interesting recursion. + +% \begin{everbatim*} +% \newcommand\Factors [1]{\xinttheiiexpr +% subs(seq((i/:3=1)?{omit}{[L][i]},i=0..len(L)-1), +% L=rseq(#1;(p^2>[@][0])?{([@][0]>1)?{break(1,[@][0],1)}{abort}} +% {(([@][0])/:p)?{omit} +% {iter(([@][0])//p; (@/:p)?{break(@,p,e)}{@//p},e=1++)}},p=2++))\relax } +% \Factors {41^4*59^2*29^3*13^5*17^8*29^2*59^4*37^6} +% \end{everbatim*} + +% This might look a bit scary, I admit.% +% % +% \footnote{Look at the +% \hyperlink{BrentSalamin}{Brent-Salamin algorithm implementation} for a much +% saner example.} +% % + +% \xintexprname has minimal tools and +% is obstinate about doing everything expandably! We are hampered by absence of a +% notion of ``nuple''. The algorithm divides |N| by |2| until no more possible, +% then by |3|, then by |4| (which is silly), then by |5|, then by |6| (silly +% again), \dots. + +% The variable |L=rseq(#1;...)| expands, if one follows the steps, to a comma +% separated list starting with the initial (evaluated) |N=#1| and then +% pseudo-triplets where the first item is |N| trimmed of small primes, the +% second item is the last prime divisor found, and the third item is its +% exponent in original |N|. + +% The algorithm needs to keep handy the last computed quotient by prime powers, +% hence all of them, but at the very end it will be cleaner to get rid of them +% (this corresponds to the first line in the code above). This is achieved in a +% cumbersome inefficient way; indeed each item extraction |[L][i]| is costly: it +% is not like accessing an array stored in memory, due to expandability, nothing +% can be stored in memory! Nevertheless, this step could be done here in a far +% less inefficient manner if there was a variant of |seq| which, in the spirit +% of \csbxint{iloopindex}, would know how many steps it had been through so far. +% This is a feature to be added to |\xintexpr|! (as well as a |++| construct +% allowing a non unit step). + +% Notice that in |iter(([@][0])//p;| the |@| refers to the previous triplet (or +% in the first step to |N|), but the latter |@| showing up in |(@/:p)?| refers +% to the previous value computed by |iter|. + +% \begin{snugframed} +% Parentheses are essential in |..([y][0])| else the parser will see |..[| and +% end up in ultimate confusion, and also in |([@][0])/:p| else the parser will +% see the itemwise operator |]/| on lists and again be very confused (I could +% implement a |]/:| on lists, but in this situation this would also be very +% confusing to the parser.) +% \end{snugframed} + +% See \autoref{ssec:factorize} for a routine |\Factorize| written directly with +% \xintname macros. Last time I checked |\Factors| was about seven times slower +% than |\Factorize| in test cases such as +% |16246355912554185673266068721806243461403654781833| and others. Among the +% various things explaining the speed difference, there is fact that the +% |\Factorize| algorithm step by increments of two, not one, and also it divides +% only once, obtaining quotient and remainder in one go. These two things +% already make for a speed-up factor of about four. Thus, |\Factors| is not +% completely inefficient in comparison, and was quite easier to come up with +% than |\Factorize|. + +\subsection{User defined variables} +\label{ssec:uservariables} +\label{xintdefvar} +\label{xintdefiivar} +\label{xintdeffloatvar} + +Since release |1.1| it is possible to make an assignment to a variable name +and let it be known to the parsers of \xintexprname. +\begin{everbatim*} +% definitions +\xintdefvar Pi:=3.141592653589793238462643;% +\xintdefvar x_1 := 10;\xintdefvar x_2 := 20;\xintdefvar y@3 := 30;% +\xintdefiivar List := seq(x(x+1)/2, x=0..10);% +% usage +$x_1\cdot x_2\cdot y@3+1=\xinttheiiexpr x_1*x_2*y@3+1\relax$\newline +$\pi^{100}\approx\xintthefloatexpr Pi^100\relax$\newline +\xinttheiiexpr List\relax\ contains \xinttheiiexpr [List][7]\relax.\par +\end{everbatim*} + +For catcodes issues (particularly, for the semi-colon used to delimit the +fetched expression), see the discussion of \csbxint{exprSafeCatcodes}. +\begin{framed} + Both syntaxes |\xintdefvar foo := <expr>;| and |\xintdefvar foo = <expr>;| + are accepted.\NewWithf{1.3c} +\end{framed} +Spaces in the variable name or around the equal sign are removed and are +immaterial. + +As shown above a variable can be assigned a "list" value. +Simultaneous assignments are allowed: +\begin{everbatim*} +\xintdefvar x1, x2, x3 := 3, 10^2, -1;% +\xintdefiivar A, B := 1500, 135;% +\xintloop +\xintifboolexpr{B} + {\xintdefiivar A, B := B, A 'mod' B;\iftrue} + {\iffalse} +\repeat +The last non zero remainder is \xinttheiiexpr A\relax. +\end{everbatim*} + +The variable names are expanded in an |\edef| (and stripped of spaces). +Example: +\begin{everbatim} +\xintdefvar x\xintListWithSep{, x}{\xintSeq{0}{10}} := seq(2**i, i = 0..10);% +\end{everbatim} +This defines the variables |x0|, |x1|, \dots, |x10| for future usage. + +Legal variable names are composed of letters, digits, |_| and |@| and characters. +A variable name must start with a letter: +\begin{itemize}[nosep] +\item the first character can not be a digit, +\item and names starting with |@| or |_| are reserved (worldwide, + extra-terrestrial locations included if under UNO supervision) by author for + internal purposes. +\end{itemize} + +|x_1x| is a licit variable name, as well as |x_1x_| and |x_1x_2| and |x_1x_2y| +etc... hence tacit multiplication fails in cases like |x_1x_2| with |x_1| and +|x_2| defined as variables; the parser goes not go to the effort of tracing +back its steps, and it is too late when it realizes |x_1x_2| isn't a valid +variable name. An explicit infix |*| operator is needed. + +Single letter names |a..z| and |A..Z| are pre-declared by the package for use +as special type of variables called ``dummy variables''. It is allowed to +overwrite their original meanings and assign them values. See further +\csbxint{unassignvar}. + +The assignments are done with \csa{xintdefvar}, \csa{xintdefiivar}, or +\csa{xintdeffloatvar} and the variable value will be computed using respectively +\csbxint{expr}, \csbxint{iiexpr} or \csbxint{floatexpr}. It can then be used +in all three parsers if the parser understands the format. Currently this +means that variables using \csa{xintdefvar} or \csa{xintdeffloatvar} can not +be used in the \csbxint{iiexpr} parser, and variables defined via +\csa{xintdefiivar} can be used in all parsers. + +When defining a variable with \csa{xintdeffloatvar}, it is important to know +that the rounding to \csbxint{theDigits} digits of precision happens inside +\csa{xintfloatexpr} only if an operation is executed. Thus, for a variable +definition which uses no operations (and \emph{only} for them), the value is +recorded inside the variable with all its digits preserved. If +\csbxint{theDigits} changes afterwards, the variable will be rounded to that +precision in force at time of use. +\begin{everbatim*} +\xintdeffloatvar e:=2.7182818284590452353602874713526624977572470936999595749669676;% +\xinttheexpr e\relax\newline % shows the recorded value +\xintthefloatexpr e\relax\newline % output rounds +\xintthefloatexpr 1+e\relax\newline % the rounding was done by addition (trust me...) +\xintdeffloatvar e:=float(2.7182818284590452353602874713526624977572470936999595749669676);% +\xinttheexpr e\relax\par % use of float forced immediate rounding +\end{everbatim*} + +In the next examples we examine the effect of cumulated float operations on +rounding errors: +\begin{everbatim*} +\xintdefvar e_1:=add(1/i!, i=0..10);% exact sum +\xintdeffloatvar e_2:=add(1/i!, i=0..10);% float sum +\xintthefloatexpr e_1, e_2\relax\newline +\xintdefvar e_3:=e_1+add(1/i!, i=11..20);% exact sum +\xintdeffloatvar e_4:=e_2+add(1/i!, i=11..20);% float sum +\xintthefloatexpr e_3, e_4\relax\newline +\xintdeffloatvar e:=2.7182818284590452353602874713526624977572470936999595749669676;% +\xintDigits:=24; +\xintthefloatexpr[16] e, e^1000, e^1000000\relax (e rounded to 24 digits first)\newline +\xintDigits:=16; +\xintthefloatexpr e, e^1000, e^1000000\relax (e rounded to 16 digits first)\par +\end{everbatim*} + +With |\xintverbosetrue| the values of the assigned variables will be written +to the log. For example like this (the line numbers here are artificial): + +\begin{everbatim} +Package xintexpr Info: (on line 2875) + Variable "e" defined with value 2718281828459045235360287471352662497757247 +0936999595749669676[-61]. +Package xintexpr Info: (on line 2879) + Variable "e" defined with value 2718281828459045[-15]. +Package xintexpr Info: (on line 2886) + Variable "e_1" defined with value 9864101/3628800[0]. +Package xintexpr Info: (on line 2887) + Variable "e_2" defined with value 2718281801146385[-15]. +Package xintexpr Info: (on line 2889) + Variable "e_3" defined with value 6613313319248080001/2432902008176640000[0 +]. +Package xintexpr Info: (on line 2890) + Variable "e_4" defined with value 2718281828459046[-15]. +Package xintexpr Info: (on line 2892) + Variable "e" defined with value 2718281828459045235360287471352662497757247 +0936999595749669676[-61]. +\end{everbatim} + + +\subsubsection{\csh{xintunassignvar}} +\label{xintunassignvar} + +Variable declarations obey the current scope. To let a (multi-letter) name be +unknown to (all parsers of) \xintexprname\CHANGED{1.3d} without waiting the +end of the scope one issues \csa{xintunassignvar}\marg{variable}. Prior to +|1.3d|, this only redefined the variable to represent the value \dtt{0}. + +In the special case of \csa{xintunassignvar}\marg{letter}, the effect is +different,\IMPORTANT{} as it is synonymous with +\csbxint{newdummy}\marg{letter}: the (catcode 11) \meta{letter} recovers or +acquires meaning as a dummy variable in the current scope. +\begin{everbatim*} +\xintFor #1 in {e_1, e_2, e_3, e_4, e} \do {\xintunassignvar {#1}} +% overwriting a dummy letter +\xintdefvar i := 3;% +\xinttheiiexpr add(i, i = 1..10)\relax\ ("i" has the fixed value 3)\newline +\xintunassignvar{i}% back to normal +\xinttheiiexpr add(i, i = 1..10)\relax\ ("i" is again a dummy variable)\par +\end{everbatim*} + +Under \csbxint{globaldefstrue} regime the effect of \csa{xintunassignvar} is +global. + +\subsubsection{\csh{xintnewdummy}} +\label{xintnewdummy} + +Any catcode 11 character can serve as a dummy variable, via this declaration: +\begin{everbatim} +\xintnewdummy{<character>} +\end{everbatim} +For example with Xe\TeX\ or Lua\LaTeX\ the following works: +\begin{everbatim} +% use a Unicode engine +\input xintexpr.sty +\xintnewdummy ξ% or any other letter character ! +\xinttheexpr add(ξ, ξ=1..10)\relax +\bye +\end{everbatim} +Under \csbxint{globaldefstrue} regime the effect of \csa{xintnewdummy} is +global. + +\subsubsection{\csh{xintensuredummy}, \csh{xintrestorelettervar}} +\label{xintensuredummy} +\label{xintrestorelettervar} + +Use\NewWith{1.3e} +\begin{everbatim} +\xintensuredummy{<character>} +... +... code using the (catcode 11) character as a dummy variable +... +\xintrestorelettervar{<character>} +\end{everbatim} +if other parts need the letter as an assigned variable name. For example +\xinttrigname being written at high level needs a few genuine dummy variables, +and it uses \csbxint{ensuredummy} to be certain everything is ok. + + +\subsection{User defined functions} +\label{ssec:userfunctions} +\def\HOOKLOCALTOC#1#2#3{} +\etocsetnexttocdepth{subsubsection}\localtableofcontents +\let\HOOKLOCALTOC\empty + +\subsubsection{\csh{xintdeffunc}} +\label{xintdeffunc} + +Since release |1.2c| it is possible to declare functions: +\begin{everbatim*} +\xintdeffunc + Rump(x,y):=1335 y^6/4 + x^2 (11 x^2 y^2 - y^6 - 121 y^4 - 2) + 11 y^8/2 + x/2y; +\end{everbatim*}(notice the numerous tacit multiplications in this expression; +and that |x/2y| is interpreted as |x/(2y)|.) + + + +Here are a few important items (bookmark this for reading again later once you +have gained experience in using this interface...): +\begin{itemize} +\item The function names are composed of letters, digits, underscores or |@| + signs. A function name must start with a letter. It may be a single letter + (see \autoref{sssec:overload}). +\item The variables used in the function signature are single letters + (lowercase or uppercase) which have \emph{not} been re-declared via + \csbxint{defvar} as assigned variables. The choice of the letters is + entirely up to the user and has nil influence on the actual function, + naturally. +\item A function can have at most nine variables. +\item The mechanism for functions shares a common code base with the one + implementing \csbxint{NewExpr}. This means it shares its features and also + its \hyperref[sssec:limitations]{limitations}. % + + Most notably,\IMPORTANT{} the |1.3d| \csbxint{eval}, \csbxint{ieval}, + \csbxint{floateval} can not be used inside the parsed + expression: only the lower level syntax + \csbxint{expr}|...\relax| et al. is accepted (and not + \csbxint{theexpr} et al.\CHANGED{1.3e} which are about the same as \csbxint{eval} et al.). + Prior to |1.3e| \csbxint{NewExpr} and \csbxint{deffunc} diverged on that + point, but their behaviour is now identical. +\item In order to allow recursive constructs, a core mechanism is implemented + which inhibits immediate expansion in a new definition; think of + \csbxint{deffunc} as being + analogous to a |\protected\edef|. This means that another function + |bar(x,..)| whose definition uses |foo(17.5)| will only store that it should + at some point compute + |foo(17.5)|, in place of storing its actual value. +\item If |foo(x)| definition is not recursive, then you should use + \csbxint{defefunc} rather. This is analogous to an |\edef| without the + |\protected|.\NewWith{1.3e} Then |bar(x,...)| (defined with + \csbxint{deffunc} or \csbxint{defefunc}) will store the actual + evaluation of |foo(17.5)|. +\item If |foo(x)| definition does need recursivity and you want to use + efficiently |foo(17.5)| in another function definition, assign it to a + variable (see \csbxint{defvar}) and use that variable rather in the + definition of |bar()|. Notice that only the variable value, not its name, + gets stored, so the variable name is a temporary auxiliary. In the analogy + with TeX macros one can think of \csbxint{defvar} or \csbxint{eval} as + producing expansion like typesetting does, whereas \csbxint{deffunc} is like + a + |\protected\edef|, and \csbxint{defefunc} an |\edef| not making the defined + function |\protected|. +\item A function declared via \csbxint{deffunc} remains unknown to + \csbxint{floatexpr} (or \csbxint{floateval}). See \csbxint{deffloatfunc}, + \csbxint{defiifunc}. One can use the same formula in a new definition, but + if one wants the expansion to execute in a parser independent way, one can + transfer a function like this:\NewWith{1.3e} +\begin{everbatim} +\xintdeffloatfunc foo(x) := float(\xintexpr foo(x)\relax); +\end{everbatim} + The \func{float} wrapper is in order for the float variant to produce an + already-rounded value, possibly speeding-up usage if used as input for other + functions. And in the reverse direction one can do: +\begin{everbatim} +\xintdeffunc bar(x) := \xintfloatexpr bar(float(x))\relax; +\end{everbatim} + With this the transplanted float-function will expand in \csbxint{expr} as it + would have in \csbxint{floatexpr}, i.e. using float operations; this is different + from declaring the function again with the same expression as used for the + original, as it would have then been parsed with a mapping of infix operators to the + macros doing the exact operations, not the floating point ones. + + The |float(x)| above is not mandatory but recommended. The macro associated + to the user float function |bar(x)| may use many times its argument |x| and + it does not care to round it, because it basically expect an already rounded + value; but in \csbxint{expr} that value could very well be a fraction + |19/13| and its float rounding will be done again by each float macro + receiving it as argument; with a \func{float} used as above this will have + already been done once and the ulterior roundings are faster: they have + nothing to do apart from realizing that they have nothing to do.... One can + also use \func{sfloat}, this would serve to nothing for the |19/13| case but + would possibly for a short integer input involved in multiplications. +\item If the expression uses an \func{iterr}, \func{rseq}, or \func{rrseq}) it + must hide its |;| inside braces to let it not be confused with the ending + |;|. +\item \csbxint{deffunc} tries to set the catcode of |;| before fetching the + expression as a delimited parameter, but this is too late if the whole thing + was already fetched as argument to some macro. On the other hand the + (reasonable) catcode of the |:| does not matter at all, actually this colon + before the equality sign is optional. +\end{itemize} + + +A function once declared is a first class citizen, its +expression is entirely parsed and converted into a big nested \fexpan dable +macro. When used its action is via this defined macro. For example +\begin{everbatim*} +\xintdeffunc + e(z):=(((((((((z/10+1)z/9+1)z/8+1)z/7+1)z/6+1)z/5+1)z/4+1)z/3+1)z/2+1)z+1; +\end{everbatim*} +creates a macro whose meaning one can find in the log file, after +|\xintverbosetrue|. Here it is: +\begin{everbatim} + Function e for \xintexpr parser associated to \XINT_expr_userfunc_e with me +aning macro:#1->\xintAdd {\xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xi +ntDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\x +intAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\ +xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {#1}{10}}{1}}{#1}}{9} +}{1}}{#1}}{8}}{1}}{#1}}{7}}{1}}{#1}}{6}}{1}}{#1}}{5}}{1}}{#1}}{4}}{1}}{#1}}{3}} +{1}}{#1}}{2}}{1}}{#1}}{1} +\end{everbatim} + +The main problem is that dummy variables in the defining expression are usable +only to the extent that their values are numerical. For example +% +\centeredline{|\xintdeffunc f(x):=add(i^2,i=1..x);|} +% + is not currently possible. See \autoref{sssec:limitations} and the next + subsection. + +% In this example one could use the alternative syntax with list +% operations:% +% % +% \footnote{It turns out |`+`(seq(i^2, i=1..x))| would work here, but this isn't +% always the case with |seq| constructs.} +% %! par exemple \xintdeffunc g(a,b,c):=seq(x+a+b,x=1..c); +% %! donne une erreur avec g(0,0,2). Mardi 08 mars 2016 à 09:12:43. +% \begin{everbatim*} +% \xintdeffunc f(x):=`+`([1..x]^2);\xinttheexpr seq(f(x), x=1..20)\relax +% \end{everbatim*} + +% Side remark: as the |seq(f(x), x=1..10)| does many times the same +% computations, an |rseq| here would be more efficient:\footnote{Note that +% |omit| and |abort| are not usable in |add| or |mul| (currently).} +% \begin{everbatim*} +% \xinttheexpr rseq(1; (x>20)?{abort}{@+x^2}, x=2++)\relax +% \end{everbatim*} + +On the other hand a construct like the following has no issue, as the values +iterated over do not depend upon the function parameters: +\begin{everbatim*} +\xintdeffunc f(x):=iter(1{;} @*x/i+1, i=10..1);% one must hide the first semi-colon ! +\xinttheexpr e(1), f(1)\relax +\end{everbatim*} + + +Another problem is with trying to do |g(f(x))| where |g()| expects two +arguments and |f()| was defined to output two comma separated values. This +works fine numerically but not with a variable |x| inside the definition of +another function. + +See \autoref{sssec:csv} for more about comma separated values in output and +input. + +\subsubsection{\csh{xintdefiifunc}} +\label{xintdefiifunc} + +With \csbxint{deffunc} the created function is known by the \csbxint{expr} +parser only. + Cryptic error messages will signal failures of using with another parser a + function declared for one parser (particularly if the name is a single + letter, because the parser will have made an attempt to use the letter as a + dummy variable.) + +For usage in the \csbxint{iiexpr} parser, it is required to use +\csa{xintdefiifunc}. + +\subsubsection{\csh{xintdeffloatfunc}} +\label{xintdeffloatfunc} + +With \csbxint{deffunc} the created function is known by the \csbxint{expr} +parser only. For usage in the \csbxint{floatexpr} parser, it is required to use +\csa{xintdeffloatfunc}. See \csbxint{deffunc} for more information on this +point. + + +\subsubsection{Some examples of recursive definitions} +\label{sssec:recursive} + +Since |1.3|, it is possible to make recursive definitions. Here +are two examples: +\begin{everbatim*} +\xintdeffunc GCD(a,b):=if(b,GCD(b,a/:b),a); +\end{everbatim*} +This of course is the Euclide algorithm: it will be here applied to variables +which may be fractions. For example: +\begin{everbatim*} +\xinttheexpr GCD(385/102, 605/238)\relax +\end{everbatim*} + +But there is already a built-in \func{gcd} (which +accepts arbitrarily many arguments): +\begin{everbatim*} +\xinttheexpr gcd(385/102, 605/238)\relax +\end{everbatim*} + +Since |1.3d| the built-in \func{gcd} accepts inputs being fractions and +produces the positive generator of the corresponding fractional ideal. And +loading of \xintgcdname is not needed for this function to be available.\NewWith{1.3d} + +Our second example is modular exponentiation: +\begin{everbatim*} +\xintdefiifunc powmod_a(x, m, n) := + ifone(m, + % m=1, return x modulo n + x /: n, + % m > 1 test if odd or even and do recursive call + if(odd(m), (x*sqr(powmod_a(x, m//2, n))) /: n, + sqr(powmod_a(x, m//2, n)) /: n + ) + ); +\xintdefiifunc powmod(x, m, n) := if(m, powmod_a(x, m, n), 1); +\end{everbatim*} +I have made the definition here for the |\xintiiexpr| parser; we could do the +same for the |\xintexpr|-parser (but its usage with big powers would quickly +create big denominators, think |powmod(1/2, 1000, 1)| for example.) +\begin{everbatim*} +\xinttheiiexpr seq(powmod(x, 1000, 128), x=9, 11, 13, 15, 17, 19, 21)\relax\par +\end{everbatim*} +The function assumes the exponent is non-negative (the Python |pow| behaves +the same), but zealous users will add the necessary code for negative +exponents, after having defined another function for modular inverse! + +It is mandatory for such definitions to use the \func{if} function, and not +the |(x)?{A}{B}| construct which much choose a branch. The parsing of the +\func{if} function keeps the memory of the two alternative branches; to the +contrary, the \emph{constructed} |powmod| function will expand \emph{only} the +then relevant branch. This is of course absolutely needed for things such as +the Euclide algorithm where it would be catastrophic to evaluate both branches +as the first one involves a division by |b| and the algorithm stops only when +|b| is actually zero. + +If function |A| needs function |B| which needs function |A| start by giving to +|B| some dummy definition, define |A|, then define |B| properly. TODO: add +some example here... + +\subsubsection{\csh{xintdefefunc}} +\label{xintdefefunc} + +Think of former described variant \csbxint{deffunc} as doing the same as this +\csbxint{defefunc}\NewWith{1.3e} but with an extra protection added to the +defined function. If you don't need recursivity, \csbxint{defefunc} is the +better tool, as numerical evaluation involving it and arising in further +definitions will be converted on the spot to actual values, rather than being +delayed for expansion to actual use of the defined function in \csbxint{eval} +or \csbxint{ieval}. + +\subsubsection{\csh{xintdeffloatefunc}} +\label{xintdeffloatefunc} + +The ``unprotected'' variant of \csbxint{deffloatfunc}.\NewWith{1.3e} + +\subsubsection{\csh{xintdefiiefunc}} +\label{xintdefiiefunc} + +The ``unprotected'' variant of \csbxint{defiifunc}.\NewWith{1.3e} + + +\subsubsection{Using the same name for both a variable and a function} +\label{sssec:overload} + +It is licit to overload a variable name (all Latin letters are predefined as +dummy variables) with a function name and vice versa. The parsers will decide +from the context if the function or variable interpretation must be used +(dropping various cases of tacit multiplication as normally applied). +\begin{everbatim*} +\xintdefiifunc f(x):=x^3; +\xinttheiiexpr add(f(f),f=100..120)\relax\newline +\xintdeffunc f(x,y):=x^2+y^2; +\xinttheexpr mul(f(f(f,f),f(f,f)),f=1..10)\relax +\xintunassigniiexprfunc{f}\xintunassignexprfunc{f}% +\end{everbatim*} + +% N.B.: we have declared in this section |f| and |g| as functions. They remain +% usable as dummy variables, but tacit multiplication in front of parentheses is +% dropped, in order for their function meanings to prevail. + +% \begin{everbatim*} +% \xintdeffunc f(x):=x^2; +% \xinttheexpr seq(f(f+f), f= 1..10)\relax\newline % f is used both as function and dummy variable +% \xinttheexpr seq(f*(f+f), f= 1..10)\relax % f is used as dummy variable +% \xintunassignexprfunc{f}\newline % drop meaning as function +% \xinttheexpr seq(f(f+f), f= 1..10)\relax % f as dummy variable, tacit multiplication applies +% \end{everbatim*} + + +\subsubsection{\csh{xintunassignexprfunc}, \csh{xintunassigniiexprfunc}, + \csh{xintunassignfloatexprfunc}} +\label{xintunassignexprfunc} +\label{xintunassigniiexprfunc} +\label{xintunassignfloatexprfunc} + +Function names can be unassigned via \csa{xintunassignexprfunc}\marg{name}, +\csa{xintunassigniiexprfunc}\marg{name}, and +\csa{xintunassignfloatexprfunc}\marg{name}.\NewWith{1.3d} +\begin{everbatim*} +\xintunassignexprfunc{e} +\xintunassignexprfunc{f} +\end{everbatim*} + +Warning: no check is done to avoid undefining built-in functions... + +\subsubsection{\csh{ifxintverbose} conditional} +\label{xintverbosetrue} +\label{xintverbosefalse} +\label{ifxintverbose} + +With |\xintverbosetrue| the meanings of the +functions (or rather their associated macros) will be written to the log. For +example the |Rump| declaration above generates this in the log file: +\begin{everbatim} + Function Rump for \xintexpr parser associated to \XINT_expr_userfunc_Rump w +ith meaning macro:#1#2->\xintAdd {\xintAdd {\xintAdd {\xintDiv {\xintMul {1335} +{\xintPow {#2}{6}}}{4}}{\xintMul {\xintPow {#1}{2}}{\xintSub {\xintSub {\xintSu +b {\xintMul {11}{\xintMul {\xintPow {#1}{2}}{\xintPow {#2}{2}}}}{\xintPow {#2}{ +6}}}{\xintMul {121}{\xintPow {#2}{4}}}}{2}}}}{\xintDiv {\xintMul {11}{\xintPow +{#2}{8}}}{2}}}{\xintDiv {#1}{\xintMul {2}{#2}}} +\end{everbatim} +and the declaration |\xintdeffunc f(x):=iter(1{;} @*x/i+1, i=10..1);| generates: +\begin{everbatim} + Function f for \xintexpr parser associated to \XINT_expr_userfunc_f with me +aning macro:#1->\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\xi +ntAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\x +intMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\ +xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul { +1}{#1}}{10/1[0]}}{1}}{#1}}{9/1[0]}}{1}}{#1}}{8/1[0]}}{1}}{#1}}{7/1[0]}}{1}}{#1} +}{6/1[0]}}{1}}{#1}}{5/1[0]}}{1}}{#1}}{4/1[0]}}{1}}{#1}}{3/1[0]}}{1}}{#1}}{2/1[0 +]}}{1}}{#1}}{1/1[0]}}{1} +\end{everbatim} + +Starting with |1.2d| the definitions made by \csbxint{NewExpr} have local +scope, hence this is also the case with the definitions made by +\csbxint{deffunc}. See also \csb{ifxintglobaldefs} conditional. + +\subsubsection{\csh{ifxintglobaldefs} conditional} +\label{xintglobaldefstrue} +\label{xintglobaldefsfalse} +\label{ifxintglobaldefs} + +If true user defined variables (\csbxint{defvar}, ...) and functions +(\csbxint{deffunc}, ...) for the expression parsers,\NewWith{1.3c} as well as +macros obtained via \csbxint{NewExpr} et al have global scope. If false +(default) they have local scope. + +\subsubsection{Functions expanding to comma separated values} +\label{sssec:csv} + +It is possible to define functions which expand to comma-separated values, for +example the declarations: +\begin{everbatim*} +\xintdeffunc f(x):= x, x^2, x^3, x^x; +\xintdeffunc g(x):= x^[0..x];% x^[1, 2, 3, x] would be like f above. +\end{everbatim*} +will generate +\begin{everbatim} + Function f for \xintexpr parser associated to \XINT_expr_userfunc_f with me +aning macro:#1->#1,\xintPow {#1}{2},\xintPow {#1}{3},\xintPow {#1}{#1} + + Function g for \xintexpr parser associated to \XINT_expr_userfunc_g with me +aning macro:#1->\xintApply::csv {\xintPow {#1}}{\xintSeq::csv {0}{#1}} +\end{everbatim} +and we can check that they work: +\begin{everbatim*} +\xinttheexpr f(10)\relax; \xinttheexpr g(10)\relax +\end{everbatim*} + +However please consider this as WIP. They are some known (or half-known, +because the author gets a headache whenever he reconsiders the whole thing) +thorny issues, mostly related to the fact that \xintexprname has no proper +variable type for lists. See \autoref{ssec:lists}. + +Here is another aspect: the documentation of release |1.3c| included this paragraph: + +\begin{quote} + It is possible to define functions of variables which stand for lists (see + \autoref{ssec:lists}), or functions defining lists of comma separated items. + For example the scalar product and cross product of 3-dimensional vectors + can be defined this way: +\end{quote} +\begin{everbatim*} +\xintdeffunc dprod(V, W) := [V][0]*[W][0] + [V][1]*[W][1] + [V][2]*[W][2]; +\xintdeffunc cprod(V, W) := [V][1]*[W][2] - [V][2]*[W][1], + [V][2]*[W][0] - [V][0]*[W][2], + [V][0]*[W][1] - [V][1]*[W][0]; +\xintdeffunc Det3(U, V, W) := dprod(cprod(U, V), W); +\end{everbatim*} + +But it should be added promptly that due to absence to typed variables of type +list (see \autoref{ssec:lists}), usage of the above is very subtle: although +it is possible to define variables |U|, |V|, |W| expanding to three components +each it is impossible to use them with |Det3(U, V, W)| because \csbxint{expr} +will convert |U, V, W| to a comma separated list of \dtt{9} numbers, and +|Det3| was defined as a function of only \dtt{3} things. + +The only way (currently) is to define |U|, |V|, |W| as \emph{functions} +(possibly of no variable), then to define a new \emph{function} |Z = Det3(U, V, +W)|, and finally to evaluate |Z| with no argument: +\begin{everbatim*} +\xintdeffunc V() := 1, 1, 1; +\xintdeffunc W() := 1, 5, 25; +\xintdeffunc Y() := 1, 10, 100; +\xintdeffunc Z() := Det3(V(), W(), Y()); +% \xinteval{Det3(V(), W(), Y())} does NOT work, one must go via Z() +\xinteval{Z()} +\end{everbatim*} + +It is better for pure numerics to define the |Det3()| initially as a function +of \dtt{9} variables. But the above works well if one really wants to work +with variables: +\begin{everbatim*} +\xintdeffunc V(x) := 1, x, x^2; +\xintdeffunc Z(x,y,z) := Det3(V(x), V(y), V(z)); +\xinteval{Z(1, 5, 10)} +\end{everbatim*} + +This can be combined with usage of my other package +\href{http://ctan.org/pkg/polexpr}{polexpr}. I thank Thomas \textsc{Söll} who +explored precisely that during 2018. + +To tell the whole truth,\CHANGED{1.3e} until |1.3e| the above worked +\emph{only} with at least one variable, the syntax with no variables had a +bug. + +Cleaning up: +\begin{everbatim*} +\xintunassignexprfunc{g} +\xintunassignexprfunc{V} +\xintunassignexprfunc{W} +\xintunassignexprfunc{Y} +\xintunassignexprfunc{Z} +\xintunassignexprfunc{dprod}\xintunassignexprfunc{cprod}\xintunassignexprfunc{Det3} +\end{everbatim*} + +\subsubsection{Example with the \textsc{Rump} test} +\label{sssec:Rump} + +Let's try out our |Rump()| function: +\begin{everbatim*} +\xinttheexpr Rump(77617,33096)\relax. +\end{everbatim*} +Nothing problematic for an \emph{exact} evaluation, naturally ! + +Thus to test the \textsc{Rump} polynomial (it is not quite a polynomial with +its |x/2y| final term) with floats, we \emph{must} also +declare |Rump| as a function to be used there: +\begin{everbatim*} +\xintdeffloatfunc + Rump(x,y):=333.75 y^6 + x^2 (11 x^2 y^2 - y^6 - 121 y^4 - 2) + 5.5 y^8 + x/2y; +\end{everbatim*} + +The numbers are scanned with the current precision, hence as here it is +\dtt{16}, they are scanned exactly in this case. We can then vary the +precision for the evaluation. +\begin{everbatim*} +\def\CR{\cr} +\halign +{\tabskip1ex +\hfil\bfseries#&\xintDigits:=\xintiloopindex;\xintthefloatexpr Rump(77617,33096)#\cr +\xintiloop [8+1] +\xintiloopindex &\relax\CR +\ifnum\xintiloopindex<40 \repeat +} +\end{everbatim*} + +\subsubsection{\csh{xintNewFunction}} +\label{xintNewFunction} + +The syntax is analogous to the one of \csbxint{NewExpr} but achieves something +\emph{completely different} from +\csbxint{NewExpr}/\csbxint{deffunc}. Here is an example: +\begin{everbatim*} +\xintNewFunction {foo}[3]{add(mul(x+i, i=#1..#2),x=1..#3)} +\end{everbatim*} +\begin{framed} + We now have a genuine function |foo( , , )| of three variables which we can + use fully in \emph{all three parsers}, be it with numerical arguments or + variables or whatever. +\end{framed} +\begin{everbatim*} +\xinttheexpr seq(foo(0, 3, j), j= 1..10)\relax +\end{everbatim*} +See \autoref{ssec:PrimesIV} for some additional examples. + +This construct is only syntactic sugar to benefit from functional notation. +Each time the created «function-macro» |foo()| will be encountered the +corresponding expression will get inserted as a sub-expression (of the same +type as the surrounding one), the macro parameters having been replaced with +the (already evaluated) function arguments, and the parser \emph{will then + have to parse the expression.} It is very much like a macro substitution, +but with parentheses and comma separated arguments (which can be arbitrary +expressions themselves). +\begin{everbatim} + Function foo for the expression parsers is associated to \XINT_expr_macrofu +nc_foo with meaning macro:#1#2#3->add(mul(x+i, i=\XINT_expr_wrapit {#1}..\XINT_ +expr_wrapit {#2}),x=1..\XINT_expr_wrapit {#3}) +\end{everbatim} +Thus, this works with quite arbitrary constructs, contrarily to the mechanism +of |\xintdeffunc|. It is not currently possible to define a |foo| function +like the one above via |\xintdeffunc|.% +% +\footnote{Or rather, it turns out that no error is raised on making the + definition via \csbxint{deffunc} but the created supporting macro is only + garbage and raises errors on use.} + +One can declare a function |foo| with |[0]| arguments: it may be used +as |foo()| or |foo(nil)| (prior to |1.3b| only the latter was accepted).\CHANGED{1.3b} + +\subsection{List operations} +\label{ssec:lists} + +By \emph{list} we hereby mean simply comma-separated values, for example |3, +-7, 1e5|. This section describes some syntax which allows to manipulate such +lists, for example |[3, -7, 1e5][1]| extracts |-7| (we follow the Python +convention of enumerating starting at zero.) + +In the context of dummy variables, lists can be used in substitutions: +\begin{everbatim*} +\xinttheiiexpr subs(`+`(L), L = 1, 3, 5, 7, 9)\relax\newline +\end{everbatim*} +and also the |rseq| and |iter| constructs allow |@| to refer to a list: +\begin{everbatim*} +\xinttheiiexpr iter(0, 1; ([@][1], [@][0]+[@][1]), i=1..10)\relax\newline +\end{everbatim*} +where each step constructs a new list with two entries. + +However, despite appearances there is not really internally a notion of a +\emph{list type} and it is currently impossible to create, +manipulate, or return on output a \emph{list of lists}. There is a special +reserved variable |nil| which stands for the empty list. + +The syntax which is explained next includes in particular what are called +\emph{list itemwise operators} such as: +\begin{everbatim*} +\xinttheiiexpr 37+[13,100,1000]\relax\newline +\end{everbatim*}% +This part of the syntax is considered provisory, for the reason that its +presence might make more difficult some extensions in the future. On the other +hand the Python-like slicing syntax should not change. + + +\begin{itemize} + \item |a..b| constructs the \textbf{small} integers from the ceil $\lceil + a\rceil$ to the floor + $\lfloor b\rfloor$ (possibly a decreasing sequence): one has to be careful + if using this for algorithms that |1..0| for example is not empty or |1| + but expands to |1, 0|. Again, |a..b| \emph{can not} be used with |a| and + |b| greater than $2^{31}-1$. Also, only about at most \dtt{5000} integers + can be generated (this depends upon some \TeX{} memory settings). + + The |..| has lower precedence than the arithmetic operations. +\begin{everbatim*} +\xinttheexpr 1.5+0.4..2.3+1.1\relax; \xinttheexpr 1.9..3.4\relax; \xinttheexpr 2..3\relax +\end{everbatim*} + + \item |a..[d]..b| allows to generate big integers, or also fractions, it + proceeds with step (non necessarily integral nor positive) |d|. It does + \emph{not} replace |a| by its ceil, nor |b| by its floor. The generated + list is empty if |b-a| and |d| are of opposite signs; if |d=0| or if |a=b| + the list expands to single element |a|. +\begin{everbatim*} +\xinttheexpr 1.5..[1.01]..11.23\relax +\end{everbatim*} + + \item |[list][n]| extracts the |n+1|th element if |n>=0|. If + |n<0| it extracts from the tail. List items are numbered (since |1.2g|) as + in Python, the first element corresponding to |n=0|. + |len(list)| computes the number of items of the list. +\begin{everbatim*} +\xinttheiexpr \empty[0..10][6], len(0..10), [0..10][-1], [0..10][23*18-22*19]\relax\ +(and 23*18-22*19 has value \the\numexpr 23*18-22*19\relax). +\end{everbatim*} + +See the next frame for why the example above has |\empty| token at start. + +As shown, it is perfectly legal to do operations in the index parameter, which +will be handled by the parser as everything else. The same remark applies to +the next items. + + \item |[list][:n]| extracts the first |n| elements if |n>0|, or suppresses + the last \verb+|n|+ elements if |n<0|. +\begin{everbatim*} +\xinttheiiexpr [0..10][:6]\relax\ and \xinttheiiexpr [0..10][:-6]\relax +\end{everbatim*} + \item |[list][n:]| suppresses the first |n| elements if |n>0|, or extracts + the last \verb+|n|+ elements if |n<0|. +\begin{everbatim*} +\xinttheiiexpr [0..10][6:]\relax\ and \xinttheiiexpr [0..10][-6:]\relax +\end{everbatim*} +\item More generally, |[list][a:b]| works according to the Python ``slicing'' + rules (inclusive of negative indices). Notice though that there is no + optional third argument for the step, which always defaults to |+1|. +\begin{everbatim*} +\xinttheiiexpr [1..20][6:13]\relax\ = \xinttheiiexpr [1..20][6-20:13-20]\relax +\end{everbatim*} +\item It is naturally possible to nest these things: +\begin{everbatim*} +\xinttheexpr [[1..50][13:37]][10:-10]\relax +\end{everbatim*} +\item itemwise operations either on the left or the right are possible: +\begin{everbatim*} +\xinttheiiexpr 123*[1..10]^2\relax +\end{everbatim*} + +\begin{snugframed} + List operations are implemented using square brackets, but the |\xintiexpr| + and |\xintfloatexpr| parsers also check to see if an optional parameter + within brackets is specified before the start of the expression. To avoid the + resulting confusion if this |[| actually serves to delimit + comma separated values for list operations, one can either:\IMPORTANT{} + \begin{itemize} + \item insert something before the bracket such as |\empty| token, +\begin{everbatim*} +\xinttheiexpr \empty [1,3,6,99,100,200][2:4]\relax +\end{everbatim*} + \item use parentheses: +\begin{everbatim*} +\xinttheiexpr ([1,3,6,99,100,200][2:4])\relax +\end{everbatim*} + \end{itemize} + + + Notice though that |([1,3,6,99,100,200])[2:4]| would not work: it is + mandatory for |][| and |][:| not to be interspersed with parentheses. Spaces + are perfectly legal: +\begin{everbatim*} +\xinttheiexpr \empty[1..10 ] [ : 7 ]\relax +\end{everbatim*} + +Similarly all the |+[|, |*[|, \dots and |]**|, |]/|, \dots operators admit +spaces but nothing else between their constituent characters. +\begin{everbatim*} +\xinttheiexpr \empty [ 1 . . 1 0 ] * * 1 1 \relax +\end{everbatim*} +\end{snugframed} + +In an other vein, the parser will be confused by |1..[a,b,c][1]|, and one must +write |1..([a,b,c][1])|. And things such as |[100,300,500,700][2]//11| or +|[100,300,500,700][2]/11| are syntax errors and one must use parentheses, as +in |([100,300,500,700][2])/11|. + +\end{itemize} + + + +\subsection{Analogies and differences of \csh{xintiiexpr} with \csh{numexpr}} + +\csbxint{iiexpr}|..\relax| is a parser of expressions knowing only (big) +integers. There are, besides the enlarged range of allowable inputs, some +important differences of syntax between |\numexpr| and |\xintiiexpr| and +variants: +\begin{itemize} +\item Contrarily to |\numexpr|, the |\xintiiexpr| parser will stop expanding + only after having encountered (and swallowed) a \emph{mandatory} |\relax| + token. +\item In particular, spaces between digits (and not only around infix + operators or parentheses) do not stop |\xintiiexpr|, contrarily to the + situation with |numexpr|: |\the\numexpr 7 + 3 5\relax| expands (in one + step)% +% +\footnote {The |\numexpr| triggers continued expansion after the space + following the |3| to check if some operator like |+| is upstream. But + after having found the |5| it treats it as and end-marker.} +% + to \dtt{\detokenize\expandafter{\the\numexpr 7 + 3 5\relax}\unskip}, whereas + |\xintthe\xintiiexpr 7 + 3 5\relax| expands (in two steps) to + \dtt{\detokenize\expandafter\expandafter\expandafter {\xintthe\xintiiexpr 7 + + 3 5\relax}}.% +% +\footnote {Since |1.2l| one can also use the underscore |_| to separate digits +for readability of long numbers.} + +\item Inside an |\edef|, an expression |\xintiiexpr...\relax| get fully + evaluated, whereas |\numexpr| without |\the| or |\number| prefix would not, + if not itself embedded in another |\the\numexpr| or similar context. +\item (ctd.) The private format to which |\xintiiexpr...\relax| (et al.) + evaluates needs |\xintthe| prefix to be printed on the page, or be used in + macros (expanding their argument.) The |\the| \TeX\ primitive prefix would + not work here. +\item (ctd.) As a synonym to |\xintthe\xintiiexpr| one can use |\xinttheiiexpr|, + or (since |1.2h|) |\thexintiiexpr|. +\item (ctd.) One can embed a |\numexpr...\relax| (with its |\relax|!) inside an + |\xintiiexpr...\relax| without |\the| or |\number|, but the reverse situation + requires use of |\xintthe|. +\item |\numexpr -(1)\relax| is illegal. But |\xintiiexpr -(1)\relax| is + perfectly legal and gives the expected result (what else ?). +\item |\numexpr 2\cnta\relax| is illegal (with |\cnta| a |\count| register.) But + |\xintiiexpr 2\cnta\relax| is perfectly legal and will do the tacit + multiplication. +\item |\the\numexpr| or |\number\numexpr| expands in one step, but + |\xintthe\xintiiexpr| or |\xinttheiiexpr| needs two steps. +\end{itemize} + +\subsection{Chaining expressions for expandable algorithmics} +\label{ssec:fibonacci} + +We will see in this section how to chain |\xintexpr|-essions with +|\expandafter|'s, like it is possible with |\numexpr|. For this it is +convenient to use |\romannumeral0\xintexpro| which is the once-expanded form of +|\xintexpr|, as we can then chain using only one |\expandafter| each time. + +For example, here is the code employed +on the title page to compute (expandably, of course!) the 1250th Fibonacci +number: + +\begin{everbatim*} +\catcode`_ 11 +\def\Fibonacci #1{% \Fibonacci{N} computes F(N) with F(0)=0, F(1)=1. + \expandafter\Fibonacci_a\expandafter + {\the\numexpr #1\expandafter}\expandafter + {\romannumeral0\xintiiexpro 1\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro 1\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro 1\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro 0\relax}} +% +\def\Fibonacci_a #1{% + \ifcase #1 + \expandafter\Fibonacci_end_i + \or + \expandafter\Fibonacci_end_ii + \else + \ifodd #1 + \expandafter\expandafter\expandafter\Fibonacci_b_ii + \else + \expandafter\expandafter\expandafter\Fibonacci_b_i + \fi + \fi {#1}% +}% * signs are omitted from the next macros, tacit multiplications +\def\Fibonacci_b_i #1#2#3{\expandafter\Fibonacci_a\expandafter + {\the\numexpr #1/2\expandafter}\expandafter + {\romannumeral0\xintiiexpro sqr(#2)+sqr(#3)\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro (2#2-#3)#3\relax}% +}% end of Fibonacci_b_i +\def\Fibonacci_b_ii #1#2#3#4#5{\expandafter\Fibonacci_a\expandafter + {\the\numexpr (#1-1)/2\expandafter}\expandafter + {\romannumeral0\xintiiexpro sqr(#2)+sqr(#3)\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro (2#2-#3)#3\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro #2#4+#3#5\expandafter\relax\expandafter}\expandafter + {\romannumeral0\xintiiexpro #2#5+#3(#4-#5)\relax}% +}% end of Fibonacci_b_ii +% code as used on title page: +%\def\Fibonacci_end_i #1#2#3#4#5{\xintthe#5} +%\def\Fibonacci_end_ii #1#2#3#4#5{\xinttheiiexpr #2#5+#3(#4-#5)\relax} +% new definitions: +\def\Fibonacci_end_i #1#2#3#4#5{{#4}{#5}}% {F(N+1)}{F(N)} in \xintexpr format +\def\Fibonacci_end_ii #1#2#3#4#5% + {\expandafter + {\romannumeral0\xintiiexpro #2#4+#3#5\expandafter\relax + \expandafter}\expandafter + {\romannumeral0\xintiiexpro #2#5+#3(#4-#5)\relax}}% idem. +% \FibonacciN returns F(N) (in encapsulated format: needs \xintthe for printing) +\def\FibonacciN {\expandafter\xint_secondoftwo\romannumeral-`0\Fibonacci }% +\catcode`_ 8 +\end{everbatim*} + + +The macro |\Fibonacci| produces not one specific value |F(N)| but a pair of +successive values |{F(N)}{F(N+1)}| which can then serve as starting point of +another routine devoted to compute a whole sequence |F(N), F(N+1), +F(N+2),....|. Each of |F(N)| and |F(N+1)| is kept in the encapsulated internal +\xintexprname format. + +|\FibonacciN| produces the single |F(N)|. It also keeps it in the private +format; thus printing it will need the |\xintthe| prefix. + +\begingroup\footnotesize\sffamily\baselineskip 10pt +Here a code snippet which +checks the routine via a \string\message\ of the first $51$ Fibonacci +numbers (this is not an efficient way to generate a sequence of such +numbers, it is only for validating \csa{FibonacciN}). +% +\begin{everbatim} +\def\Fibo #1.{\xintthe\FibonacciN {#1}}% +\message{\xintiloop [0+1] \expandafter\Fibo\xintiloopindex., + \ifnum\xintiloopindex<49 \repeat \xintthe\FibonacciN{50}.} +\end{everbatim} +\endgroup + +The way we use |\expandafter|'s to chain successive |\xintiiexpro| evaluations +is exactly analogous to what is possible with |\numexpr|. The various +|\romannumeral0\xintiiexpro| could very well all have been |\xintiiexpr|'s but +then we would have needed |\expandafter\expandafter\expandafter| each +time. + +\begin{framed} + There is a difference though: |\numexpr| does \emph{NOT} expand inside an + |\edef|, and to force its expansion we must prefix it with |\the| or + |\number| or |\romannumeral| or another |\numexpr| which is itself prefixed, + etc\dots. + + But |\xintexpr|, |\xintiexpr|, ..., expand fully in an |\edef|, with the + completely expanded + result encapsulated in a private format. + + Using |\xintthe| as prefix is necessary to print the result (like |\the| or + |\number| in the case of |\numexpr|), but it is not necessary to get the + computation done (contrarily to the situation with |\numexpr|). +\end{framed} + + +Our |\Fibonacci| expands completely under \fexpan sion, so we can use +\hyperref[fdef]{\ttfamily\char92fdef} rather than |\edef| in a situation such +as +% +\leftedline {|\fdef \X {\FibonacciN {100}}|} +% +but it is usually about as efficient to employ |\edef|. And if we want +% +\leftedline{|\edef \Y {(\FibonacciN{100},\FibonacciN{200})}|,} +% +then |\edef| is necessary. + +Allright, so let's now give the code to generate |{F(N)}{F(N+1)}{F(N+2)}...|, +using |\Fibonacci| for the first two and then using the standard recursion +|F(N+2)=F(N+1)+F(N)|: + +\catcode`_ 11 +\def\FibonacciSeq #1#2{%#1=starting index, #2>#1=ending index + \expandafter\Fibonacci_Seq\expandafter + {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2-1}% +}% +\def\Fibonacci_Seq #1#2{% + \expandafter\Fibonacci_Seq_loop\expandafter + {\the\numexpr #1\expandafter}\romannumeral0\Fibonacci {#1}{#2}% +}% +\def\Fibonacci_Seq_loop #1#2#3#4{% standard Fibonacci recursion + {#3}\unless\ifnum #1<#4 \Fibonacci_Seq_end\fi + \expandafter\Fibonacci_Seq_loop\expandafter + {\the\numexpr #1+1\expandafter}\expandafter + {\romannumeral0\xintiiexpro #2+#3\relax}{#2}{#4}% +}% +\def\Fibonacci_Seq_end\fi\expandafter\Fibonacci_Seq_loop\expandafter + #1\expandafter #2#3#4{\fi {#3}}% +\catcode`_ 8 + +\begingroup\footnotesize\baselineskip10pt +\everb|@ +\catcode`_ 11 +\def\FibonacciSeq #1#2{%#1=starting index, #2>#1=ending index + \expandafter\Fibonacci_Seq\expandafter + {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2-1}% +}% +\def\Fibonacci_Seq #1#2{% + \expandafter\Fibonacci_Seq_loop\expandafter + {\the\numexpr #1\expandafter}\romannumeral0\Fibonacci {#1}{#2}% +}% +\def\Fibonacci_Seq_loop #1#2#3#4{% standard Fibonacci recursion + {#3}\unless\ifnum #1<#4 \Fibonacci_Seq_end\fi + \expandafter\Fibonacci_Seq_loop\expandafter + {\the\numexpr #1+1\expandafter}\expandafter + {\romannumeral0\xintiiexpro #2+#3\relax}{#2}{#4}% +}% +\def\Fibonacci_Seq_end\fi\expandafter\Fibonacci_Seq_loop\expandafter + #1\expandafter #2#3#4{\fi {#3}}% +\catcode`_ 8 +| +\endgroup + +This |\FibonacciSeq| macro is +completely expandable but it is not \fexpan dable. + +This is not a problem in the next example which uses \csbxint{For*} as the +latter applies repeatedly full expansion to what comes next each time it +fetches an item from its list argument. Thus \csbxint{For*} still manages to +generate the list via iterated full expansion. + + +\begin{figure*}[ht!] + \phantomsection\label{fibonacci} + \newcounter{myindex} + \fdef\Fibxxx{\FibonacciN {30}}% + \setcounter{myindex}{30}% +\centeredline{\tabskip 1ex +\vbox{\halign{\bfseries#.\hfil&#\hfil &\hfil #\cr + \xintFor* #1 in {\FibonacciSeq {30}{59}}\do + {\themyindex &\xintthe#1 & + \xintiiRem{\xintthe#1}{\xintthe\Fibxxx}\stepcounter{myindex}\cr }}% +}\vrule +\vbox{\halign{\bfseries#.\hfil&#\hfil &\hfil #\cr + \xintFor* #1 in {\FibonacciSeq {60}{89}}\do + {\themyindex &\xintthe#1 & + \xintiiRem{\xintthe#1}{\xintthe\Fibxxx}\stepcounter{myindex}\cr }}% +}\vrule +\vbox{\halign{\bfseries#.\hfil&#\hfil &\hfil #\cr + \xintFor* #1 in {\FibonacciSeq {90}{119}}\do + {\themyindex &\xintthe#1 & + \xintiiRem{\xintthe#1}{\xintthe\Fibxxx}\stepcounter{myindex}\cr }}% +}}% +% +\centeredline{Some Fibonacci numbers together with their residues modulo + |F(30)|\dtt{=\xintthe\Fibxxx}} +\end{figure*} + +\begingroup\footnotesize\baselineskip10pt +\everb|@ +\newcounter{myindex}% not "index", which would overwrite theindex environment! +% (many have probably been bitten by this trap) +\tabskip 1ex + \fdef\Fibxxx{\FibonacciN {30}}% + \setcounter{myindex}{30}% +\vbox{\halign{\bfseries#.\hfil&#\hfil &\hfil #\cr + \xintFor* #1 in {\FibonacciSeq {30}{59}}\do + {\themyindex &\xintthe#1 & + \xintiiRem{\xintthe#1}{\xintthe\Fibxxx}\stepcounter{myindex}\cr }}% +}\vrule +\vbox{\halign{\bfseries#.\hfil&#\hfil &\hfil #\cr + \xintFor* #1 in {\FibonacciSeq {60}{89}}\do + {\themyindex &\xintthe#1 & + \xintiiRem{\xintthe#1}{\xintthe\Fibxxx}\stepcounter{myindex}\cr }}% +}\vrule +\vbox{\halign{\bfseries#.\hfil&#\hfil &\hfil #\cr + \xintFor* #1 in {\FibonacciSeq {90}{119}}\do + {\themyindex &\xintthe#1 & + \xintiiRem{\xintthe#1}{\xintthe\Fibxxx}\stepcounter{myindex}\cr }}% +}% +| +\endgroup + +This produces the Fibonacci numbers from |F(30)| to |F(119)|, and +computes also all the +congruence classes modulo |F(30)|. The output has +been put in a \hyperref[fibonacci]{float}, which appears +\vpageref[above]{fibonacci}. I leave to the mathematically inclined +readers the task to explain the visible patterns\dots |;-)|. + +\section{The \xintname bundle} + +\localtableofcontents + +\subsection{Characteristics} + +\begin{framed} + The main characteristics are: + \begin{enumerate} + \item exact algebra on ``big numbers'', integers as well as + fractions, + \item floating point variants with user-chosen precision, + \item the computational macros are compatible with expansion-only context, + \item the bundle comes with parsers (integer-only, or handling fractions, or + doing floating point computations) of infix operations implementing + beyond infix operations extra features such as dummy variables. + \end{enumerate} + + + Since |1.2| ``big numbers'' must have less than about \dtt{19950} digits: + the maximal number of digits for addition is at \dtt{19968} digits, and it + is \dtt{19959} for multiplication. The reasonable range of use of the + package is with numbers of up to a few hundred digits.\footnotemark + + \TeX\ does not know off-hand how to print on the page such very long + numbers, see \autoref{ssec:printnumber}. +\end{framed} +\footnotetext{For example multiplication of integers having from \dtt{50} to + \dtt{100} digits takes roughly of the order of the millisecond on a 2012 + desktop computer. I compared this to using Python3: using timeit module on a + wrapper defined as |return w*z| with random integers of \dtt{100} digits, I + observe on the same computer a computation time of roughly $4.10^{-7}$s per + call. And with |return str(w*z)| then this becomes more like $16.10^{-7}$s + per call. And with |return str(int(W)*int(Z))| where |W| and |Z| are + strings, this becomes about $26.10^{-7}$s (I am deliberately ignoring + Python's Decimal module here...) Anyway, my sentence from earlier version of + this documentation: \emph{this is, I guess, at least about 1000 times slower + than what can be expected with any reasonable programming language,} is + about right. I then added: \emph{nevertheless as compilation of a typical + \LaTeX\ document already takes of the order of seconds and even dozens of + seconds for long ones, this leaves room for reasonably many computations + via \xintexprname or via direct use of the macros of + \xintname/\xintfracname.}} + +Integers with only $10$ digits and starting with a $3$ already exceed the +\TeX{} bound; and \TeX{} does not have a native processing of floating point +numbers (multiplication by a decimal number of a dimension register is allowed +--- this is used for example by the +\href{http://mirror.ctan.org/graphics/pgf/base}{pgf} basic math engine.) + +\TeX{} elementary operations on numbers are done via the non-expandable +\emph{\char92advance, \char92multiply, \emph{and} \char92divide} assignments. +This was changed with \eTeX{}'s |\numexpr| which does expandable computations +using standard infix notations with \TeX{} integers. But \eTeX{} did not +modify the \TeX{} bound on acceptable integers, and did not add floating point +support. + +The \href{http://www.ctan.org/pkg/bigintcalc}{bigintcalc} package by +\textsc{Heiko Oberdiek} provided expandable macros (using some of |\numexpr| +possibilities, when available) on arbitrarily big integers, beyond the \TeX{} +bound. It does not provide an expression parser.% +% +\footnote{One can currently use package + \href{http://ctan.org/pkg/bnumexpr}{bnumexpr} to associate the |bigintcalc| + macros with an expression parser. This may be unavailable in future if + |bnumexpr| becomes more tightly associated with future evolutions or + variants of \xintcorename.} +% +\xintname did it again using more of |\numexpr| for higher speed, and in a +later evolution added handling of exact fractions, of scientific numbers, and +an expression parser. Arbitrary precision floating points operations were +added as a derivative, and not part of the initial design goal. + +The concept of signed infinities, signed zeroes, |NaN|'s, error +traps\dots,\footnote{The latter exist as work-in-progress for some time in the + source code.} have not been implemented, only the notion of `scientific +notation with a given number of significant figures'.% +% +\footnote{multiplication of two floats with |P=\xinttheDigits| digits is + first done exactly then rounded to |P| digits, rather than using a + specially tailored multiplication for floating point numbers which + would be more efficient (it is a waste to evaluate fully the + multiplication result with |2P| or |2P-1| digits.)} + +The \LaTeX3 project has implemented expandably floating-point computations with +\dtt{16} significant figures +(\href{http://www.ctan.org/pkg/l3kernel}{l3fp}), including +functions such as exp, log, sine and cosine.\footnote{at the time of writing (2014/10/28) the + \href{http://www.ctan.org/pkg/l3kernel}{l3fp} (exactly represented) floating + point numbers have their exponents limited to $\pm$\dtt{9999}.} +% + +More directly related to the \xintname bundle there is the \liiibigint{} +package, also devoted to big integers and in development a.t.t.o.w (2015/10/09, +no division yet). It is part of the experimental trunk of the +\href{http://latex-project.org}{\LaTeX3 Project} and provides an expression +parser for expandable arithmetic with big integers. Its author Bruno +\textsc{Le Floch} succeeded brilliantly into implementing expandably the +Karatsuba multiplication algorithm and he achieves \emph{sub-quadratic growth + for the computation time}. This shows up very clearly with numbers having +thousands of digits, up to the maximum which a.t.t.o.w is at $8192$ digits. + + +The \liiibigint{} multiplication from late |2015| is observed to be roughly +|3x--4x| faster than the one from \csbxint{iiexpr} in the range of \dtt{4000} +to \dtt{5000} digits integers, and isn't far from being |9x| faster at +\dtt{8000} digits. On the other hand \csbxint{iiexpr}'s multiplication is +found to be on average roughly |2.5x| faster than \liiibigint's for numbers up +to \dtt{100} digits and the two packages achieve about the same speed at +\dtt{900} digits: but each such multiplication of numbers of \dtt{900} digits +costs about one or two tenths of a second on a 2012 desktop computer, whereas +the order of magnitude is rather the |ms| for numbers with \dtt{50--100} +digits.\footnote{I have tested this again on |2016/12/19|, but the macros have + not changed on the \liiibigint{} side and barely on the \xintcorename side, + hence I got again the same results\dots} + +Even with the superior \liiibigint{} Karatsuba multiplication it takes about +|3.5s| on this 2012 desktop computer for a single multiplication of two +\dtt{5000}-digits numbers. Hence it is not possible to do routinely such +computations in a document. I have long been thinking that without the +expandability constraint much higher speeds could be achieved, but perhaps I +have not given enough thought to sustain that optimistic stance.\footnote{The + \href{http://www.ctan.org/pkg/apnum}{apnum} package implements + (non-expandably) arbitrary precision fixed point algebra and (v1.6) + functions exp, log, sqrt, the trigonometrical direct and inverse functions.} + +I remain of the opinion that if one really wants to do computations with +\emph{thousands} of digits, one should drop the expandability requirement. +Indeed, as clearly demonstrated long ago by the +\href{http://www.ctan.org/pkg/pi}{pi computing file} by \textsc{D. Roegel} one +can program \TeX{} to compute with many digits at a much higher speed than +what \xintname achieves: but, direct access to memory storage in one form or +another seems a necessity for this kind of speed and one has to renounce at +the complete expandability.% +% +\footnote{The Lua\TeX{} project possibly makes endeavours such as \xintname + appear even more insane that they are, in truth: \xintname is able to handle + fast enough computations involving numbers with less than one hundred digits + and brings this to all engines.} + +\subsection{Floating point evaluations} +\label{ssec:floatingpoint} + +Floating point macros are provided by package \xintfracname to work with a +given arbitrary precision |P|. The default value is $P=16$ meaning that the +significands of the produced (non-zero) numbers have \dtt{16} decimal digits. +The syntax to set the precision to |P| is +% +\centeredline{|\xintDigits:=P;|} +% +The value is local to the group or environment (if using \LaTeX). To query the +current value use \csbxint{theDigits}. + +Most floating point macros accept an optional first argument |[P]| which then +sets the target precision and replaces the |\xintDigits| assigned value (the +|[P]| must be repeated if the arguments are themselves \xintfracname macros +with arguments of their own.) In this section |P| refers to the prevailing +|\xinttheDigits| float precision or to the target precision set in this way as +an optional argument. + +\csbxint{floatexpr}|[Q]...\relax| also admits an optional argument |[Q]| but +it has an altogether different meaning: the computations are always done with +the prevailing |\xinttheDigits| precision and the optional argument |Q| is +used for the final rounding. This makes sense only if |Q<\xinttheDigits| and +is intended to clean up the result from dubious last digits. + + + + + + + +\begin{framed} + The |IEEE 754|\footnotemark\ requirement of \emph{correct rounding} for + addition, subtraction, multiplication, division and square root is achieved + (in arbitrary precision) by the macros of \xintfracname hence also by the + infix operators |+|, |-|, |*|, |/|. + + This means that for operands given with at most |P| significant digits + (and arbitrary exponents) the output coincides exactly with the rounding + of the exact theoretical result (barring overflow or underflow). + + +{\footnotesize Due to a typographical oversight, this documentation + (up to |1.2j|) adjoined |^| and |**| to the above list of + infix operators. But as + is explained in \autoref{xintFloatPower}, what is guaranteed regarding + integer powers is an error of at most |0.52ulp|, not the correct rounding. + Half-integer powers are computed as square roots of integer powers.\par }% + + The rounding mode is ``round to nearest, ties away from zero''. + It is not customizable. + + Currently \xintfracname has no notion of |NaN|s or signed infinities or signed + zeroes, but this is intended for the future. +\end{framed} +% +\footnotetext{The |IEEE 754-1985| standard was for hardware implementations of + binary floating-point arithmetic with a specific value for the precision + ($24$ bits for single precision, $53$ bits for double precision). The newer + {\texttt{IEEE 754-2008}} + (\url{https://en.wikipedia.org/wiki/IEEE_floating_point}) normalizes five + basic formats, three binaries and two decimals ($16$ and $34$ decimal + digits) and discusses extended formats with higher precision. These + standards are only indirectly relevant to libraries like \xintname dealing + with arbitrary precision.% +} + + +Since release +|1.2f|, square root extraction achieves correct rounding in arbitrary +precision. + +The power +function in the expression parsers accepts integer exponents and also +half-integer exponents for float expressions.\footnote{Half-integer exponents + work inside expressions, but not via the \csbxint{FloatPower} macro.} +A preliminary implementation of fractional powers is available see +\xintlogname. Trigonometrical functions are available (\xinttrigname). + + +The maximal floating point decimal exponent is currently +\dtt{\number"7FFFFFFF} which is the maximal number handled by \TeX. The +minimal exponent is its opposite. But this means that overflow or underflow +are detected only via low-level |\numexpr| arithmetic overflows which are +basically un-recoverable. Besides there are some border effects as the +routines need to add or subtract lengths of numbers from exponents, possibly +triggering the low-level overflows. In the future not only the Precision but +also the maximal and minimal exponents |Emin| and |Emax| will be specifiable +by the user. + +Since |1.2f|, the float macros round their inputs to the target precision |P| +before further processing. Formerly, the initial rounding was done to |P+2| +digits (and at least |P+3| for the power operation.) + +The more ambitious model would be for the computing macros to obey the +intrinsic precision of their inputs, i.e. to compute the correct rounding to +|P| digits of the exact mathematical result corresponding to inputs allowed to +have their own higher precision.% +% +\footnote{The |MPFR| library + \url{http://www.mpfr.org/} implements this but it does not know fractions!} +% +This would be feasible by \xintfracname which after all knows how to compute +exactly, but I have for the time being decided that for reasons of efficiency, +the chosen model is the one of rounding inputs to the target precision first. + +The float macros of \xintfracname have to handle inputs which +not only may have much more digits than the target float precision, but may +even be fractions: in a way this means infinite precision. + +From releases |1.08a| to |1.2j| a fraction input $AeM/BeN$ had its numerator +and denominator $A$ and $B$ truncated to |Q+2| digits of precision, then the +substituted fraction was correctly rounded to |Q| digits of precision (usually +with |Q| set to |P+2|) and then the operation was implemented on such rounded +inputs. But this meant that two fractions representing the same rational +number could end up being rounded differently (with a difference of one unit +in the last place), if it had numerators and denominators with at least |Q+3| +digits. + +Starting with release |1.2k| a fractional input $AeM/BeN$ is handled +intrinsically: the fraction, independently of its representation $AeM/BeN$, is +\emph{correctly rounded} to |P| digits during the input parsing. Hence the +output depends only on its arguments as mathematical fractions and not on +their representatives as quotients. + +Notice that in float expressions, the |/| is treated as operator, and is +applied to arguments which are generally already |P|-floats, hence the above +discussion becomes relevant in this context only for the special input form +|qfloat(A/B)| or when using a sub-expression |\xintexpr A/B\relax| embedded in +the float expression with |A| or |B| having more digits than the prevailing +float precision |P|. + + + + + + +\subsection{Expansion matters} + +\subsubsection{Full expansion of the first token} +\label{ssec:expansions} + +The whole business of \xintname is to build upon |\numexpr| and handle +arbitrarily large numbers. Each basic operation is thus done via a macro: +\csbxint{iiAdd}, \csbxint{iiSub}, \csbxint{iiMul}, \csbxint{iiDivision}. In +order to handle more complex operations, it must be possible to nest these +macros. +% +An expandable macro can not execute a |\def| or an |\edef|. But the macro must +expand its arguments to find the digits it is supposed to manipulate. \TeX{} +provides a tool to do the job of (expandable !) repeated expansion of the +first token found until hitting something non expandable, such as a digit, a +|\def| token, a brace, a |\count| token, etc... is found. A space token also +will stop the expansion (and be swallowed, contrarily to the non-expandable +tokens). + +By convention in this manual \fexpan sion (``full expansion'' or ``full first +expansion'') will be this \TeX{} process of expanding repeatedly the first +token seen. For those familiar with \LaTeX3 (which is not used by \xintname) +this is what is called in its documentation full expansion (whereas expansion +inside |\edef| would be described I think as ``exhaustive'' expansion). + +Most of the package macros, and all those dealing with computations% +% +\footnote{except \csbxint{XTrunc}.}, +% +are expandable in the strong sense that they expand to their final result via +this \fexpan sion. This will be signaled in their descriptions via a +\etype{}star in the margin. + +These macros not only have this property of \fexpan dability, they all begin +by first applying \fexpan sion to their arguments. Again from \LaTeX3's +conventions this will be signaled by a% +% +\ntype{{\setbox0 \hbox{\Ff}\hbox to \wd0 {\hss f\hss}}} +% +margin annotation next to the description of the arguments. + +\subsubsection{Summary of important expandability aspects} + +\begin{enumerate} +\item the macros \fexpan d their arguments, this means that they expand the + first token seen (for each argument), then expand, etc..., until something + un-expandable such as a\strut{} digit or a brace is hit against. This + example +% + \leftedline{|\def\x{98765}\def\y{43210}| |\xintiiAdd {\x}{\x\y}|} +% + is \emph{not} a legal construct, as the |\y| will remain untouched by + expansion and not get converted into the digits which are expected by the + sub-routines of |\xintiiAdd|. It is a |\numexpr| which will expand it and an + arithmetic overflow will arise as |9876543210| exceeds the \TeX{} bounds. + The same would hold for |\xintAdd|. + + \begingroup\slshape + To the contrary \csbxint{theiiexpr} and others have no issues with + things such as |\xinttheiiexpr \x+\x\y\relax|.\hfill + \endgroup + +\item\label{fn:expansions} using |\if...\fi| constructs \emph{inside} the + package macro arguments requires suitably mastering \TeX niques + (|\expandafter|'s and/or swapping techniques) to ensure that the \fexpan sion + will indeed absorb the \csa{else} or closing \csa{fi}, else some error will + arise in further processing. Therefore it is highly recommended to use the + package provided conditionals such as \csbxint{ifEq}, \csbxint{ifGt}, + \csbxint{ifSgn},\dots\ or, for \LaTeX{} users and when dealing + with short integers the + \href{http://www.ctan.org/pkg/etoolbox}{etoolbox}% +% +\footnote{\url{http://www.ctan.org/pkg/etoolbox}} + expandable conditionals (for small integers only) such as \texttt{\char92 + ifnumequal}, \texttt{\char92 ifnumgreater}, \dots . Use of + \emph{non-expandable} things such as \csa{ifthenelse} is impossible inside the + arguments of \xintname macros. + + \begingroup\slshape + One can use naive |\if..\fi| things inside an \csbxint{theexpr}-ession + and cousins, as long as the test is + expandable, for example\upshape +% +\leftedline{|\xinttheiexpr\ifnum3>2 143\else 33\fi + 0^2\relax|$\to$\dtt{\xinttheiexpr \ifnum3>2 143\else 33\fi 0^2\relax + =1430\char`\^2}} +% + \endgroup + +\item after the definition |\def\x {12}|, one can not use + {\color{blue}|-\x|} as input to one of the package macros: the \fexpan sion + will act only on the minus sign, hence do nothing. The only way is to use the + \csbxint{Opp} macro (or \csbxint{iiOpp} which is integer only) + which obtains the opposite of a given number. + + \begingroup\slshape + Again, this is otherwise inside an \csbxint{theexpr}-ession or + \csbxint{thefloatexpr}-ession. There, the + minus sign may prefix macros which will expand to numbers (or parentheses + etc...) + \endgroup + +\def\x {12}% +\def\AplusBC #1#2#3{\xintAdd {#1}{\xintMul {#2}{#3}}}% + +\item \label{item:xpxp} With the definition +% +\leftedline{|\def\AplusBC #1#2#3{\xintAdd {#1}{\xintMul {#2}{#3}}}|} +% +one obtains an + expandable macro producing the expected result, not in two, but rather in + three steps: a first expansion is consumed by the macro expanding to its + definition. As the package macros expand their arguments until no more is + possible (regarding what comes first), this |\AplusBC| may be used inside + them: {|\xintAdd {\AplusBC {1}{2}{3}}{4}|} does work and returns + \dtt{\xintAdd {\AplusBC {1}{2}{3}}{4}}. + + If, for some reason, it is important to create a macro expanding in two steps + to its final value, one may either do: +% +\smallskip +% +\leftedline {|\def\AplusBC #1#2#3{\romannumeral-`0\xintAdd {#1}{\xintMul + {#2}{#3}}}|} +% +or use the \emph{lowercase} form of \csa{xintAdd}: +% +\smallskip +% +\leftedline {|\def\AplusBC #1#2#3{\romannumeral0\xintadd {#1}{\xintMul + {#2}{#3}}}|} + + and then \csa{AplusBC} will share the same properties as do the + other \xintname `primitive' macros. + +\item +The |\romannumeral0| and |\romannumeral-`0| things above look like an invitation +to hacker's territory; if it is not important that the macro expands in two +steps only, there is no reason to follow these guidelines. Just chain +arbitrarily the package macros, and the new ones will be completely expandable +and usable one within the other. + +Since release |1.07| the \csbxint{NewExpr} macro automatizes the creation of +such expandable macros: +% +\leftedline{|\xintNewExpr\AplusBC[3]{#1+#2*#3}|} +% +creates the |\AplusBC| macro doing the above and expanding in two expansion +steps. + +\item In the expression parsers of \xintexprname such as + \csbxint{expr}|..\relax|, \csbxint{floatexpr}|..\relax| the contents are + expanded completely from left to right until the ending |\relax| is found + and swallowed, and spaces and even (to some extent) catcodes do not matter. + +\item For all variants, prefixing with \csbxint{the} allows to print the + result or use it in other contexts. Shortcuts \csbxint{theexpr}, + \csbxint{thefloatexpr}, \csbxint{theiiexpr}, \dots\ are available. + +\end{enumerate} + +\subsection {Input formats for macros}\label{ssec:inputs} + +Macros can have different types of arguments (we do not consider here the +\csbxint{expr}-parsers but only the macros of +\xintcorename/\xintname/\xintfracname). In a macro description, a +margin annotation signals what is the argument type. +\begin{enumerate} +\item \TeX\ integers\ntype{\numx} are handled inside a |\numexpr..\relax| + hence may be count registers or variables. Beware that |-(1+1)| is not legal + and raises an error, but |0-(1+1)| is. Also |2\cnta| with |\cnta| a |\count| + isn't legal. Integers must be kept less than \dtt{\number "7FFFFFFF} in + absolute value, although the \emph{scaling} operation |(a*b)/c| computes the + intermediate product with twice as many bits. + + The slash |/| does a \fbox{rounded} division which is a fact of life of + |\numexpr| which I have found very annoying in at least nine cases out of + ten, not to say ninety-nine cases out of one hundred. Besides, it is at odds + with \TeX's |\divide| which does a truncated division (non-expandably). + + But to follow-suit |/| also does rounded integer division in + \csbxint{iiexpr}|..\relax|, and the operator |//| does there the truncated + division. + +\item the strict format\ntype{f} applies to macros handling big integers but + only \fexpan ding their arguments. After this \fexpan sion the input should + be a string of digits, optionally preceded by a unique minus sign. The first + digit can be zero only if it is the only digit. A plus sign is not accepted. + |-0| is not legal in the strict format. Macros of \xintname with a double + |ii| require this `strict' format for the inputs. + +\item the extended integer format\ntype{\Numf} applies when the macro parses + its arguments via \csbxint{Num}. The input may then have arbitrarily many + leading minus and plus signs, followed by leading zeroes, and further + digits. With \xintfracname loaded, \csbxint{Num} is extended to + accept fractions and its action is to truncate them to integers. + + At |1.2o| many macros from \xintcorename/\xintname which + use \csbxint{Num} to parse their arguments got deprecated, see + \autoref{ssec:coredeprecated}, \autoref{ssec:xintdeprecated}, and + \autoref{ssec:xintdeprecatedNum}. + + All these macros have now been removed at |1.3|.\CHANGEDf{1.3} + +\item the fraction input format\ntype{\Ff} applies to the arguments of + \xintfracname macros handling genuine fractions. It allows two types + of inputs: general and restricted. The restricted type is parsed faster, + but... is restricted. + \begin{description} + \item[general:] inputs of the shape |A.BeC/D.EeF|. Example: +\begin{everbatim*} +\noindent\xintRaw{+--0367.8920280e17/-++278.289287e-15}\newline +\xintRaw{+--+1253.2782e++--3/---0087.123e---5}\par +\end{everbatim*} + The input parser does not reduce fractions to smallest terms. + Here are the rules of this general fraction format: + \begin{itemize} + \item everything is optional, absent numbers are treated as zero, here are + some extreme cases: +\begin{everbatim*} +\xintRaw{}, \xintRaw{.}, \xintRaw{./1.e}, \xintRaw{-.e}, \xintRaw{e/-1} +\end{everbatim*} + \item |AB| and |DE| may start with pluses and minuses, then leading + zeroes, then digits. + \item |C| and |F| will be given to |\numexpr| and can be anything + recognized as such and not provoking arithmetic overflow (the lengths of + |B| and |E| will also intervene to build the final exponent naturally + which must obey the \TeX{} bound). + \item the |/|, |.| (numerator and/or denominator) and |e| + (numerator and/or denominator) are all optional components. + \item each of |A|, |B|, |C|, |D|, |E| and |F| may arise from \fexpan sion + of a macro. + \item the whole thing may arise from \fexpan sion, however the |/|, |.|, + and |e| should all come from this initial expansion. The |e| of + scientific notation is mandatorily lowercased. + \end{itemize} + \item[restricted:] inputs either of the shape |A[N]| or |A/B[N]|, which + represents the fraction |A/B| times |10^N|. The whole thing or + each of |A|, |B|, |N| (but then not |/| or |[|) may arise from \fexpan + sion, |A| (after expansion) \emph{must} have a unique optional minus sign + and no leading zeroes, |B| (after expansion) if present \emph{must} be a + positive integer with no signs and no leading zeroes, |[N]| if present + will be given to |\numexpr|. Any deviation from the rules above will + result in errors. + \end{description} + Notice that |*|, |+| and |-| contrarily to the |/| (which is treated simply + as a kind of delimiter) are not acceptable within arguments of this + type\ntype{\Ff} (see \autoref{sec:useofcount} + for some exceptions to this.) +\end{enumerate} + +Generally speaking, there should be no spaces among the digits in the inputs +(in arguments to the package macros). Although most would be harmless in most +macros, there are some cases where spaces could break havoc.% +\footnote{The \csbxint{Num} macro does not remove spaces between digits beyond + the first non zero ones; however this should not really alter the subsequent + functioning of the arithmetic macros, and besides, since \xintcorename 1.2 + there is an initial parsing of the entire number, during which spaces will + be gobbled. However I have not done a complete review of the legacy code to + be certain of all possibilities after |1.2| release. One thing to be aware + of is that \csa{numexpr} stops on spaces between digits (although it + provokes an expansion to see if an infix operator follows); the exponent for + \csbxint{iiPow} or the argument of the factorial \csbxint{iiFac} are only + subjected to such a \csa{numexpr} (there are a few other macros with such + input types in \xintname). If the input is given as, say |1 2\x| where + \csa{x} is a macro, the macro \csa{x} will not be expanded by the + \csa{numexpr}, and this will surely cause problems afterwards. Perhaps a + later \xintname will force \csa{numexpr} to expand beyond spaces, but I + decided that was not really worth the effort. Another immediate cause of + problems is an input of the type |\xintiiAdd{<space>\x}{\y}|, because the + space will stop the initial expansion; this will most certainly cause an + arithmetic overflow later when the \csa{x} will be expanded in a + \csa{numexpr}. Thus in conclusion, damages due to spaces are unlikely if + only explicit digits are involved in the inputs, or arguments are single + macros with no preceding space.} +So the best is to avoid them entirely. + +This is entirely otherwise inside an |\xintexpr|-ession, where spaces are +ignored (except when they occur inside arguments to some macros, thus +escaping the |\xintexpr| parser). See the \autoref{sec:expr}. + +There are also some slighly more obscure expansion types: in particular, the +\csbxint{ApplyInline} and \csbxint{For*} macros from \xinttoolsname apply a +special iterated \fexpan sion, which gobbles spaces, to the non-braced items +(braced items are submitted to no expansion because the opening brace stops +it) coming from their list argument; this is denoted by a special +symbol\ntype{{\lowast f}} in the margin. Some other macros such as +\csbxint{Sum} from \xintfracname first do an \fexpan sion, then treat each +found (braced or not) item (skipping spaces between such items) via the +general fraction input parsing, this is signaled as +here\ntype{f{$\to$}{\lowast\Ff}} in the margin where the signification of the +\lowast{} is thus a bit different from the previous case. + +A few macros from \xinttoolsname do not expand, or expand only once their +argument\ntype{n{{\color{black}\upshape, resp.}} o}. This is also +signaled in the margin with notations \`a la \LaTeX3. + + +\subsection{Output formats of macros} +\label{ssec:outputs} + +We do not consider here the \csbxint{expr}-parsers but only the macros from \xintcorename, \xintname and \xintfracname. Macros of other +components of the bundle may have their own output formats, for example for +continuous fractions with \xintcfracname. +There are mainly three types of outputs:% + +\begin{itemize}[nosep,listparindent=\leftmarginiii] +\item arithmetic macros from \xintcorename/\xintname deliver integers + in the strict format as described in the previous section. +\item arithmetic macros from \xintfracname produce on output the strict +fraction format |A/B[N]|, which stands for |(A/B)|$\times$|10^N|, where |A| +and |B| are integers, |B| is positive, and |N| is a ``short'' integer. The +output is not reduced to smallest terms. The |A| and |B| may end with zeroes +(\emph{i.e}, |N| does not represent all powers of ten). The denominator |B| is +always strictly positive. There is no |+| sign. The |-| is always first if +present (i.e. the denominator on output is always positive.) The output will +be expressed as such a fraction even if the inputs are both integers and the +mathematical result is an integer. The |B=1| is not removed.% +% +\footnote{refer to the documentation of \csbxint{PRaw} for an alternative.} +\item macros with |Float| in their names produce on output scientific +format with |P=|\nobreak\csbxint{theDigits} digits, a lowercase |e| and an +exponent |N|. The first digit is not zero, it is preceded by an optional minus +sign and is followed by a dot and |P-1| digits. Trailing zeroes are not +trimmed. There is one exceptional case: +\begin{itemize}[nosep] +\item if the value is mathematically zero, it is output as |0.e0|, + i.e. zeros after the decimal mark are removed and the exponent is always |0|. +\end{itemize} +Future versions of the package may modify this. +\end{itemize} + + +\subsection{Count registers and variables}\label{sec:useofcount} + +Inside |\xintexpr..\relax| and its variants, a count register or count control +sequence is automatically unpacked using |\number|, with tacit multiplication: +|1.23\counta| is like |1.23*\number\counta|. There +is a subtle difference between count \emph{registers} and count +\emph{variables}. In |1.23*\counta| the unpacked |\counta| variable defines a +complete operand thus |1.23*\counta 7| is a syntax error. But |1.23*\count0| +just replaces |\count0| by |\number\count0| hence |1.23*\count0 7| is like +|1.23*57| if |\count0| contains the integer value |5|. + +Regarding now the package macros, there is first the case of arguments having to +be short integers: this means that they are fed to a |\numexpr...\relax|, hence +submitted to a \emph{complete expansion} which must deliver an integer, and +count registers and even algebraic expressions with them like +|\mycountA+\mycountB*17-\mycountC/12+\mycountD| are admissible arguments (the +slash stands here for the rounded integer division done by |\numexpr|). This +applies in particular to the number of digits to truncate or round with, to the +indices of a series partial sum, \dots + +The macros allowing the extended format for long numbers or dealing with +fractions will \emph{to some extent} allow the direct use of count +registers and even infix algebra inside their arguments: a count +register |\mycountA| or |\count 255| is admissible as numerator or also as +denominator, with no need to be prefixed by |\the| or |\number|. It is possible +to have as argument an algebraic expression as would be acceptable by a +|\numexpr...\relax|, under this condition: \emph{each of the numerator and + denominator is expressed with at most \emph{nine} + tokens}.% +% +\footnote{The |1.2k| and earlier versions manual claimed up to 8 + tokens, but low-level TeX error arose if the |\numexpr...\relax| occupied + exactly 8 tokens \emph{and} evaluated to zero. With |1.2l| and later, up to + 9 tokens are always safe and one may even drop the ending |\relax|. But + well, all these explanations are somewhat silly because prefixing by |\the| + or |\number| is always working with arbitrarily many tokens.} +% +% +\footnote{Attention! in the \LaTeX{} context a + \csa{value}\texttt{\{countername\}} will behave ok only if it is first in + the input, if not it will not get expanded, and braces around the name will + be removed and chaos\IMPORTANT{} will ensue inside a \csa{numexpr}. One + should enclose the whole input in \csa{the}\csa{numexpr}|...|\csa{relax} in + such cases.} +% +Important: a slash for rounded division in a |\numexpr| should be written with +braces |{/}| to not be confused with the \xintfracname delimiter between +numerator and denominator (braces will be removed internally and the slash +will count for one token). Example: +|\mycountA+\mycountB{/}17/1+\mycountA*\mycountB|, or |\count 0+\count +2{/}17/1+\count 0*\count 2|. +% +\leftedline{|\cnta 10 \cntb 35 \xintRaw + {\cnta+\cntb{/}17/1+\cnta*\cntb}|\dtt{->\cnta 10 \cntb 35 \xintRaw + {\cnta+\cntb{/}17/1+\cnta*\cntb}}} +% +For longer algebraic expressions using +count registers, there are two possibilities: +\begin{enumerate}[nosep] +\item let the numerator and the denominator be presented as |\the\numexpr...\relax|, +\item or as |\numexpr {...}\relax| (the braces are removed during processing; + they are not legal for |\numexpr...\relax| syntax.) +\end{enumerate} +\everb|@ +\cnta 100 \cntb 10 \cntc 1 +\xintPRaw {\numexpr {\cnta*\cnta+\cntb*\cntb+\cntc*\cntc+ + 2*\cnta*\cntb+2*\cnta*\cntc+2*\cntb*\cntc}\relax/% + \numexpr {\cnta*\cnta+\cntb*\cntb+\cntc*\cntc}\relax } +| +\cnta 100 \cntb 10 \cntc 1 +% +\leftedline{\dtt{\xintPRaw {\numexpr + {\cnta*\cnta+\cntb*\cntb+\cntc*\cntc+ + 2*\cnta*\cntb+2*\cnta*\cntc+2*\cntb*\cntc}\relax/% + \numexpr {\cnta*\cnta+\cntb*\cntb+\cntc*\cntc}\relax }}} + +\subsection{Dimension registers and variables} +\label{sec:Dimensions} + +\meta{dimen} variables can be converted into (short) integers suitable for the +\xintname macros by prefixing them with |\number|. This transforms a dimension +into an explicit short integer which is its value in terms of the |sp| unit +($1/65536$\,|pt|). +When |\number| is applied to a \meta{glue} variable, the stretch and shrink +components are lost. + +For \LaTeX{} users: a length is a \meta{glue} variable, prefixing a +length macro defined by \csa{newlength} with \csa{number} will thus discard +the |plus| and |minus| glue components and return the dimension component as +described above, and usable in the \xintname bundle macros. + +This conversion is done automatically inside an +|\xintexpr|-essions, with tacit multiplication implied if prefixed by some +(integral or decimal) number. + +One may thus compute areas or volumes with no limitations, in units of |sp^2| +respectively |sp^3|, do arithmetic with them, compare them, etc..., and possibly +express some final result back in another unit, with the suitable conversion +factor and a rounding to a given number of decimal places. + +A \hyperref[tableofdimensions]{table of dimensions} illustrates that the +internal values used by \TeX{} do not correspond always to the closest +rounding. For example a millimeter exact value in terms of |sp| units is +\dtt{72.27/10/2.54*65536=\xinttheexpr trunc(72.27/10/2.54*65536,3)\relax ...} +and \TeX{} uses internally \dtt{\number\dimexpr 1mm\relax}|sp| (\TeX{} +truncates to get an integral multiple of the |sp| unit; see at the end of this +section the exact rules applied internally by \TeX). + +\begin{figure*}[ht!] +\phantomsection\label{tableofdimensions} +\begingroup\let\ignorespaces\empty + \let\unskip\empty + \def\T{\expandafter\TT\number\dimexpr} + \def\TT#1!{\gdef\tempT{#1}} + \def\E{\expandafter\expandafter\expandafter + \EE\xintexpr reduce(} + \def\EE#1!{\gdef\tempE{#1}} +\centeredline{\begin{tabular}{% + >{\bfseries\strut}c% + c% + >{\E}c<{)\relax!}@{}% + >{\xintthe\tempE}r@{${}={}$}% + >{\xinttheexpr trunc(\tempE,3)\relax...}l% + >{\T}c<{!}@{}% + >{\tempT}r% + >{\xinttheexpr round(100*(\tempT-\tempE)/\tempE,4)\relax\%}c} + \hline + Unit&% + definition&% + \omit &% + \multicolumn{2}{c}{Exact value in \texttt{sp} units\strut}&% + \omit &% + \omit\parbox{2cm}{\centering\strut\TeX's value in \texttt{sp} units\strut}&% + \omit\parbox{2cm}{\centering\strut Relative error\strut}\\\hline + cm&0.01 m&72.27/2.54*65536&&&1cm&&\\ + mm&0.001 m&72.27/10/2.54*65536&&&1mm&&\\ + in&2.54 cm&72.27*65536&&&1in&&\\ + pc&12 pt&12*65536&&&1pc&&\\ + pt&1/72.27 in&65536&&&1pt&&\\ + bp&1/72 in&72.27*65536/72&&&1bp&&\\ + \omit\hfil\llap{3}bp\strut\hfil&1/24 in&72.27*65536/24&&&3bp&&\\ + \omit\hfil\llap{12}bp\strut\hfil&1/6 in&72.27*65536/6&&&12bp&&\\ + \omit\hfil\llap{72}bp\strut\hfil&1 in&72.27*65536&&&72bp&&\\ + dd&1238/1157 pt&1238/1157*65536&&&1dd&&\\ + \omit\hfil\llap{11}dd\strut\hfil&11*1238/1157 pt&11*1238/1157*65536&&&11dd&&\\ + \omit\hfil\llap{12}dd\strut\hfil&12*1238/1157 pt&12*1238/1157*65536&&&12dd&&\\ + sp&1/65536 pt&1&&&1sp&&\\\hline + \multicolumn{8}{c}{\bfseries\large\TeX{} \strut dimensions}\\\hline +\end{tabular}} +\endgroup +\end{figure*} + +There is something quite amusing with the Didot point. According to the \TeX +Book, $1157$\,|dd|=$1238$\,|pt|. The actual internal value of $1$\,|dd| in \TeX{} is $70124$\,|sp|. We can use \xintcfracname to display the list of +centered convergents of the fraction $70124/65536$: +% +\leftedline{|\xintListWithSep{, }{\xintFtoCCv{70124/65536}}|} +% +\xintFor* #1 in {\xintFtoCCv{70124/65536}}\do {$\printnumber{#1}$, }% +and we don't find +$1238/1157$ therein, but another approximant $1452/1357$! + +And indeed multiplying $70124/65536$ by $1157$, and respectively $1357$, we find +the approximations (wait for more, later): +% +\leftedline{``$1157$\,|dd|''\dtt{=\xinttheexpr trunc(1157\dimexpr + 1dd\relax/\dimexpr 1pt\relax,12)\relax}\dots|pt|} +% +\leftedline{``$1357$\,|dd|''\dtt{=\xinttheexpr trunc(1357\dimexpr + 1dd\relax/\dimexpr 1pt\relax,12)\relax}\dots|pt|} +% +and we seemingly discover that $1357$\,|dd|=$1452$\,|pt| is \emph{far more + accurate} than +the \TeX Book formula $1157$\,|dd|=$1238$\,|pt|~! +The formula to compute $N$\,|dd| was +% +\leftedline{|\xinttheexpr trunc(N\dimexpr 1dd\relax/\dimexpr + 1pt\relax,12)\relax}|} +% + +What's the catch? The catch is that \TeX{} \emph{does not} compute $1157$\,|dd| +like we just did:% +% +\leftedline{$1157$\,|dd|=|\number\dimexpr 1157dd\relax/65536|% + \dtt{=\xintTrunc{12}{\number\dimexpr 1157dd\relax/65536}}\dots|pt|} +% +\leftedline{$1357$\,|dd|=|\number\dimexpr 1357dd\relax/65536|% + \dtt{=\xintTrunc{12}{\number\dimexpr 1357dd\relax/65536}}\dots|pt|} +% +We thus discover that \TeX{} (or rather here, e-\TeX{}, but one can check that +this works the same in \TeX82), uses $1238/1157$ as a conversion +factor (and necessarily intermediate computations simulate higher precision +than a priori available with integers less than $2^{31}$ or rather $2^{30}$ for +dimensions). Hence the $1452/1357$ ratio is irrelevant, an artefact +of the rounding (or rather, as we see, truncating) for one |dd| to be +expressed as an integral number of |sp|'s. + +Let us now +use |\xintexpr| to compute the value of the Didot point in millimeters, if +the above rule is exactly verified: +% +\leftedline{|\xinttheexpr + trunc(1238/1157*25.4/72.27,12)\relax|% + \dtt{=\xinttheexpr trunc(1238/1157*25.4/72.27,12)\relax}|...mm|} +% +This fits very well with the possible values of the Didot point as listed in +the +\href{http://en.wikipedia.org/wiki/Point_%28typography%29#Didot}{Wikipedia Article}. +% +The value $0.376065$\,|mm| is said to be \emph{the traditional value in + European printers' offices}. So the $1157$\,|dd|=$1238$\,|pt| rule refers to +this Didot point, or more precisely to the \emph{conversion factor} to be used +between this Didot and \TeX{} points. + +The actual value in millimeters of exactly one Didot point as implemented in +\TeX{} is +% +\leftedline {|\xinttheexpr trunc(\dimexpr + 1dd\relax/65536/72.27*25.4,12)\relax|} +% +\leftedline{\dtt{=\xinttheexpr trunc(\dimexpr + 1dd\relax/65536/72.27*25.4,12)\relax}|...mm|} +% +The difference of circa $5$\AA\ is arguably tiny! + +% 543564351/508000000 + +By the way the \emph{European printers' offices \emph{(dixit Wikipedia)} + Didot} is thus exactly +% +\leftedline{|\xinttheexpr reduce(.376065/(25.4/72.27))\relax|% + \dtt{=\xinttheexpr reduce(.376065/(25.4/72.27))\relax}\,|pt|} +% +and the centered convergents of this fraction are \xintFor* #1 in +{\xintFtoCCv{543564351/508000000}}\do {\dtt{\printnumber{#1}}\xintifForLast{.}{, }} We do +recover the $1238/1157$ therein! + +\begin{framed} + Here is how \TeX\ converts |abc.xyz...<unit>|. First the decimal is + \emph{rounded} to the nearest integral multiple of |1/65536|, say |X/65536|. + The |<unit>| is associated to a ratio |N/D|, which represents |<unit>/pt|. + For the Didot point the ratio is indeed |1238/1157|. \TeX\ \emph{truncates} + the fraction |XN/D| to an integer |M|. The dimension is represented by |M + sp|. + + For more details refer to:\newline + \url{http://tex.stackexchange.com/questions/338297/why-pdf-file-cannot-be-reproduced/338510#338510}. +\end{framed} + + +\subsection{\csh{ifcase}, \csh{ifnum}, ... constructs}\label{sec:ifcase} + +When using things such as |\ifcase \xintSgn{\A}| one has to make sure to leave +a space after the closing brace for \TeX{} to +stop its scanning for a number: once \TeX{} has finished expanding +|\xintSgn{\A}| and has so far obtained either |1|, |0|, or |-1|, a +space (or something `unexpandable') must stop it looking for more +digits. Using |\ifcase\xintSgn\A| without the braces is very dangerous, +because the blanks (including the end of line) following |\A| will be +skipped and not serve to stop the number which |\ifcase| is looking for. +% +\begin{everbatim*} +\begin{enumerate}[nosep]\def\A{1} +\item \ifcase \xintSgn\A 0\or OK\else ERROR\fi +\item \ifcase \xintSgn\A\space 0\or OK\else ERROR\fi +\item \ifcase \xintSgn{\A} 0\or OK\else ERROR\fi +\end{enumerate} +\end{everbatim*} + +In order to use successfully |\if...\fi| constructions either as arguments to +the \xintname bundle expandable macros, or when building up a completely +expandable macro of one's own, one needs some \TeX nical expertise (see also +\autoref{fn:expansions} on page~\pageref{fn:expansions}). + +It is thus much to be recommended to use the expandable branching macros, +provided by \xintfracname succh as \csbxint{ifSgn}, \csbxint{ifZero}, +\csbxint{ifOne}, \csbxint{ifNotZero}, \csbxint{ifTrueAelseB}, \csbxint{ifCmp}, +\csbxint{ifGt}, \csbxint{ifLt}, \csbxint{ifEq}, +\csbxint{ifInt}... See their respective documentations. All these conditionals +always have either two or three branches, and empty brace pairs |{}| for +unused branches should not be forgotten. + +If these tests are to be applied to standard \TeX{} short integers, it is more +efficient to use (under \LaTeX{}) the equivalent conditional tests from the +\href{http://www.ctan.org/pkg/etoolbox}{etoolbox}% +% +\footnote{\url{http://www.ctan.org/pkg/etoolbox}} +package. + +\subsection{No variable declarations are needed} + + There is no notion of a \emph{declaration of a variable}. + + To do a computation and assign its result to some macro |\z|, the user will employ the |\def|, |\edef|, or |\newcommand| (in \LaTeX) + as usual, keeping in mind that two expansion steps are needed, thus |\edef| + is initially the main tool: +% +\begin{everbatim*} +\def\x{1729728} \def\y{352827927} \edef\z{\xintiiMul {\x}{\y}} +\meaning\z +\end{everbatim*} + +As an alternative to |\edef| the package provides |\oodef| which expands +exactly twice the replacement text, and |\fdef| which applies \fexpan sion to +the replacement text during the definition. +\begin{everbatim*} +\def\x{1729728} \def\y{352827927} \oodef\w {\xintiiMul\x\y} \fdef\z{\xintiiMul {\x}{\y}} +\meaning\w, \meaning\z +\end{everbatim*} + +In practice |\oodef| is slower than |\edef|, except for computations ending in +very big final replacement texts (thousands of digits). On the other hand +|\fdef|\IMPORTANT{} appears to be slightly faster than |\edef| already in the +case of expansions leading to only a few dozen digits. + +\xintexprname does provide an interface to declare and assign values to +identifiers which can then be used in expressions: \autoref{xintdefvar}. + + +\subsection{When expandability is too much} + +Let's use the macros of \autoref{ssec:fibonacci} related to Fibonacci numbers. +Notice that the $47$th Fibonacci number is \dtt{\xintthe\FibonacciN {47}} thus +already too big for \TeX{} and \eTeX{}. + + +The |\FibonacciN| macro found in \autoref{ssec:fibonacci} is completely +expandable, it is even \fexpan dable. We need a wrapper with |\xintthe| +prefix +\begin{everbatim*} +\def\theFibonacciN{\xintthe\FibonacciN} +\end{everbatim*} +to print in the document or to use within |\message| (or \LaTeX\ |typeout|) to +write to the log and terminal. + +\begingroup + \def\A {1859} \def\B {1573} + \edef\X {\theFibonacciN\A} \edef\Y {\theFibonacciN\B} + \edef\GCDAB {\xintiiGCD\A\B}\edef\Z {\theFibonacciN\GCDAB} + \edef\GCDXY{\xintiiGCD\X\Y} + + The |\xintthe| prefix also allows its use it as argument to the \xintname + macros: for example if we are interested in knowing how many digits + $F(1250)$ has, it suffices to issue |\xintLen {\theFibonacciN {1250}}| + (which expands to \dtt{\xintLen {\theFibonacciN {1250}}}). Or if we want to + check the formula $gcd(F(1859),F(1573))=F(gcd(1859,1573))=F(143)$, we only + need% +% +\footnote{The + \csa{xintiiGCD} macro is provided by both the \xintgcdname package (since + |1.0|) and by the \xintname package (since |1.3d|).} +% +\begin{everbatim} +$\xintiiGCD{\theFibonacciN{1859}}{\theFibonacciN{1573}}=% + \theFibonacciN{\xintiiGCD{1859}{1573}}$ +\end{everbatim} +% +which produces: +% +\leftedline{$\dtt{\xintiiGCD{\X}{\Y}}=\dtt{\theFibonacciN{\GCDAB}}$} + +The |\theFibonacciN| macro expanded its |\xintiiGCD{1859}{1573}| argument via the +services of |\numexpr|: this step allows only things obeying the \TeX{} bound, +naturally! (but \dtt{F(\xintiiPow2{31}}) would be rather big anyhow...). + +This is very convenient but of course it repeats the complete evaluation each +time it is done. In practice, it is often useful to store the result of such +evaluations in macros. Any |\edef| will break expandability, but if the goal +is at some point to print something to the |dvi| or |pdf| output, and not only +to the |log| file, then expandability has to be broken one day or another! + +Hence, in practice, if we want to print in the document some computation +results, we can proceed like this and avoid having to repeat identical +evaluations: +\begin{everbatim} +\begingroup + \def\A {1859} \def\B {1573} + \edef\X {\theFibonacciN\A} \edef\Y {\theFibonacciN\B} + \edef\GCDAB {\xintiiGCD\A\B}\edef\Z {\theFibonacciN\GCDAB} + \edef\GCDXY{\xintiiGCD\X\Y} +The identity $\gcd(F(\A),F(\B))=F(\gcd(\A,\B))$ can be checked via evaluation +of both sides: $\gcd(F(\A),F(\B))=\gcd(\printnumber\X,\printnumber\Y)= +\printnumber{\GCDXY} = F(\gcd(\A,\B)) = F(\GCDAB) =\printnumber\Z$.\par + % some further computations involving \A, \B, \X, \Y +\endgroup % closing the group removes assignments to \A, \B, ... +% or choose longer names less susceptible to overwrite something. +% Note: there is no LaTeX \newecommand which would be to \edef like \newcommand is to \def +\end{everbatim} +The identity $\gcd(F(\A),F(\B))=F(\gcd(\A,\B))$ can be checked via evaluation +of both sides: $\gcd(F(\A),F(\B))=\gcd(\printnumber\X,\printnumber\Y)= +\printnumber{\GCDXY} = F(\gcd(\A,\B)) = F(\GCDAB) =\printnumber\Z$.\par +\endgroup + +One may legitimately ask the author: why expandability +to such extremes, for things such as big fractions or floating point numbers +(even continued fractions...) which anyhow can not be used directly within +\TeX's primitives such as |\ifnum|? Why insist on a concept +which is foreign to the vast majority of \TeX\ users and even programmers? + +I have no answer: it made definitely sense at the start of \xintname (see +\autoref{ssec:origins}) and once started I could not stop. + + +\subsection{Possible syntax errors to avoid} + +\edef\x{\xintMul {3}{5}/\xintMul{7}{9}} + +Here is a list of imaginable input errors. Some will cause compilation errors, +others are more annoying as they may pass through unsignaled. +\begin{itemize} +\item using |-| to prefix some macro: |-\xintiiSqr{35}/271|.% +% +\footnote{to the + contrary, this \emph{is} + allowed inside an |\xintexpr|-ession.} +\item using one pair of braces too many |\xintIrr{{\xintiiPow {3}{13}}/243}| (the + computation goes through with no error signaled, but the result is completely + wrong). +\item things like |\xintiiAdd { \x}{\y}| as the space will cause \csa{x} to be + expanded later, most probably within a |\numexpr| thus provoking possibly an + arithmetic overflow. +\item using |[]| and decimal points at the same time |1.5/3.5[2]|, or with a + sign in the denominator |3/-5[7]|. The scientific notation has no such + restriction, the two inputs |1.5/-3.5e-2| and |-1.5e2/3.5| are equivalent: + |\xintRaw{1.5/-3.5e-2}|\dtt{=\xintRaw{1.5/-3.5e-2}}, + |\xintRaw{-1.5e2/3.5}|\dtt{=\xintRaw{-1.5e2/3.5}}. +\item generally speaking, using in a context expecting an integer (possibly + restricted to the \TeX{} bound) a macro or expression which returns a + fraction: |\xinttheexpr 4/2\relax| outputs \dtt{\xinttheexpr 4/2\relax}, + not $2$. Use |\xintNum {\xinttheexpr 4/2\relax}| or |\xinttheiexpr 4/2\relax| + (which rounds the result to the nearest integer, here, the result is already + an integer) or |\xinttheiiexpr 4/2\relax|. Or, divide in your head |4| by + |2| and insert the result directly in the \TeX{} source. +\end{itemize} + +\subsection{Error messages} + +In situations such as division by zero, the \TeX{} run will be interrupted +with some error message. The user is asked to hit the RETURN key thrice, which +will display additional information. In non-interactive +|nonstopmode| the \TeX{} run goes on uninterrupted and the error data will be +found in the compilation log. + +Here is an example interactive run: +\begin{everbatim} +! Undefined control sequence. +<argument> \ ! / + DivisionByZero (hit <RET> thrice) +l.11 \xintiiDivision{123}{0} + +? +! Undefined control sequence. +<argument> \ ! / + Division of 123 by 0 +l.11 \xintiiDivision{123}{0} + +? +! Undefined control sequence. +<argument> \ ! / + next: {0}{0} +l.11 \xintiiDivision{123}{0} + +? +[1] (./temptest.aux) ) +Output written on temptest.dvi (1 page, 216 bytes). +Transcript written on temptest.log. +\end{everbatim} + +This is an experimental feature, which is in preparation for next major +release.% +% +\footnote{The related macros checking or resetting error flags are implemented + in embryonic form but no user interface is provided with |1.2l| release.} +% +For the good functioning of this the macro with the weird appearance +{\catcode`/ 11 \catcode`! 11 \catcode32 11 |\ ! /|} (yes, this is a single +control sequence) must be left undefined. I trust it will be |;-)|.% +% +\footnote{The implementation is cloned from \LaTeX3, the + {\catcode`/ 11 \catcode`! 11 \catcode32 11 |\ ! /|} was chosen for its + shortness.} + +Deprecated macros also generate an (expandable) error message. Just hit the +|RETURN| key once to proceed.\IMPORTANT\ Most deprecated macros at |1.2o| are +listed either in \autoref{ssec:coredeprecated} or +\autoref{ssec:xintdeprecated} or \autoref{ssec:xintdeprecatedNum}. All +were removed at |1.3|.\CHANGED{1.3} + +The expression parsers are at |1.2l| still using a slightly less evolved +method which lets \TeX{} display an undefined control sequence name giving +some indication of the underlying problem (we copied this method from the +|bigintcalc| package). The name of the control sequence is the message. + +\begin{multicols}{2}\parskip0pt\relax +\begin{everbatim} +\xintError:ignored +\xintError:removed +\xintError:inserted +\xintError:unknownfunction +\xintError:we_are_doomed +\xintError:missing_xintthe! +\end{everbatim} +\end{multicols} + + +Some constructs in \xintexprname-essions use delimited macros and there is +thus possibility in case of an ill-formed expression to end up beyond the +|\relax| end-marker. Such a situation can also occur from a non-terminated +|\numexpr|: +\begin{everbatim} +\xinttheexpr 3 + \numexpr 5+4\relax followed by some LaTeX code... +\end{everbatim} +as the |\numexpr| will swallow the |\relax| whose presence is mandatory for +|\xinttheexpr|, errors will inevitably arise and may +lead to very cryptic messages; but nothing unusual or especially traumatizing +for the daring experienced \TeX/\LaTeX\ user, whose has seen zillions of +un-helpful error messages already in her daily practice of +\TeX/\LaTeX.\footnote{not to mention the \LaTeX\ error messages used by + Emacs AUC\TeX\ mode also for Plain \TeX\ runs...} + + +\subsection{Package namespace, catcodes} + + +The bundle packages needs that the \csa{space} and \csa{empty} control +sequences are pre-defined with the identical meanings as in Plain \TeX{} (or +\LaTeX2e which has the same macros). + +Private macros of \xintkernelname, \xintcorename, \xinttoolsname, +\xintname, \xintfracname, \xintexprname, \xintbinhexname, \xintgcdname, +\xintseriesname, and \xintcfracname{} use one or more underscores |_| as +private letter, to reduce the risk of getting overwritten. They almost +all begin either with |\XINT_| or with |\xint_|, a handful of these +private macros such as \csa{XINTsetupcatcodes}, \csa{XINTdigits} and +those with names such as |\XINTinFloat...| or |\XINTinfloat...| do not +have any underscore in their names (for obscure legacy reasons). + +\xintkernelname provides \hyperref[odef]{|\odef|}, \hyperref[oodef]{|\oodef|}, +\hyperref[fdef]{|\fdef|}: if macros with these names already exist +\xinttoolsname will not overwrite them. The same meanings are independently +available under the names |\xintodef|, |\xintoodef|, etc... + +Apart from |\thexintexpr|, |\thexintiexpr|, ... +all other public macros from the \xintname bundle packages start with |\xint|. + +For the good functioning of the macros, standard catcodes are assumed for the +minus sign, the forward slash, the square brackets, the letter `e'. These +requirements are dropped inside an |\xintexpr|-ession: spaces are gobbled, +catcodes mostly do not matter, the |e| of scientific notation may be |E| (on +input) \dots{} + +If a character used in the |\xintexpr| syntax is made active, +this will surely cause problems; prefixing it with |\string| is one option. +There is \csbxint{exprSafeCatcodes} and \csbxint{exprRestoreCatcodes} to +temporarily turn off potentially active characters. + +\begin{framed} + For advanced \TeX\ users. At loading time of the packages the + catcode configuration may be arbitrary as long as it satisfies the following + requirements: the percent is of category code comment character, the + backslash is of category code escape character, digits have category code + other and letters have category code letter. Nothing else is assumed. +\end{framed} + +As pointed out in previous section the control sequence {\catcode`/ 11 + \catcode`! 11 \catcode32 11 |\ ! /|} must be left undefined. + +\subsection{Origins of the package} +\label{ssec:origins} + +|2013/03/28.| Package |bigintcalc| by \textsc{Heiko Oberdiek} already +provides expandable arithmetic operations on ``big integers'', +exceeding the \TeX{} limits (of $2^{31}-1$), so why another% +% +\footnote{this section was written before the \xintfracname package; the + author is not aware of another package allowing expandable + computations with arbitrarily big fractions.} +% +one? + +I got started on this in early March 2013, via a thread on the +|c.t.tex| usenet group, where \textsc{Ulrich D\,i\,e\,z} used the +previously cited package together with a macro (|\ReverseOrder|) +which I had contributed to another thread.% +% +\footnote{the \csa{ReverseOrder} could be avoided in that circumstance, + but it does play a crucial r\^ole here.} +% +What I had learned in this +other thread thanks to interaction with \textsc{Ulrich D\,i\,e\,z} and +\textsc{GL} on expandable manipulations of tokens motivated me to +try my hands at addition and multiplication. + +I wrote macros \csa{bigMul} and \csa{bigAdd} which I posted to the +newsgroup; they appeared to work comparatively fast. These first +versions did not use the \eTeX{} \csa{numexpr} primitive, they worked +one digit at a time, having previously stored carry-arithmetic in +1200 macros. + +I noticed that the |bigintcalc| package used \csa{numexpr} +if available, but (as far as I could tell) not +to do computations many digits at a time. Using \csa{numexpr} for +one digit at a time for \csa{bigAdd} and \csa{bigMul} slowed them +a tiny bit but avoided cluttering \TeX{} memory with the 1200 +macros storing pre-computed digit arithmetic. I wondered if some speed +could be gained by using \csa{numexpr} to do four digits at a time +for elementary multiplications (as the maximal admissible number +for \csa{numexpr} has ten digits). + +|2013/04/14|. This initial \xintname was followed by \xintfracname which +handled exactly fractions and decimal numbers. + +|2013/05/25|. Later came \xintexprname and at the same time \xintfracname got +extended to handle floating point numbers. + +|2013/11/22|. Later, \xinttoolsname was detached. + +|2014/10/28|. Release |1.1| significantly extended the \xintexprname parsers. + +|2015/10/10|. Release |1.2| rewrote the core integer routines which had +remained essentially unmodified, apart from a slight improvement of division +early 2014. + +This |1.2| release also got its impulse from a fast +``reversing'' macro, which I wrote after my interest got awakened again as a +result of correspondance with Bruno \textsc{Le Floch} during September 2015: +this new reverse uses a \TeX nique which \emph{requires} the tokens to be +digits. I wrote a routine which works (expandably) in quasi-linear time, but a +less fancy |O(N^2)| variant which I developed concurrently proved to be faster +all the way up to perhaps $7000$ digits, thus I dropped the quasi-linear one. +The less fancy variant has the advantage that \xintname can handle numbers +with more than $19900$ digits (but not much more than $19950$). This is with +the current common values of the input save stack and maximal expansion depth: +$5000$ and $10000$ respectively. + + +\section{Some utilities from the \xinttoolsname package}\label{sec:sometoolsutils} + +This is a first overview. Many examples combining these utilities with the +arithmetic macros of \xintname are to be found in \autoref{sec:tools}. See +also \autoref{sec:examples}. + +\subsection{Assignments}\label{sec:assign} + +\xintAssign {357}{323}\to\tmpA\tmpB +\xintAssign \xintBezout{357}{323}\to\tmpU\tmpV\tmpD + +It might not be necessary to maintain at all times complete expandability. A +devoted syntax is provided to make these things more efficient, for example when +using the \csbxint{iiDivision} macro which computes both quotient and remainder +at +the same time: +% +\leftedline{\csbxint{Assign} + |\xintiiDivision{\xintiiPow {2}{1000}}{\xintiiFac{100}}\A\B|} +% +give: +\xintAssign\xintiiDivision{\xintiiPow {2}{1000}}{\xintiiFac{100}}\to\A\B +|\meaning\A|\dtt{: \printnumber{\meaning\A}\relax} and +|\meaning\B|\dtt{: \printnumber{\meaning\B}\relax}. +% +Another example (which uses \csbxint{Bezout} from the \xintgcdname package): +% +\leftedline{\csbxint{Assign} +% + |\xintBezout{357}{323}\to\U\V\D|} +% +is equivalent to setting |\U| to +\dtt{\tmpU}, |\V| to \dtt{\tmpV}, and |\D| to \dtt{\tmpD}. And indeed +\dtt{$\tmpU\times\tmpA+\tmpV\times\tmpB= + \xintiiAdd{\xintiiMul\tmpU\tmpA}{\xintiiMul\tmpV\tmpB}$} is a Bézout Identity. + +Thus, what |\xintAssign| does is to first apply an +\hyperref[ssec:expansions]{\fexpan sion} to what comes next; it then defines one +after the other (using |\def|; an optional argument allows to modify the +expansion type, see \autoref{xintAssign} for details), the macros found after +|\to| to correspond to the successive braced contents (or single tokens) located +prior to |\to|. In case the first token (after the +optional parameter within brackets, \emph{cf.} the \csbxint{Assign} detailed +document) is not an opening brace |{|, |\xintAssign| consider that there is + only one macro to define, and that its replacement text should be all that + follows until the |\to|. + +\xintAssign +{3570902836026}{200467139463}\to\tmpA\tmpB +\xintAssign +\xintBezout{3570902836026}{200467139463}\to\tmpU\tmpV\tmpD + +\leftedline +{\csbxint{Assign}|\xintBezout{3570902836026}{200467139463}\to\U\V\D|} +\noindent +gives then |\U| with meaning \dtt{\tmpU}, + |\V| with meaning \dtt{\tmpV} and |\D| with meaning \dtt{\tmpD}. + +% +In situations when one does not know in advance the number of items, one has +\csbxint{AssignArray} or its synonym \csbxint{DigitsOf}: +% +\leftedline{\csbxint{DigitsOf}|\xintiiPow{2}{100}\to|\csa{DIGITS}} +% +This defines \csa{DIGITS} to be macro with one parameter, \csa{DIGITS}|{0}| +gives the size |N| of the array and \csa{DIGITS}|{n}|, for |n| from |1| to |N| +then gives the |n|th element of the array, here the |n|th digit of $2^{100}$, +from the most significant to the least significant. As usual, the generated +macro \csa{DIGITS} is completely expandable (in two steps). As it wouldn't make +much sense to allow indices exceeding the \TeX{} bounds, the macros created by +\csbxint{AssignArray} put their argument inside a \csa{numexpr}, so it is +completely expanded and may be a count register, not necessarily prefixed by +|\the| or |\number|. Consider the following code snippet: +% +\begin{everbatim*} +% \newcount\cnta +% \newcount\cntb +\begingroup +\xintDigitsOf\xintiiPow{2}{100}\to\DIGITS +\cnta = 1 +\cntb = 0 +\loop +\advance \cntb \xintiiSqr{\DIGITS{\cnta}} +\ifnum \cnta < \DIGITS{0} +\advance\cnta 1 +\repeat + +|2^{100}| (=\xintiiPow {2}{100}) has \DIGITS{0} digits and the sum of their squares is \the\cntb. +These digits are, from the least to the most significant: \cnta = \DIGITS{0} \loop +\DIGITS{\cnta}\ifnum \cnta > 1 \advance\cnta -1 , \repeat.\endgroup +\end{everbatim*} + +Warning: \csbxint{Assign}, \csbxint{AssignArray} and \csbxint{DigitsOf} +\emph{do not do any check} on whether the macros they define are already +defined. + + +\subsection{Utilities for expandable manipulations}\label{sec:utils} + +The package now has more utilities to deal expandably with `lists of things', +which were treated un-expandably in the previous section with \csa{xintAssign} +and \csa{xintAssignArray}: \csbxint{ReverseOrder} and \csbxint{Length} since the +first release, \csbxint{Apply} and \csbxint{ListWithSep} since |1.04|, +\csbxint{RevWithBraces}, \csbxint{CSVtoList}, \csbxint{NthElt} since |1.06|, +\csbxint{ApplyUnbraced}, since |1.06b|, \csbxint{loop} and \csbxint{iloop} since +|1.09g|.% +% +\footnote{All these utilities, as well as \csbxint{Assign}, + \csbxint{AssignArray} and the \csbxint{For} loops are now available from the + \xinttoolsname package, independently of the big integers facilities of + \xintname.} + +As an example the following code uses only expandable operations: +\begin{everbatim*} +$2^{100}$ (=\xintiiPow {2}{100}) has \xintLen{\xintiiPow {2}{100}} digits and the sum of their +squares is \xintiiSum{\xintApply {\xintiiSqr}{\xintiiPow {2}{100}}}. These digits are, from the +least to the most significant: \xintListWithSep {, }{\xintRev{\xintiiPow {2}{100}}}. The thirteenth +most significant digit is \xintNthElt{13}{\xintiiPow {2}{100}}. The seventh least significant one +is \xintNthElt{7}{\xintRev{\xintiiPow {2}{100}}}. +\end{everbatim*} + +It would be more efficient to do once and for all +|\edef\z{\xintiiPow {2}{100}}|, and then use |\z| in place of + |\xintiiPow {2}{100}| everywhere as this would spare the CPU some repetitions. + +Expandably computing primes is done in \autoref{xintSeq}. + +\subsection{A new kind of for loop} + +As part of the \hyperref[sec:tools]{utilities} coming with the \xinttoolsname +package, there is a new kind of for loop, \csbxint{For}. Check it out +(\autoref{xintFor} and also in next section). + +\subsection{A new kind of expandable loop} + +Also included in \xinttoolsname, \csbxint{iloop} is an expandable loop giving +access to an iteration index, without using count registers which would break +expandability. Check it out (\autoref{xintiloop} and also in next section). + + + +\section {Additional examples using \xinttoolsname or \xintexprname or both} +\label{sec:examples} + +Note: \xintexprname.sty automatically loads \xinttoolsname.sty. + +\subsection{Completely expandable prime test} +\label{ssec:primesI} + +Let us now construct a completely expandable macro which returns $1$ if its +given input is prime and $0$ if not: +\everb|@ +\def\remainder #1#2{\the\numexpr #1-(#1/#2)*#2\relax } +\def\IsPrime #1% + {\xintANDof {\xintApply {\remainder {#1}}{\xintSeq {2}{\xintiiSqrt{#1}}}}} +| + +This uses \csbxint{iiSqrt} and assumes its input is at least $5$. Rather than +\xintname's own \csbxint{iiRem} we used a quicker |\numexpr| expression as we +are dealing with short integers. Also we used \csbxint{ANDof} which will +return $1$ only if all the items are non-zero. The macro is a bit +silly with an even input, ok, let's enhance it to detect an even input: +\everb|@ +\def\IsPrime #1% + {\xintiiifOdd {#1} + {\xintANDof % odd case + {\xintApply {\remainder {#1}} + {\xintSeq [2]{3}{\xintiiSqrt{#1}}}% + }% + } + {\xintifEq {#1}{2}{1}{0}}% + } +| + +We used the \xintname expandable tests (on big integers or fractions) +in order for |\IsPrime| to be \fexpan dable. + +Our integers are short, but without |\expandafter|'s with +|\@firstoftwo|, % @ n'est plus actif dans le dtx 1.1 ! +or some other related techniques, +direct use of |\ifnum..\fi| tests is dangerous. So to make the macro more +efficient we are going to use the expandable tests provided by the package +\href{http://ctan.org/pkg/etoolbox}{etoolbox}% +% +\footnote{\url{http://ctan.org/pkg/etoolbox}}. +% +The macro becomes: +% +\everb|@ +\def\IsPrime #1% + {\ifnumodd {#1} + {\xintANDof % odd case + {\xintApply {\remainder {#1}}{\xintSeq [2]{3}{\xintiiSqrt{#1}}}}} + {\ifnumequal {#1}{2}{1}{0}}} +| + +In the odd case however we have to assume the integer is at least $7$, as +|\xintSeq| generates an empty list if |#1=3| or |5|, and |\xintANDof| returns +$1$ when supplied an empty list. Let us ease up a bit |\xintANDof|'s work by +letting it work on only $0$'s and $1$'s. We could use: +% +\everb|@ +\def\IsNotDivisibleBy #1#2% + {\ifnum\numexpr #1-(#1/#2)*#2=0 \expandafter 0\else \expandafter1\fi} +| +\noindent +where the |\expandafter|'s are crucial for this macro to be \fexpan dable and +hence work within the applied \csbxint{ANDof}. Anyhow, now that we have loaded +\href{http://ctan.org/pkg/etoolbox}{etoolbox}, we might as well use: +% +\everb|@ +\newcommand{\IsNotDivisibleBy}[2]{\ifnumequal{#1-(#1/#2)*#2}{0}{0}{1}} +| +\noindent +Let us enhance our prime macro to work also on the small primes: +\everb|@ +\newcommand{\IsPrime}[1] % returns 1 if #1 is prime, and 0 if not + {\ifnumodd {#1} + {\ifnumless {#1}{8} + {\ifnumequal{#1}{1}{0}{1}}% 3,5,7 are primes + {\xintANDof + {\xintApply + { \IsNotDivisibleBy {#1}}{\xintSeq [2]{3}{\xintiiSqrt{#1}}}}% + }}% END OF THE ODD BRANCH + {\ifnumequal {#1}{2}{1}{0}}% EVEN BRANCH +} +| + +The input is still assumed positive. There is a deliberate blank before +\csa{IsNotDivisibleBy} to use this feature of \csbxint{Apply}: a space stops the +expansion of the applied macro (and disappears). This expansion will be done by +\csbxint{ANDof}, which has been designed to skip everything as soon as it finds +a false (i.e. zero) input. This way, the efficiency is considerably improved. + +We did generate via the \csbxint{Seq} too many potential divisors though. Later +sections give two variants: one with \csbxint{iloop} (\autoref{ssec:primesII}) +which is still expandable and another one (\autoref{ssec:primesIII}) which is a +close variant of the |\IsPrime| code above but with the \csbxint{For} loop, thus +breaking expandability. The \hyperref[ssec:primesII]{xintiloop variant} does not +first evaluate the integer square root, the \hyperref[ssec:primesIII]{xintFor + variant} still does. I did not compare their efficiencies. + + +Let us construct with this expandable primality test a table of the prime +numbers up to $1000$. We need to count how many we have in order to know how +many tab stops one shoud add in the last row.% +% +\footnote{although a tabular row may have less tabs than in the + preamble, there is a problem with the \char`\|\space\space vertical + rule, if one does that.} +% +There is some subtlety for this +last row. Turns out to be better to insert a |\\| only when we know for sure we +are starting a new row; this is how we have designed the |\OneCell| macro. And +for the last row, there are many ways, we use again |\xintApplyUnbraced| but +with a macro which gobbles its argument and replaces it with a tabulation +character. The \csbxint{For*} macro would be more elegant here. +% +\everb?@ +\newcounter{primecount} +\newcounter{cellcount} +\newcommand{\NbOfColumns}{13} +\newcommand{\OneCell}[1]{% + \ifnumequal{\IsPrime{#1}}{1} + {\stepcounter{primecount} + \ifnumequal{\value{cellcount}}{\NbOfColumns} + {\\\setcounter{cellcount}{1}#1} + {&\stepcounter{cellcount}#1}% + } % was prime + {}% not a prime, nothing to do +} +\newcommand{\OneTab}[1]{&} +\begin{tabular}{|*{\NbOfColumns}{r}|} +\hline +2 \setcounter{cellcount}{1}\setcounter{primecount}{1}% + \xintApplyUnbraced \OneCell {\xintSeq [2]{3}{999}}% + \xintApplyUnbraced \OneTab + {\xintSeq [1]{1}{\the\numexpr\NbOfColumns-\value{cellcount}\relax}}% + \\ +\hline +\end{tabular} +There are \arabic{primecount} prime numbers up to 1000. +? + +The table has been put in \hyperref[primesupto1000]{float} which appears +\vpageref{primesupto1000}. +We had to be careful to use in the last row \csbxint{Seq} with its optional +argument |[1]| so as to not generate a decreasing sequence from |1| to |0|, but +really an empty sequence in case the row turns out to already have all its +cells (which doesn't happen here but would with a number of columns dividing +$168$). +% +\newcommand{\IsNotDivisibleBy}[2]{\ifnumequal{#1-(#1/#2)*#2}{0}{0}{1}} + +\newcommand{\IsPrime}[1] + {\ifnumodd {#1} + {\ifnumless {#1}{8} + {\ifnumequal{#1}{1}{0}{1}}% 3,5,7 are primes + {\xintANDof + {\xintApply + { \IsNotDivisibleBy {#1}}{\xintSeq [2]{3}{\xintiiSqrt{#1}}}}% + }}% END OF THE ODD BRANCH + {\ifnumequal {#1}{2}{1}{0}}% EVEN BRANCH +} + +\newcounter{primecount} +\newcounter{cellcount} +\newcommand{\NbOfColumns}{13} +\newcommand{\OneCell}[1] + {\ifnumequal{\IsPrime{#1}}{1} + {\stepcounter{primecount} + \ifnumequal{\value{cellcount}}{\NbOfColumns} + {\\\setcounter{cellcount}{1}#1} + {&\stepcounter{cellcount}#1}% + } % was prime + {}% not a prime nothing to do +} +\newcommand{\OneTab}[1]{&} +\begin{figure*}[ht!] + \centering + \phantomsection\label{primesupto1000} + \begin{tabular}{|*{\NbOfColumns}{r}|} + \hline + 2\setcounter{cellcount}{1}\setcounter{primecount}{1}% + \xintApplyUnbraced \OneCell {\xintSeq [2]{3}{999}}% + \xintApplyUnbraced \OneTab + {\xintSeq [1]{1}{\the\numexpr\NbOfColumns-\value{cellcount}\relax}}% + \\ + \hline + \end{tabular} +\smallskip +\centeredline{There are \arabic{primecount} prime numbers up to 1000.} +\end{figure*} + +\subsection{Another completely expandable prime test} +\label{ssec:primesII} + +The |\IsPrime| macro from \autoref{ssec:primesI} checked expandably if a (short) +integer was prime, here is a partial rewrite using \csbxint{iloop}. We use the +|etoolbox| expandable conditionals for convenience, but not everywhere as +|\xintiloopindex| can not be evaluated while being braced. This is also the +reason why |\xintbreakiloopanddo| is delimited, and the next macro +|\SmallestFactor| which returns the smallest prime factor examplifies that. One +could write more efficient completely expandable routines, the aim here was only +to illustrate use of the general purpose \csbxint{iloop}. A little table giving +the first values of |\SmallestFactor| follows, its coding uses \csbxint{For}, +which is described later; none of this uses count registers. +% + + +\begin{everbatim*} +\let\IsPrime\undefined \let\SmallestFactor\undefined % clean up possible previous mess +\newcommand{\IsPrime}[1] % returns 1 if #1 is prime, and 0 if not + {\ifnumodd {#1} + {\ifnumless {#1}{8} + {\ifnumequal{#1}{1}{0}{1}}% 3,5,7 are primes + {\if + \xintiloop [3+2] + \ifnum#1<\numexpr\xintiloopindex*\xintiloopindex\relax + \expandafter\xintbreakiloopanddo\expandafter1\expandafter.% + \fi + \ifnum#1=\numexpr (#1/\xintiloopindex)*\xintiloopindex\relax + \else + \repeat 00\expandafter0\else\expandafter1\fi + }% + }% END OF THE ODD BRANCH + {\ifnumequal {#1}{2}{1}{0}}% EVEN BRANCH +}% +\catcode`_ 11 +\newcommand{\SmallestFactor}[1] % returns the smallest prime factor of #1>1 + {\ifnumodd {#1} + {\ifnumless {#1}{8} + {#1}% 3,5,7 are primes + {\xintiloop [3+2] + \ifnum#1<\numexpr\xintiloopindex*\xintiloopindex\relax + \xint_afterfi{\xintbreakiloopanddo#1.}% + \fi + \ifnum#1=\numexpr (#1/\xintiloopindex)*\xintiloopindex\relax + \xint_afterfi{\expandafter\xintbreakiloopanddo\xintiloopindex.}% + \fi + \iftrue\repeat + }% + }% END OF THE ODD BRANCH + {2}% EVEN BRANCH +}% +\catcode`_ 8 +{\centering + \begin{tabular}{|c|*{10}c|} + \hline + \xintFor #1 in {0,1,2,3,4,5,6,7,8,9}\do {&\bfseries #1}\\ + \hline + \bfseries 0&--&--&2&3&2&5&2&7&2&3\\ + \xintFor #1 in {1,2,3,4,5,6,7,8,9}\do + {\bfseries #1% + \xintFor #2 in {0,1,2,3,4,5,6,7,8,9}\do + {&\SmallestFactor{#1#2}}\\}% + \hline + \end{tabular}\par +} +\end{everbatim*} + +\subsection{Miller-Rabin Pseudo-Primality expandably} +\label{ssec:PrimesIV} + +This section is based on my \url{http://tex.stackexchange.com/a/165008} post. + +At the time of writing, the code at the link above is still the version from +April 2016 and it needed some hacks to get recursive (pseudo)-functions +defined. Since |1.2h| of |2016/11/20| there is \csbxint{NewFunction} which +allows us here to avoid such internal hacking. + +And since |1.3| of |2018/03/01|, it is possible to use \csbxint{defiifunc} +also for recursive definitions, so we use it here, but we can benefit from it +only for modular exponentiation as the rest of the code uses |iter| or |break| +statements which are not yet compatible with \csbxint{defiifunc}. + +The |isPseudoPrime(n)| is usable in \csbxint{iiexpr}-essions and establishes +if its (positive) argument is a Miller-Rabin PseudoPrime to the bases $2, 3, +5, 7, 11, 13, 17$. If this is true and $n<341550071728321$ (which has 15 +digits) then $n$ really is a prime number. + +Similarly $n=3825123056546413051$ (19 digits) is the smallest composite number +which is a strong pseudo prime for bases $2, 3, 5, 7, 11, 13, 17, 19$ and +$23$. It is easy to extend the code below to include these additional tests +(we could make the list of tested bases an argument too, now that I think +about it.) + +For more information see + \centeredline{\url{https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Deterministic_variants_of_the_test}} + and +\centeredline{\url{http://primes.utm.edu/prove/prove2_3.html}} + +In particular, according to \textsc{Jaeschke} \emph{On strong pseudoprimes to + several bases,} Math. Comp., 61 (1993) 915-926, if $n < 4,759,123,141$ it is +enough to establish Rabin-Miller pseudo-primality to bases $a = 2, 7, 61$ to +prove that $n$ is prime. This range is enough for \TeX\ numbers and we could +then write a very fast expandable primality test for such numbers using only +|\numexpr|. Left as an exercise\dots + +\begin{everbatim*} +% I -------------------------------- Modular Exponentiation +% Computes x^m modulo n (with m non negative). +% We will always use it with 1 < x < n + +\xintdefiifunc powmod_a(x, m, n) := + ifone(m, + % m=1, return x modulo n + x /: n, + % m > 1 test if odd or even and do recursive call + if(odd(m), (x*sqr(powmod_a(x, m//2, n))) /: n, + sqr(powmod_a(x, m//2, n)) /: n + ) + ); +\xintdefiifunc powmod(x, m, n) := if(m, powmod_a(x, m, n), 1); + +% See http://tex.stackexchange.com/a/165008 for macros written directly by a +% human. + +% For comparison here are the underlying support macros defined by +% \xintdefiifunc from the code above (since 1.3a): (with linebreaks added by +% TeX when writing to the log) + +% Function powmod_a for \xintiiexpr parser associated to \XINT_iiexpr_userfun +% c_powmod_a with meaning macro:#1#2#3->\xintiiifOne {#2}{\xintiiMod {#1}{#3}}{\x +% intiiifNotZero {\xintiiOdd {#2}}{\xintiiMod {\xintiiMul {#1}{\xintiiSqr {\xintE +% xpandArgs {XINT_iiexpr_userfunc_powmod_a}{{#1}{\xintiiDivFloor {#2}{2}}{#3}}}}} +% {#3}}{\xintiiMod {\xintiiSqr {\xintExpandArgs {XINT_iiexpr_userfunc_powmod_a}{{ +% #1}{\xintiiDivFloor {#2}{2}}{#3}}}}{#3}}} + +% Function powmod for \xintiiexpr parser associated to \XINT_iiexpr_userfunc_ +% powmod with meaning macro:#1#2#3->\xintiiifNotZero {#2}{\xintExpandArgs {XINT_i +% iexpr_userfunc_powmod_a}{{#1}{#2}{#3}}}{1} + +% II ------------------------------ Miller-Rabin compositeness witness + +% n=2^k m + 1 with m odd and k at least 1 + +% Choose 1<x<n. +% compute y=x^m modulo n +% if equals 1 we can't say anything +% if equals n-1 we can't say anything +% else put j=1, and +% compute repeatedly the square, incrementing j by 1 each time, +% thus always we have y^{2^{j-1}} +% -> if at some point n-1 mod n found, we can't say anything and break out +% -> if however we never find n-1 mod n before reaching +% z=y^{2^{k-1}} with j=k +% we then have z^2=x^{n-1}. + % Suppose z is not -1 mod n. If z^2 is 1 mod n, then n can be prime only if + % z is 1 mod n, and we can go back up, until initial y, and we have already + % excluded y=1. Thus if z is not -1 mod n and z^2 is 1 then n is not prime. + % But if z^2 is not 1, then n is not prime by Fermat. Hence (z not -1 mod n) + % implies (n is composite). (Miller test) + +% let's use again xintexpr indecipherable (except to author) syntax. Of course +% doing it with macros only would be faster. + +% Here \xintdefiifunc is not usable because not compatible with iter, break, ... +% but \xintNewFunction comes to the rescue. + +\xintNewFunction{isCompositeWitness}[4]{% x=#1, n=#2, m=#3, k=#4 + subs((y==1)?{0} + {iter(y;(j=#4)?{break(!(@==#2-1))} + {(@==#2-1)?{break(0)}{sqr(@)/:#2}},j=1++)} + ,y=powmod(#1,#3,#2))} + +% added note (2018/03/07) it is possible in the above that m=#3 is never +% zero, so we should rather call powmod_a for a small gain, but I don't +% have time to re-read the code comments and settle this. + +% III ------------------------------------- Strong Pseudo Primes + +% cf +% http://oeis.org/A014233 +% <http://mathworld.wolfram.com/Rabin-MillerStrongPseudoprimeTest.html> +% <http://mathworld.wolfram.com/StrongPseudoprime.html> + +% check if positive integer <49 si a prime. +% 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47 +\def\IsVerySmallPrime #1% + {\ifnum#1=1 \xintdothis0\fi + \ifnum#1=2 \xintdothis1\fi + \ifnum#1=3 \xintdothis1\fi + \ifnum#1=5 \xintdothis1\fi + \ifnum#1=\numexpr (#1/2)*2\relax\xintdothis0\fi + \ifnum#1=\numexpr (#1/3)*3\relax\xintdothis0\fi + \ifnum#1=\numexpr (#1/5)*5\relax\xintdothis0\fi + \xintorthat 1} + +\xintNewFunction{isPseudoPrime}[1]{% n = #1 + (#1<49)?% use ? syntax to evaluate only what is needed + {\IsVerySmallPrime{\xintthe#1}}% macro needs to be fed with #1 unlocked. + {(even(#1))? + {0} + {subs(% + % L expands to two values m, k hence isCompositeWitness does get + % its four variables x, n, m, k + isCompositeWitness(2, #1, L)? + {0}% + {isCompositeWitness(3, #1, L)? + {0}% + {isCompositeWitness(5, #1, L)? + {0}% + {isCompositeWitness(7, #1, L)? + {0}% +% above enough for N<3215031751 hence all TeX numbers + {isCompositeWitness(11, #1, L)? + {0}% +% above enough for N<2152302898747, hence all 12-digits numbers + {isCompositeWitness(13, #1, L)? + {0}% +% above enough for N<3474749660383 + {isCompositeWitness(17, #1, L)? + {0}% +% above enough for N<341550071728321 + {1}% + }% not needed to comment-out end of lines spaces inside + }% \xintexpr but this is too much of a habit for me with TeX! + }% I left some after the ? characters. + }% + }% + }% this computes (m, k) such that n = 2^k m + 1, m odd, k>=1 + , L=iter(#1//2;(even(@))?{@//2}{break(@,k)},k=1++))% + }% + }% +} + +% if needed: +%\def\IsPseudoPrime #1{\xinttheiiexpr isPseudoPrime(#1)\relax} + +\noindent The smallest prime number at least equal to 3141592653589 is +\xinttheiiexpr + seq(isPseudoPrime(3141592653589+n)? + {break(3141592653589+n)}{omit}, n=0++)\relax. +% we could not use 3141592653589++ syntax because it works only with TeX numbers +\par +\end{everbatim*} + + + + + +\subsection{A table of factorizations} +\label{ssec:factorizationtable} + +As one more example with \csbxint{iloop} let us use an alignment to display the +factorization of some numbers. The loop will actually only play a minor r\^ole +here, just handling the row index, the row contents being almost entirely +produced via a macro |\factorize|. The factorizing macro does not use +|\xintiloop| as it didn't appear to be the convenient tool. As |\factorize| will +have to be used on |\xintiloopindex|, it has been defined as a delimited macro. + +To spare some fractions of a second in the compilation time of this document +(which has many many other things to do), \number"7FFFFFED{} and +\number"7FFFFFFF, which turn out to be prime numbers, are not given to +|factorize| but just typeset directly; this illustrates use of +\csbxint{iloopskiptonext}. + +The code next generates a \hyperref[floatfactorize]{table} which has +been made into a float appearing \vpageref{floatfactorize}. Here is now +the code for factorization; the conditionals use the package provided +|\xint_firstoftwo| and |\xint_secondoftwo|, one could have employed +rather \LaTeX{}'s own |\@firstoftwo| and |\@secondoftwo|, or, simpler +still in \LaTeX{} context, the |\ifnumequal|, |\ifnumless| \dots, +utilities from the package |etoolbox| which do exactly that under the +hood. Only \TeX{} acceptable numbers are treated here, but it would be +easy to make a translation and use the \xintname macros, thus extending +the scope to big numbers; naturally up to a cost in speed. + +The reason for some strange looking expressions is to avoid arithmetic overflow. + +\begin{everbatim*} +\catcode`_ 11 +\def\abortfactorize #1\xint_secondoftwo\fi #2#3{\fi} + +\def\factorize #1.{\ifnum#1=1 \abortfactorize\fi + \ifnum\numexpr #1-2=\numexpr ((#1/2)-1)*2\relax + \expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo + \fi + {2&\expandafter\factorize\the\numexpr#1/2.}% + {\factorize_b #1.3.}}% + +\def\factorize_b #1.#2.{\ifnum#1=1 \abortfactorize\fi + \ifnum\numexpr #1-(#2-1)*#2<#2 + #1\abortfactorize + \fi + \ifnum \numexpr #1-#2=\numexpr ((#1/#2)-1)*#2\relax + \expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo + \fi + {#2&\expandafter\factorize_b\the\numexpr#1/#2.#2.}% + {\expandafter\factorize_b\the\numexpr #1\expandafter.% + \the\numexpr #2+2.}}% +\catcode`_ 8 +\begin{figure*}[ht!] +\centering\phantomsection\label{floatfactorize}\normalcolor +\tabskip1ex +\centeredline{\vbox{\halign {\hfil\strut#\hfil&&\hfil#\hfil\cr\noalign{\hrule} + \xintiloop ["7FFFFFE0+1] + \expandafter\bfseries\xintiloopindex & + \ifnum\xintiloopindex="7FFFFFED + \number"7FFFFFED\cr\noalign{\hrule} + \expandafter\xintiloopskiptonext + \fi + \expandafter\factorize\xintiloopindex.\cr\noalign{\hrule} + \ifnum\xintiloopindex<"7FFFFFFE + \repeat + \bfseries \number"7FFFFFFF&\number "7FFFFFFF\cr\noalign{\hrule} +}}} +\centeredline{A table of factorizations} +\end{figure*} +\end{everbatim*} + +\subsection{Another table of primes} +\label{ssec:primesIII} + +As a further example, let us dynamically generate a tabular with the first $50$ +prime numbers after $12345$. First we need a macro to test if a (short) number +is prime. Such a completely expandable macro was given in \autoref{ssec:primesI}, +here we consider a variant which will be slightly more efficient. This new +|\IsPrime| has two parameters. The first one is a macro which it redefines to +expand to the result of the primality test applied to the second argument. For +convenience we use the \href{http://ctan.org/pkg/etoolbox}{etoolbox} wrappers to +various |\ifnum| tests, although here there isn't anymore the constraint of +complete expandability (but using explicit |\if..\fi| in tabulars has its +quirks); equivalent tests are provided by \xintname, but they have some overhead +as they are able to deal with arbitrarily big integers. + +\def\IsPrime #1#2% +{\edef\TheNumber {\the\numexpr #2}% positive integer + \ifnumodd {\TheNumber} + {\ifnumgreater {\TheNumber}{1} + {\edef\ItsSquareRoot{\xintiiSqrt \TheNumber}% + \xintFor ##1 in {\xintintegers [3+2]}\do + {\ifnumgreater {##1}{\ItsSquareRoot} + {\def#1{1}\xintBreakFor} + {}% + \ifnumequal {\TheNumber}{(\TheNumber/##1)*##1} + {\def#1{0}\xintBreakFor } + {}% + }} + {\def#1{0}}}% 1 is not prime + {\ifnumequal {\TheNumber}{2}{\def#1{1}}{\def#1{0}}}% +}% + +\everb|@ +\def\IsPrime #1#2% """color[named]{PineGreen}#1=\Result, #2=tested number (assumed >0).;! +{\edef\TheNumber {\the\numexpr #2}%"""color[named]{PineGreen} hence #2 may be a count or \numexpr.;! + \ifnumodd {\TheNumber} + {\ifnumgreater {\TheNumber}{1} + {\edef\ItsSquareRoot{\xintiiSqrt \TheNumber}% + \xintFor """color{red}##1;! in {"""color{red}\xintintegers;! [3+2]}\do + {\ifnumgreater {"""color{red}##1;!}{\ItsSquareRoot} """color[named]{PineGreen}% "textcolor{red}{##1} is a \numexpr.;! + {\def#1{1}\xintBreakFor} + {}% + \ifnumequal {\TheNumber}{(\TheNumber/##1)*##1} + {\def#1{0}\xintBreakFor } + {}% + }} + {\def#1{0}}}% 1 is not prime + {\ifnumequal {\TheNumber}{2}{\def#1{1}}{\def#1{0}}}% +} +| + +As we used \csbxint{For} inside a macro we had to double the |#| in its |#1| +parameter. Here is now the code which creates the prime table (the table has +been put in a \hyperref[primes]{float}, which should be found on page +\pageref{primes}): + +\everb?@ +\newcounter{primecount} +\newcounter{cellcount} +\begin{figure*}[ht!] + \centering + \begin{tabular}{|*{7}c|} + \hline + \setcounter{primecount}{0}\setcounter{cellcount}{0}% + \xintFor """color{red}#1;! in {"""color{red}\xintintegers;! [12345+2]} \do +"""color[named]{PineGreen}% "textcolor{red}{#1} is a \numexpr.;! + {\IsPrime\Result{#1}% + \ifnumgreater{\Result}{0} + {\stepcounter{primecount}% + \stepcounter{cellcount}% + \ifnumequal {\value{cellcount}}{7} + {"""color{red}\the#1;! \\\setcounter{cellcount}{0}} + {"""color{red}\the#1;! &}} + {}% + \ifnumequal {\value{primecount}}{50} + {\xintBreakForAndDo + {\multicolumn {6}{l|}{These are the first 50 primes after 12345.}\\}} + {}% + }\hline +\end{tabular} +\end{figure*} +? + +\begin{figure*}[ht!] + \centering\phantomsection\label{primes} + \begin{tabular}{|*{7}c|} + \hline + \setcounter{primecount}{0}\setcounter{cellcount}{0}% + \xintFor #1 in {\xintintegers [12345+2]} \do + {\IsPrime\Result{#1}% + \ifnumgreater{\Result}{0} + {\stepcounter{primecount}% + \stepcounter{cellcount}% + \ifnumequal {\value{cellcount}}{7} + {\the#1 \\\setcounter{cellcount}{0}} + {\the#1 &}} + {}% + \ifnumequal {\value{primecount}}{50} + {\xintBreakForAndDo + {\multicolumn {6}{l|}{These are the first 50 primes after 12345.}\\}} + {}% + }\hline +\end{tabular} +\end{figure*} + +\subsection{Factorizing again} +\label{ssec:factorize} + +Here is an \fexpan dable macro which computes the factors of an integer. It +uses the \xintname macros only. +\begin{everbatim*} +\catcode`\@ 11 +\let\factorize\relax +\newcommand\Factorize [1] + {\romannumeral0\expandafter\factorize\expandafter{\romannumeral-`0#1}}% +\newcommand\factorize [1]{\xintiiifOne{#1}{ 1}{\factors@a #1.{#1};}}% +\def\factors@a #1.{\xintiiifOdd{#1} + {\factors@c 3.#1.}% + {\expandafter\factors@b \expandafter1\expandafter.\romannumeral0\xinthalf{#1}.}}% +\def\factors@b #1.#2.{\xintiiifOne{#2} + {\factors@end {2, #1}}% + {\xintiiifOdd{#2}{\factors@c 3.#2.{2, #1}}% + {\expandafter\factors@b \the\numexpr #1+\@ne\expandafter.% + \romannumeral0\xinthalf{#2}.}}% +}% +\def\factors@c #1.#2.{% + \expandafter\factors@d\romannumeral0\xintiidivision {#2}{#1}{#1}{#2}% +}% +\def\factors@d #1#2#3#4{\xintiiifNotZero{#2} + {\xintiiifGt{#3}{#1} + {\factors@end {#4, 1}}% ultimate quotient is a prime with power 1 + {\expandafter\factors@c\the\numexpr #3+\tw@.#4.}}% + {\factors@e 1.#3.#1.}% +}% +\def\factors@e #1.#2.#3.{\xintiiifOne{#3} + {\factors@end {#2, #1}}% + {\expandafter\factors@f\romannumeral0\xintiidivision {#3}{#2}{#1}{#2}{#3}}% +}% +\def\factors@f #1#2#3#4#5{\xintiiifNotZero{#2} + {\expandafter\factors@c\the\numexpr #4+\tw@.#5.{#4, #3}}% + {\expandafter\factors@e\the\numexpr #3+\@ne.#4.#1.}% +}% +\def\factors@end #1;{\xintlistwithsep{, }{\xintRevWithBraces {#1}}}% +\catcode`@ 12 +\end{everbatim*} +The macro will be acceptably efficient only with numbers having somewhat small +prime factors. +\begin{everbatim} +\Factorize{16246355912554185673266068721806243461403654781833} +\end{everbatim} +\begingroup\fdef\Z +{\Factorize{16246355912554185673266068721806243461403654781833}} +\noindent{\small\dtt{\Z}} + + +It puts a little stress on the input save stack in order +not be bothered with previously gathered things.\footnote{2015/11/18 I have + not revisited this code for a long time, and perhaps I could improve it now + with some new techniques.} + +Its output is a comma separated list with the number first, then its prime +factors with multiplicity. Let's produce something prettier: +\begin{everbatim*} +\catcode`_ 11 +\def\ShowFactors #1{\expandafter\ShowFactors_a\romannumeral-`0\Factorize{#1},\relax,\relax,} +\def\ShowFactors_a #1,{#1=\ShowFactors_b} +\def\ShowFactors_b #1,#2,{\if\relax#1\else#1^{#2}\expandafter\ShowFactors_b\fi} +\catcode`_ 8 +\end{everbatim*} +\begin{everbatim} +$$\ShowFactors{16246355912554185673266068721806243461403654781833}$$ +\end{everbatim} +$$\csname ShowFactors_a\expandafter\endcsname\Z,\relax,\relax,$$ +\endgroup + +If we only considered small integers, we could write pure |\numexpr| methods +which would be very much faster (especially if we had a table of small primes +prepared first) but still ridiculously slow compared to any non expandable +implementation, not to mention use of programming languages directly accessing +the CPU registers\dots + +\subsection{The Quick Sort algorithm illustrated}\label{ssec:quicksort} + +First a completely expandable macro which sorts a comma separated list of +numbers.% +% +\footnote{The code in earlier versions of this manual handled inputs composed + of braced items. I have switched to comma separated inputs on the occasion + of \url{http://tex.stackexchange.com/a/273084}. The version here is like + |code 3| on \url{http://tex.stackexchange.com} (which is about |3x| faster + than the earlier code it replaced in this manual) with a modification to + make it more efficient if the data has many repeated values. + + A faster routine (for sorting hundreds of values) is provided as |code 6| at + the link mentioned in the footnote, it is based on Merge Sort, but limited + to inputs which one can handle as \TeX{} dimensions.% + + This |code 6| could be extended to handle more general numbers, as + acceptable by \xintfracname. I have also written a non expandable version, + which is even faster, but this matters really only when handling hundreds or + rather thousands of values.} +% + +The |\QSx| macro expands its list argument, which may thus be a macro; its +comma separated items must expand to integers or decimal numbers or fractions +or scientific notation as acceptable to \xintfracname, but if an item is +itself some (expandable) macro, this macro will be expanded each time the item +is considered in a comparison test! This is actually good if the macro expands +in one step to the digits, and there are many many digits, but bad if the macro +needs to do many computations. Thus |\QSx| should be used with either explicit +numbers or with items being macros expanding in one step to the numbers +(particularly if these numbers are very big). + +If the interest is only in \TeX{} integers, then one should replace the +|\xintifCmp| macro with a suitable conditional, possibly helped by tools such as +|\ifnumgreater|, |\ifnumequal| and |\ifnumless| from +\href{http://ctan.org/pkg/etoolbox}{etoolbox} (\LaTeX{} only; I didn't see a +direct equivalent to |\xintifCmp|.) Or, if we are dealing with decimal numbers +with at most four+four digits, then one should use suitable |\ifdim| tests. +Naturally this will boost consequently the speed, from having skipped all the +overhead in parsing fractions and scientific numbers as are acceptable by +\xintfracname macros, and subsequent treatment. + +\begin{everbatim*} +% THE QUICK SORT ALGORITHM EXPANDABLY +% \usepackage{xintfrac} in the preamble (latex) +\makeatletter +% use extra safe delimiters +\catcode`! 3 \catcode`? 3 +\def\QSx {\romannumeral0\qsx }% +% first we check if empty list (else \qsx@finish will not find a comma) +\def\qsx #1{\expandafter\qsx@a\romannumeral-`0#1,!,?}% +\def\qsx@a #1{\ifx,#1\expandafter\qsx@abort\else + \expandafter\qsx@start\fi #1}% +\def\qsx@abort #1?{ }% +\def\qsx@start {\expandafter\qsx@finish\romannumeral0\qsx@b,}% +\def\qsx@finish ,#1{ #1}% +% +% we check if empty of single and if not pick up the first as Pivot: +\def\qsx@b ,#1#2,#3{\ifx?#3\xintdothis\qsx@empty\fi + \ifx!#3\xintdothis\qsx@single\fi + \xintorthat\qsx@separate {#1#2}{}{}{#1#2}#3}% +\def\qsx@empty #1#2#3#4#5{ }% +\def\qsx@single #1#2#3#4#5?{, #4}% +\def\qsx@separate #1#2#3#4#5#6,% +{% + \ifx!#5\expandafter\qsx@separate@done\fi + \xintifCmp {#5#6}{#4}% + \qsx@separate@appendtosmaller + \qsx@separate@appendtoequal + \qsx@separate@appendtogreater {#5#6}{#1}{#2}{#3}{#4}% +}% +% +\def\qsx@separate@appendtoequal #1#2{\qsx@separate {#2,#1}}% +\def\qsx@separate@appendtogreater #1#2#3{\qsx@separate {#2}{#3,#1}}% +\def\qsx@separate@appendtosmaller #1#2#3#4{\qsx@separate {#2}{#3}{#4,#1}}% +% +\def\qsx@separate@done\xintifCmp #1% + \qsx@separate@appendtosmaller + \qsx@separate@appendtoequal + \qsx@separate@appendtogreater #2#3#4#5#6#7?% +{% + \expandafter\qsx@f\expandafter {\romannumeral0\qsx@b #4,!,?}{\qsx@b #5,!,?}{#3}% +}% +% +\def\qsx@f #1#2#3{#2, #3#1}% +% +\catcode`! 12 \catcode`? 12 +\makeatother + +% EXAMPLE +\begingroup +\edef\z {\QSx {1.0, 0.5, 0.3, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, + 1.3, 1.1, 0.7, 1.6, 0.6, 0.9, 0.8, 0.2, 0.1, 1.9}} +\meaning\z + +\def\a {3.123456789123456789}\def\b {3.123456789123456788} +\def\c {3.123456789123456790}\def\d {3.123456789123456787} +\oodef\z {\QSx { \a, \b, \c, \d}}% +% The space before \a to let it not be expanded during the conversion from CSV +% values to List. The \oodef expands exactly twice (via a bunch of \expandafter's) +\meaning\z +\endgroup +\end{everbatim*} (the spaces after \string\d, etc... come from the use of the +|\meaning| primitive.) + +The choice of pivot as first element is bad if the list is already almost +sorted. Let's add a variant which will pick up the pivot index randomly. The +previous routine worked also internally with comma separated lists, but for a +change this one will use internally lists of braced items (the initial +conversion via \csbxint{CSVtoList} handles all potential spurious space +problems). + +\unless\ifxetex % pour tester compilation de xint.dtx avec xetex qui n'a pas + % \pdfuniformdeviate +\begin{everbatim*} +% QuickSort expandably on comma separated values with random choice of pivots +% ====> Requires availability of \pdfuniformdeviate <==== +% \usepackage{xintfrac, xinttools} in preamble +\makeatletter +\def\QSx {\romannumeral0\qsx }% This is a f-expandable macro. +% This converts from comma separated values on input and back on output. +% **** NOTE: these steps (and the other ones too, actually) are costly if input +% has thousands of items. +\def\qsx #1{\xintlistwithsep{, }% + {\expandafter\qsx@sort@a\expandafter{\romannumeral0\xintcsvtolist{#1}}}}% +% +% we check if empty or single or double and if not pick up the first as Pivot: +\def\qsx@sort@a #1% + {\expandafter\qsx@sort@b\expandafter{\romannumeral0\xintlength{#1}}{#1}}% +\def\qsx@sort@b #1{\ifcase #1 + \expandafter\qsx@sort@empty + \or\expandafter\qsx@sort@single + \or\expandafter\qsx@sort@double + \else\expandafter\qsx@sort@c\fi {#1}}% +\def\qsx@sort@empty #1#2{ }% +\def\qsx@sort@single #1#2{#2}% +\catcode`_ 11 +\def\qsx@sort@double #1#2{\xintifGt #2{\xint_exchangetwo_keepbraces}{}#2}% +\catcode`_ 8 +\def\qsx@sort@c #1#2{% + \expandafter\qsx@sort@sep@a\expandafter + {\romannumeral0\xintnthelt{\pdfuniformdeviate #1+\@ne}{#2}}#2?}% +\def\qsx@sort@sep@a #1{\qsx@sort@sep@loop {}{}{}{#1}}% +\def\qsx@sort@sep@loop #1#2#3#4#5% +{% + \ifx?#5\expandafter\qsx@sort@sep@done\fi + \xintifCmp {#5}{#4}% + \qsx@sort@sep@appendtosmaller + \qsx@sort@sep@appendtoequal + \qsx@sort@sep@appendtogreater {#5}{#1}{#2}{#3}{#4}% +}% +% +\def\qsx@sort@sep@appendtoequal #1#2{\qsx@sort@sep@loop {#2{#1}}}% +\def\qsx@sort@sep@appendtogreater #1#2#3{\qsx@sort@sep@loop {#2}{#3{#1}}}% +\def\qsx@sort@sep@appendtosmaller #1#2#3#4{\qsx@sort@sep@loop {#2}{#3}{#4{#1}}}% +% +\def\qsx@sort@sep@done\xintifCmp #1% + \qsx@sort@sep@appendtosmaller + \qsx@sort@sep@appendtoequal + \qsx@sort@sep@appendtogreater #2#3#4#5#6% +{% + \expandafter\qsx@sort@recurse\expandafter + {\romannumeral0\qsx@sort@a {#4}}{\qsx@sort@a {#5}}{#3}% +}% +% +\def\qsx@sort@recurse #1#2#3{#2#3#1}% +% +\makeatother + +% EXAMPLES +\begingroup +\edef\z {\QSx {1.0, 0.5, 0.3, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, + 1.3, 1.1, 0.7, 1.6, 0.6, 0.9, 0.8, 0.2, 0.1, 1.9}} +\meaning\z + +\def\a {3.123456789123456789}\def\b {3.123456789123456788} +\def\c {3.123456789123456790}\def\d {3.123456789123456787} +\oodef\z {\QSx { \a, \b, \c, \d}}% +% The space before \a to let it not be expanded during the conversion from CSV +% values to List. The \oodef expands exactly twice (via a bunch of \expandafter's) +\meaning\z + +\def\somenumbers{% +3997.6421, 8809.9358, 1805.4976, 5673.6478, 3179.1328, 1425.4503, 4417.7691, +2166.9040, 9279.7159, 3797.6992, 8057.1926, 2971.9166, 9372.2699, 9128.4052, +1228.0931, 3859.5459, 8561.7670, 2949.6929, 3512.1873, 1698.3952, 5282.9359, +1055.2154, 8760.8428, 7543.6015, 4934.4302, 7526.2729, 6246.0052, 9512.4667, +7423.1124, 5601.8436, 4433.5361, 9970.4849, 1519.3302, 7944.4953, 4910.7662, +3679.1515, 8167.6824, 2644.4325, 8239.4799, 4595.1908, 1560.2458, 6098.9677, +3116.3850, 9130.5298, 3236.2895, 3177.6830, 5373.1193, 5118.4922, 2743.8513, +8008.5975, 4189.2614, 1883.2764, 9090.9641, 2625.5400, 2899.3257, 9157.1094, +8048.4216, 3875.6233, 5684.3375, 8399.4277, 4528.5308, 6926.7729, 6941.6278, +9745.4137, 1875.1205, 2755.0443, 9161.1524, 9491.1593, 8857.3519, 4290.0451, +2382.4218, 3678.2963, 5647.0379, 1528.7301, 2627.8957, 9007.9860, 1988.5417, +2405.1911, 5065.8063, 5856.2141, 8989.8105, 9349.7840, 9970.3013, 8105.4062, +3041.7779, 5058.0480, 8165.0721, 9637.7196, 1795.0894, 7275.3838, 5997.0429, +7562.6481, 8084.0163, 3481.6319, 8078.8512, 2983.7624, 3925.4026, 4931.5812, +1323.1517, 6253.0945}% + +\oodef\z {\QSx \somenumbers}% produced as a comma+space separated list +% black magic as workaround to the shrinkability of spaces in last line... +\hsize 87\fontcharwd\font`0 +\lccode`~=32 +\lowercase{\def~}{\discretionary{}{}{\kern\fontcharwd\font`0}}\catcode32 13 +\noindent\phantom{000}\scantokens\expandafter{\meaning\z}\par +\endgroup +\end{everbatim*} +\fi % fin de si pas xetex + + +All the previous examples were with numbers which could have been handled via +|\ifdim| tests rather than the \csbxint{ifCmp} macro from \xintfracname; using +|\ifdim| tests would naturally be faster. Even faster routine is |code 6| at +\url{http://tex.stackexchange.com/a/273084} which uses |\pdfescapestring| and a +Merge Sort algorithm. + +We then turn to a graphical illustration of the algorithm.% +% +\footnote{I have rewritten (2015/11/21) the routine to do only once (and not thrice) the + needed calls to \csa{xintifCmp}, up to the price of one additional |\edef|, + although due to the context execution time on our side is not an issue and + moreover is anyhow overwhelmed by the TikZ's activities. Simultaneously I + have updated the code \url{http://tex.stackexchange.com/a/142634/4686}. The + variant with the choice of pivot on the right has more overhead: the reason + is simply that we do not convert the data into an array, but maintain a list + of tokens with self-reorganizing delimiters.} +% +For simplicity the pivot is always chosen as the first list item. Then we also +give a variant which picks up the last item as pivot. +\begin{everbatim*} +% in LaTeX preamble: +% \usepackage{xintfrac, xinttools} +% \usepackage{color} +% or, when using Plain TeX: +% \input xintfrac.sty \input xinttools.sty +% \input color.tex +% +% Color definitions +\definecolor{LEFT}{RGB}{216,195,88} +\definecolor{RIGHT}{RGB}{208,231,153} +\definecolor{INERT}{RGB}{199,200,194} +\definecolor{INERTpiv}{RGB}{237,237,237} +\definecolor{PIVOT}{RGB}{109,8,57} +% Start of macro defintions +\makeatletter +% \catcode`? 3 % a bit too paranoid. Normal ? will do. +% +% argument will never be empty +\def\QS@cmp@a #1{\QS@cmp@b #1??}% +\def\QS@cmp@b #1{\noexpand\QS@sep@A\@ne{#1}\QS@cmp@d {#1}}% +\def\QS@cmp@d #1#2{\ifx ?#2\expandafter\QS@cmp@done\fi + \xintifCmp {#1}{#2}\tw@\@ne\z@{#2}\QS@cmp@d {#1}}% +\def\QS@cmp@done #1?{?}% +% +\def\QS@sep@A #1?{\QSLr\QS@sep@L #1\thr@@?#1\thr@@?#1\thr@@?}% +\def\QS@sep@L #1#2{\ifcase #1{#2}\or\or\else\expandafter\QS@sep@I@start\fi \QS@sep@L}% +\def\QS@sep@I@start\QS@sep@L {\noexpand\empty?\QSIr\QS@sep@I}% +\def\QS@sep@I #1#2{\ifcase#1\or{#2}\or\else\expandafter\QS@sep@R@start\fi\QS@sep@I}% +\def\QS@sep@R@start\QS@sep@I {\noexpand\empty?\QSRr\QS@sep@R}% +\def\QS@sep@R #1#2{\ifcase#1\or\or{#2}\else\expandafter\QS@sep@done\fi\QS@sep@R}% +\def\QS@sep@done\QS@sep@R {\noexpand\empty?}% +% +\def\QS@loop {% + \xintloop + % pivot phase + \def\QS@pivotcount{0}% + \let\QSLr\DecoLEFTwithPivot \let\QSIr \DecoINERT + \let\QSRr\DecoRIGHTwithPivot \let\QSIrr\DecoINERT + \centerline{\QS@list}% + % sorting phase + \ifnum\QS@pivotcount>\z@ + \def\QSLr {\QS@cmp@a}\def\QSRr {\QS@cmp@a}% + \def\QSIr {\QSIrr}\let\QSIrr\relax + \edef\QS@list{\QS@list}% compare + \let\QSLr\relax\let\QSRr\relax\let\QSIr\relax + \edef\QS@list{\QS@list}% separate + \def\QSLr ##1##2?{\ifx\empty##1\else\noexpand \QSLr {{##1}##2}\fi}% + \def\QSIr ##1##2?{\ifx\empty##1\else\noexpand \QSIr {{##1}##2}\fi}% + \def\QSRr ##1##2?{\ifx\empty##1\else\noexpand \QSRr {{##1}##2}\fi}% + \edef\QS@list{\QS@list}% gather + \let\QSLr\DecoLEFT \let\QSRr\DecoRIGHT + \let\QSIr\DecoINERTwithPivot \let\QSIrr\DecoINERT + \centerline{\QS@list}% + \repeat }% +% +% \xintFor* loops handle gracefully empty lists. +\def\DecoLEFT #1{\xintFor* ##1 in {#1} \do {\colorbox{LEFT}{##1}}}% +\def\DecoINERT #1{\xintFor* ##1 in {#1} \do {\colorbox{INERT}{##1}}}% +\def\DecoRIGHT #1{\xintFor* ##1 in {#1} \do {\colorbox{RIGHT}{##1}}}% +\def\DecoPivot #1{\begingroup\color{PIVOT}\advance\fboxsep-\fboxrule\fbox{#1}\endgroup}% +% +\def\DecoLEFTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% + \xintFor* ##1 in {#1} \do + {\xintifForFirst {\DecoPivot {##1}}{\colorbox{LEFT}{##1}}}}% +\def\DecoINERTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% + \xintFor* ##1 in {#1} \do + {\xintifForFirst {\colorbox{INERTpiv}{##1}}{\colorbox{INERT}{##1}}}}% +\def\DecoRIGHTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% + \xintFor* ##1 in {#1} \do + {\xintifForFirst {\DecoPivot {##1}}{\colorbox{RIGHT}{##1}}}}% +% +\def\QuickSort #1{% warning: not compatible with empty #1. + % initialize, doing conversion from comma separated values to a list of braced items + \edef\QS@list{\noexpand\QSRr{\xintCSVtoList{#1}}}% many \edef's are to follow anyhow +% earlier I did a first drawing of the list, here with the color of RIGHT elements, +% but the color should have been for example white, anyway I drop this first line + %\let\QSRr\DecoRIGHT + %\par\centerline{\QS@list}% +% + % loop as many times as needed + \QS@loop }% +% +% \catcode`? 12 % in case we had used a funny ? as delimiter. +\makeatother +%% End of macro definitions. +%% Start of Example +\begingroup\offinterlineskip +\small +% \QuickSort {1.0, 0.5, 0.3, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, +% 1.3, 1.1, 0.7, 1.6, 0.6, 0.9, 0.8, 0.2, 0.1, 1.9} +% \medskip +% with repeated values +\QuickSort {1.0, 0.5, 0.3, 0.8, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, + 1.3, 1.1, 0.7, 0.3, 1.6, 0.6, 0.3, 0.8, 0.2, 0.8, 0.7, 1.2} +\endgroup +\end{everbatim*} + +Here is the variant which always picks the pivot as the rightmost element. + +\begin{everbatim*} +\makeatletter +% +\def\QS@cmp@a #1{\noexpand\QS@sep@A\expandafter\QS@cmp@d\expandafter + {\romannumeral0\xintnthelt{-1}{#1}}#1??}% +% +\def\DecoLEFTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% + \xintFor* ##1 in {#1} \do + {\xintifForLast {\DecoPivot {##1}}{\colorbox{LEFT}{##1}}}} +\def\DecoINERTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% + \xintFor* ##1 in {#1} \do + {\xintifForLast {\colorbox{INERTpiv}{##1}}{\colorbox{INERT}{##1}}}} +\def\DecoRIGHTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% + \xintFor* ##1 in {#1} \do + {\xintifForLast {\DecoPivot {##1}}{\colorbox{RIGHT}{##1}}}} +\def\QuickSort #1{% + % initialize, doing conversion from comma separated values to a list of braced items + \edef\QS@list{\noexpand\QSLr {\xintCSVtoList{#1}}}% many \edef's are to follow anyhow + % + % loop as many times as needed + \QS@loop }% +\makeatother +\begingroup\offinterlineskip +\small +% \QuickSort {1.0, 0.5, 0.3, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, +% 1.3, 1.1, 0.7, 1.6, 0.6, 0.9, 0.8, 0.2, 0.1, 1.9} +% \medskip +% with repeated values +\QuickSort {1.0, 0.5, 0.3, 0.8, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, + 1.3, 1.1, 0.7, 0.3, 1.6, 0.6, 0.3, 0.8, 0.2, 0.8, 0.7, 1.2} +\endgroup +\end{everbatim*} + +The choice of the first or last item as pivot is not a good one as nearly +ordered lists will take quadratic time. But for explaining the algorithm via a +graphical interpretation, it is not that bad. If one wanted to pick up the +pivot randomly, the routine would have to be substantially rewritten: in +particular the |\Deco..withPivot| macros need to know where the pivot is, and +currently this is implemented by using either |\xintifForFirst| or +|\xintifForLast|. + +\etocdepthtag.toc {macros} +\addtocontents{toc}{\gdef\string\sectioncouleur{{joli}}} +\addtocontents{toc}{\gdef\string\SKIPSECTIONINTERSPACE{\kern\smallskipamount}} +\renewcommand{\etocaftertochook}{\addvspace{\bigskipamount}} + +\clearpage +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} +\csname xintkernelnameUp\endcsname +\section{Macros of the \xintkernelname package} +\RaisedLabel{sec:kernel} + +\localtableofcontents + +The \xintkernelname package contains mainly the common code base for handling +the load-order of the bundle packages, the management of catcodes at loading +time, definition of common constants and macro utilities which are used +throughout the code etc ... it is automatically loaded by all packages of the +bundle. + +It provides a few macros possibly useful in other contexts. + +\subsection{\csh{odef}, \csh{oodef}, \csh{fdef}} +\label{odef} +\label{oodef} +\label{fdef} + +\csa{oodef}|\controlsequence {<stuff>}| does +\everb|@ + \expandafter\expandafter\expandafter\def + \expandafter\expandafter\expandafter\controlsequence + \expandafter\expandafter\expandafter{<stuff>} +| + +This works only for a single +|\controlsequence|, with no parameter text, even without parameters. An +alternative would be: +\everb|@ +\def\oodef #1#{\def\oodefparametertext{#1}% + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\def + \expandafter\expandafter\expandafter\oodefparametertext + \expandafter\expandafter\expandafter } +| + +\noindent +but it does not allow |\global| as prefix, and, besides, would have anyhow its +use (almost) limited to parameter texts without macro parameter tokens +(except if the expanded thing does not see them, or is designed to deal with +them). + +There is a similar macro |\odef| with only one expansion of the replacement text +|<stuff>|, and |\fdef| which expands fully |<stuff>| using |\romannumeral-`0|. + +They can be prefixed with |\global|. It appears than |\fdef| is generally a bit +faster than |\edef| when expanding macros from the \xintname bundle, when the +result has a few dozens of digits. |\oodef| needs thousands of digits it seems +to become competitive. + + +\subsection{\csh{xintReverseOrder}}\label{xintReverseOrder} + +\csa{xintReverseOrder}\marg{list}\etype{n} does not do any expansion of its +argument and just reverses the order of the tokens in the \meta{list}. Braces +are removed once and the enclosed material, now unbraced, does not get +reversed. Unprotected spaces (of any character code) are gobbled. +% +\leftedline{|\xintReverseOrder{\xintDigitsOf\xintiiPow {2}{100}\to\Stuff}|} +% +\leftedline{gives: + \ttfamily{\string\Stuff\string\to1002\string\xintiiPow\string\xintDigitsOf}} + +\subsection{\csh{xintLength}} +\label{xintLength} + +\csa{xintLength}\marg{list}\etype{n} counts how many tokens (or braced items) +there are (possibly none). It does no expansion of its argument, so to use it +to count things in the replacement text of a macro |\x| one should do +|\expandafter\xintLength\expandafter{\x}|. Blanks between items are not +counted. See also \csbxint{NthElt}|{0}| (from \xinttoolsname) +which first \fexpan ds its argument and then applies the same code. +% +\leftedline{|\xintLength {\xintiiPow {2}{100}}|\dtt{=\xintLength + {\xintiiPow{2}{100}}}} +% +\leftedline{${}\neq{}$|\xintLen {\xintiiPow {2}{100}}|\dtt{=\xintLen + {\xintiiPow{2}{100}}}} + +\subsection{\csh{xintLastItem}} +\label{xintLastItem} + +\csa{xintLastItem}\marg{list}\etype{n} returns the last item (unbraced) of its +argument. If the list has no items the output is empty. + +It does no expansion, which should be obtained via suitable |\expandafter|'s. +See also \csbxint{NthElt}|{-1}| from \xinttoolsname which obtains the same +result (but with another code) after having however \fexpan ded its +argument first. + +\subsection{\csh{xintreplicate}} +\label{xintreplicate} + +\csa{romannumeral}\csa{xintreplicate}|{x}|\marg{stuff}\etype{\numx n} is simply +copied over from \LaTeX3's |\prg_replicate:nn| with some minor changes.% +% +\footnote{I started with the code from Joseph \textsc{Wright}'s answer to \url{http://tex.stackexchange.com/questions/16189/repeat-command-n-times}.} +It +does not do any expansion of its second argument but inserts it in the upcoming +token stream precisely |x| times. Using it with a negative |x| raises no error +and does nothing.% +% +\footnote{This behaviour may change in future.} + +Note that expansion must be triggered by a |\romannumeral|. + + +\subsection{\csh{xintgobble}} +\label{xintgobble} + +\csa{romannumeral}\csa{xintgobble}|{x}|\etype{\numx} is a Gobbling macro +written in the spirit of \LaTeX3's |\prg_replicate:nn| (which I cloned as +\csbxint{replicate}.) It gobbles |x| tokens upstream, with |x| allowed to be +as large as \dtt{531440}. Don't use it with |x<0|. + + +Note that expansion must be triggered by a |\romannumeral|. + +\csbxint{gobble} looks as if it must be related to \csbxint{Trim} from +\xinttoolsname, but the latter uses different code (using directly +\csbxint{gobble} is not possible because one must make sure not to gobble more +than the number of available items; and counting available items first is an +overhead which \csbxint{Trim} avoids.) It is rather\csbxint{Keep} with a +negative first argument which hands over to \csbxint{gobble} (because in that +case it is needed to count anyhow beforehand the number of items, hence +\csbxint{gobble} can then be used safely.) + +I wrote an \csa{xintcount} in the same spirit as \csa{xintreplicate} and +\csa{xintgobble}. But it needs to be counting hundreds of tokens to be worth +its salt compared to \csbxint{Length}. + +\subsection{(WIP) \csh{xintUniformDeviate}} +\label{xintUniformDeviate} + +\csa{xintUniformDeviate}|{x}|\etype{\numx} is a wrapper of engine +|\pdfuniformdeviate| (or |\uniformdeviate|).% +% +\footnote{The |\uniformdeviate| primitive has been added to Xe\TeX\ + and will be available with \TeX Live 2019 release.} +The implementation is to be +considered experimental for the time being.\NewWith{1.3b}% + +The argument is expanded in |\numexpr| and the macro itself needs two +expansion steps. It produces like the engine primitive an integer (digit +tokens) with minimal value \dtt{0} and maximal one \dtt{x-1} if |x| is +positive, or minimal value \dtt{x+1} and maximal value \dtt{0} if |x| is +negative. For the discussion next, |x| is supposed positive as this +avoids having to insert absolute values in formulas. + +The underlying engine Random Number Generator works with an array of 55 28bits +integers. To produce a « uniform » random integer in a given range +\dtt{0..x-1} it produces next pseudo-random |y| (supposedly uniformly +distributed, i.e. non-uniformity can be neglected) such that \dtt{$0\leq y < + 2^{28}$} and the output is the rounding of \dtt{$x*(y/2^{28})$}, with upper +bound |x| remapped to |0|. This has following corollaries: +\begin{enumerate} +\item with |x=2^{29}| or |x=2^{30}| the engine primitive produces only even + numbers, +\item with |x=3*2^{26}| the integers produced by the RNG when taken modulo + three obey the proportion |1:1:2|, not |1:1:1|, +\item with |x=3*2^{14}| there is analogous although weaker non-uniformity of + the random integers when taken modulo 3, +\item generally speaking pure powers of two should generate uniform random + integers, but when the range is divisible by large powers of + two, the non-uniformity may be amplified in surprising ways by modulo + operations. +\end{enumerate} +These observations are not to be construed as criticism of the engine +primitive itself, which comes from MetaPost, as the code comments and more +generally the whole of \emph{The Art of Computer Programming, Vol. 2} stresses +that it should rather be seen as producing random fractions (the unit fraction +being $2^{28}$). Using it as a generator for \emph{integers} is a bit of an +abuse. + +The first goal of \csa{xintUniformDeviate} is to guarantee a better uniformity +for the distribution of random integers in any given range |x|. + +\emph{If the probability to obtain a given |y| in |0..x-1| is + \verb$(1+e(y))/x$, the ``{relative non-uniformity}'' for that value |y| is + \verb$|e(y)|$.} + +The engine primitive guarantees only \dtt{$x/2^{28}$} relative non-uniformity, and +\csa{xintUniformDeviate} (in its current implementation) improves this by +a factor \dtt{|2^{28}=|\number"10000000}: the non-uniformity is guaranteed to +be bounded by \dtt{$x/2^{56}$}.% +% +\expandafter\footnote\expandafter{\ifnum\value{footnote}=55 This «56» is proof + of existence of devil, no? \fi These estimates assume that the engine RNG underlying stream of + 28-bits integers can be considered uniform; it is known that the + parity bits of these 28-bits integers have a period of |55(2^{55}-1)| and + that after that many draws the count of 1s has only an excess of 55 compared + to the count of 0s, so the scale seems to be an intrinsic non-uniformity of + |2^{-55}| but it is not obvious if it applies to much shorter ranges. At any + rate we assumed that the non-uniformity for |x| a power of two less than + |2^{28}| is negligible in comparison to |2^{-28}|. Bigger powers of 2 + produce only even integers because the output is rescaled by + factor |x/2^{28}|!} +% +With such a small non-uniformity, modulo phenomena as mentioned earlier are +not observable in reasonable computing time.% +% +\footnote{The function \func{qraw} is used here not so much to speed up the + loop expansion, but in relation to \autoref{ssec:memory} to avoid too much + usage of |\csname...\endcsname| storage. Besides, if we had used |mod3| + function we would have needed |\xinttheiiexpr mod3(\pdfun...)\relax| + wrapping for each individual macro. So we decided rather to use a macro + |\ModThree|; of course we could have used |\numexpr|, with the technical + problem to expand only once |\pdfuniformdeviate|, which would have led to + some extra manoeuver, so ok for |\ModThree|.} +% +\begin{everbatim*} +%\xintdefiifunc mod3(x):= x 'mod' 3; +\xintNewIIExpr\ModThree[1]{#1 'mod' 3} + +\pdfsetrandomseed 87654321 +\xintdefiivar BadDigits:=qraw(% + \romannumeral\xintreplicate{503}{\ModThree{\pdfuniformdeviate "C000000},}% + \ModThree{\pdfuniformdeviate "C000000}% +);% 504=503+1 + +\pdfsetrandomseed 87654321 +\xintdefiivar GoodDigits:=qraw(% + \romannumeral\xintreplicate{503}{\ModThree{\xintUniformDeviate{"C000000}},}% + \ModThree{\xintUniformDeviate{"C000000}}% +);% 504=503+1 + +These 504 digits generated from \string\pdfuniformdeviate: +\xinttheiiexpr BadDigits\relax\hfill\break +contain these respective amounts of 0, 1, and 2: +% (this is definitely not the fastest way to count, but it is fun - and expandable) +\xinttheiiexpr iter(0,0,0;(i=0)?{[@][0]+1,[@][1],[@][2]} + {(i=1)?{[@][0],[@][1]+1,[@][2]} + {[@][0],[@][1],[@][2]+1}}, + i=BadDigits)\relax\par + +These 504 digits generated from \string\xintUniformDeviate: +\xinttheiiexpr GoodDigits\relax\hfill\break +contain these respective amounts of 0, 1, and 2: +\xinttheiiexpr iter(0,0,0;(i=0)?{[@][0]+1,[@][1],[@][2]} + {(i=1)?{[@][0],[@][1]+1,[@][2]} + {[@][0],[@][1],[@][2]+1}}, + i=GoodDigits)\relax\par +% % output to data file for double-check with python +% \newwrite\out +% \immediate\openout\out=\jobname.data +% \immediate\write\out{Lbad=[\xinttheiiexpr BadDigits\relax]} +% \immediate\write\out{Lgood=[\xinttheiiexpr GoodDigits\relax]} +% \immediate\closeout\out +\end{everbatim*} + +There is a second peculiarity of the engine RNG: two seeds sharing the same +low |k| bits generate sequences of 28-bits integers which are identical modulo +|2^k|! In particular after setting the seed, there are only 2 distinct +sequences of parity bits for the integers generated by |\pdfuniformdeviate (2 +to the power 28)|... + +In order to mitigate, \csa{xintUniformDeviate} currently only uses the +seven high bits from the underlying random stream, using multiple calls to +|\pdfuniformdeviate 128|. From the Birthday Effect, after about |2^{11}| seeds +one will likely pick a new one sharing its 22 low bits with an earlier one. + +\begin{enumerate} +\item but as the final random integer is obtained by additional operations + involving the range |x| (currently a modulo operation), for odd ranges it is + more difficult for bit correlations to be seen, +\item anyway as they are only +|2^{28}| seeds in total, after only |2^{14}| seeds it is likely to encounter +one already explored, and then random integers are identical, however +complicated the RNG's raw output is malaxed, and whatever the target range +|x|. And |2^{14}| is only eight times as large as |2^{11}|. +\end{enumerate} + +It would be nice if the engine provided some user interface for + letting its RNG execute a given number of iterations without the overhead + of replicated executions of |\pdfuniformdeviate|. This could help gain + entropy and would reduce correlations across series from distinct seeds. + +\smallskip +\emph{The description above summarizes parts of discussions held with Bruno Le + Floch in May 2018 on occasion of his LaTeX3 contributions related to this.} +\par +\smallskip + +\TeXnote +currently the implementation of \csbxint{UniformDeviate} consumes exactly 5 +calls to the engine primitive at each execution; the improved |x/2^{56}| +non-uniformity could be obtained with only 2 calls, but paranoïa about the +phenonemon of seeds with common bits has led me to accept the overhead of +using the 7 high bits of 4 random 28bits integers, rather than one single +28bits integer, or two, or three. + +Timings indicate that one \csbxint{UniformDeviate} has a time cost about 13 +times the one for one call to the engine primitive (and not only 5, as the +extra arithmetic expressions add overhead which is more costly than the +primitive itself). Except if the code using the pseudo-random number is very +short, this time penalty will prove in practice much less severe (and this is +one important reason why we opted for obtaining 28bits via the 7 high bits of +4 successive pseudo random numbers from the engine primitive). For example +let's raise 100 times a random integer to the tenth power: +% +\footnote{This is done on a |2.4GHz| processor. Hmm... or on a |2.8GHz| one, + I should add some automatic recognition to the build process...} +% +\begin{everbatim*} +\pdfsetrandomseed 12345678 +\pdfresettimer\romannumeral\xintreplicate + {100}{\fdef\foo{\xintiiPow{\xintUniformDeviate{100000000}}{10}}}% +\the\dimexpr\pdfelapsedtime sp\relax\space (with \string\xintUniformDeviate)\newline +(last result: \foo)\newline +\pdfsetrandomseed 12345678 +\pdfresettimer\romannumeral\xintreplicate + {100}{\fdef\foo{\xintiiPow{\pdfuniformdeviate 100000000}{10}}}% +\the\dimexpr\pdfelapsedtime sp\relax\space (with \string\pdfuniformdeviate)\newline +(last result: \foo)\par +\end{everbatim*} + +\TeXnote +the macros \csbxint{RandomDigits} or \csbxint{iiRandRange}, and their +variants, as well as the supporting macros for \func{random} generate random +decimal digits eight by eight as if using +\csa{xintUniformDeviate}|{100000000}|, but via a direct optimized call made +possibly by the range being a power of 10. + +\clearpage +\let\xintkernelnameUp\undefined +\csname xintcorenameUp\endcsname +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} +\section{Macros of the \xintcorename package} +\RaisedLabel{sec:core} + +\localtableofcontents + +Package \xintcorename is automatically loaded by \xintname. + +\xintcorename provides for big integers the four basic arithmetic operations +(addition, subtraction, multiplication, division), as well as powers and +factorials. + +In the descriptions of the macros \texttt{\n} and \texttt{\m} stand +for (big) integers or macros \hyperref[ssec:expansions]{\fexpan ding} to +such big integers in strict format as described in \autoref{ssec:inputs}. + +All macros require strict integer format on input and produce +strict integer format on output, except:\IMPORTANT +\begin{itemize}[nosep] +\item \csbxint{iNum} which converts to strict integer format an input in + \emph{extended} integer format, i.e. admitting multiple leading plus or + minus signs, then possibly leading zeroes, then digits, +\item and \csbxint{Num} which is an alias for the former, which gets redefined by + \xintfracname to accept more generally also decimal numbers or fractions as + input and which truncates them to integers. +\end{itemize} + +Most removed macros listed in \autoref{ssec:coredeprecated} were by design +applying \csbxint{Num} to their inputs. Typically these macros had a single +|i| in their names, for example \csa{xintiAdd} was such a companion to +\csa{xintiiAdd}. \xintfracname redefined \csbxint{Num} to be the macro +accepting general fractional input and truncating it to an integer. Hence a +macro such as \csa{xintiAdd} was compatible with the output format of +\xintfracname macros, contrarily to \csbxint{iiAdd} which handles only strict +integer format for its inputs. Of course, \xintfracname defined also its own +\csbxint{Add} which did the addition of its arguments without truncating them +to integers... but whose output format is the |A/B[N]| format explained in +\autoref{ssec:outputs}, hence even if representing a small integer it can not +be used directly in a \TeX\ context such as |\ifnum|, contrarily to +\csa{xintiAdd} or to \csbxint{iiAdd}. + +\begin{framed} + This situation was the result of some early-on design + decisions which now appear misguided and impede further development. Hence, + at |1.2o| it has been decided to deprecate \emph{all} such |i|-macros. And + they got removed from the package at |1.3|.\CHANGEDf{1.3} +\end{framed} +The |ii| in the names of the macros such as \csbxint{iiAdd} serves to stress +that they accept only strict integers as input (this is signaled by the margin +annotation \textcolor[named]{PineGreen}{\emph{f}}), or macros \fexpan ding to +such strict format (big) integers and that they produce strict integers as +output. + +Other macros, such as \csbxint{Double}, lack the |ii|, but this is only a +legacy of the history of the package and they have the same requirements for +input and format of output as the |ii|-macros.% +% +\footnote{Regarding \csbxint{FDg} and \csbxint{LDg}, this is a breaking change + because formerly they used \csbxint{Num}.} + +The letter \texttt{x} (with margin annotation +\smash{\textcolor[named]{PineGreen}{\numx}}) stands for an argument which will +be handled embedded in |\numexpr..\relax|. It will thus be completely expanded +and must give an integer obeying the \TeX{} bounds. See also +\autoref{sec:useofcount}. This is the case for the argument of \csbxint{iiFac} +or the exponent argument of \csbxint{iiPow}. + +The {\color[named]{PineGreen}$\star$}'s in the margin are there to remind of +the complete expandability, even \fexpan dability of the macros, as discussed +in \autoref{ssec:expansions}. + +\subsection{\csh{xintiNum}}\label{xintiNum} + +|\xintiNum|\n\etype{f} removes chains of plus or minus signs, followed by +zeroes. +\begin{everbatim*} +\xintiNum{+---++----+--000000000367941789479} +\end{everbatim*} + +\subsection{\csh{xintDouble}}\label{xintDouble} + +|\xintDouble|\n\etype{f} computes |2N|. + +\subsection{\csh{xintHalf}}\label{xintHalf} + +|\xintHalf|\n\etype{f} computes |N/2| +truncated towards zero. + +\subsection{\csh{xintInc}}\label{xintInc} + +|\xintInc|\n\etype{f} evaluates |N+1|. + +\subsection{\csh{xintDec}}\label{xintDec} + +|\xintDec|\n\etype{f} evaluates |N-1|. + +\subsection{\csh{xintDSL}}\label{xintDSL} + +|\xintDSL|\n\etype{f} is decimal shift left, \emph{i.e.} multiplication by +ten. + +\subsection{\csh{xintDSR}}\label{xintDSR} + +|\xintDSR|\n\etype{f} is truncated decimal shift right, \emph{i.e.} it is the +truncation of |N/10| towards zero. + +\subsection{\csh{xintDSRr}}\label{xintDSRr} + +|\xintDSRr|\n\etype{f} is rounded decimal shift right, \emph{i.e.} it is the +rounding of |N/10| away from zero. It is needed in \xintcorename for use by +\csbxint{iiDivRound}. + +\subsection{\csh{xintFDg}}\label{xintFDg} + +|\xintFDg|\n\etype{f} outputs the first digit (most significant) of the +number. + +\subsection{\csh{xintLDg}}\label{xintLDg} + +|\xintLDg|\n\etype{f} outputs the least significant digit. When the number +is positive, this is the same as the remainder in the Euclidean division by +ten. + +\subsection{\csh{xintiiSgn}}\label{xintiiSgn} + +|\xintiiSgn|\n\etype{f} returns 1 if the number is positive, 0 if it is zero +and -1 if it is negative. + +\subsection{\csh{xintiiOpp}}\label{xintiiOpp} + +|\xintiiOpp|\n\etype{f} outputs the opposite |-N| of the number |N|. + +Important note: an input such as |-\foo| is not legal, generally speaking, as +argument to the macros of the \xintname bundle (except, naturally in +\csbxint{expr}-essions). The reason is that the minus sign stops the \fexpan +sion done during parsing of the inputs. One must use the syntax +|\xintiiOpp{\foo}| if one wants to pass |-\foo| as +argument to other macros. + +\subsection{\csh{xintiiAbs}}\label{xintiiAbs} + +|\xintiiAbs|\n\etype{f} outputs the absolute value of the number. + +\subsection{\csh{xintiiAdd}}\label{xintiiAdd} + +|\xintiiAdd|\n\m\etype{ff} computes the sum of the two (big) integers. + +\subsection{\csh{xintiiCmp}}\label{xintiiCmp} + +|\xintiiCmp|\n\m\etype{ff} produces \dtt{1} if |N>M|, \dtt{0} if |N=M|, +and \dtt{-1} if |N<M|. + +At |1.2l| this macro was moved from package \xintname to \xintcorename. + +\subsection{\csh{xintiiSub}}\label{xintiiSub} + +|\xintiiSub|\n\m\etype{ff} computes the difference |N-M|. + +\subsection{\csh{xintiiMul}}\label{xintiiMul} + +|\xintiiMul|\n\m\etype{ff} computes the product of two (big) integers. + +\subsection{\csh{xintiiSqr}}\label{xintiiSqr} + +|\xintiiSqr|\n\etype{f} produces the square. + +\subsection{\csh{xintiiPow}}\label{xintiiPow} + +|\xintiiPow|\n\x\etype{f\numx} computes |N^x|. For |x=0|, this is 1. For |N=0| +and |x<0|, or if \verb+|N|>1+ and |x<0|, an error is raised. There will also +be an error if |x| exceeds the maximal \eTeX{} number \dtt{\number"7FFFFFFF}, +but the real limit for exponents comes from either the computation time or the +settings of some \TeX\ memory parameters. + +\begin{framed} + Indeed, the maximal power of $2$ which \xintname is able to compute + explicitely is |2^(2^17)=2^131072| which has \dtt{39457} digits. This + exceeds the maximal size on input for the \xintcorename multiplication, hence + any |2^N| with a higher |N| will fail. On the other hand |2^(2^16)| has + \dtt{19729} digits, thus it can be squared once to obtain |2^(2^17)| or + multiplied by anything smaller, thus all exponents up to and including |2^17| + are allowed (because the power operation works by squaring things and making + products). +\end{framed} + +% Side remark: after all it does pay to think! I almost melted my CPU trying by +% dichotomy to pin-point the exact maximal allowable |N| for |\xintiiPow 2{N}| +% before finally making the reasoning above. Indeed, each such computation with +% |N>130000| activates the fan of my laptop and results in so warm a keyboard +% that I can hardly go on working on it! And it takes about 12 minutes for each +% |\xintiiPow2{N}| with such |N|'s of the order of $130000$ (a.t.t.o.w.). + +\subsection{\csh{xintiiFac}}\label{xintiiFac} + +|\xintiiFac|\x\etype{\numx} computes the factorial. + +\begin{framed} + The (theoretically) allowable range is $0\leqslant x\leqslant10000$. + + However the maximal possible computation depends on the values of some memory + parameters of the |tex| executable: with the current default settings of + TeXLive 2015, the maximal computable factorial (a.t.t.o.w. 2015/10/06) turns + out to be $5971!$ which has $19956$ digits.%\footnotemark +\end{framed} + + + +The |factorial| function, or equivalently |!| as post-fix operator is +available in \csbxint{iiexpr}, \csbxint{expr}: +\begin{everbatim*} +\printnumber{\xinttheiiexpr 200!\relax}\par +\end{everbatim*} +See also \csbxint{FloatFac} from package \xintfracname for the float variant, +used in \csbxint{floatexpr}. + + + +\subsection{\csh{xintiiDivision}}\label{xintiiDivision} + + +|\xintiiDivision|\m\n\etype{ff} produces |{quotient}{remainder}|, in the sense +of (mathematical) Euclidean division: |M = QN + R|, +|0|${}\leq{}$\verb+R < |N|+. So the remainder is always non-negative and the +formula |M = QN + R| always holds independently of the signs of |N| or |M|. +Division by zero is an error (even if |M| vanishes) and returns |{0}{0}|. + +\subsection{\csh{xintiiQuo}}\label{xintiiQuo} + +|\xintiiQuo|\m\n\etype{ff} computes the quotient from the Euclidean division. + +\subsection{\csh{xintiiRem}}\label{xintiiRem} + +|\xintiiRem|\m\n\etype{ff} computes the remainder from the Euclidean +division. + +\subsection{\csh{xintiiDivRound}}\label{xintiiDivRound} + +|\xintiiDivRound|\m\n\etype{ff} returns the rounded value of the algebraic +quotient $M/N$ of two big integers. The rounding is ``away from zero.'' +\begin{everbatim*} +\xintiiDivRound {100}{3}, \xintiiDivRound {101}{3} +\end{everbatim*} + +\subsection{\csh{xintiiDivTrunc}}\label{xintiiDivTrunc} + +|\xintiiDivTrunc|\m\n\etype{ff} computes $trunc(M/N)$. For positive arguments +$M,N>0$ it is the same as the Euclidean quotient \csbxint{iiQuo}. +\begin{everbatim*} +\xintiiQuo{1000}{57} (Euclidean), \xintiiDivTrunc{1000}{57} (truncated), +\xintiiDivRound{1000}{57} (rounded)\newline +\xintiiQuo{-1000}{57}, \xintiiDivTrunc{-1000}{57} (t), \xintiiDivRound{-1000}{57} (r)\newline +\xintiiQuo{1000}{-57}, \xintiiDivTrunc{1000}{-57} (t), \xintiiDivRound{1000}{-57} (r)\newline +\xintiiQuo{-1000}{-57}, \xintiiDivTrunc{-1000}{-57} (t), \xintiiDivRound{-1000}{-57} (r)\par +\end{everbatim*} + +\subsection{\csh{xintiiDivFloor}}\label{xintiiDivFloor} + +|\xintiiDivFloor|\m\n\etype{ff} computes $floor(M/N)$. For positive divisor +$N>0$ and arbitrary dividend $M$ it is the same as the Euclidean quotient +\csbxint{iiQuo}. +\begin{everbatim*} +\xintiiQuo{1000}{57} (Euclidean), \xintiiDivFloor{1000}{57} (floored)\newline +\xintiiQuo{-1000}{57}, \xintiiDivFloor{-1000}{57}\newline +\xintiiQuo{1000}{-57}, \xintiiDivFloor{1000}{-57}\newline +\xintiiQuo{-1000}{-57}, \xintiiDivFloor{-1000}{-57}\par +\end{everbatim*} + +\subsection{\csh{xintiiMod}}\label{xintiiMod} + +|\xintiiMod|\m\n\etype{ff} computes $M - N*floor(M/N)$. For positive divisor +$N>0$ and arbitrary dividend $M$ it is the same as the Euclidean remainder +\csbxint{iiRem}. + +Formerly, this macro computed $M - N*trunc(M/N)$. The former meaning is +retained as \csa{xintiiModTrunc}. +\begin{everbatim*} +\xintiiRem {1000}{57} (Euclidean), \xintiiMod {1000}{57} (floored), +\xintiiModTrunc {1000}{57} (truncated)\newline +\xintiiRem {-1000}{57}, \xintiiMod {-1000}{57}, \xintiiModTrunc {-1000}{57}\newline +\xintiiRem {1000}{-57}, \xintiiMod {1000}{-57}, \xintiiModTrunc {1000}{-57}\newline +\xintiiRem {-1000}{-57}, \xintiiMod {-1000}{-57}, \xintiiModTrunc {-1000}{-57}\par +\end{everbatim*} + +\subsection{\csh{xintNum}}\label{xintNum} + +|\xintNum|\etype{f} is originally an alias for \csbxint{iNum}. But with +\xintfracname loaded its meaning is \hyperref[xintNumFrac]{modified} to accept +more general inputs. It then becomes an alias to \csbxint{TTrunc} which +truncates the general input to an integer in strict format. + +\subsection{Removed macros}\label{ssec:coredeprecated} + +These macros were deprecated at |1.2o| and removed at |1.3|.\CHANGED{1.3} +|\xintiiFDg| (renamed to \csbxint{FDg}), +|\xintiiLDg| (renamed to \csbxint{LDg}), +|\xintiOpp|, +|\xintiAbs|, +|\xintiAdd|, +|\xintCmp| (it gets defined by \xintfracname, so deprecation will usually not be +seen; the macro with this name from former \xintcorename should have been +called |\xintiCmp| actually), +|\xintSgn| (it also gets its proper definition from \xintfracname), +|\xintiSub|, +|\xintiMul|, +|\xintiDivision|, +|\xintiQuo|, +|\xintiRem|, +|\xintiDivRound|, +|\xintiDivTrunc|, +|\xintiMod|, +|\xintiSqr|, +|\xintiPow|, +|\xintiFac|. + + +\clearpage +\let\xintcorenameUp\undefined +\csname xintnameUp\endcsname +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} +\section{Macros of the \xintname package} +\RaisedLabel{sec:xint} + +This package loads automatically \xintcorename (and \xintkernelname) hence +all macros described in \autoref{sec:core} are still available. + +\etocsetnexttocdepth{subsubsection} +\localtableofcontents + +This is \texttt{\xintbndlversion} of +\texttt{\xintbndldate}. + +Version |1.0| was released |2013/03/28|. +Since |1.1 2014/10/28| the core arithmetic macros have been moved to a separate +package \xintcorename, which is automatically loaded by \xintname. +Only the \csbxint{iiSum}, \csbxint{iiPrd}, \csbxint{iiSquareRoot}, +\csbxint{iiPFactorial}, \csbxint{iiBinomial} genuinely add to the arithmetic +macros from \xintcorename. (\csbxint{iiFac} which computes factorials is +already in \xintcorename.) + +With the exception of \csbxint{Len}, of the «Boolean logic macros» (see +next paragraphs) all macros require inputs being integers in strict format, see \autoref{ssec:inputs}.% +% +\footnote{of +course for conditionals such as \csbxint{iiifCmp} this constraint applies only +to the first two arguments.} +% +The |ii| in the macro names is here as a reminder of that fact. The output is +an integer in strict format, or a pair of two braced such integers for +\csbxint{iiSquareRoot}, with the exception of \csbxint{iiE} which may produce +strings of zero's if its first argument is zero. + +Macros \csbxint{DecSplit} and \csbxint{ReverseDigits} are non-arithmetic and +have their own specific rules. + +For all macros described here for which it makes sense, package \xintfracname +defines a similar one without |ii| in its name. This will handle more general +inputs: decimal, scientific numbers, fractions. The |ii| macros provided here +by \xintname can be nested inside macros of \xintfracname but the opposite +does not apply, because the output format of the \xintfracname macros, even +for representing integers, is not understood by the |ii| macros. The «Boolean +macros» \csbxint{AND} etc... are exceptions though, they work fine if served +as inputs some \xintfracname output, despite doing only \fexpan +sion. Prior to |1.2o|, these macros did apply the \csbxint{Num} +or the more general \xintfracname general parsing, but this overhead was +deemed superfluous as it serves only to handle hand-written input and is not +needed if the input is obtained as a nested chain of \xintfracname macros for +example. + +Prior to release |1.2o|, \xintname defined additional macros which applied +\csbxint{Num} to their input arguments. All these macros were deprecated at +|1.2o| and have been removed at |1.3|.\CHANGED{1.3} + +At |1.3d| macros \csbxint{iiGCD} and \csbxint{iiLCM} from package \xintgcdname +are also available from loading \xintname only. They are support macros for +the (multi-arguments) functions \func{gcd} and \func{lcm} in \csbxint{iiexpr}. + +See \autoref{ssec:expansions} for the significance of the +\textcolor[named]{PineGreen}{\Numf}, \textcolor[named]{PineGreen}{\emph{f}}, +\textcolor[named]{PineGreen}{\numx} and \textcolor[named]{PineGreen}{$\star$} +margin annotations. + + + + + +\subsection{\csh{xintiLen}}\label{xintiLen} + +|\xintiLen|\n\etype{\Numf} returns the length of the number, after its parsing +via \csbxint{iNum}. The count does not include the sign. +\begin{everbatim*} +\xintiLen{-12345678901234567890123456789} +\end{everbatim*} + +Prior to |1.2o|, the package defined only \csbxint{Len}, which is extended by +\xintfracname to fractions or decimal numbers, hence acquires a bit more +overhead then. + +\subsection{\csh{xintReverseDigits}} \label{xintReverseDigits} + +\the\dp\strutbox, \the\ht\strutbox, \the\baselineskip + +|\xintReverseDigits|\n\etype{f} will reverse the order of the digits of the +number. \csa{xintRev} is the former denomination and is kept as an alias. +Leading zeroes resulting from the operation are not removed. Contrarily to +\csbxint{ReverseOrder} this macro \fexpan ds its argument; it is only usable +with digit tokens. It does \emph{not} apply \csbxint{Num} to its argument (so +this must be done explicitely if the argument is an integer produced from some +\xintfracname macros). It does accept a leading minus sign which will be left +upfront in the output. + +\begingroup +\begin{everbatim*} +\oodef\x{\xintReverseDigits + {98765432109876543210987654321098765432109876543210}}\meaning\x\par +\noindent\oodef\x{\xintReverseDigits {\xintReverseDigits + {98765432109876543210987654321098765432109876543210}}}\meaning\x\par +\end{everbatim*} +\endgroup + +\subsection{\csh{xintiiGCD}} + +This is the same as the \csbxint{iiGCD} from package \xintgcdname. + +\subsection{\csh{xintiiLCM}} + +This is the same as the \csbxint{iiLCM} from package \xintgcdname. + +\subsection{\csh{xintDecSplit}} +\label{xintDecSplit} + +|\xintDecSplit|\x\n\etype{\numx f} cuts the |N| (a list of digits) into two +pieces |L| and |R|: it outputs |{L}{R}| where the original |N| +is the concatenation |LR|. These two pieces are decided according to |x|: +\begin{itemize}[nosep] +\item for |x>0|, |R| coincides with the |x| least significant digits. If |x| + equals or exceeds the length of |N| the first piece |L| will thus be + \emph{empty}, +\item for |x=0|, |R| is empty, and |L| is all of |N|, +\item for |x<0|, the first piece |L| consists of the \verb+|x|+ most + significant digits and the second piece |R| gets the remaining ones. If |x| + equals or exceeds the length of |N| the second piece |R| will thus be + \emph{empty}. +\end{itemize} + +This macro provides public interface to some functionality which is primarily +of internal interest. It operates only (after \fexpan sion) on ``strings'' of +digits tokens: leading zeroes are allowed but a leading sign (even a minus +sign) will provoke an error. + +Breaking change with |1.2i|: formerly |N<0| was replaced by its + absolute value. Now, a sign (positive or negative) will create an error. + + +\subsection{\csh{xintDecSplitL}, \csh{xintDecSplitR}} +\label{xintDecSplitL} +\label{xintDecSplitR} + +|\xintDecSplitL|\x\n\etype{\numx f} returns the first piece (unbraced) from +the \csa{xintDecSplit} output. + +\noindent|\xintDecSplitR|\x\n\etype{\numx f} returns the second piece +(unbraced) from the \csa{xintDecSplit} output. + +\subsection{\csh{xintiiE}}\label{xintiiE} + +|\xintiiE|\n\x\etype{f\numx } serves to extend |N| with |x| zeroes. The +parameter |x| must be non-negative. The same output would be obtained via +\csbxint{DSH}|{-x}{N}|, except for |N=0|, as |\xintDSH{-x}{N}| multiplies |N| +by |10^x| hence produces |0| if |N=0| whereas +|\xintiiE{0}{x}| produces |x+1| zeros. +\begin{everbatim*} +\xintiiE {0}{91}\par +\end{everbatim*} + +\subsection{\csh{xintDSH}}\label{xintDSH} + +|\xintDSH|\x\n\etype{\numx f} is parametrized decimal shift. When |x| is +negative, it is like iterating \csbxint{DSL} \verb+|x|+ times (\emph{i.e.} +multiplication by $10^{-x}$). When |x| positive, it is like iterating +\csbxint{DSR} |x| times (and is more efficient), and for a non-negative |N| +this is thus the same as the quotient from the Euclidean division by |10^x|. + +\subsection{\csh{xintDSHr}, \csh{xintDSx}}\label{xintDSHr}\label{xintDSx} + +|\xintDSHr|\x\n\etype{\numx f} expects |x| to be zero or positive and it +returns then a value |R| which is correlated to the value |Q| returned by +\csbxint{DSH}\x\n{} in the following manner: +\begin{itemize} +\item if |N| is + positive or zero, |Q| and |R| are the quotient and remainder in + the Euclidean division by |10^x| (obtained in a more efficient + manner than using \csa{xintiiDivision}), +\item if |N| is negative let + |Q1| and |R1| be the quotient and remainder in the Euclidean + division by |10^x| of the absolute value of |N|. If |Q1| + does not vanish, then |Q=-Q1| and |R=R1|. If |Q1| vanishes, then + |Q=0| and |R=-R1|. +\item for |x=0|, |Q=N| and |R=0|. +\end{itemize} +So one has |N = 10^x Q + R| if |Q| turns out to be zero or +positive, and |N = 10^x Q - R| if |Q| turns out to be negative, +which is exactly the case when |N| is at most |-10^x|. + +|\xintDSx|\x\n\etype{\numx f} for |x| negative is exactly as +|\xintDSH|\x\n, \emph{i.e.} multiplication by $10^{-|x|}$. For |x| zero or +positive it returns the two numbers |{Q}{R}| described above, each one within +braces. So |Q| is |\xintDSH|\x\n, and |R| is |\xintDSHr|\x\n, but computed +simultaneously. + +\subsection{\csh{xintiiEq}}\label{xintiiEq} + +|\xintiiEq|\n\m\etype{ff} returns 1 if |N=M|, 0 otherwise. + +\subsection{\csh{xintiiNotEq}}\label{xintiiNotEq} + +|\xintiiNotEq|\n\m\etype{ff} returns 0 if |N=M|, 1 otherwise. + + +\subsection{\csh{xintiiGeq}}\label{xintiiGeq} + +|\xintiiGeq|\n\m\etype{ff} returns 1 if the \emph{absolute value} +of the first number is at least equal to the absolute value of the second +number. If \verb+|N|<|M|+ it returns 0. + +Important: the macro compares \emph{absolute values}. + +\subsection{\csh{xintiiGt}}\label{xintiiGt} + +|\xintiiGt|\n\m\etype{ff} returns 1 if |N|$>$|M|, 0 otherwise. + +\subsection{\csh{xintiiLt}}\label{xintiiLt} + +|\xintiiLt|\n\m\etype{ff} returns 1 if |N|$<$|M|, 0 otherwise. + +\subsection{\csh{xintiiGtorEq}}\label{xintiiGxstorEq} + +|\xintiiGtorEq|\n\m\etype{ff} returns 1 if |N|$\geqslant$|M|, 0 otherwise. +Extended by \xintfracname to fractions. + +\subsection{\csh{xintiiLtorEq}}\label{xintiiLtorEq} + +|\xintiiLtorEq|\n\m\etype{ff} returns 1 if |N|$\leqslant$|M|, 0 otherwise. + +\subsection{\csh{xintiiIsZero}}\label{xintiiIsZero} + +|\xintiiIsZero|\n\etype{f} returns 1 if |N=0|, 0 otherwise. + +\subsection{\csh{xintiiIsNotZero}}\label{xintiiIsNotZero} + +|\xintiiIsNotZero|\n\etype{f} returns 1 if |N!=0|, 0 otherwise. + +\subsection{\csh{xintiiIsOne}}\label{xintiiIsOne} + +|\xintiiIsOne|\n\etype{f} returns 1 if |N=1|, 0 otherwise. + +\subsection{\csh{xintiiOdd}}\label{xintiiOdd} + +|\xintiiOdd|\n\etype{f} is 1 if the number is odd and 0 otherwise. + +\subsection{\csh{xintiiEven}}\label{xintiiEven} + +|\xintiiEven|\n\etype{f} is 1 if the number is even and 0 otherwise. + +\subsection{\csh{xintiiMON}}\label{xintiiMON} + +|\xintiiMON|\n\etype{f} computes |(-1)^N|. +\begin{everbatim*} +\xintiiMON {-280914019374101929} +\end{everbatim*} + +\subsection{\csh{xintiiMMON}}\label{xintiiMMON} + +|\xintiiMMON|\n\etype{f} computes |(-1)^{N-1}|. +\begin{everbatim*} +\xintiiMMON {280914019374101929} +\end{everbatim*} + +\subsection{\csh{xintiiifSgn}}\label{xintiiifSgn} + +\csh{xintiiifSgn}\marg{N}\marg{A}\marg{B}\marg{C}\etype{fnnn} executes either +the \meta{A}, \meta{B} or \meta{C} code, depending on its first argument being +respectively negative, zero, or positive. + +\subsection{\csh{xintiiifZero}}\label{xintiiifZero} + +\csa{xintiiifZero}\marg{N}\marg{IsZero}\marg{IsNotZero}\etype{fnn} expandably +checks if the first mandatory argument |N| (a number, possibly a fraction if +\xintfracname is loaded, or a macro expanding to one such) is zero or not. It +then either executes the first or the second branch. + +Beware that both branches must be present. + +\subsection{\csh{xintiiifNotZero}}\label{xintiiifNotZero} + +\csa{xintiiifNotZero}\marg{N}\marg{IsNotZero}\marg{IsZero}\etype{fnn} +expandably checks if the first mandatory argument |N| is not +zero or is zero. It then either executes the first or the second branch. + +Beware that both branches must be present. + +\subsection{\csh{xintiiifOne}}\label{xintiiifOne} + +\csa{xintiiifOne}\marg{N}\marg{IsOne}\marg{IsNotOne}\etype{fnn} expandably +checks if the first mandatory argument |N| is one or not one. It +then either executes the first or the second branch. Beware that both branches +must be present. + +\subsection{\csh{xintiiifCmp}}\label{xintiiifCmp} + +\csa{xintiiifCmp}\marg{A}\marg{B}\marg{A<B}\marg{A=B}\marg{A>B}\etype{ffnnn} +compares its first two arguments and chooses accordingly the correct branch. + +\subsection{\csh{xintiiifEq}}\label{xintiiifEq} + +\csa{xintiiifEq}\marg{A}\marg{B}\marg{A=B}\marg{not(A=B)}\etype{ffnn} checks +equality of its two first arguments and executes the corresponding branch. + +\subsection{\csh{xintiiifGt}}\label{xintiiifGt} + +\csa{xintiiifGt}\marg{A}\marg{B}\marg{A>B}\marg{not(A>B)}\etype{ffnn} +checks if $A>B$ and executes the corresponding branch. + +\subsection{\csh{xintiiifLt}}\label{xintiiifLt} + +\csa{xintiiifLt}\marg{A}\marg{B}\marg{A<B}\marg{not(A<B)}\etype{ffnn} +checks if $A<B$ and executes the corresponding branch. + +\subsection{\csh{xintiiifOdd}}\label{xintiiifOdd} + +\csa{xintiiifOdd}\marg{A}\marg{A odd}\marg{A even}\etype{fnn} checks if $A$ is +and odd integer and executes the corresponding branch. + +\subsection{\csh{xintiiSum}}\label{xintiiSum} + +\csa{xintiiSum}\marg{braced things}\etype{{\lowast f}} after expanding its +argument expects to find a sequence of tokens (or braced material). Each is +\fexpan ded, and the sum of all these numbers is returned. +\begin{everbatim*} +\xintiiSum{{123}{-98763450}{\xintiiFac{7}}{\xintiiMul{3347}{591}}}\newline +\xintiiSum{1234567890}\newline +\xintiiSum{1234}\newline +\xintiiSum{} +\end{everbatim*} + +A sum with only one term returns that +number: |\xintiiSum {{-1234}}|\dtt{=\xintiiSum {{-1234}}}. +Attention that |\xintiiSum {-1234}| is not legal input and would make the +\TeX{} run fail. + +\subsection{\csh{xintiiPrd}}\label{xintiiPrd} + +\csa{xintiiPrd}\marg{braced things}\etype{{\lowast f}} after expanding its +argument expects to find a sequence of (of braced items or unbraced +single tokens). Each is +expanded (with the usual meaning), and the product of all these numbers is +returned. +\begin{everbatim*} +\xintiiPrd{{-9876}{\xintiiFac{7}}{\xintiiMul{3347}{591}}}\newline +\xintiiPrd{123456789123456789}\newline +\xintiiPrd {1234}\newline +\xintiiPrd{} +\end{everbatim*} + +Attention that |\xintiiPrd {-1234}| is not legal input and would make the \TeX{} +compilation fail. +\begin{everbatim*} +$2^{200}3^{100}7^{100}=\printnumber + {\xintiiPrd {{\xintiiPow {2}{200}}{\xintiiPow {3}{100}}{\xintiiPow {7}{100}}}}$ +\end{everbatim*} + +With \xintexprname, the syntax is the natural one: +\begin{everbatim*} +$2^{200}3^{100}7^{100}=\printnumber{\xinttheiiexpr 2^200 * 3^100 * 7^100\relax}$ +\end{everbatim*} + +\subsection{\csh{xintiiSquareRoot}} +\label{xintiiSquareRoot} + +|\xintiiSquareRoot|\n\etype{f} returns two braced integers |{M}{d}| which +satisfy |d>0| and |M^2-d=N| with +|M| the smallest (hence if |N=k^2| is a perfect square then |M=k+1|, |d=2k+1|). + +\begin{everbatim*} +\xintAssign\xintiiSquareRoot {17000000000000000000000000}\to\A\B +\xintiiSub{\xintiiSqr\A}\B=\A\string^2-\B +\end{everbatim*} + +A rational approximation to $\sqrt{|N|}$ is $|M|-\frac{|d|}{|2M|}$ which is a +majorant and the error is at most |1/2M| (if |N| is a perfect square |k^2| +this gives |k+1/(2k+2)|, not |k|.) + +Package \xintfracname has \csbxint{FloatSqrt} for square roots of floating +point numbers. + +\subsection{\csh{xintiiSqrt}, \csh{xintiiSqrtR}} +\label{xintiiSqrt}\label{xintiiSqrtR} + +\noindent|\xintiiSqrt|\n\ computes the largest integer whose square +is at most equal to |N|.\etype{f} |\xintiiSqrtR| +produces the rounded, not truncated, square root.\etype{f} +\begin{everbatim*} +\begin{itemize}[nosep] +\item \xintiiSqrt {3000000000000000000000000000000000000} +\item \xintiiSqrtR {3000000000000000000000000000000000000} +\item \xintiiSqrt {\xintiiE {3}{100}} +\end{itemize} +\end{everbatim*} + +\subsection{\csh{xintiiBinomial}}\label{xintiiBinomial} + +|\xintiiBinomial{x}{y}|\etype{\numx\numx} computes binomial coefficients. + +If |x<0| an out-of-range error is raised. Else, if |y<0| or if |x<y| the macro +evaluates to \dtt{\xintiiBinomial{1}{-1}}. + + +%\begin{framed} + The allowable range is $0\leqslant x\leqslant99999999$. +%\end{framed} + % Thus the maximal computable value is ${9999 \choose 5000}$ which turns out + % to have \dtt{3008} digits. + But this theoretical range includes binomial coefficients with more than the + roughly 19950 digits that the arithmetics of \xintname can handle. In such + cases, the computation will end up in a low-level \TeX{} error after a + long time. + +% +It turns out that ${65000 \choose 32500}$ has \dtt{19565} digits and +${64000 \choose 32000}$ has \dtt{19264} digits. The latter can be evaluated +(this takes a long long time) but presumably not the former (I didn't try). +Reasonable feasible evaluations are with binomial coefficients not exceeding +about one thousand digits. + + +% +The |binomial| function is available in the \xintexprname parsers. +\begin{everbatim*} +\xinttheiiexpr seq(binomial(100,i), i=47..53)\relax +\end{everbatim*} + +See \csbxint{FloatBinomial} from package \xintfracname for the float variant, +used in \csbxint{floatexpr}. + + +In order to +evaluate binomial coefficients ${x \choose y}$ with $x>99999999$, or even +$x\geqslant 2^{31}$, but $y$ is not too large, one may use an ad hoc function +definition such as: +\begin{everbatim*} +\xintdeffunc mybigbinomial(x,y):=`*`(x-y+1..[1]..x)//y!;% +% without [1], x would have been limited to < 2^31 +\printnumber{\xinttheexpr mybigbinomial(98765432109876543210,10)\relax} +\end{everbatim*} + + +To get this functionality in macro form, one can do: +\begin{everbatim*} +\xintNewIIExpr\MyBigBinomial [2]{`*`(#1-#2+1..[1]..#1)//#2!} +\printnumber{\MyBigBinomial {98765432109876543210}{10}} +\end{everbatim*} + +As we used \csa{xintNewIIExpr}, this macro will only accept strict integers. +Had we used \csa{xintNewExpr} the |\MyBigBinomial| would have accepted general +fractions or decimal numbers, and computed the product at the numerator +without truncating them to integers; but the factorial at the denominator +would truncate its argument. + +\subsection{\csh{xintiiPFactorial}}\label{xintiiPFactorial} + +|\xintiiPFactorial{a}{b}|\etype{\numx\numx} computes the partial factorial +|(a+1)(a+2)...b|. For |a=b| the product is considered empty hence returns |1|. + +%\begin{framed} + The allowed range +% +% +% + is $-100000000\leqslant a, b\leqslant99999999$. + The + rule is to interpret the formula as the product of the + $j$'s such that $a<j\leqslant b$, hence in particular if $a\geqslant b$ the + product is empty and the macro evaluates to |1|. + + Only for $0\leqslant a\leqslant b$ is the behaviour to be considered + stable. For $a>b$ or negative arguments, the definitive rules have not yet + been fixed. + +\begin{everbatim*} +\xintiiPFactorial {100}{130} +\end{everbatim*} +%\end{framed} + +This theoretical range allows computations whose result values would have more +than the roughly 19950 digits that the arithmetics of \xintname can handle. In +such cases, the computation will end up in a low-level \TeX{} error after a +long time. + +The |pfactorial| function is available in the \xintexprname parsers. +\begin{everbatim*} +\xinttheiiexpr pfactorial(100,130)\relax +\end{everbatim*} + +See \csbxint{FloatPFactorial} from package \xintfracname for the float +variant, used in \csbxint{floatexpr}. + + +In case values are needed with $b>99999999$, or even $b\geqslant 2^{31}$, but +$b-a$ is not too large, one may use an ad hoc function definition such as: +\begin{everbatim*} +\xintdeffunc mybigpfac(a,b):=`*`(a+1..[1]..b);% +% without [1], b would have been limited to < 2^31 +\printnumber{\xinttheexpr mybigpfac(98765432100,98765432120)\relax} +\end{everbatim*} + +\subsection{\csh{xintiiMax}}\label{xintiiMax} + +|\xintiiMax|\n\m\etype{ff} returns the largest of the two in the sense +of the order structure on the relative integers (\emph{i.e.} the right-most +number if they are put on a line with positive numbers on the right): +|\xintiiMax {-5}{-6}|\dtt{=\xintiiMax{-5}{-6}}. + +\subsection{\csh{xintiiMin}}\label{xintiiMin} + +|\xintiiMin|\n\m\etype{ff} returns the smallest of the two in the sense of the +order structure on the relative integers (\emph{i.e.} the left-most number if +they are put on a line with positive numbers on the right): |\xintiiMin +{-5}{-6}|\dtt{=\xintiiMin{-5}{-6}}. + +\subsection{\csh{xintiiMaxof}}\label{xintiiMaxof} + +\csa{xintiiMaxof}|{{a}{b}{c}...}|\etype{f{$\to$}\lowast f} returns the +maximum. The list argument may be a macro, it is \fexpan ded first. + +\subsection{\csh{xintiiMinof}}\label{xintiiMinof} + +\csa{xintiiMinof}|{{a}{b}{c}...}|\etype{f{$\to$}\lowast f} returns the +minimum. The list argument may be a macro, it is \fexpan ded first. + +\subsection{\csh{xintifTrueAelseB}} +\label{xintifTrueAelseB} + +\csa{xintifTrueAelseB}\marg{f}\marg{true branch}\marg{false branch}\etype{fnn} +is a synonym for \csbxint{iiifNotZero}. + +{\small + \noindent |\xintiiifnotzero| is lowercase companion macro.\par } + +Note 1: as it does only \fexpan sion on its argument it fails with inputs such +as |--0|. But with \xintfracname loaded, it does work fine if nested with +other \xintfracname macros, because the output format of such macros is fine +as input to \csbxint{iiifNotZero}. This remark applies to all other «Boolean +logic» macros next. + +Note 2: prior to |1.2o| this macro was using \csbxint{ifNotZero} which applies +\csbxint{Num} to its argument (or gets redefined by \xintfracname to handle +general decimal numbers or fractions). Hence it would have +worked with input such as |--0|. But it was decided at |1.2o| that the +overhead was not worth it. The same remark applies to the other «Boolean +logic» type macros next. + +\subsection{\csh{xintifFalseAelseB}} +\label{xintifFalseAelseB} + +\csa{xintifFalseAelseB}\marg{f}\marg{false branch}\marg{true + branch}\etype{fnn} is a synonym for \csbxint{iiifZero}. + +{\small + \noindent |\xintiiifzero| is lowercase companion macro.\par } + +\subsection{\csh{xintNOT}}\label{xintNOT} + +\csa{xintNOT}\etype{f} is a synonym for \csa{xintiiIsZero}. + +{\small |\xintiiiszero| serves as lowercase companion macro.\par} + + +\subsection{\csh{xintAND}}\label{xintAND} + +|\xintAND{f}{g}|\etype{ff} returns \dtt{1} if |f!=0| and |g!=0| and \dtt{0} +otherwise. + +\subsection{\csh{xintOR}}\label{xintOR} + +|\xintOR{f}{g}|\etype{ff} returns \dtt{1} if |f!=0| or |g!=0| and \dtt{0} +otherwise. + +\subsection{\csh{xintXOR}}\label{xintXOR} + +|\xintXOR{f}{g}|\etype{ff} returns \dtt{1} if exactly one of |f| or |g| +is true (i.e. non-zero), else \dtt{0}. + +\subsection{\csh{xintANDof}}\label{xintANDof} + +\csa{xintANDof}|{{a}{b}{c}...}|\etype{f{$\to$}\lowast f} returns \dtt{1} if +all are true (i.e. non zero) and \dtt{0} otherwise. The list argument may be a +macro, it (or rather its first token) is \fexpan ded first to deliver its +items. + +\subsection{\csh{xintORof}}\label{xintORof} + +\csa{xintORof}|{{a}{b}{c}...}|\etype{f{$\to$}\lowast f} returns \dtt{1} if at +least one is true (i.e. does not vanish), else it produces \dtt{0}. The list +argument may be a macro, it is \fexpan ded first. + +\subsection{\csh{xintXORof}}\label{xintXORof} + +\csa{xintXORof}|{{a}{b}{c}...}|\etype{f{$\to$}\lowast f} returns \dtt{1} if an +odd number of them are true (i.e. do not vanish), else it produces \dtt{0}. +The list argument may be a macro, it is \fexpan ded first. + +\subsection{\csh{xintLen}}\label{xintLen} + +|\xintLen|\etype{\Numf} is originally an alias for \csbxint{iLen}. But with +\xintfracname loaded its meaning is \hyperref[xintLenFrac]{modified} to accept +more general inputs. + +\subsection{Removed macros (they require \xintfracname)}\label{ssec:xintdeprecated} + +These macros now require \xintfracname. They have been removed from \xintname +at |1.3|.\CHANGED{1.3} +|\xintEq|, +|\xintNeq|, +|\xintGeq|, +|\xintGt|, +|\xintLt|, +|\xintGtorEq|, +|\xintLtorEq|, +|\xintIsZero|, +|\xintIsNotZero|, +|\xintIsOne|, +|\xintOdd|, +|\xintEven|, +|\xintifSgn|, +|\xintifCmp|, +|\xintifEq|, +|\xintifGt|, +|\xintifLt|, +|\xintifZero|, +|\xintifNotZero|, +|\xintifOne|, +|\xintifOdd|. + +With the exception of |\xintNeq| which was renamed to |\xintNotEq|, the above +listed macros all belong to \xintfracname. + +\subsection{Removed macros (they used \csh{xintNum})}\label{ssec:xintdeprecatedNum} + +These macros filtered their arguments via \csbxint{Num}. They got deprecated +at |1.2o| and removed at |1.3|:\CHANGED{1.3} +|\xintMON|, +|\xintMMON|, +|\xintiMax|, +|\xintiMin|, +|\xintiMaxof|, +|\xintiMinof|, +|\xintiSquareRoot|, +|\xintiSqrt|, +|\xintiSqrtR|, +|\xintiBinomial|, +|\xintiPFactorial|. + +\begin{framed} + All randomness related macros are Work-In-Progress: implementation and user + interface may change. They work only if the \TeX\ engine provides the + \csa{uniformdeviate} or \csa{pdfuniformdeviate} primitive. See + \csbxint{UniformDeviate} for additional information. +\end{framed} + +\subsection{(WIP) \csh{xintRandomDigits}}\label{xintRandomDigits} + +|\xintRandomDigits{N}|\etype{\numx} expands in two steps to |N| random decimal +digits. The argument must be non-negative and is limited by \TeX\ memory +parameters.\NewWith{1.3b} +On \TeX Live 2018 with input save stack size at \dtt{5000} the +maximal allowed |N| is at most \dtt{19984} (tested within a |\write| to an +auxiliary file, the macro context may cause a reduced maximum). +\begin{everbatim*} +\pdfsetrandomseed 271828182 +\xintRandomDigits{92} +\end{everbatim*} + +\TeXnote the digits are produced eight by eight by the same method which would +result from \csbxint{UniformDeviate}|{100000000}| but with less overhead. + +% \subsection{\csh{\xintOneRandomDigit}}\label{xintOneRandomDigit} + +\subsection{(WIP) \csh{xintXRandomDigits}}\label{xintXRandomDigits} + +|\xintXRandomDigits{N}|\retype{\numx} expands under exhaustive expansion +(|\edef|, |\write|, |\csname| ...) to |N| random decimal +digits. The argument must be non-negative.\NewWith{1.3b} +For example: +\begin{everbatim} +\newwrite\out +\immediate\openout\out=\jobname-out.txt +\immediate\write\out{\xintXRandomDigits{4500000}} +\immediate\closeout\out +\end{everbatim} +creates a \dtt{4500001} bytes file (it ends with a line feed character). +Trying with \dtt{5000000} raises this error: +\begin{everbatim} +Runaway text? +588875947168511582764514135070217555354479805240439407753451354223283\ETC. +! TeX capacity exceeded, sorry [main memory size=5000000]. +<inserted text> 666515098 + +l.15 ...ate\write\out{\xintXRandomDigits{5000000}} + +No pages of output. +Transcript written on temp.log. +\end{everbatim} +This can be lifted by increasing the \TeX\ memory settings (installation +dependent). + +\TeXnote the digits are produced eight by eight by the same method which would +result from \csbxint{UniformDeviate}|{100000000}| but with less overhead. + +\subsection{(WIP) \csh{xintiiRandRange}}\label{xintiiRandRange} + +|\xintiiRandRange{A}|\etype{f} expands to a random (big) integer |N| +such that |0<=N<A|. It is a supporting macro for \func{randrange}. As with +Python's function of the same name, it is an error if |A<=0|.\NewWith{1.3b} +\begin{everbatim*} +\pdfsetrandomseed 271828314 +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\newline +\xintiiRandRange{\xintNum{1e40}}\newline +\pdfsetrandomseed 271828314 +\xinttheiiexpr randrange(num(1e40))\relax\newline % bare 1e40 not understood by \xintiiexpr +\pdfsetrandomseed 271828314 +\xinttheexpr randrange(1e40)\relax +\end{everbatim*} + +Of course, keeping in mind that the set of seeds is of cardinality |2^{28}|, +randomness is a bit illusory here say with |A=10^N|, |N>8|, if we proceed +immediately after having set the seed. If we add some entropy in any way, then +it is slightly more credible; but I think that for each seed the period is +something like |2^{27}(2^{55}-1)55|,% +% +\footnote{Compare the result of exercise 3.2.2-30 in TAOCP, vol II.} +% +so we expect at most about |2^{110}55| +``points in time'', and this is already small compared to the |10^40| +from example above. Thus already we are very far from being intrinsically +able to generate all numbers with fourty digits as random numbers, and this +makes the previous section about usage of \csbxint{XRandomDigits} to generate +millions of digits a bit comical... + +\TeXnote the digits are produced eight by eight by the same method which would +result from \csbxint{UniformDeviate}|{100000000}| but with less overhead. + +\subsection{(WIP) \csh{xintiiRandRangeAtoB}}\label{xintiiRandRangeAtoB} + +|\xintiiRandRangeAtoB{A}{B}|\etype{ff} expands to a random (big) integer |N| +such that |A<=N<B|. It is a supporting macro for \func{randrange}. As with +Python's function of the same name, it is an error if |B<=A|.\NewWith{1.3b} +\begin{everbatim*} +\pdfsetrandomseed 271828314 +12345678911111111111111111111\newline +\xintiiRandRangeAtoB{12345678911111111111111111111}{12345678922222222222222222222}\newline +\pdfsetrandomseed 271828314 +\def\test{% +\xinttheiiexpr randrange(12345678911111111111111111111,12345678922222222222222222222)\relax}% +\romannumeral\xintreplicate{10}{\test\newline}% +12345678922222222222222222222 +\end{everbatim*} + +\TeXnote the digits are produced eight by eight by the same method which would +result from \csbxint{UniformDeviate}|{100000000}| but with less overhead. + +\clearpage +\let\xintnameUp\undefined +\csname xintfracnameUp\endcsname +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} +\section{Macros of the \xintfracname package} +\RaisedLabel{sec:frac} + +First version of this package was in release |1.03| (|2013/04/14|) of the +\xintname bundle. + +At release |1.3| (|2018/02/28|) the behaviour of \csbxint{Add} (and of +\csbxint{Sub}) was modified:\CHANGED{1.3} when adding |a/b| and |c/d| they +will use always the least common multiple of the denominators. This helps +limit the build-up of denominators, but the author still hesitates if the +fraction should be reduced to smallest terms. The current method allows (for +example when multiplying two polynomials) to keep a well-predictable +denominator among various terms, even though some may be reducible. + +\localtableofcontents + +\xintfracname loads automatically \xintcorename and \xintname and inherits +their macro definitions. Only these two are redefined: +\hyperref[xintNumFrac]{\string\xintNum} and +\hyperref[xintLenFrac]{\string\xintLen}. As explained in \autoref{ssec:inputs} +and \autoref{ssec:outputs} the interchange format for the \xintfracname +macros, i.e. |A/B[N]|, is not understood by the |ii|-named macros of +\xintcorename/\xintname which expect the so-called strict integer format. +Hence, to use such an |ii|-macro with an output from an \xintfracname macro, +an extra \csbxint{Num} wrapper is required. But macros already defined by +\xintfracname cover most use cases hence this should be a rarely needed. + +In the macro descriptions, the variable |f|\ntype{\Ff} and the margin +indicator stand for the \xintfracname input format for integers, scientific +numbers, and fractions as described in \autoref{ssec:inputs}. + +As in the \hyperref[sec:xint]{xint.sty} documentation, |x|\ntype{\numx} stands +for something which internally will be handled in a \csa{numexpr}. It may thus +be an expression as understood by \csa{numexpr} but its evaluation and +intermediate steps must obey the \TeX\ bound. + +The output format for most macros is the |A/B[N]| format but naturally the +float macros use the scientific notation on output. And some macros are +special, for example \csbxint{Trunc} produces decimal numbers, \csbxint{Irr} +produces an |A/B| with no |[N]|, \csbxint{iTrunc} and \csbxint{iRound} produce +integers without trailing |[N]| either, etc\dots + +|1.3a| belatedly adds documentation for some macros such as +\csbxint{DivFloor} which had been defined long ago, but did not make it to the +user manual for various reasons, one being that it is thought few users will +use directly the \xintfracname macros, the \csbxint{expr} interface being more +convenient. For complete documentation refer to |sourcexint.pdf|. + +\subsection{\csh{xintNum}}\label{xintNumFrac} + +The original \csbxint{Num} \etype{\Ff} from \xintname is made a synonym to +\csbxint{TTrunc} (whose description is to be found farther in this section). + +Attention that for example |\xintNum{1e100000}| expands to the needed +\dtt{100001} digits... + +The original \hyperref[xintiNum]{\string\xintNum} from \xintcorename which +does not understand the fraction slash or the scientific notation is still +available under the name \csbxint{iNum}. + +\subsection{\csh{xintRaw}}\label{xintRaw} + +This macro `prints' the\etype{\Ff} +fraction |f| as it is received by the package after its parsing and +expansion, in a form |A/B[N]| equivalent to the internal +representation: the denominator |B| is always strictly positive and is +printed even if it has value |1|. +\begin{everbatim*} +\xintRaw{\the\numexpr 571*987\relax.123e-10/\the\numexpr-201+59\relax e-7} +\end{everbatim*} + +No simplification is done, not even of common zeroes between numerator and +denominator: +\begin{everbatim*} +\xintRaw {178000/25600000} +\end{everbatim*} + +\subsection{\csh{xintNumerator}}\label{xintNumerator} + +The input data\etype{\Ff} is parsed as if by \csbxint{Raw} into |A/B[N]| +format and +the macro outputs |A| if |N<=0|, or |A| extended by |N| zeroes if |N>0|. +\begin{everbatim*} +\xintNumerator {178000/25600000[17]}\newline +\xintNumerator {312.289001/20198.27}\newline +\xintNumerator {178000e-3/256e5}\newline +\xintNumerator {178.000/25600000} +\end{everbatim*} + +\subsection{\csh{xintDenominator}}\label{xintDenominator} + +The input data\etype{\Ff} is parsed as if by \csbxint{Raw} into |A/B[N]| +format and +the macro outputs |B| if |N>0|, or |B| extended by \verb+|N|+ zeroes if |N<=0|. +\begin{everbatim*} +\xintDenominator {178000/25600000[17]}\newline +\xintDenominator {312.289001/20198.27}\newline +\xintDenominator {178000e-3/256e5}\newline +\xintDenominator {178.000/25600000} +\end{everbatim*} + +\subsection{\csh{xintRawWithZeros}}\label{xintRawWithZeros} + +This macro parses the input\etype{\Ff} and outputs |A/B|, with |A| +as would be returned by \csa{xintNumerator}|{f}| and |B| as would be returned by +\csa{xintDenominator}|{f}|. +\begin{everbatim*} +\xintRawWithZeros{178000/25600000[17]}\newline +\xintRawWithZeros{312.289001/20198.27}\newline +\xintRawWithZeros{178000e-3/256e5}\newline +\xintRawWithZeros{178.000/25600000}\newline +\xintRawWithZeros{\the\numexpr 571*987\relax.123e-10/\the\numexpr-201+59\relax e-7} +\end{everbatim*} + +\subsection{\csh{xintREZ}}\label{xintREZ} + +The input\etype{\Ff} is first parsed into |A/B[N]| as by \csbxint{Raw}, then +trailing zeroes of |A| and |B| are suppressed and |N| is accordingly adjusted. +\begin{everbatim*} +\xintREZ {178000/25600000[17]} +\end{everbatim*} + +This macro is used internally by various other constructs; its implementation +was redone entirely at |1.3a|, and it got faster on long inputs. + +\subsection{\csh{xintIrr}}\label{xintIrr} + +This puts the fraction\etype{\Ff} into its unique irreducible form: +\begin{everbatim*} +\xintIrr {178.256/256.1780}, \xintIrr {178000/25600000[17]} +\end{everbatim*} + +The current implementation does not cleverly first factor powers of +2 and 5, and |\xintIrr {2/3[100]}| will execute the +Euclidean division of |2|\raisebox{.5ex}{|.|}|10^{100}| by |3|, which is a bit +stupid as it could have known that the \dtt{100} trailing zeros can not bring +any divisibility by \dtt{3}. + +Starting with release |1.08|, \csa{xintIrr} does not remove the trailing |/1| +when the output is an integer. This was deemed better for various (questionable?) +reasons, anyway the output format is since \emph{always} |A/B| with |B>0|, even +in cases where it turns out that |B=1|. +Use \csbxint{PRaw} on top of \csa{xintIrr} if it is needed to get rid of such a +trailing |/1|. + +\subsection{\csh{xintPIrr}}\label{xintPIrr} + +This puts the fraction\etype{\Ff} into irreducible form, +\emph{keeping as is the + decimal part} |[N]| from raw internal |A/B[N]| format.\NewWith{1.3} +(|P| stands here for \emph{Partial}) +\begin{everbatim*} +\xintPIrr {178.256/256.1780}, \xintPIrr {178000/25600000[17]} +\end{everbatim*} + +Notice that the output always has the ending |[N]|, which is exactly the +opposite of \csbxint{Irr}'s behaviour. The interest of this macro is mainly in +handling fractions which somehow acquired a big |[N]| (perhaps from input in +scientific notation) and for which the reduced fraction would have a very +large number of digits. This large number of digits can considerably slow-down +computations done afterwards. + +For example package \href{http://ctan.org/pkg/polexpr}{polexpr} uses +\csa{xintPIrr} when differentiating a polynomial, or in setting up a Sturm +chain for localization of the real roots of a polynomial. This is relevant to +polynomials whose coefficients were input in decimal notation, as this +automatically creates internally some |[N]|. Keeping and combining those +|[N]|'s during computations significantly increases their speed. + +\subsection{\csh{xintJrr}}\label{xintJrr} + +This also puts the fraction\etype{\Ff} into its unique irreducible form: +\begin{everbatim*} +\xintJrr {178.256/256.178} +\end{everbatim*} + +This is (supposedly, not tested for ages) faster than \csa{xintIrr} for +fractions having some big common factor in the numerator and the denominator. +\begin{everbatim*} +\xintJrr {\xintiiPow{\xintiiFac {15}}{3}/% + \xintiiPrd{{\xintiiFac{10}}{\xintiiFac{30}}{\xintiiFac{5}}}} +\end{everbatim*} + +But to notice the difference one would need computations with much bigger +numbers than in this example. As \csbxint{Irr}, \csa{xintJrr} does not remove +the trailing |/1| from a fraction reduced to an integer. + +\subsection{\csh{xintPRaw}}\label{xintPRaw} + +|PRaw|\etype{\Ff} stands for ``pretty raw''. It does like \csbxint{Raw} apart +from removing the |[N]| part if |N=0| and removing the |B| if |B=1|. +\begin{everbatim*} +\xintPRaw {123e10/321e10}, \xintPRaw {123e9/321e10}, \xintPRaw {\xintIrr{861/123}} +\end{everbatim*} + +\subsection{\csh{xintDecToString}}\label{xintDecToString} + +This is\etype{\Ff} a macro tailored for printing decimal numbers. It does not +trim trailing zeros, use |\xintDecToString{\xintREZ{<foo>}}| for that. +\NewWith{1.3} +\begin{everbatim*} +\xintDecToString {123456789e5}\newline +\xintDecToString {123456789e-5}\newline +\xintDecToString {12345e-10}\newline +\xintDecToString {12345e-10/123}\par % just leave denominator as is +\end{everbatim*} +Consider it an unstable macro, what it does exactly is yet to be decided. It +is a backport from \href{http://ctan.org/pkg/polexpr}{polexpr}'s +|\PolDecToString|, which has now been made an alias to it. + +\subsection{\csh{xintTrunc}}\label{xintTrunc} + +\csa{xintTrunc}|{x}{f}|\etype{\numx\Ff} returns the integral part, a dot +(standing for the decimal mark), and +then the first |x| digits of the decimal expansion of the fraction |f|, except +when the fraction is (or evaluates to) zero, then it simply prints \dtt{0} +(with no dot). + +\begin{framed} + The argument |x| must be non-negative, the behaviour is currently undefined + when |x<0| and will provoke errors. +\end{framed} + +Except when the input is (or evaluates to) exactly zero, the output contains +exactly |x| digits after the decimal mark, thus the output may be +\dtt{0.00...0} or \dtt{-0.00...0}, indicating that the original fraction was +positive, respectively negative. + +\begin{framed} + \textbf{Warning:} \emph{it is not yet decided is this behaviour is + definitive.} + + Currently \xintfracname has no notion of a positive zero or a negative zero. + Hence transitivity of \csbxint{Trunc} is broken for the case where the first + truncation gives on output \dtt{0.00...0} or \dtt{-0.00...0}: a second + truncation to less digits will then output \dtt{0}, whereas if it had been + applied directly to the initial input it would have produced \dtt{0.00...0} + or respectively \dtt{-0.00...0} (with less zeros). + + If \xintfracname distinguished zero, positive zero, and + negative zero it would be possible to maintain transitivity. + + The problem would also be fixed, even without distinguishing a negative zero + on input, if \csbxint{Trunc} always produced \dtt{0.00...0} (with no sign) + when the mathematical result is zero, discarding the information on original + input being positive, zero, or negative. + + I have multiple times hesitated about what to do and must postpone again + final decision. +\end{framed} +\begin{everbatim*} +\xintTrunc {16}{-803.2028/20905.298}\newline +\xintTrunc {20}{-803.2028/20905.298}\newline +\xintTrunc {10}{\xintPow {-11}{-11}}\newline +\xintTrunc {12}{\xintPow {-11}{-11}}\newline +\xintTrunc {50}{\xintPow {-11}{-11}}\newline +\xintTrunc {12}{\xintAdd {-1/3}{3/9}}\par +\end{everbatim*} +The digits printed are exact up to and including the last one. + + +\subsection{\csh{xintXTrunc}}\label{xintXTrunc} + + +\csa{xintXTrunc}|{x}{f}|\retype{\numx\Ff} is similar to \csbxint{Trunc} with +the following important differences: +\begin{itemize}[nosep] +\item it is completely expandable but not +\fexpan dable, as is indicated by the hollow star in the margin, +\item hence it can not be used as argument to the other package macros, but as + it \fexpan ds its |{f}| argument, it accepts arguments expressed with other + \xintfracname macros, +\item it requires |x>0|, +\item contrarily to \csbxint{Trunc} the number of digits on output is not + limited to about \dtt{19950} and may go well beyond \dtt{100000} (this is + mainly useful for outputting a decimal expansion to a file), +\item when the mathematical result is zero, it always prints it as + \dtt{0.00...0} or \dtt{-0.00...0} with |x| zeros after the decimal mark. +\end{itemize} + +\textbf{Warning:} +transitivity is broken too (see discussion of \csbxint{Trunc}), due to the +sign in the last item. Hence \emph{the definitive policy is yet to be fixed.} + +Transitivity is here in the sense of using a first |\edef| and then a second +one, because it is not possible to nest \csb{xintXTrunc} directly as argument +to itself. Besides, although the number of digits on output isn't limited, +nevertheless |x| should be less than about |19970| when the number of digits +of the input (assuming it is expressed as a decimal number) is even bigger: +|\xintXTrunc{30000}{\Z}| after |\edef\Z{\xintXTrunc{60000}{1/66049}| raises an +error in contrast with a direct |\xintXTrunc{30000}{1/66049}|. But +|\xintXTrunc{30000}{123.456789}| works, because here the number of digits +originally present is smaller than what is asked for, thus the routine only +has to add trailing zeros, and this has no limitation (apart from \TeX\ main +memory). + +\csbxint{XTrunc} will expand fully in an |\edef| or a |\write| (|\message|, +|\wlog|, \dots) or in an \csbxint{expr}-ession, or as list argument to +\csbxint{For*}. + +Here is an example session where the +user checks that the decimal expansion of $1/66049=1/257^2$ has the maximal +period length $257*256=65792$ (this period length must be a divisor of +$\phi(66049)$ and to check it is the maximal one it is enough to show that +neither $32896$ nor $256$ are periods.) + +\begingroup\small +\everb|@ +$ rlwrap etex -jobname worksheet-66049 +This is pdfTeX, Version 3.14159265-2.6-1.40.17 (TeX Live 2016) (preloaded format=etex) + restricted \write18 enabled. +**xintfrac.sty +entering extended mode +(/usr/local/texlive/2016/texmf-dist/tex/generic/xint/xintfrac.sty +(/usr/local/texlive/2016/texmf-dist/tex/generic/xint/xint.sty +(/usr/local/texlive/2016/texmf-dist/tex/generic/xint/xintcore.sty +(/usr/local/texlive/2016/texmf-dist/tex/generic/xint/xintkernel.sty)))) +*% we load xinttools for \xintKeep, etc... \xintXTrunc itself has no more + +*% any dependency on xinttools.sty since 1.2i + +*\input xinttools.sty +(/usr/local/texlive/2016/texmf-dist/tex/generic/xint/xinttools.sty) +*\def\m#1;{\message{#1}} + +*\m \the\numexpr 257*257\relax; +66049 +*\m \the\numexpr 257*256\relax; +65792 +*% Thus 1/66049 will have a period length dividing 65792. + +*% Let us first check it is indeed periodical. + +*\edef\Z{\xintXTrunc{66000}{1/66049}} + +*% Let's display the first decimal digits. + +*\m \xintXTrunc{208}{\Z}; + +0.00001514027464458205271843631243470756559523989765174340262532362337052794137 +6856576178291874214598252812306015231116292449545034746930309315810988811337037 +6538630410755651107511090251177156353616254598858423 +*% let's now fetch the trailing digits + +*\m \xintKeep{65792-66000}{\Z};% 208 trailing digits + +0000151402746445820527184363124347075655952398976517434026253236233705279413768 +5657617829187421459825281230601523111629244954503474693030931581098881133703765 +38630410755651107511090251177156353616254598858423 +*% yes they match! we now check that 65792/2 and 65792/257=256 aren't periods. + +*\m \xintXTrunc{256}{\Z}; + +0.00001514027464458205271843631243470756559523989765174340262532362337052794137 +6856576178291874214598252812306015231116292449545034746930309315810988811337037 +6538630410755651107511090251177156353616254598858423291798513225029902042423049 +554118911717058547442 +*\m \xintXTrunc{256+256}{\Z}; + +0.00001514027464458205271843631243470756559523989765174340262532362337052794137 +6856576178291874214598252812306015231116292449545034746930309315810988811337037 +6538630410755651107511090251177156353616254598858423291798513225029902042423049 +5541189117170585474420505987978621932201850141561567926842192917379521264515738 +3154930430438008145467758785144362518736089872670290239064936637950612424109373 +3440324607488379839210283274538600130206361943405653378552286938485064119063119 +8049932625777831609865402958409665551333 +*% now with 65792/2=32896. Problem: we can't do \xintXTrunc{32896+100}{\Z} + +*% but only direct \xintXTrunc{32896+100}{1/66049}. Anyway we want to nest it + +*% hence let's do it all with (slower) \xintKeep, \xintKeepUnbraced. + +*\m \xintKeep {-100}{\xintKeepUnbraced{2+65792/2+100}{\Z}}; + +9999848597253554179472815636875652924344047601023482565973746763766294720586231 +434238217081257854017 +*% This confirms 32896 isn't a period length. + +*% To conclude let's write the 66000 digits to the log. + +*\wlog{\Z} + +*% We want always more digits: + +*\wlog{\xintXTrunc{150000}{1/66049}} + +*\bye +| +\endgroup % $ à cause de fontification de AUCTeX. + +The acute observer will have noticed that there is something funny when one +compares the first digits with those after the middle-period: +\begin{everbatim} +0000151402746445820527184363124347075655952398976517434026253236233705279413768... +9999848597253554179472815636875652924344047601023482565973746763766294720586231... +\end{everbatim} +Mathematical exercise: can you explain why the two indeed add to |9999...9999|? + +You can try your hands at this simpler one: +\begin{everbatim*} +1/49=\xintTrunc{42+5}{1/49}...\newline +\xintTrim{2}{\xintTrunc{21}{1/49}}\newline +\xintKeep{-21}{\xintTrunc{42}{1/49}} +\end{everbatim*} + +This was again an example of the type |1/N| with |N| the square of a prime. +One can also find counter-examples within this class: |1/31^2| and |1/37^2| +have an odd period length (|465| and respectively |111|) hence they can not +exhibit the symmetry. + +\begin{framed} + Mathematical challenge: prove generally that if the period length of the + decimal expansion of |1/p^r| (with |p| a prime distinct from |2| and |5| and + |r| a positive exponent) is even, then the previously observed symmetry + about the two halves of the period adding to a string of nine's applies. +\end{framed} + + + +\subsection{\csh{xintTFrac}}\label{xintTFrac} + +\csa{xintTFrac}|{f}|\etype{\Ff} returns the fractional part, +|f=trunc(f)+frac(f)|. Thus if |f<0|, then |-1<frac(f)<=0| and if |f>0| one has +|0<= frac(f)<1|. The |T| stands for `Trunc', and there should exist also +similar macros associated respectively with `Round', `Floor', and `Ceil', each +type of rounding to an integer deserving arguably to be associated with a +fractional ``modulo''. By sheer laziness, the package currently implements +only the ``modulo'' associated with `Truncation'. Other types of modulo may be +obtained more cumbersomely via a combination of the rounding with a subsequent +subtraction from |f|. + +Notice that the result is filtered through \csbxint{REZ}, and will thus be of +the form |A/B[N]|, where neither |A| nor |B| has trailing zeros. But the +output fraction is not reduced to smallest terms. + +The function call in expressions (\csbxint{expr}, \csbxint{floatexpr}) is +|frac|. Inside |\xintexpr..\relax|, the function |frac| is mapped to +\csa{xintTFrac}. Inside |\xintfloatexpr..\relax|, |frac| first applies +\csa{xintTFrac} to its argument (which may be an exact fraction with more +digits than the floating point precision) and only in a second stage makes the +conversion to a floating point number with the precision as set by |\xintDigits| +(default is \dtt{16}). +\begin{everbatim*} +\xintTFrac {1235/97}, \xintTFrac {-1235/97}\newline +\xintTFrac {1235.973}, \xintTFrac {-1235.973}\newline +\xintTFrac {1.122435727e5}\par +\end{everbatim*} + +\subsection{\csh{xintRound}}\label{xintRound} + +\csa{xintRound}|{x}{f}|\etype{\numx\Ff} returns the start of the decimal +expansion of the fraction |f|, rounded to |x| digits precision after the decimal +point. The argument |x| should be non-negative. Only when |f| evaluates exactly +to zero does \csa{xintRound} return |0| without decimal point. When |f| is not +zero, its sign is given in the output, also when the digits printed are all +zero. +\begin{everbatim*} +\xintRound {16}{-803.2028/20905.298}\newline +\xintRound {20}{-803.2028/20905.298}\newline +\xintRound {10}{\xintPow {-11}{-11}}\newline +\xintRound {12}{\xintPow {-11}{-11}}\newline +\xintRound {12}{\xintAdd {-1/3}{3/9}}\par +\end{everbatim*} + +\subsection{\csh{xintFloor}}\label{xintFloor} + +|\xintFloor {f}|\etype{\Ff} returns the largest relative integer |N| with +|N|${}\leqslant{}$|f|. +\begin{everbatim*} +\xintFloor {-2.13}, \xintFloor {-2}, \xintFloor {2.13} +\end{everbatim*} +Note the trailing |[0]|, see \csbxint{iFloor} if it is not desired. + +\subsection{\csh{xintCeil}}\label{xintCeil} + +|\xintCeil {f}|\etype{\Ff} returns the smallest relative integer |N| with +|N|${}>{}$|f|. +\begin{everbatim*} +\xintCeil {-2.13}, \xintCeil {-2}, \xintCeil {2.13} +\end{everbatim*} + +\subsection{\csh{xintiTrunc}}\label{xintiTrunc} + +\csa{xintiTrunc}|{x}{f}|\etype{\numx\Ff} returns the integer equal to |10^x| +times what \csa{xintTrunc}|{x}{f}| would produce. +\begin{everbatim*} +\xintiTrunc {16}{-803.2028/20905.298}\newline +\xintiTrunc {10}{\xintPow {-11}{-11}}\newline +\xintiTrunc {12}{\xintPow {-11}{-11}}\par +\end{everbatim*} + +In particular \csa{xintiTrunc}|{0}{f}|'s output is in strict integer format +contrarily to \csa{xintTrunc}|{0}{f}| which produces an output with a decimal +mark, except if |f| turns out to be zero. + +\subsection{\csh{xintTTrunc}}\label{xintTTrunc} + +\csa{xintTTrunc}|{f}|\etype{\Ff} truncates to an integer (truncation towards +zero). This is the same as |\xintiTrunc {0}{f}| and also the same as +\csbxint{Num}. + +\subsection{\csh{xintiRound}}\label{xintiRound} + +\csa{xintiRound}|{x}{f}|\etype{\numx\Ff} returns the integer equal to |10^x| +times what \csa{xintRound}|{x}{f}| would return. +\begin{everbatim*} +\xintiRound {16}{-803.2028/20905.298}\newline +\xintiRound {10}{\xintPow {-11}{-11}}\par +\end{everbatim*} + +In particular \csa{xintiRound}|{0}{f}|'s output is in strict integer format +contrarily to \csa{xintRound}|{0}{f}| which produces an output with a decimal +mark, except if |f| turns out to be zero. + +\subsection{\csh{xintiFloor}}\label{xintiFloor} + +|\xintiFloor {f}|\etype{\Ff} does the same as \csbxint{Floor} but without the +trailing |/1[0]|. +\begin{everbatim*} +\xintiFloor {-2.13}, \xintiFloor {-2}, \xintiFloor {2.13} +\end{everbatim*} + +\subsection{\csh{xintiCeil}}\label{xintiCeil} + +|\xintiCeil {f}|\etype{\Ff} does the same as \csbxint{Ceil} but its output is +without the |/1[0]|. +\begin{everbatim*} +\xintiCeil {-2.13}, \xintiCeil {-2}, \xintiCeil {2.13} +\end{everbatim*} + +\subsection{\csh{xintE}}\label{xintE} + +|\xintE {f}{x}|\etype{\Ff\numx} multiplies the fraction |f| by $10^x$. The +\emph{second} argument |x| must obey the \TeX{} bounds. Example: +\begin{everbatim*} +\count 255 123456789 \xintE {10}{\count 255} +\end{everbatim*} +Don't feed this example to \csbxint{Num}! + +\subsection{\csh{xintCmp}}\label{xintCmp} + +This\etype{\Ff\Ff} compares two fractions |F| and |G| and produces +|-1|, |0|, or |1| according to |F<G|, |F=G|, |F>G|. + +For choosing branches according to the result of comparing |f| and |g|, see +\csbxint{ifCmp}. + +\subsection{\csh{xintEq}}\label{xintEq} + +|\xintEq{f}{g}|\etype{\Ff\Ff} returns 1 if |f=g|, 0 otherwise. + +\subsection{\csh{xintNotEq}}\label{xintNotEq} + +|\xintNotEq{f}{g}|\etype{\Ff\Ff} returns 0 if |f=g|, 1 otherwise. + + +\subsection{\csh{xintGeq}}\label{xintGeq} + +This\etype{\Ff\Ff} compares the \emph{absolute values} of two +fractions. +|\xintGeq{f}{g}| outputs |1| if {\catcode`| 12 $|f|\geqslant|g|$} and |0| +if not. + +Important: the macro compares \emph{absolute values}. + +\subsection{\csh{xintGt}}\label{xintGt} + +|\xintGt{f}{g}|\etype{\Ff\Ff} returns \dtt{1} if |f|$>$|g|, \dtt{0} otherwise. + +\subsection{\csh{xintLt}}\label{xintLt} + +|\xintLt{f}{g}|\etype{\Ff\Ff} returns \dtt{1} if |f|$<$|g|, \dtt{0} otherwise. + +\subsection{\csh{xintGtorEq}}\label{xintGxstorEq} + +|\xintGtorEq{f}{g}|\etype{\Ff\Ff} returns \dtt{1} if |f|$\geqslant$|g|, \dtt{0} otherwise. +Extended by \xintfracname to fractions. + +\subsection{\csh{xintLtorEq}}\label{xintLtorEq} + +|\xintLtorEq{f}{g}|\etype{\Ff\Ff} returns \dtt{1} if |f|$\leqslant$|g|, \dtt{0} otherwise. + +\subsection{\csh{xintIsZero}}\label{xintIsZero} + +|\xintIsZero{f}|\etype{f} returns \dtt{1} if |f=0|, \dtt{0} otherwise. + +\subsection{\csh{xintIsNotZero}}\label{xintIsNotZero} + +|\xintIsNotZero{f}|\etype{f} returns \dtt{1} if |f!=0|, \dtt{0} otherwise. + +\subsection{\csh{xintIsOne}}\label{xintIsOne} + +|\xintIsOne{f}|\etype{f} returns \dtt{1} if |f=1|, \dtt{0} otherwise. + +\subsection{\csh{xintOdd}}\label{xintOdd} + +|\xintOdd{f}|\etype{f} returns \dtt{1} if the integer obtained by truncation is +odd, and \dtt{0} otherwise. + +\subsection{\csh{xintEven}}\label{xintEven} + +|\xintEven{f}|\etype{f} returns \dtt{1} if the integer obtained by truncation is +even, and \dtt{0} otherwise. + +\subsection{\csh{xintifSgn}}\label{xintifSgn} + +\csh{xintifSgn}\marg{f}\marg{A}\marg{B}\marg{C}\etype{\Ff nnn} executes either the +\meta{A}, \meta{B} or \meta{C} code, depending on its first argument being +respectively negative, zero, or positive. + +\subsection{\csh{xintifZero}}\label{xintifZero} + +\csa{xintifZero}\marg{f}\marg{IsZero}\marg{IsNotZero}\etype{\Ff nn} expandably +checks if the first mandatory argument |N| (a number, possibly a fraction if +\xintfracname is loaded, or a macro expanding to one such) is zero or not. It +then either executes the first or the second branch. + +Beware that both branches must be present. + +\subsection{\csh{xintifNotZero}}\label{xintifNotZero} + +\csa{xintifNotZero}\marg{N}\marg{IsNotZero}\marg{IsZero}\etype{\Ff nn} +expandably checks if the first mandatory argument |f| is not +zero or is zero. It then either executes the first or the second branch. + +Beware that both branches must be present. + +\subsection{\csh{xintifOne}}\label{xintifOne} + +\csa{xintifOne}\marg{N}\marg{IsOne}\marg{IsNotOne}\etype{\Ff nn} expandably +checks if the first mandatory argument |f| is one or not one. It +then either executes the first or the second branch. Beware that both branches +must be present. + +\subsection{\csh{xintifOdd}}\label{xintifOdd} + +\csa{xintifOdd}\marg{N}\marg{odd}\marg{not odd}\etype{\Ff nn} expandably +checks if the first mandatory argument |f|, after truncation to an integer, is +odd or even. It then executes accordingly the first or the second branch. +Beware that both branches must be present. + +\subsection{\csh{xintifCmp}}\label{xintifCmp} + +\csa{xintifCmp}\marg{f}\marg{g}\marg{if f<g}\marg{if f=g}\marg{if + f>g}\etype{\Ff\Ff nnn} compares its first two arguments and chooses accordingly +the correct branch. + +\subsection{\csh{xintifEq}}\label{xintifEq} + +\csa{xintifEq}\marg{f}\marg{g}\marg{YES}\marg{NO}\etype{\Ff\Ff nn} checks +equality of its two first arguments and executes accordingly the |YES| or the +|NO| branch. + +\subsection{\csh{xintifGt}}\label{xintifGt} + +\csa{xintifGt}\marg{f}\marg{g}\marg{YES}\marg{NO}\etype{\Ff\Ff nn} +checks if $f>g$ and in that case executes the |YES| branch. + +\subsection{\csh{xintifLt}}\label{xintifLt} + +\csa{xintifLt}\marg{f}\marg{g}\marg{YES}\marg{NO}\etype{\Ff\Ff nn} +checks if $f<g$ and in that case executes the |YES| branch. + +\subsection{\csh{xintifInt}}\label{xintifInt} + +\csa{xintifInt}|{f}{YES branch}{NO branch}|\etype{\Ff nn} expandably chooses +the |YES| branch if |f| reveals itself after expansion and simplification to +be an integer. + +\subsection{\csh{xintSgn}}\label{xintSgn} + +The sign of a fraction.\etype{\Ff} + +\subsection{\csh{xintOpp}}\label{xintOpp} + +The opposite of a fraction.\etype{\Ff} +Note that |\xintOpp {3}| produces \dtt{\xintOpp + {3}} whereas |\xintiiOpp {3}| produces \dtt{\xintiiOpp {3}}. + +\subsection{\csh{xintAbs}}\label{xintAbs} + +The absolute value\etype{\Ff}. Note that |\xintAbs {-2}|\dtt{=\xintAbs {-2}} +where |\xintiiAbs {-2}| outputs \dtt{=\xintiiAbs {-2}}. + +\subsection{\csh{xintAdd}}\label{xintAdd} + +Computes the addition\etype{\Ff\Ff} of two fractions. + +Since |1.3| always uses the least common multiple of the +denominators.\CHANGED{1.3} + +\subsection{\csh{xintSub}}\label{xintSub} + +Computes the difference\etype{\Ff\Ff} of two fractions (|\xintSub{F}{G}| +computes |F-G|). + +Since |1.3| always uses the least common multiple of the +denominators.\CHANGED{1.3} + +\subsection{\csh{xintMul}}\label{xintMul} + +Computes the product\etype{\Ff\Ff} of two fractions. + +Output is not reduced to smallest terms. + +\subsection{\csh{xintDiv}}\label{xintDiv} + +Computes the quotient \etype{\Ff\Ff} of two fractions. +(|\xintDiv{F}{G}| computes |F/G|). + +Output is not reduced to smallest terms. + +\subsection{\csh{xintDivFloor}} +\label{xintDivFloor} + +Computes the quotient \etype{\Ff\Ff} of two arguments then apply floor +function to get an integer (in strict format). This macro was defined at |1.1| +(but was left not documented until |1.3a|...) and changed at |1.2p|, formerly +it appended |/1[0]| to output. +\begin{everbatim*} +\xintDivFloor{-170/3}{23/2} +\end{everbatim*} + +\subsection{\csh{xintMod}} +\label{xintMod} + +Computes the remainder associated to the floored division\etype{\Ff\Ff} +\csbxint{DivFloor}. Prior to |1.2p| the meaning was the one of +\csbxint{ModTrunc}. Was left undocumented until |1.3a|. +\begin{everbatim*} +\xintMod{-170/3}{23/2} +\end{everbatim*} + +Modified at |1.3| to use a l.c.m. for the denominator of the result. +\CHANGED{1.3} + +\subsection{\csh{xintDivMod}} +\label{xintDivMod} + +Computes both the floored division and the remainder\etype{\Ff\Ff} +\csbxint{DivFloor}. New at |1.2p| and documented at |1.3a|. +\begin{everbatim*} +\oodef\foo{\xintDivMod{-170/3}{23/2}}\meaning\foo +\end{everbatim*} + +\subsection{\csh{xintDivTrunc}} +\label{xintDivTrunc} + +Computes the quotient \etype{\Ff\Ff} of two arguments then +truncates to an integer (in strict format). +\begin{everbatim*} +\xintDivTrunc{-170/3}{23/2} +\end{everbatim*} + +\subsection{\csh{xintModTrunc}} +\label{xintModTrunc} + +Computes the remainder\etype{\Ff\Ff} associated with the truncated division of +two arguments. Prior to |1.2p| it was named \csbxint{Mod}, but the latter then +got associated with floored division. +\begin{everbatim*} +\xintModTrunc{-170/3}{23/2} +\end{everbatim*} + +Modified at |1.3| to use a l.c.m. for the denominator of the result. +\CHANGED{1.3} + +\subsection{\csh{xintDivRound}} +\label{xintDivRound} + +Computes the quotient \etype{\Ff\Ff} of the two arguments then rounds to an +integer (in strict format). +\begin{everbatim*} +\xintDivRound{-170/3}{23/2} +\end{everbatim*} + +\subsection{\csh{xintSqr}}\label{xintSqr} + +Computes the square\etype{\Ff} of one fraction. + +\subsection{\csh{xintPow}}\label{xintPow} + +\csa{xintPow}{|{f}{x}|}:\etype{\Ff\Numf} computes |f^x| with |f| a fraction and +|x| possibly also, but |x| will first get truncated to a (positive or negative) +integer. + +The exponent |x| must obey the TeX-bound, but this limit is theoretical, as +\TeX's memory or expansion settings get saturated quite earlier: it is +explained in the documentation of \csbxint{iiPow} that the maximal power of +$2$ computable by \xintname is |2^131072| which has \dtt{39457} digits. +Actually, the pratical range is even smaller due to execution times. + +The output will always be in the form |A/B[n]| (even if the exponent +vanishes: |\xintPow {2/3}{0}|\dtt{=\xintPow{2/3}{0}}). + + +Within an \csbxint{iiexpr}|..\relax| the infix operator |^| is mapped to +\csa{xintiiPow}; within an \csbxint{expr}-ession it is mapped to +\csa{xintPow}. + +\subsection{\csh{xintFac}}\label{xintFac} + +This is a convenience variant of \csbxint{iiFac} which applies \csbxint{Num} +to its argument\etype{\Numf}. Notice however that the output will have a trailing +|[0]| according to the \xintfracname format for integers. + + +\subsection{\csh{xintBinomial}}\label{xintBinomial} + +This is a convenience variant of \csbxint{iiBinomial} which applies +\csbxint{Num} to its arguments\etype{\Numf\Numf}. Notice however that the +output will have a trailing |[0]| according to the \xintfracname format for +integers. + + +\subsection{\csh{xintPFactorial}}\label{xintPFactorial} + +This is a convenience variant of \csbxint{iiPFactorial} which applies +\csbxint{Num} to its arguments\etype{\Numf\Numf}. Notice however that the +output will have a trailing |[0]| according to the \xintfracname format for +integers. + + +\subsection{\csh{xintMax}}\label{xintMax} + +The maximum of two fractions.\etype{\Ff\Ff} Beware that |\xintMax {2}{3}| +produces \dtt{\xintMax {2}{3}}. The original, for use with +integers only with no need of normalization, is available as \csbxint{iiMax}: +|\xintiiMax {2}{3}=|\dtt{\xintiiMax {2}{3}}.\etype{ff} + +\begin{everbatim*} +\xintMax {2.5}{7.2} +\end{everbatim*} + +\subsection{\csh{xintMin}}\label{xintMin} + +The minimum of two fractions.\etype{\Ff\Ff} Beware that |\xintMin {2}{3}| +produces \dtt{\xintMin {2}{3}}. The original, for use with +integers only with no need of normalization, is available as \csbxint{iiMin}: +|\xintiiMin {2}{3}=|\dtt{\xintiiMin {2}{3}}.\etype{ff} + +\begin{everbatim*} +\xintMin {2.5}{7.2} +\end{everbatim*} + +\subsection{\csh{xintMaxof}}\label{xintMaxof} + +The maximum of any number of fractions, each within braces, and the whole +thing within braces. \etype{f{$\to$}{\lowast\Ff}} + +\begin{everbatim*} +\xintMaxof {{1.23}{1.2299}{1.2301}} and \xintMaxof {{-1.23}{-1.2299}{-1.2301}} +\end{everbatim*} + +\subsection{\csh{xintMinof}}\label{xintMinof} + +The minimum of any number of fractions, each within braces, and the whole +thing within braces. \etype{f{$\to$}{\lowast\Ff}} + +\begin{everbatim*} +\xintMinof {{1.23}{1.2299}{1.2301}} and \xintMinof {{-1.23}{-1.2299}{-1.2301}} +\end{everbatim*} + +\subsection{\csh{xintSum}}\label{xintSum} + +This\etype{f{$\to$}{\lowast\Ff}} computes the sum of fractions. The output +will now always be in the form |A/B[n]|. The original, for big integers only +(in strict format), is available as \csa{xintiiSum}. + +\begin{everbatim*} +\xintSum {{1282/2196921}{-281710/291927}{4028/28612}} +\end{everbatim*} + +No simplification attempted. + +\subsection{\csh{xintPrd}}\label{xintPrd} + +TThis\etype{f{$\to$}{\lowast\Ff}} computes the product of fractions. The output +will now always be in the form |A/B[n]|. The original, for big integers only +(in strict format), is available as \csa{xintiiPrd}. + +\begin{everbatim*} +\xintPrd {{1282/2196921}{-281710/291927}{4028/28612}} +\end{everbatim*} + +No simplification attempted. + +\begin{everbatim*} +$\xintIsOne {21921379213/21921379213}\neq\xintIsOne {1.00000000000000000000000000000001}$ +\end{everbatim*} + +\subsection{\csh{xintDigits}, \csh{xinttheDigits}} +\label{xintDigits} +\label{xinttheDigits} + +The syntax |\xintDigits := D;| (where spaces do not matter) assigns the +value of |D| to the number of digits to be used by floating point +operations. The default is |16|. The maximal value is |32767|. The macro +|\xinttheDigits|\etype{} serves to print the current value. + +\subsection{\csh{xintFloat}}\label{xintFloat} + + +The macro |\xintFloat [P]{f}|\etype{{\upshape[\numx]}\Ff} has an optional +argument |P| which replaces the current value of |\xinttheDigits|. The +fraction |f| is then printed in scientific notation with a rounding to |P| digits. + +That is, on output: the first digit is from |1| to |9|, it is possibly +prefixed by a minus sign and is followed by a dot and |P-1| digits, then a +lower case |e| and an exponent |N|. The trailing zeroes are not trimmed. + +\begin{framed} + There is currently one exceptional case: the zero value, which gets output + as \dtt{\xintFloat{0}}. It is yet to be decided what the final policy will be. +\end{framed} + +Starting with |1.2k|, when the input is a fraction |AeN/BeM| +the output always is the \emph{correct rounding} to |P| digits. Formerly, this +was guaranteed only when |A| and |B| had at most |P+2| digits, or when |B| was +|1| and |A| was arbitrary, but in other cases it was only guaranteed that the +difference between the original fraction and the rounding was at most +\dtt{0.6} unit in the last place (of the output), hence the output could +differ in the last digit (and earlier ones in case of chains of zeros or +nines) from the correct rounding. + +Also: for releases |1.2j| and earlier, in the special case when +|A/B| ended up being rounded up to the next power of ten, the output was with +a mantissa of the shape |10.0...0eN|. However, this worked only for |B=1| or +when both |A| and |B| had at most |P+2| digits, because the detection of the +rounding-up to next power of ten was done not on original |A/B| but on an +approximation |A'/B'|, and it could happen that |A'/B'| was itself being +rounded \emph{down} to a power of ten which however was a rounding \emph{up} +of original |A/B|. With the |1.2j| refactoring which achieves correct rounding +in all cases, it was decided not to add to the code the extra overhead of +detecting with 100\% fiability the rounding up to next power of ten (such +overhead would necessitate alterations of the algorithm and as a result we +would end up with a slightly less efficient one; it would make sense in a +model where inputs have their intrinsic precisions which is obeyed by the +implementation of the basic operations, but currently the design decision for +the floating point macros is that when the target precision is |P| the inputs +are rounded first to |P| digits before further processing.) +\begin{everbatim*} +{\def\x{99999999999999994999999999999999/99999999999999999999999999999999}% +\xintFor #1 in {13, 14, 15, 16, 17, 18, 19, 47, 48, 49, 50, 79, 80, 81} +\do{#1: \xintFloat[#1]{\x}\xintifForLast{\par}{\newline}}}% +\end{everbatim*} +As an aside, which is illustrated by the above, rounding is not +transitive in the number of kept digits. +\begin{everbatim*} +{\def\x{137893789173289739179317/13890138013801398}% +\xintFor* #1 in {\xintSeq{4}{20}} +\do{#1: \xintFloat[#1]{\x}\newline}}% +\xintFloat{5/9999999999999999}\newline +\xintFloat[32]{5/9999999999999999}\newline +\xintFloat[48]{5/9999999999999999}\par +\end{everbatim*} + + + +\subsection{\csh{xintPFloat}}\label{xintPFloat} + +The macro |\xintPFloat [P]{f}|\etype{{\upshape[\numx]}\Ff} is like +\csbxint{Float} but ``pretty-prints'' the output. Its behaviour has changed +with release |1.2f|\IMPORTANT{}: there is only one simplification rule now +which is that decimal notation (with possibly needed extra zeros) is used in +place of scientific notation when the exponent would end up being between +\dtt{-5} and \dtt{5} inclusive. + +If the input vanishes the output will be \dtt{\xintPFloat{0}} with a a decimal +mark.% +% +\footnote{Currently there are no subnormal numbers, and no underflow + because the exponent is only limited by the maximal \TeX\ number; thus + underflow situations would manifest themselves via low-level arithmetic + overflow errors.} + +\csbxint{thefloatexpr} applies this macro to its output (or each of +its outputs, if comma separated). + +Currently trailing zeros are not trimmed. + +\begin{everbatim*} +\begingroup\def\test #1{#1${}\to{}$\xintPFloat{#1}}% +\string\xintDigits\ at \xinttheDigits +\begin{itemize}[nosep] +\item \test {0} +\item \test {1.23456789e-7} +\item \test {1.23456789e-6} +\item \test {1.23456789e-5} +\item \test {1.23456789e-4} +\item \test {1.23456789e-3} +\item \test {1.23456789e-2} +\item \test {1.23456789e-1} +\item \test {1.23456789e0} +\item \test {1.23456789e1} +\item \test {1.23456789e2} +\item \test {1.23456789e3} +\item \test {1.23456789e4} +\item \test {1.23456789e5} +\item \test {1.23456789e6} +\item \test {1.23456789e7} +\end{itemize} +\endgroup +\end{everbatim*} + + +\subsection{\csh{xintFloatE}}\label{xintFloatE} + +|\xintFloatE [P]{f}{x}|\etype{{\upshape[\numx]}\Ff\numx} multiplies the input +|f| by $10^x$, and +converts it to float format according to the optional first argument or current +value of |\xinttheDigits|. +\begin{everbatim*} +\xintFloatE {1.23e37}{53} +\end{everbatim*} + +\subsection{\csh{xintFloatAdd}}\label{xintFloatAdd} + + +|\xintFloatAdd [P]{f}{g}|\etype{{\upshape[\numx]}\Ff\Ff} first replaces |f| +and |g| with their float approximations |f'| and |g'| to |P| significant +places or to the precision from |\xintDigits|. It then produces +the sum |f'+g'|, correctly rounded to nearest with the same number of +significant places. + + +\subsection{\csh{xintFloatSub}}\label{xintFloatSub} + + +|\xintFloatSub [P]{f}{g}|\etype{{\upshape[\numx]}\Ff\Ff} first replaces |f| +and |g| with their float approximations |f'| and |g'| to |P| significant +places or to the precision from |\xintDigits|. It then produces +the difference |f'-g'| correctly rounded to nearest |P|-float. + + +\subsection{\csh{xintFloatMul}}\label{xintFloatMul} + + +|\xintFloatMul [P]{f}{g}|\etype{{\upshape[\numx]}\Ff\Ff} first replaces |f| +and |g| with their float approximations |f'| and |g'| to |P| (or +|\xinttheDigits|) significant places. It then correctly rounds +the product |f'*g'| to nearest |P|-float. + +See \autoref{ssec:floatingpoint} for more. + +\begin{framed} + It is obviously much needed that the author improves its algorithms to avoid + going through the exact |2P| or |2P-1| digits before + throwing to the waste-bin half of those digits ! + + % \xintname initially was purely an \emph{exact} arbitrary precision + % arithmetic machine, and the introduction of floating point numbers was an + % after-thought. I got it working in release |1.07 (2013/05/25)| and never had + % time to come back to it. +\end{framed} + +\subsection{\csh{xintFloatDiv}}\label{xintFloatDiv} + + +|\xintFloatDiv [P]{f}{g}|\etype{{\upshape[\numx]}\Ff\Ff} first replaces |f| +and |g| with their float approximations |f'| and |g'| to |P| (or +|\xinttheDigits|) significant places. It then correctly rounds +the fraction |f'/g'| to nearest |P|-float. + +See \autoref{ssec:floatingpoint} for more. + +Notice in the special situation with |f| and |g| integers that |\xintFloatDiv +[P]{f}{g}| will \emph{not necessarily} give the correct rounding of the +exact fraction |f/g|. Indeed the macro arguments are each first individually +rounded to |P| digits of precision. The correct syntax to get the correctly +rounded integer fraction |f/g| is \csbxint{Float}|[P]{f/g}|. + +\subsection{\csh{xintFloatPow}}\label{xintFloatPow} + +|\xintFloatPow [P]{f}{x}|\etype{{\upshape[\numx]}\Ff\numx} uses either the +optional argument |P| or in its absence the value of |\xinttheDigits|. It +computes a floating approximation to |f^x|. + +The exponent |x| will be handed over to a |\numexpr|, hence count registers are +accepted on input for this |x|. And the absolute value \verb+|x|+ must obey the +\TeX{} bound. + +The argument |f| is first rounded to |P| significant places to give +|f'|. The output |Z| is such that the exact |f'^x| differs from +|Z| by an absolute error less than |0.52 ulp(Z)|. +\begin{everbatim*} +\xintFloatPow [8]{3.1415}{1234567890} +\end{everbatim*} + +\subsection{\csh{xintFloatPower}}\label{xintFloatPower} + +\csa{xintFloatPower}|[P]{f}{g}|\etype{{\upshape[\numx]}\Ff\Numf} computes a +floating point value |f^g| where the exponent |g| is not constrained to be at +most the \TeX{} bound \dtt{\number "7FFFFFFF}. It may even be a fraction +|A/B| but must simplify to a (possibly big) integer. The exponent of the +\emph{output} however \emph{must} at any rate obey the \TeX{} bound. + +The argument |f| is first rounded to |P| significant places to give +|f'|. The output |Z| is then such that the exact |f'^g| differs from +|Z| by an absolute error less than |0.52 ulp(Z)|. + +This is the macro which is used for the |^| (or |**|) infix operators in +|\xintthefloatexpr...\relax|. In this context (but not directly with the +macro,) half-integer exponents are allowed. This is handled via an integer power +followed by a square-root extraction. The exponent is first rounded to nearest +integer or half-integer so that the computation never raises errors (except +naturally for negative exponent and zero |f|.) The |0.52 ulp(Z)| bound applies +with half-integer exponents too. + + +Notice that this is a bound on the distance from |f'^g| to |Z|, as |f| always +gets rounded to |P| or \csbxint{theDigits} digits. The distance from |f^g| to +|Z| can be much worse if |g| is very large. Roughly, when |g| is negligible +compared to |10^P|, we get an extra difference of up to about |50g ulp(Z)| +which completely dwarfs the |0.52 ulp(Z)|. Thus, if |f| has strictly more than +|P| digits, then the computation must be done with an elevated working +precision |P'|. For example with |g=1000| we should use |P'=P+6| to achieve a +total error at worst slightly bigger than |0.55 ulp(Z)| after the final +rounding from |P'| to |P| digits to get |Z|. + +Examples:% +% +\footnote{|\np| is formatting macro from the \url{http://ctan.org/pkg/numprint} + package.} +% +\begin{everbatim*} +\np{\xintFloatPower [8]{3.1415}{3e9}}\newline% Notice that 3e9>2^31 +\np{\xintFloatPower [48]{1.1547}{\xintiiPow {2}{35}}}\newline +\end{everbatim*}% +$2^{35}=\xintiiPow {2}{35}$ exceeds \TeX's bound, but what +counts is the exponent of the result which, while dangerously close to +$2^{31}$ is not quite there yet. + +With expressions: +\begin{everbatim*} +{\xintDigits:=48;\np{\xintthefloatexpr 1.1547^(2^35)\relax}} +\end{everbatim*} + +There is a subtlety here that the |2^35| will be evaluated as a floating point +number but fortunately it only has \dtt{11} digits, hence the final evaluation +is done with a correct exponent. It would have been safer, and also more +efficient to code the above rather as: +\begin{everbatim} +\xintthefloatexpr 1.1547^\xintiiexpr 2^35\relax\relax +\end{everbatim} + +Here is an example with +|12^16| as exponent, which has $18$ digits (\dtt{={\xintiiPow{12}{16}}}). +\begin{everbatim*} +{\xintDigits:=12;\np{\xintthefloatexpr (1+1e-8)^\xintiiexpr 12^16\relax\relax}}\newline +\np{\xintthefloatexpr (1+1e-8)^\xintiiexpr 12^16\relax\relax}\newline +{\xintDigits:=27;\np{\xintthefloatexpr (1+1e-8)^(12^16)\relax}}\newline +{\xintDigits:=48;\np{\xintthefloatexpr (1+1e-8)^(12^16)\relax}} +\end{everbatim*} + +There is an important difference between |\xintFloatPower[Q]{X}{Y}| and +|\xintthefloatexpr[Q] X^Y\relax|: in the former case the computation is done +with |Q| digits or precision,% +% +\footnote{if |X| and |Y| themselves stand for some +floating point macros with arguments, their respective evaluations obey the +precision |\xinttheDigits| or as set optionally in the macro calls +themselves.} +% +whereas with \csbxint{thefloatexpr}|[Q]| the evaluation of the +expression proceeds with |\xinttheDigits| digits of precision, and the final +result is then rounded to |Q| digits: thus this makes real sense only if used +with |Q<\xinttheDigits|. + +\subsection{\csh{xintFloatSqrt}}\label{xintFloatSqrt} + +\csa{xintFloatSqrt}|[P]{f}|\etype{{\upshape[\numx]}\Ff} computes a floating +point approximation of $\sqrt{|f|}$, either using the optional precision |P| or +the value of |\xinttheDigits|. + +More precisely since |1.2f| the macro achieves so-called \emph{correct + rounding}:\IMPORTANT{} the produced value is the rounding to |P| significant +places of the abstract exact value, \emph{if the input has itself at most |P| + digits} (and an arbitrary exponent). +\begin{everbatim*} +\xintFloatSqrt [89]{10}\newline +\xintFloatSqrt [89]{100}\newline +\xintFloatSqrt [89]{123456789}\par +\end{everbatim*} + +And now some tests to check that correct rounding applies correctly (sic): +\begin{everbatim*} +The argument has 16 digits, hence escapes initial rounding:\newline +\xintFloatSqrt {5625000075000001}\newline +This one gets rounded hence same value is computed:\newline +\xintFloatSqrt {5625000075000001.4}\newline +but actual value is more like:\newline +\xintFloatSqrt [24]{5625000075000001.4}\newline +\xintFloatSqrt [32]{5625000075000001.4}\newline +The argument has 48 digits, hence escapes initial rounding:\newline +\xintFloatSqrt [48]{562500000000000000000000750000000000000000000001}\newline +\xintFloatSqrt [64]{562500000000000000000000750000000000000000000001}\newline +\xintFloatSqrt [80]{562500000000000000000000750000000000000000000001}\newline +\end{everbatim*} +(we observe in passing illustrations that rounding to nearest is not +transitive.)\par + + + + + + +\subsection{\csh{xintFloatFac}}\label{xintFloatFac} + +\csa{xintFloatFac}|[P]{f}|\etype{{\upshape[\numx]}\Numf} returns the +factorial with either \csa{xinttheDigits} or |P| digits of precision. + + + +The exact theoretical value differs from the calculated one |Y| by an absolute +error strictly less than |0.6 ulp(Y)|. + +\begin{everbatim*} +$1000!\approx{}$\xintFloatFac [30]{1000} +\end{everbatim*} +The computation proceeds via doing explicitely the product, as +the Stirling formula cannot be used for lack so far of |exp/log|. + +The maximal allowed argument is $99999999$, but already $100000!$ currently +takes, for \dtt{16} digits of precision, a few seconds on my laptop (it +returns \dtt{2.824229407960348e456573}). + +The |factorial| function is available in \csbxint{floatexpr}: +\begin{everbatim*} +\xintthefloatexpr factorial(1000)\relax % same as 1000! +\end{everbatim*} + +\subsection{\csh{xintFloatBinomial}}\label{xintFloatBinomial} + +\csa{xintFloatBinomial}|[P]{x}{y}|\etype{{\upshape[\numx]}\Numf\Numf} computes +binomial coefficients with either \csa{xinttheDigits} or |P| digits of +precision. + +When |x<0| an out-of-range error is raised. Else if |y<0| or if |x<y| the +macro evaluates to \dtt{\xintFloatBinomial{1}{-1}}. +The exact theoretical value differs from the calculated one |Y| by an absolute +error strictly less than |0.6 ulp(Y)|. + +\begin{everbatim*} +${3000\choose 1500}\approx{}$\xintFloatBinomial [24]{3000}{1500} +\end{everbatim*} + +% \begin{everbatim*} +% ${9999\choose 5000}\approx{}$\xintFloatBinomial [24]{9999}{5000} +% \end{everbatim*} + +% 2015/11/28 +% 7.95895131766219474168799e3007 +% aparté: (testé avec Maple 16, 2015/11/28) +% > binomial (9999.,5000.); +% 3008 +% 0.795895131768 10 +% +% > Digits:=32; +% Digits := 32 +% +% > binomial (9999.,5000.); +% 3008 +% 0.795895131768 10 +% apparemment le binomial de Maple ne sait pas calculer avec plus de +% précision! +% et son dernier chiffre est faux! Pourtant GAMMA(9999.) fonctionne. Sauf si +% je n'ai pas compris quelque chose il me semble donc que le binomial de Maple +% est bogué...binomial(100.,50.); marche lui et binomial(4999.,2000.); aussi, +% bon clairement on a un bug de Maple ! oui binomial(8999.,5000.); ainsi que +% binomial(10999.,5000.); fonctionnent avec Digits:=32 mais **pas** +% binomial(9999.,5000.)... binomial(10000.,5000.); et binomial(9998.,5000.); +% sont OK. Est-ce qu'on gagne quelque chose pour un bug report ? +% > binomial(9999.,5000.); +% 3008 +% 0.795895131768 10 +% > binomial(10000.,5000.); +% 3009 +% 0.1591790263532438948337597273641521 10 +% > binomial(9998.,5000.); +% 3008 +% 0.3979077671466477799149739359402922 10 +% en plus je lui demande 32 chiffres et il m'en sort 34. + +The associated function in \csbxint{floatexpr} is \func{binomial}: +\begin{everbatim*} +\xintthefloatexpr binomial(3000,1500)\relax +\end{everbatim*} + +The computation is based on the formula |(x-y+1)...x/y!| (here one arranges +|y<=x-y| naturally). + + +\subsection{\csh{xintFloatPFactorial}}\label{xintFloatPFactorial} + +\csa{xintFloatPFactorial}|[P]{x}{y}|\etype{{\upshape[\numx]}\Numf\Numf} +computes the product |(x+1)...y|. + + + + +The arguments must be integers (they are expanded inside |\numexpr|) +and the allowed range is $-100000000\leqslant x, y\leqslant99999999$. If +$x\geqslant y$ the product is considered empty hence returns one (as a +floating point value). +See also \csbxint{iiPFactorial}. + + +The exact theoretical value differs from the calculated one |Y| by an absolute +error strictly less than |0.6 ulp(Y)|. + +The associated function in \csbxint{floatexpr} is \func{pfactorial}: +\begin{everbatim*} +\xintthefloatexpr pfactorial(2500,5000)\relax +\end{everbatim*} + +\xintDigits:=16; + +\subsection{\csh{xintFrac}}\label{xintFrac} + +This is a \LaTeX{} only macro,\etype{\Ff} to be used in math mode only. It +will print a fraction, internally represented as something equivalent to +|A/B[n]| as |\frac {A}{B}10^n|. The power of ten is omitted when |n=0|, the +denominator is omitted when it has value one, the number being separated from +the power of ten by a |\cdot|. |$\xintFrac {178.000/25600000}$| gives $\xintFrac +{178.000/25600000}$, |$\xintFrac {178.000/1}$| gives $\xintFrac {178.000/1}$, +|$\xintFrac {3.5/5.7}$| gives $\xintFrac {3.5/5.7}$, and |$\xintFrac {\xintNum + {\xintiiFac{10}/|\allowbreak|\xintiiSqr{\xintiiFac {5}}}}$| gives $\xintFrac +{\xintNum {\xintiiFac{10}/\xintiiSqr{\xintiiFac {5}}}}$. As shown by the examples, +simplification of the input (apart from removing the decimal points and moving +the minus sign to the numerator) is not done automatically and must be the +result of macros such as |\xintIrr|, |\xintREZ|, or |\xintNum| (for fractions +being in fact integers.) + +\subsection{\csh{xintSignedFrac}}\label{xintSignedFrac} + + +This is as \csbxint{Frac}\etype{\Ff} except that a negative fraction has the +sign put in front, not in the numerator. +\begin{everbatim*} +\[\xintFrac{-355/113}=\xintSignedFrac {-355/113}\] +\end{everbatim*} + +\subsection{\csh{xintFwOver}}\label{xintFwOver} + +This does the same as \csa{xintFrac}\etype{\Ff} except that the \csa{over} +primitive is used for the fraction (in case the denominator is not one; and a +pair of braces contains the |A\over B| part). |$\xintFwOver {178.000/25600000}$| +gives $\xintFwOver {178.000/25600000}$, |$\xintFwOver {178.000/1}$| gives +$\xintFwOver {178.000/1}$, |$\xintFwOver {3.5/5.7}$| gives $\xintFwOver +{3.5/5.7}$, and |$\xintFwOver {\xintNum {\xintiiFac{10}/\xintiiSqr{\xintiiFac + {5}}}}$| gives $\xintFwOver {\xintNum {\xintiiFac{10}/\xintiiSqr{\xintiiFac + {5}}}}$. + +\subsection{\csh{xintSignedFwOver}}\label{xintSignedFwOver} + +This is as \csbxint{FwOver}\etype{\Ff} except that a negative fraction has the +sign put in front, not in the numerator. +\begin{everbatim*} +\[\xintFwOver{-355/113}=\xintSignedFwOver {-355/113}\] +\end{everbatim*} + +\subsection{\csh{xintLen}}\label{xintLenFrac} + +The original \csbxint{Len} macro\etype{\Ff} is extended to accept a fraction +on input: the length of |A/B[n]| is the length of |A| plus the length of |B| +plus the absolute value of |n| and minus one (an integer input as |N| is +internally represented in a form equivalent to |N/1[0]| so the minus one means +that the extended \csa{xintLen} behaves the same as the original for +integers). +\begin{everbatim*} +\xintLen{201710/298219}=\xintLen{201710}+\xintLen{298219}-1\newline +\xintLen{1234/1}=\xintLen{1234}=\xintLen{1234[0]}=\xintiLen{1234}\newline +\xintLen{-1e3/5.425} (\xintRaw {-1e3/5.425})\par +\end{everbatim*} +The length is computed on the |A/B[n]| which would have been returned by +\csbxint{Raw}, as illustrated by the last example above. + +|\xintLen| is only for use with such (scientific) numbers or fractions. See +also \csbxint{NthElt} from \xinttoolsname. See also \csbxint{Length} (which +however does not expand its argument) from \xintkernelname for counting more +general tokens (or rather braced items). + +\clearpage +\let\xintfracnameUp\undefined +\csname xintexprnameUp\endcsname +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} +\section{Macros of the \xintexprname package}% +\RaisedLabel{sec:expr} + +\localtableofcontents + +The \xintexprname package was first released with version |1.07| +(|2013/05/25|) of the \xintname bundle. It was substantially enhanced with +release |1.1| from |2014/10/28|. + +The package loads automatically \xintfracname and \xinttoolsname. +\begin{itemize} +\item |1.3d| adds \csbxint{eval}, \csbxint{ieval}, \csbxint{iieval}, + \csbxint{floateval}.\NewWith{1.3d} +\item for the \func{gcd} and \func{lcm} functions, it is NOT necessary anymore + to + load package \xintgcdname. And they now work not only with integers:\NewWith{1.3d} +\begin{everbatim*} +\xinttheiiexpr lcm (2^5*7*13^10*17^5,2^3*13^15*19^3,7^3*13*23^2)\relax\newline +\end{everbatim*}% +but also with fractions:\IMPORTANT +\begin{everbatim*} +\xinttheexpr lcm(7/300, 11/150, 13/60), gcd(7/300, 11/150, 13/60)\relax\par +\end{everbatim*} +\item for allowing hexadecimal (uppercase letters only) input, it is \emph{necessary} + to load package \xintbinhexname.\IMPORTANT + \begin{everbatim*} +\xinttheexpr "A*"B*"C*"D*"D*"F, "FF.FF, reduce("FF.FFF + 16^-3)\relax +\end{everbatim*} +\end{itemize} + +Please refer to \autoref{sec:xintexprsyntax} for a more detailed description +of some syntax elements. + +\subsection{The \csh{xintexpr} expressions} +\label{xintexpr} +\label{xinttheexpr} +\label{thexintexpr} +\label{xintthe} + +An \xintexprname{}ession is a construct +\csbxint{expr}\meta{expandable\_expression}|\relax|\etype{x} where the +expandable expression is read and completely expanded from left to right. + +An |\xintexpr...\relax| \emph{must} end in a |\relax| (which will be absorbed). +Like a |\numexpr| expression, it is not printable as is, nor can it be directly +employed as argument to the other package macros. For this one must use one +of the three equivalent forms: +\begin{itemize} +\item \csb{thexintexpr}\meta{expandable\_expression}|\relax|\etype{x}, or +\item \csb{xinttheexpr}\meta{expandable\_expression}|\relax|\etype{x}, or +\item \csb{xintthe}|\xintexpr|\meta{expandable\_expression}|\relax|.\etype{x} +\end{itemize} + +The computations are done \emph{exactly}, and with no simplification of the +result. See \csbxint{floatexpr} for a similar parser which rounds each +operation inside the expression to \csbxint{theDigits} digits of precision. + +As an alternative and equivalent syntax to +\begin{everbatim} +\xintexpr round(<expression>, D)\relax +\end{everbatim} +there is\footnote{For truncation rather than rounding, one uses +|\xintexpr trunc(<expression>, D)\relax|.} +\begin{everbatim} +\xintiexpr [D] <expression> \relax +\end{everbatim} +The parameter |D| must be zero or positive.\footnote{|D=0| + corresponds to using |round(<expression>)| not |round(<expression>,0)| which + would leave a trailing dot. Same for |trunc|. There is also function |float| + for floating point rounding to \csbxint{theDigits} or the given number of + significant digits as second argument.} Perhaps some future version will +give a meaning to using a negative |D|.\footnote{Thanks to KT for this + suggestion. Sorry for the delay in implementing it... matter of formatting + the output and corresponding choice of user interface are still in need of + some additional thinking.} + +\begin{itemize} +\item the expression may contain arbitrarily many levels of nested parenthesized + sub-expressions, +\item the expression may contain explicitely or from a macro expansion a + sub-expression |\xintexpr...\relax|, which itself may contain a + sub-expressions etc\dots +\item to let sub-contents evaluate as a sub-unit it should thus be either + \begin{enumerate} + \item parenthesized, + \item or a sub-expression |\xintexpr...\relax|. + \end{enumerate} + \item to use an expression as argument to the other package macros, + or more generally to macros which expand their arguments, one must use the + |\xinttheexpr...\relax| or |\xintthe\xintexpr...\relax| forms. + \item similarly, + printing the result itself must be done with these forms. + \item one should not use |\xinttheexpr...\relax| as a sub-constituent of an + |\xintexpr...\relax| but only the + |\xintexpr...\relax| form which is more efficient in this context. + \item each \xintexprname{}ession, whether prefixed or not with |\xintthe|, is + completely expandable and obtains its result in two expansion steps. +\end{itemize} + +See \autoref{sec:xintexprsyntax} for the primary information on built-in +operators and functions. This section now adds some complementary information. + + +\begin{itemize}[parsep=0pt, labelwidth=\leftmarginii, + itemindent=0pt, listparindent=\leftmarginiii, leftmargin=\leftmarginii] +\item An expression is built the standard way with opening and closing + parentheses, infix operators, and (big) numbers, with possibly a fractional + part, and/or scientific notation (except for \csbxint{iiexpr} which only + admits big integers). All variants work with comma separated expressions. On + output each comma will be followed by a space. A decimal number must have + digits either before or after the decimal mark. + +\item As everything gets expanded, the characters |.|, |+|, |-|, |*|, |/|, |^|, + |!|, |&|, \verb+|+, |?|, |:|, |<|, |>|, |=|, |(|, |)|, |"|, |]|, |[|, |@| + and the comma |,| should not (if used in the expression) be active. For + example, the French language in |Babel| system, for pdf\LaTeX, activates |!|, + |?|, |;| and |:|. Turn off the activity before expressions using such characters. + + Alternatively the macro \csbxint{exprSafeCatcodes} resets all + characters potentially needed by \csbxint{expr} to their standard catcodes + and \csbxint{exprRestoreCatcodes} restores the former status. + +\item Count registers and |\numexpr|-essions are accepted (LaTeX{}'s counters + can be inserted using |\value|) natively without |\the| or |\number| as + prefix. Also dimen registers and control sequences, skip registers and + control sequences (\LaTeX{}'s lengths), |\dimexpr|-essions, + |\glueexpr|-essions are automatically unpacked using |\number|, discarding + the stretch and shrink components and giving the dimension value in |sp| + units ($1/65536$th of a \TeX{} point). Furthermore, tacit multiplication is + implied, when the (count or dimen or glue) register or variable, or the + (|\numexpr| or |\dimexpr| or |\glueexpr|) expression is immediately prefixed + by a (decimal) number. See \autoref{ssec:tacit multiplication} for the complete rules + of tacit multiplication.\IMPORTANT + +\item With a macro |\x| defined like this: + % + \leftedline{|\def\x {\xintexpr \a + \b \relax}| or |\edef\x {\xintexpr + \a+\b\relax}|} + % + one may then do |\xintthe\x|, either for printing the result on the page or + to use it in some other macros expanding their arguments. The |\edef| does + the computation immediately but keeps it in an internal private format. + Naturally, the |\edef| is only possible if |\a| and |\b| are already + defined. With both approaches the |\x| can be inserted in other expressions, + as for example (assuming naturally as we use an |\edef| that in the + `yet-to-be computed' case the |\a| and |\b| now have some suitable meaning): + % + \leftedline {|\edef\y {\xintexpr \x^3\relax}|} + +\item There is also \csbxint{boolexpr}| ... \relax| and + \csbxint{theboolexpr}| ... \relax|. Same as |\xintexpr| with the final + result converted to $1$ if it is not zero. + +\item See also + \csbxint{ifboolexpr} (\autoref{xintifboolexpr}) and the + \func{bool} and \func{togl} functions + in \autoref{sec:expr}. Here is an example: +\catcode`| 12 % +\begin{everbatim*} +\xintNewBoolExpr \AssertionA[3]{ #1 && (#2||#3) } +\xintNewBoolExpr \AssertionB[3]{ #1 || (#2&) } +\xintNewBoolExpr \AssertionC[3]{ xor(#1,#2,#3) } +{\centering\normalcolor\xintFor #1 in {0,1} \do {% + \xintFor #2 in {0,1} \do {% + \xintFor #3 in {0,1} \do {% + #1 AND (#2 OR #3) is \textcolor[named]{OrangeRed}{\AssertionA {#1}{#2}{#3}}\hfil + #1 OR (#2 AND #3) is \textcolor[named]{OrangeRed}{\AssertionB {#1}{#2}{#3}}\hfil + #1 XOR #2 XOR #3 is \textcolor[named]{OrangeRed}{\AssertionC {#1}{#2}{#3}}\\}}}} +\end{everbatim*}\catcode`| 13 + + This example used for efficiency \csbxint{NewBoolExpr}. See also the + \autoref{xintNewExpr}. + +\item See also \csbxint{ifsgnexpr}. + +\item There is \csbxint{floatexpr}| ... \relax| where the algebra is done + in floating point approximation (also for each intermediate result). Use the + syntax |\xintDigits:=N;| to set the precision. Default: $16$ digits. + % + \leftedline{|\xintthefloatexpr 2^100000\relax:| \dtt{\xintthefloatexpr + 2^100000\relax }} + % + The square-root operation can be used in |\xintexpr|, it is computed + as a float with the precision set by |\xintDigits| or by the optional + second argument: + % +\begin{everbatim*} +\xinttheexpr sqrt(2,60)\relax\newline +Here the [60] is to avoid truncation to |\xinttheDigits| of precision on output.\newline +\printnumber{\xintthefloatexpr [60] sqrt(2,60)\relax} +\end{everbatim*} + + Floats are quickly indispensable when using the power function , as exact + results will easily have hundreds, if not thousands, of digits. + % +\begin{everbatim*} +\xintDigits:=48;\xintthefloatexpr 2^100000\relax +\end{everbatim*} + + Only integer and (in |\xintfloatexpr...\relax|) half-integer exponents are + allowed. + +\item if one uses \emph{macros} within |\xintexpr..\relax| one should + obviously take into account that the parser will \emph{not} see the macro + arguments, hence once cannot use the syntax there, except if the arguments + are themselves wrapped as |\xinttheexpr...\relax| and assuming the macro + \fexpan ds these arguments. +\end{itemize} + + +\subsection{\texorpdfstring{\texttt{\protect\string\numexpr}}{\textbackslash + numexpr} or \texorpdfstring{\texttt{\protect\string\dimexpr}}{\textbackslash + dimexpr} expressions, count and dimension registers and variables} +\label{ssec:countinexpr} + +Count registers, count control sequences, dimen registers, dimen control +sequences (like |\parindent|), skips and skip control sequences, |\numexpr|, +|\dimexpr|, |\glueexpr|, |\fontdimen| can be inserted directly, they will be +unpacked using |\number| which gives the internal value in terms of scaled +points for the dimensional variables: $1$\,|pt|${}=65536$\,|sp| (stretch and +shrink components are thus discarded). + +Tacit multiplication (see \autoref{ssec:tacit multiplication}) is implied, +when a number or decimal number prefixes such a register or control sequence. +\LaTeX{} lengths are skip control sequences and \LaTeX{} counters should be +inserted using |\value|. + +Release |1.2| of the |\xintexpr| parser also recognizes and prefixes with +|\number| the |\ht|, |\dp|, and |\wd| \TeX{} primitives as well as the +|\fontcharht|, |\fontcharwd|, |\fontchardp| and |\fontcharic| \eTeX{} +primitives. + +In the case of numbered registers like |\count255| or |\dimen0| (or |\ht0|), +the resulting digits will be re-parsed, so for example |\count255 0| is like +|100| if |\the\count255| would give |10|. The same happens with inputs such +as |\fontdimen6\font|. And |\numexpr 35+52\relax| will be exactly as if |87| +as been encountered by the parser, thus more digits may follow: |\numexpr +35+52\relax 000| is like |87000|. If a new |\numexpr| follows, it is treated +as what would happen when |\xintexpr| scans a number and finds a non-digit: it +does a tacit multiplication. +\begin{everbatim*} +\xinttheexpr \numexpr 351+877\relax\numexpr 1000-125\relax\relax{} is the same +as \xinttheexpr 1228*875\relax. +\end{everbatim*} + +Control sequences however (such as |\parindent|) are picked up as a whole by +|\xintexpr|, and the numbers they define cannot be extended extra digits, a +syntax error is raised if the parser finds digits rather than a legal +operation after such a control sequence. + +A token list variable must be prefixed by |\the|, it will not be unpacked +automatically (the parser will actually try |\number|, and thus fail). Do not +use |\the| but only |\number| with a dimen or skip, as the |\xintexpr| parser +doesn't understand |pt| and its presence is a syntax error. To use a dimension +expressed in terms of points or other \TeX{} recognized units, incorporate it in +|\dimexpr...\relax|. + +Regarding how dimensional expressions are converted by \TeX{} into scaled points +see also \autoref{sec:Dimensions}. + +\subsection{Catcodes and spaces} + +Active characters may (and will) break the functioning of \csbxint{expr}. +Inside an expression one may prefix, for example a |:| with |\string|. Or, for +a more radical way, there is \csbxint{exprSafeCatcodes}. This is a +non-expandable step as it changes catcodes. + +\subsubsection{\csh{xintexprSafeCatcodes}} +\label{xintexprSafeCatcodes} + +This macro sets the catcodes of many characters to safe values. This is used +internally by \csbxint{NewExpr} (restoring the catcodes on exit), hence it +does not have to be protected against active characters when used at +top-level. + +Also \csbxint{defvar}, \csbxint{deffunc}, ..., use it before fetching their +semi-colon delimited arguments, so they can be used (also in the document +body) for example with Babel+French which makes the semi-colon active in the +(\LaTeX) document body.\CHANGED{1.3c} + +As \csbxint{NewExpr} and \csbxint{deffunc} and variants use internally some +|\scantokens|, they will (reasonably) succeed in sanitizing catcodes in the +expressions, even if all is from the replacement text of some macro whose +definition was done under some special catcode regime. + +But \csbxint{deffunc}, \csbxint{defvar} and variants need the (catcode other) +semi-colon as delimiter. Thus make sure the semi-colon has its normal catcode +when using \csbxint{deffunc} inside some macro definition. + +The macros \csbxint{deffunc} and variants ignore completely the colon in |:=| +(which furthermore is optional) so it can have any (reasonable) frozen catcode. + +The macros \csbxint{defvar} and variants are also compatible with any +reasonable frozen catcode of the colon |:| in |:=|, and the colon presence is +only optional.\NewWith{1.3c} + +\begin{framed} + It is important to ALWAYS shortly let \csbxint{exprSafeCatcodes} be followed + by \csbxint{exprRestoreCatcodes}.\IMPORTANTf{} If one uses twice + \csbxint{exprSafeCatcodes} then the next \csbxint{exprRestoreCatcodes} will + restore the ancien catcode regime at time of the first one. +\end{framed} + +\subsubsection{\csh{xintexprRestoreCatcodes}} +\label{xintexprRestoreCatcodes} + +Restores the catcodes to the earlier state. More precisely, +\csbxint{exprSafeCatcodes} sets a toggle (with local scope). If the toggle is +set already it does not restore the current catcodes. The next +\csa{xintexprRestoreCatcodes} unsets the toggle.\CHANGED{1.3c} +So, in case of nesting, the +catcodes are restored to what they were when the \emph{first} un-paired +\csbxint{exprSafeCatcodes} got executed. + +\bigskip + +Spaces inside an |\xinttheexpr...\relax| should mostly be +innocuous (except inside macro arguments). + +|\xintexpr| and |\xinttheexpr| are for the most part agnostic regarding +catcodes: (unbraced) digits, binary operators, minus and plus signs as +prefixes, dot as decimal mark, parentheses, may be indifferently of catcode +letter or other or subscript or superscript, ..., it doesn't matter.% +% +\footnote{Furthermore, although \csbxint{expr} uses \csa{string}, it is + escape-char agnostic. It should work with any \csa{escapechar} setting + including -1.} + +The characters |+|, |-|, |*|, |/|, |^|, |!|, |&|, \verb+|+, |?|, |:|, |<|, |>|, +|=|, |(|, |)|, |"|, |[|, |]|, |;|, the dot and the comma should not be active if +in the expression, as everything is expanded along the way. If one of them is +active, it should be prefixed with |\string|. + +The exclamation mark |!| should have its standard catcode: with catcode letter +it is used internally and hence will confuse the parsers if it comes from the +expression. + +Digits, slash, square brackets, minus sign, in the output from an +|\xinttheexpr| are all of catcode 12. For |\xintthefloatexpr| the `e' in the +output has its standard catcode ``letter''. + +A macro with arguments will expand and grab its arguments before the +parser may get a chance to see them, so the situation with catcodes and spaces +is not the same within such macro arguments. + + + +\subsection{Expandability, \csh{xintexpro}} + +As is the case with all other package macros |\xintexpr| \fexpan ds (in two +steps) to its final (non-printable) result; and |\xinttheexpr| \fexpan ds (in +two steps) to the chain of digits (and possibly minus sign |-|, decimal mark +|.|, fraction slash |/|, scientific |e|, square brackets |[|, |]|) representing +the result. + +Starting with |1.09j|, an |\xintexpr..\relax| can be inserted without +|\xintthe| prefix inside an |\edef|, or a |\write|. It expands to a private +more compact representation (five tokens) than |\xinttheexpr| or +|\xintthe\xintexpr|. + +The material between |\xintexpr| and |\relax| should contain only expandable +material. + +The once expanded |\xintexpr| is |\romannumeral0\xintexpro|.\CHANGED{1.3d} +\centeredline{ATTENTION! Prior to |1.3d| the |\xintexpro| macro was named + |\xinteval|.} +But \csbxint{eval} is now something else. And there +is similarly |\xintiexpro| (formerly |\xintieval|), |\xintiiexpro| (formerly +|\xintiieval|), and |\xintfloatexpro| (formerly |\xintfloateval|). For an +example see \autoref{ssec:fibonacci}. + +An expression can only be legally finished by a |\relax| token, which +will be absorbed. + +It is quite possible to nest expressions among themselves; for example, if one +needs inside an |\xintiiexpr...\relax| to do some computations with fractions, +rounding the final result to an integer, one just has to insert +|\xintiexpr...\relax|. The functioning of the infix operators will not be in +the least affected from the fact that the surrounding ``environment'' is the +|\xintiiexpr| one. + +\subsection{Memory considerations} +\label{ssec:memory} + +The parser creates an undefined control sequence for each intermediate +computation evaluation: addition, subtraction, etc\dots Thus, a moderately sized +expression might create 10, or 20 such control sequences. On my \TeX{} +installation, the memory available for such things is of circa \np{200000} +multi-letter control words. So this means that a document containing hundreds, +perhaps even thousands of expressions will compile with no problem. + +Besides the hash table, also \TeX{} main memory is impacted. Thus, if +\xintexprname is used for computing plots% +% +\footnote{this is not very probable as so far \xintname does not include + a mathematical library with floating point calculations, but provides + only the basic operations of algebra.}% +% +, this may cause a problem. In my testing and with current |TL2015| memory +settings, I ran into problems after doing about \emph{ten thousand} +evaluations (for example |(#1+#2)*#3-#1*#3-#2*#3)|) each with number having +\emph{hundreds} of digits. Typical error message can be: +\begin{everbatim} +./testaleatoires.tex:243: TeX capacity exceeded, sorry [pool size=6134970]. +<argument> ...19140037877484848545931233090884903 +\end{everbatim} + +There is a (partial) solution.% +% +\footnote{which convinced me that I could stick with the parser + implementation despite its potential impact on the hash-table and + other parts of \TeX{}'s memory.} + +A document can possibly do tens of thousands of evaluations only if some +identical formulae are being used repeatedly, with varying arguments (from +previous computations possibly) or coming from data being fetched from a file. +Most certainly, there will be a a few dozens formulae at most, but they will +be used again and again with varying inputs. + +With the \csbxint{NewExpr} macro, it is possible to convert once and +for all an expression containing parameters into an expandable macro +with parameters. Only this initial definition of this macro actually +activates the \csbxint{expr} parser and will (very moderately) impact +the hash-table: once this unique parsing is done, a macro with +parameters is produced which is built-up recursively from the +\csbxint{Add}, \csbxint{Mul}, etc... macros, exactly as it would be +necessary to do without the facilities of the \xintexprname package. + +Notice that since |1.2c| the \csbxint{deffunc} construct allows an alternative +to \csa{xintNewExpr} whose syntax uses arbitrary letters rather than macro +parameters |#1|, |#2|, ..., |#9|. The declared function must still be used +inside an expression, but its use will need only as many |\csname|'s as were +needed for the function arguments plus one more for encapsulating the function +result. + +\subsection{\csh{xintiexpr}, \csh{xinttheiexpr}} +\label{xintiexpr}\label{xinttheiexpr}\label{thexintiexpr} + +Equivalent\etype{x} to doing |\xintexpr round(...)\relax| (more precisely, +|round| is applied to each one of the evaluated values, if the expression was +comma separated). Thus, only the \emph{final result value} is rounded to an +integer. Half integers are rounded towards $+\infty$ for positive numbers and +towards $-\infty$ for negative ones. + +An optional parameter |d>0| within brackets, immediately after |\xintiexpr| +is allowed: it instructs the expression to do its final rounding to the +nearest value with that many digits after the decimal mark, \emph{i.e.}, +|\xintiexpr [d] <expression>\relax| is equivalent (in case of a single +expression) to |\xintexpr round(<expression>, d)\relax|. + +|\xintiexpr [0] ...| is the same as |\xintiexpr ...|.\footnote{Incidentally + using |round(...,0)| in place of |round(...)| in |\xintexpr| would leave a + trailing dot in the produced value.} + +If truncation rather than rounding is needed use (in case of a single +expression, naturally) |\xintexpr trunc(...)\relax| for truncation to an +integer or |\xintexpr trunc(...,d)\relax| for truncation to a decimal number +with |d>0| digits after the decimal mark. + +Perhaps in the future some meaning will be given to using negative value for +the optional parameter |d|.\footnote{Thanks to KT for this suggestion.} + +|\thexintiexpr| is synonym to |\xinttheiexpr|. + +\subsection{\csh{xintiiexpr}, \csh{xinttheiiexpr}} +\label{xintiiexpr}\label{xinttheiiexpr}\label{thexintiiexpr} + +This variant\etype{x} does not know fractions. It deals almost only with long +integers. Comma separated lists of expressions are allowed. + +\begin{framed} + It maps |/| to the \emph{rounded} quotient. The operator + |//| is, like in |\xintexpr...\relax|, mapped to \emph{truncated} division. + The Euclidean quotient (which for positive operands is like the truncated + quotient) was, prior to release |1.1|, associated to |/|. The function + |quo(a,b)| can still be employed. +\end{framed} + +The \csbxint{iiexpr}-essions use the `ii' macros for addition, subtraction, +multiplication, power, square, sums, products, Euclidean quotient and +remainder. + +The |round|, |trunc|, |floor|, |ceil| functions are still available, and are +about the only places where fractions can be used, but |/| within, if not +somehow hidden will be executed as integer rounded division. To avoid this one +can wrap the input in \dtt{qfrac}: this means however that none of the normal +expression parsing will be executed on the argument. + +To understand the illustrative examples, recall that |round| and |trunc| have +a second (non negative) optional argument. In a normal \csbxint{expr}-essions, +|round| and |trunc| are mapped to \csbxint{Round} and \csbxint{Trunc}, in +\csbxint{iiexpr}-essions, they are mapped to \csbxint{iRound} and +\csbxint{iTrunc}. + + +\begin{everbatim*} +\xinttheiiexpr 5/3, round(5/3,3), trunc(5/3,3), trunc(\xintDiv {5}{3},3), +trunc(\xintRaw {5/3},3)\relax{} are problematic, but +% +\xinttheiiexpr 5/3, round(qfrac(5/3),3), trunc(qfrac(5/3),3), floor(qfrac(5/3)), +ceil(qfrac(5/3))\relax{} work! +\end{everbatim*} + +On the other hand decimal numbers and scientific numbers can be used directly +as arguments to the |num|, |round|, or any function producing an integer. + +\begin{framed} + Scientific numbers will be + represented with as many zeroes as necessary, thus one does not want to + insert \dtt{num(1e100000)} for example in an \csa{xintiiexpr}ession ! +\end{framed} + +% +\begin{everbatim*} +\xinttheiiexpr num(13.4567e3)+num(10000123e-3)\relax % should (num truncates) compute 13456+10000 +\end{everbatim*} +% + +The |reduce| function is not available and will raise un error. The |frac| +function also. The |sqrt| function is mapped to \csbxint{iiSqrt} which gives +a truncated square root. The |sqrtr| function is mapped to \csbxint{iiSqrtR} +which gives a rounded square root. + +One can use the Float macros if one is careful to use |num|, or |round| +etc\dots on their output. + +\begin{everbatim*} +\xinttheiiexpr \xintFloatSqrt [20]{2}, \xintFloatSqrt [20]{3}\relax % no operations + +\noindent The next example requires the |round|, and one could not put the |+| inside it: + +\xinttheiiexpr round(\xintFloatSqrt [20]{2},19)+round(\xintFloatSqrt [20]{3},19)\relax + +(the second argument of |round| and |trunc| tells how many digits from after the +decimal mark one should keep.) +\end{everbatim*} + +The whole point of \csbxint{iiexpr} is to gain some speed in +\emph{integer-only} algorithms, and the above explanations related to how to +nevertheless use fractions therein are a bit peripheral. We observed +(2013/12/18) of the order of $30$\% speed gain when dealing with numbers with +circa one hundred digits (1.2: this info may be obsolete). + + +|\thexintiiexpr| is synonym to |\xinttheiiexpr|. + +\subsection{\csh{xintboolexpr}, + \csh{xinttheboolexpr}} +\label{xintboolexpr}\label{xinttheboolexpr}\label{thexintboolexpr} + + +Equivalent\etype{x} to doing |\xintexpr ...\relax| and returning $1$ if the +result does not vanish, and $0$ is the result is zero. As |\xintexpr|, this +can be used on comma separated lists of expressions, and will return a +comma separated list of $0$'s and $1$'s. + +|\thexintboolexpr| is synonym to |\xinttheboolexpr|. + +There is slight quirk in case it is used as a sub-expression: the boolean +expression needs at least one logic operation else the value is not +standardized to |1| or |0|, for example we get from +\begin{everbatim*} +\xinttheexpr \xintboolexpr 1.23\relax\relax\newline +\end{everbatim*}which is to be compared with +\begin{everbatim*} +\xinttheboolexpr 1.23\relax +\end{everbatim*} + +A related issue existed with +|\xinttheexpr \xintiexpr 1.23\relax\relax|, which was fixed with |1.1| +release, and I decided back then not to add the needed overhead also to the +|\xintboolexpr| context, as one only needs to use |?(1.23)| for example or +involve the |1.23| in any logic operation like |1.23 'and' 3.45|, or involve +the |\xintboolexpr ..\relax | itself with any logical operation, contrarily to +the sub-|\xintiexpr| case where |\xinttheexpr 1+\xintiexpr 1.23\relax\relax| +did behave contrarily to expectations until |1.1|. + + +\subsection{\csh{xintfloatexpr}, + \csh{xintthefloatexpr}} +\label{xintfloatexpr}\label{xintthefloatexpr}\label{thexintfloatexpr} + +\csbxint{floatexpr}|...\relax|\etype{x} is exactly like |\xintexpr...\relax| +but with the four binary operations and the power function are mapped to +\csa{xintFloatAdd}, \csa{xintFloatSub}, \csa{xintFloatMul}, \csa{xintFloatDiv} +and \csa{xintFloatPower}, respectively.\footnote{Since |1.2f| the \string^ + handles half-integer exponents, contrarily to \csa{xintFloatPower}.} + +The target precision for the computation is from the +current setting of |\xintDigits|. Comma separated lists of expressions are +allowed. + +An optional parameter within brackets is allowed: +\begin{itemize} +\item if positive it instructs the macro to round the result to that many + digits of precision. It thus makes sense to employ it only if this parameter is + less than the \csbxint{theDigits} precision. +\item if negative it means to trim off that many digits (of course, rounding + the value).\NewWith{1.3e} Don't use it to trim all digits (or more than all)! +\end{itemize} + +Since |1.2f| all float operations first round their arguments; a parsed number +is not rounded prior to its use as operand to such a float operation. + +|\thexintfloatexpr| is synonym to |\xintthefloatexpr|. + +|\xintDigits:=36;|\xintDigits:=36; +% +\leftedline{|\xintthefloatexpr + (1/13+1/121)*(1/179-1/173)/(1/19-1/18)\relax|} +% +\leftedline{\dtt{\xintthefloatexpr + (1/13+1/121)*(1/179-1/173)/(1/19-1/18)\relax}} +% 0.00564487459334466559166166079096852897 +% +\leftedline{|\xintthefloatexpr\xintexpr + (1/13+1/121)*(1/179-1/173)/(1/19-1/18)\relax\relax|} +% +\leftedline{\dtt{\xintthefloatexpr\xintexpr + (1/13+1/121)*(1/179-1/173)/(1/19-1/18)\relax\relax}} + +\xintDigits := 16; + +The latter is the rounding of the exact result. The former one has +its last three digits wrong due to the cumulative effect of rounding errors +in the intermediate computations, as compared to exact evaluations. + + + + +I recall here from \autoref{ssec:floatingpoint} that with release |1.2f| the +float macros for addition, subtraction, multiplication and division round +their arguments first to |P| significant places with |P| the asked-for +precision of the output; and similarly the power macros and the +square root macro. This does not modify anything for computations with +arguments having at most |P| significant places already. + +\subsection{\csh{xinteval}, \csh{xintieval}, \csh{xintiieval}, + \csh{xintfloateval}} +\label{xinteval}\label{xintieval}\label{xintiieval}\label{xintfloateval} + +\begin{framed} + Prior to |1.3d|,\NewWithf{1.3d} these macros existed but with a different meaning: they + arose in the once-expanded \csbxint{expr}, etc..., i.e. one had: +\begin{everbatim} +\def\xintexpr{\romannumeral0\xinteval} +\end{everbatim} + The\IMPORTANTf\ old macros were renamed into \csa{xintexpro}, etc..., in order to free + their names for new meanings, more alike what one finds in + other math packages. +\end{framed} + +\csbxint{eval}\etype{x} is an \fexpan dable macro which is basically defined +like this: +\begin{everbatim} +\def\xinteval#1{\romannumeral-`0\xinttheexpr#1\relax} +\end{everbatim} +thus expands in two steps (its exact definition differs from the one given +above in order to achieve a slight optimization). +\begin{everbatim*} +\xinteval{add(x^2, x = 100..110), add(x^3, x = 100..110)} +\end{everbatim*} + +\csbxint{ieval}\etype{x} is similarly related to \csbxint{theiexpr}. Its optional +argument must be located inside the braces: +\begin{everbatim*} +\xintieval{[7] 355/113} +\end{everbatim*} + +\csbxint{iieval}\etype{x} is similarly related to \csbxint{theiiexpr}. +\begin{everbatim*} +\xintiieval{add(x^2, x = 100..110), add(x^3, x = 100..110)} +\end{everbatim*} + +\csbxint{floateval}\etype{x} is similarly related to \csbxint{thefloatexpr}. Its optional +argument must be located inside the braces: +\begin{everbatim*} +\xintfloateval{[7] 355/113} +\end{everbatim*} + +When negative it tells how many digits to remove from the prevailing precision +(\csbxint{theDigits}):\NewWith{1.3e} +\begin{everbatim*} +\xintfloateval{[-2] 355/113} has \xinttheDigits\ minus 2 digits. +\end{everbatim*} + +These macros are useful when one uses some extra wrapper doing some parsing of +its input, like the |\num| macro of +\href{http://ctan.org/pkg/siunitx}{siunitx}, which would choke on some of the +syntax elements allowed inside \csb{xintexpr}|...\relax| (for example +brackets). +As shown in the above examples, these macros, like the underlying parsers +accept arbitrarily many comma separated expressions. + + +\subsection{Using an expression parser within another one} + +This was already illustrated before. In the following: +\begin{everbatim*} +\xintthefloatexpr \xintexpr add(1/i, i=1234..1243)\relax ^100\relax +\end{everbatim*}, +the inner sum is computed exactly. Then it will be rounded to |\xinttheDigits| +significant digits, and then its power will be evaluated as a float operation. +One should avoid the "|\xintthe|" parsers in inner positions as this induces +digit by digit parsing of the inner computation result by the outer parser. +Here is the same computation done with floats all the way: +\begin{everbatim*} +\xintthefloatexpr add(1/i, i=1234..1243)^100\relax +\end{everbatim*} + +Not surprisingly this differs from the previous one which was exact until +raising to the |100|th power. + +The fact that the inner expression occurs inside a bigger one has nil +influence on its behaviour. There is the limitation though that the outputs +from \csbxint{expr} and \csbxint{floatexpr} can not be used directly in +\csbxint{theiiexpr} integer-only parser. But one can do: +\begin{everbatim*} +\xinttheiiexpr round(\xintfloatexpr 3.14^10\relax)\relax % or trunc +\end{everbatim*} + + +\subsection{The \csh{xintthecoords} macro} +\label{xintthecoords} + +It converts a comma separated list into the format for list of coordinates as +expected by the |TikZ| |coordinates| syntax.% +% +\footnote{The implementation had to work around the +problem that |TikZ| seemingly allows only a maximal number of about one +hundred expansion steps for the list to be entirely produced.}% +% +\begin{everbatim*} +\begin{figure}[htbp] +\centering\begin{tikzpicture}[scale=10]\xintDigits:=8; + \clip (-1.1,-.25) rectangle (.3,.25); + \draw [blue] (-1.1,0)--(1,0); + \draw [blue] (0,-1)--(0,+1); + \draw [red] plot[smooth] coordinates {% + \xintthecoords % (converts what is next into (x1, y1) (x2, y2)... format) + \xintfloatexpr seq((x^2-1,mul(x-t,t=-1+[0..4]/2)),x=-1.2..[0.1]..+1.2) \relax }; +\end{tikzpicture} +\caption{Coordinates with \cs{xintthecoords}.} +\end{figure} +\end{everbatim*} + +% Notice: if x goes no take exactly value 1 or -1, the origin appears slightly +% off the curve, not MY fault!!! + +As examplified above, \csbxint{thecoords} is to be used followed immediately +by either \csbxint{floatexpr} or \csbxint{iexpr} or \csbxint{iiexpr}. See +\url{https://tex.stackexchange.com/a/447290} for another example. + +As |TikZ| will not understand the |A/B[N]| format which is used on output by +|\xintexpr|, |\xintthecoords\xintexpr| has no use inside a |TikZ| picture but +may have other usages; the reason for the spaces in output is to allow if +necessary to print on the page for examination and give \TeX\ a change to +establish line-breaks. + +\begin{everbatim*} +\edef\x{\xintthecoords \xintexpr rrseq(1/2,1/3; @1+@2, x=1..20)\relax } +\meaning\x +++ +\end{everbatim*} + +\subsection{\csh{xintifboolexpr}, \csh{xintifboolfloatexpr}, \csh{xintifbooliiexpr}} +\label{xintifboolexpr} +\label{xintifboolfloatexpr} +\label{xintifbooliiexpr} + +\csh{xintifboolexpr}\marg{expr}\marg{YES}\marg{NO}\etype{xnn} does +\csbxint{theexpr}<expr>|\relax| and then executes the \meta{YES} or the +\meta{NO} branch depending on whether the outcome was non-zero or zero. Thus +one can read \emph{if bool expr} as meaning \emph{if not zero}: +\centeredline{if \meta{expr}-ession does not vanish do \meta{YES} else do + \meta{NO}} + +The expression is not limited to using only comparison operators and Boolean +logic (|<|, |>|, |==|, |!=|, |&&|, \verb+||+, \func{all}, \func{any}, +\func{xor}, \func{bool}, \func{togl}, ...), it can be the most general +computation. + +\csh{xintifboolfloatexpr}\marg{expr}\marg{YES}\marg{NO}\etype{xnn} does +\csbxint{thefloatexpr}\meta{expr}|\relax| and then executes the \meta{YES} or the +\meta{NO} branch depending on whether the outcome was non zero or zero. + +\csh{xintifbooliiexpr}\marg{expr}\marg{YES}\marg{NO}\etype{xnn} does +\csbxint{theiiexpr}\meta{expr}|\relax| and then executes the \meta{YES} or the +\meta{NO} branch depending on whether the outcome was non zero or zero. + +The expression argument must be a single one, comma separated sub-expressions +will cause low-level errors. + +\subsection{\csh{xintifsgnexpr}, \csh{xintifsgnfloatexpr}, \csh{xintifsgniiexpr}} +\label{xintifsgnexpr} +\label{xintifsgnfloatexpr} +\label{xintifsgniiexpr} + +\csh{xintifsgnexpr}\marg{expr}\marg{<0}\marg{=0}\marg{>0}\etype{xnnn} evaluates +the \csbxint{expr}ession and chooses the branch corresponding to its sign. + +\csh{xintifsgnfloatexpr}\marg{expr}\marg{<0}\marg{=0}\marg{>0}\etype{xnnn} evaluates +the \csbxint{floatexpr}ession and chooses the branch corresponding to its sign. + +\csh{xintifsgniiexpr}\marg{expr}\marg{<0}\marg{=0}\marg{>0}\etype{xnnn} evaluates +the \csbxint{iiexpr}ession and chooses the branch corresponding to its sign.\NewWith{1.3d} + +The expression argument must be a single one, comma separated sub-expressions +will cause low-level errors. + +\subsection{The \csh{xintNewExpr} macro} +\label{xintNewExpr} + +The macro is used as: +% +\leftedline{|\xintNewExpr{\myformula}[n]|\marg{stuff}, where} +\begin{itemize} +\item \meta{stuff} will be inserted inside |\xinttheexpr . . . \relax|, +\item |n| is an integer between zero and nine, inclusive, which is the number + of parameters of |\myformula|, +\item the placeholders |#1|, |#2|, ..., |#n| are used inside \meta{stuff} in + their usual r\^ole,% +% +\catcode`# 12 +\footnote{if \csa{xintNewExpr} is used inside a macro, + the |#|'s must be doubled as usual.} + \footnote{the |#|'s will in pratice have their usual + catcode, but category code other |#|'s are accepted too.} +\catcode`# 6 +% +\item the |[n]| is \emph{mandatory}, even for |n=0|.% +\footnote{there is some use for \csa{xintNewExpr}|[0]| compared to an + \csa{edef} as \csa{xintNewExpr} has some built-in catcode protection.} +\item the macro |\myformula| is defined without checking if it already exists, + \LaTeX{} users might prefer to do first |\newcommand*\myformula {}| to get a + reasonable error message in case |\myformula| already exists, +\item the protection against active characters is done automatically (as long + as the whole thing has not already been fetched as a macro argument and + the catcodes correspondingly already frozen). +\end{itemize} + +It will be a completely expandable macro entirely built-up using |\xintAdd|, +|\xintSub|, |\xintMul|, |\xintDiv|, |\xintPow|, etc\dots as corresponds to the +expression written with the infix operators. +Macros created by |\xintNewExpr| can thus be nested. + +\begin{everbatim*} + \xintNewFloatExpr \FA [2]{(#1+#2)^10} + \xintNewFloatExpr \FB [2]{sqrt(#1*#2)} +\begin{enumerate}[nosep] + \item \FA {5}{5} + \item \FB {30}{10} + \item \FA {\FB {30}{10}}{\FB {40}{20}} +\end{enumerate} +\end{everbatim*} + + The use of \csbxint{NewExpr} circumvents the impact of the |\xintexpr| + parsers on \TeX's memory: it is useful if one has a formula which has to be + re-evaluated thousands of times with distinct inputs each with dozens, or + hundreds of digits. + + A ``formula'' created by |\xintNewExpr| is thus a macro whose parameters are + given to a possibly very complicated combination of the various macros of + \xintname and \xintfracname. Consequently, one can not use at all any infix + notation in the inputs, but only the formats which are recognized by the + \xintfracname macros. + + This is thus quite different from a macro with parameters which one would + have defined via a simple |\def| or |\newcommand| as for example: + % + \leftedline{|\newcommand\myformula [1]{\xinttheexpr (#1)^3\relax}|} + % + Such a macro |\myformula|, if it was used tens of thousands of times with + various big inputs would end up populating large parts of \TeX's memory. It + would thus be better for such use cases to go for: + % + \leftedline{|\xintNewExpr\myformula [1]{#1^3\relax}|} + % + Here naturally the situation is over-simplified and it would be even simpler + to go directly for the use of the macro |\xintPow| or |\xintPower|. + + +|\xintNewExpr| tries to do as many evaluations as are possible at the time the +macro parameters are still parameters. Let's see a few examples. For this I +will use |\meaning| which reveals the contents of a macro. + +\begin{enumerate} +\item the examples use a mysterious |\fixmeaning| macro, which is there to get + in the display |\romannumeral`^^@| rather than the frankly cabalistic + |\romannumeral``| which made the admiration of the readers of the + documentation dated |2015/10/19| (the second |`| stood for an ascii code + zero token as per |T1| encoded |newtxtt| font). Thus the true meaning is + ``fixed'' to display something different which is how the macro could be + defined in a standard |tex| source file (modulo, as one can see in example, + the use of characters such as |:| as letters in control sequence names). + Prior to |1.2a|, the meaning would have started with a more mundane + |\romannumeral-`0|, but I decided at the time of releasing |1.2a| to imitate + the serious guys and switch for the more hacky yet |\romannumeral`^^@| + everywhere in the source code (not only in the macros produced by + \csbxint{NewExpr}), or to be more precise for an equivalent as the caret has + catcode letter in \xintname's source code, and I had to use another + character. +\item the meaning reveals the use of some private macros from the \xintname + bundle, which should not be directly used. If the things look a bit + complicated, it is because they have to cater for many possibilities. +\item the point of showing the meaning is also to see what has already been + evaluated in the construction of the macros. +\end{enumerate} + +\begin{everbatim*} +\xintNewIIExpr\FA [1]{13*25*78*#1+2826*292}\fixmeaning\FA +\end{everbatim*} +\smallskip + +\begin{everbatim*} +\xintNewIExpr\FA [2]{(3/5*9/7*13/11*#1-#2)*3^7} +\printnumber{\fixmeaning\FA} +\end{everbatim*} + +\smallskip + +\begin{everbatim*} +% an example with optional parameter +\xintNewIExpr\FA [3]{[24] (#1+#2)/(#1-#2)^#3} +\printnumber{\fixmeaning\FA} +\end{everbatim*} + +\smallskip + +\begin{everbatim*} +\xintNewFloatExpr\FA [2]{[12] 3.1415^3*#1-#2^5} +\printnumber{\fixmeaning\FA} +\end{everbatim*} + +\smallskip + +\begin{everbatim*} +\xintNewExpr\DET[9]{ #1*#5*#9+#2*#6*#7+#3*#4*#8-#1*#6*#8-#2*#4*#9-#3*#5*#7 } +\printnumber{\fixmeaning\DET} +\end{everbatim*} + +\unless\ifxetex +Notice that since |1.2c| it is perhaps more natural to do: +\begin{everbatim*} +% attention that «ad» would try to use non-existent variable "ad" +\xintdeffunc det2(a, b, c, d) := a*d - b*c ; +% This is impossible because we must use single letters : +% \xintdeffunc det3(x_11, x_12, x_13, x_21, x_22, x_23, x_31, x_32, x_33) := +% x_11 * det2 (x_22, x_23, x_32, x_33) + x_21 * det2 (x_32, x_33, x_12, x_13) +% + x_31 * det2 (x_12, x_13, x_22, x_23); +\xintdeffunc det3 (a, b, c, u, v, w, x, y, z) := a*v*z + b*w*x + c*u*y - b*u*z - c*v*x - a*w*y ; +\xinttheexpr det3 (1,1,1,1,2,4,1,3,9), det3 (1,10,100,1,100,10000,1,1000,1000000), + 90*900*990, reduce(det3 (1,1/2,1/3,1/2,1/3,1/4,1/3,1/4,1/5))\relax\newline +\xintdeffunc det3bis (a, b, c, u, v, w, x, y, z) := + a*det2(v,w,y,z)-b*det2(u,w,x,z)+c*det2(u,v,x,y); +\pdfsetrandomseed 123456789 % xint.pdf should be predictable from xint.dtx ! +\xinttheexpr subs(subs(subs(subs(subs(subs(subs(subs(subs( +% we use one extra pair of parentheses to hide the commas from the subs + (a, b, c, u, v, w, x, y, z, det3 (a, b, c, u, v, w, x, y, z), + det3bis (a, b, c, u, v, w, x, y, z)), + z=\pdfuniformdeviate 1000), y=\pdfuniformdeviate 1000), x=\pdfuniformdeviate 1000), + w=\pdfuniformdeviate 1000), v=\pdfuniformdeviate 1000), u=\pdfuniformdeviate 1000), + c=\pdfuniformdeviate 1000), b=\pdfuniformdeviate 1000), a=\pdfuniformdeviate 1000)\relax +\end{everbatim*} + + +The last computation with its nine nested |subs| can be coded more +economically (and efficiently), exploiting the fact that a single dummy +variable can expand to a whole list: +\begin{everbatim*} +\pdfsetrandomseed 123456789 % xint.pdf should be predictable from xint.dtx ! +\xinttheexpr subs((L, det3(L), det3bis(L)), % parentheses used to hide the inner commas + L=\pdfuniformdeviate 1000, \pdfuniformdeviate 1000, \pdfuniformdeviate 1000, + \pdfuniformdeviate 1000, \pdfuniformdeviate 1000, \pdfuniformdeviate 1000, + \pdfuniformdeviate 1000, \pdfuniformdeviate 1000, \pdfuniformdeviate 1000)\relax +\end{everbatim*} +\fi % de pas de xetex + +With |\xintverbosetrue| we will find in the log: + +\begin{everbatim} + Function det3 for \xintexpr parser associated to \XINT_expr_userfunc_det3 w +ith meaning macro:#1#2#3#4#5#6#7#8#9->\xintSub {\xintSub {\xintSub {\xintAdd {\ +xintAdd {\xintMul {\xintMul {#1}{#5}}{#9}}{\xintMul {\xintMul {#2}{#6}}{#7}}}{\ +xintMul {\xintMul {#3}{#4}}{#8}}}{\xintMul {\xintMul {#2}{#4}}{#9}}}{\xintMul { +\xintMul {#3}{#5}}{#7}}}{\xintMul {\xintMul {#1}{#6}}{#8}} + + Function det3bis for \xintexpr parser associated to \XINT_expr_userfunc_det +3bis with meaning macro:#1#2#3#4#5#6#7#8#9->\xintAdd {\xintSub {\xintMul {#1}{\ +xintExpandArgs {XINT_expr_userfunc_det2}{{#5}{#6}{#8}{#9}}}}{\xintMul {#2}{\xin +tExpandArgs {XINT_expr_userfunc_det2}{{#4}{#6}{#7}{#9}}}}}{\xintMul {#3}{\xintE +xpandArgs {XINT_expr_userfunc_det2}{{#4}{#5}{#7}{#8}}}} +\end{everbatim} + + + +\medskip +Lists, including Python-like selectors, are compatible with +\csa{xintNewExpr}:% +% +\footnote{The |\empty| token is optional here, but it would + be needed in case of \csbxint{NewFloatExpr} or \csbxint{NewIExpr}.} +% +\begin{everbatim*} +\xintNewExpr\Foo[5]{\empty[#1..[#2]..#3][#4:#5]} +\begin{itemize}[nosep] +\item |\Foo{1}{3}{90}{20}{30}|->\Foo{1}{3}{90}{20}{30} +\item |\Foo{1}{3}{90}{-40}{-15}|->\Foo{1}{3}{90}{-40}{-15} +\item |\Foo{1.234}{-0.123}{-10}{3}{7}|->\Foo{1.234}{-0.123}{-10}{3}{7} +\end{itemize} +\fdef\test {\Foo {0}{10}{100}{3}{6}}\meaning\test +++ +\end{everbatim*} + +In this last example the macro |\Foo| will not be able to handle an empty |#4| +or |#5|: this is only possible in an expression, because the parser identifies +|][:| or |:]| and handles them appropriately. During the construction of |\Foo| +the parser will find |][#4:| and not |][:|. + +\begin{framed} + The \csbxint{deffunc}, \csbxint{defiifunc}, \csbxint{deffloatfunc} + declarators added to \xintexprname since release |1.2c| are based on the + same underlying mechanism as \csa{xintNewExpr}, \csa{xintNewIIExpr}, ... The + discussion that follows applies to them too. +\end{framed} + +\subsubsection {Conditional operators and \csh{NewExpr}} +\label{sssec:cond} + +The |?| and |??| conditional operators cannot be parsed by |\xintNewExpr| when +they contain macro parameters |#1|,\dots, |#9| within their scope. However +replacing them with the functions |if| and, respectively |ifsgn|, the parsing +should succeed. And the created macro will \emph{not evaluate the branches to + be skipped}, thus behaving exactly like |?| and |??| would have in the +|\xintexpr|. + +\begin{everbatim*} +\xintNewExpr\Formula [3]{ if((#1>#2) && (#2>#3), sqrt(#1-#2)*sqrt(#2-#3), #1^2+#3/#2) }% +\printnumber{\fixmeaning\Formula } +\end{everbatim*} + +This formula (with its |\xintiiifNotZero|) will gobble the false branch without +evaluating it when used with given arguments. + +Remark: the meaning above reveals some of the private macros used by the +package. They are not for direct use. + +Another example + +\begin{everbatim*} +\xintNewExpr\myformula[3]{ ifsgn(#1,#2/#3,#2-#3,#2*#3) }% +\fixmeaning\myformula +\end{everbatim*} + +Again, this macro gobbles the false branches, as would have the operator |??| +inside an |\xintexpr|-ession. + +\subsubsection{External macros and \csh{xintNewExpr}; the protect function} +\label{sssec:protect} + +For macros within such a created \xintname-formula macro, there +are two cases: +\begin{itemize} +\item the macro does not involve the numbered parameters in its arguments: it + may then be left as is, and will be evaluated once during the construction of + the formula, +\item it does involve at least one of the macro parameters as argument. Then: + \begin{snugframed} + the whole thing (macro + argument) should be |protect|-ed, not in the + \LaTeX{} sense (!), but in the following way: |protect(\macro {#1})|.\IMPORTANT + \end{snugframed} +\end{itemize} + +Here is a silly example illustrating the general principle: the macros here have +equivalent functional forms which are more convenient; but some of the more +obscure package macros of \xintname dealing with integers do not have functions +pre-defined to be in correspondance with them, use this mechanism could be +applied to them. + +\begin{everbatim*} +\xintNewExpr\formulaA[2]{protect(\xintRound{#1}{#2}) - protect(\xintTrunc{#1}{#2})}% +\printnumber{\fixmeaning\formulaA} + +\xintNewIIExpr\formulaB [3]{rem(#1,quo(protect(\the\numexpr #2\relax),#3))}% +\noindent\printnumber{\fixmeaning\formulaB } +\end{everbatim*} + +Only macros involving the |#1|, |#2|, etc\dots should be protected in this +way; the |+|, |*|, etc\dots symbols, the functions from the \csbxint{expr} +syntax, none should ever be included in a protected string. + + +\subsubsection{Limitations of \csh{NewExpr} and \csh{deffunc}} +\label{sssec:limitations} + +\csbxint{NewExpr} will pre-evaluate everything as long as it does not contain +the macro parameters |#1|, |#2|, ... and the special measures to take when +these are inside branches to |?| and |??| (replace these operators by |if| and +|ifsgn|) or as arguments to macros external to \xintexprname (use |protect|) +were discussed in \autoref{sssec:cond} and \autoref{sssec:protect}. + +The main remaining limitation is that expressions with dummy variables are +compatible with \csa{xintNewExpr} only to the extent that the iterated-over +list of values does not depend on the macro parameters |#1|, |#2|, ... For +example, this works: +\begin{everbatim*} +\xintNewExpr \FA [2] {reduce(add((t+#1)/(t+#2), t=0..5))} +\FA {1}{1}, \FA {1}{2}, \FA {2}{3} +\end{everbatim*} +but the |5| can not be abstracted into a third argument |#3|. + +There are no restriction on using macro parameters |#1|, |#2|, ... with list +constructs. For example, this works: +\begin{everbatim*} +\xintNewIExpr \FB [3] {[4] `+`([1/3..[#1/3]..#2]*#3)} +\begin{itemize}[nosep] +\item \FB {1}{10/3}{100} % (1/3+2/3+...+10/3)*100 +\item \FB {5}{5}{20} % (1/3+6/3+11/3)*20 +\item \FB {3}{4}{1} % (1/3+4/3+7/3+10/3)*1 +\end{itemize} +\end{everbatim*} + +Some simple expressions with |add| or |mul| can be also expressed with |`+`| +and |`*`| and list operations. But there is no hope for |seq|, |iter|, etc... +if the |#1|, |#2|, ... are used inside the list argument: +|seq(x(x+#1)(x+#2),x=1..#3)| is currently not compatible with +\csa{xintNewExpr}. But |seq(x(x+#1)(x+#2), x=1..10)| has no problem. + +All the preceeding applies identically for \csbxint{deffunc}, \csbxint{defiifunc}, +\csbxint{deffloatfunc} which share the same routines as \csa{xintNewExpr}, +\csa{xintNewIIExpr}, ..., replacing the |#1|, |#2|, ... in the discussion by +the letters used as function arguments. + +Here is a final syntax restriction: it is possible to use sub-expressions only if they use +\csa{xintexpr}, those with \csa{xinttheexpr}, or \csbxint{eval} are illegal. +\begin{everbatim*} +\xintNewExpr \FC [4] {#1+\xintexpr #2*#3\relax + #4} +\printnumber{\fixmeaning\FC} +\end{everbatim*}\newline +works, but +\begin{everbatim} +\xintNewExpr \FD [1] {#1+\xinttheexpr 1\relax} +\end{everbatim} +or +\begin{everbatim} +\xintNewExpr \FD [1] {#1+\xinteval{1}} +\end{everbatim} +do not. + +Prior to |1.3e| it would have been possible to do\CHANGED{1.3e} +\begin{everbatim} +\xintdeffunc FD(t) := t + \xinttheexpr 1\relax ; +\end{everbatim} +and even +\begin{everbatim} +\xintdeffunc FE(t,u) := t + \xinttheexpr u\relax ; +\end{everbatim} +They are now illegal, but fortunately +\begin{everbatim*} +\xintdeffunc FD(t) := t + \xintexpr 1\relax ; +\end{everbatim*} +and even for example +\begin{everbatim*} +\xintdeffunc FE(t,u) := \xintfloatexpr t + u\relax ; +\end{everbatim*} +do work. The latter would not have worked formerly. It now does, see +\xinttrigname for use case. + +Anyway, one should never use |\xinttheexpr| for sub-expressions but only +|\xintexpr|, so these restrictions on the \csbxint{NewExpr} and +\csbxint{deffunc} syntax have no importance. However since the package +provides the high level \csbxint{eval} et al., it may trap some users. But if +they read the documentation they will have been warned. + +\subsection{\csh{xintNewFloatExpr}}\label{xintNewFloatExpr} + +This is exactly like \csbxint{NewExpr} except that the created formulas are +set-up to use |\xintthefloatexpr|. Careful though that the |[...]| list syntax +if first thing in the expression will be confused by the parser with the +optional rounding argument |[N]| of \csbxint{floatexpr} (cf. +\autoref{ssec:lists}.) Use an |\empty| token: +\begin{everbatim*} +\xintNewFloatExpr\F[1]{\empty[divmod(11.7,#1)][1]} +% this is a bit silly example, done only to check that it works +\F{1.35} +\end{everbatim*} + +The numbers hard-wired in the original expression are evaluated using the +prevailing |\xintDigits| precision at time of creation; the rest of the +formula will be evaluated using the precision valid at the time of use. +\begin{everbatim*} +\xintNewFloatExpr \f [1] {sqrt(#1)} +\f {2} (with \xinttheDigits{} digits of precision). + +{\xintDigits := 32;\f {2} (with \xinttheDigits{} digits of precision).} + +\xintNewFloatExpr \f [1] {sqrt(#1)*sqrt(2)} +\f {2} (with \xinttheDigits {} digits of precision). + +\xintDigits := 32;\f {2} (?? we thought we had a higher precision.) + +\xintNewFloatExpr \f [1] {sqrt(#1)*sqrt(2)} +\f {2} (with \xinttheDigits {} digits of precision) + +\xintDigits := 16;% back to default +\end{everbatim*} + +The |sqrt(2)| in the first |sqrt(#1)*sqrt(2)| NewFloatExpression was computed +with only \dtt{\xinttheDigits} digits of precision. In the second one, the +|sqrt(2)| gets pre-evaluated with \dtt{32} digits of precision. + +\subsection{\csh{xintNewIExpr}}\label{xintNewIExpr} + +Like \csbxint{NewExpr} but using |\xinttheiexpr|. As |\xintiexpr| admits an +optional rounding argument |[N]| the same caveat when square brackets come +first in the expression as in the discussion of \csbxint{NewFloatExpr} +applies. + + +\subsection{\csh{xintNewIIExpr}}\label{xintNewIIExpr} + +Like \csbxint{NewExpr} but using |\xinttheiiexpr|. + +\subsection{\csh{xintNewBoolExpr}}\label{xintNewBoolExpr} + +Like \csbxint{NewExpr} but using |\xinttheboolexpr|. + +\xintDigits:= 16; + +\subsection{The \cshnolabel{xintdefvar}, \cshnolabel{xintdefiivar}, \cshnolabel{xintdeffloatvar} macros} + +See \autoref{xintdefvar} for their documentation. + +\subsection{The \cshnolabel{xintdeffunc}, \cshnolabel{xintdefiifunc}, \cshnolabel{xintdeffloatfunc} macros} + +See \autoref{xintdeffunc} for their documentation. + +\subsection{The \cshnolabel{xintNewFunction} macro} + +See \autoref{xintNewFunction} for its documentation. + +\subsection{Technicalities} + +As already mentioned \csa{xintNewExpr}|\myformula[n]| does not check the prior +existence of a macro |\myformula|. And the number of parameters |n| given as +mandatory argument within square brackets should be (at least) equal +to the number of parameters in the expression. + +Obviously I should mention that \csa{xintNewExpr} itself can not be used in an +expansion-only context, as it creates a macro. + +The |\escapechar| setting may be arbitrary when using |\xintexpr|. + +The format of the output of +|\xintexpr|\meta{stuff}|\relax| is a |!| (with catcode 11) followed by various things: +\begin{everbatim*} +\edef\f {\xintexpr 1.23^10\relax }\meaning\f +\end{everbatim*} + +\begin{framed} + Note that |\xintexpr| expands in an |\edef|, contrarily + to |\numexpr| which is non-expandable, if not prefixed by |\the|, |\number|, + or |\romannumeral| or in some other context where \TeX{} is building a number. See + \autoref{ssec:fibonacci} for some illustration. +\end{framed} + +I decided to put all intermediate results (from each evaluation of an infix +operators, or of a parenthesized subpart of the expression, or from application +of the minus as prefix, or of the exclamation sign as postfix, or any +encountered braced material) inside |\csname...\endcsname|, as this can be done +expandably and encapsulates an arbitrarily long fraction in a single token (left +with undefined meaning), thus providing tremendous relief to the programmer in +his/her expansion control. + +\begin{framed} + As the |\xintexpr| computations corresponding to functions and infix + or postfix operators are done inside |\csname...\endcsname|, the + \fexpan dability could possibly be dropped and one could imagine + implementing the basic operations with expandable but not \fexpan + dable macros (as \csbxint{XTrunc}.) I have not investigated that + possibility. +\end{framed} + +Syntax errors in the input such as using a one-argument function with two +arguments will generate low-level \TeX{} processing unrecoverable errors, with +cryptic accompanying message. + +Some other problems will give rise to `error messages' macros giving some +indication on the location and nature of the problem. Mainly, an attempt has +been made to handle gracefully missing or extraneous parentheses. + +However, this mechanism is completely inoperant for parentheses involved in +the syntax of the |seq|, |add|, |mul|, |subs|, |rseq| and |rrseq| functions, +and missing parentheses may cause the parser to fetch tokens beyond the ending +|\relax| necessarily ending up in cryptic low-level \TeX-errors. + +Note that the |,<letter>=| part must be visible, it can not arise from +expansion (the equal sign does not have to be an equal sign, it can be any +token and will be gobbled).\IMPORTANT{} However for |iter|, |iterr|, |rseq|, +|rrseq|, the initial values delimited by a |;| are parsed in the normal way, +and in particular may be braced or arise from expansion. This is useful as the +|;| may be hidden from \csa{xintdeffunc} as |{;}| for example. Again, this +remark does \emph{not} apply to the comma |,| which precedes the |<letter>=| +part. The comma will be fetched by delimited macros and must be there. Nesting +is handled by checking (again using suitable delimited macros) that +parentheses are suitably balanced. + + +Note that |\relax| is \emph{mandatory} (contrarily to the situation for |\numexpr|). + +\subsection{Acknowledgements (2013/05/25)} + +I was greatly helped in my preparatory thinking, prior to producing such an +expandable parser, by the commented source of the +\href{http://www.ctan.org/pkg/l3kernel}{l3fp} package, specifically the +|l3fp-parse.dtx| file (in the version of April-May 2013; I think there was in +particular a text called ``roadmap'' which was helpful). Also the source of the +|calc| package was instructive, despite the fact that here for |\xintexpr| the +principles are necessarily different due to the aim of achieving expandability. + + +\clearpage +\let\xintexprnameUp\undefined +\csname xinttrignameUp\endcsname +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} +\section{Macros of the \xinttrigname package} +\RaisedLabel{sec:trig} + +\localtableofcontents + +This package provides trigonometric functions for use with \xintexprname. +The sole macro is \csbxint{reloadxinttrig}. + +This package was first included in release |1.3e| (|2019/04/01|) of +\xintexprname. It is automatically loaded by \xintexprname. + +\textbf{Acknowledgements} I finally decided to release some such functions +under friendly pressure of Jürgen \textsc{Gilg} and Thomas \textsc{Söll}, let +them both be thanked here. + +\subsection{\csh{xintreloadxinttrig}}\label{xintreloadxinttrig} + +\begin{framed} + After modifying \csbxint{Digits},\IMPORTANTf{} one must issue + \csbxint{reloadxinttrig} to let the package re-configure itself. +\end{framed} + +The library is pre-configured to be able to handle a precision of up to about +\fbox{\dtt{60}} digits (make this \dtt{59} at most for the inverse functions). +But absence of guard digits (whether in the used hard-coded constants or in +passing over values from one auxiliary function to the next) due to high level +(user) interface used for the programming means that the produced values are +definitely expected to be wrong in the last digit or last two digits. I should +actually give some estimate of the actual maximal error in |ulps| unit, but I +have not done the complete analysis for lack of time. + +Final computation results should thus probably be printed via +\csbxint{floateval}|{[-2]....}| in order to strip off (with rounding) the last +two digits, if one does not like seeing those non-meaningful figures in the +last one or two positions (I don't say those last two figures are +\emph{systematically} off). For example, to achieve \dtt{16} digits of +precision one should work with a precision of 18 digits (being careful to have +issued \csbxint{reloadxinttrig}) and round results using +\csbxint{floateval}|{[-2]....}|. + +Another approach is to use \csbxint{ieval}|{[D]...}| for conversion to +a fixed point format. + +In future, lower level coding will probably replace the high-level interface, +or at least the macros produced by the high-level interface will be hacked +into to tell the float macros to work at a somewhat elevated precision. + +\subsection{Constants} + +They are the correct rounding to \csbxint{Digits} precision of the +mathematically exact ones. Their values get incorporated into the +trigonometrical functions at the time of their definitions during loading or +reloading of the package. They are left free to use, or modified, or +\csbxint{unassignvar}'d, as this will have no impact whatsoever on the +functions. + +\begin{description} +\vardesc{twoPi} what could that be? +\vardesc{threePiover2} +\vardesc{Pi} +\vardesc{Piover2} +\vardesc{oneRadian} this is one radian in degrees: $180/\pi$ +\vardesc{oneDegree} this is one degree in radian: $\pi/180$ +\vardesc{invfact2} this is $1/2!$ +\vardesc{invfact3} this is $1/3!$ +\item[\dots] +\vardesc{invfact44} this is $1/44!$ +\end{description} + +For a (very) slight optimization of usage, it is recommended to convert them +to macro form, for example: +\begin{everbatim*} +\edef\oneDegree{\xintfloatexpr oneDegree\relax} +\xintfloateval{sin(37\oneDegree)}\newline +\xintfloateval{sind(37)}\newline +\end{everbatim*} +By the way, the above value differs by |1ulp| from correct rounding of exact +one (which looks \dtt{...520482}79917...), see \autoref{ssec:trignotes}. + +\subsection{Functions} + +\subsubsection{Direct trigonometry} + +With the variable in radians: + +\begin{description} +\funcdesc{sin} sine +\funcdesc{cos} cosine +\funcdesc{tan} tangent +\funcdesc{cot} cotangent +\funcdesc{sec} secant +\funcdesc{csc} cosecant +\end{description} + +With the variable in degrees: + +\begin{description} +\funcdesc{sind} sine +\funcdesc{cosd} cosine +\funcdesc{tand} tangent +\funcdesc{cotd} cotangent +\funcdesc{secd} secant +\funcdesc{cscd} cosecant +\end{description} + +Only available with the variable in radians: +\begin{description} +\funcdesc{tg} tangent +\funcdesc{cotg} cotangent +\funcdesc{sinc} cardinal sine $\sinc(x) = \sin(x)/x$ +\end{description} + +\subsubsection{Inverse trigonometry} + +With the value in radians: + +\begin{description} +\funcdesc{asin} arcsine +\funcdesc{acos} arccosine +\funcdesc{atan} arctangent +\funcdesc[x, y]{Arg} the main branch of the argument of the complex number +|x+iy|, from $-\pi$ (excluded) to $\pi$ (included). Inherent rounding of +output makes +-\var{Pi} a possible return value. +\funcdesc[x, y]{pArg} the branch of the argument of the complex number +|x+iy| with values going from $0$ (included) to $2\pi$ (excluded). Inherent +rounding makes \var{twoPi} a possible return value. +\funcdesc[y, x]{atan2} it is |Arg(x, y)|. Note the reversal of the arguments, +this seems to be the most frequently encountered convention across languages. +\end{description} + +With the value in degrees: + +\begin{description} +\funcdesc{asind} arcsine +\funcdesc{acosd} arccosine +\funcdesc{atand} arctangent +\funcdesc[x, y]{Argd} the main branch of the argument of the complex number +|x+iy|, from $-180$ (excluded) to $180$ (included). Inherent rounding of +output can cause |-180| +to be returned. +\funcdesc[x, y]{pArgd} the branch of the argument of the complex number +|x+iy| with values going from $0$ (included) to $360$ (excluded). Inherent rounding of +output can cause |360| to be returned. +\funcdesc[y, x]{atan2d} it is |Arg(x, y)|. Note the reversal of the arguments, +this seems to be the most frequently encountered convention across languages. +\end{description} + +\subsubsection{Conversion functions (optional definitions left to user + decision)} + +Python provides functions |degrees()| and |radians()|. But as most of the +\xinttrigname functions are already defined for the two units, I felt this was +not really needed. It is a oneliner to add them: +\begin{everbatim} +\xintdeffloatefunc radians(x) := x * oneDegree; +\xintdeffloatefunc degrees(x) := x * oneRadian; +\xintdefefunc radians(x) := x * oneDegree; +\xintdefefunc degrees(x) := x * oneRadian; +\end{everbatim} + +The variants for \csbxint{expr} above do an exact multiplication, I did not +add a \func{float} wrapper to force rounding as anyhow the trigonometrical +functions will do this initial rounding of their arguments. But if you define +a variable for multiple later use using such a |degrees()| function, it would +be better to add a \func{float} wrapper in the variable definition so the +rounding is already done: rounding an already rounded value is unavoidable +overhead but proceeds faster as it is quicly realized the input actually needs +no rounding. + +Notice however that the conversion factors above are without guard digits. One +can do this: +\begin{everbatim} +\xintdeffloatefunc radians(x) := float(\xintexpr x * oneDegreewithmoredigits\relax); +\xintdeffloatefunc degrees(x) := float(\xintexpr x * oneRadianwithmoredigits\relax); +\end{everbatim} +But recall that |x| will normally already be a rounded value, so this is +perhaps a bit complex for not much ado. Probably better to work overall with +an elevated precision and print final results at a lower precision. + +\subsection{Important implementation notes} +\label{ssec:trignotes} + +\begin{itemize} +\item The package is almost entirely implemented using the high level user + interface of \xintexprname, see \autoref{sec:xintexprsyntax} for + \csbxint{deffloatefunc} and \csbxint{deffloatvar}, the main two exceptions + are: + \begin{enumerate}[nolistsep] + \item the range reduction for the |sind()| and |cosd()| functions which + required for optimized efficiency the coding at some more core level. + \item a change at core level was done to \csbxint{deffunc} in order to + facilitate the transfer of the defined functions from the float parser to + the exact parser. See \autoref{sssec:limitations}, the source code + comments in |sourcexint.pdf| and the discussion of \csbxint{deffunc} for + details. The \csbxint{defefunc} added at |1.3e| was also motivated by this + context. + \end{enumerate} + To avoid problems if the package is reloaded at a time the user has + used some letter variables as assigned variables, I added + \csbxint{ensuredummy} and \csbxint{restorelettervar}. +\item It is not possible from this interface to (easily) let the computation + proceed with a temporarily elevated precision (``guard digits''). Expect + thus some errors in the last places; basically one should use the optional + rounding argument of either \csbxint{floateval} or \csbxint{ieval} to reduce + the number of digits of printed values by about two digits, if one + hopes to get correct rounding (most of the time). +\item Currently, \xintname is lacking some dedicated internal representation + of floats which means that most operations re-parse the digit tokens of their + arguments to count them\dots\ this does not contribute to efficiency (you + can load the module under |\xintverbosetrue| regime and see how the nested + macros look like and get an idea of how many times some rather silly + re-counting of mantissa lengths will get done!) +\item One should not overwrite some function names which are employed as + auxiliaries: |sin_aux|, |cos_aux|, |sin_|, |cos_|, |sind_|, |cosd_|, + |asin_l|\dots others\dots |asin_a|, |asind_a|, |atan_a|, |atand_a|, + |atan_b|, |atand_b|. If you redefine any one of them, you break the + whole thing. +\item Floats with large exponents are integers and are multiple of \dtt{1000}; + hence modulo \dtt{360} all such ``angles'' are multiple of \dtt{40} degrees. + Needless to say that considering usage of the sine and cosine functions + with such large float numbers is meaningless. +\item Regarding such a big float angle in radians, \xinttrigname converts + it to degrees by multiplication by (pre-rounded) $180/\pi$, then it does + range reduction modulo $360$ and goes back to radians in the appropriate + octants and use the series (roughly said). Thus |cos()| and |sin()| will be + evaluated as if at some of the finitely many rounded multiples of (exact) + $2\pi/9$. When the unit in the last place of the original input was for + example \dtt{1e9} it is clear that the final result means nothing at all; + this intrinsic problem is not one of conversion from radians to degrees: the + unit in the last place interval extends above possibly astronomical numbers of + intervals of length $2\pi$. This is an in-built inadequacy of (large) + floating point numbers for trigonometrical evaluations; the argument should + be treated then as a uniformly distributed random variable modulo $2\pi$, + and the sine and cosine values should be random variables realizing the value + distribution of these mathematical functions. Clearly this adds some + programming complication of deciding how to make the transition. Too lazy + for that. +\item Did I say the implementation was done at very high level (for the most + part), hence has ample room for optimization? This is particularly the case + for the handling of small inputs by functions such as sine or arcsine. +\end{itemize} + +\clearpage +\let\xinttrignameUp\undefined +\csname xintlognameUp\endcsname +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} + +\section{Macros of the \xintlogname package} +\RaisedLabel{sec:log} + +\localtableofcontents + +This package provides logarithms, exponentials and fractional powers for use +with \xintexprname. + +This package was first included in release |1.3e| (|2019/04/01|) of +\xintexprname. It is automatically loaded by \xintexprname. + +Currently it is a wrapper to import package +\href{http://www.ctan.org/pkg/poormanlog}{poormanlog} which computes with +\dtt{8} or \dtt{9} digits of precision, adding the \func{log}, \func{exp}, and +\func{pow} function to the \func{log10} and \func{pow10} provided by the package. + +\subsection{\csh{poormanloghack}} +\label{ssec:poormanloghack} + +\begin{description} +\item[\string\poormanloghack\string{**\string}] use it to let the |**| operator be remapped to the + \func{pow} function. +\item[\string\poormanloghack\string{\string^\string}] use it to let the |^| operator be remapped to the + \func{pow} function. +\end{description} +If used, they obey \TeX\ scoping as usual. +\begin{everbatim*} +\begingroup +\poormanloghack{**}\xintfloateval{[8]1.234**5.678}\newline +\poormanloghack{^}\xintfloateval{[8]1.234^5.678}\par +\endgroup +% ** and ^ now do not accept fractional exponents: only half-integer ones and +% only in \xintfloateval, not \xinteval. +\end{everbatim*} + +Notice that in \csbxint{floateval} those (equivalent) operators already +natively handle half-integer exponents. Once remapped to the \func{pow} +function they will become less precise than the original ones for half-integer +and integer exponents. + +\subsection{Functions} + +All those functions achieve only about \dtt{8} or \dtt{9} digits of precision. +Notice in particular that the digits beyond the ninth printed by \func{log} +have no significance (here we suppose |1<x<10|), but I did not add the +rounding overhead as it is expected anyhow that the final result will be +appropriately rounded. Notice however that \func{log10} should be seen as +going from floating point to fixed point (in the sense of the number of +fractional digits) and \func{pow10} from fixed point to floating point. + +\begin{description} +\funcdesc{log10} logarithm in base 10 +\funcdesc{pow10} fractional powers of 10 +\funcdesc{log} natural logarithm via |log10(x)*2.3025850923| formula; only the +first 8 or 9 digits of the output are significant... +\funcdesc{exp} exponential function via |pow10(x*0.434294481903)| formula +\funcdesc[x, y]{pow} computes $x^y$ via the formula |pow10(y*log10(x))| +\end{description} + +\begin{everbatim*} +\xintfloateval{[9] log(2), exp(1), pow(2,0.5)} +\end{everbatim*} +Notice that the last digit of |log(2)| is not the correctly rounded one... I +did say 9 \textbf{or} 8 digits or precision... The documentation of +\href{http://www.ctan.org/pkg/poormanlog}{poormanlog} mentions an error of up +to 2 units in the ninth digit when computing |log10(x)| for |1<x<10| and +|10^x| for |0<x<1|. + +\clearpage +\let\xintlognameUp\undefined +\csname xintbinhexnameUp\endcsname +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} +\section{Macros of the \xintbinhexname package} +\RaisedLabel{sec:binhex} + +\localtableofcontents + +This package provides expandable conversions of (big) integers to +and from binary and hexadecimal. + +First version of this package was in the |1.08| (|2013/06/07|) release of +\xintname. Its routines remained un-modified until their complete rewrite at +release |1.2m| (|2017/07/31|). The new macros are faster, using techniques +from the |1.2| (|2015/10/10|) release of \xintcorename. But the inputs are now +limited to a few thousand digits, whereas the |1.08| could handle (slowly...) +tens of thousands of digits. + +\autoref{tab:binhexsizes} recapitulates the maximal allowed sizes (they got +increased at |1.2n|): +for macro |\xintFooToBar| in the first column, the value in the second column +is the maximal |N| such that |\edef\X{\xintFooToBar{<N digits>}}| does not +raise an error with standard \TeX\ memory parameters (input stack +size=\dtt{5000}, expansion depth=\dtt{10000}, parameter stack +size=\dtt{10000}). The tests were done with TL2017 and |etex|. Nested calls +will allow slightly lesser values only. The third column gives the +corresponding maximal size of output. The fourth column gives the \TeX\ +parameter cited in the error message when trying with |N+1| digits. + +\begin{table}[htbp] +\capstart + \centering +\def\E#1#2!{\edef\F{\the\numexpr(#1-\xintLength{#2})/2}% + \relax\romannumeral\xintreplicate{\F}{ }#2% + \romannumeral\xintreplicate{#1-\F-\xintLength{#2}}{ }\relax}% +% non satisfactory because depends on #1 oddness, but well. Temporary destined +% to stay... +\begin{tabular}{r>{\E{19}}c<{!}>{\E{19}}c<{!}r} + \hline + &Max\ length\ of\ input&->\ length\ of\ output&Limiting factor\\ + \csbxint{DecToHex}&6014&4995&input stack size=5000\\ + \csbxint{DecToBin}&6014&19979&input stack size=5000\\ + \csbxint{HexToDec}&8298&9992&input stack size=5000\\ + \csbxint{BinToDec}&19988&6017&input stack size=5000\\ + \csbxint{BinToHex}&19988&4997&input stack size=5000\\ + \csbxint{HexToBin}&4996&19984&input stack size=5000\\ + \csbxint{CHexToBin}&4997&19988&input stack size=5000\\ + \hline +\end{tabular} +\caption{Maximal sizes of inputs (at \texttt{1.2n}) for \xintbinhexname macros}\label{tab:binhexsizes} +\end{table} + +Roughly, base |10| numbers are limited to \dtt{6000} digits, hexadecimal +numbers to (almost) \dtt{5000} digits, and binary numbers to (almost) +\dtt{20000} digits. With the surprising exception of \csbxint{HexToDec} which +allows almost \dtt{8300} hexadecimal digits on input. + +The argument is first \fexpan ded. +It may optionally have a unique leading minus sign (a plus sign is not +allowed), and leading zeroes. + +An input (possibly signed) with no leading zeroes is guaranteed to give an +output without leading zero, with the sole, deliberate, exception of +\csbxint{CHexToBin}: from |N| hexadecimal digits it produces |4N| binary +digits, hence possibly with up to three leading zeroes (if the +input had none.) + +Inputs with leading zeroes usually produce outputs with an unspecified, +case-dependent, number of leading zeroes (\csbxint{BinToHex} always uses the +minimal number of hexadecimal digits needed to represent the binary digits, +inclusive of leading zeroes if present.) + +The macros converting from binary or decimal are robust against +non terminated inputs like |\the\numexpr 2+3| or |\the\mathcode`\-|. The macro +\csbxint{HexToDec} also but not \csbxint{HexToBin} and \csbxint{CHexToBin} +(anyway there are no primitive in (e)-\TeX\ to my knowledge which will +generate hexadecimal digits and may force expansion of next token). + +Hexadecimal digits |A..F| must be in uppercase. Category code for them on +input may be \emph{letter} or \emph{other}. On output they are of category +code \emph{letter}, and in uppercase. + +Low-level unrecoverable errors will happen if for example a supposedly binary +input contains other digits than |0| and |1|. Inputs can not start with a +|0b|, |0x|, |#x|, |"| or similar prefix: only digits/letters according to the +binary, decimal, or hexadecimal notation. + + +With this package loaded additionally to \xintexprname, hexadecimal input is +possible in expressions: simply by using the prefix |"|. Such hexadecimal +numbers may have a fractional part. Lowercase hexadecimal letters are +currently \emph{not} recognized as such in expressions. +Currently the |p| postfix notation from standard programming languages +standing for an extra +power of two multiplicand is not implemented. + +% \clearpage + +\subsection{\csh{xintDecToHex}}\label{xintDecToHex} + +Converts from decimal to hexadecimal.\etype{f} + +\texttt{\string\xintDecToHex \string{\printnumber{2718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003}\string}}\endgraf\noindent\dtt{->\printnumber{\xintDecToHex{2718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003}}} + +\subsection{\csh{xintDecToBin}}\label{xintDecToBin} + +Converts from decimal to binary.\etype{f} + +\texttt{\string\xintDecToBin \string{\printnumber{2718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003}\string}}\endgraf\noindent\dtt{->\printnumber{\xintDecToBin{2718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003}}} + +\subsection{\csh{xintHexToDec}}\label{xintHexToDec} + +Converts from hexadecimal to decimal.\etype{f} + +\texttt{\string\xintHexToDec + \string{\printnumber{11A9397C66949A97051F7D0A817914E3E0B17C41B11C48BAEF2B5760BB38D272F46DCE46C6032936BF37DAC918814C63}\string}}\endgraf\noindent +\dtt{->\printnumber{\xintHexToDec{11A9397C66949A97051F7D0A817914E3E0B17C41B11C48BAEF2B5760BB38D272F46DCE46C6032936BF37DAC918814C63}}} + +\subsection{\csh{xintBinToDec}}\label{xintBinToDec} + +Converts from binary to decimal.\etype{f} + +\texttt{\string\xintBinToDec + \string{\printnumber{100011010100100111001011111000110011010010100100110101001011100000101000111110111110100001010100000010111100100010100111000111110000010110001011111000100000110110001000111000100100010111010111011110010101101010111011000001011101100111000110100100111001011110100011011011100111001000110110001100000001100101001001101101011111100110111110110101100100100011000100000010100110001100011}\string}}\endgraf\noindent +\dtt{->\printnumber{\xintBinToDec{100011010100100111001011111000110011010010100100110101001011100000101000111110111110100001010100000010111100100010100111000111110000010110001011111000100000110110001000111000100100010111010111011110010101101010111011000001011101100111000110100100111001011110100011011011100111001000110110001100000001100101001001101101011111100110111110110101100100100011000100000010100110001100011}}} + +\subsection{\csh{xintBinToHex}}\label{xintBinToHex} + +Converts from binary to hexadecimal.\etype{f} The input is first zero-filled +to |4N| binary digits, hence the output will have |N| hexadecimal digits +(thus, if the input did not have a leading zero, the output will not either). + +\texttt{\string\xintBinToHex + \string{\printnumber{100011010100100111001011111000110011010010100100110101001011100000101000111110111110100001010100000010111100100010100111000111110000010110001011111000100000110110001000111000100100010111010111011110010101101010111011000001011101100111000110100100111001011110100011011011100111001000110110001100000001100101001001101101011111100110111110110101100100100011000100000010100110001100011}\string}}\endgraf\noindent +\dtt{->\printnumber{\xintBinToHex{100011010100100111001011111000110011010010100100110101001011100000101000111110111110100001010100000010111100100010100111000111110000010110001011111000100000110110001000111000100100010111010111011110010101101010111011000001011101100111000110100100111001011110100011011011100111001000110110001100000001100101001001101101011111100110111110110101100100100011000100000010100110001100011}}} + +\subsection{\csh{xintHexToBin}}\label{xintHexToBin} + +Converts from hexadecimal to binary. Up to three leading zeroes of the output +are trimmed.\etype{f} + +\texttt{\string\xintHexToBin + \string{\printnumber{11A9397C66949A97051F7D0A817914E3E0B17C41B11C48BAEF2B5760BB38D272F46DCE46C6032936BF37DAC918814C63}\string}}\endgraf\noindent +\dtt{->\printnumber{\xintHexToBin{11A9397C66949A97051F7D0A817914E3E0B17C41B11C48BAEF2B5760BB38D272F46DCE46C6032936BF37DAC918814C63}}} + +\subsection{\csh{xintCHexToBin}}\label{xintCHexToBin} + +Converts from hexadecimal to binary.\etype{f} Same as \csbxint{HexToBin}, but +an input with |N| hexadecimal digits will give an output with exactly |4N| +binary digits, leading zeroes are not trimmed. + +\texttt{\string\xintCHexToBin + \string{\printnumber{11A9397C66949A97051F7D0A817914E3E0B17C41B11C48BAEF2B5760BB38D272F46DCE46C6032936BF37DAC918814C63}\string}}\endgraf\noindent +\dtt{->\printnumber{\xintCHexToBin{11A9397C66949A97051F7D0A817914E3E0B17C41B11C48BAEF2B5760BB38D272F46DCE46C6032936BF37DAC918814C63}}} + +This can be combined with \csbxint{BinToHex} for round-trips preserving +leading zeroes for |4N| binary digits numbers, whereas using +\csbxint{HexToBin} gives reproducing round-trips only for |4N| binary numbers +numbers not starting with |0000|. +\begin{everbatim*} +This zero-fills to 4N digits the input, hence gives here a leading zero in output: +\xintBinToHex{0001111}\newline +Chaining, we end up with 4N-3 digits, as three binary zeroes are trimmed: +\xintHexToBin{\xintBinToHex{0001111}}\newline +But this will always reproduce the initial input zero-filled to length 4N: +\xintCHexToBin{\xintBinToHex{0001111}}\par +Another example (visible space characters manually inserted):\newline +$000000001111101001010001\xrightarrow{\text{\string\xintBinToHex}} +\xintBinToHex{000000001111101001010001}\xrightarrow{\text{\string\xintHexToBin\hphantom{X}}} +\text{\textvisiblespace\textvisiblespace\textvisiblespace} +\xintHexToBin{\xintBinToHex{000000001111101001010001}}$\newline +$000000001111101001010001\xrightarrow{\text{\string\xintBinToHex}} +\xintBinToHex{000000001111101001010001}\xrightarrow{\text{\string\xintCHexToBin}} +\xintCHexToBin{\xintBinToHex{000000001111101001010001}}$ +\par +\end{everbatim*} +\clearpage +\let\xintbinhexnameUp\undefined +\csname xintgcdnameUp\endcsname +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} +\section{Macros of the \xintgcdname package} +\RaisedLabel{sec:gcd} + +\localtableofcontents + +This package was included in the original release |1.0| (|2013/03/28|) of the +\xintname bundle. + +Since release |1.09a| the macros filter their inputs through the \csbxint{Num} +macro, so one can use count registers, or fractions as long as they reduce to +integers. + +Since release |1.1|, the two ``|typeset|'' macros require the explicit +loading by the user of package \xinttoolsname. + +At |1.3d| macros \csbxint{iiGCD} and \csbxint{iiLCM} are copied over to +\xintname, hence \func{gcd} and \func{lcm} functions in \csbxint{iiexpr} are +available simply from loading \xintexprname, \xintgcdname is not +needed.\NewWith{1.3d} + + +%% \clearpage + +\subsection{\csh{xintiiGCD}}\label{xintiiGCD} + +|\xintiiGCD|\n\m\etype{ff} computes the greatest common divisor. It is +positive, except when both |N| and |M| vanish, in which case the macro returns +zero. +% +\leftedline{\csa{xintiiGCD}|{10000}{1113}|\dtt{=\xintiiGCD{10000}{1113}}} +% +\leftedline{|\xintiiGCD{123456789012345}{9876543210321}=|\dtt + {\xintiiGCD{123456789012345}{9876543210321}}} + +With release |1.3d|, this macro is also available from loading +\xintname\NewWith{1.3d}, hence also with \xintexprname, as it used by the +\func{gcd} function in \csbxint{iiexpr}, hence removes a dependency of +\xintexprname on \xintgcdname. + +\subsection{\csh{xintGCD}}\label{xintGCD} + +\csa{xintGCD} uses \csbxint{Num} overhead to make its arguments into strict +integers\etype{\Numf\Numf} first. With \xintfracname loaded this conversion +means truncation to integers. + +\subsection{\csh{xintGCDof}}\label{xintGCDof} + +\csa{xintGCDof}|{{a}{b}{c}...}|\etype{f{$\to$}{\lowast\Numf}} computes the greatest common divisor of all +integers |a|, |b|, \dots{} The list argument +may be a macro, it is \fexpan ded first and must contain at least one item. + +\subsection{\csh{xintiiLCM}}\label{xintiiLCM} + +|\xintiiLCM|\n\m\etype{ff} computes the least common multiple of integers. It +is positive, except if one |N| or |M| vanishes, in which case the macro +returns zero. +% +\leftedline{\csa{xintiiLCM}|{10000}{1113}|\dtt{=\xintiiLCM{10000}{1113}}} +% +\leftedline{|\xintiiLCM{123456789012345}{9876543210321}=|\dtt + {\xintiiLCM{123456789012345}{9876543210321}}} + +With release |1.3d|, this macro is also available from loading +\xintname\NewWith{1.3d}, hence also with \xintexprname, as it used by the +\func{lcm} function in \csbxint{iiexpr}, hence removes a dependency of +\xintexprname on \xintgcdname. + +\subsection{\csh{xintLCM}}\label{xintLCM} + +\csa{xintLCM} uses \csbxint{Num} overhead to make its arguments into strict +integers\etype{\Numf\Numf} first. With \xintfracname loaded this conversion +means truncation to integers. + +\subsection{\csh{xintLCMof}}\label{xintLCMof} + +\csa{xintLCMof}|{{a}{b}{c}...}|\etype{f{$\to$}{\lowast\Numf}} computes the least +common multiple of all integers |a|, |b|, \dots{} The list argument may be a +macro, it is \fexpan ded first and must contain at least one item. + +\subsection{\csh{xintBezout}}\label{xintBezout} + +|\xintBezout|\n\m\etype{\Numf\Numf} returns three numbers |U|, |V|, +|D| within braces where |D| is the (non-negative) GCD, and \dtt{UN + VM = D}. +\begin{everbatim*} +\oodef\X{\xintBezout {10000}{1113}}\meaning\X\par +\xintAssign {\xintBezout {10000}{1113}}\to\U\V\D +U: \meaning\U, V: \meaning\V, D: \meaning\D\par +AU+BV: \xinttheiiexpr 10000*\U+1113*\V\relax\par +\noindent\oodef\X{\xintBezout {123456789012345}{9876543210321}}\meaning\X\par +\xintAssign \X\to\U\V\D +U: \meaning\U, V: \meaning\V, D: \meaning\D\par +AU+BV: \xinttheiiexpr 123456789012345*\U+9876543210321*\V\relax +\end{everbatim*} + +\subsection{\csh{xintEuclideAlgorithm}}\label{xintEuclideAlgorithm} + +|\xintEuclideAlgorithm|\n\m\etype{\Numf\Numf} applies the Euclide algorithm +and keeps a copy of all quotients and remainders. +\begin{everbatim*} +\edef\X{\xintEuclideAlgorithm {10000}{1113}}\meaning\X +\end{everbatim*} + +The first item is the number of steps, the second is |N|, the +third is the GCD, the fourth is |M| then the first quotient and +remainder, the second quotient and remainder, \dots until the +final quotient and last (zero) remainder. + +\subsection{\csh{xintBezoutAlgorithm}}\label{xintBezoutAlgorithm} + +|\xintBezoutAlgorithm|\n\m\etype{\Numf\Numf} applies the Euclide algorithm +and keeps a copy of all quotients and remainders. Furthermore it computes the +entries of the successive products of the 2 by 2 matrices +$\left(\vcenter{\halign {\,#&\,#\cr q & 1 \cr 1 & 0 \cr}}\right)$ formed from +the quotients arising in the algorithm. +\begin{everbatim*} +\edef\X{\xintBezoutAlgorithm {10000}{1113}}\printnumber{\meaning\X} +\end{everbatim*} + +The first item is the number of steps, the second is |N|, then +|0|, |1|, the GCD, |M|, |1|, |0|, the first quotient, the first +remainder, the top left entry of the first matrix, the bottom left +entry, and then these four things at each step until the end. + +\subsection{\csh{xintTypesetEuclideAlgorithm}}\label{xintTypesetEuclideAlgorithm} + +This macro is just an example of how to organize the data returned by +\csa{xintEuclideAlgorithm}.\ntype{\Numf\Numf} Copy the source code to a new +macro and modify it to what is needed. + +\emph{Usage of this macro requires the user to load} \xinttoolsname.\IMPORTANT + +\leftedline{|\xintTypesetEuclideAlgorithm {123456789012345}{9876543210321}|} +\xintTypesetEuclideAlgorithm {123456789012345}{9876543210321} + +\subsection{\csh{xintTypesetBezoutAlgorithm}}% +\label{xintTypesetBezoutAlgorithm} + +This macro is just an example of how to organize the data returned by +\csa{xintBezoutAlgorithm}.\ntype{\Numf\Numf} Copy the source code to a new +macro and modify it to what is needed. + +\emph{Usage of this macro requires the user to load} \xinttoolsname.\IMPORTANT + +\leftedline{|\xintTypesetBezoutAlgorithm {10000}{1113}|} +\xintTypesetBezoutAlgorithm {10000}{1113} + +\clearpage +\let\xintgcdnameUp\undefined +\csname xintseriesnameUp\endcsname +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} +\section{Macros of the \xintseriesname package} +\RaisedLabel{sec:series} + +\localtableofcontents + +This package was first released with version |1.03| (|2013/04/14|) of the +\xintname bundle. + +The \Ff{} expansion type of various macro arguments is only a \Numf{} if only +\xintname but not \xintfracname is loaded. The macro \csbxint{iSeries} is +special and expects summing big integers obeying the strict format, even if +\xintfracname is loaded. + +The arguments serving as indices are of the \numx{} expansion type. + +In some cases one or two of the macro arguments are only expanded at a later +stage not immediately. + +\begin{framed} + Since |1.3|, \csbxint{Add} and \csbxint{Sub} use systematically the least + common multiple of the denominators. Some of the comments in this chapter + refer to the earlier situation where often the denominators were simply + multiplied together. \emph{They have yet to be updated to reflect the new + situation brought by the |1.3| release.} Some of these comments may now be + off-synced from the actual computation results and thus may be wrong. +\end{framed} +%% \clearpage + +\subsection{\csh{xintSeries}}\label{xintSeries} + +\csa{xintSeries}|{A}{B}{\coeff}|\etype{\numx\numx\Ff} computes +$\sum_{\text{|n=A|}}^{\text{|n=B|}}$|\coeff{n}|. The initial and final indices +must obey the |\numexpr| constraint of expanding to numbers at most |2^31-1|. +The |\coeff| macro must be a one-parameter \fexpan dable macro, taking on +input an explicit number |n| and producing some number or fraction |\coeff{n}|; +it is expanded at the time it is +needed.% +% + +\begin{everbatim*} +\def\coeff #1{\xintiiMON{#1}/#1.5} % (-1)^n/(n+1/2) +\fdef\w {\xintSeries {0}{50}{\coeff}} % we want to re-use it +\fdef\z {\xintJrr {\w}[0]} % the [0] for a microsecond gain. +% \xintJrr preferred to \xintIrr: a big common factor is suspected. +% But numbers much bigger would be needed to show the greater efficiency. +\[ \sum_{n=0}^{n=50} \frac{(-1)^n}{n+\frac12} = \xintFrac\z \] +\end{everbatim*} + +The definition of |\coeff| as |\xintiiMON{#1}/#1.5| is quite suboptimal. It +allows |#1| to be a big integer, but anyhow only small integers are accepted +as initial and final indices (they are of the \numx{} type). Second, when the +\xintfracname parser sees the |#1.5| it will remove the dot hence create a +denominator with one digit more. For example |1/3.5| turns internally into +|10/35| whereas it would be more efficient to have |2/7|. For info here is the +non-reduced |\w|: +\[\xintFrac\w\] +It would have been bigger still in releases earlier than |1.1|: now, the +\xintfracname \csbxint{Add} routine does not multiply blindly denominators +anymore, it checks if one is a multiple of the other. However it does not +practice systematic reduction to lowest terms. + +A more efficient way to code |\coeff| is illustrated next. +\begin{everbatim*} +\def\coeff #1{\the\numexpr\ifodd #1 -2\else2\fi\relax/\the\numexpr 2*#1+1\relax [0]}% +% The [0] in \coeff is a tiny optimization: in its presence the \xintfracname parser +% sees something which is already in internal format. +\fdef\w {\xintSeries {0}{50}{\coeff}} +\[\sum_{n=0}^{n=50} \frac{(-1)^n}{n+\frac12}=\xintFrac\w\] +\end{everbatim*} +The reduced form |\z| as displayed above only differs from this one by a +factor of \dtt{\xintNum {\xintDenominator\w/\xintDenominator\z}}. + +\setlength{\columnsep}{0pt} +\everb|@ +\def\coeffleibnitz #1{\the\numexpr\ifodd #1 1\else-1\fi\relax/#1[0]} +\cnta 1 +\loop +% in this loop we recompute from scratch each partial sum! +% we can afford that, as \xintSeries is fast enough. +\noindent\hbox to 2em{\hfil\texttt{\the\cnta.} }% + \xintTrunc {12}{\xintSeries {1}{\cnta}{\coeffleibnitz}}\dots +\endgraf +\ifnum\cnta < 30 \advance\cnta 1 \repeat +| + +\begin{multicols}{3} + \def\coeffleibnitz #1{\the\numexpr\ifodd #1 1\else-1\fi\relax/#1[0]} \cnta 1 + \loop + \noindent\hbox to 2em{\hfil\dtt{\the\cnta.} }% + \xintTrunc {12}{\xintSeries {1}{\cnta}{\coeffleibnitz}}\dots + \endgraf + \ifnum\cnta < 30 \advance\cnta 1 \repeat +\end{multicols} + +\subsection{\csh{xintiSeries}}\label{xintiSeries} + +\def\coeff #1{\xintiTrunc {40} + {\the\numexpr\ifodd #1 -2\else2\fi\relax/\the\numexpr 2*#1+1\relax [0]}}% + +\csa{xintiSeries}|{A}{B}{\coeff}|\etype{\numx\numx f} computes + $\sum_{\text{|n=A|}}^{\text{|n=B|}}$|\coeff{n}| where |\coeff{n}| + must \fexpan d to a (possibly long) integer in the strict format. +\everb|@ +\def\coeff #1{\xintiTrunc {40}{\xintiiMON{#1}/#1.5}}% +% better: +\def\coeff #1{\xintiTrunc {40} + {\the\numexpr 2*\xintiiMON{#1}\relax/\the\numexpr 2*#1+1\relax [0]}}% +% better still: +\def\coeff #1{\xintiTrunc {40} + {\the\numexpr\ifodd #1 -2\else2\fi\relax/\the\numexpr 2*#1+1\relax [0]}}% +% (-1)^n/(n+1/2) times 10^40, truncated to an integer. +\[ \sum_{n=0}^{n=50} \frac{(-1)^n}{n+\frac12} \approx + \xintTrunc {40}{\xintiSeries {0}{50}{\coeff}[-40]}\dots\] +| + +\[ \sum_{n=0}^{n=50} \frac{(-1)^n}{n+\frac12} \approx \xintTrunc +{40}{\xintiSeries {0}{50}{\coeff}[-40]}\] + +We should have cut out at +least the last two digits: truncating errors originating with the first +coefficients of the sum will never go away, and each truncation +introduces an uncertainty in the last digit, so as we have 40 terms, we +should trash the last two digits, or at least round at 38 digits. It is +interesting to compare with the computation where rounding rather than +truncation is used, and with the decimal +expansion of the exactly computed partial sum of the series: +\everb|@ +\def\coeff #1{\xintiRound {40} % rounding at 40 + {\the\numexpr\ifodd #1 -2\else2\fi\relax/\the\numexpr 2*#1+1\relax [0]}}% +% (-1)^n/(n+1/2) times 10^40, rounded to an integer. +\[ \sum_{n=0}^{n=50} \frac{(-1)^n}{n+\frac12} \approx + \xintTrunc {40}{\xintiSeries {0}{50}{\coeff}[-40]}\] +\def\exactcoeff #1% + {\the\numexpr\ifodd #1 -2\else2\fi\relax/\the\numexpr 2*#1+1\relax [0]}% +\[ \sum_{n=0}^{n=50} \frac{(-1)^n}{n+\frac12} + = \xintTrunc {50}{\xintSeries {0}{50}{\exactcoeff}}\dots\] +| + +\def\coeff #1{\xintiRound {40} + {\the\numexpr\ifodd #1 -2\else2\fi\relax/\the\numexpr 2*#1+1\relax [0]}}% +% (-1)^n/(n+1/2) times 10^40, rounded to an integer. +\[ \sum_{n=0}^{n=50} \frac{(-1)^n}{n+\frac12} \approx + \xintTrunc {40}{\xintiSeries {0}{50}{\coeff}[-40]}\] +\def\exactcoeff #1% + {\the\numexpr\ifodd #1 -2\else2\fi\relax/\the\numexpr 2*#1+1\relax [0]}% +\[ \sum_{n=0}^{n=50} \frac{(-1)^n}{n+\frac12} + = \xintTrunc {50}{\xintSeries {0}{50}{\exactcoeff}}\dots\] +This shows indeed that our sum of truncated terms +estimated wrongly the 39th and 40th digits of the exact result% +% +\footnote{as the series is alternating, we can roughly expect an error + of $\sqrt{40}$ and the last two digits are off by 4 units, which is + not contradictory to our expectations.} +% +and that the sum of rounded terms fared a bit better. + +\subsection{\csh{xintRationalSeries}}\label{xintRationalSeries} + + +\noindent \csa{xintRationalSeries}|{A}{B}{f}{\ratio}|\etype{\numx\numx\Ff\Ff} +evaluates $\sum_{\text{|n=A|}}^{\text{|n=B|}}$|F(n)|, where |F(n)| is specified +indirectly via the data of |f=F(A)| and the one-parameter macro |\ratio| which +must be such that |\macro{n}| expands to |F(n)/F(n-1)|. The name indicates that +\csa{xintRationalSeries} was designed to be useful in the cases where +|F(n)/F(n-1)| is a rational function of |n| but it may be anything expanding to +a fraction. The macro |\ratio| must be an expandable-only compatible macro and +expand to its value after iterated full expansion of its first item. |A| and +|B| are fed to a |\numexpr| hence may be count registers or arithmetic +expressions built with such; they must obey the \TeX{} bound. The initial term +|f| may be a macro |\f|, it will be expanded to its value representing |F(A)|. + +\begin{everbatim*} +\def\ratio #1{2/#1[0]}% 2/n, to compute exp(2) +\cnta 0 % previously declared count +\begin{quote} +\loop \fdef\z {\xintRationalSeries {0}{\cnta}{1}{\ratio }}% +\noindent$\sum_{n=0}^{\the\cnta} \frac{2^n}{n!}= + \xintTrunc{12}\z\dots= + \xintFrac\z=\xintFrac{\xintIrr\z}$\vtop to 5pt{}\par +\ifnum\cnta<20 \advance\cnta 1 \repeat +\end{quote} +\end{everbatim*} + +\begin{everbatim*} +\def\ratio #1{-1/#1[0]}% -1/n, comes from the series of exp(-1) +\cnta 0 % previously declared count +\begin{quote} +\loop +\fdef\z {\xintRationalSeries {0}{\cnta}{1}{\ratio }}% +\noindent$\sum_{n=0}^{\the\cnta} \frac{(-1)^n}{n!}= + \xintTrunc{20}\z\dots=\xintFrac{\z}=\xintFrac{\xintIrr\z}$% + \vtop to 5pt{}\par +\ifnum\cnta<20 \advance\cnta 1 \repeat +\end{quote} +\end{everbatim*} + + + \def\ratioexp #1#2{\xintDiv{#1}{#2}}% #1/#2 + +\medskip We can incorporate an indeterminate if we define |\ratio| to be +a macro with two parameters: |\def\ratioexp + #1#2{\xintDiv{#1}{#2}}|\texttt{\%}| x/n: x=#1, n=#2|. +Then, if |\x| expands to some fraction |x|, the +macro % +% +\leftedline{|\xintRationalSeries {0}{b}{1}{\ratioexp{\x}}|} +will compute $\sum_{n=0}^{n=b} x^n/n!$:\par +\begin{everbatim*} +\cnta 0 +\def\ratioexp #1#2{\xintDiv{#1}{#2}}% #1/#2 +\loop +\noindent +$\sum_{n=0}^{\the\cnta} (.57)^n/n! = \xintTrunc {50} + {\xintRationalSeries {0}{\cnta}{1}{\ratioexp{.57}}}\dots$ + \vtop to 5pt {}\endgraf +\ifnum\cnta<50 \advance\cnta 10 \repeat +\end{everbatim*} + +Observe that in this last example the |x| was directly inserted; if it +had been a more complicated explicit fraction it would have been +worthwile to use |\ratioexp\x| with |\x| defined to expand to its value. +In the further situation where this fraction |x| is not explicit but +itself defined via a complicated, and time-costly, formula, it should be +noted that \csa{xintRationalSeries} will do again the evaluation of |\x| +for each term of the partial sum. The easiest is thus when |x| can be +defined as an |\edef|. If however, you are in an expandable-only context +and cannot store in a macro like |\x| the value to be used, a variant of +\csa{xintRationalSeries} is needed which will first evaluate this |\x| and then +use this result without recomputing it. This is \csbxint{RationalSeriesX}, +documented next. + +Here is a slightly more complicated evaluation: +\begin{everbatim*} +\cnta 1 +\begin{multicols}{2} +\loop \fdef\z {\xintRationalSeries + {\cnta} + {2*\cnta-1} + {\xintiiPow {\the\cnta}{\cnta}/\xintiiFac{\cnta}} + {\ratioexp{\the\cnta}}}% +\fdef\w {\xintRationalSeries {0}{2*\cnta-1}{1}{\ratioexp{\the\cnta}}}% +\noindent +$\sum_{n=\the\cnta}^{\the\numexpr 2*\cnta-1\relax} \frac{\the\cnta^n}{n!}/% + \sum_{n=0}^{\the\numexpr 2*\cnta-1\relax} \frac{\the\cnta^n}{n!} = + \xintTrunc{8}{\xintDiv\z\w}\dots$ \vtop to 5pt{}\endgraf +\ifnum\cnta<20 \advance\cnta 1 \repeat +\end{multicols} +\end{everbatim*} + + +\subsection{\csh{xintRationalSeriesX}}\label{xintRationalSeriesX} + + +\noindent\csa{xintRationalSeriesX}|{A}{B}{\first}{\ratio}{\g}|% +\etype{\numx\numx\Ff\Ff f} is a parametrized version of \csa{xintRationalSeries} +where |\first| is now a one-parameter macro such that |\first{\g}| gives the +initial term and |\ratio| is a two-parameter macro such that |\ratio{n}{\g}| +represents the ratio of one term to the previous one. The parameter |\g| is +evaluated only once at the beginning of the computation, and can thus itself be +the yet unevaluated result of a previous computation. + +Let |\ratio| be such a two-parameter macro; note the subtle differences +between% +% +\leftedline{|\xintRationalSeries {A}{B}{\first}{\ratio{\g}}|} +% +\leftedline{and |\xintRationalSeriesX {A}{B}{\first}{\ratio}{\g}|.} First the +location of braces differ... then, in the former case |\first| is a +\emph{no-parameter} macro expanding to a fractional number, and in the latter, +it is a +\emph{one-parameter} macro which will use |\g|. Furthermore the |X| variant +will expand |\g| at the very beginning whereas the former non-|X| former variant +will evaluate it each time it needs it (which is bad if this +evaluation is time-costly, but good if |\g| is a big explicit fraction +encapsulated in a macro). + +The example will use the macro \csbxint{PowerSeries} which computes +efficiently exact partial sums of power series, and is discussed in the +next section. +\begin{everbatim*} +\def\firstterm #1{1[0]}% first term of the exponential series +% although it is the constant 1, here it must be defined as a +% one-parameter macro. Next comes the ratio function for exp: +\def\ratioexp #1#2{\xintDiv {#1}{#2}}% x/n +% These are the (-1)^{n-1}/n of the log(1+h) series: +\def\coefflog #1{\the\numexpr\ifodd #1 1\else-1\fi\relax/#1[0]}% +% Let L(h) be the first 10 terms of the log(1+h) series and +% let E(t) be the first 10 terms of the exp(t) series. +% The following computes E(L(a/10)) for a=1,...,12. +\begin{multicols}{3}\raggedcolumns +\cnta 0 +\loop +\noindent\xintTrunc {18}{% + \xintRationalSeriesX {0}{9}{\firstterm}{\ratioexp} + {\xintPowerSeries{1}{10}{\coefflog}{\the\cnta[-1]}}}\dots +\endgraf +\ifnum\cnta < 12 \advance \cnta 1 \repeat +\end{multicols} +\end{everbatim*} + + +These completely exact operations rapidly create numbers with many digits. Let +us print in full the raw fractions created by the operation illustrated above: + +\fdef\z{\xintRationalSeriesX {0}{9}{\firstterm} +{\ratioexp}{\xintPowerSeries{1}{10}{\coefflog}{1[-1]}}} + +|E(L(1[-1]))=|\dtt{\printnumber{\z}} (length of numerator: +\xintLen {\xintNumerator \z}) + +\fdef\z{\xintRationalSeriesX {0}{9}{\firstterm} +{\ratioexp}{\xintPowerSeries{1}{10}{\coefflog}{12[-2]}}} + +|E(L(12[-2]))=|\dtt{\printnumber{\z}} (length of numerator: +\xintLen {\xintNumerator \z}) + +\fdef\z{\xintRationalSeriesX {0}{9}{\firstterm} +{\ratioexp}{\xintPowerSeries{1}{10}{\coefflog}{123[-3]}}} + +|E(L(123[-3]))=|\dtt{\printnumber{\z}} (length of numerator: +\xintLen {\xintNumerator \z}) + +We see that the denominators here remain the same, as our input only had various +powers of ten as denominators, and \xintfracname efficiently assemble (some +only, as we can see) powers of ten. Notice that 1 more digit in an input +denominator seems to mean 90 more in the raw output. We can check that with some +other test cases: + +\fdef\z{\xintRationalSeriesX {0}{9}{\firstterm} +{\ratioexp}{\xintPowerSeries{1}{10}{\coefflog}{1/7}}} + +|E(L(1/7))=|\dtt{\printnumber{\z}} (length of numerator: +\xintLen {\xintNumerator \z}; length of denominator: +\xintLen {\xintDenominator \z}) + +\fdef\z{\xintRationalSeriesX {0}{9}{\firstterm} +{\ratioexp}{\xintPowerSeries{1}{10}{\coefflog}{1/71}}} + +|E(L(1/71))=|\dtt{\printnumber{\z}} (length of numerator: +\xintLen {\xintNumerator \z}; length of denominator: +\xintLen {\xintDenominator \z}) + +\fdef\z{\xintRationalSeriesX {0}{9}{\firstterm} +{\ratioexp}{\xintPowerSeries{1}{10}{\coefflog}{1/712}}} + +|E(L(1/712))=|\dtt{\printnumber{\z}} (length of numerator: +\xintLen {\xintNumerator \z}; length of denominator: +\xintLen {\xintDenominator \z}) + + +Thus +decimal numbers such as |0.123| (equivalently +|123[-3]|) give less computing intensive tasks than fractions such as |1/712|: +in the case of decimal numbers the (raw) denominators originate in the +coefficients of the series themselves, powers of ten of the input within +brackets being treated separately. And even then the +numerators will grow with the size of the input in a sort of linear way, the +coefficient being given by the order of series: here 10 from the log and 9 from +the exp, so 90. One more digit in the input means 90 more digits in the +numerator of the output: obviously we can not go on composing such partial sums +of series and hope that \xintname will joyfully do all at the speed of light! + +Hence, truncating the output (or better, rounding) is the only way to go if one +needs a general calculus of special functions. This is why the package +\xintseriesname provides, besides \csbxint{Series}, \csbxint{RationalSeries}, or +\csbxint{PowerSeries} which compute \emph{exact} sums, +\csbxint{FxPtPowerSeries} for fixed-point computations and a (tentative naive) +\csbxint{FloatPowerSeries}. + +\subsection{\csh{xintPowerSeries}}\label{xintPowerSeries} + +\csa{xintPowerSeries}|{A}{B}{\coeff}{f}|\etype{\numx\numx\Ff\Ff} +evaluates the sum +$\sum_{\text{|n=A|}}^{\text{|n=B|}}$|\coeff{n}|${}\cdot |f|^{\text{|n|}}$. The +initial and final indices are given to a |\numexpr| expression. The |\coeff| +macro (which, as argument to \csa{xintPowerSeries} is expanded only at the time +|\coeff{n}| is needed) should be defined as a one-parameter expandable macro, +its input will be an explicit number. + +The |f| can be either a fraction directly input or a macro |\f| expanding to +such a fraction. It is actually more efficient to encapsulate an explicit +fraction |f| in such a macro, if it has big numerators and denominators (`big' +means hundreds of digits) as it will then take less space in the processing +until being (repeatedly) used. + +This macro computes the \emph{exact} result (one can use it also for +polynomial evaluation), using a Horner scheme which helps avoiding a +denominator build-up (this problem however, even if using a naive additive +approach, is much less acute since release |1.1| and its new policy regarding +\csbxint{Add}). + +\begin{everbatim*} +\def\geom #1{1[0]} % the geometric series +\def\f {5/17[0]} +\[ \sum_{n=0}^{n=20} \Bigl(\frac 5{17}\Bigr)^n + =\xintFrac{\xintIrr{\xintPowerSeries {0}{20}{\geom}{\f}}} + =\xintFrac{\xinttheexpr (17^21-5^21)/12/17^20\relax}\] +\end{everbatim*} + +\begin{everbatim*} +\def\coefflog #1{1/#1[0]}% 1/n +\def\f {1/2[0]}% +\[ \log 2 \approx \sum_{n=1}^{20} \frac1{n\cdot 2^n} + = \xintFrac {\xintIrr {\xintPowerSeries {1}{20}{\coefflog}{\f}}}\] +\[ \log 2 \approx \sum_{n=1}^{50} \frac1{n\cdot 2^n} + = \xintFrac {\xintIrr {\xintPowerSeries {1}{50}{\coefflog}{\f}}}\] +\end{everbatim*} + + +\begin{everbatim*} +\setlength{\columnsep}{0pt} +\begin{multicols}{3} +\cnta 1 % previously declared count +\loop % in this loop we recompute from scratch each partial sum! +% we can afford that, as \xintPowerSeries is fast enough. +\noindent\hbox to 2em{\hfil\texttt{\the\cnta.} }% + \xintTrunc {12} + {\xintPowerSeries {1}{\cnta}{\coefflog}{\f}}\dots +\endgraf +\ifnum \cnta < 30 \advance\cnta 1 \repeat +\end{multicols} +\end{everbatim*} + + +\begin{everbatim*} +\def\coeffarctg #1{1/\the\numexpr\ifodd #1 -2*#1-1\else2*#1+1\fi\relax }% +% the above gives (-1)^n/(2n+1). The sign being in the denominator, +% **** no [0] should be added ****, +% else nothing is guaranteed to work (even if it could by sheer luck) +% Notice in passing this aspect of \numexpr: +% **** \numexpr -(1)\relax is ilegal !!! **** +\def\f {1/25[0]}% 1/5^2 +\[\mathrm{Arctg}(\frac15)\approx \frac15\sum_{n=0}^{15} \frac{(-1)^n}{(2n+1)25^n} += \xintFrac{\xintIrr {\xintDiv {\xintPowerSeries {0}{15}{\coeffarctg}{\f}}{5}}}\] +\end{everbatim*} + + +\subsection{\csh{xintPowerSeriesX}}\label{xintPowerSeriesX} + +%{\small\hspace*{\parindent}New with release |1.04|.\par} + +\noindent This is the same as \csbxint{PowerSeries}\ntype{\numx\numx\Ff\Ff} +apart +from the fact that the last parameter |f| is expanded once and for all before +being then used repeatedly. If the |f| parameter is to be an explicit big +fraction with many (dozens) digits, rather than using it directly it is slightly +better to have some macro |\g| defined to expand to the explicit fraction and +then use \csbxint{PowerSeries} with |\g|; but if |f| has not yet been evaluated +and will be the output of a complicated expansion of some |\f|, and if, due to +an expanding only context, doing |\edef\g{\f}| is no option, then +\csa{xintPowerSeriesX} should be used with |\f| as last parameter. +% +\begin{everbatim*} +\def\ratioexp #1#2{\xintDiv {#1}{#2}}% x/n +% These are the (-1)^{n-1}/n of the log(1+h) series: +\def\coefflog #1{\the\numexpr\ifodd #1 1\else-1\fi\relax/#1[0]}% +% Let L(h) be the first 10 terms of the log(1+h) series and +% let E(t) be the first 10 terms of the exp(t) series. +% The following computes L(E(a/10)-1) for a=1,..., 12. +\begin{multicols}{3}\raggedcolumns +\cnta 1 +\loop +\noindent\xintTrunc {18}{% + \xintPowerSeriesX {1}{10}{\coefflog} + {\xintSub + {\xintRationalSeries {0}{9}{1[0]}{\ratioexp{\the\cnta[-1]}}} + {1}}}\dots +\endgraf +\ifnum\cnta < 12 \advance \cnta 1 \repeat +\end{multicols} +\end{everbatim*} + + +\subsection{\csh{xintFxPtPowerSeries}}\label{xintFxPtPowerSeries} + +\csa{xintFxPtPowerSeries}|{A}{B}{\coeff}{f}{D}|\etype{\numx\numx} +computes +$\sum_{\text{|n=A|}}^{\text{|n=B|}}$|\coeff{n}|${}\cdot |f|^{\,\text{|n|}}$ with each + term of the series truncated to |D| digits\etype{\Ff\Ff\numx} + after the decimal point. As + usual, |A| and |B| are completely expanded through their inclusion in a + |\numexpr| expression. Regarding |D| it will be similarly be expanded each + time it is used inside an \csa{xintTrunc}. The one-parameter macro |\coeff| + is similarly expanded at the time it is used inside the + computations. Idem for |f|. If |f| itself is some complicated macro it is + thus better to use the variant \csbxint{FxPtPowerSeriesX} which expands it + first and then uses the result of that expansion. + +The current (|1.04|) implementation is: the first power |f^A| is +computed exactly, then \emph{truncated}. Then each successive power is +obtained from the previous one by multiplication by the exact value of +|f|, and truncated. And |\coeff{n}|\raisebox{.5ex}{|.|}|f^n| is obtained +from that by multiplying by |\coeff{n}| (untruncated) and then +truncating. Finally the sum is computed exactly. Apart from that +\csa{xintFxPtPowerSeries} (where |FxPt| means `fixed-point') is like +\csa{xintPowerSeries}. + +There should be a variant for things of the type $\sum c_n \frac {f^n}{n!}$ to +avoid having to compute the factorial from scratch at each coefficient, the same +way \csa{xintFxPtPowerSeries} does not compute |f^n| from scratch at each |n|. +Perhaps in the next package release. + +\def\coeffexp #1{1/\xintiiFac {#1}[0]}% [0] for faster parsing +\def\f {-1/2[0]}% +\newcount\cnta + +\setlength{\multicolsep}{0pt} + +\begin{multicols}{3}[% +\centeredline{$e^{-\frac12}\approx{}$}]% +\cnta 0 +\noindent\loop +$\xintFxPtPowerSeries {0}{\cnta}{\coeffexp}{\f}{20}$\\ +\ifnum\cnta<19 +\advance\cnta 1 +\repeat\par +\end{multicols} +\everb|@ +\def\coeffexp #1{1/\xintiiFac {#1}[0]}% 1/n! +\def\f {-1/2[0]}% [0] for faster input parsing +\cnta 0 % previously declared \count register +\noindent\loop +$\xintFxPtPowerSeries {0}{\cnta}{\coeffexp}{\f}{20}$\\ +\ifnum\cnta<19 \advance\cnta 1 \repeat\par +| + + +% +\leftedline{|\xintFxPtPowerSeries {0}{19}{\coeffexp}{\f}{25}=| +\dtt{\xintFxPtPowerSeries {0}{19}{\coeffexp}{\f}{25}}} +\fdef\z{\xintIrr {\xintPowerSeries {0}{19}{\coeffexp}{\f}}} +% + +\texttt{\hyphenchar\font45 }% +It is no difficulty for \xintfracname to compute exactly, with the help +of \csa{xintPowerSeries}, the nineteenth partial sum, and to then give +(the start of) its exact decimal expansion: +% +\leftedline{|\xintPowerSeries {0}{19}{\coeffexp}{\f}| ${}= + \displaystyle\xintFrac{\z}$% + \vphantom{\vrule height 20pt depth 12pt}}% +% +\leftedline{${}=\xintTrunc {30}{\z}\dots$} Thus, one should always +estimate a priori how many ending digits are not reliable: if there are +|N| terms and |N| has |k| digits, then digits up to but excluding the +last |k| may usually be trusted. If we are optimistic and the series is +alternating we may even replace |N| with $\sqrt{|N|}$ to get the number |k| +of digits possibly of dubious significance. + +\subsection{\csh{xintFxPtPowerSeriesX}}\label{xintFxPtPowerSeriesX} + + +\noindent\csa{xintFxPtPowerSeriesX}|{A}{B}{\coeff}{\f}{D}|% +\ntype{\numx\numx} +computes, exactly as +\csa{xintFxPtPowerSeries}, the sum of +|\coeff{n}|\raisebox{.5ex}{|.|}|\f^n|\etype{\Ff\Ff\numx} from |n=A| to |n=B| with each term +of the series being \emph{truncated} to |D| digits after the decimal +point. The sole difference is that |\f| is first expanded and it +is the result of this which is used in the computations. + + +Let us illustrate this on the numerical exploration of the identity +% +\leftedline{|log(1+x) = -log(1/(1+x))|} +% +Let |L(h)=log(1+h)|, and |D(h)=L(h)+L(-h/(1+h))|. Theoretically thus, +|D(h)=0| but we shall evaluate |L(h)| and |-h/(1+h)| keeping only 10 +terms of their respective series. We will assume $|h|<0.5$. With only +ten terms kept in the power series we do not have quite 3 digits +precision as $2^{10}=1024$. So it wouldn't make sense to evaluate things +more precisely than, say circa 5 digits after the decimal points. +\begin{everbatim*} +\cnta 0 +\def\coefflog #1{\the\numexpr\ifodd#1 1\else-1\fi\relax/#1[0]}% (-1)^{n-1}/n +\def\coeffalt #1{\the\numexpr\ifodd#1 -1\else1\fi\relax [0]}% (-1)^n +\begin{multicols}2 +\loop +\noindent \hbox to 2.5cm {\hss\texttt{D(\the\cnta/100): }}% +\xintAdd {\xintFxPtPowerSeriesX {1}{10}{\coefflog}{\the\cnta [-2]}{5}} + {\xintFxPtPowerSeriesX {1}{10}{\coefflog} + {\xintFxPtPowerSeriesX {1}{10}{\coeffalt}{\the\cnta [-2]}{5}} + {5}}\endgraf +\ifnum\cnta < 49 \advance\cnta 7 \repeat +\end{multicols} +\end{everbatim*} + + +Let's say we evaluate functions on |[-1/2,+1/2]| with values more or less also +in |[-1/2,+1/2]| and we want to keep 4 digits of precision. So, roughly we need +at least 14 terms in series like the geometric or log series. Let's make this +15. Then it doesn't make sense to compute intermediate summands with more than 6 +digits precision. So we compute with 6 digits +precision but return only 4 digits (rounded) after the decimal point. +This result with 4 post-decimal points precision is then used as input +to the next evaluation. +\begin{everbatim*} +\begin{multicols}2 +\loop +\noindent \hbox to 2.5cm {\hss\texttt{D(\the\cnta/100): }}% +\dtt{\xintRound{4} + {\xintAdd {\xintFxPtPowerSeriesX {1}{15}{\coefflog}{\the\cnta [-2]}{6}} + {\xintFxPtPowerSeriesX {1}{15}{\coefflog} + {\xintRound {4}{\xintFxPtPowerSeriesX {1}{15}{\coeffalt} + {\the\cnta [-2]}{6}}} + {6}}% + }}\endgraf +\ifnum\cnta < 49 \advance\cnta 7 \repeat +\end{multicols} +\end{everbatim*} + +Not bad... I have cheated a bit: the `four-digits precise' numeric +evaluations were left unrounded in the final addition. However the inner +rounding to four digits worked fine and made the next step faster than +it would have been with longer inputs. The morale is that one should not +use the raw results of \csa{xintFxPtPowerSeriesX} with the |D| digits +with which it was computed, as the last are to be considered garbage. +Rather, one should keep from the output only some smaller number of +digits. This will make further computations faster and not less precise. +I guess there should be some macro to do this final truncating, or +better, rounding, at a given number |D'<D| of digits. Maybe for the next +release. + +\subsection{\csh{xintFloatPowerSeries}}\label{xintFloatPowerSeries} + + +\noindent\csa{xintFloatPowerSeries}|[P]{A}{B}{\coeff}{f}|% +\ntype{{\upshape[\numx]}\numx\numx} + computes +$\sum_{\text{|n=A|}}^{\text{|n=B|}}$|\coeff{n}|${}\cdot |f|^{\,\text{|n|}}$ +with a floating point +precision given by the optional parameter |P| or by the current setting of +|\xintDigits|.\etype{\Ff\Ff} + +In the current, preliminary, version, no attempt has been made to try to +guarantee to the final result the precision |P|. Rather, |P| is used for all +intermediate floating point evaluations. So +rounding errors will make some of the last printed digits invalid. The +operations done are first the evaluation of |f^A| using \csa{xintFloatPow}, then +each successive power is obtained from this first one by multiplication by |f| +using \csa{xintFloatMul}, then again with \csa{xintFloatMul} this is multiplied +with |\coeff{n}|, and the sum is done adding one term at a time with +\csa{xintFloatAdd}. To sum up, this is just the naive transformation of +\csa{xintFxPtPowerSeries} from fixed point to floating point. + +\def\coefflog #1{\the\numexpr\ifodd#1 1\else-1\fi\relax/#1[0]}% + +\everb+@ +\def\coefflog #1{\the\numexpr\ifodd#1 1\else-1\fi\relax/#1[0]}% +\xintFloatPowerSeries [8]{1}{30}{\coefflog}{-1/2[0]} ++ + +% +\leftedline{\dtt{\xintFloatPowerSeries [8]{1}{30}{\coefflog}{-1/2[0]}}} + +\subsection{\csh{xintFloatPowerSeriesX}}\label{xintFloatPowerSeriesX} + + +\noindent\csa{xintFloatPowerSeriesX}|[P]{A}{B}{\coeff}{f}|% +\ntype{{\upshape[\numx]}\numx\numx} +is like +\csa{xintFloatPowerSeries} with the difference that |f| is +expanded once\etype{\Ff\Ff} +and for all at the start of the computation, thus allowing +efficient chaining of such series evaluations. +\def\coefflog #1{\the\numexpr\ifodd#1 1\else-1\fi\relax/#1[0]}% + +\everb+@ +\def\coeffexp #1{1/\xintiiFac {#1}[0]}% 1/n! (exact, not float) +\def\coefflog #1{\the\numexpr\ifodd#1 1\else-1\fi\relax/#1[0]}% +\xintFloatPowerSeriesX [8]{0}{30}{\coeffexp} + {\xintFloatPowerSeries [8]{1}{30}{\coefflog}{-1/2[0]}} ++ + +% +\leftedline{\dtt{\xintFloatPowerSeriesX [8]{0}{30}{\coeffexp} + {\xintFloatPowerSeries [8]{1}{30}{\coefflog}{-1/2[0]}}}} + +\subsection{Computing \texorpdfstring{$\log 2$}{log(2)} and \texorpdfstring{$\pi$}{pi}}\label{ssec:Machin} + +In this final section, the use of \csbxint{FxPtPowerSeries} (and +\csbxint{PowerSeries}) will be +illustrated on the (expandable... why make things simple when it is so easy to +make them difficult!) computations of the first digits of the decimal expansion +of the familiar constants $\log 2$ and $\pi$. + +Let us start with $\log 2$. We will get it from this formula (which is +left as an exercise): % +% +\leftedline{\dtt{log(2)=-2\,log(1-13/256)-% + 5\,log(1-1/9)}} +% +The number of terms to be kept in the log series, for a desired +precision of |10^{-D}| was roughly estimated without much theoretical +analysis. Computing exactly the partial sums with \csa{xintPowerSeries} +and then printing the truncated values, from |D=0| up to |D=100| showed +that it worked in terms of quality of the approximation. Because of +possible strings of zeroes or nines in the exact decimal expansion (in +the present case of $\log 2$, strings of zeroes around the fourtieth and +the sixtieth decimals), this +does not mean though that all digits printed were always exact. In +the end one always end up having to compute at some higher level of +desired precision to validate the earlier result. + +Then we tried with \csa{xintFxPtPowerSeries}: this is worthwile only for +|D|'s at least 50, as the exact evaluations are faster (with these +short-length |f|'s) for a lower +number of digits. And as expected the degradation in the quality of +approximation was in this range of the order of two or three digits. +This meant roughly that the 3+1=4 ending digits were wrong. Again, we ended +up having to compute with five more digits and compare with the earlier +value to validate it. We use truncation rather than rounding because our +goal is not to obtain the correct rounded decimal expansion but the +correct exact truncated one. + +% 693147180559945309417232121458176568075500134360255254120680009493 + +\begin{everbatim*} +\def\coefflog #1{1/#1[0]}% 1/n +\def\xa {13/256[0]}% we will compute log(1-13/256) +\def\xb {1/9[0]}% we will compute log(1-1/9) +\def\LogTwo #1% +% get log(2)=-2log(1-13/256)- 5log(1-1/9) +{% we want to use \printnumber, hence need something expanding in two steps + % only, so we use here the \romannumeral0 method + \romannumeral0\expandafter\LogTwoDoIt \expandafter + % Nb Terms for 1/9: + {\the\numexpr #1*150/143\expandafter}\expandafter + % Nb Terms for 13/256: + {\the\numexpr #1*100/129\expandafter}\expandafter + % We print #1 digits, but we know the ending ones are garbage + {\the\numexpr #1\relax}% allows #1 to be a count register +}% +\def\LogTwoDoIt #1#2#3% +% #1=nb of terms for 1/9, #2=nb of terms for 13/256, +{% #3=nb of digits for computations, also used for printing + \xinttrunc {#3} % lowercase form to stop the \romannumeral0 expansion! + {\xintAdd + {\xintMul {2}{\xintFxPtPowerSeries {1}{#2}{\coefflog}{\xa}{#3}}} + {\xintMul {5}{\xintFxPtPowerSeries {1}{#1}{\coefflog}{\xb}{#3}}}% + }% +}% +\noindent $\log 2 \approx \LogTwo {60}\dots$\endgraf +\noindent\phantom{$\log 2$}${}\approx{}$\printnumber{\LogTwo {65}}\dots\endgraf +\noindent\phantom{$\log 2$}${}\approx{}$\printnumber{\LogTwo {70}}\dots\endgraf +\end{everbatim*} + +Here is the code doing an exact evaluation of the partial sums. We have +added a |+1| to the number of digits for estimating the number of terms +to keep from the log series: we experimented that this gets exactly the +first |D| digits, for all values from |D=0| to |D=100|, except in one +case (|D=40|) where the last digit is wrong. For values of |D| +higher than |100| it is more efficient to use the code using +\csa{xintFxPtPowerSeries}. +\everb|@ +\def\LogTwo #1% get log(2)=-2log(1-13/256)- 5log(1-1/9) +{% + \romannumeral0\expandafter\LogTwoDoIt \expandafter + {\the\numexpr (#1+1)*150/143\expandafter}\expandafter + {\the\numexpr (#1+1)*100/129\expandafter}\expandafter + {\the\numexpr #1\relax}% +}% +\def\LogTwoDoIt #1#2#3% +{% #3=nb of digits for truncating an EXACT partial sum + \xinttrunc {#3} + {\xintAdd + {\xintMul {2}{\xintPowerSeries {1}{#2}{\coefflog}{\xa}}} + {\xintMul {5}{\xintPowerSeries {1}{#1}{\coefflog}{\xb}}}% + }% +}% +| + +Let us turn now to Pi, computed with the Machin formula (but see also the +approach via the \hyperlink{BrentSalamin}{Brent-Salamin algorithm} with +\csa{xintfloatexpr}) Again the numbers of terms to keep in the two |arctg| +series were roughly estimated, and some experimentations showed that removing +the last three digits was enough (at least for |D=0-100| range). And the +algorithm does print the correct digits when used with |D=1000| (to be +convinced of that one needs to run it for |D=1000| and again, say for +|D=1010|.) A theoretical analysis could help confirm that this algorithm +always gets better than |10^{-D}| precision, but again, strings of zeroes or +nines encountered in the decimal expansion may falsify the ending digits, +nines may be zeroes (and the last non-nine one should be increased) and zeroes +may be nine (and the last non-zero one should be decreased). + +\hypertarget{MachinCode}{} +\begin{everbatim*} +\def\coeffarctg #1{\the\numexpr\ifodd#1 -1\else1\fi\relax/% + \the\numexpr 2*#1+1\relax [0]}% +%\def\coeffarctg #1{\romannumeral0\xintmon{#1}/\the\numexpr 2*#1+1\relax }% +\def\xa {1/25[0]}% 1/5^2, the [0] for faster parsing +\def\xb {1/57121[0]}% 1/239^2, the [0] for faster parsing +\def\Machin #1{% #1 may be a count register, \Machin {\mycount} is allowed + \romannumeral0\expandafter\MachinA \expandafter + % number of terms for arctg(1/5): + {\the\numexpr (#1+3)*5/7\expandafter}\expandafter + % number of terms for arctg(1/239): + {\the\numexpr (#1+3)*10/45\expandafter}\expandafter + % do the computations with 3 additional digits: + {\the\numexpr #1+3\expandafter}\expandafter + % allow #1 to be a count register: + {\the\numexpr #1\relax }}% +\def\MachinA #1#2#3#4% +{\xinttrunc {#4} + {\xintSub + {\xintMul {16/5}{\xintFxPtPowerSeries {0}{#1}{\coeffarctg}{\xa}{#3}}} + {\xintMul{4/239}{\xintFxPtPowerSeries {0}{#2}{\coeffarctg}{\xb}{#3}}}% + }}% +\begin{framed} + \[ \pi = \Machin {60}\dots \] +\end{framed} +\end{everbatim*} + +Here is a variant|\MachinBis|, +which evaluates the partial sums \emph{exactly} using +\csa{xintPowerSeries}, before their final truncation. No need for a +``|+3|'' then. +\begin{everbatim*} +\def\MachinBis #1{% #1 may be a count register, +% the final result will be truncated to #1 digits post decimal point + \romannumeral0\expandafter\MachinBisA \expandafter + % number of terms for arctg(1/5): + {\the\numexpr #1*5/7\expandafter}\expandafter + % number of terms for arctg(1/239): + {\the\numexpr #1*10/45\expandafter}\expandafter + % allow #1 to be a count register: + {\the\numexpr #1\relax }}% +\def\MachinBisA #1#2#3% +{\xinttrunc {#3} % + {\xintSub + {\xintMul {16/5}{\xintPowerSeries {0}{#1}{\coeffarctg}{\xa}}} + {\xintMul{4/239}{\xintPowerSeries {0}{#2}{\coeffarctg}{\xb}}}% +}}% +\end{everbatim*} + +Let us use this variant for a loop showing the build-up of digits: +\begin{everbatim*} +\begin{multicols}{2} + \cnta 0 % previously declared \count register + \loop \noindent + \centeredline{\dtt{\MachinBis{\cnta}}}% + \ifnum\cnta < 30 + \advance\cnta 1 \repeat +\end{multicols} +\end{everbatim*} + +\hypertarget{Machin1000}{} +% +You want more digits and have some time? compile this copy of the +\hyperlink{MachinCode}{|\Machin|} with |etex| (or |pdftex|): +% +\everb|@ +% Compile with e-TeX extensions enabled (etex, pdftex, ...) +\input xintfrac.sty +\input xintseries.sty +% pi = 16 Arctg(1/5) - 4 Arctg(1/239) (John Machin's formula) +\def\coeffarctg #1{\the\numexpr\ifodd#1 -1\else1\fi\relax/% + \the\numexpr 2*#1+1\relax [0]}% +\def\xa {1/25[0]}% +\def\xb {1/57121[0]}% +\def\Machin #1{% + \romannumeral0\expandafter\MachinA \expandafter + {\the\numexpr (#1+3)*5/7\expandafter}\expandafter + {\the\numexpr (#1+3)*10/45\expandafter}\expandafter + {\the\numexpr #1+3\expandafter}\expandafter + {\the\numexpr #1\relax }}% +\def\MachinA #1#2#3#4% +{\xinttrunc {#4} + {\xintSub + {\xintMul {16/5}{\xintFxPtPowerSeries {0}{#1}{\coeffarctg}{\xa}{#3}}} + {\xintMul {4/239}{\xintFxPtPowerSeries {0}{#2}{\coeffarctg}{\xb}{#3}}}% +}}% +\pdfresettimer +\fdef\Z {\Machin {1000}} +\odef\W {\the\pdfelapsedtime} +\message{\Z} +\message{computed in \xintRound {2}{\W/65536} seconds.} +\bye +| + +This will log the first 1000 digits of $\pi$ after the decimal point. On my +laptop (a 2012 model) this took about $5.05$ seconds last time I tried.% +% +\footnote{With \texttt{1.09i} and earlier \xintname, this used to be \dtt{42} + seconds; starting with \texttt{1.09j}, and prior to \texttt{1.2}, it was + \dtt{16} seconds (this was probably due to a more efficient division with + denominators at most $9999$). The |1.2| \xintcorename achieves a further + gain at \dtt{5.6} seconds.} +% +\footnote{With |\xintDigits:=1001;|, the non-optimized implementation with the + |iter| of \xintexprname fame using the + \hyperlink{BrentSalamin}{Brent-Salamin algorithm}, took, last time I tried + (1.2i), about \dtt{7} seconds on my laptop (the last two digits were wrong, + which is ok as they serve as guard digits), and for obtaining about + \dtt{500} digits, it was about \dtt{1.7}s. This is not bad, taking into + account that the syntax is almost free rolling speech, contrarily to the + code above for the Machin formula computation; we would like to use the + quadratically convergent Brent-Salamin algorithm for more digits, but with + such computations with numbers of one thousand digits we are beyond the + border of the reasonable range for \xintname. Innocent people not knowing + what it means to compute with \TeX, and with the extra constraint of + expandability will wonder why this is at least thousands of times slower + than with any other language (with a little Python program using the + |Decimal| library, I timed the Brent-Salamin algorithm to \dtt{4.4ms} for + about |1000| digits and \dtt{1.14ms} for |500| digits.) I will just say that + for example digits are represented and manipulated via their ascii-code ! + all computations must convert from ascii-code to cpu words; furthermore + nothing can be stored away. And there is no memory storage with |O(1)| time + access... if expandability is to be verified.} +% + + +As mentioned in the +introduction, the file \href{http://www.ctan.org/pkg/pi}{pi.tex} by \textsc{D. + Roegel} shows that orders of magnitude faster computations are possible within +\TeX{}, but recall our constraints of complete expandability and be merciful, +please. + +\textbf{Why truncating rather than rounding?} One of our main competitors +on the market of scientific computing, a canadian product (not +encumbered with expandability constraints, and having barely ever heard +of \TeX{} ;-), prints numbers rounded in the last digit. Why didn't we +follow suit in the macros \csa{xintFxPtPowerSeries} and +\csa{xintFxPtPowerSeriesX}? To round at |D| digits, and excluding a +rewrite or cloning of the division algorithm which anyhow would add to +it some overhead in its final steps, \xintfracname needs to truncate at +|D+1|, then round. And rounding loses information! So, with more time +spent, we obtain a worst result than the one truncated at |D+1| (one +could imagine that additions and so on, done with only |D| digits, cost +less; true, but this is a negligeable effect per summand compared to the +additional cost for this term of having been truncated at |D+1| then +rounded). Rounding is the way to go when setting up algorithms to +evaluate functions destined to be composed one after the other: exact +algebraic operations with many summands and an |f| variable which is a +fraction are costly and create an even bigger fraction; replacing |f| +with a reasonable rounding, and rounding the result, is necessary to +allow arbitrary chaining. + +But, for the +computation of a single constant, we are really interested in the exact +decimal expansion, so we truncate and compute more terms until the +earlier result gets validated. Finally if we do want the rounding we can +always do it on a value computed with |D+1| truncation. + +\clearpage +\let\xintseriesnameUp\undefined +\csname xintcfracnameUp\endcsname +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} +\section{Macros of the \xintcfracname package} +\RaisedLabel{sec:cfrac} + +\localtableofcontents + +First version of this package was included in release |1.04| (|2013/04/25|) of the +\xintname bundle. It was kept almost unchanged until |1.09m| of |2014/02/26| +which brought some new macros: \csbxint{FtoC}, \csbxint{CtoF}, \csbxint{CtoCv}, +dealing with sequences of braced partial quotients rather than comma separated +ones, \csbxint{FGtoC} which is to produce ``guaranteed'' coefficients of some +real number known approximately, and \csbxint{GGCFrac} for displaying arbitrary +material as a continued fraction; also, some changes to existing macros: +\csbxint{FtoCs} and \csbxint{CntoCs} insert spaces after the commas, +\csbxint{CstoF} and \csbxint{CstoCv} authorize spaces in the input also before +the commas. + +Note: \csbxint{CstoF} and \csbxint{CstoCv} create a partial dependency on +\xinttoolsname (its \csbxint{CSVtoList}.) + +This section contains: +\begin{enumerate} +\item an \hyperref[ssec:cfracoverview]{overview} of the package functionalities, +\item a description of each one of the package macros, +\item further illustration of their use via the study of the + \hyperref[ssec:e-convergents]{convergents of $e$}. +\end{enumerate} + +\subsection{Package overview}\label{ssec:cfracoverview} + +The package computes partial quotients and convergents of a fraction, or +conversely start from coefficients and obtain the corresponding fraction; three +macros \csbxint {CFrac}, \csbxint {GCFrac} and \csbxint {GGCFrac} are +for typesetting (the first two assume that the coefficients are numeric +quantities acceptable by the \xintfracname \csbxint{Frac} macro, the +last one will display arbitrary material), the others +can be nested (if applicable) or see their outputs further processed by other +macros from the \xintname bundle, particularly the macros of \xinttoolsname +dealing with sequences of braced items or comma separated lists. + +A \emph{simple} continued fraction has coefficients +|[c0,c1,...,cN]| (usually called partial quotients, but I +dislike this entrenched terminology), where |c0| is a positive or +negative integer and the others are positive integers. + +Typesetting is usually done via the |amsmath| macro |\cfrac|: +\begin{everbatim*} +\[ c_0 + \cfrac{1}{c_1+\cfrac1{c_2+\cfrac1{c_3+\cfrac1{\ddots}}}}\] +\end{everbatim*} + +Here is a concrete example: +\begin{everbatim*} +\[ \xintFrac {208341/66317}=\xintCFrac {208341/66317}\]% +\end{everbatim*} +But it is the macro \csbxint{CFrac} which did all the work of \emph{computing} +the continued fraction \emph{and} using |\cfrac| from |amsmath| to typeset +it. + +A \emph{generalized} continued fraction has the same structure but the +numerators are not restricted to be $1$, and numbers used in the continued +fraction may be arbitrary, also fractions, irrationals, complex, +indeterminates.% +% +\footnote{\xintcfracname may be used with indeterminates, + for basic conversions from one inline format to another, but not for + actual computations. See \csbxint{GGCFrac}.} +% +The \emph{centered} continued fraction is an +example: +\begin{everbatim*} +\[ \xintFrac {915286/188421}=\xintGCFrac {5+-1/7+1/39+-1/53+-1/13} + =\xintCFrac {915286/188421}\] +\end{everbatim*} + +The macro \csbxint{GCFrac}, contrarily to +\csbxint{CFrac}, does not compute anything, it just typesets starting from a +generalized continued fraction in inline format, which in this example +was input literally. We also used \csa{xintCFrac} +for comparison of the two types of continued fractions. + +To let \TeX{} compute the centered continued fraction of |f| there is +\csbxint{FtoCC}: +\begin{everbatim*} +\[\xintFrac {915286/188421}\to\xintFtoCC {915286/188421}\] +\end{everbatim*} +The package macros are expandable and may be nested (naturally \csa{xintCFrac} +and \csa{xintGCFrac} must be at the top level, as they deal with typesetting). +\begin{everbatim*} +\[\xintGCFrac {\xintFtoCC{915286/188421}}\] +\end{everbatim*} + +The `inline' format expected on input by \csbxint{GCFrac} is +% +\leftedline{$a_0+b_0/a_1+b_1/a_2+b_2/a_3+\cdots+b_{n-2}/a_{n-1}+b_{n-1}/a_n$} +% +Fractions among the coefficients are allowed but they must be enclosed +within braces. Signed integers may be left without braces (but the |+| +signs are mandatory). No spaces are allowed around the plus and fraction +symbols. The coefficients may themselves be macros, as long as these +macros are \fexpan dable. +\begin{everbatim*} +\[ \xintFrac{\xintGCtoF {1+-1/57+\xintPow {-3}{7}/\xintiiQuo {132}{25}}} + = \xintGCFrac {1+-1/57+\xintPow {-3}{7}/\xintiiQuo {132}{25}}\] +\end{everbatim*} +To compute the actual fraction one has \csbxint{GCtoF}: +\begin{everbatim*} +\[\xintFrac{\xintGCtoF {1+-1/57+\xintPow {-3}{7}/\xintiiQuo {132}{25}}}\] +\end{everbatim*} +For non-numeric input there is \csbxint{GGCFrac}. +\begin{everbatim*} +\[\xintGGCFrac {a_0+b_0/a_1+b_1/a_2+b_2/\ddots+\ddots/a_{n-1}+b_{n-1}/a_n}\] +\end{everbatim*} +For regular continued fractions, there is a simpler comma separated format: +\begin{everbatim*} +\[-7,6,19,1,33\to\xintFrac{\xintCstoF{-7,6,19,1,33}}=\xintCFrac{\xintCstoF{-7,6,19,1,33}}\] +\end{everbatim*} +The macro \csbxint{FtoCs} produces from a fraction |f| the comma separated +list of its coefficients. +\begin{everbatim*} +\[\xintFrac{1084483/398959}=[\xintFtoCs{1084483/398959}]\] +\end{everbatim*} +If one prefers other separators, one can use the two arguments macros +\csbxint{FtoCx} whose first argument is the separator (which may consist of more +than one token) which is to be used. +\begin{everbatim*} +\[\xintFrac{2721/1001}=\xintFtoCx {+1/(}{2721/1001})\cdots)\] +\end{everbatim*} +This allows under Plain \TeX{} with |amstex| to obtain the same effect +as with \LaTeX{}+|\amsmath|+\csbxint{CFrac}: +% +\leftedline{|$$\xintFwOver{2721/1001}=\xintFtoCx {+\cfrac1\\ }{2721/1001}\endcfrac$$|} + +As a shortcut to \csa{xintFtoCx} with separator |1+/|, there is +\csbxint{FtoGC}: +\begin{everbatim*} +2721/1001=\xintFtoGC {2721/1001} +\end{everbatim*} +Let us compare in that case with the output of \csbxint{FtoCC}: +\begin{everbatim*} +2721/1001=\xintFtoCC {2721/1001} +\end{everbatim*} +To obtain the coefficients as a sequence of braced numbers, there is +\csbxint{FtoC} (this is a shortcut for |\xintFtoCx {}|). This list +(sequence) may then be manipulated using the various macros of \xinttoolsname +such as the non-expandable macro \csbxint{AssignArray} or the expandable +\csbxint{Apply} and \csbxint{ListWithSep}. + +Conversely to go from such a sequence of braced coefficients to the +corresponding fraction there is \csbxint{CtoF}. + +The `|\printnumber|' (\autoref{ssec:printnumber}) macro which we use in this +document to print long numbers can also be useful on long continued fractions. +% +\begin{everbatim*} +\printnumber{\xintFtoCC {35037018906350720204351049/244241737886197404558180}} +\end{everbatim*} +% +If we apply \csbxint{GCtoF} to this generalized continued fraction, we +discover that the original fraction was reducible: +% +\leftedline{|\xintGCtoF + {143+1/2+...+-1/9}|\dtt{=\xintGCtoF{143+1/2+1/5+-1/4+-1/4+-1/4+-1/3+1/2+1/2+1/6+-1/22+1/2+1/10+-1/5+-1/11+-1/3+1/4+-1/2+1/2+1/4+-1/2+1/23+1/3+1/8+-1/6+-1/9}}} + +\def\mymacro #1{$\xintFrac{#1}=[\xintFtoCs{#1}]$\vtop to 6pt{}} + +\begingroup +\catcode`^\active +\def^#1^{\hbox{#1}}% + +When a generalized continued fraction is built with integers, and +numerators are only |1|'s or |-1|'s, the produced fraction is +irreducible. And if we compute it again with the last sub-fraction +omitted we get another irreducible fraction related to the bigger one by +a Bézout identity. Doing this here we get: +% +\leftedline{|\xintGCtoF {143+1/2+...+-1/6}|\dtt{=\xintGCtoF{143+1/2+1/5+-1/4+-1/4+-1/4+-1/3+1/2+1/2+1/6+-1/22+1/2+1/10+-1/5+-1/11+-1/3+1/4+-1/2+1/2+1/4+-1/2+1/23+1/3+1/8+-1/6}}} +and indeed: +\[\begin{vmatrix} + ^2897319801297630107^ & ^328124887710626729^\\ + ^20197107104701740^ & ^2287346221788023^ + \end{vmatrix} = \mbox{\dtt{\xintiiSub {\xintiiMul {2897319801297630107}{2287346221788023}}{\xintiiMul{20197107104701740}{328124887710626729}}}}\] + +\endgroup + +The various fractions obtained from the truncation of a continued fraction to +its initial terms are called the convergents. The macros of \xintcfracname +such as \csbxint{FtoCv}, \csbxint{FtoCCv}, and others which compute such +convergents, return them as a list of braced items, with no separator (as does +\csbxint {FtoC} for the partial quotients). Here is an example: + +\begin{everbatim*} +\[\xintFrac{915286/188421}\to + \xintListWithSep{,}{\xintApply\xintFrac{\xintFtoCv{915286/188421}}}\] +\end{everbatim*} +\begin{everbatim*} +\[\xintFrac{915286/188421}\to + \xintListWithSep{,}{\xintApply\xintFrac{\xintFtoCCv{915286/188421}}}\] +\end{everbatim*} +% +We thus see that the `centered convergents' obtained with \csbxint{FtoCCv} are +among the fuller list of convergents as returned by \csbxint{FtoCv}. + +Here is a more complicated use of \csa{xintApply} +and \csa{xintListWithSep}. We first define a macro which will be applied to each +convergent:% +% +\leftedline{|\newcommand{\mymacro}[1]{$\xintFrac{#1}=[\xintFtoCs{#1}]$\vtop to 6pt{}}|} +% +Next, we use the following code: +% +\leftedline{|$\xintFrac{49171/18089}\to{}$|} +% +\leftedline{|\xintListWithSep {, + }{\xintApply{\mymacro}{\xintFtoCv{49171/18089}}}|} +It produces:\par +\noindent$ \xintFrac{49171/18089}\to {}$\xintListWithSep {, + }{\xintApply{\mymacro}{\xintFtoCv{49171/18089}}}. + +The macro \csbxint{CntoF} allows to specify the coefficients as a function given +by a one-parameter macro. The produced values do not have to be integers. +\begin{everbatim*} +\def\cn #1{\xintiiPow {2}{#1}}% 2^n + \[\xintFrac{\xintCntoF {6}{\cn}}=\xintCFrac [l]{\xintCntoF {6}{\cn}}\] +\end{everbatim*} + +Notice the use of the optional argument |[l]| to \csa{xintCFrac}. Other +possibilities are |[r]| and (default) |[c]|. +\begin{everbatim*} +\def\cn #1{\xintPow {2}{-#1}}% + \[\xintFrac{\xintCntoF {6}{\cn}}=\xintGCFrac [r]{\xintCntoGC {6}{\cn}}= + [\xintFtoCs {\xintCntoF {6}{\cn}}]\] +\end{everbatim*} +We used \csbxint{CntoGC} as we wanted to display also the continued fraction and +not only the fraction returned by \csa{xintCntoF}. + +There are also \csbxint{GCntoF} and \csbxint{GCntoGC} which allow the same for +generalized fractions. An initial portion of a generalized continued +fraction for $\pi$ is obtained like this +\begin{everbatim*} +\def\an #1{\the\numexpr 2*#1+1\relax }% +\def\bn #1{\the\numexpr (#1+1)*(#1+1)\relax }% +\[\xintFrac{\xintDiv {4}{\xintGCntoF {5}{\an}{\bn}}} = + \cfrac{4}{\xintGCFrac{\xintGCntoGC {5}{\an}{\bn}}} = + \xintTrunc {10}{\xintDiv {4}{\xintGCntoF {5}{\an}{\bn}}}\dots\] +\end{everbatim*} + +We see that the quality of approximation is not fantastic compared to the simple +continued fraction of $\pi$ with about as many terms: +\begin{everbatim*} +\[\xintFrac{\xintCstoF{3,7,15,1,292,1,1}}= + \xintGCFrac{3+1/7+1/15+1/1+1/292+1/1+1/1}= + \xintTrunc{10}{\xintCstoF{3,7,15,1,292,1,1}}\dots\] +\end{everbatim*} + +When studying the continued fraction of some real number, there is always +some doubt about how many terms are valid, when computed starting from some +approximation. If $f\leqslant x\leqslant g$ and $f, g$ both have the +same first $K$ partial quotients, then $x$ also has the same first $K$ quotients +and convergents. The macro \csbxint{FGtoC} outputs as a sequence of braced items +the common partial quotients of its two arguments. We can thus use it to produce +a sure list of valid convergents of $\pi$ for example, starting from some proven +lower and upper bound: +\begin{everbatim*} +$$\pi\to [\xintListWithSep{,} + {\xintFGtoC {3.14159265358979323}{3.14159265358979324}}, \dots]$$ +\noindent$\pi\to\xintListWithSep{,\allowbreak\;} + {\xintApply{\xintFrac} + {\xintCtoCv{\xintFGtoC {3.14159265358979323}{3.14159265358979324}}}}, \dots$ +\end{everbatim*} + + +\subsection{\csh{xintCFrac}}\label{xintCFrac} + +\csa{xintCFrac}|{f}|\ntype{\Ff} is a math-mode only, \LaTeX{} with |amsmath| +only, macro which first computes then displays with the help of |\cfrac| the +simple continued fraction corresponding to the given fraction. It admits an +optional argument which may be |[l]|, |[r]| or (the default) |[c]| to specify +the location of the one's in the numerators of the sub-fractions. Each +coefficient is typeset using the \csbxint{Frac} macro from the \xintfracname +package. This macro is \fexpan dable in the sense that it prepares expandably +the whole expression with the multiple |\cfrac|'s, but it is not completely +expandable naturally as |\cfrac| isn't. + +\subsection{\csh{xintGCFrac}}\label{xintGCFrac} + +\csa{xintGCFrac}|{a+b/c+d/e+f/g+h/...+x/y}|\ntype{f} uses similarly |\cfrac| +to prepare the typesetting with the |amsmath| |\cfrac| (\LaTeX{}) of a +generalized continued fraction given in inline format (or as macro which +will \fexpan d to it). It admits the +same optional argument as \csa{xintCFrac}. Plain \TeX{} with |amstex| +users, see \csbxint{GCtoGCx}. +\begin{everbatim*} +\[\xintGCFrac {1+\xintPow{1.5}{3}/{1/7}+{-3/5}/\xintiiFac {6}}\] +\end{everbatim*} +This is mostly a typesetting macro, although it does provoke the +expansion of the coefficients. See \csbxint{GCtoF} if you are impatient +to see this specific fraction computed. + +It admits an optional argument within square brackets which may be +either |[l]|, |[c]| or |[r]|. Default is |[c]| (numerators are centered). + +Numerators and denominators are made arguments to the \csbxint{Frac} +macro. This allows them to be themselves fractions or anything \fexpan +dable giving numbers or fractions, but also means however that they can +not be arbitrary material, they can not contain color changing macros +for example. One of the reasons is that \csa{xintGCFrac} tries to +determine the signs of the numerators and chooses accordingly to use +$+$ or $-$. + +\subsection{\csh{xintGGCFrac}}\label{xintGGCFrac} + +\csa{xintGGCFrac}|{a+b/c+d/e+f/g+h/...+x/y}|\ntype{f} is a clone of +\csbxint{GCFrac}, hence again \LaTeX{} specific with package +|amsmath|. +It does not assume the coefficients to be numbers as understood by +\xintfracname. The macro can be used for displaying arbitrary content as +a continued fraction with |\cfrac|, using only plus signs though. Note +though that it will first \fexpan d its argument, which may be thus be +one of the \xintcfracname macros producing a (general) continued +fraction in inline format, see \csbxint{FtoCx} for an example. If this +expansion is not wished, it is enough to start the argument with a +space. +\begin{everbatim*} +\[\xintGGCFrac {1+q/1+q^2/1+q^3/1+q^4/1+q^5/\ddots}\] +\end{everbatim*} + +\subsection{\csh{xintGCtoGCx}}\label{xintGCtoGCx} +%{\small New with release |1.05|.\par} + +\csa{xintGCtoGCx}|{sepa}{sepb}{a+b/c+d/e+f/...+x/y}|\etype{nnf} returns the list +of the coefficients of the generalized continued fraction of |f|, each one +within a pair of braces, and separated with the help of |sepa| and |sepb|. Thus +% +\leftedline{|\xintGCtoGCx :;{1+2/3+4/5+6/7}| gives \xintGCtoGCx + :;{1+2/3+4/5+6/7}} +% +The following can be used byt Plain \TeX{}+|amstex| users to obtain an +output similar as the ones produced by \csbxint{GCFrac} and +\csbxint{GGCFrac}:\par +\everb|@ +$$\xintGCtoGCx {+\cfrac}{\\}{a+b/...}\endcfrac$$ +$$\xintGCtoGCx {+\cfrac\xintFwOver}{\\\xintFwOver}{a+b/...}\endcfrac$$ +| + +\subsection{\csh{xintFtoC}}\label{xintFtoC} + +\csa{xintFtoC}|{f}|\etype{\Ff} computes the +coefficients of the simple continued fraction of |f| and returns them as a list +(sequence) of braced items. + +\begin{everbatim*} +\fdef\test{\xintFtoC{-5262046/89233}}\texttt{\meaning\test} +\end{everbatim*} + +\subsection{\csh{xintFtoCs}}\label{xintFtoCs} + +\csa{xintFtoCs}|{f}|\etype{\Ff} returns the comma separated list of the +coefficients of the simple continued fraction of |f|. Notice that starting with +|1.09m| a space follows each comma (mainly for usage in text mode, as in math +mode spaces are produced in the typeset output by \TeX{} itself). +\begin{everbatim*} +\[ \xintSignedFrac{-5262046/89233} \to [\xintFtoCs{-5262046/89233}]\] +\end{everbatim*} + +\subsection{\csh{xintFtoCx}}\label{xintFtoCx} + +\csa{xintFtoCx}|{sep}{f}|\etype{n\Ff} returns the list of the +coefficients of the simple continued fraction of |f| separated with the +help of |sep|, which may be anything (and is kept unexpanded). For +example, with Plain \TeX{} and |amstex|, +% +\leftedline{|$$\xintFtoCx {+\cfrac1\\ }{-5262046/89233}\endcfrac$$|} +% +will display the continued fraction using +|\cfrac|. Each coefficient is inside a brace pair \hbox{|{ }|}, allowing +a macro to end the separator and fetch it as argument, +for example, again with Plain \TeX{} and |amstex|: +\everb|@ + \def\highlight #1{\ifnum #1>200 \textcolor{red}{#1}\else #1\fi} + $$\xintFtoCx {+\cfrac1\\ \highlight}{104348/33215}\endcfrac$$ +| + +Due to the different and extremely cumbersome syntax of |\cfrac| under +\LaTeX{} it proves a bit tortuous to obtain there the same effect. +Actually, it is partly for this purpose that |1.09m| added \csbxint +{GGCFrac}. We thus use \csa{xintFtoCx} with a suitable separator, and\; +then the whole thing as argument to \csbxint{GGCFrac}: +\begin{everbatim*} +\def\highlight #1{\ifnum #1>200 \fcolorbox{blue}{white}{\boldmath\color{red}$#1$}% + \else #1\fi} +\[\xintGGCFrac {\xintFtoCx {+1/\highlight}{208341/66317}}\] +\end{everbatim*} + +\subsection{\csh{xintFtoGC}}\label{xintFtoGC} + +\csa{xintFtoGC}|{f}|\etype{\Ff} does the same as \csa{xintFtoCx}|{+1/}{f}|. Its +output may thus be used in the package macros expecting such an `inline +format'. +% This continued fraction is a \emph{simple} one, not a +% \emph{generalized} one, but as it is produced in the format used for +% user input of generalized continued fractions, the macro was called +% \csa{xintFtoGC} rather than \csa{xintFtoC} for example. +% +\begin{everbatim*} +566827/208524=\xintFtoGC {566827/208524} +\end{everbatim*} + +\subsection{\csh{xintFGtoC}}\label{xintFGtoC} + +\csa{xintFGtoC}|{f}{g}|\etype{\Ff\Ff} computes the common initial coefficients +to +two given fractions |f| and |g|. Notice that any real number |f<x<g| or |f>x>g| +will then necessarily share with |f| and |g| these common initial coefficients +for its regular continued fraction. The coefficients are output as a sequence of +braced numbers. This list can then be manipulated via macros from +\xinttoolsname, or other macros of \xintcfracname. + +\begin{everbatim*} +\fdef\test{\xintFGtoC{-5262046/89233}{-5314647/90125}}\texttt{\meaning\test} +\end{everbatim*} +\begin{everbatim*} +\fdef\test{\xintFGtoC{3.141592653}{3.141592654}}\texttt{\meaning\test} +\end{everbatim*} +\begin{everbatim*} +\fdef\test{\xintFGtoC{3.1415926535897932384}{3.1415926535897932385}}\meaning\test +\end{everbatim*} +\begin{everbatim*} +\xintRound {30}{\xintCstoF{\xintListWithSep{,}{\test}}} +\end{everbatim*} +\begin{everbatim*} +\xintRound {30}{\xintCtoF{\test}} +\end{everbatim*} +\begin{everbatim*} +\fdef\test{\xintFGtoC{1.41421356237309}{1.4142135623731}}\meaning\test +\end{everbatim*} + +\subsection{\csh{xintFtoCC}}\label{xintFtoCC} + +\csa{xintFtoCC}|{f}|\etype{\Ff} returns the `centered' continued fraction of +|f|, in `inline format'. % +\begin{everbatim*} +566827/208524=\xintFtoCC {566827/208524} +\end{everbatim*} +\begin{everbatim*} +\[\xintFrac{566827/208524} = \xintGCFrac{\xintFtoCC{566827/208524}}\] +\end{everbatim*} + +\subsection{\csh{xintCstoF}}\label{xintCstoF} + +\csa{xintCstoF}|{a,b,c,d,...,z}|\etype{f} computes the fraction corresponding to +the coefficients, which may be fractions or even macros expanding to such +fractions. The final fraction may then be highly reducible. + +\emph{Usage of this macro requires the user to load} \xinttoolsname.\IMPORTANT + +Starting with +release |1.09m| spaces before commas are allowed and trimmed automatically +(spaces after commas were already silently handled in earlier releases). +\begin{everbatim*} +\[\xintGCFrac {-1+1/3+1/-5+1/7+1/-9+1/11+1/-13}= + \xintSignedFrac{\xintCstoF {-1,3,-5,7,-9,11,-13}}=\xintSignedFrac{\xintGCtoF + {-1+1/3+1/-5+1/7+1/-9+1/11+1/-13}}\] +\end{everbatim*} +\begin{everbatim*} +\[\xintGCFrac{{1/2}+1/{1/3}+1/{1/4}+1/{1/5}}=\xintFrac{\xintCstoF {1/2,1/3,1/4,1/5}}\] +\end{everbatim*} +% +A generalized continued fraction may produce a reducible fraction +(\csa{xintCstoF} tries its best not to accumulate in a silly way superfluous +factors but will not do simplifications which would be obvious to a human, like +simplification by 3 in the result above). + +\subsection{\csh{xintCtoF}}\label{xintCtoF} + +\csa{xintCtoF}|{{a}{b}{c}...{z}}|\etype{f} computes the fraction corresponding +to the coefficients, which may be fractions or even macros. +\begin{everbatim*} +\xintCtoF {\xintApply {\xintiiPow 3}{\xintSeq {1}{5}}} +\end{everbatim*} +\begin{everbatim*} +\[ \xintFrac{14946960/4805083}=\xintCFrac {14946960/4805083}\] +\end{everbatim*} +In the example above the power of $3$ was already pre-computed via the expansion +done by |\xintApply|, but if we try with |\xintApply { \xintiiPow 3}| where the +space will stop this expansion, we can check that |\xintCtoF| will itself +provoke the needed coefficient expansion.% ok + +\subsection{\csh{xintGCtoF}}\label{xintGCtoF} + +\csa{xintGCtoF}|{a+b/c+d/e+f/g+......+v/w+x/y}|\etype{f} computes the fraction +defined by the inline generalized continued fraction. Coefficients may be +fractions but must then be put within braces. They can be macros. The plus signs +are mandatory. +\begin{everbatim*} +\[\xintGCFrac {1+\xintPow{1.5}{3}/{1/7}+{-3/5}/\xintiiFac {6}} = +\xintFrac{\xintGCtoF {1+\xintPow{1.5}{3}/{1/7}+{-3/5}/\xintiiFac {6}}} = +\xintFrac{\xintIrr{\xintGCtoF + {1+\xintPow{1.5}{3}/{1/7}+{-3/5}/\xintiiFac {6}}}}\] +\end{everbatim*} + +\begin{everbatim*} +\[ \xintGCFrac{{1/2}+{2/3}/{4/5}+{1/2}/{1/5}+{3/2}/{5/3}} = + \xintFrac{\xintGCtoF {{1/2}+{2/3}/{4/5}+{1/2}/{1/5}+{3/2}/{5/3}}} \] +\end{everbatim*} + +The macro tries its best not to accumulate superfluous factor in the +denominators, but doesn't reduce the fraction to irreducible form before +returning it and does not do simplifications which would be obvious to a human. + +\subsection{\csh{xintCstoCv}}\label{xintCstoCv} + +\csa{xintCstoCv}|{a,b,c,d,...,z}|\etype{f} returns the sequence of the +corresponding convergents, each one within braces. + +\emph{Usage of this macro requires the user to load} \xinttoolsname.\IMPORTANT + +It is allowed to use fractions as coefficients (the computed +convergents have then no reason to be the real convergents of the final +fraction). When the coefficients are integers, the convergents are irreducible +fractions, but otherwise it is not necessarily the case. +\begin{everbatim*} +\xintListWithSep:{\xintCstoCv{1,2,3,4,5,6}} +\end{everbatim*} +\begin{everbatim*} +\xintListWithSep:{\xintCstoCv{1,1/2,1/3,1/4,1/5,1/6}} +\end{everbatim*} +\begin{everbatim*} +\[\xintListWithSep{\to}{\xintApply\xintFrac{\xintCstoCv {\xintPow + {-.3}{-5},7.3/4.57,\xintCstoF{3/4,9,-1/3}}}}\] +\end{everbatim*} + +\subsection{\csh{xintCtoCv}}\label{xintCtoCv} + +\csa{xintCtoCv}|{{a}{b}{c}...{z}}|\etype{f} returns the sequence of the +corresponding convergents, each one within braces. +\begin{everbatim*} +\fdef\test{\xintCtoCv {11111111111}}\texttt{\meaning\test} +\end{everbatim*} + +\subsection{\csh{xintGCtoCv}}\label{xintGCtoCv} + +\csa{xintGCtoCv}|{a+b/c+d/e+f/g+......+v/w+x/y}|\etype{f} returns the list of +the corresponding convergents. The coefficients may be fractions, but must then +be inside braces. Or they may be macros, too. + +The convergents will in the general case be reducible. To put them into +irreducible form, one needs one more step, for example it can be done +with |\xintApply\xintIrr|. +\begin{everbatim*} +\[\xintListWithSep{,}{\xintApply\xintFrac + {\xintGCtoCv{3+{-2}/{7/2}+{3/4}/12+{-56}/3}}}\] +\[\xintListWithSep{,}{\xintApply\xintFrac{\xintApply\xintIrr + {\xintGCtoCv{3+{-2}/{7/2}+{3/4}/12+{-56}/3}}}}\] +\end{everbatim*} + + +\subsection{\csh{xintFtoCv}}\label{xintFtoCv} + +\csa{xintFtoCv}|{f}|\etype{\Ff} returns the list of the (braced) convergents of +|f|, with no separator. To be treated with \csbxint{AssignArray} or +\csbxint{ListWithSep}. +\begin{everbatim*} +\[\xintListWithSep{\to}{\xintApply\xintFrac{\xintFtoCv{5211/3748}}}\] +\end{everbatim*} + +\subsection{\csh{xintFtoCCv}}\label{xintFtoCCv} + +\csa{xintFtoCCv}|{f}|\etype{\Ff} returns the list of the (braced) centered +convergents of |f|, with no separator. To be treated with \csbxint{AssignArray} +or \csbxint{ListWithSep}. +\begin{everbatim*} +\[\xintListWithSep{\to}{\xintApply\xintFrac{\xintFtoCCv{5211/3748}}}\] +\end{everbatim*} + +\subsection{\csh{xintCntoF}}\label{xintCntoF} + + +\csa{xintCntoF}|{N}{\macro}|\etype{\numx f} computes the fraction |f| having +coefficients |c(j)=\macro{j}| for |j=0,1,...,N|. The |N| parameter is given to a +|\numexpr|. The values of the coefficients, as returned by |\macro| do not have +to be positive, nor integers, and it is thus not necessarily the case that the +original |c(j)| are the true coefficients of the final |f|. +\begin{everbatim*} +\def\macro #1{\the\numexpr 1+#1*#1\relax} \xintCntoF {5}{\macro} +\end{everbatim*} + +This example shows that the fraction is output with a trailing number in square +brackets (representing a power of ten), this is for consistency with what do +most macros of \xintfracname, and does not have to be always this annoying |[0]| +as the coefficients may for example be numbers in scientific notation. To avoid +these trailing square brackets, for example if the coefficients are known to be integers, there is always the possibility to filter the output via +\csbxint{PRaw}, or \csbxint{Irr} (the latter is overkill in the case of integer +coefficients, as the fraction is guaranteed to be irreducible then). + +\subsection{\csh{xintGCntoF}}\label{xintGCntoF} + +\csa{xintGCntoF}|{N}{\macroA}{\macroB}|\etype{\numx ff} returns the fraction |f| +corresponding to the inline generalized continued fraction +|a0+b0/a1+b1/a2+....+b(N-1)/aN|, with |a(j)=\macroA{j}| and |b(j)=\macroB{j}|. +The |N| parameter is given to a |\numexpr|. +\begin{everbatim*} +\def\coeffA #1{\the\numexpr #1+4-3*((#1+2)/3)\relax }% +\def\coeffB #1{\the\numexpr \ifodd #1 -\fi 1\relax }% (-1)^n +\[\xintGCFrac{\xintGCntoGC {6}{\coeffA}{\coeffB}} = + \xintFrac{\xintGCntoF {6}{\coeffA}{\coeffB}}\] +\end{everbatim*} +There is also \csbxint{GCntoGC} to get the `inline format' continued +fraction. + +\subsection{\csh{xintCntoCs}}\label{xintCntoCs} + +\csa{xintCntoCs}|{N}{\macro}|\etype{\numx f} produces the comma separated list +of the corresponding coefficients, from |n=0| to |n=N|. The |N| is given to a +|\numexpr|. % +\begin{everbatim*} +\xintCntoCs {5}{\macro} +\end{everbatim*} +\begin{everbatim*} +\[ \xintFrac{\xintCntoF{5}{\macro}}=\xintCFrac{\xintCntoF {5}{\macro}}\] +\end{everbatim*} + +\subsection{\csh{xintCntoGC}}\label{xintCntoGC} + +% +\csa{xintCntoGC}|{N}{\macro}|\etype{\numx f} evaluates the |c(j)=\macro{j}| from +|j=0| to |j=N| and returns a continued fraction written in inline format: +|{c(0)}+1/{c(1)}+1/...+1/{c(N)}|. The parameter |N| is given to a |\numexpr|. +The coefficients, after expansion, are, as shown, being enclosed in an added +pair of braces, they may thus be fractions. +\begin{everbatim*} +\def\macro #1{\the\numexpr\ifodd#1 -1-#1\else1+#1\fi\relax/\the\numexpr 1+#1*#1\relax} +\fdef\x{\xintCntoGC {5}{\macro}}\meaning\x +\[\xintGCFrac{\xintCntoGC {5}{\macro}}\] +\end{everbatim*} + +\subsection{\csh{xintGCntoGC}}\label{xintGCntoGC} + +\csa{xintGCntoGC}|{N}{\macroA}{\macroB}|\etype{\numx ff} evaluates the +coefficients and then returns the corresponding +|{a0}+{b0}/{a1}+{b1}/{a2}+...+{b(N-1)}/{aN}| inline generalized fraction. |N| is +givent to a |\numexpr|. The coefficients are enclosed into pairs +of braces, and may thus be fractions, the fraction slash will not be +confused in further processing by the continued fraction slashes. +% +\begin{everbatim*} +\def\an #1{\the\numexpr #1*#1*#1+1\relax}% +\def\bn #1{\the\numexpr \ifodd#1 -\fi 1*(#1+1)\relax}% +$\xintGCntoGC {5}{\an}{\bn}=\xintGCFrac {\xintGCntoGC {5}{\an}{\bn}} = +\displaystyle\xintFrac {\xintGCntoF {5}{\an}{\bn}}$\par +\end{everbatim*} + +\subsection{\csh{xintCstoGC}}\label{xintCstoGC} + +\csa{xintCstoGC}|{a,b,..,z}|\etype{f} transforms a comma separated list (or +something expanding to such a list) into an `inline format' continued fraction +|{a}+1/{b}+1/...+1/{z}|. The coefficients are just copied and put within braces, +without expansion. The output can then be used in \csbxint{GCFrac} for example. +\begin{everbatim*} +\[\xintGCFrac {\xintCstoGC {-1,1/2,-1/3,1/4,-1/5}}=\xintSignedFrac{\xintCstoF {-1,1/2,-1/3,1/4,-1/5}}\] +\end{everbatim*} +\subsection{\csh{xintiCstoF}, \csh{xintiGCtoF}, \csh{xintiCstoCv}, \csh{xintiGCtoCv}}\label{xintiCstoF} +\label{xintiGCtoF} +\label{xintiCstoCv} +\label{xintiGCtoCv} + +Essentially\etype{f} the same as the corresponding macros without the +`i', but for integer-only input. Infinitesimally faster, mainly for +internal use by the package. + +\subsection{\csh{xintGCtoGC}}\label{xintGCtoGC} + +\csa{xintGCtoGC}|{a+b/c+d/e+f/g+......+v/w+x/y}|\etype{f} expands (with the +usual meaning) each one of the coefficients and returns an inline continued +fraction of the same type, each expanded coefficient being enclosed within +braces. +% +\begin{everbatim*} +\fdef\x {\xintGCtoGC {1+\xintPow{1.5}{3}/{1/7}+{-3/5}/% + \xintiiFac {6}+\xintCstoF {2,-7,-5}/16}} \meaning\x +\end{everbatim*} + +To be honest I have forgotten for which purpose I wrote this macro in the first +place. + +\subsection{Euler's number \texorpdfstring{$e$}{e}}\label{ssec:e-convergents} + +Let us explore +the convergents of Euler's number $e$. +\smallskip The volume of computation is kept minimal by the following steps: +\begin{itemize} +\item a comma separated list of the first 36 coefficients is produced by + \csbxint{CntoCs}, +\item this is then given to \csbxint{iCstoCv} which produces the list of the + convergents (there is also \csbxint{CstoCv}, but our + coefficients being integers we used the infinitesimally + faster \csbxint{iCstoCv}), +\item then the whole list was converted into a sequence of one-line paragraphs, + each convergent becomes the argument to a macro printing it + together with its decimal expansion with 30 digits after the decimal point. +\item A count register |\cnta| was used to give a line count serving as a visual + aid: we could also have done that in an expandable way, but well, let's relax + from time to time\dots +\end{itemize} + +\begin{everbatim*} +\def\cn #1{\the\numexpr\ifcase \numexpr #1+3-3*((#1+2)/3)\relax + 1\or1\or2*(#1/3)\fi\relax } +% produces the pattern 1,1,2,1,1,4,1,1,6,1,1,8,... which are the +% coefficients of the simple continued fraction of e-1. +\cnta 0 +\def\mymacro #1{\advance\cnta by 1 + \noindent + \hbox to 3em {\hfil\small\dtt{\the\cnta.} }% + $\xintTrunc {30}{\xintAdd {1[0]}{#1}}\dots= + \xintFrac{\xintAdd {1[0]}{#1}}$}% +\xintListWithSep{\vtop to 6pt{}\vbox to 12pt{}\par} + {\xintApply\mymacro{\xintiCstoCv{\xintCntoCs {35}{\cn}}}} +\end{everbatim*} + + +\smallskip + +% The actual computation of the list of all 36 convergents accounts for +% only 8\% of the total time (total time equal to about 5 hundredths of a second +% in my testing, on my laptop): another 80\% is occupied with the computation of +% the truncated decimal expansions (and the addition of 1 to everything as the +% formula gives the continued fraction of $e-1$). + +One can with no problem compute +much bigger convergents. Let's get the 200th convergent. It turns out to +have the same first 268 digits after the decimal point as $e-1$. Higher +convergents get more and more digits in proportion to their index: the 500th +convergent already gets 799 digits correct! To allow speedy compilation of the +source of this document when the need arises, I limit here to the 200th +convergent. +% (getting the 500th took about 1.2s on my laptop last time I tried, +% and the 200th convergent is obtained ten times faster). +\begin{everbatim*} +\fdef\z {\xintCntoF {199}{\cn}}% +\begingroup\parindent 0pt \leftskip 2.5cm +\indent\llap {Numerator = }\printnumber{\xintNumerator\z}\par +\indent\llap {Denominator = }\printnumber{\xintDenominator\z}\par +\indent\llap {Expansion = }\printnumber{\xintTrunc{268}\z}\dots\par\endgroup +\end{everbatim*} + + +One can also use a centered continued fraction: we get more digits but there are +also more computations as the numerators may be either +$1$ or $-1$. + +\clearpage +\let\xintcfracnameUp\undefined +\csname xinttoolsnameUp\endcsname +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} +\section{Macros of the \xinttoolsname package} + +\RaisedLabel{sec:tools} + +\localtableofcontents + +These utilities used to be provided within the \xintname package; since |1.09g| +(|2013/11/22|) they have been moved to an independently usable package +\xinttoolsname, which has none of the \xintname facilities regarding big +numbers. Whenever relevant release |1.09h| has made the macros |\long| so they +accept |\par| tokens on input. + +The completely expandable utilities (up to \csbxint{iloop}) are documented +first, then the non expandable utilities. + +A brief overview is in \autoref{sec:sometoolsutils} and \autoref{sec:examples} +has more examples of use of macros of this package. + +\subsection{\csh{xintRevWithBraces}}\label{xintRevWithBraces} + +%{\small New in release |1.06|.\par} + +\edef\X{\xintRevWithBraces{12345}} +\edef\y{\xintRevWithBraces\X} +\expandafter\def\expandafter\w\expandafter + {\romannumeral0\xintrevwithbraces{{\A}{\B}{\C}{\D}{\E}}} + +% +\csa{xintRevWithBraces}\marg{list}\etype{f} first does the \fexpan sion of its +argument then it reverses the order of the tokens, or braced material, it +encounters, maintaining existing braces and adding a brace pair around each +naked token encountered. Space tokens (in-between top level braces or naked +tokens) are gobbled. This macro is mainly thought out for use on a \meta{list} +of such braced material; with such a list as argument the \fexpan sion will only +hit against the first opening brace, hence do nothing, and the braced stuff may +thus be macros one does not want to expand. +% +\leftedline{|\edef\x{\xintRevWithBraces{12345}}|} +% +\leftedline{|\meaning\x:|\dtt{\meaning\X}} +% +\leftedline{|\edef\y{\xintRevWithBraces\x}|} +% +\leftedline{|\meaning\y:|\dtt{\meaning\y}} +% +The examples above could be defined with |\edef|'s because the braced material +did not contain macros. Alternatively: +% +\leftedline{|\expandafter\def\expandafter\w\expandafter|} +% +\leftedline{|{\romannumeral0\xintrevwithbraces{{\A}{\B}{\C}{\D}{\E}}}|} +% +\leftedline{|\meaning\w:|\dtt{\meaning\w}} +% +The macro \csa{xintReverseWithBracesNoExpand}\etype{n} does the same job +without the initial expansion of its argument. + + +\subsection{\csh{xintZapFirstSpaces}, \csh{xintZapLastSpaces}, \csh{xintZapSpaces}, \csh{xintZapSpacesB}} +\label{xintZapFirstSpaces} +\label{xintZapLastSpaces} +\label{xintZapSpaces} +\label{xintZapSpacesB} +%{\small New with release |1.09f|.\par} + +\csa{xintZapFirstSpaces}\marg{stuff}\etype{n} does not do \emph{any} expansion +of its argument, nor brace removal of any sort, nor does it alter \meta{stuff} +in anyway apart from stripping away all \emph{leading} spaces. + +This macro will be mostly of interest to programmers who will know what I will +now be talking about. \emph{The essential points, naturally, are the complete + expandability and the fact that no brace removal nor any other alteration is + done to the input.} + +\TeX's input scanner already converts consecutive blanks into single space +tokens, but |\xintZapFirstSpaces| handles successfully also inputs with +consecutive multiple space tokens. +However, it is assumed that \meta{stuff} does not contain (except inside braced +sub-material) space tokens of character code distinct from $32$. + +It expands in two steps, and if the goal is to apply it to the +expansion text of |\x| to define |\y|, then one can do: +|\odef\y{\romannumeral0\expandafter\xintzapfirstspaces\expandafter{\x}}| +(one can also define a wrapper macro to |\xintZapFirstSpaces| in order to +expand once the argument first, but \xinttoolsname not being a programming +layer, it provides no «Generate Variants» facilities). + +Other use case: inside a macro which received a parameter |#1|, one can do +|\oodef\x{\xintZapFirstSpaces {#1}}|, or, if |#1|, after leading spaces have +been stripped can accept |\edef| expansion, one can do +|\edef\x{\xintZapFirstSpaces{#1}}|. + +\begingroup +\def\x { \a { \X } { \b \Y } } +% +\leftedline{|\xintZapFirstSpaces { \a { \X } { \b \Y } }->|% +\dtt{\color{magenta}{}\expandafter\detokenize\expandafter +{\romannumeral0\expandafter\xintzapfirstspaces\expandafter{\x}}}+++} +\endgroup + +\medskip + +\noindent\csbxint{ZapLastSpaces}\marg{stuff}\etype{n} does not do \emph{any} expansion of +its argument, nor brace removal of any sort, nor does it alter \meta{stuff} in +anyway apart from stripping away all \emph{ending} spaces. The same remarks as +for \csbxint{ZapFirstSpaces} apply. + +\begingroup +\def\x { \a { \X } { \b \Y } } +% +\leftedline{|\xintZapLastSpaces { \a { \X } { \b \Y } }->|% +\dtt{\color{magenta}{}\expandafter\detokenize\expandafter +{\romannumeral0\expandafter\xintzaplastspaces\expandafter{\x}}}+++} +\endgroup + +\medskip + +\noindent\csbxint{ZapSpaces}\marg{stuff}\etype{n} does not do \emph{any} +expansion of its +argument, nor brace removal of any sort, nor does it alter \meta{stuff} in +anyway apart from stripping away all \emph{leading} and all \emph{ending} +spaces. The same remarks as for \csbxint{ZapFirstSpaces} apply. + +\begingroup +\def\x { \a { \X } { \b \Y } } +% +\leftedline{|\xintZapSpaces { \a { \X } { \b \Y } }->|% +\dtt{\color{magenta}{}\expandafter\detokenize\expandafter +{\romannumeral0\expandafter\xintzapspaces\expandafter{\x}}}+++} +\endgroup + +\medskip + +\noindent\csbxint{ZapSpacesB}\marg{stuff}\etype{n} does not do \emph{any} +expansion of +its argument, nor does it alter \meta{stuff} in anyway apart from stripping away +all leading and all ending spaces and possibly removing one level of braces if +\meta{stuff} had the shape |<spaces>{braced}<spaces>|. The same remarks as for +\csbxint{ZapFirstSpaces} apply. + +\begingroup +\def\x { \a { \X } { \b \Y } } +% +\leftedline{|\xintZapSpacesB { \a { \X } { \b \Y } }->|% +\dtt{\color{magenta}{}\expandafter\detokenize\expandafter +{\romannumeral0\expandafter\xintzapspacesb\expandafter{\x}}}+++} +\def\x { { \a { \X } { \b \Y } } } +% +\leftedline{|\xintZapSpacesB { { \a { \X } { \b \Y } } }->|% +\dtt{\color{magenta}{}\expandafter\detokenize\expandafter +{\romannumeral0\expandafter\xintzapspacesb\expandafter{\x}}}+++} +\endgroup + The spaces here at the start and end of the output come from the braced + material, and are not removed (one would need a second application for that; + recall though that the \xintname zapping macros do not expand their argument). + +\subsection{\csh{xintCSVtoList}} +\label{xintCSVtoList} +\label{xintCSVtoListNoExpand} + + +\csa{xintCSVtoList}|{a,b,c...,z}|\etype{f} returns |{a}{b}{c}...{z}|. A +\emph{list} is by +convention in this manual simply a succession of tokens, where each braced thing +will count as one item (``items'' are defined according to the rules of \TeX{} +for fetching undelimited parameters of a macro, which are exactly the same rules +as for \LaTeX{} and macro arguments [they are the same things]). The word +`list' in `comma separated list of items' has its usual linguistic meaning, +and then an ``item'' is what is delimited by commas. + +So \csa{xintCSVtoList} takes on input a `comma separated list of items' and +converts it into a `\TeX{} list of braced items'. The argument to +|\xintCSVtoList| may be a macro: it will first be +\hyperref[ssec:expansions]{\fexpan ded}. Hence the item before the first comma, +if it is itself a macro, will be expanded which may or may not be a good thing. +A space inserted at the start of the first item serves to stop that expansion +(and disappears). The macro \csbxint{CSVtoListNoExpand}\etype{n} does the same +job without +the initial expansion of the list argument. + +Apart from that no expansion of the items is done and the list items may thus be +completely arbitrary (and even contain perilous stuff such as unmatched |\if| +and |\fi| tokens). + +Contiguous spaces and tab characters, are collapsed by \TeX{} +into single spaces. All such spaces around commas% +% +\footnote{and multiple space tokens are not a problem; but those at the + top level (not hidden inside braces) \emph{must} be of character code + |32|.} +% +\fbox{are removed}, as well as +the spaces at the start and the spaces at the end of the list.% +% +\footnote{let us recall that this is all done completely expandably... + There is absolutely no alteration of any sort of the item apart from + the stripping of initial and final space tokens (of character code + |32|) and brace removal if and only if the item apart from intial and + final spaces (or more generally multiple |char 32| space tokens) is + braced.} +% +The items may contain explicit |\par|'s or +empty lines (converted by the \TeX{} input parsing into |\par| tokens). + +\begingroup + +\edef\X{\xintCSVtoList { 1 ,{ 2 , 3 , 4 , 5 }, a , {b,T} U , { c , d } , { {x , + y} } }} + +% +\leftedline{|\xintCSVtoList { 1 ,{ 2 , 3 , 4 , 5 }, a , {b,T} U , { c , d } , + { {x , y} } }|} +% +\leftedline{|->|% +{\makeatletter\dtt{\expandafter\strip@prefix\meaning\X}}} + +One sees on this example how braces protect commas from +sub-lists to be perceived as delimiters of the top list. Braces around an entire +item are removed, even when surrounded by spaces before and/or after. Braces for +sub-parts of an item are not removed. + +We observe also that there is a slight difference regarding the brace stripping +of an item: if the braces were not surrounded by spaces, also the initial and +final (but no other) spaces of the \emph{enclosed} material are removed. This is +the only situation where spaces protected by braces are nevertheless removed. + +From the rules above: for an empty argument (only spaces, no braces, no comma) +the output is +\dtt{\expandafter\detokenize\expandafter{\romannumeral0\xintcsvtolist { }}} +(a list with one empty item), +for ``|<opt. spaces>{}<opt. +spaces>|'' the output is +\dtt{\expandafter\detokenize\expandafter + {\romannumeral0\xintcsvtolist { {} }}} +(again a list with one empty item, the braces were removed), +for ``|{ }|'' the output is +\dtt{\expandafter\detokenize\expandafter + {\romannumeral0\xintcsvtolist {{ }}}} +(again a list with one empty item, the braces were removed and then +the inner space was removed), +for ``| { }|'' the output is +\dtt{\expandafter\detokenize\expandafter +{\romannumeral0\xintcsvtolist { { }}}} (again a list with one empty item, the initial space served only to stop the expansion, so this was like ``|{ }|'' as input, the braces were removed and the inner space was stripped), +for ``\texttt{\ \{\ \ \}\ }'' the output is +\dtt{\expandafter\detokenize\expandafter +{\romannumeral0\xintcsvtolist { { } }}} (this time the ending space of the first +item meant that after brace removal the inner spaces were kept; recall though +that \TeX{} collapses on input consecutive blanks into one space token), +for ``|,|'' the output consists of two consecutive +empty items +\dtt{\expandafter\detokenize\expandafter{\romannumeral0\xintcsvtolist + {,}}}. Recall that on output everything is braced, a |{}| is an ``empty'' +item. +% +Most of the above is mainly irrelevant for every day use, apart perhaps from the +fact to be noted that an empty input does not give an empty output but a +one-empty-item list (it is as if an ending comma was always added at the end of +the input). + +\def\y { \a,\b,\c,\d,\e} +\expandafter\def\expandafter\Y\expandafter{\romannumeral0\xintcsvtolist{\y}} +\def\t {{\if},\ifnum,\ifx,\ifdim,\ifcat,\ifmmode} +\expandafter\def\expandafter\T\expandafter{\romannumeral0\xintcsvtolist{\t}} + +% +\leftedline{|\def\y{ \a,\b,\c,\d,\e} \xintCSVtoList\y->|% + {\makeatletter\dtt{\expandafter\strip@prefix\meaning\Y}}} +% +\leftedline{|\def\t {{\if},\ifnum,\ifx,\ifdim,\ifcat,\ifmmode}|} +% +\leftedline +{|\xintCSVtoList\t->|\makeatletter\dtt{\expandafter\strip@prefix\meaning\T}} +% +The results above were automatically displayed using \TeX's primitive +\csa{meaning}, which adds a space after each control sequence name. These spaces +are not in the actual braced items of the produced lists. The first items |\a| +and |\if| were either preceded by a space or braced to prevent expansion. The +macro \csa{xintCSVtoListNoExpand} would have done the same job without the +initial expansion of the list argument, hence no need for such protection but if +|\y| is defined as |\def\y{\a,\b,\c,\d,\e}| we then must do: +% +\leftedline{|\expandafter\xintCSVtoListNoExpand\expandafter {\y}|} Else, we +may have direct use: % +% +\leftedline{|\xintCSVtoListNoExpand + {\if,\ifnum,\ifx,\ifdim,\ifcat,\ifmmode}|} +% +\leftedline{|->|\dtt{\expandafter\detokenize\expandafter + {\romannumeral0\xintcsvtolistnoexpand + {\if,\ifnum,\ifx,\ifdim,\ifcat,\ifmmode}}}} +% +Again these spaces are an artefact from the use in the source of the document of +\csa{meaning} (or rather here, \csa{detokenize}) to display the result of using +\csa{xintCSVtoListNoExpand} (which is done for real in this document +source). + +For the similar conversion from comma separated list to braced items list, but +without removal of spaces around the commas, there is +\csa{xintCSVtoListNonStripped}\etype{f} and +\csa{xintCSVtoListNonStrippedNoExpand}\etype{n}. + +\endgroup + +\subsection{\csh{xintNthElt}}\label{xintNthElt} + + +\def\macro #1{\the\numexpr 9-#1\relax} + +\csa{xintNthElt\x}\marg{list}\etype{\numx f} gets (expandably) the |x|th +item of the \meta{list}. A braced item will lose one level of brace +pairs. The token list is first \fexpan ded. + +Items are counted starting at one. + +\leftedline{|\xintNthElt {3}{{agh}\u{zzz}\v{Z}}| is + \texttt{\xintNthElt {3}{{agh}\u{zzz}\v{Z}}}} +% +\leftedline{|\xintNthElt {3}{{agh}\u{{zzz}}\v{Z}}| is + \texttt{\expandafter\expandafter\expandafter + \detokenize\expandafter\expandafter\expandafter {\xintNthElt + {3}{{agh}\u{{zzz}}\v{Z}}}}} +% +\leftedline{|\xintNthElt {2}{{agh}\u{{zzz}}\v{Z}}| is + \texttt{\expandafter\expandafter\expandafter + \detokenize\expandafter\expandafter\expandafter {\xintNthElt + {2}{{agh}\u{{zzz}}\v{Z}}}}} +% +\leftedline{|\xintNthElt {37}{\xintiiFac {100}}|\dtt{=\xintNthElt + {37}{\xintiiFac {100}}} is the thirty-seventh digit of $100!$.} +% +\leftedline{|\xintNthElt {10}{\xintFtoCv + {566827/208524}}|\dtt{=\xintNthElt {10}{\xintFtoCv + {566827/208524}}}} +\leftedline{is the tenth convergent of $566827/208524$ (uses \xintcfracname + package).} +% +\leftedline{|\xintNthElt {7}{\xintCSVtoList {1,2,3,4,5,6,7,8,9}}|% + \dtt{=\xintNthElt {7}{\xintCSVtoList {1,2,3,4,5,6,7,8,9}}}} +% +\leftedline{|\xintNthElt {0}{\xintCSVtoList {1,2,3,4,5,6,7,8,9}}|% + \dtt{=\xintNthElt {0}{\xintCSVtoList {1,2,3,4,5,6,7,8,9}}}} +% +\leftedline{|\xintNthElt {-3}{\xintCSVtoList {1,2,3,4,5,6,7,8,9}}|% + \dtt{=\xintNthElt {-3}{\xintCSVtoList {1,2,3,4,5,6,7,8,9}}}} + +If |x=0|, +the macro returns the \emph{length} of the expanded list: this is not equivalent +to \csbxint{Length} which does no pre-expansion. And it is different from +\csbxint{Len} which is to be used only on integers or fractions. + +If |x<0|, the macro returns the \verb+|x|+th element from the end of the list. +Thus for example |x=-1| will fetch the last item of the list. +% +\leftedline {|\xintNthElt {-5}{{{agh}}\u{zzz}\v{Z}}| is + \texttt{\expandafter\expandafter\expandafter \detokenize + \expandafter\expandafter\expandafter{\xintNthElt {-5}{{{agh}}\u{zzz}\v{Z}}}}} + +The macro \csa{xintNthEltNoExpand}\etype{\numx n} does the same job but without +first expanding the list argument: |\xintNthEltNoExpand {-4}{\u\v\w T\x\y\z}| is +\xintNthEltNoExpand {-4}{\a\b\c\u\v\w T\x\y\z}. + +If |x| is strictly larger (in absolute value) than the length of the list +then |\xintNthElt| produces empty contents. + +\subsection{\csh{xintKeep}}\label{xintKeep} + +\csa{xintKeep\x}\marg{list}\etype{\numx f} expands the token list argument |L| +and produces a new list, depending on the value of |x|: +\begin{itemize}[nosep] +\item if |x>0|, the new list contains the first |x| items from |L| (counting + starts at one.) \emph{Each + such item will be output within a brace pair.} Use \csbxint{KeepUnbraced} if + this is not desired. This means that if the list item was braced to start + with, there is no modification, but if it was a token without braces, + then it acquires them. +\item if |x>=length(L)|, the new list is the old one with all its items now + braced. +\item if |x=0| the empty list is returned. +\item if |x<0| the last \verb+|x|+ elements compose the output in the same + order as in the initial list; as the macro proceeds by removing head items + the kept items end up in output as they were in input: no added braces. +\item if |x<=-length(L)| the output is identical with the input. +\end{itemize} + +\csa{xintKeepNoExpand} does the same without first \fexpan ding its list +argument. +% +\begin{everbatim*} +\fdef\test {\xintKeep {17}{\xintKeep {-69}{\xintSeq {1}{100}}}}\meaning\test\par +\noindent\fdef\test {\xintKeep {7}{{1}{2}{3}{4}{5}{6}{7}{8}{9}}}\meaning\test\par +\noindent\fdef\test {\xintKeep {-7}{{1}{2}{3}{4}{5}{6}{7}{8}{9}}}\meaning\test\par +\noindent\fdef\test {\xintKeep {7}{123456789}}\meaning\test\par +\noindent\fdef\test {\xintKeep {-7}{123456789}}\meaning\test\par +\end{everbatim*} + + +\subsection{\csh{xintKeepUnbraced}}\label{xintKeepUnbraced} + +Same as \csbxint{Keep} but no brace pairs are added around the kept items from +the head of the list in the case |x>0|: each such item will lose one level of +braces. Thus, to remove braces from all items of the list, one can use +\csbxint{KeepUnbraced} with its first argument larger than the length of the +list; the same is obtained from \csbxint{ListWithSep}|{}|\marg{list}. But the +new list will then have generally many more items than the original ones, +corresponding to the unbraced original items. + +For |x<0| the macro is no different from \csbxint{Keep}. Hence the name is a +bit misleading because brace removal will happen only if |x>0|. + +\csa{xintKeepUnbracedNoExpand} does the same without first \fexpan ding +its list argument. +% +\begin{everbatim*} +\fdef\test {\xintKeepUnbraced {10}{\xintSeq {1}{100}}}\meaning\test\par +\noindent\fdef\test {\xintKeepUnbraced {7}{{1}{2}{3}{4}{5}{6}{7}{8}{9}}}\meaning\test\par +\noindent\fdef\test {\xintKeepUnbraced {-7}{{1}{2}{3}{4}{5}{6}{7}{8}{9}}}\meaning\test\par +\noindent\fdef\test {\xintKeepUnbraced {7}{123456789}}\meaning\test\par +\noindent\fdef\test {\xintKeepUnbraced {-7}{123456789}}\meaning\test\par +\end{everbatim*} + +\subsection{\csh{xintTrim}}\label{xintTrim} + +\csa{xintTrim\x}\marg{list}\etype{\numx f} expands the list argument and +gobbles its first |x| elements. +\begin{itemize}[nosep] +\item if |x>0|, the first |x| items from |L| are gobbled. The remaining items + are not modified. +\item if |x>=length(L)|, the returned list is empty. +\item if |x=0| the original list is returned (with no added braces.) +\item if |x<0| the last \verb+|x|+ items of the list are removed. \emph{The + head items end up braced in the output.} Use \csbxint{TrimUnbraced} if + this is not desired. +\item if |x<=-length(L)| the output is empty. +\end{itemize} + +\csa{xintTrimNoExpand} does the same without first \fexpan ding its list +argument. +\begin{everbatim*} +\fdef\test {\xintTrim {17}{\xintTrim {-69}{\xintSeq {1}{100}}}}\meaning\test\par +\noindent\fdef\test {\xintTrim {7}{{1}{2}{3}{4}{5}{6}{7}{8}{9}}}\meaning\test\par +\noindent\fdef\test {\xintTrim {-7}{{1}{2}{3}{4}{5}{6}{7}{8}{9}}}\meaning\test\par +\noindent\fdef\test {\xintTrim {7}{123456789}}\meaning\test\par +\noindent\fdef\test {\xintTrim {-7}{123456789}}\meaning\test\par +\end{everbatim*} + +\subsection{\csh{xintTrimUnbraced}}\label{xintTrimUnbraced} + +Same as \csbxint{Trim} but in case of a negative |x| (cutting items from +the tail), the kept items from the head are not enclosed in brace pairs. They +will lose one level of braces. The name is a bit misleading +because when |x>0| there is no brace-stripping done on the kept items, because +the macro works simply by gobbling the head ones. + +\csa{xintTrimUnbracedNoExpand} does the same without first \fexpan ding its list +argument. + +\begin{everbatim*} +\fdef\test {\xintTrimUnbraced {-90}{\xintSeq {1}{100}}}\meaning\test\par +\noindent\fdef\test {\xintTrimUnbraced {7}{{1}{2}{3}{4}{5}{6}{7}{8}{9}}}\meaning\test\par +\noindent\fdef\test {\xintTrimUnbraced {-7}{{1}{2}{3}{4}{5}{6}{7}{8}{9}}}\meaning\test\par +\noindent\fdef\test {\xintTrimUnbraced {7}{123456789}}\meaning\test\par +\noindent\fdef\test {\xintTrimUnbraced {-7}{123456789}}\meaning\test\par +\end{everbatim*} + +\subsection{\csh{xintListWithSep}}\label{xintListWithSep} + + +\def\macro #1{\the\numexpr 9-#1\relax} + +\csa{xintListWithSep}\marg{sep}\marg{list}\etype{nf} inserts the separator +\meta{sep} in-between all items of the given list of braced items (or +individual tokens). The items are fetched as does \TeX\ with undelimited macro +arguments, thus they end up unbraced in output. If the \meta{list} is only one +(or multiple) space tokens, the output is empty. + +The list argument \meta{list} gets \fexpan ded first (thus if it is a macro +whose contents are braced items, the first opening brace stops the expansion, +and it is as if the macro had been expanded once.) The separator \meta{sep} is +not pre-expanded, it ends up as is in the output (if the \meta{list} contained +at least two items.) + +The variant \csa{xintListWithSepNoExpand}\etype{nn} does the same +job without the initial expansion of the \meta{list} argument. +\begin{everbatim*} +\edef\foo{\xintListWithSep{, }{123456789{10}{11}{12}}}\meaning\foo\newline +\edef\foo{\xintListWithSep{:}{\xintiiFac{20}}}\meaning\foo\newline +\oodef\FOO{\xintListWithSepNoExpand{\FOO}{\bat\baz\biz\buz}}\meaning\FOO\newline +% a braced item or a space stops the f-expansion: +\oodef\foo{\xintListWithSep{\FOO}{{\bat}\baz\biz\buz}}\meaning\foo\newline +\oodef\foo{\xintListWithSep{\FOO}{ \bat\baz\biz\buz}}\meaning\foo\par +\end{everbatim*} + +\subsection{\csh{xintApply}}\label{xintApply} + + +\def\macro #1{\the\numexpr 9-#1\relax} + +\csa{xintApply}|{\macro}|\marg{list}\etype{ff} expandably applies the one +parameter macro |\macro| to each item in the \meta{list} given as second +argument and returns a new list with these outputs: each item is given one after +the other as parameter to |\macro| which is expanded at that time (as usual, +\emph{i.e.} fully for what comes first), the results are braced and output +together as a succession of braced items (if |\macro| is defined to start with a +space, the space will be gobbled and the |\macro| will not be expanded; it is +allowed to have its own arguments, the list items serve as last arguments to +|\macro|). Hence |\xintApply{\macro}{{1}{2}{3}}| returns +|{\macro{1}}{\macro{2}}{\macro{3}}| where all instances of |\macro| have been +already \fexpan ded. + +Being expandable, |\xintApply| is useful for example inside alignments where +implicit groups make standard loops constructs usually fail. In such situation +it is often not wished that the new list elements be braced, see +\csbxint{ApplyUnbraced}. The |\macro| does not have to be expandable: +|\xintApply| will try to expand it, the expansion may remain partial. + +The \meta{list} may +itself be some macro expanding (in the previously described way) to the list of +tokens to which the macro |\macro| will be applied. For example, if the +\meta{list} expands to some positive number, then each digit will be replaced by +the result of applying |\macro| on it. % +% +\leftedline{|\def\macro #1{\the\numexpr + 9-#1\relax}|} % +% +\leftedline{|\xintApply\macro{\xintiiFac + {20}}|\dtt{=\xintApply\macro{\xintiiFac {20}}}} + +The macro \csa{xintApplyNoExpand}\etype{fn} does the same job without the first +initial expansion which gave the \meta{list} of braced tokens to which |\macro| +is applied. + +\subsection{\csh{xintApplyUnbraced}}\label{xintApplyUnbraced} + + +\csa{xintApplyUnbraced}|{\macro}|\marg{list}\etype{ff} is like \csbxint{Apply}. +The difference is that after having expanded its list argument, and applied +|\macro| in turn to each item from the list, it reassembles the outputs without +enclosing them in braces. The net effect is the same as doing +% +\leftedline{|\xintListWithSep {}{\xintApply {\macro}|\marg{list}|}|} This is +useful for preparing a macro which will itself define some other macros or make +assignments, as the scope will not be limited by brace pairs. +% +\begin{everbatim*} +\def\macro #1{\expandafter\def\csname myself#1\endcsname {#1}} +\xintApplyUnbraced\macro{{elta}{eltb}{eltc}} +\begin{enumerate}[nosep,label=(\arabic{*})] +\item \meaning\myselfelta +\item \meaning\myselfeltb +\item \meaning\myselfeltc +\end{enumerate} +\end{everbatim*} + +% +The macro \csa{xintApplyUnbracedNoExpand}\etype{fn} does the same job without +the first initial expansion which gave the \meta{list} of braced tokens to which +|\macro| is applied. + +\subsection{\csh{xintSeq}}\label{xintSeq} + +\csa{xintSeq}|[d]{x}{y}|\etype{{{\upshape[\numx]}}\numx\numx} generates +expandably |{x}{x+d}...| up to and possibly including |{y}| if |d>0| or down +to and including |{y}| if |d<0|. Naturally |{y}| is omitted if |y-x| is not a +multiple of |d|. If |d=0| the macro returns |{x}|. If |y-x| and |d| have +opposite signs, the macro returns nothing. If the optional argument |d| is +omitted it is taken to be the sign of |y-x|. Hence |\xintSeq {1}{0}| is not +empty but |{1}{0}|. But |\xintSeq [1]{1}{0}| is empty. + + +The arguments |x| and |y| are expanded inside a |\numexpr| so they may be +count registers or a \LaTeX{} |\value{countername}|, or arithmetic with such +things. + +% +\begin{everbatim*} +\xintListWithSep{,\hskip2pt plus 1pt minus 1pt }{\xintSeq {12}{-25}} +\end{everbatim*} +% +\begin{everbatim*} +\xintiiSum{\xintSeq [3]{1}{1000}} +\end{everbatim*} + +When the macro is used without the optional argument |d|, it can only generate +up to about $5000$ numbers\IMPORTANT, the precise value depends upon some +\TeX{} memory parameter (input save stack). + +With the optional argument |d| the macro proceeds differently (but less +efficiently) and does not stress the input save stack. + + + +\subsection{\csh{xintloop}, \csh{xintbreakloop}, \csh{xintbreakloopanddo}, \csh{xintloopskiptonext}} +\label{xintloop} +\label{xintbreakloop} +\label{xintbreakloopanddo} +\label{xintloopskiptonext} + +|\xintloop|\meta{stuff}|\if<test>...\repeat|\retype{} is an expandable loop +compatible with nesting. However to break out of the loop one almost always need +some un-expandable step. The cousin \csbxint{iloop} is \csbxint{loop} with an +embedded expandable mechanism allowing to exit from the loop. The iterated +macros may contain |\par| tokens or empty lines. + +If a sub-loop is to be used all the material from the start of the main loop and +up to the end of the entire subloop should be braced; these braces will be +removed and do not create a group. The simplest to allow the nesting of one or +more sub-loops is to brace everything between \csa{xintloop} and \csa{repeat}, +being careful not to leave a space between the closing brace and |\repeat|. + +As this loop and \csbxint{iloop} will primarily be of interest to experienced +\TeX{} macro programmers, my description will assume that the user is +knowledgeable enough. Some examples in this document will be perhaps more +illustrative than my attemps at explanation of use. + +One can abort the loop with \csbxint{breakloop}; this should not be used inside +the final test, and one should expand the |\fi| from the corresponding test +before. One has also \csbxint{breakloopanddo} whose first argument will be +inserted in the token stream after the loop; one may need a macro such as +|\xint_afterfi| to move the whole thing after the |\fi|, as a simple +|\expandafter| will not be enough. + +One will usually employ some count registers to manage the exit test from the +loop; this breaks expandability, see \csbxint{iloop} for an expandable integer +indexed loop. Use in alignments will be complicated by the fact that cells +create groups, and also from the fact that any encountered unexpandable material +will cause the \TeX{} input scanner to insert |\endtemplate| on each encountered +|&| or |\cr|; thus |\xintbreakloop| may not work as expected, but the situation +can be resolved via |\xint_firstofone{&}| or use of |\TAB| with |\def\TAB{&}|. +It is thus simpler for alignments to use rather than \csbxint{loop} either the +expandable \csbxint{ApplyUnbraced} or the non-expandable but alignment +compatible \csbxint{ApplyInline}, \csbxint{For} or \csbxint{For*}. + +As an example, let us suppose we have two macros |\A|\marg{i}\marg{j} and +|\B|\marg{i}\marg{j} behaving like (small) integer valued matrix entries, and we +want to define a macro |\C|\marg{i}\marg{j} giving the matrix product (|i| and +|j| may be count registers). We will assume that |\A[I]| expands to the number +of rows, |\A[J]| to the number of columns and want the produced |\C| to act in +the same manner. The code is very dispendious in use of |\count| registers, not +optimized in any way, not made very robust (the defined macro can not have the +same name as the first two matrices for example), we just wanted to quickly +illustrate use of the nesting capabilities of |\xintloop|.% +% +\footnote{for a more sophisticated implementation of matrix + multiplication, inclusive of determinants, inverses, and display + utilities, with entries big integers or decimal numbers or even + fractions see \url{http://tex.stackexchange.com/a/143035/4686} from + November 11, 2013.} +% + + +\begin{everbatim*} +\newcount\rowmax \newcount\colmax \newcount\summax +\newcount\rowindex \newcount\colindex \newcount\sumindex +\newcount\tmpcount +\makeatletter +\def\MatrixMultiplication #1#2#3{% + \rowmax #1[I]\relax + \colmax #2[J]\relax + \summax #1[J]\relax + \rowindex 1 + \xintloop % loop over row index i + {\colindex 1 + \xintloop % loop over col index k + {\tmpcount 0 + \sumindex 1 + \xintloop % loop over intermediate index j + \advance\tmpcount \numexpr #1\rowindex\sumindex*#2\sumindex\colindex\relax + \ifnum\sumindex<\summax + \advance\sumindex 1 + \repeat }% + \expandafter\edef\csname\string#3{\the\rowindex.\the\colindex}\endcsname + {\the\tmpcount}% + \ifnum\colindex<\colmax + \advance\colindex 1 + \repeat }% + \ifnum\rowindex<\rowmax + \advance\rowindex 1 + \repeat + \expandafter\edef\csname\string#3{I}\endcsname{\the\rowmax}% + \expandafter\edef\csname\string#3{J}\endcsname{\the\colmax}% + \def #3##1{\ifx[##1\expandafter\Matrix@helper@size + \else\expandafter\Matrix@helper@entry\fi #3{##1}}% +}% +\def\Matrix@helper@size #1#2#3]{\csname\string#1{#3}\endcsname }% +\def\Matrix@helper@entry #1#2#3% + {\csname\string#1{\the\numexpr#2.\the\numexpr#3}\endcsname }% +\def\A #1{\ifx[#1\expandafter\A@size + \else\expandafter\A@entry\fi {#1}}% +\def\A@size #1#2]{\ifx I#23\else4\fi}% 3rows, 4columns +\def\A@entry #1#2{\the\numexpr #1+#2-1\relax}% not pre-computed... +\def\B #1{\ifx[#1\expandafter\B@size + \else\expandafter\B@entry\fi {#1}}% +\def\B@size #1#2]{\ifx I#24\else3\fi}% 4rows, 3columns +\def\B@entry #1#2{\the\numexpr #1-#2\relax}% not pre-computed... +\makeatother +\MatrixMultiplication\A\B\C \MatrixMultiplication\C\C\D +\MatrixMultiplication\C\D\E \MatrixMultiplication\C\E\F +\begin{multicols}2 + \[\begin{pmatrix} + \A11&\A12&\A13&\A14\\ + \A21&\A22&\A23&\A24\\ + \A31&\A32&\A33&\A34 + \end{pmatrix} + \times + \begin{pmatrix} + \B11&\B12&\B13\\ + \B21&\B22&\B23\\ + \B31&\B32&\B33\\ + \B41&\B42&\B43 + \end{pmatrix} + = + \begin{pmatrix} + \C11&\C12&\C13\\ + \C21&\C22&\C23\\ + \C31&\C32&\C33 + \end{pmatrix}\] + \[\begin{pmatrix} + \C11&\C12&\C13\\ + \C21&\C22&\C23\\ + \C31&\C32&\C33 + \end{pmatrix}^2 = \begin{pmatrix} + \D11&\D12&\D13\\ + \D21&\D22&\D23\\ + \D31&\D32&\D33 + \end{pmatrix}\] + \[\begin{pmatrix} + \C11&\C12&\C13\\ + \C21&\C22&\C23\\ + \C31&\C32&\C33 + \end{pmatrix}^3 = \begin{pmatrix} + \E11&\E12&\E13\\ + \E21&\E22&\E23\\ + \E31&\E32&\E33 + \end{pmatrix}\] + \[\begin{pmatrix} + \C11&\C12&\C13\\ + \C21&\C22&\C23\\ + \C31&\C32&\C33 + \end{pmatrix}^4 = \begin{pmatrix} + \F11&\F12&\F13\\ + \F21&\F22&\F23\\ + \F31&\F32&\F33 + \end{pmatrix}\] +\end{multicols} +\end{everbatim*} + + +\subsection{\csh{xintiloop}, \csh{xintiloopindex}, \csh{xintouteriloopindex}, + \csh{xintbreakiloop}, \csh{xintbreakiloopanddo}, \csh{xintiloopskiptonext}, +\csh{xintiloopskipandredo}} +\label{xintiloop} +\label{xintbreakiloop} +\label{xintbreakiloopanddo} +\label{xintiloopskiptonext} +\label{xintiloopskipandredo} +\label{xintiloopindex} +\label{xintouteriloopindex} + +\csa{xintiloop}|[start+delta]|\meta{stuff}|\if<test> ... \repeat|\retype{} is a +completely expandable nestable loop. complete expandability depends naturally on +the actual iterated contents, and complete expansion will not be achievable +under a sole \fexpan sion, as is indicated by the hollow star in the margin; +thus the loop can be used inside an |\edef| but not inside arguments to the +package macros. It can be used inside an |\xintexpr..\relax|. The +|[start+delta]| is mandatory, not optional. + +This loop benefits via \csbxint{iloopindex} to (a limited access to) the integer +index of the iteration. The starting value |start| (which may be a |\count|) and +increment |delta| (\emph{id.}) are mandatory arguments. A space after the +closing square bracket is not significant, it will be ignored. Spaces inside the +square brackets will also be ignored as the two arguments are first given to a +|\numexpr...\relax|. Empty lines and explicit |\par| tokens are accepted. + +As with \csbxint{loop}, this tool will mostly be of interest to advanced users. +For nesting, one puts inside braces all the +material from the start (immediately after |[start+delta]|) and up to and +inclusive of the inner loop, these braces will be removed and do not create a +loop. In case of nesting, \csbxint{outeriloopindex} gives access to the index of +the outer loop. If needed one could write on its model a macro giving access to +the index of the outer outer loop (or even to the |nth| outer loop). + +The \csa{xintiloopindex} and \csa{xintouteriloopindex} can not be used inside +braces, and generally speaking this means they should be expanded first when +given as argument to a macro, and that this macro receives them as delimited +arguments, not braced ones. Or, but naturally this will break expandability, one +can assign the value of \csa{xintiloopindex} to some |\count|. Both +\csa{xintiloopindex} and \csa{xintouteriloopindex} extend to the litteral +representation of the index, thus in |\ifnum| tests, if it comes last one has to +correctly end the macro with a |\space|, or encapsulate it in a +|\numexpr..\relax|. + +When the repeat-test of the loop is, for example, |\ifnum\xintiloopindex<10 +\repeat|, this means that the last iteration will be with |\xintiloopindex=10| +(assuming |delta=1|). There is also |\ifnum\xintiloopindex=10 \else\repeat| to +get the last iteration to be the one with |\xintiloopindex=10|. + +One has \csbxint{breakiloop} and \csbxint{breakiloopanddo} to abort the loop. +The syntax of |\xintbreakiloopanddo| is a bit surprising, the sequence of tokens +to be executed after breaking the loop is not within braces but is delimited by +a dot as in: +% +\leftedline{|\xintbreakiloopanddo <afterloop>.etc.. etc... \repeat|} +% +The reason is that one may wish to use the then current value of +|\xintiloopindex| in |<afterloop>| but it can't be within braces at the time it +is evaluated. However, it is not that easy as |\xintiloopindex| must be expanded +before, so one ends up with code like this: +% +\leftedline +{|\expandafter\xintbreakiloopanddo\expandafter\macro\xintiloopindex.%|} +% +\leftedline{|etc.. etc.. \repeat|} +% +As moreover the |\fi| from the test leading to the decision of breaking out of +the loop must be cleared out of the way, the above should be +a branch of an expandable conditional test, else one needs something such +as: +% +\leftedline +{|\xint_afterfi{\expandafter\xintbreakiloopanddo\expandafter\macro\xintiloopindex.}%|} +% +\leftedline{|\fi etc..etc.. \repeat|} + +There is \csbxint{iloopskiptonext} to abort the current iteration and skip to +the next, \hyperref[xintiloopskipandredo]{\ttfamily\hyphenchar\font45 \char92 + xintiloopskip\-and\-redo} to skip to the end of the current iteration and redo +it with the same value of the index (something else will have to change for this +not to become an eternal loop\dots ). + +Inside alignments, if the looped-over text contains a |&| or a |\cr|, any +un-expandable material before a \csbxint{iloopindex} will make it fail because +of |\endtemplate|; in such cases one can always either replace |&| by a macro +expanding to it or replace it by a suitable |\firstofone{&}|, and similarly for +|\cr|. + +\phantomsection\label{edefprimes} +As an example, let us construct an |\edef\z{...}| which will define |\z| to be a +list of prime numbers: +\begin{everbatim*} +\begingroup +\edef\z +{\xintiloop [10001+2] + {\xintiloop [3+2] + \ifnum\xintouteriloopindex<\numexpr\xintiloopindex*\xintiloopindex\relax + \xintouteriloopindex, + \expandafter\xintbreakiloop + \fi + \ifnum\xintouteriloopindex=\numexpr + (\xintouteriloopindex/\xintiloopindex)*\xintiloopindex\relax + \else + \repeat + }% no space here + \ifnum \xintiloopindex < 10999 \repeat }% +\meaning\z\endgroup +\end{everbatim*}and we should have taken +some steps to not have a trailing comma, but +the point was to show that one can do that in an |\edef|\,! See also +\autoref{ssec:primesII} which extracts from this code its way of testing +primality. + +Let us create an alignment where each row will contain all divisors of its +first entry. +Here is the output, thus obtained without any count register: +\begin{everbatim*} +\begin{multicols}2 +\tabskip1ex \normalcolor +\halign{&\hfil#\hfil\cr + \xintiloop [1+1] + {\expandafter\bfseries\xintiloopindex & + \xintiloop [1+1] + \ifnum\xintouteriloopindex=\numexpr + (\xintouteriloopindex/\xintiloopindex)*\xintiloopindex\relax + \xintiloopindex&\fi + \ifnum\xintiloopindex<\xintouteriloopindex\space % CRUCIAL \space HERE + \repeat \cr }% + \ifnum\xintiloopindex<30 + \repeat +} +\end{multicols} +\end{everbatim*} +We wanted this first entry in bold face, but |\bfseries| leads to +unexpandable tokens, so the |\expandafter| was necessary for |\xintiloopindex| +and |\xintouteriloopindex| not to be confronted with a hard to digest +|\endtemplate|. An alternative way of coding: +% +\begin{everbatim} +\tabskip1ex +\def\firstofone #1{#1}% +\halign{&\hfil#\hfil\cr + \xintiloop [1+1] + {\bfseries\xintiloopindex\firstofone{&}% + \xintiloop [1+1] \ifnum\xintouteriloopindex=\numexpr + (\xintouteriloopindex/\xintiloopindex)*\xintiloopindex\relax + \xintiloopindex\firstofone{&}\fi + \ifnum\xintiloopindex<\xintouteriloopindex\space % \space is CRUCIAL + \repeat \firstofone{\cr}}% + \ifnum\xintiloopindex<30 \repeat } +\end{everbatim} + +\begin{framed} + The next utilities are not compatible with expansion-only context. +\end{framed} + +\subsection{\csh{xintApplyInline}}\label{xintApplyInline} + + +\csa{xintApplyInline}|{\macro}|\marg{list}\ntype{o{\lowast f}} works non +expandably. It applies the one-parameter |\macro| to the first element of the +expanded list (|\macro| may have itself some arguments, the list item will be +appended as last argument), and is then re-inserted in the input stream after +the tokens resulting from this first expansion of |\macro|. The next item is +then handled. + +This is to be used in situations where one needs to do some repetitive +things. It is not expandable and can not be completely expanded inside a +macro definition, to prepare material for later execution, contrarily to what +\csbxint{Apply} or \csbxint{ApplyUnbraced} achieve. + +\begin{everbatim*} +\def\Macro #1{\advance\cnta #1 , \the\cnta} +\cnta 0 +0\xintApplyInline\Macro {3141592653}. +\end{everbatim*} +The first argument |\macro| does not have to be an expandable macro. + +\csa{xintApplyInline} submits its second, token list parameter to an +\hyperref[ssec:expansions]{\fexpan +sion}. Then, each \emph{unbraced} item will also be \fexpan ded. This provides +an easy way to insert one list inside another. \emph{Braced} items are not +expanded. Spaces in-between items are gobbled (as well as those at the start +or the end of the list), but not the spaces \emph{inside} the braced items. + +\csa{xintApplyInline}, despite being non-expandable, does survive to +contexts where the executed |\macro| closes groups, as happens inside +alignments with the tabulation character |&|. +This tabular provides an example:\par +\begin{everbatim*} +\centerline{\normalcolor\begin{tabular}{ccc} + $N$ & $N^2$ & $N^3$ \\ \hline + \def\Row #1{ #1 & \xintiiSqr {#1} & \xintiiPow {#1}{3} \\ \hline }% + \xintApplyInline \Row {\xintCSVtoList{17,28,39,50,61}} +\end{tabular}}\medskip +\end{everbatim*} + +We see that despite the fact that the first encountered tabulation character in +the first row close a group and thus erases |\Row| from \TeX's memory, +|\xintApplyInline| knows how to deal with this. + +Using \csbxint{ApplyUnbraced} is an alternative: the difference is that +this would have prepared all rows first and only put them back into the +token stream once they are all assembled, whereas with |\xintApplyInline| +each row is constructed and immediately fed back into the token stream: when +one does things with numbers having hundreds of digits, one learns that +keeping on hold and shuffling around hundreds of tokens has an impact on +\TeX{}'s speed (make this ``thousands of tokens'' for the impact to be +noticeable). + +One may nest various |\xintApplyInline|'s. For example (see the +\hyperref[float]{table} \vpageref{float}):\par +\begin{everbatim*} +\begin{figure*}[ht!] + \centering\phantomsection\label{float} + \def\Row #1{#1:\xintApplyInline {\Item {#1}}{0123456789}\\ }% + \def\Item #1#2{&\xintiiPow {#1}{#2}}% + \centeredline {\begin{tabular}{ccccccccccc} &0&1&2&3&4&5&6&7&8&9\\ \hline + \xintApplyInline \Row {0123456789} + \end{tabular}} +\end{figure*} +\end{everbatim*} + +One could not move the definition of |\Item| inside the tabular, +as it would get lost after the first |&|. But this +works: +\everb|@ +\begin{tabular}{ccccccccccc} + &0&1&2&3&4&5&6&7&8&9\\ \hline + \def\Row #1{#1:\xintApplyInline {&\xintiiPow {#1}}{0123456789}\\ }% + \xintApplyInline \Row {0123456789} +\end{tabular} +| + +A limitation is that, contrarily to what one may have expected, the +|\macro| for an |\xintApplyInline| can not be used to define +the |\macro| for a nested sub-|\xintApplyInline|. For example, +this does not work:\par +\everb|@ + \def\Row #1{#1:\def\Item ##1{&\xintiiPow {#1}{##1}}% + \xintApplyInline \Item {0123456789}\\ }% + \xintApplyInline \Row {0123456789} % does not work +| +\noindent But see \csbxint{For}. + +\subsection{\csh{xintFor}, \csh{xintFor*}}\label{xintFor}\label{xintFor*} + +\csbxint{For}\ntype{on} is a new kind of for loop.\footnote{first introduced + with \xintname |1.09c| of |2013/10/09|.} Rather than using macros +for encapsulating list items, its behaviour is like a macro with parameters: +|#1|, |#2|, \dots, |#9| are used to represent the items for up to nine levels of +nested loops. Here is an example: +% +\everb|@ +\xintFor #9 in {1,2,3} \do {% + \xintFor #1 in {4,5,6} \do {% + \xintFor #3 in {7,8,9} \do {% + \xintFor #2 in {10,11,12} \do {% + $$#9\times#1\times#3\times#2=\xintiiPrd{{#1}{#2}{#3}{#9}}$$}}}} +| +\noindent This example illustrates that one does not have to use |#1| as the +first one: +the order is arbitrary. But each level of nesting should have its specific macro +parameter. Nine levels of nesting is presumably overkill, but I did not know +where it was reasonable to stop. |\par| tokens are accepted in both the comma +separated list and the replacement text. + +\begin{framed} + \TeX nical notes: + +\begin{itemize} + \item The |#1| is replaced in the iterated-over text exactly as in general + \TeX\ macros or \LaTeX\ commands. This spares the user quite a few + |\expandafter|'s or other tricks needed with loops which have the + values encapsulated in macros, like \LaTeX's |\@for| and |\@tfor|. + + \item \csa{xintFor} (and \csa{xintFor*}) isn't purely expandable: one can + not use it inside an |\edef|. But it may be used, as will be shown in + examples, in some contexts such as \LaTeX's |tabular| which are usually + hostile to non-expandable loops. + + \item \csa{xintFor} (and \csa{xintFor*}) does some assignments prior to + executing each iteration of the replacement text, but it acts purely + expandably after the last iteration, hence if for example the replacement + text ends with a |\\|, the loop can be used insided a tabular and be + followed by a |\hline| without creating the dreaded ``|Misplaced + \noalign|'' error. + + \item It does not create groups. + + \item It makes no global assignments. + + \item The iterated replacement text may close a group which was opened even + before the start of the loop (typical example being with |&| in + alignments). +\begin{everbatim*} +\begin{tabular}{rccccc} + \hline + \xintFor #1 in {A, B, C} \do {% + #1:\xintFor #2 in {a, b, c, d, e} \do {&($ #2 \to #1 $)}\\ }% + \hline +\end{tabular} +\end{everbatim*} + + \item There is no facility provided which would give access to a count of + the number of iterations as it is technically not easy to do so it in a + way working with nested loops while maintaining the ``expandable after + done'' property; something in the spirit of \csbxint{iloopindex} is + possible but this approach would bring its own limitations and + complications. Hence the user is invited to update her own count or + \LaTeX{} counter or macro at each iteration, if needed. + + \item A |\macro| whose definition uses internally an \csbxint{For} loop + may be used inside another \csbxint{For} loop even if the two loops both + use the same macro parameter. The loop definition inside |\macro| + must use |##| as is the general rule for definitions done inside macros. + + \item \csbxint{For} is for comma separated values and \csbxint{For*} for + lists of braced items; their respective expansion policies differ. They + are described later. +\end{itemize} +\unskip +\end{framed} + +\noindent Regarding \csbxint{For}: +\begin{itemize}[nosep, listparindent=\leftmarginiii] +\item the spaces between the various declarative elements are all optional, +\item in the list of comma separated values, spaces around the commas or at + the start and end are ignored, +\item if an item must contain itself its own commas, then it should + be braced, and the braces will be removed before feeding the iterated-over + text, +\item the list may be a macro, it is expanded only once, +\item items are not pre-expanded. The first item should be braced or start + with a space if the list is explicit and the item should not be + pre-expanded, +\item empty items give empty |#1|'s in the replacement text, they are not + skipped, +\item an empty list executes once the replacement text with an empty parameter + value, +\item the list, if not a macro, \fbox{must be braced.} +\end{itemize} + +\noindent Regarding \csbxint{For*}:\ntype{{\lowast f}n} +\begin{itemize}[nosep, listparindent=\leftmarginiii] +\item it handles lists of braced items (or naked tokens), +\item it \hyperref[ssec:expansions]{\fexpan ds} the list, +\item and more generally it \hyperref[ssec:expansions]{\fexpan ds} each naked + token encountered + before assigning the |#1| values (gobbling spaces in the process); + this + makes it easy to simulate concatenation of multiple lists|\x|, |\y|: + if |\x| expands to |{1}{2}{3}| and |\y| expands to |{4}{5}{6}| then |{\x\y}| + as argument to |\xintFor*| has the same effect as |{{1}{2}{3}{4}{5}{6}}|. + + For a further illustration see the use of |\xintFor*| at the end of + \autoref{ssec:fibonacci}. +\item spaces at the start, end, or in-between items are gobbled (but naturally + not the spaces inside \emph{braced} items), +\item except if the list argument is a macro (with no parameters), \fbox{it + must be braced.}, +\item an empty list leads to an empty result. +\end{itemize} + +The macro \csbxint{Seq} which generates arithmetic sequences is to be used +with \csbxint{For*} as its output consists of successive braced numbers (given +as digit tokens). +\begin{everbatim*} +\xintFor* #1 in {\xintSeq [+2]{-7}{+2}}\do {stuff + with #1\xintifForLast{\par}{\newline}} +\end{everbatim*} + + +When nesting \csa{xintFor*} loops, using \csa{xintSeq} in the inner loops is +inefficient, as the arithmetic sequence will be re-created each time. A more +efficient style is: +% +\begin{everbatim} + \edef\innersequence {\xintSeq[+2]{-50}{50}}% + \xintFor* #1 in {\xintSeq {13}{27}} \do + {\xintFor* #2 in \innersequence \do {stuff with #1 and #2}% + .. some other macros .. } +\end{everbatim} + +This is a general remark applying for any nesting of loops, one should avoid +recreating the inner lists of arguments at each iteration of the outer loop. + + +When the loop is defined inside a macro for later execution the |#| characters +must be doubled.% +% +\footnote{sometimes what seems to be a macro argument isn't really; in + \csa{raisebox\{1cm\}\{}\csa{xintFor \#1 in \{a,b,c\} }\csa{do + \{\#1\}\}} no doubling should be done.} +% +For example: +% +\begin{everbatim*} +\def\T{\def\z {}% + \xintFor* ##1 in {{u}{v}{w}} \do {% + \xintFor ##2 in {x,y,z} \do {% + \expandafter\def\expandafter\z\expandafter {\z\sep (##1,##2)} }% + }% +}% +\T\def\sep {\def\sep{, }}\z +\end{everbatim*} + +Similarly when the replacement text +of |\xintFor| defines a macro with parameters, the macro character |#| must be +doubled. + + +The iterated macros as well as the list items are allowed to contain explicit +|\par| tokens. + + +\subsection{\csh{xintifForFirst}, \csh{xintifForLast}} +\label{xintifForFirst}\label{xintifForLast} + +\csbxint{ifForFirst}\,\texttt{\{YES branch\}\{NO branch\}}\etype{nn} + and \csbxint{ifForLast}\,\texttt{\{YES + branch\}\hskip 0pt plus 0.2em \{NO branch\}}\etype{nn} execute the |YES| or +|NO| branch +if the +\csbxint{For} +or \csbxint{For*} loop is currently in its first, respectively last, iteration. + +Designed to work as expected under nesting (but see frame next.) Don't forget +an empty brace pair |{}| if a branch is to do nothing. May be used multiple +times in the replacement text of the loop. + +\begin{framed} + \noindent Pay attention to these implementation features: + \begin{itemize}[nosep, listparindent=\leftmarginiii] + \item \emph{if an inner \csbxint{For} loop is positioned before the + \csb{xintifForFirst} or \csb{xintifForLast} of the outer loop it will + contaminate their settings. This applies also naturally if the inner loop + arises from the expansion of some macro located before the outer + conditionals.} + + One fix is to make sure that the outer conditionals are expanded before the + inner loop is executed, e.g. this will be the case if the inner loop is + located inside one of the branches of the conditional. + + Another approach is to enclose, if feasible, the inner loop in a group of + its own. + \item \emph{if the replacement text closes a group (e.g. from a |&| inside an + alignment), the conditionals will lose their ascribed meanings and end up + possibly undefined, depending whether there is some outer loop whose + execution started before the opening of the group.} + + The fix is to arrange things so that the conditionals are expanded + before \TeX\ encounters the closing-group token. + \end{itemize} +\end{framed} + +\subsection{ \csh{xintBreakFor}, \csh{xintBreakForAndDo}} +\label{xintBreakFor}\label{xintBreakForAndDo} + +One may immediately terminate an \csbxint{For} or \csbxint{For*} loop with +\csbxint{BreakFor}. + +\begin{framed} + As it acts by clearing up all the rest of the replacement text when + encountered, it will not work from inside some |\if...\fi| without + suitable |\expandafter| or swapping technique. + + Also it can't be used from inside braces as from there it can't see the end + of the replacement text. +\end{framed} + +There is also \csbxint{BreakForAndDo}. Both are illustrated by various examples +in the next section which is devoted to ``forever'' loops. + +\subsection{\csh{xintintegers}, \csh{xintdimensions}, \csh{xintrationals}} +\label{xintegers}\label{xintintegers} +\label{xintdimensions}\label{xintrationals} + +If the list argument to \csbxint{For} (or \csbxint{For*}, both are equivalent in +this context) is \csbxint{integers} (equivalently \csbxint{egers}) or more +generally \csbxint{integers}|[||start|\allowbreak|+|\allowbreak|delta||]| +(\emph{the whole within braces}!)% +% +\footnote{the |start+delta| optional specification may have extra spaces + around the plus sign of near the square brackets, such spaces are + removed. The same applies with \csa{xintdimensions} and + \csa{xintrationals}.}, +% +then \csbxint{For} does an infinite iteration where +|#1| (or |#2|, \dots, |#9|) will run through the arithmetic sequence of (short) +integers with initial value |start| and increment |delta| (default values: +|start=1|, |delta=1|; if the optional argument is present it must contains both +of them, and they may be explicit integers, or macros or count registers). The +|#1| (or |#2|, \dots, |#9|) will stand for |\numexpr <opt sign><digits>\relax|, +and the litteral representation as a string of digits can thus be obtained as +\fbox{\csa{the\#1}} or |\number#1|. Such a |#1| can be used in an |\ifnum| test +with no need to be postfixed with a space or a |\relax| and one should +\emph{not} add them. + +If the list argument is \csbxint{dimensions} or more generally +\csbxint{dimensions}|[||start|\allowbreak|+|\allowbreak|delta||]| (\emph{within + braces}!), then +\csbxint{For} does an infinite iteration where |#1| (or |#2|, \dots, |#9|) will +run through the arithmetic sequence of dimensions with initial value +|start| and increment |delta|. Default values: |start=0pt|, |delta=1pt|; if +the optional argument is present it must contain both of them, and they may +be explicit specifications, or macros, or dimen registers, or length macros +in \LaTeX{} (the stretch and shrink components will be discarded). The |#1| +will be |\dimexpr <opt sign><digits>sp\relax|, from which one can get the +litteral (approximate) representation in points via |\the#1|. So |#1| can be +used anywhere \TeX{} expects a dimension (and there is no need in conditionals +to insert a |\relax|, and one should \emph{not} do it), and to print its value +one uses \fbox{\csa{the\#1}}. The chosen representation guarantees exact +incrementation with no rounding errors accumulating from converting into +points at each step. + + + + + + +If the list argument to \csbxint{For} (or \csbxint{For*}) is \csbxint{rationals} +or more generally +\csbxint{rationals}|[||start|\allowbreak|+|\allowbreak|delta||]| (\emph{within + braces}!), then \csbxint{For} does an infinite iteration where |#1| (or |#2|, +\dots, |#9|) will run through the arithmetic sequence of \xintfracname fractions +with initial value |start| and increment |delta| (default values: |start=1/1|, +|delta=1/1|). This loop works \emph{only with \xintfracname loaded}. if the +optional argument is present it must contain both of them, and they may be given +in any of the formats recognized by \xintfracname (fractions, decimal +numbers, numbers in scientific notations, numerators and denominators in +scientific notation, etc...) , or as macros or count registers (if they are +short integers). The |#1| (or |#2|, \dots, |#9|) will be an |a/b| fraction +(without a |[n]| part), where +the denominator |b| is the product of the denominators of +|start| and |delta| (for reasons of speed |#1| is not reduced to irreducible +form, and for another reason explained later |start| and |delta| are not put +either into irreducible form; the input may use explicitely \csa{xintIrr} to +achieve that). +\begin{everbatim*} +\begingroup\small +\noindent\parbox{\dimexpr\linewidth-3em}{\color[named]{OrangeRed}% +\xintFor #1 in {\xintrationals [10/21+1/21]} \do +{#1=\xintifInt {#1} + {\textcolor{blue}{\xintTrunc{10}{#1}}} + {\xintTrunc{10}{#1}}% display in blue if an integer + \xintifGt {#1}{1.123}{\xintBreakFor}{, }% + }} +\endgroup\smallskip +\end{everbatim*} + +\smallskip The example above confirms that computations are done exactly, and +illustrates that the two initial (reduced) denominators are not multiplied when +they are found to be equal. It is thus recommended to input |start| and |delta| +with a common smallest possible denominator, or as fixed point numbers with the +same numbers of digits after the decimal mark; and this is also the reason why +|start| and |delta| are not by default made irreducible. As internally the +computations are done with numerators and denominators completely expanded, one +should be careful not to input numbers in scientific notation with exponents in +the hundreds, as they will get converted into as many zeroes. + +\begin{everbatim*} +\noindent\parbox{\dimexpr.7\linewidth}{\raggedright +\xintFor #1 in {\xintrationals [0.000+0.125]} \do +{\edef\tmp{\xintTrunc{3}{#1}}% + \xintifInt {#1} + {\textcolor{blue}{\tmp}} + {\tmp}% + \xintifGt {#1}{2}{\xintBreakFor}{, }% + }}\smallskip +\end{everbatim*} + +We see here that \csbxint{Trunc} outputs (deliberately) zero as $0$, not (here) +$0.000$, the idea being not to lose the information that the truncated thing was +truly zero. Perhaps this behaviour should be changed? or made optional? Anyhow +printing of fixed points numbers should be dealt with via dedicated packages +such as |numprint| or |siunitx|.\par + + +\subsection{\csh{xintForpair}, \csh{xintForthree}, \csh{xintForfour}}\label{xintForpair}\label{xintForthree}\label{xintForfour} + +The syntax\ntype{on} is illustrated in this +example. The notation is the usual one for |n|-uples, with parentheses and +commas. Spaces around commas and parentheses are ignored. +% +\begin{everbatim*} +{\centering\begin{tabular}{cccc} + \xintForpair #1#2 in { ( A , a ) , ( B , b ) , ( C , c ) } \do {% + \xintForpair #3#4 in { ( X , x ) , ( Y , y ) , ( Z , z ) } \do {% + $\Biggl($\begin{tabular}{cc} + -#1- & -#3-\\ + -#4- & -#2-\\ + \end{tabular}$\Biggr)$&}\\\noalign{\vskip1\jot}}% +\end{tabular}\\} +\end{everbatim*} + +\csbxint{Forpair} must be followed by either |#1#2|, |#2#3|, |#3#4|, \dots, or +|#8#9| with |#1| usable as an alias for |#1#2|, |#2| as alias for |#2#3|, +etc \dots\ and similarly for \csbxint{Forthree} (using |#1#2#3| or simply +|#1|, |#2#3#4| or simply |#2|, \dots) and \csbxint{Forfour} (with |#1#2#3#4| +etc\dots). + +Nesting works as long as the macro parameters are distinct among |#1|, |#2|, +..., |#9|. A macro which expands to an \csa{xintFor} or a +\csa{xintFor(pair,three,four)} can be used in another one with no constraint +about using distinct macro parameters. + +|\par| tokens are accepted in both the comma separated list and the +replacement text. + + +\subsection{\csh{xintAssign}}\label{xintAssign} + +\csa{xintAssign}\meta{braced things}\csa{to}% +\meta{as many cs as they are things} %\ntype{{(f$\to$\lowast [x)}{\lowast N}} +% +defines (without checking if something gets overwritten) the control sequences +on the right of \csa{to} to expand to the successive tokens or braced items +located to the left of \csa{to}. \csa{xintAssign} is not an expandable macro. + +\fexpan sion is first applied to the material in front of \csa{xintAssign} +which is fetched as one argument if it is braced. Then the expansion of this +argument is examined and successive items are assigned to the macros following +|\to|. There must be exactly as many macros as items. No check is done. The +macro assignments are done with removal of one level of brace pairs from each +item. + +After the initial \fexpan sion, each assigned (brace-stripped) item will be +expanded according to the setting of the optional parameter. + +For example |\xintAssign [e]...| means that all assignments are done using +|\edef|. With |[f]| the assignments will be made using +\hyperref[fdef]{\ttfamily\char92fdef}. The default is simply to make the +definitions with |\def|, corresponding to an empty optional paramter |[]|. +Possibilities for the optional parameter are: |[], [g], [e], [x], [o], [go], +[oo], [goo], [f], [gf]|. For example |[oo]| means a double expansion. +\begin{everbatim*} +\xintAssign \xintiiDivision{1000000000000}{133333333}\to\Q\R +\meaning\Q\newline +\meaning\R\newline +\xintAssign {{\xintiiDivision{1000000000000}{133333333}}}\to\X +\meaning\X\newline +\xintAssign [oo]{{\xintiiDivision{1000000000000}{133333333}}}\to\X +\meaning\X\newline +\xintAssign \xintiiPow{7}{13}\to\SevenToThePowerThirteen +\meaning\SevenToThePowerThirteen\par +\end{everbatim*} + +Two special cases: +\begin{itemize}[nosep] +\item if after this initial expansion no brace is found immediately after + \csa{xintAssign}, it is assumed that there is only one control sequence + following |\to|, and this control sequence is then defined via |\def| (or + what is set-up by the optional parameter) to expand to the material between + \csa{xintAssign} and \csa{to}. +\item if the material between \csa{xintAssign} and |\to| is enclosed in two + brace pairs, the first brace pair is removed, then the \fexpan sion is + immediately stopped by the inner brace pair, hence \csa{xintAssign} now + finds a unique item and thus defines only a single macro to be this item, + which is now stripped of the second pair of braces. +\end{itemize} + + +\emph{Note:} prior to release |1.09j|, |\xintAssign| did an |\edef| by default +for each item assignment but it now does |\def| corresponding to no or empty +optional parameter. + +It is allowed for the successive braced items to be separated by spaces. They +are removed during the assignments. But if a single macro is defined (which +happens if the argument after \fexpan sion does not start with a brace), +naturally the scooped up material has all intervening spaces, as it is +considered a +single item. But an upfront initial space will have been absorbed by \fexpan +sion. +\begin{everbatim*} +\def\X{ {a} {b} {c} {d} }\def\Y { u {a} {b} {c} {d} } +\xintAssign\X\to\A\B\C\D +\xintAssign\Y\to\Z +\meaning\A, \meaning\B, \meaning\C, \meaning\D+++\newline +\meaning\Z+++\par +\end{everbatim*} +As usual successive space characters in input make for a single \TeX\ space token. + + +\subsection{\csh{xintAssignArray}}\label{xintAssignArray} + +\xintAssignArray \xintBezout {1000}{113}\to\Bez + +\csa{xintAssignArray}\meta{braced things}\csa{to}\csa{myArray} +% +%\ntype{{(f$\to$\lowast x)}N} +% +first expands fully what comes immediately after |\xintAssignArray| and +expects to find a list of braced things |{A}{B}...| (or tokens). It then +defines \csa{myArray} as a macro with one parameter, such that \csa{myArray\x} +expands to give the |x|th braced thing of this original +list (the argument \texttt{\x} itself is fed to a |\numexpr| by |\myArray|, +and |\myArray| expands in two steps to its output). With |0| as parameter, +\csa{myArray}|{0}| returns the number |M| of elements of the array so that the +successive elements are \csa{myArray}|{1}|, \dots, \csa{myArray}|{M}|. +% +\leftedline{|\xintAssignArray \xintBezout {1000}{113}\to\Bez|} will set +|\Bez{0}| to \dtt{\Bez0}, |\Bez{1}| to \dtt{\Bez1}, |\Bez{2}| to +\dtt{\Bez2}, and |\Bez{3}| to \dtt{\Bez3}: +\dtt{$\Bez1\times1000+\Bez2\times113=\Bez3$.} +This macro is incompatible with expansion-only contexts. + +\csa{xintAssignArray} admits an optional parameter, for example +|\xintAssignArray [e]| means that the definitions of the macros will be made +with |\edef|. The empty optional parameter (default) means that definitions +are done with |\def|. Other possibilities: |[], [o], [oo], [f]|. Contrarily to +\csbxint{Assign} one can not use the |g| here to make the definitions global. +For this, one should rather do |\xintAssignArray| within a group starting with +|\globaldefs 1|. + + +\subsection{\csh{xintDigitsOf}}\label{xintDigitsOf} + +This is a synonym for \csbxint{AssignArray},\ntype{fN} to be used to define +an array giving all the digits of a given (positive, else the minus sign will +be treated as first item) number. +\begingroup\xintDigitsOf\xintiiPow {7}{500}\to\digits +% +\leftedline{|\xintDigitsOf\xintiiPow {7}{500}\to\digits|} +\noindent $7^{500}$ has |\digits{0}=|\digits{0} digits, and the 123rd among them +(starting from the most significant) is +|\digits{123}=|\digits{123}. +\endgroup + +\subsection{\csh{xintRelaxArray}}\label{xintRelaxArray} + +\csa{xintRelaxArray}\csa{myArray} %\ntype{N} +% +(globally) sets to \csa{relax} all macros which were defined by the previous +\csa{xintAssignArray} with \csa{myArray} as array macro. + +\clearpage +\let\xinttoolsnameUp\undefined + +\ifnum\NoSourceCode=1 +\bigskip +\begin{framed} + \small This documentation has been compiled without the source code, + which is available in the separate file: + % + \centeredline{|sourcexint.pdf|,} + % + which will open in a PDF viewer via |texdoc sourcexint.pdf|. + + To produce a single file including both the user documentation and the + source code: + \begin{itemize} + \item run |etex| on |xint.dtx| to generate |xint.tex| among other files, + \item edit |xint.tex| to set the |\NoSourceCode| toggle within it to |0|, + \item run |make clean| and then |make xint.pdf|. + \end{itemize} + This will need |latexmk|; if not available you will need in replacement of + the last step to execute manually |latex| on |xint.tex| (thrice) + then |dvipdfmx|. +\end{framed} +\fi + +\ifnum\dosourcexint=1 ++fi ++catcode`\ 0 +\catcode0 15 % retour à la normale, peu importe +\catcode`\+ 12 +\etocignoredepthtags +\etocsetnexttocdepth{section} +\tableofcontents +\makeatletter +\@gobble\fi +\StopEventually{\end{document}\endinput} +\ifnum\dosourcexint=1 +\renewcommand{\etocaftertochook}{\addvspace{\bigskipamount}} +\etocsettocstyle {}{} +\clearpage +% \newgeometry{%hmarginratio=4:3, +% hscale=0.7,vscale=0.75}% ATTENTION \newgeometry fait +% % un reset de vscale si on ne le +% % précise pas ici !!! +\else +\clearpage +\fi + +\makeatletter + +\def\MARGEPAGENO{1.25em} +\etocsettocdepth{subsubsection}% 2015/09/15 + +\etocdepthtag.toc {implementation} +\addtocontents{toc}{\gdef\string\sectioncouleur{[named]{RoyalPurple}}} + +\def\storedlinecounts {} +\def\StoreCodelineNo #1{\edef\storedlinecounts{% + \unexpanded\expandafter{\storedlinecounts}% + {{#1}{\the\c@CodelineNo}}}\c@CodelineNo\z@ } + +% \macrocode +% ========== +% 2014/11/04 did some hack with active characters à la upquote for +% straight quotes, but this is now irrelevant as we use suitable font +% from newtxtt with straight quotes. + +% +% Actually, I should not at all rely on the doc class, I should do it all by +% myself. As I don't use at all \DocInput (which caused me loads of problems +% back then when I was trying to get a workflow satisfying my views on how +% .dtx files should be structured), there is not much rationale for using the +% doc class. + +\def\macrocode{\macro@code + \frenchspacing \@vobeyspaces + \makestarlowast + \xmacro@code } + +\def\macro@font {\ttbfamily }% slashed 0 + +% \lverb +% ====== + +% Définition de \lverb +% Has become more complicated for 1.2l +\catcode`_ 11 +{\catcode32\active% +\gdef\myobeyspaces{\catcode32\active\def {\leavevmode\kern\fontcharwd\font`X}}} +\def\lverbpercent {\catcode32\active\lverbpercent_a}% +\def\lverbpercent_a #1{% + \if\XINT_sptoken\detokenize{#1}\xint_dothis{\catcode32 10 }\fi + \if-\detokenize{#1}\xint_dothis{\par #1}\fi + \if(\detokenize{#1}\xint_dothis{\par\bgroup\myobeyspaces\obeylines}\fi + \if:\detokenize{#1}\xint_dothis{}\fi + \if)\detokenize{#1}\xint_dothis{\egroup\everypar{\hskip-\parindent\everypar{}}}\fi + \if!\detokenize{#1}\xint_dothis{\lverbpercent}\fi + \ifx#1\lverbpercent\xint_dothis{\catcode32 10 \par #1}\fi + \xint_orthat{\catcode32 10 #1}% +} +\catcode`_ 8 +\long\def\lverb {% + \relax\par\smallskip%\noindent\null + \begingroup + \bgroup + \aftergroup\@@par \aftergroup\endgroup \aftergroup\medskip + \let\do\do@noligs \verbatim@nolig@list + \let\do\@makeother \dospecials + \catcode32 10 \catcode`\& 14 \catcode`\$ 0 + \catcode`\% \active + \begingroup\lccode`\~`\%\lowercase{\endgroup\let~\lverbpercent}% + \MicroFont % sera donc en couleur. + \@lverb +} + +\def\@lverb #1{\catcode`#1\active + \lccode`\~`#1\lowercase{\let~\egroup}}% + +\def\MicroFont {%\ttzfamily + \color[named]{Purple}\makestarlowast } + +% privatecodecomments +% =================== +\newenvironment{privatecodecomments} + {\par \textbf{\textcolor{red}{COMMENTAIRES PRIVÉS.}}\par + \begingroup\lccode`\~`\%\lowercase{\endgroup\let~\lverbpercent}% + \catcode`\%\active} + {\par \textbf{\textcolor{red}{FIN DES COMMENTAIRES PRIVÉS.}}\par} + +% \changed +% ======== + +\def\changed#1#2{% + \par\smallskip\noindent + \textbf{#1\if\relax\detokenize{#2}\relax\else\space(#2)\fi.}% +% \hangindent\leftmarginii + \hangindent\parindent +} + +% Hyperlinks +% ========== + +% renew some definitions (new labels, prefixed with src-) + +% hyperlink and slash +\DeclareRobustCommand\csbxint[1] + {\hyperref[\detokenize{src-xint#1}]% + {{\char92\mbox{xint}\-\endlinechar-1 + \makestarlowast \catcode`_ 12 \catcode`^ 12 + \scantokens\expandafter{\detokenize{#1}}}}} + +\DeclareRobustCommand\csbXINT[1] + {\hyperref[\detokenize{src-XINT#1}]% + {{\char92\mbox{XINT}\-\endlinechar-1 + \makestarlowast \catcode`_ 12 \catcode`^ 12 + \scantokens\expandafter{\detokenize{#1}}}}} + +\DeclareRobustCommand\csb [1] + {\hyperref[\detokenize{src-#1}]% + {{\char92 \endlinechar-1 + \makestarlowast \catcode`_ 12 \catcode`^ 12 + \scantokens\expandafter{\detokenize{#1}}}}} + +% hyperlink and no slash +\DeclareRobustCommand\csbn[1] + {\hyperref[\detokenize{src-#1}]% + {{\endlinechar-1 + \makestarlowast \catcode`_ 12 \catcode`^ 12 + \scantokens\expandafter{\detokenize{#1}}}}} + +% HACK OF \@sect +% ============== +% goal is to add labels but without having to modify currently +% existing mark-up in sources. But KOMA annoyingly makes an extra +% step needed. 2018/06/11 +\let\original@sect\@sect +\def\@sect#1#2#3#4#5#6[#7]#8{\original@sect{#1}{#2}{#3}{#4}{#5}{#6}[{#7}]% + {\begingroup + %not possible because of KOMA wrappers + %\def\csh##1{\csa{##1}\label{\detokenize{src-##1}}}% + \let\csh\cshintitle + \let\cshn\cshnintitle + #8% + \endgroup}% +}% +\def\cshintitle#1{\csa{#1}% + \label{\detokenize{src-#1}}% + %\expandafter\DescribeMacro\csname#1\endcsname + } +% \csan: no backslash +\def\cshnintitle#1{\csan{#1}\label{\detokenize{src-#1}}} + +%% END OF MACRO DEFINITIONS FOR SOURCEXINT + +\def\xintImpRunningHeader{{\catcode`,12\relax + \DOCxintfrontpage, + \xintkernelnameimp, + \xinttoolsnameimp, + \xintcorenameimp, + \xintnameimp, + \xintbinhexnameimp, + \xintgcdnameimp, + \xintfracnameimp, + \xintseriesnameimp, + \xintcfracnameimp, + \xintexprnameimp, + \xinttrignameimp, \xintlognameimp}} +\markboth{\makebox[0pt]{\xintImpRunningHeader}}{\makebox[0pt]{\xintImpRunningHeader}} + +\makeatother + +\section{Introduction to the implementation (recent changes)} + +This is \expandafter|\xintbndlversion| of \expandafter|\xintbndldate|. + +Please refer to |CHANGES.pdf| or |CHANGES.html|.\centeredline{Internet: + \url{http://mirrors.ctan.org/macros/generic/xint/CHANGES.html}} +We keep here only a brief timeline of the most important changes. + +At |1.3e| the indices which were added at |1.3c| got removed: their inclusion +caused extra time in the build of |sourcexint.pdf|, larger file size, and the +macros created using |\csname...\endcsname| were not indexed, of course the +indexing of functions would have needed systematic extra mark-up. Besides +their functionality is advantageously made available via the search function +in PDF viewers. Already the local tables of contents are useful enough most of +the time when one searches something. + +\begin{itemize} +\item Release |1.3e| of |2019/04/01|: \xinttrignameimp, \xintlognameimp, + \csbxint{defefunc} ``non-protected'' variant of \csbxint{deffunc}. Indices + removed from |sourcexint.pdf|. +\item Release |1.3d| of |2019/01/06|: bugfix of |1.2p| bug for division with a + zero dividend and a one-digit divisor, \csbxint{eval} et al. wrappers, + |gcd()| and |lcm()| work with fractions. +\item Release |1.3c| of |2018/06/17|: documentation better hyperlinked, + |sourcexint.pdf| with indices of macros. Colon in |:=| now optional for + \csbxint{defvar} and \csbxint{deffunc}. +\item Release |1.3b| of |2018/05/18|: randomness related additions (still WIP). +\item Release |1.3a| of |2018/03/07|: efficiency fix of the mechanism for + recursive functions. +\item Release |1.3| of |2018/03/01|: addition and subtraction use + systematically least common multiple of denominators. Extensive + under-the-hood refactoring of \csbxint{NewExpr} and \csbxint{deffunc} which + now allow recursive definitions. Removal of |1.2o| deprecated macros. +\item Release |1.2q| of |2018/02/06|: bugfix release (|1.2l| subtraction bug + in special situation); tacit multiplication extended to cases such as + |10!20!30!|. +\item Release |1.2p| of |2017/12/05|: maps |//| and |/:| to the floored, not + truncated, division. Simultaneous assignments possible with \csbxint{defvar}. + Efficiency improvements in \xinttoolsnameimp. +\item Release |1.2o| of |2017/08/29|: massive deprecations of those macros + from \xintcorenameimp and \xintnameimp which filtered their arguments via + \csbxint{Num}. +\item Release |1.2n| of |2017/08/06|: improvements of \xintbinhexnameimp. +\item Release |1.2m| of |2017/07/31|: rewrite of \xintbinhexnameimp in the + style of the |1.2| techniques. +\item Release |1.2l| of |2017/07/26|: under the hood efficiency improvements + in the style of the |1.2| techniques; subtraction refactored. Compatibility + of most \xintfracnameimp macros with arguments using non-delimited + |\the\numexpr| or |\the\mathcode| etc... +\item Release |1.2i| of |2016/12/13|: under the hood efficiency improvements + in the style of the |1.2| techniques. +\item Release |1.2| of |2015/10/10|: complete refactoring of the core + arithmetic macros and faster \csbxint{expr} parser. +\item Release |1.1| of |2014/10/28|: extensive changes in \xintexprnameimp. + Addition and subtraction do not multiply denominators blindly but sometimes + produce smaller ones. Also with that release, packages \xintkernelnameimp + and \xintcorenameimp got extracted from \xinttoolsnameimp and \xintnameimp. +\end{itemize} + +Some parts of the code still date back to the initial release, and + at that time I was learning my trade in expandable TeX macro programming. + At some point in the future, I will have to re-examine the older parts of + the code. + +Warning: pay attention when looking at the code to the catcode configuration +as found in \csbXINT{_setcatcodes}. Additional temporary configuration is used +at some locations. For example |!| is of catcode letter in \xintexprnameimp +and there are locations with funny catcodes e.g. using some letters with the +math shift catcode. + +\MakePercentIgnore +%\def\gardesactifs {^^A +%\catcode`\<=0 \catcode`\>=11 \catcode`\*=11 \catcode`\/=11 } +%\def\gardesinactifs {^^A +%\catcode`\<=12 \catcode`\>=12 \catcode`\*=12 \catcode`\/=12 } +%\gardesactifs +%\let</dtx>\relax +%\let<*xintkernel>\gardesinactifs +%</dtx>^^A-------------------------------------------------------- +%<*xintkernel>^^A------------------------------------------------- +%^^A -*- coding: utf-8; mode: doctex; fill-column: 78; -*- +% \clearpage\csname xintkernelnameUp\endcsname +% \section {Package \xintkernelnameimp implementation} +% \RaisedLabel{sec:kernelimp} +% +% \localtableofcontents +% +% This package provides the common minimal code base for loading management +% and catcode control and also a few programming utilities. With |1.2| a few +% more helper macros and all |\chardef|'s have been moved here. The package is +% loaded by both |xintcore.sty| and |xinttools.sty| hence by all other +% packages. +% +% \changed{1.1}{} +% separated package. +% +% \changed{1.2i}{} +% \csbxint{replicate}, \csbxint{gobble}, \csbxint{LengthUpTo} +% and \csbxint{LastItem}, and faster \csbxint{Length}. +% +% \changed{1.3b}{} +% \csbxint{UniformDeviate}. +% +% \subsection{Catcodes, \protect\eTeX{} and reload detection} +% +% The code for reload detection was initially copied from \textsc{Heiko +% Oberdiek}'s packages, then modified. +% +% The method for catcodes was also initially directly inspired by these +% packages. +% +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode35=6 % # + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \catcode95=11 % _ + \expandafter + \ifx\csname PackageInfo\endcsname\relax + \def\y#1#2{\immediate\write-1{Package #1 Info: #2.}}% + \else + \def\y#1#2{\PackageInfo{#1}{#2}}% + \fi + \let\z\relax + \expandafter + \ifx\csname numexpr\endcsname\relax + \y{xintkernel}{\numexpr not available, aborting input}% + \def\z{\endgroup\endinput}% + \else + \expandafter + \ifx\csname XINTsetupcatcodes\endcsname\relax + \else + \y{xintkernel}{I was already loaded, aborting input}% + \def\z{\endgroup\endinput}% + \fi + \fi + \ifx\z\relax\else\expandafter\z\fi% +% \end{macrocode} +% \subsubsection{\csh{XINT_setcatcodes}, \csh{XINT_storecatcodes}, +% \csh{XINT_restorecatcodes_endinput}} +% \begin{macrocode} + \def\PrepareCatcodes + {% + \endgroup + \def\XINT_restorecatcodes + {% takes care of all, to allow more economical code in modules + \catcode0=\the\catcode0 % + \catcode59=\the\catcode59 % ; xintexpr + \catcode126=\the\catcode126 % ~ xintexpr + \catcode39=\the\catcode39 % ' xintexpr + \catcode34=\the\catcode34 % " xintbinhex, and xintexpr + \catcode63=\the\catcode63 % ? xintexpr + \catcode124=\the\catcode124 % | xintexpr + \catcode38=\the\catcode38 % & xintexpr + \catcode64=\the\catcode64 % @ xintexpr + \catcode33=\the\catcode33 % ! xintexpr + \catcode93=\the\catcode93 % ] -, xintfrac, xintseries, xintcfrac + \catcode91=\the\catcode91 % [ -, xintfrac, xintseries, xintcfrac + \catcode36=\the\catcode36 % $ xintgcd only + \catcode94=\the\catcode94 % ^ + \catcode96=\the\catcode96 % ` + \catcode47=\the\catcode47 % / + \catcode41=\the\catcode41 % ) + \catcode40=\the\catcode40 % ( + \catcode42=\the\catcode42 % * + \catcode43=\the\catcode43 % + + \catcode62=\the\catcode62 % > + \catcode60=\the\catcode60 % < + \catcode58=\the\catcode58 % : + \catcode46=\the\catcode46 % . + \catcode45=\the\catcode45 % - + \catcode44=\the\catcode44 % , + \catcode35=\the\catcode35 % # + \catcode95=\the\catcode95 % _ + \catcode125=\the\catcode125 % } + \catcode123=\the\catcode123 % { + \endlinechar=\the\endlinechar + \catcode13=\the\catcode13 % ^^M + \catcode32=\the\catcode32 % + \catcode61=\the\catcode61\relax % = + }% + \edef\XINT_restorecatcodes_endinput + {% + \XINT_restorecatcodes\noexpand\endinput % + }% + \def\XINT_setcatcodes + {% + \catcode61=12 % = + \catcode32=10 % space + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode95=11 % _ LETTER + \catcode35=6 % # + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=11 % : LETTER + \catcode60=12 % < + \catcode62=12 % > + \catcode43=12 % + + \catcode42=12 % * + \catcode40=12 % ( + \catcode41=12 % ) + \catcode47=12 % / + \catcode96=12 % ` + \catcode94=11 % ^ LETTER + \catcode36=3 % $ + \catcode91=12 % [ + \catcode93=12 % ] + \catcode33=12 % ! (xintexpr.sty will use catcode 11) + \catcode64=11 % @ LETTER + \catcode38=7 % & for \romannumeral`&&@ trick. + \catcode124=12 % | + \catcode63=11 % ? LETTER + \catcode34=12 % " + \catcode39=12 % ' + \catcode126=3 % ~ MATH + \catcode59=12 % ; + \catcode0=12 % for \romannumeral`&&@ trick + }% + \XINT_setcatcodes + }% +\PrepareCatcodes +% \end{macrocode} +% Other modules could possibly be loaded under a different catcode regime. +% \begin{macrocode} +\def\XINTsetupcatcodes {% for use by other modules + \edef\XINT_restorecatcodes_endinput + {% + \XINT_restorecatcodes\noexpand\endinput % + }% + \XINT_setcatcodes +}% +% \end{macrocode} +% \subsection{Package identification} +% +% Inspired from \textsc{Heiko Oberdiek}'s packages. Modified in |1.09b| to allow +% re-use in the other modules. Also I assume now that if |\ProvidesPackage| +% exists it then does define |\ver@<pkgname>.sty|, code of |HO| for some reason +% escaping me (compatibility with LaTeX 2.09 or other things ??) seems to set +% extra precautions. +% +% |1.09c| uses e-\TeX{} |\ifdefined|. +% \begin{macrocode} +\ifdefined\ProvidesPackage + \let\XINT_providespackage\relax +\else + \def\XINT_providespackage #1#2[#3]% + {\immediate\write-1{Package: #2 #3}% + \expandafter\xdef\csname ver@#2.sty\endcsname{#3}}% +\fi +\XINT_providespackage +\ProvidesPackage {xintkernel}% + [2019/04/05 1.3e Paraphernalia for the xint packages (JFB)]% +% \end{macrocode} +% \subsection{Constants} +% \begin{macrocode} +\chardef\xint_c_ 0 +\chardef\xint_c_i 1 +\chardef\xint_c_ii 2 +\chardef\xint_c_iii 3 +\chardef\xint_c_iv 4 +\chardef\xint_c_v 5 +\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 +\chardef\xint_c_xii 12 +\chardef\xint_c_xiv 14 +\chardef\xint_c_xvi 16 +\chardef\xint_c_xviii 18 +\chardef\xint_c_xxii 22 +\chardef\xint_c_ii^v 32 +\chardef\xint_c_ii^vi 64 +\chardef\xint_c_ii^vii 128 +\mathchardef\xint_c_ii^viii 256 +\mathchardef\xint_c_ii^xii 4096 +\mathchardef\xint_c_x^iv 10000 +% \end{macrocode} +% \subsection{(WIP) \csh{xint_texuniformdeviate} and needed counts} +% \begin{macrocode} +\ifdefined\pdfuniformdeviate \let\xint_texuniformdeviate\pdfuniformdeviate\fi +\ifdefined\uniformdeviate \let\xint_texuniformdeviate\uniformdeviate \fi +\ifx\xint_texuniformdeviate\relax\let\xint_texuniformdeviate\xint_undefined\fi +\ifdefined\xint_texuniformdeviate + \csname newcount\endcsname\xint_c_ii^xiv + \xint_c_ii^xiv 16384 % "4000, 2**14 + \csname newcount\endcsname\xint_c_ii^xxi + \xint_c_ii^xxi 2097152 % "200000, 2**21 +\fi +% \end{macrocode} +% \subsection{Token management utilities} +% \changed{1.3b}{} +% |\xint_gobandstop_...| macros because this is handy for +% \csbxint{RandomDigits}. +% \begin{macrocode} +\def\XINT_tmpa { }% +\ifx\XINT_tmpa\space\else + \immediate\write-1{Package xintkernel Warning: ATTENTION!}% + \immediate\write-1{\string\space\XINT_tmpa macro does not have its normal + meaning.}% + \immediate\write-1{\XINT_tmpa\XINT_tmpa\XINT_tmpa\XINT_tmpa + All kinds of catastrophes will ensue!!!!}% +\fi +\def\XINT_tmpb {}% +\ifx\XINT_tmpb\empty\else + \immediate\write-1{Package xintkernel Warning: ATTENTION!}% + \immediate\write-1{\string\empty\XINT_tmpa macro does not have its normal + meaning.}% + \immediate\write-1{\XINT_tmpa\XINT_tmpa\XINT_tmpa\XINT_tmpa + All kinds of catastrophes will ensue!!!!}% +\fi +\let\XINT_tmpa\relax \let\XINT_tmpb\relax +\ifdefined\space\else\def\space { }\fi +\ifdefined\empty\else\def\empty {}\fi +\let\xint_gobble_\empty +\long\def\xint_gobble_i #1{}% +\long\def\xint_gobble_ii #1#2{}% +\long\def\xint_gobble_iii #1#2#3{}% +\long\def\xint_gobble_iv #1#2#3#4{}% +\long\def\xint_gobble_v #1#2#3#4#5{}% +\long\def\xint_gobble_vi #1#2#3#4#5#6{}% +\long\def\xint_gobble_vii #1#2#3#4#5#6#7{}% +\long\def\xint_gobble_viii #1#2#3#4#5#6#7#8{}% +\let\xint_gob_andstop_\space +\long\def\xint_gob_andstop_i #1{ }% +\long\def\xint_gob_andstop_ii #1#2{ }% +\long\def\xint_gob_andstop_iii #1#2#3{ }% +\long\def\xint_gob_andstop_iv #1#2#3#4{ }% +\long\def\xint_gob_andstop_v #1#2#3#4#5{ }% +\long\def\xint_gob_andstop_vi #1#2#3#4#5#6{ }% +\long\def\xint_gob_andstop_vii #1#2#3#4#5#6#7{ }% +\long\def\xint_gob_andstop_viii #1#2#3#4#5#6#7#8{ }% +\long\def\xint_firstofone #1{#1}% +\long\def\xint_firstoftwo #1#2{#1}% +\long\def\xint_secondoftwo #1#2{#2}% +\let\xint_stop_aftergobble\xint_gob_andstop_i +\long\def\xint_stop_atfirstofone #1{ #1}% +\long\def\xint_stop_atfirstoftwo #1#2{ #1}% +\long\def\xint_stop_atsecondoftwo #1#2{ #2}% +\long\def\xint_exchangetwo_keepbraces #1#2{{#2}{#1}}% +% \end{macrocode} +% \subsection{``gob til'' macros and UD style fork} +% \begin{macrocode} +\long\def\xint_gob_til_R #1\R {}% +\long\def\xint_gob_til_W #1\W {}% +\long\def\xint_gob_til_Z #1\Z {}% +\long\def\xint_gob_til_zero #10{}% +\long\def\xint_gob_til_one #11{}% +\long\def\xint_gob_til_zeros_iii #1000{}% +\long\def\xint_gob_til_zeros_iv #10000{}% +\long\def\xint_gob_til_eightzeroes #100000000{}% +\long\def\xint_gob_til_dot #1.{}% +\long\def\xint_gob_til_G #1G{}% +\long\def\xint_gob_til_minus #1-{}% +\long\def\xint_UDzerominusfork #10-#2#3\krof {#2}% +\long\def\xint_UDzerofork #10#2#3\krof {#2}% +\long\def\xint_UDsignfork #1-#2#3\krof {#2}% +\long\def\xint_UDwfork #1\W#2#3\krof {#2}% +\long\def\xint_UDXINTWfork #1\XINT_W#2#3\krof {#2}% +\long\def\xint_UDzerosfork #100#2#3\krof {#2}% +\long\def\xint_UDonezerofork #110#2#3\krof {#2}% +\long\def\xint_UDsignsfork #1--#2#3\krof {#2}% +\let\xint:\char +\long\def\xint_gob_til_xint:#1\xint:{}% +\def\xint_bracedstopper{\xint:}% +\long\def\xint_gob_til_exclam #1!{}% +\long\def\xint_gob_til_sc #1;{}% +% \end{macrocode} +% \subsection{\csh{xint_afterfi}} +% \begin{macrocode} +\long\def\xint_afterfi #1#2\fi {\fi #1}% +% \end{macrocode} +% \subsection{\csh{xint_bye}, \csh{xint_Bye}} +% \changed{1.09}{} +% |\xint_bye| +% \changed{1.2i}{} +% |\xint_Bye| for \csbxint{DSRr} and \csbxint{Round}. Also |\xint_stop_afterbye|. +% \begin{macrocode} +\long\def\xint_bye #1\xint_bye {}% +\long\def\xint_Bye #1\xint_bye {}% +\long\def\xint_stop_afterbye #1\xint_bye { }% +% \end{macrocode} +% \subsection{\csh{xintdothis}, \csh{xintorthat}} +% \changed{1.1}{} +% \changed{1.2}{} names without underscores. +% +% To be used this way: +% \lverb| +%( \if..\xint_dothis{..}\fi +%: \if..\xint_dothis{..}\fi +%: \if..\xint_dothis{..}\fi +%: ...more such... +%: \xint_orthat{...} +%) | +% Ancient testing indicated it is more efficient to list first the more +% improbable clauses. +% \begin{macrocode} +\long\def\xint_dothis #1#2\xint_orthat #3{\fi #1}% 1.1 +\let\xint_orthat \xint_firstofone +\long\def\xintdothis #1#2\xintorthat #3{\fi #1}% +\let\xintorthat \xint_firstofone +% \end{macrocode} +% \subsection{\csh{xint_zapspaces}} +% \changed{1.1}{} +% +% This little utility zaps leading, intermediate, trailing, spaces in +% completely expanding context (|\edef|, |\csname...\endcsname|). +% \centeredline{Usage: |\xint_zapspaces foo<space>\xint_gobble_i|} +% +% Will remove some brace pairs (but not spaces inside them). By the way the +% |\zap@spaces| of LaTeX2e handles unexpectedly things such as +% \centeredline{|\zap@spaces 1 {22} 3 4 \@empty|} (spaces are not all +% removed). This does not happen with |\xint_zapspaces|. +% +% Explanation: if there are leading spaces, then the first |#1| will be empty, +% and the first |#2| being undelimited will be stripped from all the remaining +% leading spaces, if there was more than one to start with. Of course +% brace-stripping may occur. And this iterates: each time a |#2| is removed, +% either we then have spaces and next |#1| will be empty, or we have no spaces +% and |#1| will end at the first space. Ultimately |#2| will be +% |\xint_gobble_i|. +% +% This is not really robust as it may switch the expansion order of macros, +% and the |\xint_zapspaces| token might end up being fetched up by a macro. +% But it is enough for our purposes, for example: +% \centeredline{|\the\numexpr\xint_zapspaces 1 2 \xint_gobble_i\relax|} +% expands to |12|, not to |12\relax|. +% +% \changed{1.2e}{} |\xint_zapspaces_o|. Expansion of |#1| should not gobble a +% space! +% +% \changed{1.2i}{} made |\long|. +% \begin{macrocode} +\long\def\xint_zapspaces #1 #2{#1#2\xint_zapspaces }% 1.1 +\long\def\xint_zapspaces_o #1{\expandafter\xint_zapspaces#1 \xint_gobble_i}% +% \end{macrocode} +% \subsection{\csh{odef}, \csh{oodef}, \csh{fdef}} +% May be prefixed with |\global|. No parameter text. +% \begin{macrocode} +\def\xintodef #1{\expandafter\def\expandafter#1\expandafter }% +\def\xintoodef #1{\expandafter\expandafter\expandafter\def + \expandafter\expandafter\expandafter#1% + \expandafter\expandafter\expandafter }% +\def\xintfdef #1#2% + {\expandafter\def\expandafter#1\expandafter{\romannumeral`&&@#2}}% +\ifdefined\odef\else\let\odef\xintodef\fi +\ifdefined\oodef\else\let\oodef\xintoodef\fi +\ifdefined\fdef\else\let\fdef\xintfdef\fi +% \end{macrocode} +% \subsection{\csh{xintReverseOrder}} +% \changed{1.0}{} does not expand its argument. The whole of xint codebase now +% contains only two calls to |\XINT_rord_main| (in \xintgcdnameimp). +% +% Attention: removes brace pairs (and swallows spaces). +% +% For digit tokens a faster reverse macro is provided by (|1.2|) +% \csbxint{ReverseDigits} in \xintnameimp. +% +% For comma separated items, |1.2g| has \csbxint{CSVReverse} in +% \xinttoolsnameimp. +% \begin{macrocode} +\def\xintReverseOrder {\romannumeral0\xintreverseorder }% +\long\def\xintreverseorder #1% +{% + \XINT_rord_main {}#1% + \xint: + \xint_bye\xint_bye\xint_bye\xint_bye + \xint_bye\xint_bye\xint_bye\xint_bye + \xint: +}% +\long\def\XINT_rord_main #1#2#3#4#5#6#7#8#9% +{% + \xint_bye #9\XINT_rord_cleanup\xint_bye + \XINT_rord_main {#9#8#7#6#5#4#3#2#1}% +}% +\def\XINT_rord_cleanup #1{% +\long\def\XINT_rord_cleanup\xint_bye\XINT_rord_main ##1##2\xint: +{% + \expandafter#1\xint_gob_til_xint: ##1% +}}\XINT_rord_cleanup { }% +% \end{macrocode} +% \subsection{\csh{xintLength}} +% \changed{1.0}{} does not expand its argument. See \csbxint{NthElt}|{0}| from +% \xinttoolsnameimp which f-expands its argument. +% +% \changed{1.2g}{} added \csbxint{CSVLength} to \xinttoolsnameimp. +% +% \changed{1.2i}{} rewrote this venerable macro. New code about 40\% +% faster across all lengths. +% \begin{macrocode} +\def\xintLength {\romannumeral0\xintlength }% +\def\xintlength #1{\long\def\xintlength ##1% +{% + \expandafter#1\the\numexpr\XINT_length_loop + ##1\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v + \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye + \relax +}}\xintlength{ }% +\long\def\XINT_length_loop #1#2#3#4#5#6#7#8#9% +{% + \xint_gob_til_xint: #9\XINT_length_finish_a\xint: + \xint_c_ix+\XINT_length_loop +}% +\def\XINT_length_finish_a\xint:\xint_c_ix+\XINT_length_loop + #1#2#3#4#5#6#7#8#9% +{% + #9\xint_bye +}% +% \end{macrocode} +% \subsection{\csh{xintLastItem}} +% \changed{1.2i}{2016/12/10} +% Output empty if input empty. One level +% of braces removed in output. Does not expand its argument. +% \begin{macrocode} +\def\xintLastItem {\romannumeral0\xintlastitem }% +\long\def\xintlastitem #1% +{% + \XINT_last_loop {}.#1% + {\xint:\XINT_last_loop_enda}{\xint:\XINT_last_loop_endb}% + {\xint:\XINT_last_loop_endc}{\xint:\XINT_last_loop_endd}% + {\xint:\XINT_last_loop_ende}{\xint:\XINT_last_loop_endf}% + {\xint:\XINT_last_loop_endg}{\xint:\XINT_last_loop_endh}\xint_bye +}% +\long\def\XINT_last_loop #1.#2#3#4#5#6#7#8#9% +{% + \xint_gob_til_xint: #9% + {#8}{#7}{#6}{#5}{#4}{#3}{#2}{#1}\xint: + \XINT_last_loop {#9}.% +}% +\long\def\XINT_last_loop_enda #1#2\xint_bye{ #1}% +\long\def\XINT_last_loop_endb #1#2#3\xint_bye{ #2}% +\long\def\XINT_last_loop_endc #1#2#3#4\xint_bye{ #3}% +\long\def\XINT_last_loop_endd #1#2#3#4#5\xint_bye{ #4}% +\long\def\XINT_last_loop_ende #1#2#3#4#5#6\xint_bye{ #5}% +\long\def\XINT_last_loop_endf #1#2#3#4#5#6#7\xint_bye{ #6}% +\long\def\XINT_last_loop_endg #1#2#3#4#5#6#7#8\xint_bye{ #7}% +\long\def\XINT_last_loop_endh #1#2#3#4#5#6#7#8#9\xint_bye{ #8}% +% \end{macrocode} +% \subsection{\csh{xintLengthUpTo}} +% \changed{1.2i}{} for use by \csbxint{Keep} and \csbxint{Trim} +% (\xinttoolsnameimp). The argument N **must be non-negative**. +% +% |\xintLengthUpTo{N}{List}| produces |-0| if length(List)>N, else it returns +% N-length(List). Hence subtracting it from N always computes min(N,length(List)). +% \changed{1.2j}{} changed ending and interface to core loop. +% \begin{macrocode} +\def\xintLengthUpTo {\romannumeral0\xintlengthupto}% +\long\def\xintlengthupto #1#2% +{% + \expandafter\XINT_lengthupto_loop + \the\numexpr#1.#2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_vii\xint_c_vi\xint_c_v\xint_c_iv + \xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye.% +}% +\def\XINT_lengthupto_loop_a #1% +{% + \xint_UDsignfork + #1\XINT_lengthupto_gt + -\XINT_lengthupto_loop + \krof #1% +}% +\long\def\XINT_lengthupto_gt #1\xint_bye.{-0}% +\long\def\XINT_lengthupto_loop #1.#2#3#4#5#6#7#8#9% +{% + \xint_gob_til_xint: #9\XINT_lengthupto_finish_a\xint:% + \expandafter\XINT_lengthupto_loop_a\the\numexpr #1-\xint_c_viii.% +}% +\def\XINT_lengthupto_finish_a\xint:\expandafter\XINT_lengthupto_loop_a + \the\numexpr #1-\xint_c_viii.#2#3#4#5#6#7#8#9% +{% + \expandafter\XINT_lengthupto_finish_b\the\numexpr #1-#9\xint_bye +}% +\def\XINT_lengthupto_finish_b #1#2.% +{% + \xint_UDsignfork + #1{-0}% + -{ #1#2}% + \krof +}% +% \end{macrocode} +% \subsection{\csh{xintreplicate}} +% \changed{1.2i}{} +% +% This is cloned from LaTeX3's |\prg_replicate:nn|, see Joseph's post +% at +% \centeredline{http://tex.stackexchange.com/questions/16189/repeat-command-n-times} +% I +% posted there an alternative not using the chained |\csname|'s but it is a bit +% less efficient (except perhaps for thousands of repetitions). +% The code in Joseph's post does |abs(#1)| replications when input |#1| is negative +% and then activates an error triggering macro; here we simply do nothing when +% |#1| is negative. +% \centeredline{Usage: |\romannumeral\xintreplicate{N}{stuff}|} +% +% When |N| is already explicit digits (even |N=0|, but non-negative) one can +% call the macro as +% \centeredline{|\romannumeral\XINT_rep N\endcsname {foo}|} +% to skip the |\numexpr|. +% \begin{macrocode} +\def\xintreplicate#1% + {\expandafter\XINT_replicate\the\numexpr#1\endcsname}% +\def\XINT_replicate #1{\xint_UDsignfork + #1\XINT_rep_neg + -\XINT_rep + \krof #1}% +\long\def\XINT_rep_neg #1\endcsname #2{\xint_c_}% +\def\XINT_rep #1{\csname XINT_rep_f#1\XINT_rep_a}% +\def\XINT_rep_a #1{\csname XINT_rep_#1\XINT_rep_a}% +\def\XINT_rep_\XINT_rep_a{\endcsname}% +\long\expandafter\def\csname XINT_rep_0\endcsname #1% + {\endcsname{#1#1#1#1#1#1#1#1#1#1}}% +\long\expandafter\def\csname XINT_rep_1\endcsname #1% + {\endcsname{#1#1#1#1#1#1#1#1#1#1}#1}% +\long\expandafter\def\csname XINT_rep_2\endcsname #1% + {\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1}% +\long\expandafter\def\csname XINT_rep_3\endcsname #1% + {\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1}% +\long\expandafter\def\csname XINT_rep_4\endcsname #1% + {\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1}% +\long\expandafter\def\csname XINT_rep_5\endcsname #1% + {\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1}% +\long\expandafter\def\csname XINT_rep_6\endcsname #1% + {\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1}% +\long\expandafter\def\csname XINT_rep_7\endcsname #1% + {\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1#1}% +\long\expandafter\def\csname XINT_rep_8\endcsname #1% + {\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1#1#1}% +\long\expandafter\def\csname XINT_rep_9\endcsname #1% + {\endcsname{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1#1#1#1}% +\long\expandafter\def\csname XINT_rep_f0\endcsname #1% + {\xint_c_}% +\long\expandafter\def\csname XINT_rep_f1\endcsname #1% + {\xint_c_ #1}% +\long\expandafter\def\csname XINT_rep_f2\endcsname #1% + {\xint_c_ #1#1}% +\long\expandafter\def\csname XINT_rep_f3\endcsname #1% + {\xint_c_ #1#1#1}% +\long\expandafter\def\csname XINT_rep_f4\endcsname #1% + {\xint_c_ #1#1#1#1}% +\long\expandafter\def\csname XINT_rep_f5\endcsname #1% + {\xint_c_ #1#1#1#1#1}% +\long\expandafter\def\csname XINT_rep_f6\endcsname #1% + {\xint_c_ #1#1#1#1#1#1}% +\long\expandafter\def\csname XINT_rep_f7\endcsname #1% + {\xint_c_ #1#1#1#1#1#1#1}% +\long\expandafter\def\csname XINT_rep_f8\endcsname #1% + {\xint_c_ #1#1#1#1#1#1#1#1}% +\long\expandafter\def\csname XINT_rep_f9\endcsname #1% + {\xint_c_ #1#1#1#1#1#1#1#1#1}% +% \end{macrocode} +% \subsection{\csh{xintgobble}} +% \changed{1.2i}{} +% +% I hesitated about allowing as many as |9^6-1=531440| tokens to gobble, but +% |9^5-1=59058| is too low for playing with long decimal expansions. +% \centeredline{Usage: |\romannumeral\xintgobble{N}...|} +% +% \begin{macrocode} +\def\xintgobble #1% + {\csname xint_c_\expandafter\XINT_gobble_a\the\numexpr#1.0}% +\def\XINT_gobble #1.{\csname xint_c_\XINT_gobble_a #1.0}% +\def\XINT_gobble_a #1{\xint_gob_til_zero#1\XINT_gobble_d0\XINT_gobble_b#1}% +\def\XINT_gobble_b #1.#2% + {\expandafter\XINT_gobble_c + \the\numexpr (#1+\xint_c_v)/\xint_c_ix-\xint_c_i\expandafter.% + \the\numexpr #2+\xint_c_i.#1.}% +\def\XINT_gobble_c #1.#2.#3.% + {\csname XINT_g#2\the\numexpr#3-\xint_c_ix*#1\relax\XINT_gobble_a #1.#2}% +\def\XINT_gobble_d0\XINT_gobble_b0.#1{\endcsname}% +\expandafter\let\csname XINT_g10\endcsname\endcsname +\long\expandafter\def\csname XINT_g11\endcsname#1{\endcsname}% +\long\expandafter\def\csname XINT_g12\endcsname#1#2{\endcsname}% +\long\expandafter\def\csname XINT_g13\endcsname#1#2#3{\endcsname}% +\long\expandafter\def\csname XINT_g14\endcsname#1#2#3#4{\endcsname}% +\long\expandafter\def\csname XINT_g15\endcsname#1#2#3#4#5{\endcsname}% +\long\expandafter\def\csname XINT_g16\endcsname#1#2#3#4#5#6{\endcsname}% +\long\expandafter\def\csname XINT_g17\endcsname#1#2#3#4#5#6#7{\endcsname}% +\long\expandafter\def\csname XINT_g18\endcsname#1#2#3#4#5#6#7#8{\endcsname}% +\expandafter\let\csname XINT_g20\endcsname\endcsname +\long\expandafter\def\csname XINT_g21\endcsname #1#2#3#4#5#6#7#8#9% + {\endcsname}% +\long\expandafter\edef\csname XINT_g22\endcsname #1#2#3#4#5#6#7#8#9% + {\expandafter\noexpand\csname XINT_g21\endcsname}% +\long\expandafter\edef\csname XINT_g23\endcsname #1#2#3#4#5#6#7#8#9% + {\expandafter\noexpand\csname XINT_g22\endcsname}% +\long\expandafter\edef\csname XINT_g24\endcsname #1#2#3#4#5#6#7#8#9% + {\expandafter\noexpand\csname XINT_g23\endcsname}% +\long\expandafter\edef\csname XINT_g25\endcsname #1#2#3#4#5#6#7#8#9% + {\expandafter\noexpand\csname XINT_g24\endcsname}% +\long\expandafter\edef\csname XINT_g26\endcsname #1#2#3#4#5#6#7#8#9% + {\expandafter\noexpand\csname XINT_g25\endcsname}% +\long\expandafter\edef\csname XINT_g27\endcsname #1#2#3#4#5#6#7#8#9% + {\expandafter\noexpand\csname XINT_g26\endcsname}% +\long\expandafter\edef\csname XINT_g28\endcsname #1#2#3#4#5#6#7#8#9% + {\expandafter\noexpand\csname XINT_g27\endcsname}% +\expandafter\let\csname XINT_g30\endcsname\endcsname +\long\expandafter\edef\csname XINT_g31\endcsname #1#2#3#4#5#6#7#8#9% + {\expandafter\noexpand\csname XINT_g28\endcsname}% +\long\expandafter\edef\csname XINT_g32\endcsname #1#2#3#4#5#6#7#8#9% + {\noexpand\csname XINT_g31\expandafter\noexpand\csname XINT_g28\endcsname}% +\long\expandafter\edef\csname XINT_g33\endcsname #1#2#3#4#5#6#7#8#9% + {\noexpand\csname XINT_g32\expandafter\noexpand\csname XINT_g28\endcsname}% +\long\expandafter\edef\csname XINT_g34\endcsname #1#2#3#4#5#6#7#8#9% + {\noexpand\csname XINT_g33\expandafter\noexpand\csname XINT_g28\endcsname}% +\long\expandafter\edef\csname XINT_g35\endcsname #1#2#3#4#5#6#7#8#9% + {\noexpand\csname XINT_g34\expandafter\noexpand\csname XINT_g28\endcsname}% +\long\expandafter\edef\csname XINT_g36\endcsname #1#2#3#4#5#6#7#8#9% + {\noexpand\csname XINT_g35\expandafter\noexpand\csname XINT_g28\endcsname}% +\long\expandafter\edef\csname XINT_g37\endcsname #1#2#3#4#5#6#7#8#9% + {\noexpand\csname XINT_g36\expandafter\noexpand\csname XINT_g28\endcsname}% +\long\expandafter\edef\csname XINT_g38\endcsname #1#2#3#4#5#6#7#8#9% + {\noexpand\csname XINT_g37\expandafter\noexpand\csname XINT_g28\endcsname}% +\expandafter\let\csname XINT_g40\endcsname\endcsname +\expandafter\edef\csname XINT_g41\endcsname + {\noexpand\csname XINT_g38\expandafter\noexpand\csname XINT_g31\endcsname}% +\expandafter\edef\csname XINT_g42\endcsname + {\noexpand\csname XINT_g41\expandafter\noexpand\csname XINT_g41\endcsname}% +\expandafter\edef\csname XINT_g43\endcsname + {\noexpand\csname XINT_g42\expandafter\noexpand\csname XINT_g41\endcsname}% +\expandafter\edef\csname XINT_g44\endcsname + {\noexpand\csname XINT_g43\expandafter\noexpand\csname XINT_g41\endcsname}% +\expandafter\edef\csname XINT_g45\endcsname + {\noexpand\csname XINT_g44\expandafter\noexpand\csname XINT_g41\endcsname}% +\expandafter\edef\csname XINT_g46\endcsname + {\noexpand\csname XINT_g45\expandafter\noexpand\csname XINT_g41\endcsname}% +\expandafter\edef\csname XINT_g47\endcsname + {\noexpand\csname XINT_g46\expandafter\noexpand\csname XINT_g41\endcsname}% +\expandafter\edef\csname XINT_g48\endcsname + {\noexpand\csname XINT_g47\expandafter\noexpand\csname XINT_g41\endcsname}% +\expandafter\let\csname XINT_g50\endcsname\endcsname +\expandafter\edef\csname XINT_g51\endcsname + {\noexpand\csname XINT_g48\expandafter\noexpand\csname XINT_g41\endcsname}% +\expandafter\edef\csname XINT_g52\endcsname + {\noexpand\csname XINT_g51\expandafter\noexpand\csname XINT_g51\endcsname}% +\expandafter\edef\csname XINT_g53\endcsname + {\noexpand\csname XINT_g52\expandafter\noexpand\csname XINT_g51\endcsname}% +\expandafter\edef\csname XINT_g54\endcsname + {\noexpand\csname XINT_g53\expandafter\noexpand\csname XINT_g51\endcsname}% +\expandafter\edef\csname XINT_g55\endcsname + {\noexpand\csname XINT_g54\expandafter\noexpand\csname XINT_g51\endcsname}% +\expandafter\edef\csname XINT_g56\endcsname + {\noexpand\csname XINT_g55\expandafter\noexpand\csname XINT_g51\endcsname}% +\expandafter\edef\csname XINT_g57\endcsname + {\noexpand\csname XINT_g56\expandafter\noexpand\csname XINT_g51\endcsname}% +\expandafter\edef\csname XINT_g58\endcsname + {\noexpand\csname XINT_g57\expandafter\noexpand\csname XINT_g51\endcsname}% +\expandafter\let\csname XINT_g60\endcsname\endcsname +\expandafter\edef\csname XINT_g61\endcsname + {\noexpand\csname XINT_g58\expandafter\noexpand\csname XINT_g51\endcsname}% +\expandafter\edef\csname XINT_g62\endcsname + {\noexpand\csname XINT_g61\expandafter\noexpand\csname XINT_g61\endcsname}% +\expandafter\edef\csname XINT_g63\endcsname + {\noexpand\csname XINT_g62\expandafter\noexpand\csname XINT_g61\endcsname}% +\expandafter\edef\csname XINT_g64\endcsname + {\noexpand\csname XINT_g63\expandafter\noexpand\csname XINT_g61\endcsname}% +\expandafter\edef\csname XINT_g65\endcsname + {\noexpand\csname XINT_g64\expandafter\noexpand\csname XINT_g61\endcsname}% +\expandafter\edef\csname XINT_g66\endcsname + {\noexpand\csname XINT_g65\expandafter\noexpand\csname XINT_g61\endcsname}% +\expandafter\edef\csname XINT_g67\endcsname + {\noexpand\csname XINT_g66\expandafter\noexpand\csname XINT_g61\endcsname}% +\expandafter\edef\csname XINT_g68\endcsname + {\noexpand\csname XINT_g67\expandafter\noexpand\csname XINT_g61\endcsname}% +% \end{macrocode} +% \subsection{(WIP) \csh{xintUniformDeviate}} +% \changed{1.3b}{} See user manual for related information. +% \begin{macrocode} +\ifdefined\xint_texuniformdeviate + \expandafter\xint_firstoftwo +\else\expandafter\xint_secondoftwo +\fi +{% + \def\xintUniformDeviate#1% + {\the\numexpr\expandafter\XINT_uniformdeviate_sgnfork\the\numexpr#1\xint:}% + \def\XINT_uniformdeviate_sgnfork#1% + {% + \if-#1\XINT_uniformdeviate_neg\fi \XINT_uniformdeviate{}#1% + }% + \def\XINT_uniformdeviate_neg\fi\XINT_uniformdeviate#1-% + {% + \fi-\numexpr\XINT_uniformdeviate\relax + }% + \def\XINT_uniformdeviate#1#2\xint: + {%( + \expandafter\XINT_uniformdeviate_a\the\numexpr% + -\xint_texuniformdeviate\xint_c_ii^vii% + -\xint_c_ii^vii*\xint_texuniformdeviate\xint_c_ii^vii% + -\xint_c_ii^xiv*\xint_texuniformdeviate\xint_c_ii^vii% + -\xint_c_ii^xxi*\xint_texuniformdeviate\xint_c_ii^vii% + +\xint_texuniformdeviate#2\xint:/#2)*#2\xint:+#2\fi\relax#1% + }% + \def\XINT_uniformdeviate_a #1\xint: + {% + \expandafter\XINT_uniformdeviate_b\the\numexpr#1-(#1% + }% + \def\XINT_uniformdeviate_b#1#2\xint:{#1#2\if-#1}% +}% +{% + \def\xintUniformDeviate#1% + {% + \the\numexpr + \XINT_expandableerror{No uniformdeviate at engine level, returning 0.}% + 0\relax + }% +}% +% \end{macrocode} +% \subsection{\csh{xintMessage}, \csh{ifxintverbose}} +% \changed{1.2c}{} for use by \csbxint{defvar} and \csbxint{deffunc} of +% \xintexprnameimp. +% +% \changed{1.2e}{} uses |\write128| rather than |\write16| for compatibility +% with future extended range of output streams, in LuaTeX in particular. +% +% \changed{1.3e}{} set the |\newlinechar|. +% \begin{macrocode} +\def\xintMessage #1#2#3{% + \edef\XINT_newlinechar{\the\newlinechar}% + \newlinechar10 + \immediate\write128{Package #1 #2: (on line \the\inputlineno)}% + \immediate\write128{\space\space\space\space#3}% + \newlinechar\XINT_newlinechar\space +}% +\newif\ifxintverbose +% \end{macrocode} +% \subsection{\csh{ifxintglobaldefs}, \csh{XINT_global}}\label{src-xintglobaldefstrue} +% \changed{1.3c}{} +% \begin{macrocode} +\newif\ifxintglobaldefs +\def\XINT_global{\ifxintglobaldefs\global\fi}% +% \end{macrocode} +% \subsection{(WIP) Expandable error message} +% \changed{1.2l}{} but really belongs to next major release beyond |1.3|. +% +% This is copied over from l3kernel code. I am using |\ ! /| control sequence +% though, which must be left undefined. |\xintError:| would be 6 letters more +% already. +% \begin{macrocode} +\def\XINT_expandableerror #1#2{% + \def\XINT_expandableerror ##1{% + \expandafter\expandafter\expandafter + \XINT_expandableerror_continue\xint_firstofone{#2#1##1#1}}% + \def\XINT_expandableerror_continue ##1#1##2#1{##1}% +}% +\begingroup\lccode`$ 32 \catcode`/ 11 \catcode`! 11 \catcode32 11 % $ +% \end{macrocode} +% \begin{macrocode} +\lowercase{\endgroup\XINT_expandableerror$\ ! /\let\ ! /\xint_undefined}% $ +\XINT_restorecatcodes_endinput% +% \end{macrocode} +% \StoreCodelineNo {xintkernel} +% \cleardoublepage\let\xintkernelnameUp\undefined +%\gardesactifs +%\let</xintkernel>\relax +%\let<*xinttools>\gardesinactifs +%</xintkernel>^^A------------------------------------------------- +%<*xinttools>^^A-------------------------------------------------- +%^^A -*- coding: utf-8; mode: doctex; -*- +% \clearpage\csname xinttoolsnameUp\endcsname +% \section{Package \xinttoolsnameimp implementation} +% \RaisedLabel{sec:toolsimp} +% +% \localtableofcontents +% +% Release |1.09g| of |2013/11/22| splits off |xinttools.sty| from |xint.sty|. +% Starting with |1.1|, \xinttoolsnameimp ceases being loaded automatically by +% \xintnameimp. +% +% \subsection{Catcodes, \protect\eTeX{} and reload detection} +% +% The code for reload detection was initially copied from \textsc{Heiko +% Oberdiek}'s packages, then modified. +% +% The method for catcodes was also initially directly inspired by these +% packages. +% +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode64=11 % @ + \catcode35=6 % # + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \let\z\endgroup + \expandafter\let\expandafter\x\csname ver@xinttools.sty\endcsname + \expandafter\let\expandafter\w\csname ver@xintkernel.sty\endcsname + \expandafter + \ifx\csname PackageInfo\endcsname\relax + \def\y#1#2{\immediate\write-1{Package #1 Info: #2.}}% + \else + \def\y#1#2{\PackageInfo{#1}{#2}}% + \fi + \expandafter + \ifx\csname numexpr\endcsname\relax + \y{xinttools}{\numexpr not available, aborting input}% + \aftergroup\endinput + \else + \ifx\x\relax % plain-TeX, first loading of xinttools.sty + \ifx\w\relax % but xintkernel.sty not yet loaded. + \def\z{\endgroup\input xintkernel.sty\relax}% + \fi + \else + \def\empty {}% + \ifx\x\empty % LaTeX, first loading, + % variable is initialized, but \ProvidesPackage not yet seen + \ifx\w\relax % xintkernel.sty not yet loaded. + \def\z{\endgroup\RequirePackage{xintkernel}}% + \fi + \else + \aftergroup\endinput % xinttools already loaded. + \fi + \fi + \fi +\z% +\XINTsetupcatcodes% defined in xintkernel.sty +% \end{macrocode} +% \subsection{Package identification} +% \begin{macrocode} +\XINT_providespackage +\ProvidesPackage{xinttools}% + [2019/04/05 1.3e Expandable and non-expandable utilities (JFB)]% +% \end{macrocode} +% \lverb|\XINT_toks is used in macros such as \xintFor. It is not used +% elsewhere in the xint bundle.| +% \begin{macrocode} +\newtoks\XINT_toks +\xint_firstofone{\let\XINT_sptoken= } %<- space here! +% \end{macrocode} +% \subsection{\csh{xintgodef}, \csh{xintgoodef}, \csh{xintgfdef}} +% \lverb|1.09i. For use in \xintAssign.| +% \begin{macrocode} +\def\xintgodef {\global\xintodef }% +\def\xintgoodef {\global\xintoodef }% +\def\xintgfdef {\global\xintfdef }% +% \end{macrocode} +% \subsection{\csh{xintRevWithBraces}} +% \lverb|New with 1.06. Makes the expansion of its argument and then reverses +% the resulting tokens or braced tokens, adding a pair of braces to each (thus, +% maintaining it when it was already there.) The reason for +% \xint:, here and in other locations, is in case #1 expands to nothing, +% the \romannumeral-`0 must be stopped| +% \begin{macrocode} +\def\xintRevWithBraces {\romannumeral0\xintrevwithbraces }% +\def\xintRevWithBracesNoExpand {\romannumeral0\xintrevwithbracesnoexpand }% +\long\def\xintrevwithbraces #1% +{% + \expandafter\XINT_revwbr_loop\expandafter{\expandafter}% + \romannumeral`&&@#1\xint:\xint:\xint:\xint:% + \xint:\xint:\xint:\xint:\xint_bye +}% +\long\def\xintrevwithbracesnoexpand #1% +{% + \XINT_revwbr_loop {}% + #1\xint:\xint:\xint:\xint:% + \xint:\xint:\xint:\xint:\xint_bye +}% +\long\def\XINT_revwbr_loop #1#2#3#4#5#6#7#8#9% +{% + \xint_gob_til_xint: #9\XINT_revwbr_finish_a\xint:% + \XINT_revwbr_loop {{#9}{#8}{#7}{#6}{#5}{#4}{#3}{#2}#1}% +}% +\long\def\XINT_revwbr_finish_a\xint:\XINT_revwbr_loop #1#2\xint_bye +{% + \XINT_revwbr_finish_b #2\R\R\R\R\R\R\R\Z #1% +}% +\def\XINT_revwbr_finish_b #1#2#3#4#5#6#7#8\Z +{% + \xint_gob_til_R + #1\XINT_revwbr_finish_c \xint_gobble_viii + #2\XINT_revwbr_finish_c \xint_gobble_vii + #3\XINT_revwbr_finish_c \xint_gobble_vi + #4\XINT_revwbr_finish_c \xint_gobble_v + #5\XINT_revwbr_finish_c \xint_gobble_iv + #6\XINT_revwbr_finish_c \xint_gobble_iii + #7\XINT_revwbr_finish_c \xint_gobble_ii + \R\XINT_revwbr_finish_c \xint_gobble_i\Z +}% +% \end{macrocode} +% \lverb|1.1c revisited this old code and improved upon the earlier endings.| +% \begin{macrocode} +\def\XINT_revwbr_finish_c#1{% +\def\XINT_revwbr_finish_c##1##2\Z{\expandafter#1##1}% +}\XINT_revwbr_finish_c{ }% +% \end{macrocode} +% \subsection{\csh{xintZapFirstSpaces}} +% \lverb|1.09f, written [2013/11/01]. Modified (2014/10/21) for release 1.1 to +% correct the bug in case of an empty argument, or argument containing only +% spaces, which had been forgotten in first version. New version is simpler than +% the initial one. This macro does NOT expand its argument.| +% \begin{macrocode} +\def\xintZapFirstSpaces {\romannumeral0\xintzapfirstspaces }% +\def\xintzapfirstspaces#1{\long +\def\xintzapfirstspaces ##1{\XINT_zapbsp_a #1##1\xint:#1#1\xint:}% +}\xintzapfirstspaces{ }% +% \end{macrocode} +% \lverb|If the original #1 started with a space, the grabbed #1 is empty. Thus +% _again? will see #1=\xint_bye, and hand over control to _again which will loop +% back into \XINT_zapbsp_a, with one initial space less. If the original #1 did +% not start with a space, or was empty, then the #1 below will be a <sptoken>, +% then an extract of the original #1, not empty and not starting with a space, +% which contains what was up to the first <sp><sp> present in original #1, or, +% if none preexisted, <sptoken> and all of #1 (possibly empty) plus an ending +% \xint:. The added initial space will stop later the \romannumeral0. No +% brace stripping is possible. Control is handed over to \XINT_zapbsp_b which +% strips out the ending \xint:<sp><sp>\xint:| +% \begin{macrocode} +\def\XINT_zapbsp_a#1{\long\def\XINT_zapbsp_a ##1#1#1{% + \XINT_zapbsp_again?##1\xint_bye\XINT_zapbsp_b ##1#1#1}% +}\XINT_zapbsp_a{ }% +\long\def\XINT_zapbsp_again? #1{\xint_bye #1\XINT_zapbsp_again }% +\xint_firstofone{\def\XINT_zapbsp_again\XINT_zapbsp_b} {\XINT_zapbsp_a }% +\long\def\XINT_zapbsp_b #1\xint:#2\xint:{#1}% +% \end{macrocode} +% \subsection{\csh{xintZapLastSpaces}} +% \lverb+1.09f, written [2013/11/01]. + +% \begin{macrocode} +\def\xintZapLastSpaces {\romannumeral0\xintzaplastspaces }% +\def\xintzaplastspaces#1{\long +\def\xintzaplastspaces ##1{\XINT_zapesp_a {}\empty##1#1#1\xint_bye\xint:}% +}\xintzaplastspaces{ }% +% \end{macrocode} +% \lverb|The \empty from \xintzaplastspaces is to prevent brace removal in the +% #2 below. The \expandafter chain removes it.| +% \begin{macrocode} +\xint_firstofone {\long\def\XINT_zapesp_a #1#2 } %<- second space here + {\expandafter\XINT_zapesp_b\expandafter{#2}{#1}}% +% \end{macrocode} +% \lverb|Notice again an \empty added here. This is in preparation for possibly looping +% back to \XINT_zapesp_a. If the initial #1 had no <sp><sp>, the stuff however +% will not loop, because #3 will already be <some spaces>\xint_bye. Notice +% that this macro fetches all way to the ending \xint:. This looks not +% very efficient, but how often do we have to strip ending spaces from +% something which also has inner stretches of _multiple_ space tokens ?;-). | +% \begin{macrocode} +\long\def\XINT_zapesp_b #1#2#3\xint:% + {\XINT_zapesp_end? #3\XINT_zapesp_e {#2#1}\empty #3\xint:}% +% \end{macrocode} +% \lverb|When we have been over all possible <sp><sp> things, we reach the +% ending space tokens, and #3 will be a bunch of spaces (possibly none) +% followed by \xint_bye. So the #1 in _end? will be \xint_bye. In all other cases +% #1 can not be \xint_bye (assuming naturally this token does nor arise in +% original input), hence control falls back to \XINT_zapesp_e which will loop back +% to \XINT_zapesp_a.| +% \begin{macrocode} +\long\def\XINT_zapesp_end? #1{\xint_bye #1\XINT_zapesp_end }% +% \end{macrocode} +% \lverb|We are done. The #1 here has accumulated all the previous material, +% and is stripped of its ending spaces, if any.| +% \begin{macrocode} +\long\def\XINT_zapesp_end\XINT_zapesp_e #1#2\xint:{ #1}% +% \end{macrocode} +% \lverb|We haven't yet reached the end, so we need to re-inject two space +% tokens after what we have gotten so far. Then we loop.| +% \begin{macrocode} +\def\XINT_zapesp_e#1{% +\long\def\XINT_zapesp_e ##1{\XINT_zapesp_a {##1#1#1}}% +}\XINT_zapesp_e{ }% +% \end{macrocode} +% \subsection{\csh{xintZapSpaces}} +% \lverb+1.09f, written [2013/11/01]. Modified for 1.1, 2014/10/21 as it has the +% same bug as \xintZapFirstSpaces. We in effect do first \xintZapFirstSpaces, +% then \xintZapLastSpaces.+ +% \begin{macrocode} +\def\xintZapSpaces {\romannumeral0\xintzapspaces }% +\def\xintzapspaces#1{% +\long\def\xintzapspaces ##1% like \xintZapFirstSpaces. + {\XINT_zapsp_a #1##1\xint:#1#1\xint:}% +}\xintzapspaces{ }% +\def\XINT_zapsp_a#1{% +\long\def\XINT_zapsp_a ##1#1#1% + {\XINT_zapsp_again?##1\xint_bye\XINT_zapsp_b##1#1#1}% +}\XINT_zapsp_a{ }% +\long\def\XINT_zapsp_again? #1{\xint_bye #1\XINT_zapsp_again }% +\xint_firstofone{\def\XINT_zapsp_again\XINT_zapsp_b} {\XINT_zapsp_a }% +\xint_firstofone{\def\XINT_zapsp_b} {\XINT_zapsp_c }% +\def\XINT_zapsp_c#1{% +\long\def\XINT_zapsp_c ##1\xint:##2\xint:% + {\XINT_zapesp_a{}\empty ##1#1#1\xint_bye\xint:}% +}\XINT_zapsp_c{ }% +% \end{macrocode} +% \subsection{\csh{xintZapSpacesB}} +% \lverb+1.09f, written [2013/11/01]. Strips up to one pair of braces (but then +% does not strip spaces inside).+ +% \begin{macrocode} +\def\xintZapSpacesB {\romannumeral0\xintzapspacesb }% +\long\def\xintzapspacesb #1{\XINT_zapspb_one? #1\xint:\xint:% + \xint_bye\xintzapspaces {#1}}% +\long\def\XINT_zapspb_one? #1#2% + {\xint_gob_til_xint: #1\XINT_zapspb_onlyspaces\xint:% + \xint_gob_til_xint: #2\XINT_zapspb_bracedorone\xint:% + \xint_bye {#1}}% +\def\XINT_zapspb_onlyspaces\xint:% + \xint_gob_til_xint:\xint:\XINT_zapspb_bracedorone\xint:% + \xint_bye #1\xint_bye\xintzapspaces #2{ }% +\long\def\XINT_zapspb_bracedorone\xint:% + \xint_bye #1\xint:\xint_bye\xintzapspaces #2{ #1}% +% \end{macrocode} +% \subsection{\csh{xintCSVtoList}, \csh{xintCSVtoListNonStripped}} +% \lverb|\xintCSVtoList transforms a,b,..,z into {a}{b}...{z}. The comma +% separated list may be a macro which is first f-expanded. First included in +% release 1.06. Here, use of \Z (and \R) perfectly safe. +% +% [2013/11/02]: Starting with 1.09f, automatically filters items with +% \xintZapSpacesB to strip away all spaces around commas, and spaces at the start +% and end of the list. The original is kept as \xintCSVtoListNonStripped, and is +% faster. But ... it doesn't strip spaces. +% +% ATTENTION: if the input is empty the output contains one item (empty, of +% course). This means an \xintFor loop always executes at least once the +% iteration, contrarily to \xintFor*.| +% \begin{macrocode} +\def\xintCSVtoList {\romannumeral0\xintcsvtolist }% +\long\def\xintcsvtolist #1{\expandafter\xintApply + \expandafter\xintzapspacesb + \expandafter{\romannumeral0\xintcsvtolistnonstripped{#1}}}% +\def\xintCSVtoListNoExpand {\romannumeral0\xintcsvtolistnoexpand }% +\long\def\xintcsvtolistnoexpand #1{\expandafter\xintApply + \expandafter\xintzapspacesb + \expandafter{\romannumeral0\xintcsvtolistnonstrippednoexpand{#1}}}% +\def\xintCSVtoListNonStripped {\romannumeral0\xintcsvtolistnonstripped }% +\def\xintCSVtoListNonStrippedNoExpand + {\romannumeral0\xintcsvtolistnonstrippednoexpand }% +\long\def\xintcsvtolistnonstripped #1% +{% + \expandafter\XINT_csvtol_loop_a\expandafter + {\expandafter}\romannumeral`&&@#1% + ,\xint_bye,\xint_bye,\xint_bye,\xint_bye + ,\xint_bye,\xint_bye,\xint_bye,\xint_bye,\Z +}% +\long\def\xintcsvtolistnonstrippednoexpand #1% +{% + \XINT_csvtol_loop_a + {}#1,\xint_bye,\xint_bye,\xint_bye,\xint_bye + ,\xint_bye,\xint_bye,\xint_bye,\xint_bye,\Z +}% +\long\def\XINT_csvtol_loop_a #1#2,#3,#4,#5,#6,#7,#8,#9,% +{% + \xint_bye #9\XINT_csvtol_finish_a\xint_bye + \XINT_csvtol_loop_b {#1}{{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}% +}% +\long\def\XINT_csvtol_loop_b #1#2{\XINT_csvtol_loop_a {#1#2}}% +\long\def\XINT_csvtol_finish_a\xint_bye\XINT_csvtol_loop_b #1#2#3\Z +{% + \XINT_csvtol_finish_b #3\R,\R,\R,\R,\R,\R,\R,\Z #2{#1}% +}% +% \end{macrocode} +% \lverb|1.1c revisits this old code and improves upon the earlier endings. +% But as the _d.. macros have already nine parameters, I needed the +% \expandafter and \xint_gob_til_Z in finish_b (compare \XINT_keep_endb, or +% also \XINT_RQ_end_b).| +% \begin{macrocode} +\def\XINT_csvtol_finish_b #1,#2,#3,#4,#5,#6,#7,#8\Z +{% + \xint_gob_til_R + #1\expandafter\XINT_csvtol_finish_dviii\xint_gob_til_Z + #2\expandafter\XINT_csvtol_finish_dvii \xint_gob_til_Z + #3\expandafter\XINT_csvtol_finish_dvi \xint_gob_til_Z + #4\expandafter\XINT_csvtol_finish_dv \xint_gob_til_Z + #5\expandafter\XINT_csvtol_finish_div \xint_gob_til_Z + #6\expandafter\XINT_csvtol_finish_diii \xint_gob_til_Z + #7\expandafter\XINT_csvtol_finish_dii \xint_gob_til_Z + \R\XINT_csvtol_finish_di \Z +}% +\long\def\XINT_csvtol_finish_dviii #1#2#3#4#5#6#7#8#9{ #9}% +\long\def\XINT_csvtol_finish_dvii #1#2#3#4#5#6#7#8#9{ #9{#1}}% +\long\def\XINT_csvtol_finish_dvi #1#2#3#4#5#6#7#8#9{ #9{#1}{#2}}% +\long\def\XINT_csvtol_finish_dv #1#2#3#4#5#6#7#8#9{ #9{#1}{#2}{#3}}% +\long\def\XINT_csvtol_finish_div #1#2#3#4#5#6#7#8#9{ #9{#1}{#2}{#3}{#4}}% +\long\def\XINT_csvtol_finish_diii #1#2#3#4#5#6#7#8#9{ #9{#1}{#2}{#3}{#4}{#5}}% +\long\def\XINT_csvtol_finish_dii #1#2#3#4#5#6#7#8#9% + { #9{#1}{#2}{#3}{#4}{#5}{#6}}% +\long\def\XINT_csvtol_finish_di\Z #1#2#3#4#5#6#7#8#9% + { #9{#1}{#2}{#3}{#4}{#5}{#6}{#7}}% +% \end{macrocode} +% \subsection{\csh{xintListWithSep}} +% \lverb|1.04. +% \xintListWithSep {\sep}{{a}{b}...{z}} returns a \sep b \sep ....\sep z. It +% f-expands its second argument. The 'sep' may be \par's: the macro +% \xintlistwithsep etc... are all declared long. 'sep' does not have to be a +% single token. It is not expanded. The "list" argument may be empty. +% +% \xintListWithSepNoExpand does not f-expand its second argument. +% +% This venerable macro from 1.04 remained unchanged for a long time and was +% finally refactored at 1.2p for increased speed. Tests done with a list of +% identical {\x} items and a sep of \z demonstrated a speed increase of about: +%( - 3x for 30 items, +%: - 4.5x for 100 items, +%: - 7.5x--8x for 1000 items. +%) | +% \begin{macrocode} +\def\xintListWithSep {\romannumeral0\xintlistwithsep }% +\def\xintListWithSepNoExpand {\romannumeral0\xintlistwithsepnoexpand }% +\long\def\xintlistwithsep #1#2% + {\expandafter\XINT_lws\expandafter {\romannumeral`&&@#2}{#1}}% +\long\def\xintlistwithsepnoexpand #1#2% +{% + \XINT_lws_loop_a {#1}#2{\xint_bye\XINT_lws_e_vi}% + {\xint_bye\XINT_lws_e_v}{\xint_bye\XINT_lws_e_iv}% + {\xint_bye\XINT_lws_e_iii}{\xint_bye\XINT_lws_e_ii}% + {\xint_bye\XINT_lws_e_i}{\xint_bye\XINT_lws_e}% + {\xint_bye\expandafter\space}\xint_bye +}% +\long\def\XINT_lws #1#2% +{% + \XINT_lws_loop_a {#2}#1{\xint_bye\XINT_lws_e_vi}% + {\xint_bye\XINT_lws_e_v}{\xint_bye\XINT_lws_e_iv}% + {\xint_bye\XINT_lws_e_iii}{\xint_bye\XINT_lws_e_ii}% + {\xint_bye\XINT_lws_e_i}{\xint_bye\XINT_lws_e}% + {\xint_bye\expandafter\space}\xint_bye +}% +\long\def\XINT_lws_loop_a #1#2#3#4#5#6#7#8#9% +{% + \xint_bye #9\xint_bye + \XINT_lws_loop_b {#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}% +}% +\long\def\XINT_lws_loop_b #1#2#3#4#5#6#7#8#9% +{% + \XINT_lws_loop_a {#1}{#2#1#3#1#4#1#5#1#6#1#7#1#8#1#9}% +}% +\long\def\XINT_lws_e_vi\xint_bye\XINT_lws_loop_b #1#2#3#4#5#6#7#8#9\xint_bye + { #2#1#3#1#4#1#5#1#6#1#7#1#8}% +\long\def\XINT_lws_e_v\xint_bye\XINT_lws_loop_b #1#2#3#4#5#6#7#8\xint_bye + { #2#1#3#1#4#1#5#1#6#1#7}% +\long\def\XINT_lws_e_iv\xint_bye\XINT_lws_loop_b #1#2#3#4#5#6#7\xint_bye + { #2#1#3#1#4#1#5#1#6}% +\long\def\XINT_lws_e_iii\xint_bye\XINT_lws_loop_b #1#2#3#4#5#6\xint_bye + { #2#1#3#1#4#1#5}% +\long\def\XINT_lws_e_ii\xint_bye\XINT_lws_loop_b #1#2#3#4#5\xint_bye + { #2#1#3#1#4}% +\long\def\XINT_lws_e_i\xint_bye\XINT_lws_loop_b #1#2#3#4\xint_bye + { #2#1#3}% +\long\def\XINT_lws_e\xint_bye\XINT_lws_loop_b #1#2#3\xint_bye + { #2}% +% \end{macrocode} +% \subsection{\csh{xintNthElt}} +% \lverb?First included in release 1.06. Last refactored in 1.2j. +% +% \xintNthElt {i}{List} returns the i th item from List (one pair of braces +% removed). The list is first f-expanded. The \xintNthEltNoExpand does no +% expansion of its second argument. Both variants expand i inside \numexpr. +% +% With i = 0, the number of items is returned using \xintLength but with the +% List argument f-expanded first. +% +% Negative values return the |i|th element from the end. +% +% When i is out of range, an empty value is returned. +% ? +% \begin{macrocode} +\def\xintNthElt {\romannumeral0\xintnthelt }% +\def\xintNthEltNoExpand {\romannumeral0\xintntheltnoexpand }% +\long\def\xintnthelt #1#2{\expandafter\XINT_nthelt_a\the\numexpr #1\expandafter.% + \expandafter{\romannumeral`&&@#2}}% +\def\xintntheltnoexpand #1{\expandafter\XINT_nthelt_a\the\numexpr #1.}% +\def\XINT_nthelt_a #1% +{% + \xint_UDzerominusfork + #1-\XINT_nthelt_zero + 0#1\XINT_nthelt_neg + 0-{\XINT_nthelt_pos #1}% + \krof +}% +\def\XINT_nthelt_zero #1.{\xintlength }% +\long\def\XINT_nthelt_neg #1.#2% +{% + \expandafter\XINT_nthelt_neg_a\the\numexpr\xint_c_i+\XINT_length_loop + #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v + \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye + -#1.#2\xint_bye +}% +\def\XINT_nthelt_neg_a #1% +{% + \xint_UDzerominusfork + #1-\xint_stop_afterbye + 0#1\xint_stop_afterbye + 0-{}% + \krof + \expandafter\XINT_nthelt_neg_b + \romannumeral\expandafter\XINT_gobble\the\numexpr-\xint_c_i+#1% +}% +\long\def\XINT_nthelt_neg_b #1#2\xint_bye{ #1}% +\long\def\XINT_nthelt_pos #1.#2% +{% + \expandafter\XINT_nthelt_pos_done + \romannumeral0\expandafter\XINT_trim_loop\the\numexpr#1-\xint_c_x.% + #2\xint:\xint:\xint:\xint:\xint:% + \xint:\xint:\xint:\xint:\xint:% + \xint_bye +}% +\def\XINT_nthelt_pos_done #1{% +\long\def\XINT_nthelt_pos_done ##1##2\xint_bye{% + \xint_gob_til_xint:##1\expandafter#1\xint_gobble_ii\xint:#1##1}% +}\XINT_nthelt_pos_done{ }% +% \end{macrocode} +% \subsection{\csh{xintKeep}} +% \lverb@& +% +% First included in release 1.09m. +% +% \xintKeep{i}{L} f-expands its second argument L. It then grabs the first i +% items from L and discards the rest. +% +% ATTENTION: **each such kept item is returned inside a brace pair** +% Use \xintKeepUnbraced to avoid that. +% +% For i equal or larger to the number N of items in (expanded) L, the full L +% is returned (with braced items). For i=0, the macro returns an empty output. +% For i<0, the macro discards the first N-|i| items. No brace pairs added to +% the remaining items. For i is less or equal to -N, the full L is returned +% (with no braces added.) +% +% \xintKeepNoExpand does not expand the L argument. +% +% +% +% Prior to 1.2i the code proceeded along a loop with no pre-computation of +% the length of L, for the i>0 case. The faster 1.2i version takes advantage +% of novel \xintLengthUpTo from xintkernel.sty. +% @ +% \begin{macrocode} +\def\xintKeep {\romannumeral0\xintkeep }% +\def\xintKeepNoExpand {\romannumeral0\xintkeepnoexpand }% +\long\def\xintkeep #1#2{\expandafter\XINT_keep_a\the\numexpr #1\expandafter.% + \expandafter{\romannumeral`&&@#2}}% +\def\xintkeepnoexpand #1{\expandafter\XINT_keep_a\the\numexpr #1.}% +\def\XINT_keep_a #1% +{% + \xint_UDzerominusfork + #1-\XINT_keep_keepnone + 0#1\XINT_keep_neg + 0-{\XINT_keep_pos #1}% + \krof +}% +\long\def\XINT_keep_keepnone .#1{ }% +\long\def\XINT_keep_neg #1.#2% +{% + \expandafter\XINT_keep_neg_a\the\numexpr + #1-\numexpr\XINT_length_loop + #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v + \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye.#2% +}% +\def\XINT_keep_neg_a #1% +{% + \xint_UDsignfork + #1{\expandafter\space\romannumeral\XINT_gobble}% + -\XINT_keep_keepall + \krof +}% +\def\XINT_keep_keepall #1.{ }% +\long\def\XINT_keep_pos #1.#2% +{% + \expandafter\XINT_keep_loop + \the\numexpr#1-\XINT_lengthupto_loop + #1.#2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_vii\xint_c_vi\xint_c_v\xint_c_iv + \xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye.% + -\xint_c_viii.{}#2\xint_bye% +}% +\def\XINT_keep_loop #1#2.% +{% + \xint_gob_til_minus#1\XINT_keep_loop_end-% + \expandafter\XINT_keep_loop + \the\numexpr#1#2-\xint_c_viii\expandafter.\XINT_keep_loop_pickeight +}% +\long\def\XINT_keep_loop_pickeight + #1#2#3#4#5#6#7#8#9{{#1{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}}% +\def\XINT_keep_loop_end-\expandafter\XINT_keep_loop + \the\numexpr-#1-\xint_c_viii\expandafter.\XINT_keep_loop_pickeight + {\csname XINT_keep_end#1\endcsname}% +\long\expandafter\def\csname XINT_keep_end1\endcsname + #1#2#3#4#5#6#7#8#9\xint_bye { #1{#2}{#3}{#4}{#5}{#6}{#7}{#8}}% +\long\expandafter\def\csname XINT_keep_end2\endcsname + #1#2#3#4#5#6#7#8\xint_bye { #1{#2}{#3}{#4}{#5}{#6}{#7}}% +\long\expandafter\def\csname XINT_keep_end3\endcsname + #1#2#3#4#5#6#7\xint_bye { #1{#2}{#3}{#4}{#5}{#6}}% +\long\expandafter\def\csname XINT_keep_end4\endcsname + #1#2#3#4#5#6\xint_bye { #1{#2}{#3}{#4}{#5}}% +\long\expandafter\def\csname XINT_keep_end5\endcsname + #1#2#3#4#5\xint_bye { #1{#2}{#3}{#4}}% +\long\expandafter\def\csname XINT_keep_end6\endcsname + #1#2#3#4\xint_bye { #1{#2}{#3}}% +\long\expandafter\def\csname XINT_keep_end7\endcsname + #1#2#3\xint_bye { #1{#2}}% +\long\expandafter\def\csname XINT_keep_end8\endcsname + #1#2\xint_bye { #1}% +% \end{macrocode} +% \subsection{\csh{xintKeepUnbraced}} +% \lverb?1.2a. Same as \xintKeep but will *not* add (or maintain) brace pairs +% around the kept items when length(L)>i>0. +% +% The name may cause a mis-understanding: for i<0, (i.e. keeping only +% trailing items), there is no brace removal at all happening. +% +% Modified for 1.2i like \xintKeep. +% ? +% \begin{macrocode} +\def\xintKeepUnbraced {\romannumeral0\xintkeepunbraced }% +\def\xintKeepUnbracedNoExpand {\romannumeral0\xintkeepunbracednoexpand }% +\long\def\xintkeepunbraced #1#2% + {\expandafter\XINT_keepunbr_a\the\numexpr #1\expandafter.% + \expandafter{\romannumeral`&&@#2}}% +\def\xintkeepunbracednoexpand #1% + {\expandafter\XINT_keepunbr_a\the\numexpr #1.}% +\def\XINT_keepunbr_a #1% +{% + \xint_UDzerominusfork + #1-\XINT_keep_keepnone + 0#1\XINT_keep_neg + 0-{\XINT_keepunbr_pos #1}% + \krof +}% +\long\def\XINT_keepunbr_pos #1.#2% +{% + \expandafter\XINT_keepunbr_loop + \the\numexpr#1-\XINT_lengthupto_loop + #1.#2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_vii\xint_c_vi\xint_c_v\xint_c_iv + \xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye.% + -\xint_c_viii.{}#2\xint_bye% +}% +\def\XINT_keepunbr_loop #1#2.% +{% + \xint_gob_til_minus#1\XINT_keepunbr_loop_end-% + \expandafter\XINT_keepunbr_loop + \the\numexpr#1#2-\xint_c_viii\expandafter.\XINT_keepunbr_loop_pickeight +}% +\long\def\XINT_keepunbr_loop_pickeight + #1#2#3#4#5#6#7#8#9{{#1#2#3#4#5#6#7#8#9}}% +\def\XINT_keepunbr_loop_end-\expandafter\XINT_keepunbr_loop + \the\numexpr-#1-\xint_c_viii\expandafter.\XINT_keepunbr_loop_pickeight + {\csname XINT_keepunbr_end#1\endcsname}% +\long\expandafter\def\csname XINT_keepunbr_end1\endcsname + #1#2#3#4#5#6#7#8#9\xint_bye { #1#2#3#4#5#6#7#8}% +\long\expandafter\def\csname XINT_keepunbr_end2\endcsname + #1#2#3#4#5#6#7#8\xint_bye { #1#2#3#4#5#6#7}% +\long\expandafter\def\csname XINT_keepunbr_end3\endcsname + #1#2#3#4#5#6#7\xint_bye { #1#2#3#4#5#6}% +\long\expandafter\def\csname XINT_keepunbr_end4\endcsname + #1#2#3#4#5#6\xint_bye { #1#2#3#4#5}% +\long\expandafter\def\csname XINT_keepunbr_end5\endcsname + #1#2#3#4#5\xint_bye { #1#2#3#4}% +\long\expandafter\def\csname XINT_keepunbr_end6\endcsname + #1#2#3#4\xint_bye { #1#2#3}% +\long\expandafter\def\csname XINT_keepunbr_end7\endcsname + #1#2#3\xint_bye { #1#2}% +\long\expandafter\def\csname XINT_keepunbr_end8\endcsname + #1#2\xint_bye { #1}% +% \end{macrocode} +% \subsection{\csh{xintTrim}} +% \lverb?& +% +% First included in release 1.09m. +% +% \xintTrim{i}{L} f-expands its second argument L. It then removes the first i +% items from L and keeps the rest. For i equal or larger to the number N of +% items in (expanded) L, the macro returns an empty output. For i=0, the +% original (expanded) L is returned. For i<0, the macro proceeds from the +% tail. It thus removes the last |i| items, i.e. it keeps the first N-|i| +% items. For |i|>= N, the empty list is returned. +% +% \xintTrimNoExpand does not expand the L argument. +% +% Speed improvements with 1.2i for i<0 branch (which hands over to +% \xintKeep). Speed improvements with 1.2j for i>0 branch which gobbles items +% nine by nine despite not knowing in advance if it will go too far. +% ? +% \begin{macrocode} +\def\xintTrim {\romannumeral0\xinttrim }% +\def\xintTrimNoExpand {\romannumeral0\xinttrimnoexpand }% +\long\def\xinttrim #1#2{\expandafter\XINT_trim_a\the\numexpr #1\expandafter.% + \expandafter{\romannumeral`&&@#2}}% +\def\xinttrimnoexpand #1{\expandafter\XINT_trim_a\the\numexpr #1.}% +\def\XINT_trim_a #1% +{% + \xint_UDzerominusfork + #1-\XINT_trim_trimnone + 0#1\XINT_trim_neg + 0-{\XINT_trim_pos #1}% + \krof +}% +\long\def\XINT_trim_trimnone .#1{ #1}% +\long\def\XINT_trim_neg #1.#2% +{% + \expandafter\XINT_trim_neg_a\the\numexpr + #1-\numexpr\XINT_length_loop + #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v + \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye + .{}#2\xint_bye +}% +\def\XINT_trim_neg_a #1% +{% + \xint_UDsignfork + #1{\expandafter\XINT_keep_loop\the\numexpr-\xint_c_viii+}% + -\XINT_trim_trimall + \krof +}% +\def\XINT_trim_trimall#1{% +\def\XINT_trim_trimall {\expandafter#1\xint_bye}% +}\XINT_trim_trimall{ }% +% \end{macrocode} +% \lverb|This branch doesn't pre-evaluate the length of the list argument. +% Redone again for 1.2j, manages to trim nine by nine. Some non optimal +% looking aspect of the code is for allowing sharing with \xintNthElt.| +% \begin{macrocode} +\long\def\XINT_trim_pos #1.#2% +{% + \expandafter\XINT_trim_pos_done\expandafter\space + \romannumeral0\expandafter\XINT_trim_loop\the\numexpr#1-\xint_c_ix.% + #2\xint:\xint:\xint:\xint:\xint:% + \xint:\xint:\xint:\xint:\xint:% + \xint_bye +}% +\def\XINT_trim_loop #1#2.% +{% + \xint_gob_til_minus#1\XINT_trim_finish-% + \expandafter\XINT_trim_loop\the\numexpr#1#2\XINT_trim_loop_trimnine +}% +\long\def\XINT_trim_loop_trimnine #1#2#3#4#5#6#7#8#9% +{% + \xint_gob_til_xint: #9\XINT_trim_toofew\xint:-\xint_c_ix.% +}% +\def\XINT_trim_toofew\xint:{*\xint_c_}% +\def\XINT_trim_finish#1{% +\def\XINT_trim_finish-% + \expandafter\XINT_trim_loop\the\numexpr-##1\XINT_trim_loop_trimnine +{% + \expandafter\expandafter\expandafter#1% + \csname xint_gobble_\romannumeral\numexpr\xint_c_ix-##1\endcsname +}}\XINT_trim_finish{ }% +\long\def\XINT_trim_pos_done #1\xint:#2\xint_bye {#1}% +% \end{macrocode} +% \subsection{\csh{xintTrimUnbraced}} +% \lverb?1.2a. Modified in 1.2i like \xintTrim? +% \begin{macrocode} +\def\xintTrimUnbraced {\romannumeral0\xinttrimunbraced }% +\def\xintTrimUnbracedNoExpand {\romannumeral0\xinttrimunbracednoexpand }% +\long\def\xinttrimunbraced #1#2% + {\expandafter\XINT_trimunbr_a\the\numexpr #1\expandafter.% + \expandafter{\romannumeral`&&@#2}}% +\def\xinttrimunbracednoexpand #1% + {\expandafter\XINT_trimunbr_a\the\numexpr #1.}% +\def\XINT_trimunbr_a #1% +{% + \xint_UDzerominusfork + #1-\XINT_trim_trimnone + 0#1\XINT_trimunbr_neg + 0-{\XINT_trim_pos #1}% + \krof +}% +\long\def\XINT_trimunbr_neg #1.#2% +{% + \expandafter\XINT_trimunbr_neg_a\the\numexpr + #1-\numexpr\XINT_length_loop + #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v + \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye + .{}#2\xint_bye +}% +\def\XINT_trimunbr_neg_a #1% +{% + \xint_UDsignfork + #1{\expandafter\XINT_keepunbr_loop\the\numexpr-\xint_c_viii+}% + -\XINT_trim_trimall + \krof +}% +% \end{macrocode} +% \subsection{\csh{xintApply}} +% \lverb|\xintApply {\macro}{{a}{b}...{z}} returns {\macro{a}}...{\macro{b}} +% where each instance of \macro is f-expanded. The list itself is first +% f-expanded and may thus be a macro. Introduced with release 1.04.| +% \begin{macrocode} +\def\xintApply {\romannumeral0\xintapply }% +\def\xintApplyNoExpand {\romannumeral0\xintapplynoexpand }% +\long\def\xintapply #1#2% +{% + \expandafter\XINT_apply\expandafter {\romannumeral`&&@#2}% + {#1}% +}% +\long\def\XINT_apply #1#2{\XINT_apply_loop_a {}{#2}#1\xint_bye }% +\long\def\xintapplynoexpand #1#2{\XINT_apply_loop_a {}{#1}#2\xint_bye }% +\long\def\XINT_apply_loop_a #1#2#3% +{% + \xint_bye #3\XINT_apply_end\xint_bye + \expandafter + \XINT_apply_loop_b + \expandafter {\romannumeral`&&@#2{#3}}{#1}{#2}% +}% +\long\def\XINT_apply_loop_b #1#2{\XINT_apply_loop_a {#2{#1}}}% +\long\def\XINT_apply_end\xint_bye\expandafter\XINT_apply_loop_b + \expandafter #1#2#3{ #2}% +% \end{macrocode} +% \subsection{\csh{xintApplyUnbraced}} +% \lverb|\xintApplyUnbraced {\macro}{{a}{b}...{z}} returns \macro{a}...\macro{z} +% where each instance of \macro is f-expanded using \romannumeral-`0. The second +% argument may be a macro as it is itself also f-expanded. No braces +% are added: this allows for example a non-expandable \def in \macro, without +% having to do \gdef. Introduced with release 1.06b.| +% \begin{macrocode} +\def\xintApplyUnbraced {\romannumeral0\xintapplyunbraced }% +\def\xintApplyUnbracedNoExpand {\romannumeral0\xintapplyunbracednoexpand }% +\long\def\xintapplyunbraced #1#2% +{% + \expandafter\XINT_applyunbr\expandafter {\romannumeral`&&@#2}% + {#1}% +}% +\long\def\XINT_applyunbr #1#2{\XINT_applyunbr_loop_a {}{#2}#1\xint_bye }% +\long\def\xintapplyunbracednoexpand #1#2% + {\XINT_applyunbr_loop_a {}{#1}#2\xint_bye }% +\long\def\XINT_applyunbr_loop_a #1#2#3% +{% + \xint_bye #3\XINT_applyunbr_end\xint_bye + \expandafter\XINT_applyunbr_loop_b + \expandafter {\romannumeral`&&@#2{#3}}{#1}{#2}% +}% +\long\def\XINT_applyunbr_loop_b #1#2{\XINT_applyunbr_loop_a {#2#1}}% +\long\def\XINT_applyunbr_end\xint_bye\expandafter\XINT_applyunbr_loop_b + \expandafter #1#2#3{ #2}% +% \end{macrocode} +% \subsection{\csh{xintSeq}} +% \lverb|1.09c. Without the optional argument puts stress on the input stack, +% should not be used to generated thousands of terms then.| +% \begin{macrocode} +\def\xintSeq {\romannumeral0\xintseq }% +\def\xintseq #1{\XINT_seq_chkopt #1\xint_bye }% +\def\XINT_seq_chkopt #1% +{% + \ifx [#1\expandafter\XINT_seq_opt + \else\expandafter\XINT_seq_noopt + \fi #1% +}% +\def\XINT_seq_noopt #1\xint_bye #2% +{% + \expandafter\XINT_seq\expandafter + {\the\numexpr#1\expandafter}\expandafter{\the\numexpr #2}% +}% +\def\XINT_seq #1#2% +{% + \ifcase\ifnum #1=#2 0\else\ifnum #2>#1 1\else -1\fi\fi\space + \expandafter\xint_stop_atfirstoftwo + \or + \expandafter\XINT_seq_p + \else + \expandafter\XINT_seq_n + \fi + {#2}{#1}% +}% +\def\XINT_seq_p #1#2% +{% + \ifnum #1>#2 + \expandafter\expandafter\expandafter\XINT_seq_p + \else + \expandafter\XINT_seq_e + \fi + \expandafter{\the\numexpr #1-\xint_c_i}{#2}{#1}% +}% +\def\XINT_seq_n #1#2% +{% + \ifnum #1<#2 + \expandafter\expandafter\expandafter\XINT_seq_n + \else + \expandafter\XINT_seq_e + \fi + \expandafter{\the\numexpr #1+\xint_c_i}{#2}{#1}% +}% +\def\XINT_seq_e #1#2#3{ }% +\def\XINT_seq_opt [\xint_bye #1]#2#3% +{% + \expandafter\XINT_seqo\expandafter + {\the\numexpr #2\expandafter}\expandafter + {\the\numexpr #3\expandafter}\expandafter + {\the\numexpr #1}% +}% +\def\XINT_seqo #1#2% +{% + \ifcase\ifnum #1=#2 0\else\ifnum #2>#1 1\else -1\fi\fi\space + \expandafter\XINT_seqo_a + \or + \expandafter\XINT_seqo_pa + \else + \expandafter\XINT_seqo_na + \fi + {#1}{#2}% +}% +\def\XINT_seqo_a #1#2#3{ {#1}}% +\def\XINT_seqo_o #1#2#3#4{ #4}% +\def\XINT_seqo_pa #1#2#3% +{% + \ifcase\ifnum #3=\xint_c_ 0\else\ifnum #3>\xint_c_ 1\else -1\fi\fi\space + \expandafter\XINT_seqo_o + \or + \expandafter\XINT_seqo_pb + \else + \xint_afterfi{\expandafter\space\xint_gobble_iv}% + \fi + {#1}{#2}{#3}{{#1}}% +}% +\def\XINT_seqo_pb #1#2#3% +{% + \expandafter\XINT_seqo_pc\expandafter{\the\numexpr #1+#3}{#2}{#3}% +}% +\def\XINT_seqo_pc #1#2% +{% + \ifnum #1>#2 + \expandafter\XINT_seqo_o + \else + \expandafter\XINT_seqo_pd + \fi + {#1}{#2}% +}% +\def\XINT_seqo_pd #1#2#3#4{\XINT_seqo_pb {#1}{#2}{#3}{#4{#1}}}% +\def\XINT_seqo_na #1#2#3% +{% + \ifcase\ifnum #3=\xint_c_ 0\else\ifnum #3>\xint_c_ 1\else -1\fi\fi\space + \expandafter\XINT_seqo_o + \or + \xint_afterfi{\expandafter\space\xint_gobble_iv}% + \else + \expandafter\XINT_seqo_nb + \fi + {#1}{#2}{#3}{{#1}}% +}% +\def\XINT_seqo_nb #1#2#3% +{% + \expandafter\XINT_seqo_nc\expandafter{\the\numexpr #1+#3}{#2}{#3}% +}% +\def\XINT_seqo_nc #1#2% +{% + \ifnum #1<#2 + \expandafter\XINT_seqo_o + \else + \expandafter\XINT_seqo_nd + \fi + {#1}{#2}% +}% +\def\XINT_seqo_nd #1#2#3#4{\XINT_seqo_nb {#1}{#2}{#3}{#4{#1}}}% +% \end{macrocode} +%\subsection{\csh{xintloop}, \csh{xintbreakloop}, \csh{xintbreakloopanddo}, +% \csh{xintloopskiptonext}} +% \lverb|1.09g [2013/11/22]. Made long with 1.09h.| +% \begin{macrocode} +\long\def\xintloop #1#2\repeat {#1#2\xintloop_again\fi\xint_gobble_i {#1#2}}% +\long\def\xintloop_again\fi\xint_gobble_i #1{\fi + #1\xintloop_again\fi\xint_gobble_i {#1}}% +\long\def\xintbreakloop #1\xintloop_again\fi\xint_gobble_i #2{}% +\long\def\xintbreakloopanddo #1#2\xintloop_again\fi\xint_gobble_i #3{#1}% +\long\def\xintloopskiptonext #1\xintloop_again\fi\xint_gobble_i #2{% + #2\xintloop_again\fi\xint_gobble_i {#2}}% +% \end{macrocode} +% \subsection{\csh{xintiloop}, +% \csh{xintiloopindex}, +% \csh{xintbracediloopindex}, +% \csh{xintouteriloopindex}, +% \csh{xintbracedouteriloopindex}, +% \csh{xintbreakiloop}, +% \csh{xintbreakiloopanddo}, +% \csh{xintiloopskiptonext}, +% \csh{xintiloopskipandredo}} +% \lverb|1.09g [2013/11/22]. Made long with 1.09h. +% +% «braced» variants added (2018/04/24) for 1.3b.| +% \begin{macrocode} +\def\xintiloop [#1+#2]{% + \expandafter\xintiloop_a\the\numexpr #1\expandafter.\the\numexpr #2.}% +\long\def\xintiloop_a #1.#2.#3#4\repeat{% + #3#4\xintiloop_again\fi\xint_gobble_iii {#1}{#2}{#3#4}}% +\def\xintiloop_again\fi\xint_gobble_iii #1#2{% + \fi\expandafter\xintiloop_again_b\the\numexpr#1+#2.#2.}% +\long\def\xintiloop_again_b #1.#2.#3{% + #3\xintiloop_again\fi\xint_gobble_iii {#1}{#2}{#3}}% +\long\def\xintbreakiloop #1\xintiloop_again\fi\xint_gobble_iii #2#3#4{}% +\long\def\xintbreakiloopanddo + #1.#2\xintiloop_again\fi\xint_gobble_iii #3#4#5{#1}% +\long\def\xintiloopindex #1\xintiloop_again\fi\xint_gobble_iii #2% + {#2#1\xintiloop_again\fi\xint_gobble_iii {#2}}% +\long\def\xintbracediloopindex #1\xintiloop_again\fi\xint_gobble_iii #2% + {{#2}#1\xintiloop_again\fi\xint_gobble_iii {#2}}% +\long\def\xintouteriloopindex #1\xintiloop_again + #2\xintiloop_again\fi\xint_gobble_iii #3% + {#3#1\xintiloop_again #2\xintiloop_again\fi\xint_gobble_iii {#3}}% +\long\def\xintbracedouteriloopindex #1\xintiloop_again + #2\xintiloop_again\fi\xint_gobble_iii #3% + {{#3}#1\xintiloop_again #2\xintiloop_again\fi\xint_gobble_iii {#3}}% +\long\def\xintiloopskiptonext #1\xintiloop_again\fi\xint_gobble_iii #2#3{% + \expandafter\xintiloop_again_b \the\numexpr#2+#3.#3.}% +\long\def\xintiloopskipandredo #1\xintiloop_again\fi\xint_gobble_iii #2#3#4{% + #4\xintiloop_again\fi\xint_gobble_iii {#2}{#3}{#4}}% +% \end{macrocode} +% \subsection{\csh{XINT_xflet}} +% \lverb|1.09e [2013/10/29]: we f-expand unbraced tokens and swallow arising +% space tokens until the dust settles.| +% \begin{macrocode} +\def\XINT_xflet #1% +{% + \def\XINT_xflet_macro {#1}\XINT_xflet_zapsp +}% +\def\XINT_xflet_zapsp +{% + \expandafter\futurelet\expandafter\XINT_token + \expandafter\XINT_xflet_sp?\romannumeral`&&@% +}% +\def\XINT_xflet_sp? +{% + \ifx\XINT_token\XINT_sptoken + \expandafter\XINT_xflet_zapsp + \else\expandafter\XINT_xflet_zapspB + \fi +}% +\def\XINT_xflet_zapspB +{% + \expandafter\futurelet\expandafter\XINT_tokenB + \expandafter\XINT_xflet_spB?\romannumeral`&&@% +}% +\def\XINT_xflet_spB? +{% + \ifx\XINT_tokenB\XINT_sptoken + \expandafter\XINT_xflet_zapspB + \else\expandafter\XINT_xflet_eq? + \fi +}% +\def\XINT_xflet_eq? +{% + \ifx\XINT_token\XINT_tokenB + \expandafter\XINT_xflet_macro + \else\expandafter\XINT_xflet_zapsp + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintApplyInline}} +% \lverb|1.09a: \xintApplyInline\macro{{a}{b}...{z}} has the same effect as +% executing \macro{a} and then applying again \xintApplyInline to the shortened +% list {{b}...{z}} until nothing is left. This is a non-expandable command +% which will result in quicker code than using \xintApplyUnbraced. It f-expands +% its second (list) argument first, which may thus be encapsulated in a macro. +% +% Rewritten in 1.09c. Nota bene: uses catcode 3 Z as privated list terminator.| +% \begin{macrocode} +\catcode`Z 3 +\long\def\xintApplyInline #1#2% +{% + \long\expandafter\def\expandafter\XINT_inline_macro + \expandafter ##\expandafter 1\expandafter {#1{##1}}% + \XINT_xflet\XINT_inline_b #2Z% this Z has catcode 3 +}% +\def\XINT_inline_b +{% + \ifx\XINT_token Z\expandafter\xint_gobble_i + \else\expandafter\XINT_inline_d\fi +}% +\long\def\XINT_inline_d #1% +{% + \long\def\XINT_item{{#1}}\XINT_xflet\XINT_inline_e +}% +\def\XINT_inline_e +{% + \ifx\XINT_token Z\expandafter\XINT_inline_w + \else\expandafter\XINT_inline_f\fi +}% +\def\XINT_inline_f +{% + \expandafter\XINT_inline_g\expandafter{\XINT_inline_macro {##1}}% +}% +\long\def\XINT_inline_g #1% +{% + \expandafter\XINT_inline_macro\XINT_item + \long\def\XINT_inline_macro ##1{#1}\XINT_inline_d +}% +\def\XINT_inline_w #1% +{% + \expandafter\XINT_inline_macro\XINT_item +}% +% \end{macrocode} +% \subsection{\csh{xintFor}, \csh{xintFor*}, \csh{xintBreakFor}, \csh{xintBreakForAndDo}} +% \lverb|1.09c [2013/10/09]: a new kind of loop which uses macro parameters +% #1, #2, #3, #4 rather than macros; while not expandable it survives executing +% code closing groups, like what happens in an alignment with the $& character. +% When inserted in a macro for later use, the # character must be doubled. +% +% The non-star variant works on a csv list, which it expands once, the +% star variant works on a token list, which it (repeatedly) f-expands. +% +% 1.09e adds \XINT_forever with \xintintegers, \xintdimensions, \xintrationals +% and \xintBreakFor, \xintBreakForAndDo, \xintifForFirst, \xintifForLast. On +% this occasion \xint_firstoftwo and \xint_secondoftwo are made long. +% +% 1.09f: rewrites large parts of \xintFor code in order to filter the comma +% separated list via \xintCSVtoList which gets rid of spaces. The #1 in +% \XINT_for_forever? has an initial space token which serves two purposes: +% preventing brace stripping, and stopping the expansion made by \xintcsvtolist. +% If the \XINT_forever branch is taken, the added space will not be a problem +% there. +% +% 1.09f rewrites (2013/11/03) the code which now allows all macro parameters +% from #1 to #9 in \xintFor, \xintFor*, and \XINT_forever. +% 1.2i: slightly more robust \xintifForFirst/Last in case of nesting. +% | +% \begin{macrocode} +\def\XINT_tmpa #1#2{\ifnum #2<#1 \xint_afterfi {{#########2}}\fi}% +\def\XINT_tmpb #1#2{\ifnum #1<#2 \xint_afterfi {{#########2}}\fi}% +\def\XINT_tmpc #1% +{% + \expandafter\edef \csname XINT_for_left#1\endcsname + {\xintApplyUnbraced {\XINT_tmpa #1}{123456789}}% + \expandafter\edef \csname XINT_for_right#1\endcsname + {\xintApplyUnbraced {\XINT_tmpb #1}{123456789}}% +}% +\xintApplyInline \XINT_tmpc {123456789}% +\long\def\xintBreakFor #1Z{}% +\long\def\xintBreakForAndDo #1#2Z{#1}% +\def\xintFor {\let\xintifForFirst\xint_firstoftwo + \let\xintifForLast\xint_secondoftwo + \futurelet\XINT_token\XINT_for_ifstar }% +\def\XINT_for_ifstar {\ifx\XINT_token*\expandafter\XINT_forx + \else\expandafter\XINT_for \fi }% +\catcode`U 3 % with numexpr +\catcode`V 3 % with xintfrac.sty (xint.sty not enough) +\catcode`D 3 % with dimexpr +\def\XINT_flet_zapsp +{% + \futurelet\XINT_token\XINT_flet_sp? +}% +\def\XINT_flet_sp? +{% + \ifx\XINT_token\XINT_sptoken + \xint_afterfi{\expandafter\XINT_flet_zapsp\romannumeral0}% + \else\expandafter\XINT_flet_macro + \fi +}% +\long\def\XINT_for #1#2in#3#4#5% +{% + \expandafter\XINT_toks\expandafter + {\expandafter\XINT_for_d\the\numexpr #2\relax {#5}}% + \def\XINT_flet_macro {\expandafter\XINT_for_forever?\space}% + \expandafter\XINT_flet_zapsp #3Z% +}% +\def\XINT_for_forever? #1Z% +{% + \ifx\XINT_token U\XINT_to_forever\fi + \ifx\XINT_token V\XINT_to_forever\fi + \ifx\XINT_token D\XINT_to_forever\fi + \expandafter\the\expandafter\XINT_toks\romannumeral0\xintcsvtolist {#1}Z% +}% +\def\XINT_to_forever\fi #1\xintcsvtolist #2{\fi \XINT_forever #2}% +\long\def\XINT_forx *#1#2in#3#4#5% +{% + \expandafter\XINT_toks\expandafter + {\expandafter\XINT_forx_d\the\numexpr #2\relax {#5}}% + \XINT_xflet\XINT_forx_forever? #3Z% +}% +\def\XINT_forx_forever? +{% + \ifx\XINT_token U\XINT_to_forxever\fi + \ifx\XINT_token V\XINT_to_forxever\fi + \ifx\XINT_token D\XINT_to_forxever\fi + \XINT_forx_empty? +}% +\def\XINT_to_forxever\fi #1\XINT_forx_empty? {\fi \XINT_forever }% +\catcode`U 11 +\catcode`D 11 +\catcode`V 11 +\def\XINT_forx_empty? +{% + \ifx\XINT_token Z\expandafter\xintBreakFor\fi + \the\XINT_toks +}% +\long\def\XINT_for_d #1#2#3% +{% + \long\def\XINT_y ##1##2##3##4##5##6##7##8##9{#2}% + \XINT_toks {{#3}}% + \long\edef\XINT_x {\noexpand\XINT_y \csname XINT_for_left#1\endcsname + \the\XINT_toks \csname XINT_for_right#1\endcsname }% + \XINT_toks {\XINT_x\let\xintifForFirst\xint_secondoftwo + \let\xintifForLast\xint_secondoftwo\XINT_for_d #1{#2}}% + \futurelet\XINT_token\XINT_for_last? +}% +\long\def\XINT_forx_d #1#2#3% +{% + \long\def\XINT_y ##1##2##3##4##5##6##7##8##9{#2}% + \XINT_toks {{#3}}% + \long\edef\XINT_x {\noexpand\XINT_y \csname XINT_for_left#1\endcsname + \the\XINT_toks \csname XINT_for_right#1\endcsname }% + \XINT_toks {\XINT_x\let\xintifForFirst\xint_secondoftwo + \let\xintifForLast\xint_secondoftwo\XINT_forx_d #1{#2}}% + \XINT_xflet\XINT_for_last? +}% +\def\XINT_for_last? +{% + \ifx\XINT_token Z\expandafter\XINT_for_last?yes\fi + \the\XINT_toks +}% +\def\XINT_for_last?yes +{% + \let\xintifForLast\xint_firstoftwo + \xintBreakForAndDo{\XINT_x\xint_gobble_i Z}% +}% +% \end{macrocode} +% \subsection{\csh{XINT_forever}, \csh{xintintegers}, \csh{xintdimensions}, \csh{xintrationals}} +% \lverb|New with 1.09e. But this used inadvertently \xintiadd/\xintimul which +% have the unnecessary \xintnum overhead. Changed in 1.09f to use +% \xintiiadd/\xintiimul which do not have this overhead. Also 1.09f uses +% \xintZapSpacesB for the \xintrationals case to get rid of leading and ending +% spaces in the #4 and #5 delimited parameters of \XINT_forever_opt_a +% (for \xintintegers and \xintdimensions this is not necessary, due to the use +% of \numexpr resp. \dimexpr in \XINT_?expr_Ua, resp.\XINT_?expr_Da).| +% \begin{macrocode} +\catcode`U 3 +\catcode`D 3 +\catcode`V 3 +\let\xintegers U% +\let\xintintegers U% +\let\xintdimensions D% +\let\xintrationals V% +\def\XINT_forever #1% +{% + \expandafter\XINT_forever_a + \csname XINT_?expr_\ifx#1UU\else\ifx#1DD\else V\fi\fi a\expandafter\endcsname + \csname XINT_?expr_\ifx#1UU\else\ifx#1DD\else V\fi\fi i\expandafter\endcsname + \csname XINT_?expr_\ifx#1UU\else\ifx#1DD\else V\fi\fi \endcsname +}% +\catcode`U 11 +\catcode`D 11 +\catcode`V 11 +\def\XINT_?expr_Ua #1#2% + {\expandafter{\expandafter\numexpr\the\numexpr #1\expandafter\relax + \expandafter\relax\expandafter}% + \expandafter{\the\numexpr #2}}% +\def\XINT_?expr_Da #1#2% + {\expandafter{\expandafter\dimexpr\number\dimexpr #1\expandafter\relax + \expandafter s\expandafter p\expandafter\relax\expandafter}% + \expandafter{\number\dimexpr #2}}% +\catcode`Z 11 +\def\XINT_?expr_Va #1#2% +{% + \expandafter\XINT_?expr_Vb\expandafter + {\romannumeral`&&@\xintrawwithzeros{\xintZapSpacesB{#2}}}% + {\romannumeral`&&@\xintrawwithzeros{\xintZapSpacesB{#1}}}% +}% +\catcode`Z 3 +\def\XINT_?expr_Vb #1#2{\expandafter\XINT_?expr_Vc #2.#1.}% +\def\XINT_?expr_Vc #1/#2.#3/#4.% +{% + \xintifEq {#2}{#4}% + {\XINT_?expr_Vf {#3}{#1}{#2}}% + {\expandafter\XINT_?expr_Vd\expandafter + {\romannumeral0\xintiimul {#2}{#4}}% + {\romannumeral0\xintiimul {#1}{#4}}% + {\romannumeral0\xintiimul {#2}{#3}}% + }% +}% +\def\XINT_?expr_Vd #1#2#3{\expandafter\XINT_?expr_Ve\expandafter {#2}{#3}{#1}}% +\def\XINT_?expr_Ve #1#2{\expandafter\XINT_?expr_Vf\expandafter {#2}{#1}}% +\def\XINT_?expr_Vf #1#2#3{{#2/#3}{{0}{#1}{#2}{#3}}}% +\def\XINT_?expr_Ui {{\numexpr 1\relax}{1}}% +\def\XINT_?expr_Di {{\dimexpr 0pt\relax}{65536}}% +\def\XINT_?expr_Vi {{1/1}{0111}}% +\def\XINT_?expr_U #1#2% + {\expandafter{\expandafter\numexpr\the\numexpr #1+#2\relax\relax}{#2}}% +\def\XINT_?expr_D #1#2% + {\expandafter{\expandafter\dimexpr\the\numexpr #1+#2\relax sp\relax}{#2}}% +\def\XINT_?expr_V #1#2{\XINT_?expr_Vx #2}% +\def\XINT_?expr_Vx #1#2% +{% + \expandafter\XINT_?expr_Vy\expandafter + {\romannumeral0\xintiiadd {#1}{#2}}{#2}% +}% +\def\XINT_?expr_Vy #1#2#3#4% +{% + \expandafter{\romannumeral0\xintiiadd {#3}{#1}/#4}{{#1}{#2}{#3}{#4}}% +}% +\def\XINT_forever_a #1#2#3#4% +{% + \ifx #4[\expandafter\XINT_forever_opt_a + \else\expandafter\XINT_forever_b + \fi #1#2#3#4% +}% +\def\XINT_forever_b #1#2#3Z{\expandafter\XINT_forever_c\the\XINT_toks #2#3}% +\long\def\XINT_forever_c #1#2#3#4#5% + {\expandafter\XINT_forever_d\expandafter #2#4#5{#3}Z}% +\def\XINT_forever_opt_a #1#2#3[#4+#5]#6Z% +{% + \expandafter\expandafter\expandafter + \XINT_forever_opt_c\expandafter\the\expandafter\XINT_toks + \romannumeral`&&@#1{#4}{#5}#3% +}% +\long\def\XINT_forever_opt_c #1#2#3#4#5#6{\XINT_forever_d #2{#4}{#5}#6{#3}Z}% +\long\def\XINT_forever_d #1#2#3#4#5% +{% + \long\def\XINT_y ##1##2##3##4##5##6##7##8##9{#5}% + \XINT_toks {{#2}}% + \long\edef\XINT_x {\noexpand\XINT_y \csname XINT_for_left#1\endcsname + \the\XINT_toks \csname XINT_for_right#1\endcsname }% + \XINT_x + \let\xintifForFirst\xint_secondoftwo + \let\xintifForLast\xint_secondoftwo + \expandafter\XINT_forever_d\expandafter #1\romannumeral`&&@#4{#2}{#3}#4{#5}% +}% +% \end{macrocode} +% \subsection{\csh{xintForpair}, \csh{xintForthree}, \csh{xintForfour}} +% \lverb|1.09c. +% +% [2013/11/02] 1.09f \xintForpair delegate to \xintCSVtoList and its +% \xintZapSpacesB the handling of spaces. Does not share code with \xintFor +% anymore. +% +% [2013/11/03] 1.09f: \xintForpair extended to accept #1#2, #2#3 etc... up to +% #8#9, \xintForthree, #1#2#3 up to #7#8#9, \xintForfour id. +% +% 1.2i: slightly more robust \xintifForFirst/Last in case of nesting. +% | +% \begin{macrocode} +\catcode`j 3 +\long\def\xintForpair #1#2#3in#4#5#6% +{% + \let\xintifForFirst\xint_firstoftwo + \let\xintifForLast\xint_secondoftwo + \XINT_toks {\XINT_forpair_d #2{#6}}% + \expandafter\the\expandafter\XINT_toks #4jZ% +}% +\long\def\XINT_forpair_d #1#2#3(#4)#5% +{% + \long\def\XINT_y ##1##2##3##4##5##6##7##8##9{#2}% + \XINT_toks \expandafter{\romannumeral0\xintcsvtolist{ #4}}% + \long\edef\XINT_x {\noexpand\XINT_y \csname XINT_for_left#1\endcsname + \the\XINT_toks \csname XINT_for_right\the\numexpr#1+\xint_c_i\endcsname}% + \ifx #5j\expandafter\XINT_for_last?yes\fi + \XINT_x + \let\xintifForFirst\xint_secondoftwo + \let\xintifForLast\xint_secondoftwo + \XINT_forpair_d #1{#2}% +}% +\long\def\xintForthree #1#2#3in#4#5#6% +{% + \let\xintifForFirst\xint_firstoftwo + \let\xintifForLast\xint_secondoftwo + \XINT_toks {\XINT_forthree_d #2{#6}}% + \expandafter\the\expandafter\XINT_toks #4jZ% +}% +\long\def\XINT_forthree_d #1#2#3(#4)#5% +{% + \long\def\XINT_y ##1##2##3##4##5##6##7##8##9{#2}% + \XINT_toks \expandafter{\romannumeral0\xintcsvtolist{ #4}}% + \long\edef\XINT_x {\noexpand\XINT_y \csname XINT_for_left#1\endcsname + \the\XINT_toks \csname XINT_for_right\the\numexpr#1+\xint_c_ii\endcsname}% + \ifx #5j\expandafter\XINT_for_last?yes\fi + \XINT_x + \let\xintifForFirst\xint_secondoftwo + \let\xintifForLast\xint_secondoftwo + \XINT_forthree_d #1{#2}% +}% +\long\def\xintForfour #1#2#3in#4#5#6% +{% + \let\xintifForFirst\xint_firstoftwo + \let\xintifForLast\xint_secondoftwo + \XINT_toks {\XINT_forfour_d #2{#6}}% + \expandafter\the\expandafter\XINT_toks #4jZ% +}% +\long\def\XINT_forfour_d #1#2#3(#4)#5% +{% + \long\def\XINT_y ##1##2##3##4##5##6##7##8##9{#2}% + \XINT_toks \expandafter{\romannumeral0\xintcsvtolist{ #4}}% + \long\edef\XINT_x {\noexpand\XINT_y \csname XINT_for_left#1\endcsname + \the\XINT_toks \csname XINT_for_right\the\numexpr#1+\xint_c_iii\endcsname}% + \ifx #5j\expandafter\XINT_for_last?yes\fi + \XINT_x + \let\xintifForFirst\xint_secondoftwo + \let\xintifForLast\xint_secondoftwo + \XINT_forfour_d #1{#2}% +}% +\catcode`Z 11 +\catcode`j 11 +% \end{macrocode} +% \subsection{\csh{xintAssign}, \csh{xintAssignArray}, \csh{xintDigitsOf}} +% \lverb|\xintAssign {a}{b}..{z}\to\A\B...\Z resp. \xintAssignArray +% {a}{b}..{z}\to\U. +% +% \xintDigitsOf=\xintAssignArray. +% +% 1.1c 2015/09/12 has (belatedly) corrected some "features" of +% \xintAssign which didn't like the case of a space right before the "\to", or +% the case with the first token not an opening brace and the subsequent +% material containing brace groups. The new code handles gracefully these +% situations.| +% \begin{macrocode} +\def\xintAssign{\def\XINT_flet_macro {\XINT_assign_fork}\XINT_flet_zapsp }% +\def\XINT_assign_fork +{% + \let\XINT_assign_def\def + \ifx\XINT_token[\expandafter\XINT_assign_opt + \else\expandafter\XINT_assign_a + \fi +}% +\def\XINT_assign_opt [#1]% +{% + \ifcsname #1def\endcsname + \expandafter\let\expandafter\XINT_assign_def \csname #1def\endcsname + \else + \expandafter\let\expandafter\XINT_assign_def \csname xint#1def\endcsname + \fi + \XINT_assign_a +}% +\long\def\XINT_assign_a #1\to +{% + \def\XINT_flet_macro{\XINT_assign_b}% + \expandafter\XINT_flet_zapsp\romannumeral`&&@#1\xint:\to +}% +\long\def\XINT_assign_b +{% + \ifx\XINT_token\bgroup + \expandafter\XINT_assign_c + \else\expandafter\XINT_assign_f + \fi +}% +\long\def\XINT_assign_f #1\xint:\to #2% +{% + \XINT_assign_def #2{#1}% +}% +\long\def\XINT_assign_c #1% +{% + \def\xint_temp {#1}% + \ifx\xint_temp\xint_bracedstopper + \expandafter\XINT_assign_e + \else + \expandafter\XINT_assign_d + \fi +}% +\long\def\XINT_assign_d #1\to #2% +{% + \expandafter\XINT_assign_def\expandafter #2\expandafter{\xint_temp}% + \XINT_assign_c #1\to +}% +\def\XINT_assign_e #1\to {}% +\def\xintRelaxArray #1% +{% + \edef\XINT_restoreescapechar {\escapechar\the\escapechar\relax}% + \escapechar -1 + \expandafter\def\expandafter\xint_arrayname\expandafter {\string #1}% + \XINT_restoreescapechar + \xintiloop [\csname\xint_arrayname 0\endcsname+-1] + \global + \expandafter\let\csname\xint_arrayname\xintiloopindex\endcsname\relax + \ifnum \xintiloopindex > \xint_c_ + \repeat + \global\expandafter\let\csname\xint_arrayname 00\endcsname\relax + \global\let #1\relax +}% +\def\xintAssignArray{\def\XINT_flet_macro {\XINT_assignarray_fork}% + \XINT_flet_zapsp }% +\def\XINT_assignarray_fork +{% + \let\XINT_assignarray_def\def + \ifx\XINT_token[\expandafter\XINT_assignarray_opt + \else\expandafter\XINT_assignarray + \fi +}% +\def\XINT_assignarray_opt [#1]% +{% + \ifcsname #1def\endcsname + \expandafter\let\expandafter\XINT_assignarray_def \csname #1def\endcsname + \else + \expandafter\let\expandafter\XINT_assignarray_def + \csname xint#1def\endcsname + \fi + \XINT_assignarray +}% +\long\def\XINT_assignarray #1\to #2% +{% + \edef\XINT_restoreescapechar {\escapechar\the\escapechar\relax }% + \escapechar -1 + \expandafter\def\expandafter\xint_arrayname\expandafter {\string #2}% + \XINT_restoreescapechar + \def\xint_itemcount {0}% + \expandafter\XINT_assignarray_loop \romannumeral`&&@#1\xint: + \csname\xint_arrayname 00\expandafter\endcsname + \csname\xint_arrayname 0\expandafter\endcsname + \expandafter {\xint_arrayname}#2% +}% +\long\def\XINT_assignarray_loop #1% +{% + \def\xint_temp {#1}% + \ifx\xint_temp\xint_bracedstopper + \expandafter\def\csname\xint_arrayname 0\expandafter\endcsname + \expandafter{\the\numexpr\xint_itemcount}% + \expandafter\expandafter\expandafter\XINT_assignarray_end + \else + \expandafter\def\expandafter\xint_itemcount\expandafter + {\the\numexpr\xint_itemcount+\xint_c_i}% + \expandafter\XINT_assignarray_def + \csname\xint_arrayname\xint_itemcount\expandafter\endcsname + \expandafter{\xint_temp }% + \expandafter\XINT_assignarray_loop + \fi +}% +\def\XINT_assignarray_end #1#2#3#4% +{% + \def #4##1% + {% + \romannumeral0\expandafter #1\expandafter{\the\numexpr ##1}% + }% + \def #1##1% + {% + \ifnum ##1<\xint_c_ + \xint_afterfi{\XINT_expandableerror{Array index negative: 0 > ##1} }% + \else + \xint_afterfi {% + \ifnum ##1>#2 + \xint_afterfi + {\XINT_expandableerror{Array index beyond range: ##1 > #2} }% + \else\xint_afterfi + {\expandafter\expandafter\expandafter\space\csname #3##1\endcsname}% + \fi}% + \fi + }% +}% +\let\xintDigitsOf\xintAssignArray +% \end{macrocode} +% \subsection{\csh{xintExpandArgs}} +% \lverb|1.3a. Added for the needs of user defined functions for the +% expression parsers. Should I re-code it to gain a bit in argument grabbing? +% Must be f-expandable.| +% \begin{macrocode} +\def\xintExpandArgs#1#2{\csname #1\expandafter\endcsname + \romannumeral0\xintapply\xint_firstofone{#2}}% +% \end{macrocode} +%\subsection{CSV (non user documented) variants of Length, Keep, Trim, NthElt, Reverse} +% +% These routines are for use by |\xintListSel:x:csv| and |\xintListSel:f:csv| +% from \xintexprnameimp, and also for the |reversed| and |len| functions. +% Refactored for |1.2j| release, following |1.2i| updates to |\xintKeep|, +% |\xintTrim|, ... +% +% These macros will remain undocumented in the user manual: +% +% -- they exist primarily for internal use by the \xintexprnameimp parsers, +% hence don't have to be general purpose; for example, they a priori need to +% handle only catcode 12 tokens (not true in |\xintNewExpr|, though) +% hence they are not really worried about +% controlling brace stripping (nevertheless |1.2j| has paid some secondary +% attention to it, see below.) They are not worried about normalizing leading +% spaces either, because none will be encountered when the macros are used as +% auxiliaries to the expression parsers. +% +% -- crucial design elements may change in future: +% +% 1. whether the handled lists must have or not have a final comma. Currently, +% the model is the one of comma separated lists with **no** final comma. But +% this means that there can not be a distinction of principle between a truly +% empty list and a list which contains one item which turns out to be empty. +% More importantly it makes the coding more complicated as it is needed to +% distinguish the empty list from the single-item list, both lacking commas. +% +% For the internal use of \xintexprnameimp, it would be ok to require all list +% items to be terminated by a comma, and this would bring quite some +% simplications here, but as initially I started with non-terminated lists, I +% have left it this way in the |1.2j| refactoring. +% +% 2. the way to represent the empty list. I was tempted for matter of +% optimization and synchronization with \xintexprnameimp context to require +% the empty list to be always represented by a space token and to not let the +% macros admit a completely empty input. But there were complications so for +% the time being |1.2j| does accept truly empty output (it is not +% distinguished from an input equal to a space token) and produces empty +% output for empty list. This means that the status of the «nil» object for +% the \xintexprnameimp parsers is not completely clarified (currently it is +% represented by a space token). +% +% The original Python slicing code in \xintexprnameimp |1.1| used +% |\xintCSVtoList| and |\xintListWithSep{,}| to convert back and forth to +% token lists and apply |\xintKeep/\xintTrim|. Release |1.2g| switched to +% devoted f-expandable macros added to \xinttoolsnameimp. Release |1.2j| +% refactored all these macros as a follow-up to |1.2i| improvements to +% |\xintKeep/\xintTrim|. They were made |\long| on this occasion and +% auxiliary |\xintLengthUpTo:f:csv| was added. +% +% Leading spaces in items are currently maintained as is by the |1.2j| +% macros, even by |\xintNthEltPy:f:csv|, with the exception of the first item, +% as the list is f-expanded. Perhaps |\xintNthEltPy:f:csv| should remove a +% leading space if present in the picked item; anyway, there are no spaces +% for the lists handled internally by the Python slicer of \xintexprnameimp, +% except the «nil» object currently represented by exactly one space. +% +% Kept items (with no leading spaces; but first item special as it will have +% lost a leading space due to f-expansion) will lose a brace pair under +% |\xintKeep:f:csv| if the first argument was positive and strictly less than +% the length of the list. This differs of course from |\xintKeep| (which +% always braces items it outputs when used with positive first argument) and +% also from |\xintKeepUnbraced| in the case when the whole list is kept. +% Actually the case of singleton list is special, and brace removal will +% happen then. +% +% This behaviour was otherwise for releases earlier than |1.2j| and may +% change again. +% +% Directly usable names are provided, but these macros (and the behaviour as +% described above) are to be considered \emph{unstable} for the time being. +% +% \subsubsection{\csh{xintLength:f:csv}} +% \lverb|1.2g. Redone for 1.2j. Contrarily to \xintLength from xintkernel.sty, +% this one expands its argument.| +% \begin{macrocode} +\def\xintLength:f:csv {\romannumeral0\xintlength:f:csv}% +\def\xintlength:f:csv #1% +{\long\def\xintlength:f:csv ##1{% + \expandafter#1\the\numexpr\expandafter\XINT_length:f:csv_a + \romannumeral`&&@##1\xint:,\xint:,\xint:,\xint:,% + \xint:,\xint:,\xint:,\xint:,\xint:,% + \xint_c_ix,\xint_c_viii,\xint_c_vii,\xint_c_vi,% + \xint_c_v,\xint_c_iv,\xint_c_iii,\xint_c_ii,\xint_c_i,\xint_bye + \relax +}}\xintlength:f:csv { }% +% \end{macrocode} +% \lverb|Must first check if empty list.| +% \begin{macrocode} +\long\def\XINT_length:f:csv_a #1% +{% + \xint_gob_til_xint: #1\xint_c_\xint_bye\xint:% + \XINT_length:f:csv_loop #1% +}% +\long\def\XINT_length:f:csv_loop #1,#2,#3,#4,#5,#6,#7,#8,#9,% +{% + \xint_gob_til_xint: #9\XINT_length:f:csv_finish\xint:% + \xint_c_ix+\XINT_length:f:csv_loop +}% +\def\XINT_length:f:csv_finish\xint:\xint_c_ix+\XINT_length:f:csv_loop + #1,#2,#3,#4,#5,#6,#7,#8,#9,{#9\xint_bye}% +% \end{macrocode} +% \subsubsection{\csh{xintLengthUpTo:f:csv}} +% \lverb|1.2j. \xintLengthUpTo:f:csv{N}{comma-list}. No ending comma. Returns +% -0 if length>N, else returns difference N-length. **N must be non-negative!!** +% +% Attention to the dot after \xint_bye for the loop interface.| +% \begin{macrocode} +\def\xintLengthUpTo:f:csv {\romannumeral0\xintlengthupto:f:csv}% +\long\def\xintlengthupto:f:csv #1#2% +{% + \expandafter\XINT_lengthupto:f:csv_a + \the\numexpr#1\expandafter.% + \romannumeral`&&@#2\xint:,\xint:,\xint:,\xint:,% + \xint:,\xint:,\xint:,\xint:,% + \xint_c_viii,\xint_c_vii,\xint_c_vi,\xint_c_v,% + \xint_c_iv,\xint_c_iii,\xint_c_ii,\xint_c_i,\xint_bye.% +}% +% \end{macrocode} +% \lverb|Must first recognize if empty list. If this is the case, return N.| +% \begin{macrocode} +\long\def\XINT_lengthupto:f:csv_a #1.#2% +{% + \xint_gob_til_xint: #2\XINT_lengthupto:f:csv_empty\xint:% + \XINT_lengthupto:f:csv_loop_b #1.#2% +}% +\def\XINT_lengthupto:f:csv_empty\xint:% + \XINT_lengthupto:f:csv_loop_b #1.#2\xint_bye.{ #1}% +\def\XINT_lengthupto:f:csv_loop_a #1% +{% + \xint_UDsignfork + #1\XINT_lengthupto:f:csv_gt + -\XINT_lengthupto:f:csv_loop_b + \krof #1% +}% +\long\def\XINT_lengthupto:f:csv_gt #1\xint_bye.{-0}% +\long\def\XINT_lengthupto:f:csv_loop_b #1.#2,#3,#4,#5,#6,#7,#8,#9,% +{% + \xint_gob_til_xint: #9\XINT_lengthupto:f:csv_finish_a\xint:% + \expandafter\XINT_lengthupto:f:csv_loop_a\the\numexpr #1-\xint_c_viii.% +}% +\def\XINT_lengthupto:f:csv_finish_a\xint: + \expandafter\XINT_lengthupto:f:csv_loop_a + \the\numexpr #1-\xint_c_viii.#2,#3,#4,#5,#6,#7,#8,#9,% +{% + \expandafter\XINT_lengthupto:f:csv_finish_b\the\numexpr #1-#9\xint_bye +}% +\def\XINT_lengthupto:f:csv_finish_b #1#2.% +{% + \xint_UDsignfork + #1{-0}% + -{ #1#2}% + \krof +}% +% \end{macrocode} +%\subsubsection{\csh{xintKeep:f:csv}} +% \lverb|1.2g 2016/03/17. Redone for 1.2j with use of \xintLengthUpTo:f:csv. +% Same code skeleton as \xintKeep but handling comma separated but non +% terminated lists has complications. The \xintKeep in case of a negative #1 +% uses \xintgobble, we don't have that for comma delimited items, hence we do +% a special loop here (this style of loop is surely competitive with +% xintgobble for a few dozens items and even more). The loop knows before +% starting that it will not go too far. +% +%| +% \begin{macrocode} +\def\xintKeep:f:csv {\romannumeral0\xintkeep:f:csv }% +\long\def\xintkeep:f:csv #1#2% +{% + \expandafter\xint_stop_aftergobble + \romannumeral0\expandafter\XINT_keep:f:csv_a + \the\numexpr #1\expandafter.\expandafter{\romannumeral`&&@#2}% +}% +\def\XINT_keep:f:csv_a #1% +{% + \xint_UDzerominusfork + #1-\XINT_keep:f:csv_keepnone + 0#1\XINT_keep:f:csv_neg + 0-{\XINT_keep:f:csv_pos #1}% + \krof +}% +\long\def\XINT_keep:f:csv_keepnone .#1{,}% +\long\def\XINT_keep:f:csv_neg #1.#2% +{% + \expandafter\XINT_keep:f:csv_neg_done\expandafter,% + \romannumeral0% + \expandafter\XINT_keep:f:csv_neg_a\the\numexpr + #1-\numexpr\XINT_length:f:csv_a + #2\xint:,\xint:,\xint:,\xint:,% + \xint:,\xint:,\xint:,\xint:,\xint:,% + \xint_c_ix,\xint_c_viii,\xint_c_vii,\xint_c_vi,% + \xint_c_v,\xint_c_iv,\xint_c_iii,\xint_c_ii,\xint_c_i,\xint_bye + .#2\xint_bye +}% +\def\XINT_keep:f:csv_neg_a #1% +{% + \xint_UDsignfork + #1{\expandafter\XINT_keep:f:csv_trimloop\the\numexpr-\xint_c_ix+}% + -\XINT_keep:f:csv_keepall + \krof +}% +\def\XINT_keep:f:csv_keepall #1.{ }% +\long\def\XINT_keep:f:csv_neg_done #1\xint_bye{#1}% +\def\XINT_keep:f:csv_trimloop #1#2.% +{% + \xint_gob_til_minus#1\XINT_keep:f:csv_trimloop_finish-% + \expandafter\XINT_keep:f:csv_trimloop + \the\numexpr#1#2-\xint_c_ix\expandafter.\XINT_keep:f:csv_trimloop_trimnine +}% +\long\def\XINT_keep:f:csv_trimloop_trimnine #1,#2,#3,#4,#5,#6,#7,#8,#9,{}% +\def\XINT_keep:f:csv_trimloop_finish-% + \expandafter\XINT_keep:f:csv_trimloop + \the\numexpr-#1-\xint_c_ix\expandafter.\XINT_keep:f:csv_trimloop_trimnine + {\csname XINT_trim:f:csv_finish#1\endcsname}% +\long\def\XINT_keep:f:csv_pos #1.#2% +{% + \expandafter\XINT_keep:f:csv_pos_fork + \romannumeral0\XINT_lengthupto:f:csv_a + #1.#2\xint:,\xint:,\xint:,\xint:,% + \xint:,\xint:,\xint:,\xint:,% + \xint_c_viii,\xint_c_vii,\xint_c_vi,\xint_c_v,% + \xint_c_iv,\xint_c_iii,\xint_c_ii,\xint_c_i,\xint_bye.% + .#1.{}#2\xint_bye% +}% +\def\XINT_keep:f:csv_pos_fork #1#2.% +{% + \xint_UDsignfork + #1{\expandafter\XINT_keep:f:csv_loop\the\numexpr-\xint_c_viii+}% + -\XINT_keep:f:csv_pos_keepall + \krof +}% +\long\def\XINT_keep:f:csv_pos_keepall #1.#2#3\xint_bye{,#3}% +\def\XINT_keep:f:csv_loop #1#2.% +{% + \xint_gob_til_minus#1\XINT_keep:f:csv_loop_end-% + \expandafter\XINT_keep:f:csv_loop + \the\numexpr#1#2-\xint_c_viii\expandafter.\XINT_keep:f:csv_loop_pickeight +}% +\long\def\XINT_keep:f:csv_loop_pickeight + #1#2,#3,#4,#5,#6,#7,#8,#9,{{#1,#2,#3,#4,#5,#6,#7,#8,#9}}% +\def\XINT_keep:f:csv_loop_end-\expandafter\XINT_keep:f:csv_loop + \the\numexpr-#1-\xint_c_viii\expandafter.\XINT_keep:f:csv_loop_pickeight + {\csname XINT_keep:f:csv_end#1\endcsname}% +\long\expandafter\def\csname XINT_keep:f:csv_end1\endcsname + #1#2,#3,#4,#5,#6,#7,#8,#9\xint_bye {#1,#2,#3,#4,#5,#6,#7,#8}% +\long\expandafter\def\csname XINT_keep:f:csv_end2\endcsname + #1#2,#3,#4,#5,#6,#7,#8\xint_bye {#1,#2,#3,#4,#5,#6,#7}% +\long\expandafter\def\csname XINT_keep:f:csv_end3\endcsname + #1#2,#3,#4,#5,#6,#7\xint_bye {#1,#2,#3,#4,#5,#6}% +\long\expandafter\def\csname XINT_keep:f:csv_end4\endcsname + #1#2,#3,#4,#5,#6\xint_bye {#1,#2,#3,#4,#5}% +\long\expandafter\def\csname XINT_keep:f:csv_end5\endcsname + #1#2,#3,#4,#5\xint_bye {#1,#2,#3,#4}% +\long\expandafter\def\csname XINT_keep:f:csv_end6\endcsname + #1#2,#3,#4\xint_bye {#1,#2,#3}% +\long\expandafter\def\csname XINT_keep:f:csv_end7\endcsname + #1#2,#3\xint_bye {#1,#2}% +\long\expandafter\def\csname XINT_keep:f:csv_end8\endcsname + #1#2\xint_bye {#1}% +% \end{macrocode} +%\subsubsection{\csh{xintTrim:f:csv}} +% \lverb|1.2g 2016/03/17. Redone for 1.2j 2016/12/20 on the basis of new +% \xintTrim.| +% \begin{macrocode} +\def\xintTrim:f:csv {\romannumeral0\xinttrim:f:csv }% +\long\def\xinttrim:f:csv #1#2% +{% + \expandafter\xint_stop_aftergobble + \romannumeral0\expandafter\XINT_trim:f:csv_a + \the\numexpr #1\expandafter.\expandafter{\romannumeral`&&@#2}% +}% +\def\XINT_trim:f:csv_a #1% +{% + \xint_UDzerominusfork + #1-\XINT_trim:f:csv_trimnone + 0#1\XINT_trim:f:csv_neg + 0-{\XINT_trim:f:csv_pos #1}% + \krof +}% +\long\def\XINT_trim:f:csv_trimnone .#1{,#1}% +\long\def\XINT_trim:f:csv_neg #1.#2% +{% + \expandafter\XINT_trim:f:csv_neg_a\the\numexpr + #1-\numexpr\XINT_length:f:csv_a + #2\xint:,\xint:,\xint:,\xint:,% + \xint:,\xint:,\xint:,\xint:,\xint:,% + \xint_c_ix,\xint_c_viii,\xint_c_vii,\xint_c_vi,% + \xint_c_v,\xint_c_iv,\xint_c_iii,\xint_c_ii,\xint_c_i,\xint_bye + .{}#2\xint_bye +}% +\def\XINT_trim:f:csv_neg_a #1% +{% + \xint_UDsignfork + #1{\expandafter\XINT_keep:f:csv_loop\the\numexpr-\xint_c_viii+}% + -\XINT_trim:f:csv_trimall + \krof +}% +\def\XINT_trim:f:csv_trimall {\expandafter,\xint_bye}% +\long\def\XINT_trim:f:csv_pos #1.#2% +{% + \expandafter\XINT_trim:f:csv_pos_done\expandafter,% + \romannumeral0% + \expandafter\XINT_trim:f:csv_loop\the\numexpr#1-\xint_c_ix.% + #2\xint:,\xint:,\xint:,\xint:,\xint:,% + \xint:,\xint:,\xint:,\xint:,\xint:\xint_bye +}% +\def\XINT_trim:f:csv_loop #1#2.% +{% + \xint_gob_til_minus#1\XINT_trim:f:csv_finish-% + \expandafter\XINT_trim:f:csv_loop\the\numexpr#1#2\XINT_trim:f:csv_loop_trimnine +}% +\long\def\XINT_trim:f:csv_loop_trimnine #1,#2,#3,#4,#5,#6,#7,#8,#9,% +{% + \xint_gob_til_xint: #9\XINT_trim:f:csv_toofew\xint:-\xint_c_ix.% +}% +\def\XINT_trim:f:csv_toofew\xint:{*\xint_c_}% +\def\XINT_trim:f:csv_finish-% + \expandafter\XINT_trim:f:csv_loop\the\numexpr-#1\XINT_trim:f:csv_loop_trimnine +{% + \csname XINT_trim:f:csv_finish#1\endcsname +}% +\long\expandafter\def\csname XINT_trim:f:csv_finish1\endcsname + #1,#2,#3,#4,#5,#6,#7,#8,{ }% +\long\expandafter\def\csname XINT_trim:f:csv_finish2\endcsname + #1,#2,#3,#4,#5,#6,#7,{ }% +\long\expandafter\def\csname XINT_trim:f:csv_finish3\endcsname + #1,#2,#3,#4,#5,#6,{ }% +\long\expandafter\def\csname XINT_trim:f:csv_finish4\endcsname + #1,#2,#3,#4,#5,{ }% +\long\expandafter\def\csname XINT_trim:f:csv_finish5\endcsname + #1,#2,#3,#4,{ }% +\long\expandafter\def\csname XINT_trim:f:csv_finish6\endcsname + #1,#2,#3,{ }% +\long\expandafter\def\csname XINT_trim:f:csv_finish7\endcsname + #1,#2,{ }% +\long\expandafter\def\csname XINT_trim:f:csv_finish8\endcsname + #1,{ }% +\expandafter\let\csname XINT_trim:f:csv_finish9\endcsname\space +\long\def\XINT_trim:f:csv_pos_done #1\xint:#2\xint_bye{#1}% +% \end{macrocode} +% \subsubsection{\csh{xintNthEltPy:f:csv}} +% \lverb|Counts like Python starting at zero. Last refactored with 1.2j. +% Attention, makes currently no effort at removing leading spaces in the +% picked item.| +% \begin{macrocode} +\def\xintNthEltPy:f:csv {\romannumeral0\xintntheltpy:f:csv }% +\long\def\xintntheltpy:f:csv #1#2% +{% + \expandafter\XINT_nthelt:f:csv_a + \the\numexpr #1\expandafter.\expandafter{\romannumeral`&&@#2}% +}% +\def\XINT_nthelt:f:csv_a #1% +{% + \xint_UDsignfork + #1\XINT_nthelt:f:csv_neg + -\XINT_nthelt:f:csv_pos + \krof #1% +}% +\long\def\XINT_nthelt:f:csv_neg -#1.#2% +{% + \expandafter\XINT_nthelt:f:csv_neg_fork + \the\numexpr\XINT_length:f:csv_a + #2\xint:,\xint:,\xint:,\xint:,% + \xint:,\xint:,\xint:,\xint:,\xint:,% + \xint_c_ix,\xint_c_viii,\xint_c_vii,\xint_c_vi,% + \xint_c_v,\xint_c_iv,\xint_c_iii,\xint_c_ii,\xint_c_i,\xint_bye + -#1.#2,\xint_bye +}% +\def\XINT_nthelt:f:csv_neg_fork #1% +{% + \if#1-\expandafter\xint_stop_afterbye\fi + \expandafter\XINT_nthelt:f:csv_neg_done + \romannumeral0% + \expandafter\XINT_keep:f:csv_trimloop\the\numexpr-\xint_c_ix+#1% +}% +\long\def\XINT_nthelt:f:csv_neg_done#1,#2\xint_bye{ #1}% +\long\def\XINT_nthelt:f:csv_pos #1.#2% +{% + \expandafter\XINT_nthelt:f:csv_pos_done + \romannumeral0% + \expandafter\XINT_trim:f:csv_loop\the\numexpr#1-\xint_c_ix.% + #2\xint:,\xint:,\xint:,\xint:,\xint:,% + \xint:,\xint:,\xint:,\xint:,\xint:,\xint_bye +}% +\def\XINT_nthelt:f:csv_pos_done #1{% +\long\def\XINT_nthelt:f:csv_pos_done ##1,##2\xint_bye{% + \xint_gob_til_xint:##1\XINT_nthelt:f:csv_pos_cleanup\xint:#1##1}% +}\XINT_nthelt:f:csv_pos_done{ }% +% \end{macrocode} +% \lverb|This strange thing is in case the picked item was the last one, hence +% there was an ending \xint: (we could not put a comma earlier for +% matters of not confusing empty list with a singleton list), and we do this +% here to activate brace-stripping of item as all other items may be +% brace-stripped if picked. This is done for coherence. Of course, in the +% context of the xintexpr.sty parsers, there are no braces in list items...| +% \begin{macrocode} +\xint_firstofone{\long\def\XINT_nthelt:f:csv_pos_cleanup\xint:} % + #1\xint:{ #1}% +% \end{macrocode} +% \subsubsection{\csh{xintReverse:f:csv}} +% \lverb|1.2g. Contrarily to \xintReverseOrder from xintkernel.sty, this +% one expands its argument. Handles empty list too. 2016/03/17. +% Made \long for 1.2j.| +% \begin{macrocode} +\def\xintReverse:f:csv {\romannumeral0\xintreverse:f:csv }% +\long\def\xintreverse:f:csv #1% +{% + \expandafter\XINT_reverse:f:csv_loop + \expandafter{\expandafter}\romannumeral`&&@#1,% + \xint:,% + \xint_bye,\xint_bye,\xint_bye,\xint_bye,% + \xint_bye,\xint_bye,\xint_bye,\xint_bye,% + \xint: +}% +\long\def\XINT_reverse:f:csv_loop #1#2,#3,#4,#5,#6,#7,#8,#9,% +{% + \xint_bye #9\XINT_reverse:f:csv_cleanup\xint_bye + \XINT_reverse:f:csv_loop {,#9,#8,#7,#6,#5,#4,#3,#2#1}% +}% +\long\def\XINT_reverse:f:csv_cleanup\xint_bye\XINT_reverse:f:csv_loop #1#2\xint: +{% + \XINT_reverse:f:csv_finish #1% +}% +\long\def\XINT_reverse:f:csv_finish #1\xint:,{ }% +% \end{macrocode} +% \subsubsection{\csh{xintFirstItem:f:csv}} +% \lverb|Added with 1.2k for use by first() in +% \xintexpr-essions, and some amount of compatibility with \xintNewExpr.| +% \begin{macrocode} +\def\xintFirstItem:f:csv {\romannumeral0\xintfirstitem:f:csv}% +\long\def\xintfirstitem:f:csv #1% +{% + \expandafter\XINT_first:f:csv_a\romannumeral`&&@#1,\xint_bye +}% +\long\def\XINT_first:f:csv_a #1,#2\xint_bye{ #1}% +% \end{macrocode} +% \subsubsection{\csh{xintLastItem:f:csv}} +% \lverb|Added with 1.2k, based on and sharing code with xintkernel's +% \xintLastItem from 1.2i. Output empty if input empty. f-expands its argument +% (hence first item, if not protected.) For use by last() in +% \xintexpr-essions with to some extent \xintNewExpr compatibility.| +% \begin{macrocode} +\def\xintLastItem:f:csv {\romannumeral0\xintlastitem:f:csv}% +\long\def\xintlastitem:f:csv #1% +{% + \expandafter\XINT_last:f:csv_loop\expandafter{\expandafter}\expandafter.% + \romannumeral`&&@#1,% + \xint:\XINT_last_loop_enda,\xint:\XINT_last_loop_endb,% + \xint:\XINT_last_loop_endc,\xint:\XINT_last_loop_endd,% + \xint:\XINT_last_loop_ende,\xint:\XINT_last_loop_endf,% + \xint:\XINT_last_loop_endg,\xint:\XINT_last_loop_endh,\xint_bye +}% +\long\def\XINT_last:f:csv_loop #1.#2,#3,#4,#5,#6,#7,#8,#9,% +{% + \xint_gob_til_xint: #9% + {#8}{#7}{#6}{#5}{#4}{#3}{#2}{#1}\xint: + \XINT_last:f:csv_loop {#9}.% +}% +% \end{macrocode} +% \subsubsection{Public names for the undocumented csv macros: +% \csh{xintCSVLength}, \csh{xintCSVKeep}, \csh{xintCSVTrim}, +% \csh{xintCSVNthEltPy}, \csh{xintCSVReverse}, +% \csh{xintCSVFirstItem}, \csh{xintCSVLastItem}} +% +% \lverb|Completely unstable macros: currently they expand the list argument +% and want no final comma. But for matters of xintexpr.sty I could as well +% decide to require a final comma, and then I could simplify implementation +% but of course this would break the macros if used with current +% functionalities.| +% \begin{macrocode} +\let\xintCSVLength \xintLength:f:csv +\let\xintCSVKeep \xintKeep:f:csv +\let\xintCSVTrim \xintTrim:f:csv +\let\xintCSVNthEltPy \xintNthEltPy:f:csv +\let\xintCSVReverse \xintReverse:f:csv +\let\xintCSVFirstItem\xintFirstItem:f:csv +\let\xintCSVLastItem \xintLastItem:f:csv +\let\XINT_tmpa\relax \let\XINT_tmpb\relax \let\XINT_tmpc\relax +\XINT_restorecatcodes_endinput% +% \end{macrocode} +% \StoreCodelineNo {xinttools} +% \cleardoublepage\let\xinttoolsnameUp\undefined +%\gardesactifs +%\let</xinttools>\relax +%\let<*xintcore>\gardesinactifs +%</xinttools>^^A-------------------------------------------------- +%<*xintcore>^^A--------------------------------------------------- +%^^A -*- coding: utf-8; mode: doctex; fill-column: 78; -*- +% \clearpage\csname xintcorenameUp\endcsname +% \section{Package \xintcorenameimp implementation} +% \RaisedLabel{sec:coreimp} +% +% \localtableofcontents +% +% Got split off from \xintnameimp with release |1.1|. +% +% The core arithmetic routines have been entirely rewritten for release +% |1.2|. The |1.2i| and |1.2l| brought again some improvements. +% +% The commenting continues (\xintdocdate) to be very sparse: actually it got +% worse than ever with release |1.2|. I will possibly add comments at a +% later date, but for the time being the new routines are not commented at +% all. +% +% |1.3| removes all macros which were deprecated at |1.2o|. +% +% \subsection{Catcodes, \protect\eTeX{} and reload detection} +% +% The code for reload detection was initially copied from \textsc{Heiko +% Oberdiek}'s packages, then modified. +% +% The method for catcodes was also initially directly inspired by these +% packages. +% +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode64=11 % @ + \catcode35=6 % # + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \let\z\endgroup + \expandafter\let\expandafter\x\csname ver@xintcore.sty\endcsname + \expandafter\let\expandafter\w\csname ver@xintkernel.sty\endcsname + \expandafter + \ifx\csname PackageInfo\endcsname\relax + \def\y#1#2{\immediate\write-1{Package #1 Info: #2.}}% + \else + \def\y#1#2{\PackageInfo{#1}{#2}}% + \fi + \expandafter + \ifx\csname numexpr\endcsname\relax + \y{xintcore}{\numexpr not available, aborting input}% + \aftergroup\endinput + \else + \ifx\x\relax % plain-TeX, first loading of xintcore.sty + \ifx\w\relax % but xintkernel.sty not yet loaded. + \def\z{\endgroup\input xintkernel.sty\relax}% + \fi + \else + \def\empty {}% + \ifx\x\empty % LaTeX, first loading, + % variable is initialized, but \ProvidesPackage not yet seen + \ifx\w\relax % xintkernel.sty not yet loaded. + \def\z{\endgroup\RequirePackage{xintkernel}}% + \fi + \else + \aftergroup\endinput % xintkernel already loaded. + \fi + \fi + \fi +\z% +\XINTsetupcatcodes% defined in xintkernel.sty +% \end{macrocode} +% \subsection{Package identification} +% \begin{macrocode} +\XINT_providespackage +\ProvidesPackage{xintcore}% + [2019/04/05 1.3e Expandable arithmetic on big integers (JFB)]% +% \end{macrocode} +% \subsection{(WIP!) Error conditions and exceptions} +% \lverb|As per the Mike Cowlishaw/IBM's General Decimal Arithmetic Specification +% +% http://speleotrove.com/decimal/decarith.html +% +% and the Python3 implementation in its Decimal module. +% +% Clamped, ConversionSyntax, DivisionByZero, DivisionImpossible, +% DivisionUndefined, Inexact, InsufficientStorage, InvalidContext, +% InvalidOperation, Overflow, Inexact, Rounded, Subnormal, +% Underflow. +% +% X3.274 rajoute LostDigits +% +% Python rajoute FloatOperation (et n'inclut pas InsufficientStorage) +% +% quote de decarith.pdf: +% The Clamped, Inexact, Rounded, and Subnormal conditions can coincide with +% each other or with other conditions. In these cases then any trap enabled +% for another condition takes precedence over (is handled before) all of +% these, any Subnormal trap takes precedence over Inexact, any Inexact trap +% takes precedence over Rounded, and any Rounded trap takes precedence over +% Clamped. +% +% WORK IN PROGRESS ! (1.2l, 2017/07/26) +% +% I follow the Python terminology: a trapped signal means it raises an +% exception which for us means an expandable error message with some possible +% user interaction. In this WIP +% state, the interaction is commented out. A non-trapped signal or condition +% would activate a (presumably silent) handler. +% +% Here, no signal-raising condition is "ignored" and all are "trapped" which +% means that error handlers are never activated, thus left in garbage state in +% the code. +% +% Various conditions can raise the same signal. +% +% Only signals, not conditions, raise Flags. +% +% If a signal is ignored it does not raise a Flag, but it activates the signal +% handler (by default now no signal is ignored.) +% +% If a signal is not ignored it raises a Flag and then if it is not trapped it +% activates the handler of the _condition_. +% +% If trapped (which is default now) an «exception» is raised, which means an +% expandable error message (I copied over the LaTeX3 code for expandable error +% messages, basically) +% interrupts the TeX run. In future, user input could +% be solicited, but currently this is commented out. +% +% For now macros to reset flags are done but without public interface nor +% documentation. +% +% Only four conditions are currently possibly encountered: +%- InvalidOperation +%- DivisionByZero +%- DivisionUndefined (which signals InvalidOperation) +%- Underflow +% +% I did it quickly, anyhow this will become more palpable when some of the +% Decimal Specification is actually implemented. The plan is to first do the +% X3.274 norm, then more complete implementation will follow... perhaps... +% | +% \begin{macrocode} +\csname XINT_Clamped_istrapped\endcsname +\csname XINT_ConversionSyntax_istrapped\endcsname +\csname XINT_DivisionByZero_istrapped\endcsname +\csname XINT_DivisionImpossible_istrapped\endcsname +\csname XINT_DivisionUndefined_istrapped\endcsname +\csname XINT_InvalidOperation_istrapped\endcsname +\csname XINT_Overflow_istrapped\endcsname +\csname XINT_Underflow_istrapped\endcsname +\catcode`- 11 +\def\XINT_ConversionSyntax-signal {{InvalidOperation}}% +\let\XINT_DivisionImpossible-signal\XINT_ConversionSyntax-signal +\let\XINT_DivisionUndefined-signal \XINT_ConversionSyntax-signal +\let\XINT_InvalidContext-signal \XINT_ConversionSyntax-signal +\catcode`- 12 +\def\XINT_signalcondition #1{\expandafter\XINT_signalcondition_a + \romannumeral0\ifcsname XINT_#1-signal\endcsname + \xint_dothis{\csname XINT_#1-signal\endcsname}% + \fi\xint_orthat{{#1}}{#1}}% +\def\XINT_signalcondition_a #1#2#3#4#5{% copied over from Python Decimal module +% #1=signal, #2=condition, #3=explanation for user, +% #4=context for error handlers, #5=used + \ifcsname XINT_#1_isignoredflag\endcsname + \xint_dothis{\csname XINT_#1.handler\endcsname {#4}}% + \fi + \expandafter\xint_gobble_i\csname XINT_#1Flag_ON\endcsname + \unless\ifcsname XINT_#1_istrapped\endcsname + \xint_dothis{\csname XINT_#2.handler\endcsname {#4}}% + \fi + \xint_orthat{% + % the flag raised is named after the signal #1, but we show condition #2 + \XINT_expandableerror{#2 (hit <RET> thrice)}% + \XINT_expandableerror{#3}% + \XINT_expandableerror{next: #5}% + % not for X3.274 + %\XINT_expandableerror{<RET>, or I\xintUse{...}<RET>, or I\xintCTRLC<RET>}% + \xint_stop_atfirstofone{#5}% + }% +}% +%% \let\xintUse\xint_stop_atfirstofthree % defined in xint.sty +\def\XINT_ifFlagRaised #1{% + \ifcsname XINT_#1Flag_ON\endcsname + \expandafter\xint_firstoftwo + \else + \expandafter\xint_secondoftwo + \fi}% +\def\XINT_resetFlag #1% + {\expandafter\let\csname XINT_#1Flag_ON\endcsname\XINT_undefined}% +\def\XINT_resetFlags {% WIP + \XINT_resetFlag{InvalidOperation}% also from DivisionUndefined + \XINT_resetFlag{DivisionByZero}% + \XINT_resetFlag{Underflow}% (\xintiiPow with negative exponent) + \XINT_resetFlag{Overflow}% not encountered so far in xint code 1.2l + % .. others .. +}% +\def\XINT_RaiseFlag #1{\expandafter\xint_gobble_i\csname XINT_#1Flag_ON\endcsname}% +% \end{macrocode} +% NOT IMPLEMENTED! WORK IN PROGRESS! (ALL SIGNALS TRAPPED, NO HANDLERS USED) +% \begin{macrocode} +\catcode`. 11 +\let\XINT_Clamped.handler\xint_firstofone % WIP +\def\XINT_InvalidOperation.handler#1{_NaN}% WIP +\def\XINT_ConversionSyntax.handler#1{_NaN}% WIP +\def\XINT_DivisionByZero.handler#1{_SignedInfinity(#1)}% WIP +\def\XINT_DivisionImpossible.handler#1{_NaN}% WIP +\def\XINT_DivisionUndefined.handler#1{_NaN}% WIP +\let\XINT_Inexact.handler\xint_firstofone % WIP +\def\XINT_InvalidContext.handler#1{_NaN}% WIP +\let\XINT_Rounded.handler\xint_firstofone % WIP +\let\XINT_Subnormal.handler\xint_firstofone% WIP +\def\XINT_Overflow.handler#1{_NaN}% WIP +\def\XINT_Underflow.handler#1{_NaN}% WIP +\catcode`. 12 +% \end{macrocode} +% \subsection{Counts for holding needed constants} +% \begin{macrocode} +\ifdefined\m@ne\let\xint_c_mone\m@ne + \else\csname newcount\endcsname\xint_c_mone \xint_c_mone -1 \fi +\ifdefined\xint_c_x^viii\else +\csname newcount\endcsname\xint_c_x^viii \xint_c_x^viii 100000000 +\fi +\ifdefined\xint_c_x^ix\else +\csname newcount\endcsname\xint_c_x^ix \xint_c_x^ix 1000000000 +\fi +\newcount\xint_c_x^viii_mone \xint_c_x^viii_mone 99999999 +\newcount\xint_c_xii_e_viii \xint_c_xii_e_viii 1200000000 +\newcount\xint_c_xi_e_viii_mone \xint_c_xi_e_viii_mone 1099999999 +% \end{macrocode} +% \subsection*{Routines handling integers as lists of token digits} +% \addcontentsline{toc}{subsection}{Routines handling integers as lists of token digits} +% \lverb|& +% Routines handling big integers which are lists of digit tokens with no +% special additional structure. +% +% Some +% routines do not accept non properly terminated inputs like "\the\numexpr1", +% or "\the\mathcode`\-", others do. +% +% These routines or their sub-routines are mainly for internal usage. +% | +% +% \subsection{\csh{XINT_cuz_small}} +% \lverb|& +% \XINT_cuz_small removes leading zeroes from the first eight digits. Expands +% following \romannumeral0. At least one digit is produced.| +% \begin{macrocode} +\def\XINT_cuz_small#1{% +\def\XINT_cuz_small ##1##2##3##4##5##6##7##8% +{% + \expandafter#1\the\numexpr ##1##2##3##4##5##6##7##8\relax +}}\XINT_cuz_small{ }% +% \end{macrocode} +% \subsection{\csh{xintNum}, \csh{xintiNum}} +% \lverb|& +% For example \xintNum {----+-+++---+----000000000000003} +% +% Very old routine got completely rewritten at 1.2l. +% +% New code uses \numexpr governed expansion and fixes some issues of former +% version particularly regarding inputs of the \numexpr...\relax type without +% \the or \number prefix, and/or possibly no terminating \relax. +% +% \xintiNum{\numexpr 1}\foo in earlier versions caused premature expansion of +% \foo. +% +% \xintiNum{\the\numexpr 1} was ok, but a bit luckily so. +% +% Also, up to 1.2k inclusive, the macro fetched tokens eight by eight, and not +% nine by nine as is done now. I have no idea why. +% +% \xintNum gets redefined by $xintfracnameimp. +% | +% \begin{macrocode} +\def\xintiNum {\romannumeral0\xintinum }% +\def\xintinum #1% +{% + \expandafter\XINT_num_cleanup\the\numexpr\expandafter\XINT_num_loop + \romannumeral`&&@#1\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z +}% +\def\xintNum {\romannumeral0\xintnum }% +\let\xintnum\xintinum +\def\XINT_num #1% +{% + \expandafter\XINT_num_cleanup\the\numexpr\XINT_num_loop + #1\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z +}% +\def\XINT_num_loop #1#2#3#4#5#6#7#8#9% +{% + \xint_gob_til_xint: #9\XINT_num_end\xint: + #1#2#3#4#5#6#7#8#9% + \ifnum \numexpr #1#2#3#4#5#6#7#8#9+\xint_c_ = \xint_c_ +% \end{macrocode} +% \lverb|& +% means that so far only signs encountered, (if syntax is legal) then possibly +% zeroes +% or a terminated or not terminated \numexpr evaluating to zero +% In that latter case a correct zero will be produced in the end. +% | +% \begin{macrocode} + \expandafter\XINT_num_loop + \else +% \end{macrocode} +% \lverb|& +% non terminated \numexpr (with nine tokens total) are +% safe as after \fi, there is then \xint: +% | +% \begin{macrocode} + \expandafter\relax + \fi +}% +\def\XINT_num_end\xint:#1\xint:{#1+\xint_c_\xint:}% empty input ok +\def\XINT_num_cleanup #1\xint:#2\Z { #1}% +% \end{macrocode} +% \subsection{\csh{xintiiSgn}} +% \lverb|& +% 1.2l made \xintiiSgn robust against non terminated input. +% +% 1.2o deprecates here \xintSgn (it requires xintfrac.sty). +% | +% \begin{macrocode} +\def\xintiiSgn {\romannumeral0\xintiisgn }% +\def\xintiisgn #1% +{% + \expandafter\XINT_sgn \romannumeral`&&@#1\xint: +}% +\def\XINT_sgn #1#2\xint: +{% + \xint_UDzerominusfork + #1-{ 0}% + 0#1{-1}% + 0-{ 1}% + \krof +}% +\def\XINT_Sgn #1#2\xint: +{% + \xint_UDzerominusfork + #1-{0}% + 0#1{-1}% + 0-{1}% + \krof +}% +\def\XINT_cntSgn #1#2\xint: +{% + \xint_UDzerominusfork + #1-\xint_c_ + 0#1\xint_c_mone + 0-\xint_c_i + \krof +}% +% \end{macrocode} +% \subsection{\csh{xintiiOpp}} +% \lverb|Attention, \xintiiOpp non robust against non terminated inputs. +% Reason is I don't want to have to grab a delimiter at the end, as everything +% happens "upfront".| +% \begin{macrocode} +\def\xintiiOpp {\romannumeral0\xintiiopp }% +\def\xintiiopp #1% +{% + \expandafter\XINT_opp \romannumeral`&&@#1% +}% +\def\XINT_Opp #1{\romannumeral0\XINT_opp #1}% +\def\XINT_opp #1% +{% + \xint_UDzerominusfork + #1-{ 0}% zero + 0#1{ }% negative + 0-{ -#1}% positive + \krof +}% +% \end{macrocode} +% \subsection{\csh{xintiiAbs}} +% \lverb|& +% Attention \xintiiAbs non robust against non terminated input. +%| +% \begin{macrocode} +\def\xintiiAbs {\romannumeral0\xintiiabs }% +\def\xintiiabs #1% +{% + \expandafter\XINT_abs \romannumeral`&&@#1% +}% +\def\XINT_abs #1% +{% + \xint_UDsignfork + #1{ }% + -{ #1}% + \krof +}% +% \end{macrocode} +% \subsection{\csh{xintFDg}} +% \lverb|& +% FIRST DIGIT. +% +% 1.2l: \xintiiFDg made robust against non terminated input. +% +% 1.2o deprecates \xintiiFDg, gives to \xintFDg former meaning of \xintiiFDg.| +% \begin{macrocode} +\def\xintFDg {\romannumeral0\xintfdg }% +\def\xintfdg #1{\expandafter\XINT_fdg \romannumeral`&&@#1\xint:\Z}% +\def\XINT_FDg #1% + {\romannumeral0\expandafter\XINT_fdg\romannumeral`&&@\xintnum{#1}\xint:\Z }% +\def\XINT_fdg #1#2#3\Z +{% + \xint_UDzerominusfork + #1-{ 0}% zero + 0#1{ #2}% negative + 0-{ #1}% positive + \krof +}% +% \end{macrocode} +% \subsection{\csh{xintLDg}} +% \lverb|& +% LAST DIGIT. +% +% Rewritten for 1.2i (2016/12/10). Surprisingly perhaps, it is faster than +% \xintLastItem from xintkernel.sty despite the \numexpr operations. +% +% 1.2o deprecates \xintiiLDg, gives to \xintLDg former meaning of \xintiiLDg. +% +% Attention \xintLDg non robust against non terminated input. +% | +% \begin{macrocode} +\def\xintLDg {\romannumeral0\xintldg }% +\def\xintldg #1{\expandafter\XINT_ldg_fork\romannumeral`&&@#1% + \XINT_ldg_c{}{}{}{}{}{}{}{}\xint_bye\relax}% +\def\XINT_ldg_fork #1% +{% + \xint_UDsignfork + #1\XINT_ldg + -{\XINT_ldg#1}% + \krof +}% +\def\XINT_ldg #1{% +\def\XINT_ldg ##1##2##3##4##5##6##7##8##9% + {\expandafter#1% + \the\numexpr##9##8##7##6##5##4##3##2##1*\xint_c_+\XINT_ldg_a##9}% +}\XINT_ldg{ }% +\def\XINT_ldg_a#1#2{\XINT_ldg_cbye#2\XINT_ldg_d#1\XINT_ldg_c\XINT_ldg_b#2}% +\def\XINT_ldg_b#1#2#3#4#5#6#7#8#9{#9#8#7#6#5#4#3#2#1*\xint_c_+\XINT_ldg_a#9}% +\def\XINT_ldg_c #1#2\xint_bye{#1}% +\def\XINT_ldg_cbye #1\XINT_ldg_c{}% +\def\XINT_ldg_d#1#2\xint_bye{#1}% +% \end{macrocode} +% +% \subsection{\csh{xintDouble}} +% \lverb|Attention \xintDouble non robust against non terminated input.| +% \begin{macrocode} +\def\xintDouble {\romannumeral0\xintdouble}% +\def\xintdouble #1{\expandafter\XINT_dbl_fork\romannumeral`&&@#1% + \xint_bye2345678\xint_bye*\xint_c_ii\relax}% +\def\XINT_dbl_fork #1% +{% + \xint_UDsignfork + #1\XINT_dbl_neg + -\XINT_dbl + \krof #1% +}% +\def\XINT_dbl_neg-{\expandafter-\romannumeral0\XINT_dbl}% +\def\XINT_dbl #1{% +\def\XINT_dbl ##1##2##3##4##5##6##7##8% + {\expandafter#1\the\numexpr##1##2##3##4##5##6##7##8\XINT_dbl_a}% +}\XINT_dbl{ }% +\def\XINT_dbl_a #1#2#3#4#5#6#7#8% + {\expandafter\XINT_dbl_e\the\numexpr 1#1#2#3#4#5#6#7#8\XINT_dbl_a}% +\def\XINT_dbl_e#1{*\xint_c_ii\if#13+\xint_c_i\fi\relax}% +% \end{macrocode} +% \subsection{\csh{xintHalf}} +% \lverb|Attention \xintHalf non robust against non terminated input.| +% \begin{macrocode} +\def\xintHalf {\romannumeral0\xinthalf}% +\def\xinthalf #1{\expandafter\XINT_half_fork\romannumeral`&&@#1% + \xint_bye\xint_Bye345678\xint_bye + *\xint_c_v+\xint_c_v)/\xint_c_x-\xint_c_i\relax}% +\def\XINT_half_fork #1% +{% + \xint_UDsignfork + #1\XINT_half_neg + -\XINT_half + \krof #1% +}% +\def\XINT_half_neg-{\xintiiopp\XINT_half}% +\def\XINT_half #1{% +\def\XINT_half ##1##2##3##4##5##6##7##8% + {\expandafter#1\the\numexpr(##1##2##3##4##5##6##7##8\XINT_half_a}% +}\XINT_half{ }% +\def\XINT_half_a#1{\xint_Bye#1\xint_bye\XINT_half_b#1}% +\def\XINT_half_b #1#2#3#4#5#6#7#8% + {\expandafter\XINT_half_e\the\numexpr(1#1#2#3#4#5#6#7#8\XINT_half_a}% +\def\XINT_half_e#1{*\xint_c_v+#1-\xint_c_v)\relax}% +% \end{macrocode} +% \subsection{\csh{xintInc}} +% \lverb|1.2i much delayed complete rewrite in 1.2 style. +% +% As we take 9 by 9 with the input save stack at 5000 this allows a bit less +% than 9 times 2500 = 22500 digits on input. +% +% Attention \xintInc non robust against non terminated input.| +% \begin{macrocode} +\def\xintInc {\romannumeral0\xintinc}% +\def\xintinc #1{\expandafter\XINT_inc_fork\romannumeral`&&@#1% + \xint_bye23456789\xint_bye+\xint_c_i\relax}% +\def\XINT_inc_fork #1% +{% + \xint_UDsignfork + #1\XINT_inc_neg + -\XINT_inc + \krof #1% +}% +\def\XINT_inc_neg-#1\xint_bye#2\relax + {\xintiiopp\XINT_dec #1\XINT_dec_bye234567890\xint_bye}% +\def\XINT_inc #1{% +\def\XINT_inc ##1##2##3##4##5##6##7##8##9% + {\expandafter#1\the\numexpr##1##2##3##4##5##6##7##8##9\XINT_inc_a}% +}\XINT_inc{ }% +\def\XINT_inc_a #1#2#3#4#5#6#7#8#9% + {\expandafter\XINT_inc_e\the\numexpr 1#1#2#3#4#5#6#7#8#9\XINT_inc_a}% +\def\XINT_inc_e#1{\if#12+\xint_c_i\fi\relax}% +% \end{macrocode} +% \subsection{\csh{xintDec}} +% \lverb|1.2i much delayed complete rewrite in the 1.2 style. Things are a +% bit more complicated than \xintInc because 2999999999 is too big for TeX. +% +% Attention \xintDec non robust against non terminated input.| +% \begin{macrocode} +\def\xintDec {\romannumeral0\xintdec}% +\def\xintdec #1{\expandafter\XINT_dec_fork\romannumeral`&&@#1% + \XINT_dec_bye234567890\xint_bye}% +\def\XINT_dec_fork #1% +{% + \xint_UDsignfork + #1\XINT_dec_neg + -\XINT_dec + \krof #1% +}% +\def\XINT_dec_neg-#1\XINT_dec_bye#2\xint_bye + {\expandafter-% + \romannumeral0\XINT_inc #1\xint_bye23456789\xint_bye+\xint_c_i\relax}% +\def\XINT_dec #1{% +\def\XINT_dec ##1##2##3##4##5##6##7##8##9% + {\expandafter#1\the\numexpr##1##2##3##4##5##6##7##8##9\XINT_dec_a}% +}\XINT_dec{ }% +\def\XINT_dec_a #1#2#3#4#5#6#7#8#9% + {\expandafter\XINT_dec_e\the\numexpr 1#1#2#3#4#5#6#7#8#9\XINT_dec_a}% +\def\XINT_dec_bye #1\XINT_dec_a#2#3\xint_bye + {\if#20-\xint_c_ii\relax+\else-\fi\xint_c_i\relax}% +\def\XINT_dec_e#1{\unless\if#11\xint_dothis{-\xint_c_i#1}\fi\xint_orthat\relax}% +% \end{macrocode} +% \subsection{\csh{xintDSL}} +% \lverb|DECIMAL SHIFT LEFT (=MULTIPLICATION PAR 10). Rewritten for 1.2i. +% This was very old code... I never came back to it, but I should have +% rewritten it long time ago. +% +% Attention \xintDSL non robust against non terminated input.| +% \begin{macrocode} +\def\xintDSL {\romannumeral0\xintdsl }% +\def\xintdsl #1{\expandafter\XINT_dsl\romannumeral`&&@#10}% +\def\XINT_dsl#1{% +\def\XINT_dsl ##1{\xint_gob_til_zero ##1\xint_dsl_zero 0#1##1}% +}\XINT_dsl{ }% +\def\xint_dsl_zero 0 0{ }% +% \end{macrocode} +% \subsection{\csh{xintDSR}} +% \lverb|Decimal shift right, truncates towards zero. Rewritten for 1.2i. +% Limited to 22483 digits on input. +% +% Attention \xintDSR non robust against non terminated input.| +% \begin{macrocode} +\def\xintDSR{\romannumeral0\xintdsr}% +\def\xintdsr #1{\expandafter\XINT_dsr_fork\romannumeral`&&@#1% + \xint_bye\xint_Bye3456789\xint_bye+\xint_c_v)/\xint_c_x-\xint_c_i\relax}% +\def\XINT_dsr_fork #1% +{% + \xint_UDsignfork + #1\XINT_dsr_neg + -\XINT_dsr + \krof #1% +}% +\def\XINT_dsr_neg-{\xintiiopp\XINT_dsr}% +\def\XINT_dsr #1{% +\def\XINT_dsr ##1##2##3##4##5##6##7##8##9% + {\expandafter#1\the\numexpr(##1##2##3##4##5##6##7##8##9\XINT_dsr_a}% +}\XINT_dsr{ }% +\def\XINT_dsr_a#1{\xint_Bye#1\xint_bye\XINT_dsr_b#1}% +\def\XINT_dsr_b #1#2#3#4#5#6#7#8#9% + {\expandafter\XINT_dsr_e\the\numexpr(1#1#2#3#4#5#6#7#8#9\XINT_dsr_a}% +\def\XINT_dsr_e #1{)\relax}% +% \end{macrocode} +% \subsection{\csh{xintDSRr}} +% \lverb|New with 1.2i. Decimal shift right, rounds away from zero; done in +% the 1.2 spirit (with much delay, sorry). Used by \xintRound, \xintDivRound. +% +% This is about the first time I am happy that the division in \numexpr +% rounds! +% +% Attention \xintDSRr non robust against non terminated input.| +% \begin{macrocode} +\def\xintDSRr{\romannumeral0\xintdsrr}% +\def\xintdsrr #1{\expandafter\XINT_dsrr_fork\romannumeral`&&@#1% + \xint_bye\xint_Bye3456789\xint_bye/\xint_c_x\relax}% +\def\XINT_dsrr_fork #1% +{% + \xint_UDsignfork + #1\XINT_dsrr_neg + -\XINT_dsrr + \krof #1% +}% +\def\XINT_dsrr_neg-{\xintiiopp\XINT_dsrr}% +\def\XINT_dsrr #1{% +\def\XINT_dsrr ##1##2##3##4##5##6##7##8##9% + {\expandafter#1\the\numexpr##1##2##3##4##5##6##7##8##9\XINT_dsrr_a}% +}\XINT_dsrr{ }% +\def\XINT_dsrr_a#1{\xint_Bye#1\xint_bye\XINT_dsrr_b#1}% +\def\XINT_dsrr_b #1#2#3#4#5#6#7#8#9% + {\expandafter\XINT_dsrr_e\the\numexpr1#1#2#3#4#5#6#7#8#9\XINT_dsrr_a}% +\let\XINT_dsrr_e\XINT_inc_e +% \end{macrocode} +% \subsection*{Blocks of eight digits} +% \addcontentsline{toc}{subsection}{Blocks of eight digits} +% \lverb|The lingua of release 1.2.| +% +% \subsection{\csh{XINT_cuz}} +% \lverb|This (launched by \romannumeral0) iterately removes all leading +% zeroes from a sequence of 8N digits ended by \R. +% +% Rewritten for 1.2l, now uses \numexpr governed expansion and \ifnum test +% rather than delimited gobbling macros. +% +% Note 2015/11/28: with only four digits the gob_til_fourzeroes had proved +% in some old testing faster than \ifnum test. But with eight digits, the +% execution times are much closer, as I tested back then. +% | +% \begin{macrocode} +\def\XINT_cuz #1{% +\def\XINT_cuz {\expandafter#1\the\numexpr\XINT_cuz_loop}% +}\XINT_cuz{ }% +\def\XINT_cuz_loop #1#2#3#4#5#6#7#8#9% +{% + #1#2#3#4#5#6#7#8% + \xint_gob_til_R #9\XINT_cuz_hitend\R + \ifnum #1#2#3#4#5#6#7#8>\xint_c_ + \expandafter\XINT_cuz_cleantoend + \else\expandafter\XINT_cuz_loop + \fi #9% +}% +\def\XINT_cuz_hitend\R #1\R{\relax}% +\def\XINT_cuz_cleantoend #1\R{\relax #1}% +% \end{macrocode} +% \subsection{\csh{XINT_cuz_byviii}} +% \lverb|This removes eight by eight leading zeroes from a sequence of 8N digits +% ended by \R. Thus, we still have 8N digits on output. Expansion started by +% \romannumeral0 | +% \begin{macrocode} +\def\XINT_cuz_byviii #1#2#3#4#5#6#7#8#9% +{% + \xint_gob_til_R #9\XINT_cuz_byviii_e \R + \xint_gob_til_eightzeroes #1#2#3#4#5#6#7#8\XINT_cuz_byviii_z 00000000% + \XINT_cuz_byviii_done #1#2#3#4#5#6#7#8#9% +}% +\def\XINT_cuz_byviii_z 00000000\XINT_cuz_byviii_done 00000000{\XINT_cuz_byviii}% +\def\XINT_cuz_byviii_done #1\R { #1}% +\def\XINT_cuz_byviii_e\R #1\XINT_cuz_byviii_done #2\R{ #2}% +% \end{macrocode} +% \subsection{\csh{XINT_unsep_loop}} +% +% \lverb|This is used as +%( \the\numexpr0\XINT_unsep_loop (blocks of 1<8digits>!)% +%: \xint_bye!2!3!4!5!6!7!8!9!\xint_bye\xint_c_i\relax +%) +% It removes the 1's and !'s, and outputs the 8N digits with a 0 token as +% as prefix which will have to be cleaned out by caller. +% +% Actually it does not matter whether the blocks contain really 8 digits, all +% that matters is that they have 1 as first digit (and at most 9 digits after +% that to obey the TeX-\numexpr bound). +% +% Done at 1.2l for usage by other macros. The similar code in earlier releases +% was strangely in O(N^2) style, apparently to avoid some memory constraints. +% But these memory constraints related to \numexpr chaining seems to be in +% many places in xint code base. The 1.2l version is written in the 1.2i style +% of \xintInc etc... and is compatible with some 1! block without digits +% among the treated blocks, they will disappear.| +% \begin{macrocode} +\def\XINT_unsep_loop #1!#2!#3!#4!#5!#6!#7!#8!#9!% +{% + \expandafter\XINT_unsep_clean + \the\numexpr #1\expandafter\XINT_unsep_clean + \the\numexpr #2\expandafter\XINT_unsep_clean + \the\numexpr #3\expandafter\XINT_unsep_clean + \the\numexpr #4\expandafter\XINT_unsep_clean + \the\numexpr #5\expandafter\XINT_unsep_clean + \the\numexpr #6\expandafter\XINT_unsep_clean + \the\numexpr #7\expandafter\XINT_unsep_clean + \the\numexpr #8\expandafter\XINT_unsep_clean + \the\numexpr #9\XINT_unsep_loop +}% +\def\XINT_unsep_clean 1{\relax}% +% \end{macrocode} +% \subsection{\csh{XINT_unsep_cuzsmall}} +% +% \lverb|This is used as +%( \romannumeral0\XINT_unsep_cuzsmall (blocks of 1<8d>!)% +%: \xint_bye!2!3!4!5!6!7!8!9!\xint_bye\xint_c_i\relax +%) +% It removes the 1's and !'s, and removes the leading zeroes *of +% the first block*. +% +% Redone for 1.2l: the 1.2 variant was strangely in O(N^2) style.| +% \begin{macrocode} +\def\XINT_unsep_cuzsmall +{% + \expandafter\XINT_unsep_cuzsmall_x\the\numexpr0\XINT_unsep_loop +}% +\def\XINT_unsep_cuzsmall_x #1{% +\def\XINT_unsep_cuzsmall_x 0##1##2##3##4##5##6##7##8% +{% + \expandafter#1\the\numexpr ##1##2##3##4##5##6##7##8\relax +}}\XINT_unsep_cuzsmall_x{ }% +% \end{macrocode} +% \subsection{\csh{XINT_div_unsepQ}} +% +% \lverb|This is used by division to remove separators from the produced +% quotient. The quotient is produced in the correct order. The routine will +% also remove leading zeroes. An extra initial block of 8 zeroes is possible +% and thus if present must be removed. Then the next eight digits must be +% cleaned of leading zeroes. Attention that there might be a single +% block of 8 zeroes. Expansion launched by \romannumeral0. +% +% Rewritten for 1.2l in 1.2i style.| +% \begin{macrocode} +\def\XINT_div_unsepQ_delim {\xint_bye!2!3!4!5!6!7!8!9!\xint_bye\xint_c_i\relax\Z}% +\def\XINT_div_unsepQ +{% + \expandafter\XINT_div_unsepQ_x\the\numexpr0\XINT_unsep_loop +}% +\def\XINT_div_unsepQ_x #1{% +\def\XINT_div_unsepQ_x 0##1##2##3##4##5##6##7##8##9% +{% + \xint_gob_til_Z ##9\XINT_div_unsepQ_one\Z + \xint_gob_til_eightzeroes ##1##2##3##4##5##6##7##8\XINT_div_unsepQ_y 00000000% + \expandafter#1\the\numexpr ##1##2##3##4##5##6##7##8\relax ##9% +}}\XINT_div_unsepQ_x{ }% +\def\XINT_div_unsepQ_y #1{% +\def\XINT_div_unsepQ_y ##1\relax ##2##3##4##5##6##7##8##9% +{% + \expandafter#1\the\numexpr ##2##3##4##5##6##7##8##9\relax +}}\XINT_div_unsepQ_y{ }% +\def\XINT_div_unsepQ_one#1\expandafter{\expandafter}% +% \end{macrocode} +% \subsection{\csh{XINT_div_unsepR}} +% +% \lverb|This is used by division to remove separators from the produced +% remainder. The remainder is here in correct order. It must be cleaned of +% leading zeroes, possibly all the way. +% +% Also rewritten for 1.2l, the 1.2 version was O(N^2) style. +% +% Terminator \xint_bye!2!3!4!5!6!7!8!9!\xint_bye\xint_c_i\relax\R +% +% We have a need for something like \R because it is not guaranteed the thing +% is not actually zero.| +% \begin{macrocode} +\def\XINT_div_unsepR +{% + \expandafter\XINT_div_unsepR_x\the\numexpr0\XINT_unsep_loop +}% +\def\XINT_div_unsepR_x#1{% +\def\XINT_div_unsepR_x 0{\expandafter#1\the\numexpr\XINT_cuz_loop}% +}\XINT_div_unsepR_x{ }% +% \end{macrocode} +% \subsection{\csh{XINT_zeroes_forviii}} +% +% \lverb|& +%( \romannumeral0\XINT_zeroes_forviii #1\R\R\R\R\R\R\R\R{10}0000001\W +%) +% produces a string of k 0's such that k+length(#1) is smallest bigger multiple +% of eight.| +% \begin{macrocode} +\def\XINT_zeroes_forviii #1#2#3#4#5#6#7#8% +{% + \xint_gob_til_R #8\XINT_zeroes_forviii_end\R\XINT_zeroes_forviii +}% +\def\XINT_zeroes_forviii_end#1{% +\def\XINT_zeroes_forviii_end\R\XINT_zeroes_forviii ##1##2##3##4##5##6##7##8##9\W +{% + \expandafter#1\xint_gob_til_one ##2##3##4##5##6##7##8% +}}\XINT_zeroes_forviii_end{ }% +% \end{macrocode} +% \subsection{\csh{XINT_sepbyviii_Z}} +% +% \lverb|This is used as +%( \the\numexpr\XINT_sepbyviii_Z <8Ndigits>\XINT_sepbyviii_Z_end 2345678\relax +%) +% It produces 1<8d>!...1<8d>!1;! +% +% Prior to 1.2l it used \Z as terminator not the semi-colon (hence the name). +% The switch to ; was done at a time I thought perhaps I would use an internal +% format maintaining such 8 digits blocks, and this has to be compatible with +% the \csname...\endcsname encapsulation in \xintexpr parsers.| +% \begin{macrocode} +\def\XINT_sepbyviii_Z #1#2#3#4#5#6#7#8% +{% + 1#1#2#3#4#5#6#7#8\expandafter!\the\numexpr\XINT_sepbyviii_Z +}% +\def\XINT_sepbyviii_Z_end #1\relax {;!}% +% \end{macrocode} +% \subsection{\csh{XINT_sepbyviii_andcount}} +% +% \lverb|This is used as +%( \the\numexpr\XINT_sepbyviii_andcount <8Ndigits>$% +%: \XINT_sepbyviii_end 2345678\relax +%: \xint_c_vii!\xint_c_vi!\xint_c_v!\xint_c_iv!$% +%: \xint_c_iii!\xint_c_ii!\xint_c_i!\xint_c_\W +%) +% It will produce +%( 1<8d>!1<8d>!....1<8d>!1\xint:<count of blocks>\xint: +%) +% Used by +% \XINT_div_prepare_g for \XINT_div_prepare_h, and also by \xintiiCmp.| +% \begin{macrocode} +\def\XINT_sepbyviii_andcount +{% + \expandafter\XINT_sepbyviii_andcount_a\the\numexpr\XINT_sepbyviii +}% +\def\XINT_sepbyviii #1#2#3#4#5#6#7#8% +{% + 1#1#2#3#4#5#6#7#8\expandafter!\the\numexpr\XINT_sepbyviii +}% +\def\XINT_sepbyviii_end #1\relax {\relax\XINT_sepbyviii_andcount_end!}% +\def\XINT_sepbyviii_andcount_a {\XINT_sepbyviii_andcount_b \xint_c_\xint:}% +\def\XINT_sepbyviii_andcount_b #1\xint:#2!#3!#4!#5!#6!#7!#8!#9!% +{% + #2\expandafter!\the\numexpr#3\expandafter!\the\numexpr#4\expandafter + !\the\numexpr#5\expandafter!\the\numexpr#6\expandafter!\the\numexpr + #7\expandafter!\the\numexpr#8\expandafter!\the\numexpr#9\expandafter!\the\numexpr + \expandafter\XINT_sepbyviii_andcount_b\the\numexpr #1+\xint_c_viii\xint:% +}% +\def\XINT_sepbyviii_andcount_end #1\XINT_sepbyviii_andcount_b\the\numexpr + #2+\xint_c_viii\xint:#3#4\W {\expandafter\xint:\the\numexpr #2+#3\xint:}% +% \end{macrocode} +% \subsection{\csh{XINT_rsepbyviii}} +% +% \lverb|This is used as +%( \the\numexpr1\XINT_rsepbyviii <8Ndigits>$% +%: \XINT_rsepbyviii_end_A 2345678$% +%: \XINT_rsepbyviii_end_B 2345678\relax UV$% +%) +% and will produce +%( 1<8digits>!1<8digits>\xint:1<8digits>!... +%) +% where the original +% digits are organized by eight, and the order inside successive pairs of +% blocks separated by \xint: has been reversed. Output ends either in +% 1<8d>!1<8d>\xint:1U\xint: (even) or 1<8d>!1<8d>\xint:1V!1<8d>\xint: (odd) +% +% The U an V should be \numexpr1 stoppers (or will expand and be ended by !). +% This macro is currently (1.2..1.2l) exclusively used in combination with +% \XINT_sepandrev_andcount or \XINT_sepandrev. +% | +% \begin{macrocode} +\def\XINT_rsepbyviii #1#2#3#4#5#6#7#8% +{% + \XINT_rsepbyviii_b {#1#2#3#4#5#6#7#8}% +}% +\def\XINT_rsepbyviii_b #1#2#3#4#5#6#7#8#9% +{% + #2#3#4#5#6#7#8#9\expandafter!\the\numexpr + 1#1\expandafter\xint:\the\numexpr 1\XINT_rsepbyviii +}% +\def\XINT_rsepbyviii_end_B #1\relax #2#3{#2\xint:}% +\def\XINT_rsepbyviii_end_A #11#2\expandafter #3\relax #4#5{#5!1#2\xint:}% +% \end{macrocode} +% \subsection{\csh{XINT_sepandrev}} +% \lverb|This is used typically as +%( \romannumeral0\XINT_sepandrev <8Ndigits>$% +%: \XINT_rsepbyviii_end_A 2345678$% +%: \XINT_rsepbyviii_end_B 2345678\relax UV$% +%: \R\xint:\R\xint:\R\xint:\R\xint:\R\xint:\R\xint:\R\xint:\R\xint:\W +%) +% and will produce +%( 1<8digits>!1<8digits>!1<8digits>!... +%) +% where the blocks have +% been globally reversed. The UV here are only place holders (must be \numexpr1 +% stoppers) to share same +% syntax as \XINT_sepandrev_andcount, they are gobbled (#2 in \XINT_sepandrev_done).| +% \begin{macrocode} +\def\XINT_sepandrev +{% + \expandafter\XINT_sepandrev_a\the\numexpr 1\XINT_rsepbyviii +}% +\def\XINT_sepandrev_a {\XINT_sepandrev_b {}}% +\def\XINT_sepandrev_b #1#2\xint:#3\xint:#4\xint:#5\xint:#6\xint:#7\xint:#8\xint:#9\xint:% +{% + \xint_gob_til_R #9\XINT_sepandrev_end\R + \XINT_sepandrev_b {#9!#8!#7!#6!#5!#4!#3!#2!#1}% +}% +\def\XINT_sepandrev_end\R\XINT_sepandrev_b #1#2\W {\XINT_sepandrev_done #1}% +\def\XINT_sepandrev_done #11#2!{ }% +% \end{macrocode} +% \subsection{\csh{XINT_sepandrev_andcount}} +% \lverb|This is used typically as +%( \romannumeral0\XINT_sepandrev_andcount <8Ndigits>$% +%: \XINT_rsepbyviii_end_A 2345678$% +%: \XINT_rsepbyviii_end_B 2345678\relax\xint_c_ii\xint_c_i +%: \R\xint:\xint_c_xii \R\xint:\xint_c_x \R\xint:\xint_c_viii \R\xint:\xint_c_vi +%: \R\xint:\xint_c_iv \R\xint:\xint_c_ii \R\xint:\xint_c_\W +%) +% and will produce +%( <length>.1<8digits>!1<8digits>!1<8digits>!... +%) +% where the +% blocks have been globally reversed and <length> is the number of blocks.| +% \begin{macrocode} +\def\XINT_sepandrev_andcount +{% + \expandafter\XINT_sepandrev_andcount_a\the\numexpr 1\XINT_rsepbyviii +}% +\def\XINT_sepandrev_andcount_a {\XINT_sepandrev_andcount_b 0!{}}% +\def\XINT_sepandrev_andcount_b #1!#2#3\xint:#4\xint:#5\xint:#6\xint:#7\xint:#8\xint:#9\xint:% +{% + \xint_gob_til_R #9\XINT_sepandrev_andcount_end\R + \expandafter\XINT_sepandrev_andcount_b \the\numexpr #1+\xint_c_i!% + {#9!#8!#7!#6!#5!#4!#3!#2}% +}% +\def\XINT_sepandrev_andcount_end\R + \expandafter\XINT_sepandrev_andcount_b\the\numexpr #1+\xint_c_i!#2#3#4\W +{\expandafter\XINT_sepandrev_andcount_done\the\numexpr #3+\xint_c_xiv*#1!#2}% +\def\XINT_sepandrev_andcount_done#1{% +\def\XINT_sepandrev_andcount_done##1!##21##3!{\expandafter#1\the\numexpr##1-##3\xint:}% +}\XINT_sepandrev_andcount_done{ }% +% \end{macrocode} +% \subsection{\csh{XINT_rev_nounsep}} +% \lverb|This is used as +%( \romannumeral0\XINT_rev_nounsep {}<blocks 1<8d>!>\R!\R!\R!\R!\R!\R!\R!\R!\W +%) +% It reverses the blocks, keeping the 1's and ! separators. Used multiple +% times in the division algorithm. The inserted {} here is not optional.| +% \begin{macrocode} +\def\XINT_rev_nounsep #1#2!#3!#4!#5!#6!#7!#8!#9!% +{% + \xint_gob_til_R #9\XINT_rev_nounsep_end\R + \XINT_rev_nounsep {#9!#8!#7!#6!#5!#4!#3!#2!#1}% +}% +\def\XINT_rev_nounsep_end\R\XINT_rev_nounsep #1#2\W {\XINT_rev_nounsep_done #1}% +\def\XINT_rev_nounsep_done #11{ 1}% +% \end{macrocode} +% \subsection{\csh{XINT_unrevbyviii}} +% \lverb|Used as \romannumeral0\XINT_unrevbyviii 1<8d>!....1<8d>! terminated +% by +%( 1;!1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W +%) +% The \romannumeral in unrevbyviii_a is for special effects (expand some token +% which was put as 1<token>! at the end of the original blocks). This +% mechanism is used by 1.2 subtraction (still true for 1.2l).| +% \begin{macrocode} +\def\XINT_unrevbyviii #11#2!1#3!1#4!1#5!1#6!1#7!1#8!1#9!% +{% + \xint_gob_til_R #9\XINT_unrevbyviii_a\R + \XINT_unrevbyviii {#9#8#7#6#5#4#3#2#1}% +}% +\def\XINT_unrevbyviii_a#1{% +\def\XINT_unrevbyviii_a\R\XINT_unrevbyviii ##1##2\W + {\expandafter#1\romannumeral`&&@\xint_gob_til_sc ##1}% +}\XINT_unrevbyviii_a{ }% +% \end{macrocode} +% \lverb|Can work with shorter ending pattern: 1;!1\R!1\R!1\R!1\R!1\R!1\R!\W +% but the longer one of unrevbyviii is ok here too. Used currently (1.2) only +% by addition, now (1.2c) with long ending pattern. Does the final clean up of +% leading zeroes contrarily to general \XINT_unrevbyviii.| +% \begin{macrocode} +\def\XINT_smallunrevbyviii 1#1!1#2!1#3!1#4!1#5!1#6!1#7!1#8!#9\W% +{% + \expandafter\XINT_cuz_small\xint_gob_til_sc #8#7#6#5#4#3#2#1% +}% +% \end{macrocode} +% \subsection*{Core arithmetic} +% \addcontentsline{toc}{subsection}{Core arithmetic} +% \lverb|The four operations have been rewritten entirely for release 1.2. +% The new routines works with separated blocks of eight digits. They all measure +% first the lengths of the arguments, even addition and subtraction (this was +% not the case with xintcore.sty 1.1 or earlier.) +% +% The technique of chaining \the\numexpr induces a limitation on the +% maximal size depending on the size of the input save stack and the maximum +% expansion depth. For the current (TL2015) settings (5000, resp. 10000), the +% induced limit for addition of numbers is at 19968 and for multiplication +% it is observed to be 19959 (valid as of 2015/10/07). +% +% Side remark: I tested that \the\numexpr was more efficient than \number. But +% it reduced the allowable numbers for addition from 19976 digits to 19968 +% digits.| +% +% \subsection{\csh{xintiiAdd}} +% \lverb|1.2l: \xintiiAdd made robust against non terminated input.| +% \begin{macrocode} +\def\xintiiAdd {\romannumeral0\xintiiadd }% +\def\xintiiadd #1{\expandafter\XINT_iiadd\romannumeral`&&@#1\xint:}% +\def\XINT_iiadd #1#2\xint:#3% +{% + \expandafter\XINT_add_nfork\expandafter#1\romannumeral`&&@#3\xint:#2\xint: +}% +\def\XINT_iadd #1#2\xint:#3% +{% + \expandafter\XINT_add_nfork\expandafter + #1\romannumeral0\xintnum{#3}\xint:#2\xint: +}% +\def\XINT_add_fork #1#2\xint:#3\xint:{\XINT_add_nfork #1#3\xint:#2\xint:}% +\def\XINT_add_nfork #1#2% +{% + \xint_UDzerofork + #1\XINT_add_firstiszero + #2\XINT_add_secondiszero + 0{}% + \krof + \xint_UDsignsfork + #1#2\XINT_add_minusminus + #1-\XINT_add_minusplus + #2-\XINT_add_plusminus + --\XINT_add_plusplus + \krof #1#2% +}% +\def\XINT_add_firstiszero #1\krof 0#2#3\xint:#4\xint:{ #2#3}% +\def\XINT_add_secondiszero #1\krof #20#3\xint:#4\xint:{ #2#4}% +\def\XINT_add_minusminus #1#2% + {\expandafter-\romannumeral0\XINT_add_pp_a {}{}}% +\def\XINT_add_minusplus #1#2{\XINT_sub_mm_a {}#2}% +\def\XINT_add_plusminus #1#2% + {\expandafter\XINT_opp\romannumeral0\XINT_sub_mm_a #1{}}% +\def\XINT_add_pp_a #1#2#3\xint: +{% + \expandafter\XINT_add_pp_b + \romannumeral0\expandafter\XINT_sepandrev_andcount + \romannumeral0\XINT_zeroes_forviii #2#3\R\R\R\R\R\R\R\R{10}0000001\W + #2#3\XINT_rsepbyviii_end_A 2345678% + \XINT_rsepbyviii_end_B 2345678\relax\xint_c_ii\xint_c_i + \R\xint:\xint_c_xii \R\xint:\xint_c_x \R\xint:\xint_c_viii \R\xint:\xint_c_vi + \R\xint:\xint_c_iv \R\xint:\xint_c_ii \R\xint:\xint_c_\W + \X #1% +}% +\let\XINT_add_plusplus \XINT_add_pp_a +% \end{macrocode} +% \begin{macrocode} +\def\XINT_add_pp_b #1\xint:#2\X #3\xint: +{% + \expandafter\XINT_add_checklengths + \the\numexpr #1\expandafter\xint:% + \romannumeral0\expandafter\XINT_sepandrev_andcount + \romannumeral0\XINT_zeroes_forviii #3\R\R\R\R\R\R\R\R{10}0000001\W + #3\XINT_rsepbyviii_end_A 2345678% + \XINT_rsepbyviii_end_B 2345678\relax\xint_c_ii\xint_c_i + \R\xint:\xint_c_xii \R\xint:\xint_c_x \R\xint:\xint_c_viii \R\xint:\xint_c_vi + \R\xint:\xint_c_iv \R\xint:\xint_c_ii \R\xint:\xint_c_\W + 1;!1;!1;!1;!\W #21;!1;!1;!1;!\W + 1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W +}% +% \end{macrocode} +% \lverb|I keep #1.#2. to check if at most 6 + 6 base 10^8 digits which can be +% treated faster for final reverse. But is this overhead at all useful ? | +% \begin{macrocode} +\def\XINT_add_checklengths #1\xint:#2\xint:% +{% + \ifnum #2>#1 + \expandafter\XINT_add_exchange + \else + \expandafter\XINT_add_A + \fi + #1\xint:#2\xint:% +}% +\def\XINT_add_exchange #1\xint:#2\xint:#3\W #4\W +{% + \XINT_add_A #2\xint:#1\xint:#4\W #3\W +}% +\def\XINT_add_A #1\xint:#2\xint:% +{% + \ifnum #1>\xint_c_vi + \expandafter\XINT_add_aa + \else \expandafter\XINT_add_aa_small + \fi +}% +\def\XINT_add_aa {\expandafter\XINT_add_out\the\numexpr\XINT_add_a \xint_c_ii}% +\def\XINT_add_out{\expandafter\XINT_cuz_small\romannumeral0\XINT_unrevbyviii {}}% +\def\XINT_add_aa_small + {\expandafter\XINT_smallunrevbyviii\the\numexpr\XINT_add_a \xint_c_ii}% +% \end{macrocode} +% \lverb|2 as first token of #1 stands for "no carry", 3 will mean a carry (we +% are adding 1<8digits> to 1<8digits>.) Version 1.2c has terminators of the +% shape 1;!, replacing the \Z! used in 1.2. +% +% Call: \the\numexpr\XINT_add_a 2#11;!1;!1;!1;!\W #21;!1;!1;!1;!\W +% where #1 and #2 are blocks of 1<8d>!, and #1 is at most as long as #2. This +% last requirement is a bit annoying (if one wants to do recursive algorithms +% but not have to check lengths), and I will probably remove it at some point. +% +% Output: blocks of 1<8d>! representing the addition, (least significant +% first), and a final 1;!. In recursive algotithm this 1;! terminator can +% thus conveniently be reused as part of input terminator (up to the length +% problem). +% +%| +% \begin{macrocode} +\def\XINT_add_a #1!#2!#3!#4!#5\W + #6!#7!#8!#9!% +{% + \XINT_add_b + #1!#6!#2!#7!#3!#8!#4!#9!% + #5\W +}% +\def\XINT_add_b #11#2#3!#4!% +{% + \xint_gob_til_sc #2\XINT_add_bi ;% + \expandafter\XINT_add_c\the\numexpr#1+1#2#3+#4-\xint_c_ii\xint:% +}% +\def\XINT_add_bi;\expandafter\XINT_add_c + \the\numexpr#1+#2+#3-\xint_c_ii\xint:#4!#5!#6!#7!#8!#9!\W +{% + \XINT_add_k #1#3!#5!#7!#9!% +}% +\def\XINT_add_c #1#2\xint:% +{% + 1#2\expandafter!\the\numexpr\XINT_add_d #1% +}% +\def\XINT_add_d #11#2#3!#4!% +{% + \xint_gob_til_sc #2\XINT_add_di ;% + \expandafter\XINT_add_e\the\numexpr#1+1#2#3+#4-\xint_c_ii\xint:% +}% +\def\XINT_add_di;\expandafter\XINT_add_e + \the\numexpr#1+#2+#3-\xint_c_ii\xint:#4!#5!#6!#7!#8\W +{% + \XINT_add_k #1#3!#5!#7!% +}% +\def\XINT_add_e #1#2\xint:% +{% + 1#2\expandafter!\the\numexpr\XINT_add_f #1% +}% +\def\XINT_add_f #11#2#3!#4!% +{% + \xint_gob_til_sc #2\XINT_add_fi ;% + \expandafter\XINT_add_g\the\numexpr#1+1#2#3+#4-\xint_c_ii\xint:% +}% +\def\XINT_add_fi;\expandafter\XINT_add_g + \the\numexpr#1+#2+#3-\xint_c_ii\xint:#4!#5!#6\W +{% + \XINT_add_k #1#3!#5!% +}% +\def\XINT_add_g #1#2\xint:% +{% + 1#2\expandafter!\the\numexpr\XINT_add_h #1% +}% +\def\XINT_add_h #11#2#3!#4!% +{% + \xint_gob_til_sc #2\XINT_add_hi ;% + \expandafter\XINT_add_i\the\numexpr#1+1#2#3+#4-\xint_c_ii\xint:% +}% +\def\XINT_add_hi;% + \expandafter\XINT_add_i\the\numexpr#1+#2+#3-\xint_c_ii\xint:#4\W +{% + \XINT_add_k #1#3!% +}% +\def\XINT_add_i #1#2\xint:% +{% + 1#2\expandafter!\the\numexpr\XINT_add_a #1% +}% +% \end{macrocode} +% \begin{macrocode} +\def\XINT_add_k #1{\if #12\expandafter\XINT_add_ke\else\expandafter\XINT_add_l \fi}% +\def\XINT_add_ke #11;#2\W {\XINT_add_kf #11;!}% +\def\XINT_add_kf 1{1\relax }% +\def\XINT_add_l 1#1#2{\xint_gob_til_sc #1\XINT_add_lf ;\XINT_add_m 1#1#2}% +\def\XINT_add_lf #1\W {1\relax 00000001!1;!}% +\def\XINT_add_m #1!{\expandafter\XINT_add_n\the\numexpr\xint_c_i+#1\xint:}% +\def\XINT_add_n #1#2\xint:{1#2\expandafter!\the\numexpr\XINT_add_o #1}% +% \end{macrocode} +% \lverb|Here 2 stands for "carry", and 1 for "no carry" (we have been adding +% 1 to 1<8digits>.)| +% \begin{macrocode} +\def\XINT_add_o #1{\if #12\expandafter\XINT_add_l\else\expandafter\XINT_add_ke \fi}% +% \end{macrocode} +% \subsection{\csh{xintiiCmp}} +% \lverb|Moved from xint.sty to xintcore.sty and rewritten for 1.2l. +% +% 1.2l's \xintiiCmp is robust against non terminated input. +% +% 1.2o deprecates \xintCmp, with xintfrac loaded it will get overwritten anyhow. +%| +% \begin{macrocode} +\def\xintiiCmp {\romannumeral0\xintiicmp }% +\def\xintiicmp #1{\expandafter\XINT_iicmp\romannumeral`&&@#1\xint:}% +\def\XINT_iicmp #1#2\xint:#3% +{% + \expandafter\XINT_cmp_nfork\expandafter #1\romannumeral`&&@#3\xint:#2\xint: +}% +\def\XINT_icmp #1#2\xint:#3% +{% + \expandafter\XINT_cmp_nfork\expandafter #1\romannumeral0\xintnum{#3}\xint:#2\xint: +}% +\def\XINT_cmp_nfork #1#2% +{% + \xint_UDzerofork + #1\XINT_cmp_firstiszero + #2\XINT_cmp_secondiszero + 0{}% + \krof + \xint_UDsignsfork + #1#2\XINT_cmp_minusminus + #1-\XINT_cmp_minusplus + #2-\XINT_cmp_plusminus + --\XINT_cmp_plusplus + \krof #1#2% +}% +\def\XINT_cmp_firstiszero #1\krof 0#2#3\xint:#4\xint: +{% + \xint_UDzerominusfork + #2-{ 0}% + 0#2{ 1}% + 0-{ -1}% + \krof +}% +\def\XINT_cmp_secondiszero #1\krof #20#3\xint:#4\xint: +{% + \xint_UDzerominusfork + #2-{ 0}% + 0#2{ -1}% + 0-{ 1}% + \krof +}% +\def\XINT_cmp_plusminus #1\xint:#2\xint:{ 1}% +\def\XINT_cmp_minusplus #1\xint:#2\xint:{ -1}% +\def\XINT_cmp_minusminus + --{\expandafter\XINT_opp\romannumeral0\XINT_cmp_plusplus {}{}}% +\def\XINT_cmp_plusplus #1#2#3\xint: +{% + \expandafter\XINT_cmp_pp + \the\numexpr\expandafter\XINT_sepbyviii_andcount + \romannumeral0\XINT_zeroes_forviii #2#3\R\R\R\R\R\R\R\R{10}0000001\W + #2#3\XINT_sepbyviii_end 2345678\relax + \xint_c_vii!\xint_c_vi!\xint_c_v!\xint_c_iv!% + \xint_c_iii!\xint_c_ii!\xint_c_i!\xint_c_\W + #1% +}% +\def\XINT_cmp_pp #1\xint:#2\xint:#3\xint: +{% + \expandafter\XINT_cmp_checklengths + \the\numexpr #2\expandafter\xint:% + \the\numexpr\expandafter\XINT_sepbyviii_andcount + \romannumeral0\XINT_zeroes_forviii #3\R\R\R\R\R\R\R\R{10}0000001\W + #3\XINT_sepbyviii_end 2345678\relax + \xint_c_vii!\xint_c_vi!\xint_c_v!\xint_c_iv!% + \xint_c_iii!\xint_c_ii!\xint_c_i!\xint_c_\W + #1;!1;!1;!1;!\W +}% +\def\XINT_cmp_checklengths #1\xint:#2\xint:#3\xint: +{% + \ifnum #1=#3 + \expandafter\xint_firstoftwo + \else + \expandafter\xint_secondoftwo + \fi + \XINT_cmp_a {\XINT_cmp_distinctlengths {#1}{#3}}#2;!1;!1;!1;!\W +}% +\def\XINT_cmp_distinctlengths #1#2#3\W #4\W +{% + \ifnum #1>#2 + \expandafter\xint_firstoftwo + \else + \expandafter\xint_secondoftwo + \fi + { -1}{ 1}% +}% +\def\XINT_cmp_a 1#1!1#2!1#3!1#4!#5\W 1#6!1#7!1#8!1#9!% +{% + \xint_gob_til_sc #1\XINT_cmp_equal ;% + \ifnum #1>#6 \XINT_cmp_gt\fi + \ifnum #1<#6 \XINT_cmp_lt\fi + \xint_gob_til_sc #2\XINT_cmp_equal ;% + \ifnum #2>#7 \XINT_cmp_gt\fi + \ifnum #2<#7 \XINT_cmp_lt\fi + \xint_gob_til_sc #3\XINT_cmp_equal ;% + \ifnum #3>#8 \XINT_cmp_gt\fi + \ifnum #3<#8 \XINT_cmp_lt\fi + \xint_gob_til_sc #4\XINT_cmp_equal ;% + \ifnum #4>#9 \XINT_cmp_gt\fi + \ifnum #4<#9 \XINT_cmp_lt\fi + \XINT_cmp_a #5\W +}% +\def\XINT_cmp_lt#1{\def\XINT_cmp_lt\fi ##1\W ##2\W {\fi#1-1}}\XINT_cmp_lt{ }% +\def\XINT_cmp_gt#1{\def\XINT_cmp_gt\fi ##1\W ##2\W {\fi#11}}\XINT_cmp_gt{ }% +\def\XINT_cmp_equal #1\W #2\W { 0}% +% \end{macrocode} +% \subsection{\csh{xintiiSub}} +% \lverb|Entirely rewritten for 1.2. +% +% Refactored at 1.2l. I was initially aiming at clinching some internal format +% of the type 1<8digits>!....1<8digits>! for chaining the arithmetic +% operations (as a preliminary step to decided upon some internal format for +% $xintfracnameimp macros), thus I wanted to uniformize delimiters in +% particular and have some core macros inputting and outputting such formats. +% But the way division is implemented makes it currently very hard to obtain a +% satisfactory solution. For subtraction I got there almost, but there was +% added overhead and, as the core sub-routine still assumed the shorter number +% will be positioned first, one would need to record the length also in the +% basic internal format, or add the overhead to not make assumption on which +% one is shorter. I thus but back-tracked my steps but in passing I improved +% the efficiency (probably) in the worst case branch. +% +% Sadly this 1.2l refactoring left an extra ! in macro \XINT_sub_l_Ida. This +% bug shows only in rare circumstances which escaped out test suite :( +% Fixed at 1.2q. +% +% The other reason for backtracking was in relation with the decimal numbers. +% Having a core format in base 10^8 but ultimately the radix is actually 10 +% leads to complications. I could use radix 10^8 for \xintiiexpr only, but +% then I need to make it compatible with sub-\xintiiexpr in \xintexpr, etc... +% there are many issues of this type. +% +% I considered also an approach like in the 1.2l \xintiiCmp, but decided to +% stick with the method here for now.| +% \begin{macrocode} +\def\xintiiSub {\romannumeral0\xintiisub }% +\def\xintiisub #1{\expandafter\XINT_iisub\romannumeral`&&@#1\xint:}% +\def\XINT_iisub #1#2\xint:#3% +{% + \expandafter\XINT_sub_nfork\expandafter + #1\romannumeral`&&@#3\xint:#2\xint: +}% +\def\XINT_isub #1#2\xint:#3% +{% + \expandafter\XINT_sub_nfork\expandafter + #1\romannumeral0\xintnum{#3}\xint:#2\xint: +}% +\def\XINT_sub_nfork #1#2% +{% + \xint_UDzerofork + #1\XINT_sub_firstiszero + #2\XINT_sub_secondiszero + 0{}% + \krof + \xint_UDsignsfork + #1#2\XINT_sub_minusminus + #1-\XINT_sub_minusplus + #2-\XINT_sub_plusminus + --\XINT_sub_plusplus + \krof #1#2% +}% +\def\XINT_sub_firstiszero #1\krof 0#2#3\xint:#4\xint:{\XINT_opp #2#3}% +\def\XINT_sub_secondiszero #1\krof #20#3\xint:#4\xint:{ #2#4}% +\def\XINT_sub_plusminus #1#2{\XINT_add_pp_a #1{}}% +\def\XINT_sub_plusplus #1#2% + {\expandafter\XINT_opp\romannumeral0\XINT_sub_mm_a #1#2}% +\def\XINT_sub_minusplus #1#2% + {\expandafter-\romannumeral0\XINT_add_pp_a {}#2}% +\def\XINT_sub_minusminus #1#2{\XINT_sub_mm_a {}{}}% +% \end{macrocode} +% \begin{macrocode} +\def\XINT_sub_mm_a #1#2#3\xint: +{% + \expandafter\XINT_sub_mm_b + \romannumeral0\expandafter\XINT_sepandrev_andcount + \romannumeral0\XINT_zeroes_forviii #2#3\R\R\R\R\R\R\R\R{10}0000001\W + #2#3\XINT_rsepbyviii_end_A 2345678% + \XINT_rsepbyviii_end_B 2345678\relax\xint_c_ii\xint_c_i + \R\xint:\xint_c_xii \R\xint:\xint_c_x \R\xint:\xint_c_viii \R\xint:\xint_c_vi + \R\xint:\xint_c_iv \R\xint:\xint_c_ii \R\xint:\xint_c_\W + \X #1% +}% +\def\XINT_sub_mm_b #1\xint:#2\X #3\xint: +{% + \expandafter\XINT_sub_checklengths + \the\numexpr #1\expandafter\xint:% + \romannumeral0\expandafter\XINT_sepandrev_andcount + \romannumeral0\XINT_zeroes_forviii #3\R\R\R\R\R\R\R\R{10}0000001\W + #3\XINT_rsepbyviii_end_A 2345678% + \XINT_rsepbyviii_end_B 2345678\relax\xint_c_ii\xint_c_i + \R\xint:\xint_c_xii \R\xint:\xint_c_x \R\xint:\xint_c_viii \R\xint:\xint_c_vi + \R\xint:\xint_c_iv \R\xint:\xint_c_ii \R\xint:\xint_c_\W + 1;!1;!1;!1;!\W + #21;!1;!1;!1;!\W + 1;!1\R!1\R!1\R!1\R!% + 1\R!1\R!1\R!1\R!\W +}% +\def\XINT_sub_checklengths #1\xint:#2\xint:% +{% + \ifnum #2>#1 + \expandafter\XINT_sub_exchange + \else + \expandafter\XINT_sub_aa + \fi +}% +\def\XINT_sub_exchange #1\W #2\W +{% + \expandafter\XINT_opp\romannumeral0\XINT_sub_aa #2\W #1\W +}% +\def\XINT_sub_aa +{% + \expandafter\XINT_sub_out\the\numexpr\XINT_sub_a\xint_c_i +}% +% \end{macrocode} +% \lverb|The post-processing (clean-up of zeros, or rescue of situation with +% A-B where actually B turns out bigger than A) will be done by a macro which +% depends on circumstances and will be initially last token before the +% reversion done by \XINT_unrevbyviii.| +% \begin{macrocode} +\def\XINT_sub_out {\XINT_unrevbyviii{}}% +% \end{macrocode} +% \lverb|1 as first token of #1 stands for "no carry", 0 will mean a carry. +% +%( Call: \the\numexpr +%: \XINT_sub_a 1#11;!1;!1;!1;!\W +%: #21;!1;!1;!1;!\W +%) +% where #1 and #2 +% are blocks of 1<8d>!, #1 (=B) *must* be at most as long as #2 (=A), +% (in radix 10^8) +% and the routine wants to compute #2-#1 = A - B +% +% 1.2l uses 1;! delimiters to match those of addition (and multiplication). +% But in the end I reverted the code branch which made it possible to chain +% such operations keeping internal format in 8 digits blocks throughout. +% +% \numexpr governed expansion stops with various possibilities: +% +%- Type Ia: #1 shorter than #2, no final carry +%- Type Ib: #1 shorter than #2, a final carry but next block of #2 > 1 +%- Type Ica: #1 shorter than #2, a final carry, next block of #2 is final and = 1 +%- Type Icb: as Ica except that 00000001 block from #2 was not final +%- Type Id: #1 shorter than #2, a final carry, next block of #2 = 0 +%- Type IIa: #1 same length as #2, turns out it was <= #2. +%- Type IIb: #1 same length as #2, but turned out > #2. +% +% Various type of post actions are then needed: +% +%- Ia: clean up of zeros in most significant block of 8 digits +% +%- Ib: as Ia +% +%- Ic: there may be significant blocks of 8 zeros to clean up from result. +% Only case Ica may have arbitrarily many of them, case Icb has only one such +% block. +% +%- Id: blocks of 99999999 may propagate and there might a be final zero block +% created which has to be cleaned up. +% +%- IIa: arbitrarily many zeros might have to be removed. +% +%- IIb: We wanted #2-#1 = - (#1-#2), but we got 10^{8N}+#2 -#1 = 10^{8N}-(#1-#2). +% We need to do the correction then we are as in IIa situation, except that +% final result can not be zero. +% +% The 1.2l method for this correction is (presumably, testing takes lots of +% time, which I do not have) more efficient than in 1.2 release. | +% \begin{macrocode} +\def\XINT_sub_a #1!#2!#3!#4!#5\W #6!#7!#8!#9!% +{% + \XINT_sub_b + #1!#6!#2!#7!#3!#8!#4!#9!% + #5\W +}% +% \end{macrocode} +% \lverb|As 1.2l code uses 1<8digits>! blocks one has to be careful with +% the carry digit 1 or 0: A #11#2#3 pattern would result into an empty #1 +% if the carry digit which is upfront is 1, rather than setting #1=1.| +% \begin{macrocode} +\def\XINT_sub_b #1#2#3#4!#5!% +{% + \xint_gob_til_sc #3\XINT_sub_bi ;% + \expandafter\XINT_sub_c\the\numexpr#1+1#5-#3#4-\xint_c_i\xint:% +}% +\def\XINT_sub_c 1#1#2\xint:% +{% + 1#2\expandafter!\the\numexpr\XINT_sub_d #1% +}% +\def\XINT_sub_d #1#2#3#4!#5!% +{% + \xint_gob_til_sc #3\XINT_sub_di ;% + \expandafter\XINT_sub_e\the\numexpr#1+1#5-#3#4-\xint_c_i\xint: +}% +\def\XINT_sub_e 1#1#2\xint:% +{% + 1#2\expandafter!\the\numexpr\XINT_sub_f #1% +}% +\def\XINT_sub_f #1#2#3#4!#5!% +{% + \xint_gob_til_sc #3\XINT_sub_fi ;% + \expandafter\XINT_sub_g\the\numexpr#1+1#5-#3#4-\xint_c_i\xint: +}% +\def\XINT_sub_g 1#1#2\xint:% +{% + 1#2\expandafter!\the\numexpr\XINT_sub_h #1% +}% +\def\XINT_sub_h #1#2#3#4!#5!% +{% + \xint_gob_til_sc #3\XINT_sub_hi ;% + \expandafter\XINT_sub_i\the\numexpr#1+1#5-#3#4-\xint_c_i\xint: +}% +\def\XINT_sub_i 1#1#2\xint:% +{% + 1#2\expandafter!\the\numexpr\XINT_sub_a #1% +}% +\def\XINT_sub_bi;% + \expandafter\XINT_sub_c\the\numexpr#1+1#2-#3\xint: + #4!#5!#6!#7!#8!#9!\W +{% + \XINT_sub_k #1#2!#5!#7!#9!% +}% +\def\XINT_sub_di;% + \expandafter\XINT_sub_e\the\numexpr#1+1#2-#3\xint: + #4!#5!#6!#7!#8\W +{% + \XINT_sub_k #1#2!#5!#7!% +}% +\def\XINT_sub_fi;% + \expandafter\XINT_sub_g\the\numexpr#1+1#2-#3\xint: + #4!#5!#6\W +{% + \XINT_sub_k #1#2!#5!% +}% +\def\XINT_sub_hi;% + \expandafter\XINT_sub_i\the\numexpr#1+1#2-#3\xint: + #4\W +{% + \XINT_sub_k #1#2!% +}% +% \end{macrocode} +% \lverb|B terminated. Have we reached the end of A (necessarily at least as +% long as B) ? (we are computing A-B, digits of B come first). +% +% If not, then we are certain that even if there is carry it will not +% propagate beyond the end of A. But it may propagate far transforming chains +% of 00000000 into 99999999, and if it does go to the final block which possibly is +% just 1<00000001>!, we will have those eight zeros to clean up. +% +% If A and B have the same length (in base 10^8) then arbitrarily many zeros +% might have to be cleaned up, and if A<B, the whole result will have to be +% complemented first.| +% \begin{macrocode} +\def\XINT_sub_k #1#2#3% +{% + \xint_gob_til_sc #3\XINT_sub_p;\XINT_sub_l #1#2#3% +}% +\def\XINT_sub_l #1% + {\xint_UDzerofork #1\XINT_sub_l_carry 0\XINT_sub_l_Ia\krof}% +\def\XINT_sub_l_Ia 1#1;!#2\W{1\relax#1;!1\XINT_sub_fix_none!}% +% \end{macrocode} +% \lverb| +% +% | +% \begin{macrocode} +\def\XINT_sub_l_carry 1#1!{\ifcase #1 + \expandafter \XINT_sub_l_Id + \or \expandafter \XINT_sub_l_Ic + \else\expandafter \XINT_sub_l_Ib\fi 1#1!}% +\def\XINT_sub_l_Ib #1;#2\W {-\xint_c_i+#1;!1\XINT_sub_fix_none!}% +\def\XINT_sub_l_Ic 1#1!1#2#3!#4;#5\W +{% + \xint_gob_til_sc #2\XINT_sub_l_Ica;% + 1\relax 00000000!1#2#3!#4;!1\XINT_sub_fix_none!% +}% +% \end{macrocode} +% \lverb|& +% We need to add some extra delimiters at the end for post-action by +% \XINT_num, so we first grab the material up to \W +% | +% \begin{macrocode} +\def\XINT_sub_l_Ica#1\W +{% + 1;!1\XINT_sub_fix_cuz!% + 1;!1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W + \xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z +}% +\def\XINT_sub_l_Id 1#1!% + {199999999\expandafter!\the\numexpr \XINT_sub_l_Id_a}% +\def\XINT_sub_l_Id_a 1#1!{\ifcase #1 + \expandafter \XINT_sub_l_Id + \or \expandafter \XINT_sub_l_Id_b + \else\expandafter \XINT_sub_l_Ib\fi 1#1!}% +\def\XINT_sub_l_Id_b 1#1!1#2#3!#4;#5\W +{% + \xint_gob_til_sc #2\XINT_sub_l_Ida;% + 1\relax 00000000!1#2#3!#4;!1\XINT_sub_fix_none!% +}% +\def\XINT_sub_l_Ida#1\XINT_sub_fix_none{1;!1\XINT_sub_fix_none}% +% \end{macrocode} +% \lverb|& +% This is the case where both operands have same 10^8-base length. +% +% We were handling A-B but perhaps B>A. The situation with A=B is also +% annoying because we then have to clean up all zeros but don't know where to +% stop (if A>B the first non-zero 8 digits block would tell use when). +% +% Here again we need to grab #3\W to position the actually used terminating +% delimiters. +% | +% \begin{macrocode} +\def\XINT_sub_p;\XINT_sub_l #1#2\W #3\W +{% + \xint_UDzerofork + #1{1;!1\XINT_sub_fix_neg!% + 1;!1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W + \xint_bye2345678\xint_bye1099999988\relax}% A - B, B > A + 0{1;!1\XINT_sub_fix_cuz!% + 1;!1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W}% + \krof + \xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z +}% +% \end{macrocode} +% \lverb|Routines for post-processing after reversal, and removal of +% separators. It is a matter of cleaning up zeros, and possibly in the bad +% case to take a complement before that.| +% \begin{macrocode} +\def\XINT_sub_fix_none;{\XINT_cuz_small}% +\def\XINT_sub_fix_cuz ;{\expandafter\XINT_num_cleanup\the\numexpr\XINT_num_loop}% +% \end{macrocode} +% \lverb|Case with A and B same number of digits in base 10^8 and B>A. +% +% 1.2l subtle chaining on the model of the 1.2i rewrite of \xintInc and +% similar routines. After taking complement, leading zeroes need to be +% cleaned up as in B<=A branch.| +% \begin{macrocode} +\def\XINT_sub_fix_neg;% +{% + \expandafter-\romannumeral0\expandafter + \XINT_sub_comp_finish\the\numexpr\XINT_sub_comp_loop +}% +\def\XINT_sub_comp_finish 0{\XINT_sub_fix_cuz;}% +\def\XINT_sub_comp_loop #1#2#3#4#5#6#7#8% +{% + \expandafter\XINT_sub_comp_clean + \the\numexpr \xint_c_xi_e_viii_mone-#1#2#3#4#5#6#7#8\XINT_sub_comp_loop +}% +% \end{macrocode} +% \lverb|#1 = 0 signifie une retenue, #1 = 1 pas de retenue, ce qui ne peut +% arriver que tant qu'il n'y a que des zéros du côté non significatif. +% Lorsqu'on est revenu au début on a forcément une retenue.| +% \begin{macrocode} +\def\XINT_sub_comp_clean 1#1{+#1\relax}% +% \end{macrocode} +% \subsection{\csh{xintiiMul}} +% \lverb|Completely rewritten for 1.2. +% +% 1.2l: \xintiiMul made robust against non terminated input.| +% \begin{macrocode} +\def\xintiiMul {\romannumeral0\xintiimul }% +\def\xintiimul #1% +{% + \expandafter\XINT_iimul\romannumeral`&&@#1\xint: +}% +\def\XINT_iimul #1#2\xint:#3% +{% + \expandafter\XINT_mul_nfork\expandafter #1\romannumeral`&&@#3\xint:#2\xint: +}% +% \end{macrocode} +% \lverb|(1.2) I have changed the fork, and it complicates matters elsewhere.| +% \begin{macrocode} +\def\XINT_mul_fork #1#2\xint:#3\xint:{\XINT_mul_nfork #1#3\xint:#2\xint:}% +\def\XINT_mul_nfork #1#2% +{% + \xint_UDzerofork + #1\XINT_mul_zero + #2\XINT_mul_zero + 0{}% + \krof + \xint_UDsignsfork + #1#2\XINT_mul_minusminus + #1-\XINT_mul_minusplus + #2-\XINT_mul_plusminus + --\XINT_mul_plusplus + \krof #1#2% +}% +\def\XINT_mul_zero #1\krof #2#3\xint:#4\xint:{ 0}% +\def\XINT_mul_minusminus #1#2{\XINT_mul_plusplus {}{}}% +\def\XINT_mul_minusplus #1#2% + {\expandafter-\romannumeral0\XINT_mul_plusplus {}#2}% +\def\XINT_mul_plusminus #1#2% + {\expandafter-\romannumeral0\XINT_mul_plusplus #1{}}% +\def\XINT_mul_plusplus #1#2#3\xint: +{% + \expandafter\XINT_mul_pre_b + \romannumeral0\expandafter\XINT_sepandrev_andcount + \romannumeral0\XINT_zeroes_forviii #2#3\R\R\R\R\R\R\R\R{10}0000001\W + #2#3\XINT_rsepbyviii_end_A 2345678% + \XINT_rsepbyviii_end_B 2345678\relax\xint_c_ii\xint_c_i + \R\xint:\xint_c_xii \R\xint:\xint_c_x \R\xint:\xint_c_viii \R\xint:\xint_c_vi + \R\xint:\xint_c_iv \R\xint:\xint_c_ii \R\xint:\xint_c_\W + \W #1% +}% +\def\XINT_mul_pre_b #1\xint:#2\W #3\xint: +{% + \expandafter\XINT_mul_checklengths + \the\numexpr #1\expandafter\xint:% + \romannumeral0\expandafter\XINT_sepandrev_andcount + \romannumeral0\XINT_zeroes_forviii #3\R\R\R\R\R\R\R\R{10}0000001\W + #3\XINT_rsepbyviii_end_A 2345678% + \XINT_rsepbyviii_end_B 2345678\relax\xint_c_ii\xint_c_i + \R\xint:\xint_c_xii \R\xint:\xint_c_x \R\xint:\xint_c_viii \R\xint:\xint_c_vi + \R\xint:\xint_c_iv \R\xint:\xint_c_ii \R\xint:\xint_c_\W + 1;!\W #21;!% + 1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W +}% +% \end{macrocode} +% \lverb|Cooking recipe, 2015/10/05.| +% \begin{macrocode} +\def\XINT_mul_checklengths #1\xint:#2\xint:% +{% + \ifnum #2=\xint_c_i\expandafter\XINT_mul_smallbyfirst\fi + \ifnum #1=\xint_c_i\expandafter\XINT_mul_smallbysecond\fi + \ifnum #2<#1 + \ifnum \numexpr (#2-\xint_c_i)*(#1-#2)<383 + \XINT_mul_exchange + \fi + \else + \ifnum \numexpr (#1-\xint_c_i)*(#2-#1)>383 + \XINT_mul_exchange + \fi + \fi + \XINT_mul_start +}% +\def\XINT_mul_smallbyfirst #1\XINT_mul_start 1#2!1;!\W +{% + \ifnum#2=\xint_c_i\expandafter\XINT_mul_oneisone\fi + \ifnum#2<\xint_c_xxii\expandafter\XINT_mul_verysmall\fi + \expandafter\XINT_mul_out\the\numexpr\XINT_smallmul 1#2!% +}% +\def\XINT_mul_smallbysecond #1\XINT_mul_start #2\W 1#3!1;!% +{% + \ifnum#3=\xint_c_i\expandafter\XINT_mul_oneisone\fi + \ifnum#3<\xint_c_xxii\expandafter\XINT_mul_verysmall\fi + \expandafter\XINT_mul_out\the\numexpr\XINT_smallmul 1#3!#2% +}% +\def\XINT_mul_oneisone #1!{\XINT_mul_out }% +\def\XINT_mul_verysmall\expandafter\XINT_mul_out + \the\numexpr\XINT_smallmul 1#1!% + {\expandafter\XINT_mul_out\the\numexpr\XINT_verysmallmul 0\xint:#1!}% +\def\XINT_mul_exchange #1\XINT_mul_start #2\W #31;!% + {\fi\fi\XINT_mul_start #31;!\W #2}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_mul_start + {\expandafter\XINT_mul_out\the\numexpr\XINT_mul_loop 100000000!1;!\W}% +\def\XINT_mul_out + {\expandafter\XINT_cuz_small\romannumeral0\XINT_unrevbyviii {}}% +% \end{macrocode} +% \lverb|& +% +%( Call: +%: \the\numexpr \XINT_mul_loop 100000000!1;!\W #11;!\W #21;! +%) +% where #1 and #2 are (globally reversed) blocks 1<8d>!. Its is generally more +% efficient if #1 is the shorter one, but a better recipe is implemented in +% \XINT_mul_checklengths. One may call \XINT_mul_loop directly (but +% multiplication by zero will produce many 100000000! blocks on output). +% +% Ends after having produced: 1<8d>!....1<8d>!1;!. The last 8-digits block is +% significant one. It can not be 100000000! except if the loop was called with +% a zero operand. +% +% Thus \XINT_mul_loop can be conveniently called directly in recursive +% routines, as the output terminator can serve as input terminator, we can +% arrange to not have to grab the whole thing again.| +% \begin{macrocode} +\def\XINT_mul_loop #1\W #2\W 1#3!% +{% + \xint_gob_til_sc #3\XINT_mul_e ;% + \expandafter\XINT_mul_a\the\numexpr \XINT_smallmul 1#3!#2\W + #1\W #2\W +}% +% \end{macrocode} +% \lverb|Each of #1 and #2 brings its 1;! for \XINT_add_a.| +% \begin{macrocode} +\def\XINT_mul_a #1\W #2\W +{% + \expandafter\XINT_mul_b\the\numexpr + \XINT_add_a \xint_c_ii #21;!1;!1;!\W #11;!1;!1;!\W\W +}% +\def\XINT_mul_b 1#1!{1#1\expandafter!\the\numexpr\XINT_mul_loop }% +\def\XINT_mul_e;#1\W 1#2\W #3\W {1\relax #2}% +% \end{macrocode} +% \lverb|1.2 small and mini multiplication in base 10^8 with carry. Used by +% the main multiplication routines. But division, float factorial, etc.. have +% their own variants as they need output with specific constraints. +% +% The minimulwc has 1<8digits carry>.<4 high digits>.<4 low digits!<8digits>. +% +% It produces a block 1<8d>! and then jump back into \XINT_smallmul_a with the +% new 8digits carry as argument. The \XINT_smallmul_a fetches a new 1<8d>! +% block to multiply, and calls back \XINT_minimul_wc having stored the +% multiplicand for re-use later. When the loop terminates, the final carry is +% checked for being nul, and in all cases the output is terminated by a 1;! +% +% Multiplication by zero will produce blocks of zeros.| +% \begin{macrocode} +\def\XINT_minimulwc_a 1#1\xint:#2\xint:#3!#4#5#6#7#8\xint:% +{% + \expandafter\XINT_minimulwc_b + \the\numexpr \xint_c_x^ix+#1+#3*#8\xint: + #3*#4#5#6#7+#2*#8\xint: + #2*#4#5#6#7\xint:% +}% +\def\XINT_minimulwc_b 1#1#2#3#4#5#6\xint:#7\xint:% +{% + \expandafter\XINT_minimulwc_c + \the\numexpr \xint_c_x^ix+#1#2#3#4#5+#7\xint:#6\xint:% +}% +\def\XINT_minimulwc_c 1#1#2#3#4#5#6\xint:#7\xint:#8\xint:% +{% + 1#6#7\expandafter!% + \the\numexpr\expandafter\XINT_smallmul_a + \the\numexpr \xint_c_x^viii+#1#2#3#4#5+#8\xint:% +}% +\def\XINT_smallmul 1#1#2#3#4#5!{\XINT_smallmul_a 100000000\xint:#1#2#3#4\xint:#5!}% +\def\XINT_smallmul_a #1\xint:#2\xint:#3!1#4!% +{% + \xint_gob_til_sc #4\XINT_smallmul_e;% + \XINT_minimulwc_a #1\xint:#2\xint:#3!#4\xint:#2\xint:#3!% +}% +\def\XINT_smallmul_e;\XINT_minimulwc_a 1#1\xint:#2;#3!% + {\xint_gob_til_eightzeroes #1\XINT_smallmul_f 000000001\relax #1!1;!}% +\def\XINT_smallmul_f 000000001\relax 00000000!1{1\relax}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_verysmallmul #1\xint:#2!1#3!% +{% + \xint_gob_til_sc #3\XINT_verysmallmul_e;% + \expandafter\XINT_verysmallmul_a + \the\numexpr #2*#3+#1\xint:#2!% +}% +\def\XINT_verysmallmul_e;\expandafter\XINT_verysmallmul_a\the\numexpr + #1+#2#3\xint:#4!% +{\xint_gob_til_zero #2\XINT_verysmallmul_f 0\xint_c_x^viii+#2#3!1;!}% +\def\XINT_verysmallmul_f #1!1{1\relax}% +\def\XINT_verysmallmul_a #1#2\xint:% +{% + \unless\ifnum #1#2<\xint_c_x^ix + \expandafter\XINT_verysmallmul_bi\else + \expandafter\XINT_verysmallmul_bj\fi + \the\numexpr \xint_c_x^ix+#1#2\xint:% +}% +\def\XINT_verysmallmul_bj{\expandafter\XINT_verysmallmul_cj }% +\def\XINT_verysmallmul_cj 1#1#2\xint:% + {1#2\expandafter!\the\numexpr\XINT_verysmallmul #1\xint:}% +\def\XINT_verysmallmul_bi\the\numexpr\xint_c_x^ix+#1#2#3\xint:% + {1#3\expandafter!\the\numexpr\XINT_verysmallmul #1#2\xint:}% +% \end{macrocode} +% \lverb|Used by division and by squaring, not by multiplication itself. +% +% This routine does not loop, it only does one mini multiplication with input +% format <4 high digits>.<4 low digits>!<8 digits>!, and on output +% 1<8d>!1<8d>!, with least significant block first.| +% \begin{macrocode} +\def\XINT_minimul_a #1\xint:#2!#3#4#5#6#7!% +{% + \expandafter\XINT_minimul_b + \the\numexpr \xint_c_x^viii+#2*#7\xint:#2*#3#4#5#6+#1*#7\xint:#1*#3#4#5#6\xint:% +}% +\def\XINT_minimul_b 1#1#2#3#4#5\xint:#6\xint:% +{% + \expandafter\XINT_minimul_c + \the\numexpr \xint_c_x^ix+#1#2#3#4+#6\xint:#5\xint:% +}% +\def\XINT_minimul_c 1#1#2#3#4#5#6\xint:#7\xint:#8\xint:% +{% + 1#6#7\expandafter!\the\numexpr \xint_c_x^viii+#1#2#3#4#5+#8!% +}% +% \end{macrocode} +% \subsection{\csh{xintiiDivision}} +% \lverb|Completely rewritten for 1.2. +% +% WARNING: some comments below try to describe the flow of tokens but they +% date back to xint 1.09j and I updated them on the fly while doing the 1.2 +% version. As the routine now works in base 10^8, not 10^4 and "drops" the +% quotient digits,rather than store them upfront as the earlier code, I may +% well have not correctly converted all such comments. At the last minute some +% previously #1 became stuff like #1#2#3#4, then of course the old comments +% describing what the macro parameters stand for are necessarily wrong. +% +% Side remark: the way tokens are grouped was not essentially modified in +% 1.2, although the situation has changed. It was fine-tuned in xint +% 1.0/1.1 but the context has changed, and perhaps I should revisit this. +% As a corollary to the fact that quotient digits are now left behind thanks +% to the chains of \numexpr, some macros which in 1.0/1.1 fetched up to 9 +% parameters now need handle less such parameters. Thus, some rationale for +% the way the code was structured has disappeared. +% +% +% 1.2l: \xintiiDivision et al. made robust against non terminated input. +% | +% \lverb-#1 = A, #2 = B. On calcule le quotient et le reste dans la division +% euclidienne de A par B: A=BQ+R, 0<= R < |B|.- +% \begin{macrocode} +\def\xintiiDivision {\romannumeral0\xintiidivision }% +\def\xintiidivision #1{\expandafter\XINT_iidivision \romannumeral`&&@#1\xint:}% +\def\XINT_iidivision #1#2\xint:#3{\expandafter\XINT_iidivision_a\expandafter #1% + \romannumeral`&&@#3\xint:#2\xint:}% +% \end{macrocode} +% \lverb|On regarde les signes de A et de B.| +% \begin{macrocode} +\def\XINT_iidivision_a #1#2% #1 de A, #2 de B. +{% + \if0#2\xint_dothis{\XINT_iidivision_divbyzero #1#2}\fi + \if0#1\xint_dothis\XINT_iidivision_aiszero\fi + \if-#2\xint_dothis{\expandafter\XINT_iidivision_bneg + \romannumeral0\XINT_iidivision_bpos #1}\fi + \xint_orthat{\XINT_iidivision_bpos #1#2}% +}% +\def\XINT_iidivision_divbyzero#1#2#3\xint:#4\xint: + {\if0#1\xint_dothis{\XINT_signalcondition{DivisionUndefined}}\fi + \xint_orthat{\XINT_signalcondition{DivisionByZero}}% + {Division of #1#4 by #2#3}{}{{0}{0}}}% +\def\XINT_iidivision_aiszero #1\xint:#2\xint:{{0}{0}}% +\def\XINT_iidivision_bneg #1% q->-q, r unchanged + {\expandafter{\romannumeral0\XINT_opp #1}}% +\def\XINT_iidivision_bpos #1% +{% + \xint_UDsignfork + #1\XINT_iidivision_aneg + -{\XINT_iidivision_apos #1}% + \krof +}% +% \end{macrocode} +% \lverb|Donc attention malgré son nom \XINT_div_prepare va jusqu'au bout. +% C'est donc en fait l'entrée principale (pour B>0, A>0) mais elle va +% regarder si B est < 10^8 et s'il vaut alors 1 ou 2, et si A < 10^8. Dans +% tous les cas le résultat est produit sous la forme {Q}{R}, avec Q et R sous +% leur forme final. On doit ensuite ajuster si le B ou le A initial était +% négatif. Je n'ai pas fait beaucoup d'efforts pour être un minimum efficace +% si A ou B n'est pas positif.| +% \begin{macrocode} +\def\XINT_iidivision_apos #1#2\xint:#3\xint:{\XINT_div_prepare {#2}{#1#3}}% +\def\XINT_iidivision_aneg #1\xint:#2\xint: + {\expandafter + \XINT_iidivision_aneg_b\romannumeral0\XINT_div_prepare {#1}{#2}{#1}}% +\def\XINT_iidivision_aneg_b #1#2{\if0\XINT_Sgn #2\xint: + \expandafter\XINT_iidivision_aneg_rzero + \else + \expandafter\XINT_iidivision_aneg_rpos + \fi {#1}{#2}}% +\def\XINT_iidivision_aneg_rzero #1#2#3{{-#1}{0}}% necessarily q was >0 +\def\XINT_iidivision_aneg_rpos #1% +{% + \expandafter\XINT_iidivision_aneg_end\expandafter + {\expandafter-\romannumeral0\xintinc {#1}}% q-> -(1+q) +}% +\def\XINT_iidivision_aneg_end #1#2#3% +{% + \expandafter\xint_exchangetwo_keepbraces + \expandafter{\romannumeral0\XINT_sub_mm_a {}{}#3\xint:#2\xint:}{#1}% r-> b-r +}% +% \end{macrocode} +% \lverb|Le diviseur B va être étendu par des zéros pour que sa longueur soit +% multiple de huit. Les zéros seront mis du côté non significatif.| +% \begin{macrocode} +\def\XINT_div_prepare #1% +{% + \XINT_div_prepare_a #1\R\R\R\R\R\R\R\R {10}0000001\W !{#1}% +}% +\def\XINT_div_prepare_a #1#2#3#4#5#6#7#8#9% +{% + \xint_gob_til_R #9\XINT_div_prepare_small\R + \XINT_div_prepare_b #9% +}% +% \end{macrocode} +% \lverb|B a au plus huit chiffres. On se débarrasse des trucs superflus. Si +% B>0 n'est ni 1 ni 2, le point d'entrée est \XINT_div_small_a {B}{A} (avec un +% A positif).| +% \begin{macrocode} +\def\XINT_div_prepare_small\R #1!#2% +{% + \ifcase #2 + \or\expandafter\XINT_div_BisOne + \or\expandafter\XINT_div_BisTwo + \else\expandafter\XINT_div_small_a + \fi {#2}% +}% +\def\XINT_div_BisOne #1#2{{#2}{0}}% +\def\XINT_div_BisTwo #1#2% +{% + \expandafter\expandafter\expandafter\XINT_div_BisTwo_a + \ifodd\xintLDg{#2} \expandafter1\else \expandafter0\fi {#2}% +}% +\def\XINT_div_BisTwo_a #1#2% +{% + \expandafter{\romannumeral0\XINT_half + #2\xint_bye\xint_Bye345678\xint_bye + *\xint_c_v+\xint_c_v)/\xint_c_x-\xint_c_i\relax}{#1}% +}% +% \end{macrocode} +% \lverb|B a au plus huit chiffres et est au moins 3. On va l'utiliser +% directement, sans d'abord le multiplier par une puissance de 10 pour qu'il +% ait 8 chiffres.| +% \begin{macrocode} +\def\XINT_div_small_a #1#2% +{% + \expandafter\XINT_div_small_b + \the\numexpr #1/\xint_c_ii\expandafter + \xint:\the\numexpr \xint_c_x^viii+#1\expandafter!% + \romannumeral0% + \XINT_div_small_ba #2\R\R\R\R\R\R\R\R{10}0000001\W + #2\XINT_sepbyviii_Z_end 2345678\relax +}% +% \end{macrocode} +% \lverb|Le #2 poursuivra l'expansion par \XINT_div_dosmallsmall ou par +% \XINT_smalldivx_a suivi de \XINT_sdiv_out.| +% \begin{macrocode} +\def\XINT_div_small_b #1!#2{#2#1!}% +% \end{macrocode} +% \lverb|On ajoute des zéros avant A, puis on le prépare sous la forme de +% blocs 1<8d>! Au passage on repère le cas d'un A<10^8.| +% \begin{macrocode} +\def\XINT_div_small_ba #1#2#3#4#5#6#7#8#9% +{% + \xint_gob_til_R #9\XINT_div_smallsmall\R + \expandafter\XINT_div_dosmalldiv + \the\numexpr\expandafter\XINT_sepbyviii_Z + \romannumeral0\XINT_zeroes_forviii + #1#2#3#4#5#6#7#8#9% +}% +% \end{macrocode} +% \lverb|Si A<10^8, on va poursuivre par \XINT_div_dosmallsmall +% round(B/2).10^8+B!{A}. On fait la division directe par \numexpr. Le résultat +% est produit sous la forme {Q}{R}.| +% \begin{macrocode} +\def\XINT_div_smallsmall\R + \expandafter\XINT_div_dosmalldiv + \the\numexpr\expandafter\XINT_sepbyviii_Z + \romannumeral0\XINT_zeroes_forviii #1\R #2\relax + {{\XINT_div_dosmallsmall}{#1}}% +\def\XINT_div_dosmallsmall #1\xint:1#2!#3% +{% + \expandafter\XINT_div_smallsmallend + \the\numexpr (#3+#1)/#2-\xint_c_i\xint:#2\xint:#3\xint:% +}% +\def\XINT_div_smallsmallend #1\xint:#2\xint:#3\xint:{\expandafter + {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #3-#1*#2}}% +% \end{macrocode} +% \lverb|Si A>=10^8, il est maintenant sous la forme 1<8d>!...1<8d>!1;! avec +% plus significatifs en premier. Donc on poursuit par$newline +% \expandafter\XINT_sdiv_out\the\numexpr\XINT_smalldivx_a +% x.1B!1<8d>!...1<8d>!1;! avec x =round(B/2), 1B=10^8+B.| +% \begin{macrocode} +\def\XINT_div_dosmalldiv + {{\expandafter\XINT_sdiv_out\the\numexpr\XINT_smalldivx_a}}% +% \end{macrocode} +% \lverb|Ici B est au moins 10^8, on détermine combien de zéros lui adjoindre +% pour qu'il soit de longueur 8N.| +% \begin{macrocode} +\def\XINT_div_prepare_b + {\expandafter\XINT_div_prepare_c\romannumeral0\XINT_zeroes_forviii }% +\def\XINT_div_prepare_c #1!% +{% + \XINT_div_prepare_d #1.00000000!{#1}% +}% +\def\XINT_div_prepare_d #1#2#3#4#5#6#7#8#9% +{% + \expandafter\XINT_div_prepare_e\xint_gob_til_dot #1#2#3#4#5#6#7#8#9!% +}% +\def\XINT_div_prepare_e #1!#2!#3#4% +{% + \XINT_div_prepare_f #4#3\X {#1}{#3}% +}% +% \end{macrocode} +% \lverb|attention qu'on calcule ici x'=x+1 (x = huit premiers chiffres du +% diviseur) et que si x=99999999, x' aura donc 9 chiffres, pas compatible avec +% div_mini (avant 1.2, x avait 4 chiffres, et on faisait la division avec x' +% dans un \numexpr). Bon, facile à dire après avoir laissé passer ce bug dans +% 1.2. C'est le problème lorsqu'au lieu de tout refaire à partir de zéro on +% recycle d'anciennes routines qui avaient un contexte différent.| +% \begin{macrocode} +\def\XINT_div_prepare_f #1#2#3#4#5#6#7#8#9\X +{% + \expandafter\XINT_div_prepare_g + \the\numexpr #1#2#3#4#5#6#7#8+\xint_c_i\expandafter + \xint:\the\numexpr (#1#2#3#4#5#6#7#8+\xint_c_i)/\xint_c_ii\expandafter + \xint:\the\numexpr #1#2#3#4#5#6#7#8\expandafter + \xint:\romannumeral0\XINT_sepandrev_andcount + #1#2#3#4#5#6#7#8#9\XINT_rsepbyviii_end_A 2345678% + \XINT_rsepbyviii_end_B 2345678\relax\xint_c_ii\xint_c_i + \R\xint:\xint_c_xii \R\xint:\xint_c_x \R\xint:\xint_c_viii \R\xint:\xint_c_vi + \R\xint:\xint_c_iv \R\xint:\xint_c_ii \R\xint:\xint_c_\W + \X +}% +\def\XINT_div_prepare_g #1\xint:#2\xint:#3\xint:#4\xint:#5\X #6#7#8% +{% + \expandafter\XINT_div_prepare_h + \the\numexpr\expandafter\XINT_sepbyviii_andcount + \romannumeral0\XINT_zeroes_forviii #8#7\R\R\R\R\R\R\R\R{10}0000001\W + #8#7\XINT_sepbyviii_end 2345678\relax + \xint_c_vii!\xint_c_vi!\xint_c_v!\xint_c_iv!% + \xint_c_iii!\xint_c_ii!\xint_c_i!\xint_c_\W + {#1}{#2}{#3}{#4}{#5}{#6}% +}% +\def\XINT_div_prepare_h #11\xint:#2\xint:#3#4#5#6%#7#8% +{% + \XINT_div_start_a {#2}{#6}{#1}{#3}{#4}{#5}%{#7}{#8}% +}% +% \end{macrocode} +% \lverb|L, K, A, x',y,x, B, «c». Attention que K est diminué de 1 plus loin. +% Comme xint 1.2 a déjà repéré K=1, on a ici au minimum K=2. Attention B est à +% l'envers, A est à l'endroit et les deux avec séparateurs. Attention que ce +% n'est pas ici qu'on boucle mais en \XINT_div_I_a.| +% \begin{macrocode} +\def\XINT_div_start_a #1#2% +{% + \ifnum #1 < #2 + \expandafter\XINT_div_zeroQ + \else + \expandafter\XINT_div_start_b + \fi + {#1}{#2}% +}% +\def\XINT_div_zeroQ #1#2#3#4#5#6#7% +{% + \expandafter\XINT_div_zeroQ_end + \romannumeral0\XINT_unsep_cuzsmall + #3\xint_bye!2!3!4!5!6!7!8!9!\xint_bye\xint_c_i\relax\xint: +}% +\def\XINT_div_zeroQ_end #1\xint:#2% + {\expandafter{\expandafter0\expandafter}\XINT_div_cleanR #1#2\xint:}% +% \end{macrocode} +% \lverb|L, K, A, x',y,x, B, «c»->K.A.x{LK{x'y}x}B«c»| +% \begin{macrocode} +\def\XINT_div_start_b #1#2#3#4#5#6% +{% + \expandafter\XINT_div_finish\the\numexpr + \XINT_div_start_c {#2}\xint:#3\xint:{#6}{{#1}{#2}{{#4}{#5}}{#6}}% +}% +\def\XINT_div_finish +{% + \expandafter\XINT_div_finish_a \romannumeral`&&@\XINT_div_unsepQ +}% +\def\XINT_div_finish_a #1\Z #2\xint:{\XINT_div_finish_b #2\xint:{#1}}% +% \end{macrocode} +% \lverb|Ici ce sont routines de fin. Le reste déjà nettoyé. R.Q«c».| +% \begin{macrocode} +\def\XINT_div_finish_b #1% +{% + \if0#1% + \expandafter\XINT_div_finish_bRzero + \else + \expandafter\XINT_div_finish_bRpos + \fi + #1% +}% +\def\XINT_div_finish_bRzero 0\xint:#1#2{{#1}{0}}% +\def\XINT_div_finish_bRpos #1\xint:#2#3% +{% + \expandafter\xint_exchangetwo_keepbraces\XINT_div_cleanR #1#3\xint:{#2}% +}% +\def\XINT_div_cleanR #100000000\xint:{{#1}}% +% \end{macrocode} +% \lverb|Kalpha.A.x{LK{x'y}x}, B, «c», au début #2=alpha est vide. On fait une +% boucle pour prendre K unités de A (on a au moins L égal à K) et les mettre +% dans alpha.| +% \begin{macrocode} +\def\XINT_div_start_c #1% +{% + \ifnum #1>\xint_c_vi + \expandafter\XINT_div_start_ca + \else + \expandafter\XINT_div_start_cb + \fi {#1}% +}% +\def\XINT_div_start_ca #1#2\xint:#3!#4!#5!#6!#7!#8!#9!% +{% + \expandafter\XINT_div_start_c\expandafter + {\the\numexpr #1-\xint_c_vii}#2#3!#4!#5!#6!#7!#8!#9!\xint:% +}% +\def\XINT_div_start_cb #1% + {\csname XINT_div_start_c_\romannumeral\numexpr#1\endcsname}% +\def\XINT_div_start_c_i #1\xint:#2!% + {\XINT_div_start_c_ #1#2!\xint:}% +\def\XINT_div_start_c_ii #1\xint:#2!#3!% + {\XINT_div_start_c_ #1#2!#3!\xint:}% +\def\XINT_div_start_c_iii #1\xint:#2!#3!#4!% + {\XINT_div_start_c_ #1#2!#3!#4!\xint:}% +\def\XINT_div_start_c_iv #1\xint:#2!#3!#4!#5!% + {\XINT_div_start_c_ #1#2!#3!#4!#5!\xint:}% +\def\XINT_div_start_c_v #1\xint:#2!#3!#4!#5!#6!% + {\XINT_div_start_c_ #1#2!#3!#4!#5!#6!\xint:}% +\def\XINT_div_start_c_vi #1\xint:#2!#3!#4!#5!#6!#7!% + {\XINT_div_start_c_ #1#2!#3!#4!#5!#6!#7!\xint:}% +% \end{macrocode} +% \lverb|#1=a, #2=alpha (de longueur K, à l'endroit).#3=reste de A.#4=x, +% #5={LK{x'y}x},#6=B,«c» -> a, x, alpha, B, {00000000}, L, K, {x'y},x, +% alpha'=reste de A, B«c».| +% \begin{macrocode} +\def\XINT_div_start_c_ 1#1!#2\xint:#3\xint:#4#5#6% +{% + \XINT_div_I_a {#1}{#4}{1#1!#2}{#6}{00000000}#5{#3}{#6}% +}% +% \end{macrocode} +% \lverb|Ceci est le point de retour de la boucle principale. a, x, alpha, B, +% q0, L, K, {x'y}, x, alpha', B«c» | +% \begin{macrocode} +\def\XINT_div_I_a #1#2% +{% + \expandafter\XINT_div_I_b\the\numexpr #1/#2\xint:{#1}{#2}% +}% +\def\XINT_div_I_b #1% +{% + \xint_gob_til_zero #1\XINT_div_I_czero 0\XINT_div_I_c #1% +}% +% \end{macrocode} +% \lverb|On intercepte petit quotient nul: #1=a, x, alpha, B, #5=q0, L, K, +% {x'y}, x, alpha', B«c» -> on lâche un q puis {alpha} L, K, {x'y}, x, +% alpha', B«c».| +% \begin{macrocode} +\def\XINT_div_I_czero 0\XINT_div_I_c 0\xint:#1#2#3#4#5{1#5\XINT_div_I_g {#3}}% +\def\XINT_div_I_c #1\xint:#2#3% +{% + \expandafter\XINT_div_I_da\the\numexpr #2-#1*#3\xint:#1\xint:{#2}{#3}% +}% +% \end{macrocode} +% \lverb|r.q.alpha, B, q0, L, K, {x'y}, x, alpha', B«c»| +% \begin{macrocode} +\def\XINT_div_I_da #1\xint:% +{% + \ifnum #1>\xint_c_ix + \expandafter\XINT_div_I_dP + \else + \ifnum #1<\xint_c_ + \expandafter\expandafter\expandafter\XINT_div_I_dN + \else + \expandafter\expandafter\expandafter\XINT_div_I_db + \fi + \fi +}% +% \end{macrocode} +% \lverb|attention très mauvaises notations avec _b et _db.| +% \begin{macrocode} +\def\XINT_div_I_dN #1\xint:% +{% + \expandafter\XINT_div_I_b\the\numexpr #1-\xint_c_i\xint:% +}% +\def\XINT_div_I_db #1\xint:#2#3#4#5% +{% + \expandafter\XINT_div_I_dc\expandafter #1% + \romannumeral0\expandafter\XINT_div_sub\expandafter + {\romannumeral0\XINT_rev_nounsep {}#4\R!\R!\R!\R!\R!\R!\R!\R!\W}% + {\the\numexpr\XINT_div_verysmallmul #1!#51;!}% + \Z {#4}{#5}% +}% +% \end{macrocode} +% \lverb|La soustraction spéciale renvoie simplement - si le chiffre q est +% trop grand. On invoque dans ce cas I_dP.| +% \begin{macrocode} +\def\XINT_div_I_dc #1#2% +{% + \if-#2\expandafter\XINT_div_I_dd\else\expandafter\XINT_div_I_de\fi + #1#2% +}% +\def\XINT_div_I_dd #1-\Z +{% + \if #11\expandafter\XINT_div_I_dz\fi + \expandafter\XINT_div_I_dP\the\numexpr #1-\xint_c_i\xint: XX% +}% +\def\XINT_div_I_dz #1XX#2#3#4% +{% + 1#4\XINT_div_I_g {#2}% +}% +\def\XINT_div_I_de #1#2\Z #3#4#5{1#5+#1\XINT_div_I_g {#2}}% +% \end{macrocode} +% \lverb|q.alpha, B, q0, L, K, {x'y},x, alpha'B«c» (q=0 has been intercepted) +% -> 1nouveauq.nouvel alpha, L, K, {x'y}, x, alpha',B«c»| +% \begin{macrocode} +\def\XINT_div_I_dP #1\xint:#2#3#4#5#6% +{% + 1#6+#1\expandafter\XINT_div_I_g\expandafter + {\romannumeral0\expandafter\XINT_div_sub\expandafter + {\romannumeral0\XINT_rev_nounsep {}#4\R!\R!\R!\R!\R!\R!\R!\R!\W}% + {\the\numexpr\XINT_div_verysmallmul #1!#51;!}% + }% +}% +% \end{macrocode} +% \lverb|1#1=nouveau q. nouvel alpha, L, K, {x'y},x,alpha', BQ«c»| +% \begin{macrocode} +% \end{macrocode} +% \lverb|#1=q,#2=nouvel alpha,#3=L, #4=K, #5={x'y}, #6=x, #7= alpha',#8=B, +% «c» -> on laisse q puis {x'y}alpha.alpha'.{{x'y}xKL}B«c»| +% \begin{macrocode} +\def\XINT_div_I_g #1#2#3#4#5#6#7% +{% + \expandafter !\the\numexpr + \ifnum#2=#3 + \expandafter\XINT_div_exittofinish + \else + \expandafter\XINT_div_I_h + \fi + {#4}#1\xint:#6\xint:{{#4}{#5}{#3}{#2}}{#7}% +}% +% \end{macrocode} +% \lverb|{x'y}alpha.alpha'.{{x'y}xKL}B«c» -> Attention retour à l'envoyeur ici +% par terminaison des \the\numexpr. On doit reprendre le Q déjà sorti, qui n'a +% plus de séparateurs, ni de leading 1. Ensuite R sans leading zeros.«c»| +% \begin{macrocode} +\def\XINT_div_exittofinish #1#2\xint:#3\xint:#4#5% +{% + 1\expandafter\expandafter\expandafter!\expandafter\XINT_div_unsepQ_delim + \romannumeral0\XINT_div_unsepR #2#3% + \xint_bye!2!3!4!5!6!7!8!9!\xint_bye\xint_c_i\relax\R\xint: +}% +% \end{macrocode} +% \lverb|ATTENTION DESCRIPTION OBSOLÈTE. #1={x'y}alpha.#2!#3=reste de A. +% #4={{x'y},x,K,L},#5=B,«c» devient {x'y},alpha sur K+4 chiffres.B, +% {{x'y},x,K,L}, #6= nouvel alpha',B,«c»| +% \begin{macrocode} +\def\XINT_div_I_h #1\xint:#2!#3\xint:#4#5% +{% + \XINT_div_II_b #1#2!\xint:{#5}{#4}{#3}{#5}% +}% +% \end{macrocode} +% \lverb|{x'y}alpha.B, {{x'y},x,K,L}, nouveau alpha',B,«c»| +% \begin{macrocode} +\def\XINT_div_II_b #11#2!#3!% +{% + \xint_gob_til_eightzeroes #2\XINT_div_II_skipc 00000000% + \XINT_div_II_c #1{1#2}{#3}% +}% +% \end{macrocode} +% \lverb|x'y{100000000}{1<8>}reste de alpha.#6=B,#7={{x'y},x,K,L}, alpha',B, +% «c» -> {x'y}x,K,L (à diminuer de 4), {alpha sur +% K}B{q1=00000000}{alpha'}B,«c»| +% \begin{macrocode} +\def\XINT_div_II_skipc 00000000\XINT_div_II_c #1#2#3#4#5\xint:#6#7% +{% + \XINT_div_II_k #7{#4!#5}{#6}{00000000}% +}% +% \end{macrocode} +% \lverb|x'ya->1qx'yalpha.B, {{x'y},x,K,L}, nouveau alpha',B, «c». En fait, +% attention, ici #3 et #4 sont les 16 premiers chiffres du numérateur,sous la +% forme blocs 1<8chiffres>. +% | +% \begin{macrocode} +\def\XINT_div_II_c #1#2#3#4% +{% + \expandafter\XINT_div_II_d\the\numexpr\XINT_div_xmini + #1\xint:#2!#3!#4!{#1}{#2}#3!#4!% +}% +\def\XINT_div_xmini #1% +{% + \xint_gob_til_one #1\XINT_div_xmini_a 1\XINT_div_mini #1% +}% +\def\XINT_div_xmini_a 1\XINT_div_mini 1#1% +{% + \xint_gob_til_zero #1\XINT_div_xmini_b 0\XINT_div_mini 1#1% +}% +\def\XINT_div_xmini_b 0\XINT_div_mini 10#1#2#3#4#5#6#7% +{% + \xint_gob_til_zero #7\XINT_div_xmini_c 0\XINT_div_mini 10#1#2#3#4#5#6#7% +}% +% \end{macrocode} +% \lverb|x'=10^8 and we return #1=1<8digits>.| +% \begin{macrocode} +\def\XINT_div_xmini_c 0\XINT_div_mini 100000000\xint:50000000!#1!#2!{#1!}% +% \end{macrocode} +% \lverb|1 suivi de q1 sur huit chiffres! #2=x', #3=y, #4=alpha.#5=B, +% {{x'y},x,K,L}, alpha', B, «c» --> nouvel alpha.x',y,B,q1,{{x'y},x,K,L}, +% alpha', B, «c» | +% \begin{macrocode} +\def\XINT_div_II_d 1#1#2#3#4#5!#6#7#8\xint:#9% +{% + \expandafter\XINT_div_II_e + \romannumeral0\expandafter\XINT_div_sub\expandafter + {\romannumeral0\XINT_rev_nounsep {}#8\R!\R!\R!\R!\R!\R!\R!\R!\W}% + {\the\numexpr\XINT_div_smallmul_a 100000000\xint:#1#2#3#4\xint:#5!#91;!}% + \xint:{#6}{#7}{#9}{#1#2#3#4#5}% +}% +% \end{macrocode} +% \lverb|alpha.x',y,B,q1, {{x'y},x,K,L}, alpha', B, «c». Attention la +% soustraction spéciale doit maintenir les blocs 1<8>!| +% \begin{macrocode} +\def\XINT_div_II_e 1#1!% +{% + \xint_gob_til_eightzeroes #1\XINT_div_II_skipf 00000000% + \XINT_div_II_f 1#1!% +}% +% \end{macrocode} +% \lverb|100000000! alpha sur K chiffres.#2=x',#3=y,#4=B,#5=q1, #6={{x'y},x,K,L}, +% #7=alpha',B«c» -> {x'y}x,K,L (à diminuer de 1), +% {alpha sur K}B{q1}{alpha'}B«c»| +% \begin{macrocode} +\def\XINT_div_II_skipf 00000000\XINT_div_II_f 100000000!#1\xint:#2#3#4#5#6% +{% + \XINT_div_II_k #6{#1}{#4}{#5}% +}% +% \end{macrocode} +% \lverb|1<a1>!1<a2>!, alpha (sur K+1 blocs de 8). x', y, B, q1, {{x'y},x,K,L}, +% alpha', B,«c». +% +% Here also we are dividing with x' which could be 10^8 in the exceptional +% case x=99999999. Must intercept it before sending to \XINT_div_mini.| +% \begin{macrocode} +\def\XINT_div_II_f #1!#2!#3\xint:% +{% + \XINT_div_II_fa {#1!#2!}{#1!#2!#3}% +}% +\def\XINT_div_II_fa #1#2#3#4% +{% + \expandafter\XINT_div_II_g \the\numexpr\XINT_div_xmini #3\xint:#4!#1{#2}% +}% +% \end{macrocode} +% \lverb|#1=q, #2=alpha (K+4), #3=B, #4=q1, {{x'y},x,K,L}, alpha', BQ«c» +% -> 1 puis nouveau q sur 8 chiffres. nouvel alpha sur K blocs, +% B, {{x'y},x,K,L}, alpha',B«c» | +% \begin{macrocode} +\def\XINT_div_II_g 1#1#2#3#4#5!#6#7#8% +{% + \expandafter \XINT_div_II_h + \the\numexpr 1#1#2#3#4#5+#8\expandafter\expandafter\expandafter + \xint:\expandafter\expandafter\expandafter + {\expandafter\xint_gob_til_exclam + \romannumeral0\expandafter\XINT_div_sub\expandafter + {\romannumeral0\XINT_rev_nounsep {}#6\R!\R!\R!\R!\R!\R!\R!\R!\W}% + {\the\numexpr\XINT_div_smallmul_a 100000000\xint:#1#2#3#4\xint:#5!#71;!}}% + {#7}% +}% +% \end{macrocode} +% \lverb|1 puis nouveau q sur 8 chiffres, #2=nouvel alpha sur K blocs, +% #3=B, #4={{x'y},x,K,L} avec L à ajuster, alpha', BQ«c» +% -> {x'y}x,K,L à diminuer de 1, {alpha}B{q}, alpha', BQ«c»| +% \begin{macrocode} +\def\XINT_div_II_h 1#1\xint:#2#3#4% +{% + \XINT_div_II_k #4{#2}{#3}{#1}% +}% +% \end{macrocode} +% \lverb|{x'y}x,K,L à diminuer de 1, alpha, B{q}alpha',B«c» +% ->nouveau L.K,x',y,x,alpha.B,q,alpha',B,«c» +% ->{LK{x'y}x},x,a,alpha.B,q,alpha',B,«c»| +% \begin{macrocode} +\def\XINT_div_II_k #1#2#3#4#5% +{% + \expandafter\XINT_div_II_l \the\numexpr #4-\xint_c_i\xint:{#3}#1{#2}#5\xint:% +}% +\def\XINT_div_II_l #1\xint:#2#3#4#51#6!% +{% + \XINT_div_II_m {{#1}{#2}{{#3}{#4}}{#5}}{#5}{#6}1#6!% +}% +% \end{macrocode} +% \lverb|{LK{x'y}x},x,a,alpha.B{q}alpha'B -> a, x, alpha, B, q, +% L, K, {x'y}, x, alpha', B«c» | +% \begin{macrocode} +\def\XINT_div_II_m #1#2#3#4\xint:#5#6% +{% + \XINT_div_I_a {#3}{#2}{#4}{#5}{#6}#1% +}% +% \end{macrocode} +% \lverb|This multiplication is exactly like \XINT_smallmul -- apart from not +% inserting an ending 1;! --, but keeps ever a vanishing ending carry.| +% \begin{macrocode} +\def\XINT_div_minimulwc_a 1#1\xint:#2\xint:#3!#4#5#6#7#8\xint:% +{% + \expandafter\XINT_div_minimulwc_b + \the\numexpr \xint_c_x^ix+#1+#3*#8\xint:#3*#4#5#6#7+#2*#8\xint:#2*#4#5#6#7\xint:% +}% +\def\XINT_div_minimulwc_b 1#1#2#3#4#5#6\xint:#7\xint:% +{% + \expandafter\XINT_div_minimulwc_c + \the\numexpr \xint_c_x^ix+#1#2#3#4#5+#7\xint:#6\xint:% +}% +\def\XINT_div_minimulwc_c 1#1#2#3#4#5#6\xint:#7\xint:#8\xint:% +{% + 1#6#7\expandafter!% + \the\numexpr\expandafter\XINT_div_smallmul_a + \the\numexpr \xint_c_x^viii+#1#2#3#4#5+#8\xint:% +}% +\def\XINT_div_smallmul_a #1\xint:#2\xint:#3!1#4!% +{% + \xint_gob_til_sc #4\XINT_div_smallmul_e;% + \XINT_div_minimulwc_a #1\xint:#2\xint:#3!#4\xint:#2\xint:#3!% +}% +\def\XINT_div_smallmul_e;\XINT_div_minimulwc_a 1#1\xint:#2;#3!{1\relax #1!}% +% \end{macrocode} +% \lverb|Special very small multiplication for division. We only need to cater +% for multiplicands from 1 to 9. The ending is different from standard +% verysmallmul, a zero carry is not suppressed. And no final 1;! is added. If +% multiplicand is just 1 let's not forget to add the zero carry 100000000! at +% the end.| +% \begin{macrocode} +\def\XINT_div_verysmallmul #1% + {\xint_gob_til_one #1\XINT_div_verysmallisone 1\XINT_div_verysmallmul_a 0\xint:#1}% +\def\XINT_div_verysmallisone 1\XINT_div_verysmallmul_a 0\xint:1!1#11;!% + {1\relax #1100000000!}% +\def\XINT_div_verysmallmul_a #1\xint:#2!1#3!% +{% + \xint_gob_til_sc #3\XINT_div_verysmallmul_e;% + \expandafter\XINT_div_verysmallmul_b + \the\numexpr \xint_c_x^ix+#2*#3+#1\xint:#2!% +}% +\def\XINT_div_verysmallmul_b 1#1#2\xint:% + {1#2\expandafter!\the\numexpr\XINT_div_verysmallmul_a #1\xint:}% +\def\XINT_div_verysmallmul_e;#1;+#2#3!{1\relax 0000000#2!}% +% \end{macrocode} +% \lverb|Special subtraction for division purposes. If the subtracted thing +% turns out to be bigger, then just return a -. If not, then we must reverse +% the result, keeping the separators.| +% \begin{macrocode} +\def\XINT_div_sub #1#2% +{% + \expandafter\XINT_div_sub_clean + \the\numexpr\expandafter\XINT_div_sub_a\expandafter + 1#2;!;!;!;!;!\W #1;!;!;!;!;!\W +}% +\def\XINT_div_sub_clean #1-#2#3\W +{% + \if1#2\expandafter\XINT_rev_nounsep\else\expandafter\XINT_div_sub_neg\fi + {}#1\R!\R!\R!\R!\R!\R!\R!\R!\W +}% +\def\XINT_div_sub_neg #1\W { -}% +\def\XINT_div_sub_a #1!#2!#3!#4!#5\W #6!#7!#8!#9!% +{% + \XINT_div_sub_b #1!#6!#2!#7!#3!#8!#4!#9!#5\W +}% +\def\XINT_div_sub_b #1#2#3!#4!% +{% + \xint_gob_til_sc #4\XINT_div_sub_bi ;% + \expandafter\XINT_div_sub_c\the\numexpr#1-#3+1#4-\xint_c_i\xint:% +}% +\def\XINT_div_sub_c 1#1#2\xint:% +{% + 1#2\expandafter!\the\numexpr\XINT_div_sub_d #1% +}% +\def\XINT_div_sub_d #1#2#3!#4!% +{% + \xint_gob_til_sc #4\XINT_div_sub_di ;% + \expandafter\XINT_div_sub_e\the\numexpr#1-#3+1#4-\xint_c_i\xint:% +}% +\def\XINT_div_sub_e 1#1#2\xint:% +{% + 1#2\expandafter!\the\numexpr\XINT_div_sub_f #1% +}% +\def\XINT_div_sub_f #1#2#3!#4!% +{% + \xint_gob_til_sc #4\XINT_div_sub_fi ;% + \expandafter\XINT_div_sub_g\the\numexpr#1-#3+1#4-\xint_c_i\xint:% +}% +\def\XINT_div_sub_g 1#1#2\xint:% +{% + 1#2\expandafter!\the\numexpr\XINT_div_sub_h #1% +}% +\def\XINT_div_sub_h #1#2#3!#4!% +{% + \xint_gob_til_sc #4\XINT_div_sub_hi ;% + \expandafter\XINT_div_sub_i\the\numexpr#1-#3+1#4-\xint_c_i\xint:% +}% +\def\XINT_div_sub_i 1#1#2\xint:% +{% + 1#2\expandafter!\the\numexpr\XINT_div_sub_a #1% +}% +\def\XINT_div_sub_bi;% + \expandafter\XINT_div_sub_c\the\numexpr#1-#2+#3\xint:#4!#5!#6!#7!#8!#9!;!\W +{% + \XINT_div_sub_l #1#2!#5!#7!#9!% +}% +\def\XINT_div_sub_di;% + \expandafter\XINT_div_sub_e\the\numexpr#1-#2+#3\xint:#4!#5!#6!#7!#8\W +{% + \XINT_div_sub_l #1#2!#5!#7!% +}% +\def\XINT_div_sub_fi;% + \expandafter\XINT_div_sub_g\the\numexpr#1-#2+#3\xint:#4!#5!#6\W +{% + \XINT_div_sub_l #1#2!#5!% +}% +\def\XINT_div_sub_hi;% + \expandafter\XINT_div_sub_i\the\numexpr#1-#2+#3\xint:#4\W +{% + \XINT_div_sub_l #1#2!% +}% +\def\XINT_div_sub_l #1% +{% + \xint_UDzerofork + #1{-2\relax}% + 0\XINT_div_sub_r + \krof +}% +\def\XINT_div_sub_r #1!% +{% + -\ifnum 0#1=\xint_c_ 1\else2\fi\relax +}% +% \end{macrocode} +% \lverb|Ici B<10^8 (et est >2). On +% exécute$newline +% \expandafter\XINT_sdiv_out\the\numexpr\XINT_smalldivx_a +% x.1B!1<8d>!...1<8d>!1;!$newline +% avec x =round(B/2), 1B=10^8+B, et A déjà en +% blocs 1<8d>! (non renversés). Le \the\numexpr\XINT_smalldivx_a va produire +% Q\Z R\W avec un R<10^8, et un Q sous forme de blocs 1<8d>! terminé par 1! +% et nécessitant le nettoyage du premier bloc. Dans cette branche le B n'a pas +% été multiplié par une puissance de 10, il peut avoir moins de huit chiffres. +% +% | +% \begin{macrocode} +\def\XINT_sdiv_out #1;!#2!% + {\expandafter + {\romannumeral0\XINT_unsep_cuzsmall + #1\xint_bye!2!3!4!5!6!7!8!9!\xint_bye\xint_c_i\relax}% + {#2}}% +% \end{macrocode} +% \lverb|La toute première étape fait la première division pour être sûr par +% la suite d'avoir un premier bloc pour A qui sera < B.| +% \begin{macrocode} +\def\XINT_smalldivx_a #1\xint:1#2!1#3!% +{% + \expandafter\XINT_smalldivx_b + \the\numexpr (#3+#1)/#2-\xint_c_i!#1\xint:#2!#3!% +}% +\def\XINT_smalldivx_b #1#2!% +{% + \if0#1\else + \xint_c_x^viii+#1#2\xint_afterfi{\expandafter!\the\numexpr}\fi + \XINT_smalldiv_c #1#2!% +}% +\def\XINT_smalldiv_c #1!#2\xint:#3!#4!% +{% + \expandafter\XINT_smalldiv_d\the\numexpr #4-#1*#3!#2\xint:#3!% +}% +% \end{macrocode} +% \lverb|On va boucler ici: #1 est un reste, #2 est x.B (avec B sans le 1 mais +% sur huit chiffres). #3#4 est le premier bloc qui reste de A. Si on a terminé +% avec A, alors #1 est le reste final. Le quotient lui est terminé par un 1! +% ce 1! disparaîtra dans le nettoyage par \XINT_unsep_cuzsmall. +% | +% \begin{macrocode} +\def\XINT_smalldiv_d #1!#2!1#3#4!% +{% + \xint_gob_til_sc #3\XINT_smalldiv_end ;% + \XINT_smalldiv_e #1!#2!1#3#4!% +}% +\def\XINT_smalldiv_end;\XINT_smalldiv_e #1!#2!1;!{1!;!#1!}% +% \end{macrocode} +% \lverb|Il est crucial que le reste #1 est < #3. J'ai documenté cette routine +% dans le fichier où j'ai préparé 1.2, il faudra transférer ici. Il n'est pas +% nécessaire pour cette routine que le diviseur B ait au moins 8 chiffres. +% Mais il doit être < 10^8.| +% \begin{macrocode} +\def\XINT_smalldiv_e #1!#2\xint:#3!% +{% + \expandafter\XINT_smalldiv_f\the\numexpr + \xint_c_xi_e_viii_mone+#1*\xint_c_x^viii/#3!#2\xint:#3!#1!% +}% +\def\XINT_smalldiv_f 1#1#2#3#4#5#6!#7\xint:#8!% +{% + \xint_gob_til_zero #1\XINT_smalldiv_fz 0% + \expandafter\XINT_smalldiv_g + \the\numexpr\XINT_minimul_a #2#3#4#5\xint:#6!#8!#2#3#4#5#6!#7\xint:#8!% +}% +\def\XINT_smalldiv_fz 0% + \expandafter\XINT_smalldiv_g\the\numexpr\XINT_minimul_a + 9999\xint:9999!#1!99999999!#2!0!1#3!% +{% + \XINT_smalldiv_i \xint:#3!\xint_c_!#2!% +}% +\def\XINT_smalldiv_g 1#1!1#2!#3!#4!#5!#6!% +{% + \expandafter\XINT_smalldiv_h\the\numexpr 1#6-#1\xint:#2!#5!#3!#4!% +}% +\def\XINT_smalldiv_h 1#1#2\xint:#3!#4!% +{% + \expandafter\XINT_smalldiv_i\the\numexpr #4-#3+#1-\xint_c_i\xint:#2!% +}% +\def\XINT_smalldiv_i #1\xint:#2!#3!#4\xint:#5!% +{% + \expandafter\XINT_smalldiv_j\the\numexpr (#1#2+#4)/#5-\xint_c_i!#3!#1#2!#4\xint:#5!% +}% +\def\XINT_smalldiv_j #1!#2!% +{% + \xint_c_x^viii+#1+#2\expandafter!\the\numexpr\XINT_smalldiv_k + #1!% +}% +% \end{macrocode} +% \lverb|On boucle vers \XINT_smalldiv_d.| +% \begin{macrocode} +\def\XINT_smalldiv_k #1!#2!#3\xint:#4!% +{% + \expandafter\XINT_smalldiv_d\the\numexpr #2-#1*#4!#3\xint:#4!% +}% +% \end{macrocode} +% \lverb|Cette routine fait la division euclidienne d'un nombre de seize +% chiffres par #1 = C = diviseur sur huit chiffres >= 10^7, avec #2 = sa +% moitié utilisée dans \numexpr pour contrebalancer l'arrondi +% (ARRRRRRGGGGGHHHH) fait par /. Le nombre divisé XY = X*10^8+Y se présente +% sous la forme 1<8chiffres>!1<8chiffres>! avec plus significatif en premier. +% +% Seul le quotient est calculé, pas le reste. En effet la routine de division +% principale va utiliser ce quotient pour déterminer le "grand" reste, et le +% petit reste ici ne nous serait d'à peu près aucune utilité. +% +% ATTENTION UNIQUEMENT UTILISÉ POUR DES SITUATIONS OÙ IL EST GARANTI QUE X < +% C ! (et C au moins 10^7) le quotient euclidien de X*10^8+Y par C sera donc < +% 10^8. Il sera renvoyé sous la forme 1<8chiffres>.| +% \begin{macrocode} +\def\XINT_div_mini #1\xint:#2!1#3!% +{% + \expandafter\XINT_div_mini_a\the\numexpr + \xint_c_xi_e_viii_mone+#3*\xint_c_x^viii/#1!#1\xint:#2!#3!% +}% +% \end{macrocode} +% \lverb|Note (2015/10/08). Attention à la différence dans l'ordre des +% arguments avec ce que je vois en dans \XINT_smalldiv_f. Je ne me souviens +% plus du tout s'il y a une raison quelconque.| +% \begin{macrocode} +\def\XINT_div_mini_a 1#1#2#3#4#5#6!#7\xint:#8!% +{% + \xint_gob_til_zero #1\XINT_div_mini_w 0% + \expandafter\XINT_div_mini_b + \the\numexpr\XINT_minimul_a #2#3#4#5\xint:#6!#7!#2#3#4#5#6!#7\xint:#8!% +}% +\def\XINT_div_mini_w 0% + \expandafter\XINT_div_mini_b\the\numexpr\XINT_minimul_a + 9999\xint:9999!#1!99999999!#2\xint:#3!00000000!#4!% +{% + \xint_c_x^viii_mone+(#4+#3)/#2!% +}% +\def\XINT_div_mini_b 1#1!1#2!#3!#4!#5!#6!% +{% + \expandafter\XINT_div_mini_c + \the\numexpr 1#6-#1\xint:#2!#5!#3!#4!% +}% +\def\XINT_div_mini_c 1#1#2\xint:#3!#4!% +{% + \expandafter\XINT_div_mini_d + \the\numexpr #4-#3+#1-\xint_c_i\xint:#2!% +}% +\def\XINT_div_mini_d #1\xint:#2!#3!#4\xint:#5!% +{% + \xint_c_x^viii_mone+#3+(#1#2+#5)/#4!% +}% +% \end{macrocode} +% \subsection*{Derived arithmetic} +% \addcontentsline{toc}{subsection}{Derived arithmetic} +% \subsection{\csh{xintiiQuo}, \csh{xintiiRem}} +% \begin{macrocode} +\def\xintiiQuo {\romannumeral0\xintiiquo }% +\def\xintiiRem {\romannumeral0\xintiirem }% +\def\xintiiquo + {\expandafter\xint_stop_atfirstoftwo\romannumeral0\xintiidivision }% +\def\xintiirem + {\expandafter\xint_stop_atsecondoftwo\romannumeral0\xintiidivision }% +% \end{macrocode} +% \subsection{\csh{xintiiDivRound}} +% \lverb|1.1, transferred from first release of bnumexpr. Rewritten for 1.2. +% Ending rewritten for 1.2i. (new \xintDSRr). +% +% 1.2l: \xintiiDivRound made robust against non terminated input.| +% \begin{macrocode} +\def\xintiiDivRound {\romannumeral0\xintiidivround }% +\def\xintiidivround #1{\expandafter\XINT_iidivround\romannumeral`&&@#1\xint:}% +\def\XINT_idivround #1#2\xint:#3% + {\expandafter\XINT_iidivround_a\expandafter #1% + \romannumeral0\xintnum{#3}\xint:#2\xint:}% +\def\XINT_iidivround #1#2\xint:#3% + {\expandafter\XINT_iidivround_a\expandafter #1\romannumeral`&&@#3\xint:#2\xint:}% +\def\XINT_iidivround_a #1#2% #1 de A, #2 de B. +{% + \if0#2\xint_dothis{\XINT_iidivround_divbyzero#1#2}\fi + \if0#1\xint_dothis\XINT_iidivround_aiszero\fi + \if-#2\xint_dothis{\XINT_iidivround_bneg #1}\fi + \xint_orthat{\XINT_iidivround_bpos #1#2}% +}% +\def\XINT_iidivround_divbyzero #1#2#3\xint:#4\xint: + {\XINT_signalcondition{DivisionByZero}{Division of #1#4 by #2#3}{}{0}}% +\def\XINT_iidivround_aiszero #1\xint:#2\xint:{ 0}% +\def\XINT_iidivround_bpos #1% +{% + \xint_UDsignfork + #1{\xintiiopp\XINT_iidivround_pos {}}% + -{\XINT_iidivround_pos #1}% + \krof +}% +\def\XINT_iidivround_bneg #1% +{% + \xint_UDsignfork + #1{\XINT_iidivround_pos {}}% + -{\xintiiopp\XINT_iidivround_pos #1}% + \krof +}% +\def\XINT_iidivround_pos #1#2\xint:#3\xint: +{% + \expandafter\expandafter\expandafter\XINT_dsrr + \expandafter\xint_firstoftwo + \romannumeral0\XINT_div_prepare {#2}{#1#30}% + \xint_bye\xint_Bye3456789\xint_bye/\xint_c_x\relax +}% +% \end{macrocode} +% \subsection{\csh{xintiiDivTrunc}} +% \lverb|1.2l: \xintiiDivTrunc made robust against non terminated input.| +% \begin{macrocode} +\def\xintiiDivTrunc {\romannumeral0\xintiidivtrunc }% +\def\xintiidivtrunc #1{\expandafter\XINT_iidivtrunc\romannumeral`&&@#1\xint:}% +\def\XINT_iidivtrunc #1#2\xint:#3{\expandafter\XINT_iidivtrunc_a\expandafter #1% + \romannumeral`&&@#3\xint:#2\xint:}% +\def\XINT_iidivtrunc_a #1#2% #1 de A, #2 de B. +{% + \if0#2\xint_dothis{\XINT_iidivtrunc_divbyzero#1#2}\fi + \if0#1\xint_dothis\XINT_iidivtrunc_aiszero\fi + \if-#2\xint_dothis{\XINT_iidivtrunc_bneg #1}\fi + \xint_orthat{\XINT_iidivtrunc_bpos #1#2}% +}% +% \end{macrocode} +% \lverb|Attention to not move DivRound code beyond that point.| +% \begin{macrocode} +\let\XINT_iidivtrunc_divbyzero\XINT_iidivround_divbyzero +\let\XINT_iidivtrunc_aiszero \XINT_iidivround_aiszero +\def\XINT_iidivtrunc_bpos #1% +{% + \xint_UDsignfork + #1{\xintiiopp\XINT_iidivtrunc_pos {}}% + -{\XINT_iidivtrunc_pos #1}% + \krof +}% +\def\XINT_iidivtrunc_bneg #1% +{% + \xint_UDsignfork + #1{\XINT_iidivtrunc_pos {}}% + -{\xintiiopp\XINT_iidivtrunc_pos #1}% + \krof +}% +\def\XINT_iidivtrunc_pos #1#2\xint:#3\xint: + {\expandafter\xint_stop_atfirstoftwo + \romannumeral0\XINT_div_prepare {#2}{#1#3}}% +% \end{macrocode} +% \subsection{\csh{xintiiModTrunc}} +% \lverb|Renamed from \xintiiMod to \xintiiModTrunc at 1.2p.| +% \begin{macrocode} +\def\xintiiModTrunc {\romannumeral0\xintiimodtrunc }% +\def\xintiimodtrunc #1{\expandafter\XINT_iimodtrunc\romannumeral`&&@#1\xint:}% +\def\XINT_iimodtrunc #1#2\xint:#3{\expandafter\XINT_iimodtrunc_a\expandafter #1% + \romannumeral`&&@#3\xint:#2\xint:}% +\def\XINT_iimodtrunc_a #1#2% #1 de A, #2 de B. +{% + \if0#2\xint_dothis{\XINT_iimodtrunc_divbyzero#1#2}\fi + \if0#1\xint_dothis\XINT_iimodtrunc_aiszero\fi + \if-#2\xint_dothis{\XINT_iimodtrunc_bneg #1}\fi + \xint_orthat{\XINT_iimodtrunc_bpos #1#2}% +}% +% \end{macrocode} +% \lverb|Attention to not move DivRound code beyond that point. A bit of abuse +% here for divbyzero defaulted-to value, which happily works in both.| +% \begin{macrocode} +\let\XINT_iimodtrunc_divbyzero\XINT_iidivround_divbyzero +\let\XINT_iimodtrunc_aiszero \XINT_iidivround_aiszero +\def\XINT_iimodtrunc_bpos #1% +{% + \xint_UDsignfork + #1{\xintiiopp\XINT_iimodtrunc_pos {}}% + -{\XINT_iimodtrunc_pos #1}% + \krof +}% +\def\XINT_iimodtrunc_bneg #1% +{% + \xint_UDsignfork + #1{\xintiiopp\XINT_iimodtrunc_pos {}}% + -{\XINT_iimodtrunc_pos #1}% + \krof +}% +\def\XINT_iimodtrunc_pos #1#2\xint:#3\xint: + {\expandafter\xint_stop_atsecondoftwo\romannumeral0\XINT_div_prepare + {#2}{#1#3}}% +% \end{macrocode} +% \subsection{\csh{xintiiDivMod}} +% \changed{1.2p}{} +% It is associated with floored division (like Python divmod +% function), and with the |//| operator in \csbxint{iiexpr}. +% \begin{macrocode} +\def\xintiiDivMod {\romannumeral0\xintiidivmod }% +\def\xintiidivmod #1{\expandafter\XINT_iidivmod\romannumeral`&&@#1\xint:}% +\def\XINT_iidivmod #1#2\xint:#3{\expandafter\XINT_iidivmod_a\expandafter #1% + \romannumeral`&&@#3\xint:#2\xint:}% +\def\XINT_iidivmod_a #1#2% #1 de A, #2 de B. +{% + \if0#2\xint_dothis{\XINT_iidivmod_divbyzero#1#2}\fi + \if0#1\xint_dothis\XINT_iidivmod_aiszero\fi + \if-#2\xint_dothis{\XINT_iidivmod_bneg #1}\fi + \xint_orthat{\XINT_iidivmod_bpos #1#2}% +}% +\def\XINT_iidivmod_divbyzero #1#2\xint:#3\xint: +{% + \XINT_signalcondition{DivisionByZero}{Division by #2 of #1#3}{}% + {{0}{0}}% à revoir... +}% +\def\XINT_iidivmod_aiszero #1\xint:#2\xint:{{0}{0}}% +\def\XINT_iidivmod_bneg #1% +{% + \expandafter\XINT_iidivmod_bneg_finish + \romannumeral0\xint_UDsignfork + #1{\XINT_iidivmod_bpos {}}% + -{\XINT_iidivmod_bpos {-#1}}% + \krof +}% +\def\XINT_iidivmod_bneg_finish#1#2% +{% + \expandafter\xint_exchangetwo_keepbraces\expandafter + {\romannumeral0\xintiiopp#2}{#1}% +}% +\def\XINT_iidivmod_bpos #1#2\xint:#3\xint:{\xintiidivision{#1#3}{#2}}% +% \end{macrocode} +% \subsection{\csh{xintiiDivFloor}} +% \lverb|1.2p. For bnumexpr actually, because \xintiiexpr could use +% \xintDivFloor which also outputs an integer in strict format.| +% \begin{macrocode} +\def\xintiiDivFloor {\romannumeral0\xintiidivfloor}% +\def\xintiidivfloor {\expandafter\xint_stop_atfirstoftwo + \romannumeral0\xintiidivmod}% +% \end{macrocode} +% \subsection{\csh{xintiiMod}} +% \lverb|Associated with floored division at 1.2p. Formerly was associated with +% truncated division.| +% \begin{macrocode} +\def\xintiiMod {\romannumeral0\xintiimod}% +\def\xintiimod {\expandafter\xint_stop_atsecondoftwo + \romannumeral0\xintiidivmod}% +% \end{macrocode} +% \subsection{\csh{xintiiSqr}} +% \lverb|1.2l: \xintiiSqr made robust against non terminated input.| +% \begin{macrocode} +\def\xintiiSqr {\romannumeral0\xintiisqr }% +\def\xintiisqr #1% +{% + \expandafter\XINT_sqr\romannumeral0\xintiiabs{#1}\xint: +}% +\def\XINT_sqr #1\xint: +{% + \expandafter\XINT_sqr_a + \romannumeral0\expandafter\XINT_sepandrev_andcount + \romannumeral0\XINT_zeroes_forviii #1\R\R\R\R\R\R\R\R{10}0000001\W + #1\XINT_rsepbyviii_end_A 2345678% + \XINT_rsepbyviii_end_B 2345678\relax\xint_c_ii\xint_c_i + \R\xint:\xint_c_xii \R\xint:\xint_c_x \R\xint:\xint_c_viii \R\xint:\xint_c_vi + \R\xint:\xint_c_iv \R\xint:\xint_c_ii \R\xint:\xint_c_\W + \xint: +}% +% \end{macrocode} +% \lverb|1.2c \XINT_mul_loop can now be called directly even with small +% arguments, thus the following check is not anymore a necessity.| +% \begin{macrocode} +\def\XINT_sqr_a #1\xint: +{% + \ifnum #1=\xint_c_i \expandafter\XINT_sqr_small + \else\expandafter\XINT_sqr_start\fi +}% +\def\XINT_sqr_small 1#1#2#3#4#5!\xint: +{% + \ifnum #1#2#3#4#5<46341 \expandafter\XINT_sqr_verysmall\fi + \expandafter\XINT_sqr_small_out + \the\numexpr\XINT_minimul_a #1#2#3#4\xint:#5!#1#2#3#4#5!% +}% +\def\XINT_sqr_verysmall#1{% +\def\XINT_sqr_verysmall + \expandafter\XINT_sqr_small_out\the\numexpr\XINT_minimul_a ##1!##2!% + {\expandafter#1\the\numexpr ##2*##2\relax}% +}\XINT_sqr_verysmall{ }% +\def\XINT_sqr_small_out 1#1!1#2!% +{% + \XINT_cuz #2#1\R +}% +% \end{macrocode} +% \lverb|An ending 1;! is produced on output for \XINT_mul_loop and gets +% incorporated to the delimiter needed by the \XINT_unrevbyviii done by +% \XINT_mul_out.| +% \begin{macrocode} +\def\XINT_sqr_start #1\xint: +{% + \expandafter\XINT_mul_out + \the\numexpr\XINT_mul_loop + 100000000!1;!\W #11;!\W #11;!% + 1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W +}% +% \end{macrocode} +% \subsection{\csh{xintiiPow}} +% \lverb|& +% The exponent is not limited but with current default settings of tex memory, +% with xint 1.2, the maximal exponent for 2^N is N = 2^17 = 131072. +% +% 1.2f Modifies the initial steps: 1) in order to be able to let more easily +% \xintiPow use \xintNum on the exponent once xintfrac.sty is loaded; 2) also +% because I noticed it was not very well coded. And it did only a \numexpr on +% the exponent, contradicting the documentation related to the "i" convention +% in names. +% +% 1.2l: \xintiiPow made robust against non terminated input.| +% \begin{macrocode} +\def\xintiiPow {\romannumeral0\xintiipow }% +\def\xintiipow #1#2% +{% + \expandafter\xint_pow\the\numexpr #2\expandafter + .\romannumeral`&&@#1\xint: +}% +\def\xint_pow #1.#2%#3\xint: +{% + \xint_UDzerominusfork + #2-\XINT_pow_AisZero + 0#2\XINT_pow_Aneg + 0-{\XINT_pow_Apos #2}% + \krof {#1}% +}% +\def\XINT_pow_AisZero #1#2\xint: +{% + \ifcase\XINT_cntSgn #1\xint: + \xint_afterfi { 1}% + \or + \xint_afterfi { 0}% + \else + \xint_afterfi + {\XINT_signalcondition{DivisionByZero}{Zero to power #1}{}{0}}% + \fi +}% +\def\XINT_pow_Aneg #1% +{% + \ifodd #1 + \expandafter\XINT_opp\romannumeral0% + \fi + \XINT_pow_Apos {}{#1}% +}% +\def\XINT_pow_Apos #1#2{\XINT_pow_Apos_a {#2}#1}% +\def\XINT_pow_Apos_a #1#2#3% +{% + \xint_gob_til_xint: #3\XINT_pow_Apos_short\xint: + \XINT_pow_AatleastTwo {#1}#2#3% +}% +\def\XINT_pow_Apos_short\xint:\XINT_pow_AatleastTwo #1#2\xint: +{% + \ifcase #2 + \xintError:thiscannothappen + \or \expandafter\XINT_pow_AisOne + \else\expandafter\XINT_pow_AatleastTwo + \fi {#1}#2\xint: +}% +\def\XINT_pow_AisOne #1\xint:{ 1}% +\def\XINT_pow_AatleastTwo #1% +{% + \ifcase\XINT_cntSgn #1\xint: + \expandafter\XINT_pow_BisZero + \or + \expandafter\XINT_pow_I_in + \else + \expandafter\XINT_pow_BisNegative + \fi + {#1}% +}% +\def\XINT_pow_BisNegative #1\xint:{\XINT_signalcondition{Underflow}{Inverse power + can not be represented by an integer}{}{0}}% +\def\XINT_pow_BisZero #1\xint:{ 1}% +% \end{macrocode} +% \lverb|B = #1 > 0, A = #2 > 1. Earlier code checked if size of B did not +% exceed a given limit (for example 131000).| +% \begin{macrocode} +\def\XINT_pow_I_in #1#2\xint: +{% + \expandafter\XINT_pow_I_loop + \the\numexpr #1\expandafter\xint:% + \romannumeral0\expandafter\XINT_sepandrev + \romannumeral0\XINT_zeroes_forviii #2\R\R\R\R\R\R\R\R{10}0000001\W + #2\XINT_rsepbyviii_end_A 2345678% + \XINT_rsepbyviii_end_B 2345678\relax XX% + \R\xint:\R\xint:\R\xint:\R\xint:\R\xint:\R\xint:\R\xint:\R\xint:\W + 1;!\W + 1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W +}% +\def\XINT_pow_I_loop #1\xint:% +{% + \ifnum #1 = \xint_c_i\expandafter\XINT_pow_I_exit\fi + \ifodd #1 + \expandafter\XINT_pow_II_in + \else + \expandafter\XINT_pow_I_squareit + \fi #1\xint:% +}% +\def\XINT_pow_I_exit \ifodd #1\fi #2\xint:#3\W {\XINT_mul_out #3}% +% \end{macrocode} +% \lverb|The 1.2c \XINT_mul_loop can be called directly even with small +% arguments, hence the "butcheckifsmall" is not a necessity as it was earlier +% with 1.2. On 2^30, it does bring roughly a 40$char37 $space time gain +% though, and 30$char37 $space gain for 2^60. The overhead on big computations +% should be negligible.| +% \begin{macrocode} +\def\XINT_pow_I_squareit #1\xint:#2\W% +{% + \expandafter\XINT_pow_I_loop + \the\numexpr #1/\xint_c_ii\expandafter\xint:% + \the\numexpr\XINT_pow_mulbutcheckifsmall #2\W #2\W +}% +\def\XINT_pow_mulbutcheckifsmall #1!1#2% +{% + \xint_gob_til_sc #2\XINT_pow_mul_small;% + \XINT_mul_loop 100000000!1;!\W #1!1#2% +}% +\def\XINT_pow_mul_small;\XINT_mul_loop + 100000000!1;!\W 1#1!1;!\W +{% + \XINT_smallmul 1#1!% +}% +\def\XINT_pow_II_in #1\xint:#2\W +{% + \expandafter\XINT_pow_II_loop + \the\numexpr #1/\xint_c_ii-\xint_c_i\expandafter\xint:% + \the\numexpr\XINT_pow_mulbutcheckifsmall #2\W #2\W #2\W +}% +\def\XINT_pow_II_loop #1\xint:% +{% + \ifnum #1 = \xint_c_i\expandafter\XINT_pow_II_exit\fi + \ifodd #1 + \expandafter\XINT_pow_II_odda + \else + \expandafter\XINT_pow_II_even + \fi #1\xint:% +}% +\def\XINT_pow_II_exit\ifodd #1\fi #2\xint:#3\W #4\W +{% + \expandafter\XINT_mul_out + \the\numexpr\XINT_pow_mulbutcheckifsmall #4\W #3% +}% +\def\XINT_pow_II_even #1\xint:#2\W +{% + \expandafter\XINT_pow_II_loop + \the\numexpr #1/\xint_c_ii\expandafter\xint:% + \the\numexpr\XINT_pow_mulbutcheckifsmall #2\W #2\W +}% +\def\XINT_pow_II_odda #1\xint:#2\W #3\W +{% + \expandafter\XINT_pow_II_oddb + \the\numexpr #1/\xint_c_ii-\xint_c_i\expandafter\xint:% + \the\numexpr\XINT_pow_mulbutcheckifsmall #3\W #2\W #2\W +}% +\def\XINT_pow_II_oddb #1\xint:#2\W #3\W +{% + \expandafter\XINT_pow_II_loop + \the\numexpr #1\expandafter\xint:% + \the\numexpr\XINT_pow_mulbutcheckifsmall #3\W #3\W #2\W +}% +% \end{macrocode} +% \subsection{\csh{xintiiFac}} +% \lverb|Moved here from xint.sty with release 1.2 (to be usable by \bnumexpr). +% +% An \xintiFac is needed by xintexpr.sty. Prior to 1.2o it was defined here +% as an alias to \xintiiFac, then redefined by xintfrac to use \xintNum. This +% was incoherent. Contrarily to other similarly named macros, +% \xintiiFac uses \numexpr on its input. This is also incoherent with the +% naming scheme, alas. +% +% Partially rewritten with release 1.2 to benefit from the inner format of the +% 1.2 multiplication. +% +% With current default settings of the etex memory and a.t.t.o.w (11/2015) the +% maximal possible computation is 5971! (which has 19956 digits). +% +% +% +% Note (end november 2015): I also tried out a quickly written recursive +% (binary split) implementation +% +%( \catcode`_ 11 +%: \catcode`^ 11 +%: \long\def\xint_firstofthree #1#2#3{#1}$% +%: \long\def\xint_secondofthree #1#2#3{#2}$% +%: \long\def\xint_thirdofthree #1#2#3{#3}$% +%: $% quickly written factorial using binary split recursive method +%: \def\tFac {\romannumeral-`0\tfac }$% +%: \def\tfac #1{\expandafter\XINT_mul_out +%: \romannumeral-`0\ufac {1}{#1}1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W}$% +%: \def\ufac #1#2{\ifcase\numexpr#2-#1\relax +%: \expandafter\xint_firstofthree +%: \or +%: \expandafter\xint_secondofthree +%: \else +%: \expandafter\xint_thirdofthree +%: \fi +%: {\the\numexpr\xint_c_x^viii+#1!1;!}$% +%: {\the\numexpr\xint_c_x^viii+#1*#2!1;!}$% +%: {\expandafter\vfac\the\numexpr (#1+#2)/\xint_c_ii.#1.#2.}$% +%: }$% +%: \def\vfac #1.#2.#3.$% +%: {$% +%: \expandafter +%: \wfac\expandafter +%: {\romannumeral-`0\expandafter +%: \ufac\expandafter{\the\numexpr #1+\xint_c_i}{#3}}$% +%: {\ufac {#2}{#1}}$% +%: }$% +%: \def\wfac #1#2{\expandafter\zfac\romannumeral-`0#2\W #1}$% +%: \def\zfac {\the\numexpr\XINT_mul_loop 100000000!1;!\W }$% core multiplication... +%: \catcode`_ 8 +%: \catcode`^ 7 +%) +% and I was quite surprised that it was only about 1.6x--2x slower in the range +% N=200 to 2000 than the \xintiiFac here which attempts to be smarter... +% +% Note (2017, 1.2l): I found out some code comment of mine that the code here +% should be more in the style of \xintiiBinomial, but I left matters +% untouched. +% +% +% +% 1.2o modifies \xintiFac to be coherent with \xintiBinomial: only with +% xintfrac.sty loaded does it use \xintNum. It is documented only as macro of +% xintfrac.sty, not as macro of xint.sty. +% | +% \begin{macrocode} +\def\xintiiFac {\romannumeral0\xintiifac }% +\def\xintiifac #1{\expandafter\XINT_fac_fork\the\numexpr#1.}% +\def\XINT_fac_fork #1#2.% +{% + \xint_UDzerominusfork + #1-\XINT_fac_zero + 0#1\XINT_fac_neg + 0-\XINT_fac_checksize + \krof #1#2.% +}% +\def\XINT_fac_zero #1.{ 1}% +\def\XINT_fac_neg #1.{\XINT_signalcondition{InvalidOperation}{Factorial of + negative: (#1)!}{}{0}}% +% \end{macrocode} +% \begin{macrocode} +\def\XINT_fac_checksize #1.% +{% + \ifnum #1>\xint_c_x^iv \xint_dothis{\XINT_fac_toobig #1.}\fi + \ifnum #1>465 \xint_dothis{\XINT_fac_bigloop_a #1.}\fi + \ifnum #1>101 \xint_dothis{\XINT_fac_medloop_a #1.\XINT_mul_out}\fi + \xint_orthat{\XINT_fac_smallloop_a #1.\XINT_mul_out}% + 1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W +}% +\def\XINT_fac_toobig #1.#2\W{\XINT_signalcondition{InvalidOperation}{Factorial + of too big argument: #1 > 10000}{}{0}}% +\def\XINT_fac_bigloop_a #1.% +{% + \expandafter\XINT_fac_bigloop_b \the\numexpr + #1+\xint_c_i-\xint_c_ii*((#1-464)/\xint_c_ii).#1.% +}% +\def\XINT_fac_bigloop_b #1.#2.% +{% + \expandafter\XINT_fac_medloop_a + \the\numexpr #1-\xint_c_i.{\XINT_fac_bigloop_loop #1.#2.}% +}% +\def\XINT_fac_bigloop_loop #1.#2.% +{% + \ifnum #1>#2 \expandafter\XINT_fac_bigloop_exit\fi + \expandafter\XINT_fac_bigloop_loop + \the\numexpr #1+\xint_c_ii\expandafter.% + \the\numexpr #2\expandafter.\the\numexpr\XINT_fac_bigloop_mul #1!% +}% +\def\XINT_fac_bigloop_exit #1!{\XINT_mul_out}% +\def\XINT_fac_bigloop_mul #1!% +{% + \expandafter\XINT_smallmul + \the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)!% +}% +\def\XINT_fac_medloop_a #1.% +{% + \expandafter\XINT_fac_medloop_b + \the\numexpr #1+\xint_c_i-\xint_c_iii*((#1-100)/\xint_c_iii).#1.% +}% +\def\XINT_fac_medloop_b #1.#2.% +{% + \expandafter\XINT_fac_smallloop_a + \the\numexpr #1-\xint_c_i.{\XINT_fac_medloop_loop #1.#2.}% +}% +\def\XINT_fac_medloop_loop #1.#2.% +{% + \ifnum #1>#2 \expandafter\XINT_fac_loop_exit\fi + \expandafter\XINT_fac_medloop_loop + \the\numexpr #1+\xint_c_iii\expandafter.% + \the\numexpr #2\expandafter.\the\numexpr\XINT_fac_medloop_mul #1!% +}% +\def\XINT_fac_medloop_mul #1!% +{% + \expandafter\XINT_smallmul + \the\numexpr + \xint_c_x^viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% +}% +\def\XINT_fac_smallloop_a #1.% +{% + \csname + XINT_fac_smallloop_\the\numexpr #1-\xint_c_iv*(#1/\xint_c_iv)\relax + \endcsname #1.% +}% +\expandafter\def\csname XINT_fac_smallloop_1\endcsname #1.% +{% + \XINT_fac_smallloop_loop 2.#1.100000001!1;!% +}% +\expandafter\def\csname XINT_fac_smallloop_-2\endcsname #1.% +{% + \XINT_fac_smallloop_loop 3.#1.100000002!1;!% +}% +\expandafter\def\csname XINT_fac_smallloop_-1\endcsname #1.% +{% + \XINT_fac_smallloop_loop 4.#1.100000006!1;!% +}% +\expandafter\def\csname XINT_fac_smallloop_0\endcsname #1.% +{% + \XINT_fac_smallloop_loop 5.#1.1000000024!1;!% +}% +\def\XINT_fac_smallloop_loop #1.#2.% +{% + \ifnum #1>#2 \expandafter\XINT_fac_loop_exit\fi + \expandafter\XINT_fac_smallloop_loop + \the\numexpr #1+\xint_c_iv\expandafter.% + \the\numexpr #2\expandafter.\the\numexpr\XINT_fac_smallloop_mul #1!% +}% +\def\XINT_fac_smallloop_mul #1!% +{% + \expandafter\XINT_smallmul + \the\numexpr + \xint_c_x^viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% +}% +\def\XINT_fac_loop_exit #1!#2;!#3{#3#2;!}% +% \end{macrocode} +% \subsection{\csh{XINT_useiimessage}} +% \lverb|1.2o| +% \begin{macrocode} +\def\XINT_useiimessage #1% used in LaTeX only +{% + \XINT_ifFlagRaised {#1}% + {\@backslashchar#1 + (load xintfrac or use \@backslashchar xintii\xint_gobble_iv#1!)\MessageBreak}% + {}% +}% +\XINT_restorecatcodes_endinput% +% \end{macrocode} +% \StoreCodelineNo {xintcore} +% \cleardoublepage\let\xintcorenameUp\undefined +%\gardesactifs +%\let</xintcore>\relax +%\let<*xint>\gardesinactifs +%</xintcore>^^A--------------------------------------------------- +%<*xint>^^A------------------------------------------------------- +%^^A -*- coding: utf-8; mode: doctex -*- +% \clearpage\csname xintnameUp\endcsname +% \section{Package \xintnameimp implementation} +% \RaisedLabel{sec:xintimp} +% +% \localtableofcontents +% +% With release |1.1| the core arithmetic routines |\xintiiAdd|, +% |\xintiiSub|, |\xintiiMul|, |\xintiiQuo|, |\xintiiPow| were separated to be +% the main component of the then new +% \xintcorenameimp. +% +% At |1.3| the macros deprecated at |1.2o| got all removed. +% +% |1.3b| adds randomness related macros. +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode64=11 % @ + \catcode35=6 % # + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \let\z\endgroup + \expandafter\let\expandafter\x\csname ver@xint.sty\endcsname + \expandafter\let\expandafter\w\csname ver@xintcore.sty\endcsname + \expandafter + \ifx\csname PackageInfo\endcsname\relax + \def\y#1#2{\immediate\write-1{Package #1 Info: #2.}}% + \else + \def\y#1#2{\PackageInfo{#1}{#2}}% + \fi + \expandafter + \ifx\csname numexpr\endcsname\relax + \y{xint}{\numexpr not available, aborting input}% + \aftergroup\endinput + \else + \ifx\x\relax % plain-TeX, first loading of xintcore.sty + \ifx\w\relax % but xintkernel.sty not yet loaded. + \def\z{\endgroup\input xintcore.sty\relax}% + \fi + \else + \def\empty {}% + \ifx\x\empty % LaTeX, first loading, + % variable is initialized, but \ProvidesPackage not yet seen + \ifx\w\relax % xintcore.sty not yet loaded. + \def\z{\endgroup\RequirePackage{xintcore}}% + \fi + \else + \aftergroup\endinput % xint already loaded. + \fi + \fi + \fi +\z% +\XINTsetupcatcodes% defined in xintkernel.sty (loaded by xintcore.sty) +% \end{macrocode} +% \subsection{Package identification} +% \begin{macrocode} +\XINT_providespackage +\ProvidesPackage{xint}% + [2019/04/05 1.3e Expandable operations on big integers (JFB)]% +% \end{macrocode} +% \subsection{More token management} +% \begin{macrocode} +\long\def\xint_firstofthree #1#2#3{#1}% +\long\def\xint_secondofthree #1#2#3{#2}% +\long\def\xint_thirdofthree #1#2#3{#3}% +\long\def\xint_stop_atfirstofthree #1#2#3{ #1}% +\long\def\xint_stop_atsecondofthree #1#2#3{ #2}% +\long\def\xint_stop_atthirdofthree #1#2#3{ #3}% +% \end{macrocode} +% \subsection{(WIP) A constant needed by \cshnolabel{xintRandomDigits} et al.} +% \begin{macrocode} +\ifdefined\xint_texuniformdeviate + \unless\ifdefined\xint_c_nine_x^viii + \csname newcount\endcsname\xint_c_nine_x^viii + \xint_c_nine_x^viii 900000000 + \fi +\fi +% \end{macrocode} +% \subsection{\csh{xintLen}, \csh{xintiLen}} +% \lverb|\xintLen gets extended to fractions by xintfrac.sty: A/B is given +% length len(A)+len(B)-1 (somewhat arbitrary). It applies \xintNum to its +% argument. A minus sign is accepted and ignored. +% +% +% For parallelism with \xintiNum/\xintNum, 1.2o defines \xintiLen. +% +% \xintLen gets redefined by $xintfracnameimp. +% | +% \begin{macrocode} +\def\xintiLen {\romannumeral0\xintilen }% +\def\xintilen #1{\def\xintilen ##1% +{% + \expandafter#1\the\numexpr + \expandafter\XINT_len_fork\romannumeral0\xintinum{##1}% + \xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v + \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye\relax +}}\xintilen{ }% +\def\xintLen {\romannumeral0\xintlen }% +\let\xintlen\xintilen +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_len_fork #1% +{% + \expandafter\XINT_length_loop\xint_UDsignfork#1{}-#1\krof +}% +% \end{macrocode} +% \subsection{\csh{xintiiLogTen}} +% \lverb|1.3e. Support for ilog10() function in \xintiiexpr. See \XINTiLogTen +% in xintfrac.sty which also currently uses -"7FFF8000 as value if input is +% zero.| +% \begin{macrocode} +\def\xintiiLogTen {\the\numexpr\xintiilogten }% +\def\xintiilogten #1% +{% + \expandafter\XINT_iilogten\romannumeral`&&@#1% + \xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v + \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye + \relax +}% +\def\XINT_iilogten #1{\if#10-"7FFF8000\fi -1+% + \expandafter\XINT_length_loop\xint_UDsignfork#1{}-#1\krof}% +% \end{macrocode} +% \subsection{\csh{xintReverseDigits}} +% \lverb|& +% 1.2. +% +% This puts digits in reverse order, not suppressing leading zeros +% after reverse. Despite lacking the "ii" in its name, it does not apply +% \xintNum to its argument (contrarily to \xintLen, this is not very coherent). +% +% 1.2l variant is robust against non terminated \the\numexpr input. +% +% This macro is currently not used elsewhere in xint code. +% | +% \begin{macrocode} +\def\xintReverseDigits {\romannumeral0\xintreversedigits }% +\def\xintreversedigits #1% +{% + \expandafter\XINT_revdigits\romannumeral`&&@#1% + {\XINT_microrevsep_end\W}\XINT_microrevsep_end + \XINT_microrevsep_end\XINT_microrevsep_end + \XINT_microrevsep_end\XINT_microrevsep_end + \XINT_microrevsep_end\XINT_microrevsep_end\XINT_microrevsep_end\Z + 1\Z!1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W +}% +\def\XINT_revdigits #1% +{% + \xint_UDsignfork + #1{\expandafter-\romannumeral0\XINT_revdigits_a}% + -{\XINT_revdigits_a #1}% + \krof +}% +\def\XINT_revdigits_a +{% + \expandafter\XINT_revdigits_b\expandafter{\expandafter}% + \the\numexpr\XINT_microrevsep +}% +\def\XINT_microrevsep #1#2#3#4#5#6#7#8#9% +{% + 1#9#8#7#6#5#4#3#2#1\expandafter!\the\numexpr\XINT_microrevsep +}% +\def\XINT_microrevsep_end #1\W #2\expandafter #3\Z{\relax#2!}% +\def\XINT_revdigits_b #11#2!1#3!1#4!1#5!1#6!1#7!1#8!1#9!% +{% + \xint_gob_til_R #9\XINT_revdigits_end\R + \XINT_revdigits_b {#9#8#7#6#5#4#3#2#1}% +}% +\def\XINT_revdigits_end#1{% +\def\XINT_revdigits_end\R\XINT_revdigits_b ##1##2\W + {\expandafter#1\xint_gob_til_Z ##1}% +}\XINT_revdigits_end{ }% +\let\xintRev\xintReverseDigits +% \end{macrocode} +% \subsection{\csh{xintiiE}} +% \lverb|Originally was used in \xintiiexpr. Transferred from xintfrac for +% 1.1. +% Code rewritten for 1.2i. +% \xintiiE{x}{e} extends x with e zeroes if e is positive and simply outputs +% x if e is zero or negative. Attention, le comportement pour e < 0 ne doit +% pas être modifié car \xintMod et autres macros en dépendent. +% | +% \begin{macrocode} +\def\xintiiE {\romannumeral0\xintiie }% +\def\xintiie #1#2% + {\expandafter\XINT_iie_fork\the\numexpr #2\expandafter.\romannumeral`&&@#1;}% +\def\XINT_iie_fork #1% +{% + \xint_UDsignfork + #1\XINT_iie_neg + -\XINT_iie_a + \krof #1% +}% +% \end{macrocode} +% \lverb|& +% le #2 a le bon pattern terminé par ; #1=0 est OK pour \XINT_rep. +% | +% \begin{macrocode} +\def\XINT_iie_a #1.% + {\expandafter\XINT_dsx_append\romannumeral\XINT_rep #1\endcsname 0.}% +\def\XINT_iie_neg #1.#2;{ #2}% +% \end{macrocode} +% \subsection{\csh{xintDecSplit}} +% \lverb@DECIMAL SPLIT +% +% The macro \xintDecSplit {x}{A} cuts A which is composed of digits (leading +% zeroes ok, but no sign) (*) into two (each possibly empty) pieces L and R. +% The concatenation LR always reproduces A. +% +% The position of the cut is specified by the first argument x. If x is zero +% or positive the cut location is x slots to the left of the right end of the +% number. If x becomes equal to or larger than the length of the number then L +% becomes empty. If x is negative the location of the cut is |x| slots to the +% right of the left end of the number. +% +% (*) versions earlier than 1.2i first replaced A with its absolute value. +% This is not the case anymore. This macro should NOT be used for A with a +% leading sign (+ or -). +% +% Entirely rewritten for 1.2i (2016/12/11). +% +% Attention: \xintDecSplit not robust against non terminated second argument. +% @ +% \begin{macrocode} +\def\xintDecSplit {\romannumeral0\xintdecsplit }% +\def\xintdecsplit #1#2% +{% + \expandafter\XINT_split_finish + \romannumeral0\expandafter\XINT_split_xfork + \the\numexpr #1\expandafter.\romannumeral`&&@#2% + \xint_bye2345678\xint_bye..% +}% +\def\XINT_split_finish #1.#2.{{#1}{#2}}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_split_xfork #1% +{% + \xint_UDzerominusfork + #1-\XINT_split_zerosplit + 0#1\XINT_split_fromleft + 0-{\XINT_split_fromright #1}% + \krof +}% +\def\XINT_split_zerosplit .#1\xint_bye#2\xint_bye..{ #1..}% +\def\XINT_split_fromleft + {\expandafter\XINT_split_fromleft_a\the\numexpr\xint_c_viii-}% +\def\XINT_split_fromleft_a #1% +{% + \xint_UDsignfork + #1\XINT_split_fromleft_b + -{\XINT_split_fromleft_end_a #1}% + \krof +}% +\def\XINT_split_fromleft_b #1.#2#3#4#5#6#7#8#9% +{% + \expandafter\XINT_split_fromleft_clean + \the\numexpr1#2#3#4#5#6#7#8#9\expandafter + \XINT_split_fromleft_a\the\numexpr\xint_c_viii-#1.% +}% +\def\XINT_split_fromleft_end_a #1.% +{% + \expandafter\XINT_split_fromleft_clean + \the\numexpr1\csname XINT_split_fromleft_end#1\endcsname +}% +\def\XINT_split_fromleft_clean 1{ }% +\expandafter\def\csname XINT_split_fromleft_end7\endcsname #1% + {#1\XINT_split_fromleft_end_b}% +\expandafter\def\csname XINT_split_fromleft_end6\endcsname #1#2% + {#1#2\XINT_split_fromleft_end_b}% +\expandafter\def\csname XINT_split_fromleft_end5\endcsname #1#2#3% + {#1#2#3\XINT_split_fromleft_end_b}% +\expandafter\def\csname XINT_split_fromleft_end4\endcsname #1#2#3#4% + {#1#2#3#4\XINT_split_fromleft_end_b}% +\expandafter\def\csname XINT_split_fromleft_end3\endcsname #1#2#3#4#5% + {#1#2#3#4#5\XINT_split_fromleft_end_b}% +\expandafter\def\csname XINT_split_fromleft_end2\endcsname #1#2#3#4#5#6% + {#1#2#3#4#5#6\XINT_split_fromleft_end_b}% +\expandafter\def\csname XINT_split_fromleft_end1\endcsname #1#2#3#4#5#6#7% + {#1#2#3#4#5#6#7\XINT_split_fromleft_end_b}% +\expandafter\def\csname XINT_split_fromleft_end0\endcsname #1#2#3#4#5#6#7#8% + {#1#2#3#4#5#6#7#8\XINT_split_fromleft_end_b}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_split_fromleft_end_b #1\xint_bye#2\xint_bye.{.#1}% puis . +\def\XINT_split_fromright #1.#2\xint_bye +{% + \expandafter\XINT_split_fromright_a + \the\numexpr#1-\numexpr\XINT_length_loop + #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v + \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye + .#2\xint_bye +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_split_fromright_a #1% +{% + \xint_UDsignfork + #1\XINT_split_fromleft + -\XINT_split_fromright_Lempty + \krof +}% +\def\XINT_split_fromright_Lempty #1.#2\xint_bye#3..{.#2.}% +% \end{macrocode} +% \subsection{\csh{xintDecSplitL}} +% \begin{macrocode} +\def\xintDecSplitL {\romannumeral0\xintdecsplitl }% +\def\xintdecsplitl #1#2% +{% + \expandafter\XINT_splitl_finish + \romannumeral0\expandafter\XINT_split_xfork + \the\numexpr #1\expandafter.\romannumeral`&&@#2% + \xint_bye2345678\xint_bye..% +}% +\def\XINT_splitl_finish #1.#2.{ #1}% +% \end{macrocode} +% \subsection{\csh{xintDecSplitR}} +% \begin{macrocode} +\def\xintDecSplitR {\romannumeral0\xintdecsplitr }% +\def\xintdecsplitr #1#2% +{% + \expandafter\XINT_splitr_finish + \romannumeral0\expandafter\XINT_split_xfork + \the\numexpr #1\expandafter.\romannumeral`&&@#2% + \xint_bye2345678\xint_bye..% +}% +\def\XINT_splitr_finish #1.#2.{ #2}% +% \end{macrocode} +% \subsection{\csh{xintDSHr}} +% \lverb@DECIMAL SHIFTS \xintDSH {x}{A}$\ +% si x <= 0, fait A -> A.10^(|x|). +% si x > 0, et A >=0, fait A -> quo(A,10^(x))$\ +% si x > 0, et A < 0, fait A -> -quo(-A,10^(x))$\ +% (donc pour x > 0 c'est comme DSR itéré x fois)$\ +% \xintDSHr donne le `reste' (si x<=0 donne zéro). +% +% Badly named macros. +% +% Rewritten for 1.2i, this was old code and \xintDSx has changed interface. +% @ +% \begin{macrocode} +\def\xintDSHr {\romannumeral0\xintdshr }% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\xintdshr #1#2% +{% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \expandafter\XINT_dshr_fork\the\numexpr#1\expandafter.\romannumeral`&&@#2;% +}% +\def\XINT_dshr_fork #1% +{% + \xint_UDzerominusfork + 0#1\XINT_dshr_xzeroorneg + #1-\XINT_dshr_xzeroorneg + 0-\XINT_dshr_xpositive + \krof #1% +}% +\def\XINT_dshr_xzeroorneg #1;{ 0}% +\def\XINT_dshr_xpositive +{% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \expandafter\xint_stop_atsecondoftwo\romannumeral0\XINT_dsx_xisPos +}% +% \end{macrocode} +% \subsection{\csh{xintDSH}} +% \begin{macrocode} +\def\xintDSH {\romannumeral0\xintdsh }% +\def\xintdsh #1#2% +{% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \expandafter\XINT_dsh_fork\the\numexpr#1\expandafter.\romannumeral`&&@#2;% +}% +\def\XINT_dsh_fork #1% +{% + \xint_UDzerominusfork + #1-\XINT_dsh_xiszero +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + 0#1\XINT_dsx_xisNeg_checkA + 0-{\XINT_dsh_xisPos #1}% + \krof +}% +\def\XINT_dsh_xiszero #1.#2;{ #2}% +\def\XINT_dsh_xisPos +{% +% \end{macrocode} +% \lverb|& + \expandafter\xint_stop_atfirstoftwo\romannumeral0\XINT_dsx_xisPos +% | +% \begin{macrocode} +}% +% \end{macrocode} +% \subsection{\csh{xintDSx}} +% \lverb@& +% --> Attention le cas x=0 est traité dans la même catégorie que x > 0 <-- +% +%( si x < 0, fait A -> A.10^(|x|) +%: si x >= 0, et A >=0, fait A -> {quo(A,10^(x))}{rem(A,10^(x))} +%: si x >= 0, et A < 0, d'abord on calcule {quo(-A,10^(x))}{rem(-A,10^(x))} +%: puis, si le premier n'est pas nul on lui donne le signe - +%: si le premier est nul on donne le signe - au second. +%) +% On peut donc toujours reconstituer l'original A par 10^x Q \pm R +% où il faut prendre le signe plus si Q est positif ou nul et le signe moins si +% Q est strictement négatif. +% +% Rewritten for 1.2i, this was old code. +% +% @ +% \begin{macrocode} +\def\xintDSx {\romannumeral0\xintdsx }% +\def\xintdsx #1#2% +{% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \expandafter\XINT_dsx_fork\the\numexpr#1\expandafter.\romannumeral`&&@#2;% +}% +\def\XINT_dsx_fork #1% +{% + \xint_UDzerominusfork + #1-\XINT_dsx_xisZero + 0#1\XINT_dsx_xisNeg_checkA + 0-{\XINT_dsx_xisPos #1}% + \krof +}% +\def\XINT_dsx_xisZero #1.#2;{{#2}{0}}% +\def\XINT_dsx_xisNeg_checkA #1.#2% +{% + \xint_gob_til_zero #2\XINT_dsx_xisNeg_Azero 0% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \expandafter\XINT_dsx_append\romannumeral\XINT_rep #1\endcsname 0.#2% +}% +\def\XINT_dsx_xisNeg_Azero #1;{ 0}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_dsx_addzeros #1% + {\expandafter\XINT_dsx_append\romannumeral\XINT_rep#1\endcsname0.}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_dsx_addzerosnofuss #1% + {\expandafter\XINT_dsx_append\romannumeral\xintreplicate{#1}0.}% +\def\XINT_dsx_append #1.#2;{ #2#1}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_dsx_xisPos #1.#2% +{% + \xint_UDzerominusfork + #2-\XINT_dsx_AisZero + 0#2\XINT_dsx_AisNeg + 0-\XINT_dsx_AisPos + \krof #1.#2% +}% +\def\XINT_dsx_AisZero #1;{{0}{0}}% +\def\XINT_dsx_AisNeg #1.-#2;% +{% + \expandafter\XINT_dsx_AisNeg_checkiffirstempty + \romannumeral0\XINT_split_xfork #1.#2\xint_bye2345678\xint_bye..% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_dsx_AisNeg_checkiffirstempty #1% +{% + \xint_gob_til_dot #1\XINT_dsx_AisNeg_finish_zero.% + \XINT_dsx_AisNeg_finish_notzero #1% +}% +\def\XINT_dsx_AisNeg_finish_zero.\XINT_dsx_AisNeg_finish_notzero.#1.% +{% + \expandafter\XINT_dsx_end + \expandafter {\romannumeral0\XINT_num {-#1}}{0}% +}% +\def\XINT_dsx_AisNeg_finish_notzero #1.#2.% +{% + \expandafter\XINT_dsx_end + \expandafter {\romannumeral0\XINT_num {#2}}{-#1}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_dsx_AisPos #1.#2;% +{% + \expandafter\XINT_dsx_AisPos_finish + \romannumeral0\XINT_split_xfork #1.#2\xint_bye2345678\xint_bye..% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_dsx_AisPos_finish #1.#2.% +{% + \expandafter\XINT_dsx_end + \expandafter {\romannumeral0\XINT_num {#2}}% + {\romannumeral0\XINT_num {#1}}% +}% +\def\XINT_dsx_end #1#2{\expandafter{#2}{#1}}% +% \end{macrocode} +% \subsection{\csh{xintiiEq}} +% \lverb|no \xintiieq.| +% \begin{macrocode} +\def\xintiiEq #1#2{\romannumeral0\xintiiifeq{#1}{#2}{1}{0}}% +% \end{macrocode} +% \subsection{\csh{xintiiNotEq}} +% \lverb|Pour xintexpr. Pas de version en lowercase.| +% \begin{macrocode} +\def\xintiiNotEq #1#2{\romannumeral0\xintiiifeq {#1}{#2}{0}{1}}% +% \end{macrocode} +% \subsection{\csh{xintiiGeq}} +% \lverb|& +% PLUS GRAND OU ÉGAL +% attention compare les **valeurs absolues** +% +% 1.2l made \xintiiGeq robust against non terminated items. +% +% 1.2l rewrote \xintiiCmp, but forgot to handle \xintiiGeq too. Done at 1.2m. +% +% This macro should have been called \xintGEq for example. +% | +% \begin{macrocode} +\def\xintiiGeq {\romannumeral0\xintiigeq }% +\def\xintiigeq #1{\expandafter\XINT_iigeq\romannumeral`&&@#1\xint:}% +\def\XINT_iigeq #1#2\xint:#3% +{% + \expandafter\XINT_geq_fork\expandafter #1\romannumeral`&&@#3\xint:#2\xint: +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_geq #1#2\xint:#3% +{% + \expandafter\XINT_geq_fork\expandafter #1\romannumeral0\xintnum{#3}\xint:#2\xint: +}% +\def\XINT_geq_fork #1#2% +{% + \xint_UDzerofork + #1\XINT_geq_firstiszero + #2\XINT_geq_secondiszero + 0{}% + \krof + \xint_UDsignsfork + #1#2\XINT_geq_minusminus + #1-\XINT_geq_minusplus + #2-\XINT_geq_plusminus + --\XINT_geq_plusplus + \krof #1#2% +}% +\def\XINT_geq_firstiszero #1\krof 0#2#3\xint:#4\xint: + {\xint_UDzerofork #2{ 1}0{ 0}\krof }% +\def\XINT_geq_secondiszero #1\krof #20#3\xint:#4\xint:{ 1}% +\def\XINT_geq_plusminus #1-{\XINT_geq_plusplus #1{}}% +\def\XINT_geq_minusplus -#1{\XINT_geq_plusplus {}#1}% +\def\XINT_geq_minusminus --{\XINT_geq_plusplus {}{}}% +\def\XINT_geq_plusplus + {\expandafter\XINT_geq_finish\romannumeral0\XINT_cmp_plusplus}% +\def\XINT_geq_finish #1{\if-#1\expandafter\XINT_geq_no + \else\expandafter\XINT_geq_yes\fi}% +\def\XINT_geq_no 1{ 0}% +\def\XINT_geq_yes { 1}% +% \end{macrocode} +% \subsection{\csh{xintiiGt}} +% \begin{macrocode} +\def\xintiiGt #1#2{\romannumeral0\xintiiifgt{#1}{#2}{1}{0}}% +% \end{macrocode} +% \subsection{\csh{xintiiLt}} +% \begin{macrocode} +\def\xintiiLt #1#2{\romannumeral0\xintiiiflt{#1}{#2}{1}{0}}% +% \end{macrocode} +% \subsection{\csh{xintiiGtorEq}} +% \begin{macrocode} +\def\xintiiGtorEq #1#2{\romannumeral0\xintiiiflt {#1}{#2}{0}{1}}% +% \end{macrocode} +% \subsection{\csh{xintiiLtorEq}} +% \begin{macrocode} +\def\xintiiLtorEq #1#2{\romannumeral0\xintiiifgt {#1}{#2}{0}{1}}% +% \end{macrocode} +% \subsection{\csh{xintiiIsZero}} +% \lverb|1.09a. restyled in 1.09i. 1.1 adds \xintiiIsZero, etc... for +% optimization in \xintexpr| +% \begin{macrocode} +\def\xintiiIsZero {\romannumeral0\xintiiiszero }% +\def\xintiiiszero #1{\if0\xintiiSgn{#1}\xint_afterfi{ 1}\else\xint_afterfi{ 0}\fi}% +% \end{macrocode} +% \subsection{\csh{xintiiIsNotZero}} +% \lverb|1.09a. restyled in 1.09i. 1.1 adds \xintiiIsZero, etc... for +% optimization in \xintexpr| +% \begin{macrocode} +\def\xintiiIsNotZero {\romannumeral0\xintiiisnotzero }% +\def\xintiiisnotzero + #1{\if0\xintiiSgn{#1}\xint_afterfi{ 0}\else\xint_afterfi{ 1}\fi}% +% \end{macrocode} +% \subsection{\csh{xintiiIsOne}} +% \lverb|Added in 1.03. 1.09a defines \xintIsOne. 1.1a adds \xintiiIsOne. +% +% \XINT_isOne rewritten for 1.2g. Works with expanded strict integers, +% positive or negative. +% +% +% +%| +% \begin{macrocode} +\def\xintiiIsOne {\romannumeral0\xintiiisone }% +\def\xintiiisone #1{\expandafter\XINT_isone\romannumeral`&&@#1XY}% +\def\XINT_isone #1#2#3Y% +{% + \unless\if#2X\xint_dothis{ 0}\fi + \unless\if#11\xint_dothis{ 0}\fi + \xint_orthat{ 1}% +}% +\def\XINT_isOne #1{\XINT_is_One#1XY}% +\def\XINT_is_One #1#2#3Y% +{% + \unless\if#2X\xint_dothis0\fi + \unless\if#11\xint_dothis0\fi + \xint_orthat1% +}% +% \end{macrocode} +% \subsection{\csh{xintiiOdd}} +% \lverb|\xintOdd is needed for the xintexpr-essions even() and odd() +% functions (and also by \xintNewExpr).| +% \begin{macrocode} +\def\xintiiOdd {\romannumeral0\xintiiodd }% +\def\xintiiodd #1% +{% + \ifodd\xintLDg{#1} %<- intentional space + \xint_afterfi{ 1}% + \else + \xint_afterfi{ 0}% + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintiiEven}} +% \begin{macrocode} +\def\xintiiEven {\romannumeral0\xintiieven }% +\def\xintiieven #1% +{% + \ifodd\xintLDg{#1} %<- intentional space + \xint_afterfi{ 0}% + \else + \xint_afterfi{ 1}% + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintiiMON}} +% \lverb|MINUS ONE TO THE POWER N| +% \begin{macrocode} +\def\xintiiMON {\romannumeral0\xintiimon }% +\def\xintiimon #1% +{% + \ifodd\xintLDg {#1} %<- intentional space + \xint_afterfi{ -1}% + \else + \xint_afterfi{ 1}% + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintiiMMON}} +% \lverb|MINUS ONE TO THE POWER N-1| +% \begin{macrocode} +\def\xintiiMMON {\romannumeral0\xintiimmon }% +\def\xintiimmon #1% +{% + \ifodd\xintLDg {#1} %<- intentional space + \xint_afterfi{ 1}% + \else + \xint_afterfi{ -1}% + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintSgnFork}} +% \lverb|Expandable three-way fork added in 1.07. The argument #1 must expand +% to non-self-ending -1,0 or 1. 1.09i with _thenstop (now _stop_at...).| +% \begin{macrocode} +\def\xintSgnFork {\romannumeral0\xintsgnfork }% +\def\xintsgnfork #1% +{% + \ifcase #1 \expandafter\xint_stop_atsecondofthree + \or\expandafter\xint_stop_atthirdofthree + \else\expandafter\xint_stop_atfirstofthree + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintiiifSgn}} +% \lverb|Expandable three-way fork added in 1.09a. Branches expandably +% depending on whether <0, =0, >0. Choice of branch guaranteed in two steps. +% +% 1.09i has \xint_firstofthreeafterstop (now \xint_stop_atfirstofthree) etc +% for faster expansion. +% +% 1.1 adds \xintiiifSgn for optimization in xintexpr-essions. Should I move +% them to xintcore? (for bnumexpr)| +% \begin{macrocode} +\def\xintiiifSgn {\romannumeral0\xintiiifsgn }% +\def\xintiiifsgn #1% +{% + \ifcase \xintiiSgn{#1} + \expandafter\xint_stop_atsecondofthree + \or\expandafter\xint_stop_atthirdofthree + \else\expandafter\xint_stop_atfirstofthree + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintiiifCmp}} +% \lverb|1.09e +% \xintifCmp {n}{m}{if n<m}{if n=m}{if n>m}. 1.1a adds ii variant| +% \begin{macrocode} +\def\xintiiifCmp {\romannumeral0\xintiiifcmp }% +\def\xintiiifcmp #1#2% +{% + \ifcase\xintiiCmp {#1}{#2} + \expandafter\xint_stop_atsecondofthree + \or\expandafter\xint_stop_atthirdofthree + \else\expandafter\xint_stop_atfirstofthree + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintiiifEq}} +% \lverb|1.09a \xintifEq {n}{m}{YES if n=m}{NO if n<>m}. 1.1a adds ii variant| +% \begin{macrocode} +\def\xintiiifEq {\romannumeral0\xintiiifeq }% +\def\xintiiifeq #1#2% +{% + \if0\xintiiCmp{#1}{#2}% + \expandafter\xint_stop_atfirstoftwo + \else\expandafter\xint_stop_atsecondoftwo + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintiiifGt}} +% \lverb|1.09a \xintifGt {n}{m}{YES if n>m}{NO if n<=m}. 1.1a adds ii variant| +% \begin{macrocode} +\def\xintiiifGt {\romannumeral0\xintiiifgt }% +\def\xintiiifgt #1#2% +{% + \if1\xintiiCmp{#1}{#2}% + \expandafter\xint_stop_atfirstoftwo + \else\expandafter\xint_stop_atsecondoftwo + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintiiifLt}} +% \lverb|1.09a \xintifLt {n}{m}{YES if n<m}{NO if n>=m}. Restyled in 1.09i. +% 1.1a adds ii variant| +% \begin{macrocode} +\def\xintiiifLt {\romannumeral0\xintiiiflt }% +\def\xintiiiflt #1#2% +{% + \ifnum\xintiiCmp{#1}{#2}<\xint_c_ + \expandafter\xint_stop_atfirstoftwo + \else \expandafter\xint_stop_atsecondoftwo + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintiiifZero}} +% \lverb|Expandable two-way fork added in 1.09a. Branches expandably depending on +% whether the argument is zero (branch A) or not (branch B). 1.09i restyling. By +% the way it appears (not thoroughly tested, though) that \if tests are faster +% than \ifnum tests. 1.1 adds ii versions. +% +% 1.2o deprecates \xintifZero.| +% \begin{macrocode} +\def\xintiiifZero {\romannumeral0\xintiiifzero }% +\def\xintiiifzero #1% +{% + \if0\xintiiSgn{#1}% + \expandafter\xint_stop_atfirstoftwo + \else + \expandafter\xint_stop_atsecondoftwo + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintiiifNotZero}} +% \begin{macrocode} +\def\xintiiifNotZero {\romannumeral0\xintiiifnotzero }% +\def\xintiiifnotzero #1% +{% + \if0\xintiiSgn{#1}% + \expandafter\xint_stop_atsecondoftwo + \else + \expandafter\xint_stop_atfirstoftwo + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintiiifOne}} +% \lverb|added in 1.09i. 1.1a adds \xintiiifOne.| +% \begin{macrocode} +\def\xintiiifOne {\romannumeral0\xintiiifone }% +\def\xintiiifone #1% +{% + \if1\xintiiIsOne{#1}% + \expandafter\xint_stop_atfirstoftwo + \else + \expandafter\xint_stop_atsecondoftwo + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintiiifOdd}} +% \lverb|1.09e. Restyled in 1.09i. 1.1a adds \xintiiifOdd.| +% \begin{macrocode} +\def\xintiiifOdd {\romannumeral0\xintiiifodd }% +\def\xintiiifodd #1% +{% + \if\xintiiOdd{#1}1% + \expandafter\xint_stop_atfirstoftwo + \else + \expandafter\xint_stop_atsecondoftwo + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintifTrueAelseB}, \csh{xintifFalseAelseB}} +% \lverb|1.09i. 1.2i has removed deprecated \xintifTrueFalse, \xintifTrue. +% +% 1.2o uses \xintiiifNotZero, see comments to \xintAND etc... This will work +% fine with arguments being nested xintfrac.sty macros, without the overhead +% of \xintNum or \xintRaw parsing.| +% \begin{macrocode} +\def\xintifTrueAelseB {\romannumeral0\xintiiifnotzero}% +\def\xintifFalseAelseB{\romannumeral0\xintiiifzero}% +% \end{macrocode} +% \subsection{\csh{xintIsTrue}, \csh{xintIsFalse}} +% \lverb|1.09c. Suppressed at 1.2o. They seem not to have been documented, fortunately.| +% \begin{macrocode} +%\let\xintIsTrue \xintIsNotZero +%\let\xintIsFalse\xintIsZero +% \end{macrocode} +% \subsection{\csh{xintNOT}} +% \lverb|1.09c. But it should have been called \xintNOT, not \xintNot. Former +% denomination deprecated at 1.2o. Besides, the macro is now defined as ii-type. +% | +% \begin{macrocode} +\def\xintNOT{\romannumeral0\xintiiiszero}% +% \end{macrocode} +% \subsection{\csh{xintAND}, \csh{xintOR}, \csh{xintXOR}} +% \lverb|Added with 1.09a. But they used \xintSgn, etc... rather than +% \xintiiSgn. This brings \xintNum overhead which is not really desired, and +% which is not needed for use by xintexpr.sty. At 1.2o I modify them to use +% only ii macros. This is enough for sign or zeroness even for xintfrac +% format, as manipulated inside the \xintexpr. Big hesitation whether there +% should be however \xintiiAND outputting 1 or 0 versus an \xintAND outputting +% 1[0] versus 0[0] for example.| +% \begin{macrocode} +\def\xintAND {\romannumeral0\xintand }% +\def\xintand #1#2{\if0\xintiiSgn{#1}\expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo\fi + { 0}{\xintiiisnotzero{#2}}}% +\def\xintOR {\romannumeral0\xintor }% +\def\xintor #1#2{\if0\xintiiSgn{#1}\expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo\fi + {\xintiiisnotzero{#2}}{ 1}}% +\def\xintXOR {\romannumeral0\xintxor }% +\def\xintxor #1#2{\if\xintiiIsZero{#1}\xintiiIsZero{#2}% + \xint_afterfi{ 0}\else\xint_afterfi{ 1}\fi }% +% \end{macrocode} +% \subsection{\csh{xintANDof}} +% \lverb|New with 1.09a. \xintANDof works also with an empty list. Empty items +% however are not accepted. +% +% 1.2l made \xintANDof robust against non terminated items. +% +% 1.2o's \xintifTrueAelseB is now an ii macro, actually. +% +% This macro as well as ORof and XORof are actually not used by xintexpr, +% which has its own csv handling macros.| +% \begin{macrocode} +\def\xintANDof {\romannumeral0\xintandof }% +\def\xintandof #1{\expandafter\XINT_andof_a\romannumeral`&&@#1\xint:}% +\def\XINT_andof_a #1{\expandafter\XINT_andof_b\romannumeral`&&@#1!}% +\def\XINT_andof_b #1% + {\xint_gob_til_xint: #1\XINT_andof_e\xint:\XINT_andof_c #1}% +\def\XINT_andof_c #1!% + {\xintifTrueAelseB {#1}{\XINT_andof_a}{\XINT_andof_no}}% +\def\XINT_andof_no #1\xint:{ 0}% +\def\XINT_andof_e #1!{ 1}% +% \end{macrocode} +% \subsection{\csh{xintORof}} +% \lverb|New with 1.09a. Works also with an empty list. Empty items +% however are not accepted. +% +% 1.2l made \xintORof robust against non terminated items.| +% \begin{macrocode} +\def\xintORof {\romannumeral0\xintorof }% +\def\xintorof #1{\expandafter\XINT_orof_a\romannumeral`&&@#1\xint:}% +\def\XINT_orof_a #1{\expandafter\XINT_orof_b\romannumeral`&&@#1!}% +\def\XINT_orof_b #1% + {\xint_gob_til_xint: #1\XINT_orof_e\xint:\XINT_orof_c #1}% +\def\XINT_orof_c #1!% + {\xintifTrueAelseB {#1}{\XINT_orof_yes}{\XINT_orof_a}}% +\def\XINT_orof_yes #1\xint:{ 1}% +\def\XINT_orof_e #1!{ 0}% +% \end{macrocode} +% \subsection{\csh{xintXORof}} +% \lverb|New with 1.09a. Works with an empty list, too. Empty items +% however are not accepted. \XINT_xorof_c more +% efficient in 1.09i. +% +% 1.2l made \xintXORof robust against non terminated items.| +% \begin{macrocode} +\def\xintXORof {\romannumeral0\xintxorof }% +\def\xintxorof #1{\expandafter\XINT_xorof_a\expandafter + 0\romannumeral`&&@#1\xint:}% +\def\XINT_xorof_a #1#2{\expandafter\XINT_xorof_b\romannumeral`&&@#2!#1}% +\def\XINT_xorof_b #1% + {\xint_gob_til_xint: #1\XINT_xorof_e\xint:\XINT_xorof_c #1}% +\def\XINT_xorof_c #1!#2% + {\xintifTrueAelseB {#1}{\if #20\xint_afterfi{\XINT_xorof_a 1}% + \else\xint_afterfi{\XINT_xorof_a 0}\fi}% + {\XINT_xorof_a #2}% + }% +\def\XINT_xorof_e #1!#2{ #2}% +% \end{macrocode} +% \subsection{\csh{xintiiMax}} +% \lverb|& +% At 1.2m, a long-standing bug was fixed: \xintiiMax had the overhead of +% applying \xintNum to its arguments due to use of a sub-macro of \xintGeq +% code to which this overhead was added at some point. +% +% And on this occasion I reduced even more number of times input is grabbed. +% | +% \begin{macrocode} +\def\xintiiMax {\romannumeral0\xintiimax }% +\def\xintiimax #1% +{% + \expandafter\xint_iimax \romannumeral`&&@#1\xint: +}% +\def\xint_iimax #1\xint:#2% +{% + \expandafter\XINT_max_fork\romannumeral`&&@#2\xint:#1\xint: +}% +% \end{macrocode} +% \lverb|& +% #3#4 vient du *premier*, +% #1#2 vient du *second*. I have renamed the sub-macros at 1.2m because the +% terminology was quite counter-intuitive; there was no bug, but still.| +% \begin{macrocode} +\def\XINT_max_fork #1#2\xint:#3#4\xint: +{% + \xint_UDsignsfork + #1#3\XINT_max_minusminus % A < 0, B < 0 + #1-\XINT_max_plusminus % B < 0, A >= 0 + #3-\XINT_max_minusplus % A < 0, B >= 0 + --{\xint_UDzerosfork + #1#3\XINT_max_zerozero % A = B = 0 + #10\XINT_max_pluszero % B = 0, A > 0 + #30\XINT_max_zeroplus % A = 0, B > 0 + 00\XINT_max_plusplus % A, B > 0 + \krof }% + \krof + #3#1#2\xint:#4\xint: + \expandafter\xint_stop_atfirstoftwo + \else + \expandafter\xint_stop_atsecondoftwo + \fi + {#3#4}{#1#2}% +}% +% \end{macrocode} +% \lverb|& +% Refactored at 1.2m for avoiding grabbing arguments. Position of inputs +% shared with iiCmp and iiGeq code.| +% \begin{macrocode} +\def\XINT_max_zerozero #1\fi{\xint_stop_atfirstoftwo }% +\def\XINT_max_zeroplus #1\fi{\xint_stop_atsecondoftwo }% +\def\XINT_max_pluszero #1\fi{\xint_stop_atfirstoftwo }% +\def\XINT_max_minusplus #1\fi{\xint_stop_atsecondoftwo }% +\def\XINT_max_plusminus #1\fi{\xint_stop_atfirstoftwo }% +\def\XINT_max_plusplus +{% + \if1\romannumeral0\XINT_geq_plusplus +}% +% \end{macrocode} +% \lverb+Premier des testés |A|=-A, second est |B|=-B. On veut le max(A,B), +% c'est donc A si |A|<|B| (ou |A|=|B|, mais peu importe alors). Donc on peut +% faire cela avec \unless. Simple.+ +% \begin{macrocode} +\def\XINT_max_minusminus --% +{% + \unless\if1\romannumeral0\XINT_geq_plusplus{}{}% +}% +% \end{macrocode} +% \subsection{\csh{xintiiMin}} +% \lverb|\xintnum added New with 1.09a. I add \xintiiMin in 1.1 and mark as +% deprecated \xintMin, renamed \xintiMin. \xintMin NOW REMOVED (1.2, as +% \xintMax, \xintMaxof), only provided by \xintfracnameimp. +% +% At 1.2m, a long-standing bug was fixed: \xintiiMin had the overhead of +% applying \xintNum to its arguments due to use of a sub-macro of \xintGeq +% code to which this overhead was added at some point. +% +% And on this occasion I reduced even more number of times input is grabbed. +% | +% \begin{macrocode} +\def\xintiiMin {\romannumeral0\xintiimin }% +\def\xintiimin #1% +{% + \expandafter\xint_iimin \romannumeral`&&@#1\xint: +}% +\def\xint_iimin #1\xint:#2% +{% + \expandafter\XINT_min_fork\romannumeral`&&@#2\xint:#1\xint: +}% +\def\XINT_min_fork #1#2\xint:#3#4\xint: +{% + \xint_UDsignsfork + #1#3\XINT_min_minusminus % A < 0, B < 0 + #1-\XINT_min_plusminus % B < 0, A >= 0 + #3-\XINT_min_minusplus % A < 0, B >= 0 + --{\xint_UDzerosfork + #1#3\XINT_min_zerozero % A = B = 0 + #10\XINT_min_pluszero % B = 0, A > 0 + #30\XINT_min_zeroplus % A = 0, B > 0 + 00\XINT_min_plusplus % A, B > 0 + \krof }% + \krof + #3#1#2\xint:#4\xint: + \expandafter\xint_stop_atsecondoftwo + \else + \expandafter\xint_stop_atfirstoftwo + \fi + {#3#4}{#1#2}% +}% +\def\XINT_min_zerozero #1\fi{\xint_stop_atfirstoftwo }% +\def\XINT_min_zeroplus #1\fi{\xint_stop_atfirstoftwo }% +\def\XINT_min_pluszero #1\fi{\xint_stop_atsecondoftwo }% +\def\XINT_min_minusplus #1\fi{\xint_stop_atfirstoftwo }% +\def\XINT_min_plusminus #1\fi{\xint_stop_atsecondoftwo }% +\def\XINT_min_plusplus +{% + \if1\romannumeral0\XINT_geq_plusplus +}% +\def\XINT_min_minusminus --% +{% + \unless\if1\romannumeral0\XINT_geq_plusplus{}{}% +}% +% \end{macrocode} +% \subsection{\csh{xintiiMaxof}} +% \lverb|New with 1.09a. 1.2 has NO MORE \xintMaxof, requires \xintfracname. +% 1.2a adds \xintiiMaxof, as \xintiiMaxof:csv is not public. +% +% NOT compatible with empty list. +% +% 1.2l made \xintiiMaxof robust against non terminated items.| +% \begin{macrocode} +\def\xintiiMaxof {\romannumeral0\xintiimaxof }% +\def\xintiimaxof #1{\expandafter\XINT_iimaxof_a\romannumeral`&&@#1\xint:}% +\def\XINT_iimaxof_a #1{\expandafter\XINT_iimaxof_b\romannumeral`&&@#1!}% +\def\XINT_iimaxof_b #1!#2% + {\expandafter\XINT_iimaxof_c\romannumeral`&&@#2!{#1}!}% +\def\XINT_iimaxof_c #1% + {\xint_gob_til_xint: #1\XINT_iimaxof_e\xint:\XINT_iimaxof_d #1}% +\def\XINT_iimaxof_d #1!% + {\expandafter\XINT_iimaxof_b\romannumeral0\xintiimax {#1}}% +\def\XINT_iimaxof_e #1!#2!{ #2}% +% \end{macrocode} +% \subsection{\csh{xintiiMinof}} +% \lverb|1.09a. 1.2a adds \xintiiMinof which was lacking.| +% \begin{macrocode} +\def\xintiiMinof {\romannumeral0\xintiiminof }% +\def\xintiiminof #1{\expandafter\XINT_iiminof_a\romannumeral`&&@#1\xint:}% +\def\XINT_iiminof_a #1{\expandafter\XINT_iiminof_b\romannumeral`&&@#1!}% +\def\XINT_iiminof_b #1!#2% + {\expandafter\XINT_iiminof_c\romannumeral`&&@#2!{#1}!}% +\def\XINT_iiminof_c #1% + {\xint_gob_til_xint: #1\XINT_iiminof_e\xint:\XINT_iiminof_d #1}% +\def\XINT_iiminof_d #1!% + {\expandafter\XINT_iiminof_b\romannumeral0\xintiimin {#1}}% +\def\XINT_iiminof_e #1!#2!{ #2}% +% \end{macrocode} +% \subsection{\csh{xintiiSum}} +% \lverb|\xintiiSum {{a}{b}...{z}} +%| +% \begin{macrocode} +\def\xintiiSum {\romannumeral0\xintiisum }% +\def\xintiisum #1{\expandafter\XINT_sumexpr\romannumeral`&&@#1\xint:}% +\def\XINT_sumexpr {\XINT_sum_loop_a 0\Z }% +\def\XINT_sum_loop_a #1\Z #2% + {\expandafter\XINT_sum_loop_b \romannumeral`&&@#2\xint:#1\xint:\Z}% +\def\XINT_sum_loop_b #1% + {\xint_gob_til_xint: #1\XINT_sum_finished\xint:\XINT_sum_loop_c #1}% +\def\XINT_sum_loop_c + {\expandafter\XINT_sum_loop_a\romannumeral0\XINT_add_fork }% +\def\XINT_sum_finished\xint:\XINT_sum_loop_c\xint:\xint:#1\xint:\Z{ #1}% +% \end{macrocode} +% \subsection{\csh{xintiiPrd}} +% \lverb|\xintiiPrd {{a}...{z}} +%| +% \begin{macrocode} +\def\xintiiPrd {\romannumeral0\xintiiprd }% +\def\xintiiprd #1{\expandafter\XINT_prdexpr\romannumeral`&&@#1\xint:}% +\def\XINT_prdexpr {\XINT_prod_loop_a 1\Z }% +\def\XINT_prod_loop_a #1\Z #2% + {\expandafter\XINT_prod_loop_b\romannumeral`&&@#2\xint:#1\xint:\Z}% +\def\XINT_prod_loop_b #1% + {\xint_gob_til_xint: #1\XINT_prod_finished\xint:\XINT_prod_loop_c #1}% +\def\XINT_prod_loop_c + {\expandafter\XINT_prod_loop_a\romannumeral0\XINT_mul_fork }% +\def\XINT_prod_finished\xint:\XINT_prod_loop_c\xint:\xint:#1\xint:\Z { #1}% +% \end{macrocode} +% \subsection{\csh{xintiiSquareRoot}} +% \lverb|First done with 1.08. +% +% 1.1 added \xintiiSquareRoot. +% +% 1.1a added \xintiiSqrtR. +% +% 1.2f (2016/03/01-02-03) has rewritten the implementation, the underlying +% mathematics remaining about the same. The routine is much faster for inputs +% having up to 16 digits (because it does it all with \numexpr directly now), +% and also much faster for very long inputs (because it now fetches only the +% needed new digits after the first 16 (or 17) ones, via the geometric +% sequence 16, then 32, then 64, etc...; earlier version did the computations +% with all remaining digits after a suitable starting point with correct 4 or +% 5 leading digits). Note however that the fetching of tokens is via +% intrinsically O(N^2) macros, hence inevitably inputs with thousands of +% digits start being treated less well. +% +% Actually there is some room for improvements, one could prepare better +% input X for the upcoming treatment of fetching its digits by 16, then 32, +% then 64, etc... +% +% Incidently, as \xintiiSqrt uses subtraction and subtraction was broken from +% 1.2 to 1.2c, then for another reason from 1.2c to 1.2f, it could +% get wrong in certain (relatively rare) cases. There was also a bug that +% made it unneedlessly slow for odd number of digits on input. +% +% 1.2f also modifies \xintFloatSqrt in xintfrac.sty which now has more +% code in common with here and benefits from the same speed improvements. +% +% 1.2k belatedly corrects the output to {1}{1} and not 11 when input is zero. +% As braces are used in all other cases they should have been used here too. +% +% Also, 1.2k adds an \xintiSqrtR macro, for coherence as \xintiSqrt is +% defined (and mentioned in user manual.) +% +% | +% +% \begin{macrocode} +\def\xintiiSquareRoot {\romannumeral0\xintiisquareroot }% +\def\xintiisquareroot #1{\expandafter\XINT_sqrt_checkin\romannumeral`&&@#1\xint:}% +\def\XINT_sqrt_checkin #1% +{% + \xint_UDzerominusfork + #1-\XINT_sqrt_iszero + 0#1\XINT_sqrt_isneg + 0-\XINT_sqrt + \krof #1% +}% +\def\XINT_sqrt_iszero #1\xint:{{1}{1}}% +\def\XINT_sqrt_isneg #1\xint:{\XINT_signalcondition{InvalidOperation}{square + root of negative: #1}{}{{0}{0}}}% +\def\XINT_sqrt #1\xint: +{% + \expandafter\XINT_sqrt_start\romannumeral0\xintlength {#1}.#1.% +}% +\def\XINT_sqrt_start #1.% +{% + \ifnum #1<\xint_c_x\xint_dothis\XINT_sqrt_small_a\fi + \xint_orthat\XINT_sqrt_big_a #1.% +}% +\def\XINT_sqrt_small_a #1.{\XINT_sqrt_a #1.\XINT_sqrt_small_d }% +\def\XINT_sqrt_big_a #1.{\XINT_sqrt_a #1.\XINT_sqrt_big_d }% +\def\XINT_sqrt_a #1.% +{% + \ifodd #1 + \expandafter\XINT_sqrt_bO + \else + \expandafter\XINT_sqrt_bE + \fi + #1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_bE #1.#2#3#4% +{% + \XINT_sqrt_c {#3#4}#2{#1}#3#4% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_bO #1.#2#3% +{% + \XINT_sqrt_c #3#2{#1}#3% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_c #1#2% +{% + \expandafter #2% + \the\numexpr \ifnum #1>\xint_c_ii + \ifnum #1>\xint_c_vi + \ifnum #1>12 \ifnum #1>20 \ifnum #1>30 + \ifnum #1>42 \ifnum #1>56 \ifnum #1>72 + \ifnum #1>90 + 10\else 9\fi \else 8\fi \else 7\fi \else 6\fi \else 5\fi + \else 4\fi \else 3\fi \else 2\fi \else 1\fi .% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_small_d #1.#2% +{% + \expandafter\XINT_sqrt_small_e + \the\numexpr #1\ifcase \numexpr #2/\xint_c_ii-\xint_c_i\relax + \or 0\or 00\or 000\or 0000\fi .% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_small_e #1.#2.% +{% + \expandafter\XINT_sqrt_small_ea\the\numexpr #1*#1-#2.#1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_small_ea #1% +{% + \if0#1\xint_dothis\XINT_sqrt_small_ez\fi + \if-#1\xint_dothis\XINT_sqrt_small_eb\fi + \xint_orthat\XINT_sqrt_small_f #1% +}% +\def\XINT_sqrt_small_ez 0.#1.{\expandafter{\the\numexpr#1+\xint_c_i + \expandafter}\expandafter{\the\numexpr #1*\xint_c_ii+\xint_c_i}}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_small_eb -#1.#2.% +{% + \expandafter\XINT_sqrt_small_ec \the\numexpr + (#1-\xint_c_i+#2)/(\xint_c_ii*#2).#1.#2.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_small_ec #1.#2.#3.% +{% + \expandafter\XINT_sqrt_small_f \the\numexpr + -#2+\xint_c_ii*#3*#1+#1*#1\expandafter.\the\numexpr #3+#1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_small_f #1.#2.% +{% + \expandafter\XINT_sqrt_small_g + \the\numexpr (#1+#2)/(\xint_c_ii*#2)-\xint_c_i.#1.#2.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_small_g #1#2.% +{% + \if 0#1% + \expandafter\XINT_sqrt_small_end + \else + \expandafter\XINT_sqrt_small_h + \fi + #1#2.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_small_h #1.#2.#3.% +{% + \expandafter\XINT_sqrt_small_f + \the\numexpr #2-\xint_c_ii*#1*#3+#1*#1\expandafter.% + \the\numexpr #3-#1.% +}% +\def\XINT_sqrt_small_end #1.#2.#3.{{#3}{#2}}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_d #1.#2% +{% + \ifodd #2 \xint_dothis{\expandafter\XINT_sqrt_big_eO}\fi + \xint_orthat{\expandafter\XINT_sqrt_big_eE}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \the\numexpr (#2-\xint_c_i)/\xint_c_ii.#1;% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_eE #1;#2#3#4#5#6#7#8#9% +{% + \XINT_sqrt_big_eE_a #1;{#2#3#4#5#6#7#8#9}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_eE_a #1.#2;#3% +{% + \expandafter\XINT_sqrt_bigormed_f + \romannumeral0\XINT_sqrt_small_e #2000.#3.#1;% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_eO #1;#2#3#4#5#6#7#8#9% +{% + \XINT_sqrt_big_eO_a #1;{#2#3#4#5#6#7#8#9}% +}% +\def\XINT_sqrt_big_eO_a #1.#2;#3#4% +{% + \expandafter\XINT_sqrt_bigormed_f + \romannumeral0\XINT_sqrt_small_e #20000.#3#4.#1;% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_bigormed_f #1#2#3;% +{% + \ifnum#3<\xint_c_ix + \xint_dothis {\csname XINT_sqrt_med_f\romannumeral#3\endcsname}% + \fi + \xint_orthat\XINT_sqrt_big_f #1.#2.#3;% +}% +\def\XINT_sqrt_med_fv {\XINT_sqrt_med_fa .}% +\def\XINT_sqrt_med_fvi {\XINT_sqrt_med_fa 0.}% +\def\XINT_sqrt_med_fvii {\XINT_sqrt_med_fa 00.}% +\def\XINT_sqrt_med_fviii{\XINT_sqrt_med_fa 000.}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_med_fa #1.#2.#3.#4;% +{% + \expandafter\XINT_sqrt_med_fb + \the\numexpr (#30#1-5#1)/(\xint_c_ii*#2).#1.#2.#3.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_med_fb #1.#2.#3.#4.#5.% +{% + \expandafter\XINT_sqrt_small_ea + \the\numexpr (#40#2-\xint_c_ii*#3*#1)*10#2+(#1*#1-#5)\expandafter.% + \the\numexpr #30#2-#1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_f #1;#2#3#4#5#6#7#8#9% +{% + \XINT_sqrt_big_fa #1;{#2#3#4#5#6#7#8#9}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_fa #1.#2.#3;#4% +{% + \expandafter\XINT_sqrt_big_ga + \the\numexpr #3-\xint_c_viii\expandafter.% + \romannumeral0\XINT_sqrt_med_fa 000.#1.#2.;#4.% +}% +% \end{macrocode} +% \lverb|& +% +% | +% \begin{macrocode} +\def\XINT_sqrt_big_ga #1.#2#3% +{% + \ifnum #1>\xint_c_viii + \expandafter\XINT_sqrt_big_gb\else + \expandafter\XINT_sqrt_big_ka + \fi #1.#3.#2.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_gb #1.#2.#3.% +{% + \expandafter\XINT_sqrt_big_gc + \the\numexpr (\xint_c_ii*#2-\xint_c_i)*\xint_c_x^viii/(\xint_c_iv*#3).% + #3.#2.#1;% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_gc #1.#2.#3.% +{% + \expandafter\XINT_sqrt_big_gd + \romannumeral0\xintiiadd + {\xintiiSub {#300000000}{\xintDouble{\xintiiMul{#2}{#1}}}00000000}% + {\xintiiSqr {#1}}.% + \romannumeral0\xintiisub{#200000000}{#1}.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_gd #1.#2.% +{% + \expandafter\XINT_sqrt_big_ge #2.#1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_ge #1;#2#3#4#5#6#7#8#9% + {\XINT_sqrt_big_gf #1.#2#3#4#5#6#7#8#9;}% +\def\XINT_sqrt_big_gf #1;#2#3#4#5#6#7#8#9% + {\XINT_sqrt_big_gg #1#2#3#4#5#6#7#8#9.}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_gg #1.#2.#3.#4.% +{% + \expandafter\XINT_sqrt_big_gloop + \expandafter\xint_c_xvi\expandafter.% + \the\numexpr #3-\xint_c_viii\expandafter.% + \romannumeral0\xintiisub {#2}{\xintiNum{#4}}.#1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_gloop #1.#2.% +{% + \unless\ifnum #1<#2 \xint_dothis\XINT_sqrt_big_ka \fi + \xint_orthat{\XINT_sqrt_big_gi #1.}#2.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_gi #1.% +{% + \expandafter\XINT_sqrt_big_gj\romannumeral\xintreplicate{#1}0.#1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_gj #1.#2.#3.#4.#5.% +{% + \expandafter\XINT_sqrt_big_gk + \romannumeral0\xintiidivision {#4#1}% + {\XINT_dbl #5\xint_bye2345678\xint_bye*\xint_c_ii\relax}.% + #1.#5.#2.#3.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_gk #1#2.#3.#4.% +{% + \expandafter\XINT_sqrt_big_gl + \romannumeral0\xintiiadd {#2#3}{\xintiiSqr{#1}}.% + \romannumeral0\xintiisub {#4#3}{#1}.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_gl #1.#2.% +{% + \expandafter\XINT_sqrt_big_gm #2.#1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_gm #1.#2.#3.#4.#5.% +{% + \expandafter\XINT_sqrt_big_gn +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \romannumeral0\XINT_split_fromleft\xint_c_ii*#3.#5\xint_bye2345678\xint_bye..% + #1.#2.#3.#4.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_gn #1.#2.#3.#4.#5.#6.% +{% + \expandafter\XINT_sqrt_big_gloop + \the\numexpr \xint_c_ii*#5\expandafter.% + \the\numexpr #6-#5\expandafter.% + \romannumeral0\xintiisub{#4}{\xintiNum{#1}}.#3.#2.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_ka #1.#2.#3.#4.% +{% + \expandafter\XINT_sqrt_big_kb +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \romannumeral0\XINT_dsx_addzeros {#1}#3;.% + \romannumeral0\xintiisub + {\XINT_dsx_addzerosnofuss {\xint_c_ii*#1}#2;}% + {\xintiNum{#4}}.% +}% +\def\XINT_sqrt_big_kb #1.#2.% +{% + \expandafter\XINT_sqrt_big_kc #2.#1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_kc #1% +{% + \if0#1\xint_dothis\XINT_sqrt_big_kz\fi + \xint_orthat\XINT_sqrt_big_kloop #1% +}% +\def\XINT_sqrt_big_kz 0.#1.% +{% + \expandafter\XINT_sqrt_big_kend + \romannumeral0% + \xintinc{\XINT_dbl#1\xint_bye2345678\xint_bye*\xint_c_ii\relax}.#1.% +}% +\def\XINT_sqrt_big_kend #1.#2.% +{% + \expandafter{\romannumeral0\xintinc{#2}}{#1}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_kloop #1.#2.% +{% + \expandafter\XINT_sqrt_big_ke + \romannumeral0\xintiidivision{#1}% + {\romannumeral0\XINT_dbl #2\xint_bye2345678\xint_bye*\xint_c_ii\relax}{#2}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_ke #1% +{% + \if0\XINT_Sgn #1\xint: + \expandafter \XINT_sqrt_big_end + \else \expandafter \XINT_sqrt_big_kf + \fi {#1}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_kf #1#2#3% +{% + \expandafter\XINT_sqrt_big_kg + \romannumeral0\xintiisub {#3}{#1}.% + \romannumeral0\xintiiadd {#2}{\xintiiSqr {#1}}.% +}% +\def\XINT_sqrt_big_kg #1.#2.% +{% + \expandafter\XINT_sqrt_big_kloop #2.#1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_sqrt_big_end #1#2#3{{#3}{#2}}% +% \end{macrocode} +% \subsection{\csh{xintiiSqrt}, \csh{xintiiSqrtR}} +% \begin{macrocode} +\def\xintiiSqrt {\romannumeral0\xintiisqrt }% +\def\xintiisqrt {\expandafter\XINT_sqrt_post\romannumeral0\xintiisquareroot }% +\def\XINT_sqrt_post #1#2{\XINT_dec #1\XINT_dec_bye234567890\xint_bye}% +\def\xintiiSqrtR {\romannumeral0\xintiisqrtr }% +\def\xintiisqrtr {\expandafter\XINT_sqrtr_post\romannumeral0\xintiisquareroot }% +% \end{macrocode} +% \lverb|N = (#1)^2 - #2 avec #1 le plus petit possible et #2>0 (hence #2<2*#1). +% (#1-.5)^2=#1^2-#1+.25=N+#2-#1+.25. Si 0<#2<#1, <= N-0.75<N, donc rounded->#1 +% si #2>=#1, (#1-.5)^2>=N+.25>N, donc rounded->#1-1.| +% \begin{macrocode} +\def\XINT_sqrtr_post #1#2% + {\xintiiifLt {#2}{#1}{ #1}{\XINT_dec #1\XINT_dec_bye234567890\xint_bye}}% +% \end{macrocode} +% \subsection{\csh{xintiiBinomial}} +% \lverb|2015/11/28-29 for 1.2f. +% +% 2016/11/19 for 1.2h: I truly can't understand why I hard-coded last +% year an error-message for arguments outside of the range for binomial +% formula. Naturally there should be no error but a rather a 0 return +% value for binomial(x,y), if y<0 or x<y ! +% +% I really lack some kind of infinity or NaN value. +% +% 1.2o deprecates \xintiBinomial. (which xintfrac.sty redefined to use +% \xintNum) +% | +% \begin{macrocode} +\def\xintiiBinomial {\romannumeral0\xintiibinomial }% +\def\xintiibinomial #1#2% +{% + \expandafter\XINT_binom_pre\the\numexpr #1\expandafter.\the\numexpr #2.% +}% +\def\XINT_binom_pre #1.#2.% +{% + \expandafter\XINT_binom_fork \the\numexpr#1-#2.#2.#1.% +}% +% \end{macrocode} +% \lverb|k.x-k.x. I hesitated to restrict maximal allowed value of x to 10000. +% Finally I don't. But due to using small multiplication and small division, x +% must have at most eight digits. If x>=2^31 an arithmetic overflow error will +% have happened already.| +% \begin{macrocode} +\def\XINT_binom_fork #1#2.#3#4.#5#6.% +{% + \if-#5\xint_dothis{\XINT_signalcondition{InvalidOperation}{Binomial with + negative first arg: #5#6}{}{0}}\fi + \if-#1\xint_dothis{ 0}\fi + \if-#3\xint_dothis{ 0}\fi + \if0#1\xint_dothis{ 1}\fi + \if0#3\xint_dothis{ 1}\fi + \ifnum #5#6>\xint_c_x^viii_mone\xint_dothis + {\XINT_signalcondition{InvalidOperation}{Binomial with too + large argument: 99999999 < #5#6}{}{0}}\fi + \ifnum #1#2>#3#4 \xint_dothis{\XINT_binom_a #1#2.#3#4.}\fi + \xint_orthat{\XINT_binom_a #3#4.#1#2.}% +}% +% \end{macrocode} +% \lverb|x-k.k. avec 0<k<x, k<=x-k. Les divisions produiront en extra après le +% quotient un terminateur 1!\Z!0!. On va procéder par petite multiplication +% suivie par petite division. Donc ici on met le 1!\Z!0! pour amorcer. +% +% Le \xint_bye!2!3!4!5!6!7!8!9!\xint_bye\xint_c_i\relax est le terminateur pour le +% \XINT_unsep_cuzsmall final.| +% \begin{macrocode} +\def\XINT_binom_a #1.#2.% +{% + \expandafter\XINT_binom_b\the\numexpr \xint_c_i+#1.1.#2.100000001!1!;!0!% +}% +% \end{macrocode} +% \lverb|y=x-k+1.j=1.k. On va évaluer par y/1*(y+1)/2*(y+2)/3 etc... On essaie +% de regrouper de manière à utiliser au mieux \numexpr. On peut aller jusqu'à +% x=10000 car 9999*10000<10^8. 463*464*465=99896880, 98*99*100*101=97990200. +% On va vérifier à chaque étape si on dépasse un seuil. Le style de +% l'implémentation diffère de celui que j'avais utilisé pour \xintiiFac. On +% pourrait tout-à-fait avoir une verybigloop, mais bon. Je rajoute aussi un +% verysmall. Le traitement est un peu différent pour elle afin d'aller jusqu'à +% x=29 (et pas seulement 26 si je suivais le modèle des autres, mais je veux +% pouvoir faire binomial(29,1), binomial(29,2), ... en vsmall).| +% \begin{macrocode} +\def\XINT_binom_b #1.% +{% + \ifnum #1>9999 \xint_dothis\XINT_binom_vbigloop \fi + \ifnum #1>463 \xint_dothis\XINT_binom_bigloop \fi + \ifnum #1>98 \xint_dothis\XINT_binom_medloop \fi + \ifnum #1>29 \xint_dothis\XINT_binom_smallloop \fi + \xint_orthat\XINT_binom_vsmallloop #1.% +}% +% \end{macrocode} +% \lverb|y.j.k. Au départ on avait x-k+1.1.k. Ensuite on a des blocs 1<8d>! +% donnant le résultat intermédiaire, dans l'ordre, et à la fin on a 1!1;!0!. +% Dans smallloop on peut prendre 4 par 4.| +% \begin{macrocode} +\def\XINT_binom_smallloop #1.#2.#3.% +{% + \ifcase\numexpr #3-#2\relax + \expandafter\XINT_binom_end_ + \or \expandafter\XINT_binom_end_i + \or \expandafter\XINT_binom_end_ii + \or \expandafter\XINT_binom_end_iii + \else\expandafter\XINT_binom_smallloop_a + \fi #1.#2.#3.% +}% +% \end{macrocode} +% \lverb|Ça m'ennuie un peu de reprendre les #1, #2, #3 ici. On a besoin de +% \numexpr pour \XINT_binom_div, mais de \romannumeral0 pour le unsep après +% \XINT_binom_mul.| +% \begin{macrocode} +\def\XINT_binom_smallloop_a #1.#2.#3.% +{% + \expandafter\XINT_binom_smallloop_b + \the\numexpr #1+\xint_c_iv\expandafter.% + \the\numexpr #2+\xint_c_iv\expandafter.% + \the\numexpr #3\expandafter.% + \the\numexpr\expandafter\XINT_binom_div + \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)*(#2+\xint_c_iii)\expandafter + !\romannumeral0\expandafter\XINT_binom_mul + \the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% +}% +\def\XINT_binom_smallloop_b #1.% +{% + \ifnum #1>98 \expandafter\XINT_binom_medloop \else + \expandafter\XINT_binom_smallloop \fi #1.% +}% +% \end{macrocode} +% \lverb|Ici on prend trois par trois.| +% \begin{macrocode} +\def\XINT_binom_medloop #1.#2.#3.% +{% + \ifcase\numexpr #3-#2\relax + \expandafter\XINT_binom_end_ + \or \expandafter\XINT_binom_end_i + \or \expandafter\XINT_binom_end_ii + \else\expandafter\XINT_binom_medloop_a + \fi #1.#2.#3.% +}% +\def\XINT_binom_medloop_a #1.#2.#3.% +{% + \expandafter\XINT_binom_medloop_b + \the\numexpr #1+\xint_c_iii\expandafter.% + \the\numexpr #2+\xint_c_iii\expandafter.% + \the\numexpr #3\expandafter.% + \the\numexpr\expandafter\XINT_binom_div + \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)\expandafter + !\romannumeral0\expandafter\XINT_binom_mul + \the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% +}% +\def\XINT_binom_medloop_b #1.% +{% + \ifnum #1>463 \expandafter\XINT_binom_bigloop \else + \expandafter\XINT_binom_medloop \fi #1.% +}% +% \end{macrocode} +% \lverb|Ici on prend deux par deux.| +% \begin{macrocode} +\def\XINT_binom_bigloop #1.#2.#3.% +{% + \ifcase\numexpr #3-#2\relax + \expandafter\XINT_binom_end_ + \or \expandafter\XINT_binom_end_i + \else\expandafter\XINT_binom_bigloop_a + \fi #1.#2.#3.% +}% +\def\XINT_binom_bigloop_a #1.#2.#3.% +{% + \expandafter\XINT_binom_bigloop_b + \the\numexpr #1+\xint_c_ii\expandafter.% + \the\numexpr #2+\xint_c_ii\expandafter.% + \the\numexpr #3\expandafter.% + \the\numexpr\expandafter\XINT_binom_div + \the\numexpr #2*(#2+\xint_c_i)\expandafter + !\romannumeral0\expandafter\XINT_binom_mul + \the\numexpr #1*(#1+\xint_c_i)!% +}% +\def\XINT_binom_bigloop_b #1.% +{% + \ifnum #1>9999 \expandafter\XINT_binom_vbigloop \else + \expandafter\XINT_binom_bigloop \fi #1.% +}% +% \end{macrocode} +% \lverb|Et finalement un par un.| +% \begin{macrocode} +\def\XINT_binom_vbigloop #1.#2.#3.% +{% + \ifnum #3=#2 + \expandafter\XINT_binom_end_ + \else\expandafter\XINT_binom_vbigloop_a + \fi #1.#2.#3.% +}% +\def\XINT_binom_vbigloop_a #1.#2.#3.% +{% + \expandafter\XINT_binom_vbigloop + \the\numexpr #1+\xint_c_i\expandafter.% + \the\numexpr #2+\xint_c_i\expandafter.% + \the\numexpr #3\expandafter.% + \the\numexpr\expandafter\XINT_binom_div\the\numexpr #2\expandafter + !\romannumeral0\XINT_binom_mul #1!% +}% +% \end{macrocode} +% \lverb|y.j.k. La partie very small. y est au plus 26 (non 29 mais retesté +% dans \XINT_binom_vsmallloop_a), et tous les binomial(29,n) sont <10^8. On +% peut donc faire y(y+1)(y+2)(y+3) et aussi il y a le fait que etex fait a*b/c +% en double precision. Pour ne pas bifurquer à la fin sur smallloop, si n=27, +% 27, ou 29 on procède un peu différemment des autres boucles. Si je testais +% aussi #1 après #3-#2 pour les autres il faudrait des terminaisons +% différentes.| +% \begin{macrocode} +\def\XINT_binom_vsmallloop #1.#2.#3.% +{% + \ifcase\numexpr #3-#2\relax + \expandafter\XINT_binom_vsmallend_ + \or \expandafter\XINT_binom_vsmallend_i + \or \expandafter\XINT_binom_vsmallend_ii + \or \expandafter\XINT_binom_vsmallend_iii + \else\expandafter\XINT_binom_vsmallloop_a + \fi #1.#2.#3.% +}% +\def\XINT_binom_vsmallloop_a #1.% +{% + \ifnum #1>26 \expandafter\XINT_binom_smallloop_a \else + \expandafter\XINT_binom_vsmallloop_b \fi #1.% +}% +\def\XINT_binom_vsmallloop_b #1.#2.#3.% +{% + \expandafter\XINT_binom_vsmallloop + \the\numexpr #1+\xint_c_iv\expandafter.% + \the\numexpr #2+\xint_c_iv\expandafter.% + \the\numexpr #3\expandafter.% + \the\numexpr \expandafter\XINT_binom_vsmallmuldiv + \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)*(#2+\xint_c_iii)\expandafter + !\the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% +}% +% \end{macrocode} +% \begin{macrocode} +\def\XINT_binom_mul #1!#21!;!0!% +{% + \expandafter\XINT_rev_nounsep\expandafter{\expandafter}% + \the\numexpr\expandafter\XINT_smallmul + \the\numexpr\xint_c_x^viii+#1\expandafter + !\romannumeral0\XINT_rev_nounsep {}1;!#2% + \R!\R!\R!\R!\R!\R!\R!\R!\W + \R!\R!\R!\R!\R!\R!\R!\R!\W + 1;!% +}% +\def\XINT_binom_div #1!1;!% +{% + \expandafter\XINT_smalldivx_a + \the\numexpr #1/\xint_c_ii\expandafter\xint: + \the\numexpr \xint_c_x^viii+#1!% +}% +% \end{macrocode} +% \lverb|Vaguement envisagé d'éviter le 10^8+ mais bon.| +% \begin{macrocode} +\def\XINT_binom_vsmallmuldiv #1!#2!1#3!{\xint_c_x^viii+#2*#3/#1!}% +% \end{macrocode} +% \lverb|On a des terminaisons communes aux trois situations small, med, big, +% et on est sûr de pouvoir faire les multiplications dans \numexpr, car on +% vient ici *après* avoir comparé à 9999 ou 463 ou 98.| +% \begin{macrocode} +\def\XINT_binom_end_iii #1.#2.#3.% +{% + \expandafter\XINT_binom_finish + \the\numexpr\expandafter\XINT_binom_div + \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)*(#2+\xint_c_iii)\expandafter + !\romannumeral0\expandafter\XINT_binom_mul + \the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% +}% +\def\XINT_binom_end_ii #1.#2.#3.% +{% + \expandafter\XINT_binom_finish + \the\numexpr\expandafter\XINT_binom_div + \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)\expandafter + !\romannumeral0\expandafter\XINT_binom_mul + \the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% +}% +\def\XINT_binom_end_i #1.#2.#3.% +{% + \expandafter\XINT_binom_finish + \the\numexpr\expandafter\XINT_binom_div + \the\numexpr #2*(#2+\xint_c_i)\expandafter + !\romannumeral0\expandafter\XINT_binom_mul + \the\numexpr #1*(#1+\xint_c_i)!% +}% +\def\XINT_binom_end_ #1.#2.#3.% +{% + \expandafter\XINT_binom_finish + \the\numexpr\expandafter\XINT_binom_div\the\numexpr #2\expandafter + !\romannumeral0\XINT_binom_mul #1!% +}% +% \end{macrocode} +% \begin{macrocode} +\def\XINT_binom_finish #1;!0!% + {\XINT_unsep_cuzsmall #1\xint_bye!2!3!4!5!6!7!8!9!\xint_bye\xint_c_i\relax}% +% \end{macrocode} +% \lverb|Duplication de code seulement pour la boucle avec très +% petits coeffs, mais en plus on fait au maximum des possibilités. (on +% pourrait tester plus le résultat déjà obtenu).| +% \begin{macrocode} +\def\XINT_binom_vsmallend_iii #1.% +{% + \ifnum #1>26 \expandafter\XINT_binom_end_iii \else + \expandafter\XINT_binom_vsmallend_iiib \fi #1.% +}% +\def\XINT_binom_vsmallend_iiib #1.#2.#3.% +{% + \expandafter\XINT_binom_vsmallfinish + \the\numexpr \expandafter\XINT_binom_vsmallmuldiv + \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)*(#2+\xint_c_iii)\expandafter + !\the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% +}% +\def\XINT_binom_vsmallend_ii #1.% +{% + \ifnum #1>27 \expandafter\XINT_binom_end_ii \else + \expandafter\XINT_binom_vsmallend_iib \fi #1.% +}% +\def\XINT_binom_vsmallend_iib #1.#2.#3.% +{% + \expandafter\XINT_binom_vsmallfinish + \the\numexpr \expandafter\XINT_binom_vsmallmuldiv + \the\numexpr #2*(#2+\xint_c_i)*(#2+\xint_c_ii)\expandafter + !\the\numexpr #1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% +}% +\def\XINT_binom_vsmallend_i #1.% +{% + \ifnum #1>28 \expandafter\XINT_binom_end_i \else + \expandafter\XINT_binom_vsmallend_ib \fi #1.% +}% +\def\XINT_binom_vsmallend_ib #1.#2.#3.% +{% + \expandafter\XINT_binom_vsmallfinish + \the\numexpr \expandafter\XINT_binom_vsmallmuldiv + \the\numexpr #2*(#2+\xint_c_i)\expandafter + !\the\numexpr #1*(#1+\xint_c_i)!% +}% +\def\XINT_binom_vsmallend_ #1.% +{% + \ifnum #1>29 \expandafter\XINT_binom_end_ \else + \expandafter\XINT_binom_vsmallend_b \fi #1.% +}% +\def\XINT_binom_vsmallend_b #1.#2.#3.% +{% + \expandafter\XINT_binom_vsmallfinish + \the\numexpr\XINT_binom_vsmallmuldiv #2!#1!% +}% +\def\XINT_binom_vsmallfinish#1{% +\def\XINT_binom_vsmallfinish1##1!1!;!0!{\expandafter#1\the\numexpr##1\relax}% +}\XINT_binom_vsmallfinish{ }% +% \end{macrocode} +% \subsection{\csh{xintiiPFactorial}} +% \lverb?2015/11/29 for 1.2f. Partial factorial pfac(a,b)=(a+1)...b, only for +% non-negative integers with a<=b<10^8. +% +% 1.2h (2016/11/20) removes the non-negativity condition. It was a bit +% unfortunate that the code raised \xintError:OutOfRangePFac if 0<=a<=b<10^8 +% was violated. The rule now applied is to interpret pfac(a,b) as the product +% for a<j<=b (not as a ratio of Gamma function), hence if a>=b, return 1 +% because of an empty product. If a<b: if a<0, return 0 for b>=0 and +% (-1)^(b-a) times |b|...(|a|-1) for b<0. But only for the range 0<= +% a <= b < 10^8 is the macro result to be considered as stable.? +% \begin{macrocode} +\def\xintiiPFactorial {\romannumeral0\xintiipfactorial }% +\def\xintiipfactorial #1#2% +{% + \expandafter\XINT_pfac_fork\the\numexpr#1\expandafter.\the\numexpr #2.% +}% +\def\xintPFactorial{\romannumeral0\xintpfactorial}% +\let\xintpfactorial\xintiipfactorial +% \end{macrocode} +% \lverb|Code is a simplified version of the one for \xintiiBinomial, with no +% attempt at implementing a "very small" branch.| +% \begin{macrocode} +\def\XINT_pfac_fork #1#2.#3#4.% +{% + \unless\ifnum #1#2<#3#4 \xint_dothis\XINT_pfac_one\fi + \if-#3\xint_dothis\XINT_pfac_neg\fi + \if-#1\xint_dothis\XINT_pfac_zero\fi + \ifnum #3#4>\xint_c_x^viii_mone\xint_dothis\XINT_pfac_outofrange\fi + \xint_orthat \XINT_pfac_a #1#2.#3#4.% +}% +\def\XINT_pfac_outofrange #1.#2.% + {\XINT_signalcondition{InvalidOperation}{PFactorial with + too big second arg: 99999999 < #2}{}{0}}% +\def\XINT_pfac_one #1.#2.{ 1}% +\def\XINT_pfac_zero #1.#2.{ 0}% +\def\XINT_pfac_neg -#1.-#2.% +{% + \ifnum #1>\xint_c_x^viii\xint_dothis\XINT_pfac_outofrange\fi + \xint_orthat + {\ifodd\numexpr#2-#1\relax\xint_afterfi{\expandafter-\romannumeral`&&@}\fi + \expandafter\XINT_pfac_a }% + \the\numexpr #2-\xint_c_i\expandafter.\the\numexpr#1-\xint_c_i.% +}% +\def\XINT_pfac_a #1.#2.% +{% + \expandafter\XINT_pfac_b\the\numexpr \xint_c_i+#1.#2.100000001!1;!% + 1\R!1\R!1\R!1\R!1\R!1\R!1\R!1\R!\W +}% +\def\XINT_pfac_b #1.% +{% + \ifnum #1>9999 \xint_dothis\XINT_pfac_vbigloop \fi + \ifnum #1>463 \xint_dothis\XINT_pfac_bigloop \fi + \ifnum #1>98 \xint_dothis\XINT_pfac_medloop \fi + \xint_orthat\XINT_pfac_smallloop #1.% +}% +\def\XINT_pfac_smallloop #1.#2.% +{% + \ifcase\numexpr #2-#1\relax + \expandafter\XINT_pfac_end_ + \or \expandafter\XINT_pfac_end_i + \or \expandafter\XINT_pfac_end_ii + \or \expandafter\XINT_pfac_end_iii + \else\expandafter\XINT_pfac_smallloop_a + \fi #1.#2.% +}% +\def\XINT_pfac_smallloop_a #1.#2.% +{% + \expandafter\XINT_pfac_smallloop_b + \the\numexpr #1+\xint_c_iv\expandafter.% + \the\numexpr #2\expandafter.% + \the\numexpr\expandafter\XINT_smallmul + \the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% +}% +\def\XINT_pfac_smallloop_b #1.% +{% + \ifnum #1>98 \expandafter\XINT_pfac_medloop \else + \expandafter\XINT_pfac_smallloop \fi #1.% +}% +\def\XINT_pfac_medloop #1.#2.% +{% + \ifcase\numexpr #2-#1\relax + \expandafter\XINT_pfac_end_ + \or \expandafter\XINT_pfac_end_i + \or \expandafter\XINT_pfac_end_ii + \else\expandafter\XINT_pfac_medloop_a + \fi #1.#2.% +}% +\def\XINT_pfac_medloop_a #1.#2.% +{% + \expandafter\XINT_pfac_medloop_b + \the\numexpr #1+\xint_c_iii\expandafter.% + \the\numexpr #2\expandafter.% + \the\numexpr\expandafter\XINT_smallmul + \the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% +}% +\def\XINT_pfac_medloop_b #1.% +{% + \ifnum #1>463 \expandafter\XINT_pfac_bigloop \else + \expandafter\XINT_pfac_medloop \fi #1.% +}% +\def\XINT_pfac_bigloop #1.#2.% +{% + \ifcase\numexpr #2-#1\relax + \expandafter\XINT_pfac_end_ + \or \expandafter\XINT_pfac_end_i + \else\expandafter\XINT_pfac_bigloop_a + \fi #1.#2.% +}% +\def\XINT_pfac_bigloop_a #1.#2.% +{% + \expandafter\XINT_pfac_bigloop_b + \the\numexpr #1+\xint_c_ii\expandafter.% + \the\numexpr #2\expandafter.% + \the\numexpr\expandafter + \XINT_smallmul\the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)!% +}% +\def\XINT_pfac_bigloop_b #1.% +{% + \ifnum #1>9999 \expandafter\XINT_pfac_vbigloop \else + \expandafter\XINT_pfac_bigloop \fi #1.% +}% +\def\XINT_pfac_vbigloop #1.#2.% +{% + \ifnum #2=#1 + \expandafter\XINT_pfac_end_ + \else\expandafter\XINT_pfac_vbigloop_a + \fi #1.#2.% +}% +\def\XINT_pfac_vbigloop_a #1.#2.% +{% + \expandafter\XINT_pfac_vbigloop + \the\numexpr #1+\xint_c_i\expandafter.% + \the\numexpr #2\expandafter.% + \the\numexpr\expandafter\XINT_smallmul\the\numexpr\xint_c_x^viii+#1!% +}% +\def\XINT_pfac_end_iii #1.#2.% +{% + \expandafter\XINT_mul_out + \the\numexpr\expandafter\XINT_smallmul + \the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% +}% +\def\XINT_pfac_end_ii #1.#2.% +{% + \expandafter\XINT_mul_out + \the\numexpr\expandafter\XINT_smallmul + \the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% +}% +\def\XINT_pfac_end_i #1.#2.% +{% + \expandafter\XINT_mul_out + \the\numexpr\expandafter\XINT_smallmul + \the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)!% +}% +\def\XINT_pfac_end_ #1.#2.% +{% + \expandafter\XINT_mul_out + \the\numexpr\expandafter\XINT_smallmul\the\numexpr \xint_c_x^viii+#1!% +}% +% \end{macrocode} +% \subsection{\csh{xintBool}, \csh{xintToggle}} +% \lverb|1.09c| +% \begin{macrocode} +\def\xintBool #1{\romannumeral`&&@% + \csname if#1\endcsname\expandafter1\else\expandafter0\fi }% +\def\xintToggle #1{\romannumeral`&&@\iftoggle{#1}{1}{0}}% +% \end{macrocode} +% \subsection{\cshnolabel{xintGCD}, \cshnolabel{xintiiGCD}} +% Copied over from \csbxint{iiGCD} of \xintgcdnameimp at |1.3d| to +% support |gcd()| function in \csbxint{iiexpr}. +% \begin{macrocode} +\def\xintiiGCD {\romannumeral0\xintiigcd }% +\def\xintiigcd #1{\expandafter\XINT_iigcd\romannumeral0\xintiiabs#1\xint:}% +\def\XINT_iigcd #1#2\xint:#3% +{% + \expandafter\XINT_gcd_fork\expandafter#1% + \romannumeral0\xintiiabs#3\xint:#1#2\xint: +}% +\def\XINT_gcd_fork #1#2% +{% + \xint_UDzerofork + #1\XINT_gcd_Aiszero + #2\XINT_gcd_Biszero + 0\XINT_gcd_loop + \krof + #2% +}% +\def\XINT_gcd_AisZero #1\xint:#2\xint:{ #1}% +\def\XINT_gcd_BisZero #1\xint:#2\xint:{ #2}% +\def\XINT_gcd_loop #1\xint:#2\xint: +{% + \expandafter\expandafter\expandafter\XINT_gcd_CheckRem + \expandafter\xint_secondoftwo + \romannumeral0\XINT_div_prepare {#1}{#2}\xint:#1\xint: +}% +\def\XINT_gcd_CheckRem #1% +{% + \xint_gob_til_zero #1\XINT_gcd_end0\XINT_gcd_loop #1% +}% +\def\XINT_gcd_end0\XINT_gcd_loop #1\xint:#2\xint:{ #2}% +% \end{macrocode} +% \subsection{\cshnolabel{xintLCM}, \cshnolabel{xintiiLCM}} +% \begin{macrocode} +\def\xintiiLCM {\romannumeral0\xintiilcm}% +\def\xintiilcm #1{\expandafter\XINT_iilcm\romannumeral0\xintiiabs#1\xint:}% +\def\XINT_iilcm #1#2\xint:#3% +{% + \expandafter\XINT_lcm_fork\expandafter#1% + \romannumeral0\xintiiabs#3\xint:#1#2\xint: +}% +\def\XINT_lcm_fork #1#2% +{% + \xint_UDzerofork + #1\XINT_lcm_iszero + #2\XINT_lcm_iszero + 0\XINT_lcm_notzero + \krof + #2% +}% +\def\XINT_lcm_iszero #1\xint:#2\xint:{ 0}% +\def\XINT_lcm_notzero #1\xint:#2\xint: +{% + \expandafter\XINT_lcm_end\romannumeral0% + \expandafter\expandafter\expandafter\XINT_gcd_CheckRem + \expandafter\xint_secondoftwo + \romannumeral0\XINT_div_prepare {#1}{#2}\xint:#1\xint: + \xint:#1\xint:#2\xint: +}% +\def\XINT_lcm_end #1\xint:#2\xint:#3\xint:{\xintiimul {#2}{\xintiiQuo{#3}{#1}}}% +% \end{macrocode} +% \subsection{(WIP) \csh{xintRandomDigits}} +% \lverb|1.3b. See user manual. Whether this will be part of xintkernel, +% xintcore, or xint is yet to be decided.| +% \begin{macrocode} +\def\xintRandomDigits{\romannumeral0\xintrandomdigits}% +\def\xintrandomdigits#1% +{% + \csname xint_gob_andstop_\expandafter\XINT_randomdigits\the\numexpr#1\xint: +}% +\def\XINT_randomdigits#1\xint: +{% + \expandafter\XINT_randomdigits_a + \the\numexpr(#1+\xint_c_iii)/\xint_c_viii\xint:#1\xint: +}% +\def\XINT_randomdigits_a#1\xint:#2\xint: +{% + \romannumeral\numexpr\xint_c_viii*#1-#2\csname XINT_% + \romannumeral\XINT_replicate #1\endcsname \csname + XINT_rdg\endcsname +}% +\def\XINT_rdg +{% + \expandafter\XINT_rdg_aux\the\numexpr% + \xint_c_nine_x^viii% + -\xint_texuniformdeviate\xint_c_ii^vii% + -\xint_c_ii^vii*\xint_texuniformdeviate\xint_c_ii^vii% + -\xint_c_ii^xiv*\xint_texuniformdeviate\xint_c_ii^vii% + -\xint_c_ii^xxi*\xint_texuniformdeviate\xint_c_ii^vii% + +\xint_texuniformdeviate\xint_c_x^viii% + \relax% +}% +\def\XINT_rdg_aux#1{XINT_rdg\endcsname}% +\let\XINT_XINT_rdg\endcsname +% \end{macrocode} +% \subsection{(WIP) \csh{XINT_eightrandomdigits}} +% \lverb|1.3b.| +% \begin{macrocode} +\def\XINT_eightrandomdigits +{% + \expandafter\xint_gobble_i\the\numexpr% + \xint_c_nine_x^viii% + -\xint_texuniformdeviate\xint_c_ii^vii% + -\xint_c_ii^vii*\xint_texuniformdeviate\xint_c_ii^vii% + -\xint_c_ii^xiv*\xint_texuniformdeviate\xint_c_ii^vii% + -\xint_c_ii^xxi*\xint_texuniformdeviate\xint_c_ii^vii% + +\xint_texuniformdeviate\xint_c_x^viii% + \relax% +}% +% \end{macrocode} +% \subsection{(WIP) \csh{xintXRandomDigits}} +% \lverb|1.3b.| +% \begin{macrocode} +\def\xintXRandomDigits#1% +{% + \csname xint_gobble_\expandafter\XINT_xrandomdigits\the\numexpr#1\xint: +}% +\def\XINT_xrandomdigits#1\xint: +{% + \expandafter\XINT_xrandomdigits_a + \the\numexpr(#1+\xint_c_iii)/\xint_c_viii\xint:#1\xint: +}% +\def\XINT_xrandomdigits_a#1\xint:#2\xint: +{% + \romannumeral\numexpr\xint_c_viii*#1-#2\expandafter\endcsname + \romannumeral`&&@\romannumeral + \XINT_replicate #1\endcsname\XINT_eightrandomdigits +}% +% \end{macrocode} +% \subsection{(WIP) \csh{xintiiRandRangeAtoB}} +% \lverb|1.3b. Support for randrange() function. +% +% Wee do it f-expandably for matters of \xintNewExpr etc... The \xintexpr will +% add \xintNum wrapper to possible fractional input. But \xintiiexpr will call +% as is. +% +% TODO: ? implement third argument (STEP) +% TODO: \xintNum wrapper (which truncates) not so good in floatexpr. Use round? +% +% It is an error if b<=a, as in Python.| +% \begin{macrocode} +\def\xintiiRandRangeAtoB{\romannumeral`&&@\xintiirandrangeAtoB}% +\def\xintiirandrangeAtoB#1% +{% + \expandafter\XINT_randrangeAtoB_a\romannumeral`&&@#1\xint: +}% +\def\XINT_randrangeAtoB_a#1\xint:#2% +{% + \xintiiadd{\expandafter\XINT_randrange + \romannumeral0\xintiisub{#2}{#1}\xint:}% + {#1}% +}% +% \end{macrocode} +% \subsection{(WIP) \csh{xintiiRandRange}} +% \lverb|1.3b. Support for randrange().| +% \begin{macrocode} +\def\xintiiRandRange{\romannumeral`&&@\xintiirandrange}% +\def\xintiirandrange#1% +{% + \expandafter\XINT_randrange\romannumeral`&&@#1\xint: +}% +\def\XINT_randrange #1% +{% + \xint_UDzerominusfork + #1-\XINT_randrange_err:empty + 0#1\XINT_randrange_err:empty + 0-\XINT_randrange_a + \krof #1% +}% +\def\XINT_randrange_err:empty#1\xint: +{% + \XINT_expandableerror{Empty range for randrange.} 0% +}% +\def\XINT_randrange_a #1\xint: +{% + \expandafter\XINT_randrange_b\romannumeral0\xintlength{#1}.#1\xint: +}% +\def\XINT_randrange_b #1.% +{% + \ifnum#1<\xint_c_x\xint_dothis{\the\numexpr\XINT_uniformdeviate{}}\fi + \xint_orthat{\XINT_randrange_c #1.}% +}% +\def\XINT_randrange_c #1.#2#3#4#5#6#7#8#9% +{% + \expandafter\XINT_randrange_d + \the\numexpr\expandafter\XINT_uniformdeviate\expandafter + {\expandafter}\the\numexpr\xint_c_i+#2#3#4#5#6#7#8#9\xint:\xint: + #2#3#4#5#6#7#8#9\xint:#1\xint: +}% +% \end{macrocode} +% \lverb|This raises following annex question: immediately after setting the +% seed is it possible for \xintUniformDeviate{N} where N>0 has exactly eight +% digits to return either 0 or N-1 ? It could be that this is never the case, +% then there is a bias in randrange(). Of course there are anyhow only 2^28 +% seeds so randrange(10^X) is by necessity biased when executed immediately +% after setting the seed, if X is at least 9.| +% \begin{macrocode} +\def\XINT_randrange_d #1\xint:#2\xint: +{% + \ifnum#1=\xint_c_\xint_dothis\XINT_randrange_Z\fi + \ifnum#1=#2 \xint_dothis\XINT_randrange_A\fi + \xint_orthat\XINT_randrange_e #1\xint: +}% +\def\XINT_randrange_e #1\xint:#2\xint:#3\xint: +{% + \the\numexpr#1\expandafter\relax + \romannumeral0\xintrandomdigits{#2-\xint_c_viii}% +}% +% \end{macrocode} +% \lverb|This is quite unlikely to get executed but if it does it must +% pay attention to leading zeros, hence the \xintinum. +% We don't have to be +% overly obstinate about removing overheads...| +% \begin{macrocode} +\def\XINT_randrange_Z 0\xint:#1\xint:#2\xint: +{% + \xintinum{\xintRandomDigits{#1-\xint_c_viii}}% +}% +% \end{macrocode} +% \lverb|Here too, overhead is not such a problem. The idea is that we got by +% extraordinary same first 8 digits as upper range bound so we pick at random +% the remaining needed digits in one go and compare with the upper bound. If too +% big, we start again with another random 8 leading digits in given range. No +% need to aim at any kind of efficiency for the check and loop back.| +% \begin{macrocode} +\def\XINT_randrange_A #1\xint:#2\xint:#3\xint: +{% + \expandafter\XINT_randrange_B + \romannumeral0\xintrandomdigits{#2-\xint_c_viii}\xint: + #3\xint:#2.#1\xint: +}% +\def\XINT_randrange_B #1\xint:#2\xint:#3.#4\xint: +{% + \xintiiifLt{#1}{#2}{\XINT_randrange_E}{\XINT_randrange_again}% + #4#1\xint:#3.#4#2\xint: +}% +\def\XINT_randrange_E #1\xint:#2\xint:{ #1}% +\def\XINT_randrange_again #1\xint:{\XINT_randrange_c}% +% \end{macrocode} +% \subsection{Adjustments for engines without uniformdeviate primitive} +% \lverb|1.3b.| +% \begin{macrocode} +\ifdefined\xint_texuniformdeviate +\else + \def\xintrandomdigits#1% + {% + \XINT_expandableerror + {No uniformdeviate at engine level, returning 0.} 0% + }% + \let\xintXRandomDigits\xintRandomDigits + \def\XINT_randrange#1\xint: + {% + \XINT_expandableerror + {No uniformdeviate at engine level, returning 0.} 0% + }% +\fi +\XINT_restorecatcodes_endinput% +% \end{macrocode} +% \StoreCodelineNo {xint} +% \cleardoublepage\let\xintnameUp\undefined +%\gardesactifs +%\let</xint>\relax +%\let<*xintbinhex>\gardesinactifs +%</xint>^^A------------------------------------------------------- +%<*xintbinhex>^^A------------------------------------------------- +%^^A -*- coding: utf-8; mode: doctex; -*- +% \clearpage\csname xintbinhexnameUp\endcsname +% \section{Package \xintbinhexnameimp implementation} +% \RaisedLabel{sec:binheximp} +% +% \localtableofcontents +% +% The commenting is currently (\xintdocdate) very sparse. +% +% The macros from |1.08| (|2013/06/07|) remained unchanged +% until their complete rewrite at |1.2m| (|2017/07/31|). +% +% At |1.2n| dependencies on \xintcorenameimp were removed, so now the package +% loads only \xintkernelnameimp (this could have been done earlier). +% +% Also at |1.2n|, macros evolved again, the main improvements being in the +% increased allowable sizes of the input for |\xintDecToHex|, |\xintDecToBin|, +% |\xintBinToHex|. Use of |\csname| governed expansion at some places rather +% than |\numexpr| with some clean-up after it. +% +% \subsection{Catcodes, \protect\eTeX{} and reload detection} +% +% The code for reload detection was initially copied from \textsc{Heiko +% Oberdiek}'s packages, then modified. +% +% The method for catcodes was also initially directly inspired by these +% packages. +% +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode64=11 % @ + \catcode35=6 % # + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \let\z\endgroup + \expandafter\let\expandafter\x\csname ver@xintbinhex.sty\endcsname + \expandafter\let\expandafter\w\csname ver@xintkernel.sty\endcsname + \expandafter + \ifx\csname PackageInfo\endcsname\relax + \def\y#1#2{\immediate\write-1{Package #1 Info: #2.}}% + \else + \def\y#1#2{\PackageInfo{#1}{#2}}% + \fi + \expandafter + \ifx\csname numexpr\endcsname\relax + \y{xintbinhex}{\numexpr not available, aborting input}% + \aftergroup\endinput + \else + \ifx\x\relax % plain-TeX, first loading of xintbinhex.sty + \ifx\w\relax % but xintkernel.sty not yet loaded. + \def\z{\endgroup\input xintkernel.sty\relax}% + \fi + \else + \def\empty {}% + \ifx\x\empty % LaTeX, first loading, + % variable is initialized, but \ProvidesPackage not yet seen + \ifx\w\relax % xintkernel.sty not yet loaded. + \def\z{\endgroup\RequirePackage{xintkernel}}% + \fi + \else + \aftergroup\endinput % xintbinhex already loaded. + \fi + \fi + \fi +\z% +\XINTsetupcatcodes% defined in xintkernel.sty +% \end{macrocode} +% \subsection{Package identification} +% \begin{macrocode} +\XINT_providespackage +\ProvidesPackage{xintbinhex}% + [2019/04/05 1.3e Expandable binary and hexadecimal conversions (JFB)]% +% \end{macrocode} +% \subsection{Constants, etc...} +% \lverb|1.2n switches to \csname-governed expansion at various places.| +% \begin{macrocode} +\newcount\xint_c_ii^xv \xint_c_ii^xv 32768 +\newcount\xint_c_ii^xvi \xint_c_ii^xvi 65536 +\def\XINT_tmpa #1{\ifx\relax#1\else + \expandafter\edef\csname XINT_csdth_#1\endcsname + {\endcsname\ifcase #1 0\or 1\or 2\or 3\or 4\or 5\or 6\or 7\or + 8\or 9\or A\or B\or C\or D\or E\or F\fi}% + \expandafter\XINT_tmpa\fi }% +\XINT_tmpa {0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}\relax +\def\XINT_tmpa #1{\ifx\relax#1\else + \expandafter\edef\csname XINT_csdtb_#1\endcsname + {\endcsname\ifcase #1 + 0000\or 0001\or 0010\or 0011\or 0100\or 0101\or 0110\or 0111\or + 1000\or 1001\or 1010\or 1011\or 1100\or 1101\or 1110\or 1111\fi}% + \expandafter\XINT_tmpa\fi }% +\XINT_tmpa {0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}\relax +\let\XINT_tmpa\relax +\expandafter\def\csname XINT_csbth_0000\endcsname {\endcsname0}% +\expandafter\def\csname XINT_csbth_0001\endcsname {\endcsname1}% +\expandafter\def\csname XINT_csbth_0010\endcsname {\endcsname2}% +\expandafter\def\csname XINT_csbth_0011\endcsname {\endcsname3}% +\expandafter\def\csname XINT_csbth_0100\endcsname {\endcsname4}% +\expandafter\def\csname XINT_csbth_0101\endcsname {\endcsname5}% +\expandafter\def\csname XINT_csbth_0110\endcsname {\endcsname6}% +\expandafter\def\csname XINT_csbth_0111\endcsname {\endcsname7}% +\expandafter\def\csname XINT_csbth_1000\endcsname {\endcsname8}% +\expandafter\def\csname XINT_csbth_1001\endcsname {\endcsname9}% +\expandafter\def\csname XINT_csbth_1010\endcsname {\endcsname A}% +\expandafter\def\csname XINT_csbth_1011\endcsname {\endcsname B}% +\expandafter\def\csname XINT_csbth_1100\endcsname {\endcsname C}% +\expandafter\def\csname XINT_csbth_1101\endcsname {\endcsname D}% +\expandafter\def\csname XINT_csbth_1110\endcsname {\endcsname E}% +\expandafter\def\csname XINT_csbth_1111\endcsname {\endcsname F}% +\let\XINT_csbth_none \endcsname +\expandafter\def\csname XINT_cshtb_0\endcsname {\endcsname0000}% +\expandafter\def\csname XINT_cshtb_1\endcsname {\endcsname0001}% +\expandafter\def\csname XINT_cshtb_2\endcsname {\endcsname0010}% +\expandafter\def\csname XINT_cshtb_3\endcsname {\endcsname0011}% +\expandafter\def\csname XINT_cshtb_4\endcsname {\endcsname0100}% +\expandafter\def\csname XINT_cshtb_5\endcsname {\endcsname0101}% +\expandafter\def\csname XINT_cshtb_6\endcsname {\endcsname0110}% +\expandafter\def\csname XINT_cshtb_7\endcsname {\endcsname0111}% +\expandafter\def\csname XINT_cshtb_8\endcsname {\endcsname1000}% +\expandafter\def\csname XINT_cshtb_9\endcsname {\endcsname1001}% +\def\XINT_cshtb_A {\endcsname1010}% +\def\XINT_cshtb_B {\endcsname1011}% +\def\XINT_cshtb_C {\endcsname1100}% +\def\XINT_cshtb_D {\endcsname1101}% +\def\XINT_cshtb_E {\endcsname1110}% +\def\XINT_cshtb_F {\endcsname1111}% +\let\XINT_cshtb_none \endcsname +% \end{macrocode} +% \subsection{Helper macros} +% \subsubsection{\csh{XINT_zeroes_foriv}} +% \lverb|& +%( \romannumeral0\XINT_zeroes_foriv #1\R{0\R}{00\R}{000\R}$% +%: \R{0\R}{00\R}{000\R}\R\W +%) +% expands to the <empty> or 0 or 00 or 000 needed which when adjoined to #1 +% extend it to length 4N.| +% \begin{macrocode} +\def\XINT_zeroes_foriv #1#2#3#4#5#6#7#8% +{% + \xint_gob_til_R #8\XINT_zeroes_foriv_end\R\XINT_zeroes_foriv +}% +\def\XINT_zeroes_foriv_end\R\XINT_zeroes_foriv #1#2\W + {\XINT_zeroes_foriv_done #1}% +\def\XINT_zeroes_foriv_done #1\R{ #1}% +% \end{macrocode} +% \subsection{\csh{xintDecToHex}} +% \lverb|Complete rewrite at 1.2m in the 1.2 style. Also, 1.2m is robust +% against non terminated inputs. +% +% Improvements of coding at 1.2n, increased maximal size. Again some coding +% improvement at 1.2o, about 6$% speed gain. +% +% An input without leading zeroes gives an output without leading zeroes.| +% \begin{macrocode} +\def\xintDecToHex {\romannumeral0\xintdectohex }% +\def\xintdectohex #1% +{% + \expandafter\XINT_dth_checkin\romannumeral`&&@#1\xint: +}% +\def\XINT_dth_checkin #1% +{% + \xint_UDsignfork + #1\XINT_dth_neg + -{\XINT_dth_main #1}% + \krof +}% +\def\XINT_dth_neg {\expandafter-\romannumeral0\XINT_dth_main}% +\def\XINT_dth_main #1\xint: +{% + \expandafter\XINT_dth_finish + \romannumeral`&&@\expandafter\XINT_dthb_start + \romannumeral0\XINT_zeroes_foriv + #1\R{0\R}{00\R}{000\R}\R{0\R}{00\R}{000\R}\R\W + #1\xint_bye\XINT_dth_tohex +}% +\def\XINT_dthb_start #1#2#3#4#5% +{% + \xint_bye#5\XINT_dthb_small\xint_bye\XINT_dthb_start_a #1#2#3#4#5% +}% +\def\XINT_dthb_small\xint_bye\XINT_dthb_start_a #1\xint_bye#2{#2#1!}% +\def\XINT_dthb_start_a #1#2#3#4#5#6#7#8#9% +{% + \expandafter\XINT_dthb_again\the\numexpr\expandafter\XINT_dthb_update + \the\numexpr#1#2#3#4% + \xint_bye#9\XINT_dthb_lastpass\xint_bye + #5#6#7#8!\XINT_dthb_exclam\relax\XINT_dthb_nextfour #9% +}% +% \end{macrocode} +% \lverb|The 1.2n inserted +% exclamations marks, which when bumping back from \XINT_dthb_again gave rise +% to a \numexpr-loop which gathered the ! delimited arguments and inserted +% \expandafter\XINT_dthb_update\the\numexpr dynamically. The 1.2o trick is to +% insert it here immediately. Then at \XINT_dthb_again the \numexpr will +% trigger an already prepared chain. +% +% The crux of the thing is handling of #3 at \XINT_dthb_update_a. +% | +% \begin{macrocode} +\def\XINT_dthb_exclam {!\XINT_dthb_exclam\relax + \expandafter\XINT_dthb_update\the\numexpr}% +\def\XINT_dthb_update #1!% +{% + \expandafter\XINT_dthb_update_a + \the\numexpr (#1+\xint_c_ii^xv)/\xint_c_ii^xvi-\xint_c_i\xint: + #1\xint:% +}% +\def\XINT_dthb_update_a #1\xint:#2\xint:#3% +{% + 0000+#1\expandafter#3\the\numexpr#2-#1*\xint_c_ii^xvi +}% +% \end{macrocode} +% \lverb|1.2m and 1.2n had some unduly complicated ending pattern for +% \XINT_dthb_nextfour as inheritance of a loop needing ! separators which was +% pruned out at 1.2o (see previous comment). +% | +% \begin{macrocode} +\def\XINT_dthb_nextfour #1#2#3#4#5% +{% + \xint_bye#5\XINT_dthb_lastpass\xint_bye + #1#2#3#4!\XINT_dthb_exclam\relax\XINT_dthb_nextfour#5% +}% +\def\XINT_dthb_lastpass\xint_bye #1!#2\xint_bye#3{#1!#3!}% +\def\XINT_dth_tohex +{% + \expandafter\expandafter\expandafter\XINT_dth_tohex_a\csname\XINT_tofourhex +}% +\def\XINT_dth_tohex_a\endcsname{!\XINT_dth_tohex!}% +\def\XINT_dthb_again #1!#2#3% +{% + \ifx#3\relax + \expandafter\xint_firstoftwo + \else + \expandafter\xint_secondoftwo + \fi + {\expandafter\XINT_dthb_again + \the\numexpr + \ifnum #1>\xint_c_ + \xint_afterfi{\expandafter\XINT_dthb_update\the\numexpr#1}% + \fi}% + {\ifnum #1>\xint_c_ \xint_dothis{#2#1!}\fi\xint_orthat{!#2!}}% +}% +\def\XINT_tofourhex #1!% +{% + \expandafter\XINT_tofourhex_a + \the\numexpr (#1+\xint_c_ii^vii)/\xint_c_ii^viii-\xint_c_i\xint: + #1\xint: +}% +\def\XINT_tofourhex_a #1\xint:#2\xint: +{% + \expandafter\XINT_tofourhex_c + \the\numexpr (#1+\xint_c_viii)/\xint_c_xvi-\xint_c_i\xint: + #1\xint: + \the\numexpr #2-\xint_c_ii^viii*#1!% +}% +\def\XINT_tofourhex_c #1\xint:#2\xint: +{% + XINT_csdth_#1% + \csname XINT_csdth_\the\numexpr #2-\xint_c_xvi*#1\relax + \csname \expandafter\XINT_tofourhex_d +}% +\def\XINT_tofourhex_d #1!% +{% + \expandafter\XINT_tofourhex_e + \the\numexpr (#1+\xint_c_viii)/\xint_c_xvi-\xint_c_i\xint: + #1\xint: +}% +\def\XINT_tofourhex_e #1\xint:#2\xint: +{% + XINT_csdth_#1% + \csname XINT_csdth_\the\numexpr #2-\xint_c_xvi*#1\endcsname +}% +% \end{macrocode} +% \lverb|We only clean-up up to 3 zero hexadecimal digits, as output was +% produced in chunks of 4 hex digits. If input had no leading zero, output +% will have none either. If input had many leading zeroes, output will have +% some number (unspecified, but a recipe can be given...) of leading zeroes... +% +% The coding is for varying a bit, I did not check if efficient, it does not +% matter.| +% \begin{macrocode} +\def\XINT_dth_finish !\XINT_dth_tohex!#1#2#3% +{% + \unless\if#10\xint_dothis{ #1#2#3}\fi + \unless\if#20\xint_dothis{ #2#3}\fi + \unless\if#30\xint_dothis{ #3}\fi + \xint_orthat{ }% +}% +% \end{macrocode} +% \subsection{\csh{xintDecToBin}} +% \lverb|Complete rewrite at 1.2m in the 1.2 style. Also, 1.2m is robust +% against non terminated inputs. +% +% Revisited at 1.2n like in \xintDecToHex: increased maximal size. +% +% An input without leading zeroes gives an output without leading zeroes. +% +% Most of the code canvas is shared with \xintDecToHex. +% | +% \begin{macrocode} +\def\xintDecToBin {\romannumeral0\xintdectobin }% +\def\xintdectobin #1% +{% + \expandafter\XINT_dtb_checkin\romannumeral`&&@#1\xint: +}% +\def\XINT_dtb_checkin #1% +{% + \xint_UDsignfork + #1\XINT_dtb_neg + -{\XINT_dtb_main #1}% + \krof +}% +\def\XINT_dtb_neg {\expandafter-\romannumeral0\XINT_dtb_main}% +\def\XINT_dtb_main #1\xint: +{% + \expandafter\XINT_dtb_finish + \romannumeral`&&@\expandafter\XINT_dthb_start + \romannumeral0\XINT_zeroes_foriv + #1\R{0\R}{00\R}{000\R}\R{0\R}{00\R}{000\R}\R\W + #1\xint_bye\XINT_dtb_tobin +}% +\def\XINT_dtb_tobin +{% + \expandafter\expandafter\expandafter\XINT_dtb_tobin_a\csname\XINT_tosixteenbits +}% +\def\XINT_dtb_tobin_a\endcsname{!\XINT_dtb_tobin!}% +\def\XINT_tosixteenbits #1!% +{% + \expandafter\XINT_tosixteenbits_a + \the\numexpr (#1+\xint_c_ii^vii)/\xint_c_ii^viii-\xint_c_i\xint: + #1\xint: +}% +\def\XINT_tosixteenbits_a #1\xint:#2\xint: +{% + \expandafter\XINT_tosixteenbits_c + \the\numexpr (#1+\xint_c_viii)/\xint_c_xvi-\xint_c_i\xint: + #1\xint: + \the\numexpr #2-\xint_c_ii^viii*#1!% +}% +\def\XINT_tosixteenbits_c #1\xint:#2\xint: +{% + XINT_csdtb_#1% + \csname XINT_csdtb_\the\numexpr #2-\xint_c_xvi*#1\relax + \csname \expandafter\XINT_tosixteenbits_d +}% +\def\XINT_tosixteenbits_d #1!% +{% + \expandafter\XINT_tosixteenbits_e + \the\numexpr (#1+\xint_c_viii)/\xint_c_xvi-\xint_c_i\xint: + #1\xint: +}% +\def\XINT_tosixteenbits_e #1\xint:#2\xint: +{% + XINT_csdtb_#1% + \csname XINT_csdtb_\the\numexpr #2-\xint_c_xvi*#1\endcsname +}% +\def\XINT_dtb_finish !\XINT_dtb_tobin!#1#2#3#4#5#6#7#8% +{% + \expandafter\XINT_dtb_finish_a\the\numexpr #1#2#3#4#5#6#7#8\relax +}% +\def\XINT_dtb_finish_a #1{% +\def\XINT_dtb_finish_a ##1##2##3##4##5##6##7##8##9% +{% + \expandafter#1\the\numexpr ##1##2##3##4##5##6##7##8##9\relax +}}\XINT_dtb_finish_a { }% +% \end{macrocode} +% \subsection{\csh{xintHexToDec}} +% \lverb|Completely (and belatedly) rewritten at 1.2m in the 1.2 style. +% +% 1.2m version robust against non terminated inputs, but there is no primitive +% from TeX which may generate hexadecimal digits and provoke expansion ahead, +% afaik, except of course if decimal digits are treated as hexadecimal. This +% robustness is not on purpose but from need to expand argument and then grab +% it again. So we do it safely. +% +% Increased maximal size at 1.2n. +% +% 1.2m version robust against non terminated inputs. +% +% An input without leading zeroes gives an output without leading zeroes. +% | +% \begin{macrocode} +\def\xintHexToDec {\romannumeral0\xinthextodec }% +\def\xinthextodec #1% +{% + \expandafter\XINT_htd_checkin\romannumeral`&&@#1\xint: +}% +\def\XINT_htd_checkin #1% +{% + \xint_UDsignfork + #1\XINT_htd_neg + -{\XINT_htd_main #1}% + \krof +}% +\def\XINT_htd_neg {\expandafter-\romannumeral0\XINT_htd_main}% +\def\XINT_htd_main #1\xint: +{% + \expandafter\XINT_htd_startb + \the\numexpr\expandafter\XINT_htd_starta + \romannumeral0\XINT_zeroes_foriv + #1\R{0\R}{00\R}{000\R}\R{0\R}{00\R}{000\R}\R\W + #1\xint_bye!2!3!4!5!6!7!8!9!\xint_bye\relax +}% +\def\XINT_htd_starta #1#2#3#4{"#1#2#3#4+100000!}% +\def\XINT_htd_startb 1#1% +{% + \if#10\expandafter\XINT_htd_startba\else + \expandafter\XINT_htd_startbb + \fi 1#1% +}% +\def\XINT_htd_startba 10#1!{\XINT_htd_again #1% + \xint_bye!2!3!4!5!6!7!8!9!\xint_bye\XINT_htd_nextfour}% +\def\XINT_htd_startbb 1#1#2!{\XINT_htd_again #1!#2% + \xint_bye!2!3!4!5!6!7!8!9!\xint_bye\XINT_htd_nextfour}% +% \end{macrocode} +% \lverb|It is a bit annoying to grab all to the end here. I have a version, +% modeled on the 1.2n variant of \xintDecToHex which solved that problem +% there, but it did not prove enough if at all faster in my brief testing and +% it had the defect of a reduced maximal allowed size of the input. | +% \begin{macrocode} +\def\XINT_htd_again #1\XINT_htd_nextfour #2% +{% + \xint_bye #2\XINT_htd_finish\xint_bye + \expandafter\XINT_htd_A\the\numexpr + \XINT_htd_a #1\XINT_htd_nextfour #2% +}% +\def\XINT_htd_a #1!#2!#3!#4!#5!#6!#7!#8!#9!% +{% + #1\expandafter\XINT_htd_update + \the\numexpr #2\expandafter\XINT_htd_update + \the\numexpr #3\expandafter\XINT_htd_update + \the\numexpr #4\expandafter\XINT_htd_update + \the\numexpr #5\expandafter\XINT_htd_update + \the\numexpr #6\expandafter\XINT_htd_update + \the\numexpr #7\expandafter\XINT_htd_update + \the\numexpr #8\expandafter\XINT_htd_update + \the\numexpr #9\expandafter\XINT_htd_update + \the\numexpr \XINT_htd_a +}% +\def\XINT_htd_nextfour #1#2#3#4% +{% + *\xint_c_ii^xvi+"#1#2#3#4+1000000000\relax\xint_bye!% + 2!3!4!5!6!7!8!9!\xint_bye\XINT_htd_nextfour +}% +% \end{macrocode} +% \lverb|If the innocent looking commented out $#6 is left in the pattern as +% was the case at 1.2m, the maximal size becomes limited at 5538 digits, not +% 8298! (with parameter stack size = 10000.) | +% \begin{macrocode} +\def\XINT_htd_update 1#1#2#3#4#5%#6!% +{% + *\xint_c_ii^xvi+10000#1#2#3#4#5!%#6!% +}% +\def\XINT_htd_A 1#1% +{% + \if#10\expandafter\XINT_htd_Aa\else + \expandafter\XINT_htd_Ab + \fi 1#1% +}% +\def\XINT_htd_Aa 10#1#2#3#4{\XINT_htd_again #1#2#3#4!}% +\def\XINT_htd_Ab 1#1#2#3#4#5{\XINT_htd_again #1!#2#3#4#5!}% +\def\XINT_htd_finish\xint_bye + \expandafter\XINT_htd_A\the\numexpr \XINT_htd_a #1\XINT_htd_nextfour +{% + \expandafter\XINT_htd_finish_cuz\the\numexpr0\XINT_htd_unsep_loop #1% +}% +\def\XINT_htd_unsep_loop #1!#2!#3!#4!#5!#6!#7!#8!#9!% +{% + \expandafter\XINT_unsep_clean + \the\numexpr 1#1#2\expandafter\XINT_unsep_clean + \the\numexpr 1#3#4\expandafter\XINT_unsep_clean + \the\numexpr 1#5#6\expandafter\XINT_unsep_clean + \the\numexpr 1#7#8\expandafter\XINT_unsep_clean + \the\numexpr 1#9\XINT_htd_unsep_loop_a +}% +\def\XINT_htd_unsep_loop_a #1!#2!#3!#4!#5!#6!#7!#8!#9!% +{% + #1\expandafter\XINT_unsep_clean + \the\numexpr 1#2#3\expandafter\XINT_unsep_clean + \the\numexpr 1#4#5\expandafter\XINT_unsep_clean + \the\numexpr 1#6#7\expandafter\XINT_unsep_clean + \the\numexpr 1#8#9\XINT_htd_unsep_loop +}% +\def\XINT_unsep_clean 1{\relax}% also in xintcore +\def\XINT_htd_finish_cuz #1{% +\def\XINT_htd_finish_cuz ##1##2##3##4##5% + {\expandafter#1\the\numexpr ##1##2##3##4##5\relax}% +}\XINT_htd_finish_cuz{ }% +% \end{macrocode} +% \subsection{\csh{xintBinToDec}} +% \lverb|Redone entirely for 1.2m. Starts by converting to hexadecimal +% first. +% +% Increased maximal size at 1.2n. +% +% An input without leading zeroes gives an output without leading zeroes. +% +% Robust against non-terminated input.| +% \begin{macrocode} +\def\xintBinToDec {\romannumeral0\xintbintodec }% +\def\xintbintodec #1% +{% + \expandafter\XINT_btd_checkin\romannumeral`&&@#1\xint: +}% +\def\XINT_btd_checkin #1% +{% + \xint_UDsignfork + #1\XINT_btd_N + -{\XINT_btd_main #1}% + \krof +}% +\def\XINT_btd_N {\expandafter-\romannumeral0\XINT_btd_main }% +\def\XINT_btd_main #1\xint: +{% + \csname XINT_btd_htd\csname\expandafter\XINT_bth_loop + \romannumeral0\XINT_zeroes_foriv + #1\R{0\R}{00\R}{000\R}\R{0\R}{00\R}{000\R}\R\W + #1\xint_bye2345678\xint_bye none\endcsname\xint: +}% +\def\XINT_btd_htd #1\xint: +{% + \expandafter\XINT_htd_startb + \the\numexpr\expandafter\XINT_htd_starta + \romannumeral0\XINT_zeroes_foriv + #1\R{0\R}{00\R}{000\R}\R{0\R}{00\R}{000\R}\R\W + #1\xint_bye!2!3!4!5!6!7!8!9!\xint_bye\relax +}% +% \end{macrocode} +% \subsection{\csh{xintBinToHex}} +% \lverb|Complete rewrite for 1.2m. +% But input for 1.2m version limited to about 13320 binary digits (expansion +% depth=10000). +% +% Again redone for 1.2n for \csname governed expansion: increased maximal size. +% +% Size of output is ceil(size(input)/4), leading zeroes in output (inherited +% from the input) are not trimmed. +% +% An input without leading zeroes gives an output without leading zeroes. +% +% Robust against non-terminated input. +% | +% \begin{macrocode} +\def\xintBinToHex {\romannumeral0\xintbintohex }% +\def\xintbintohex #1% +{% + \expandafter\XINT_bth_checkin\romannumeral`&&@#1\xint: +}% +\def\XINT_bth_checkin #1% +{% + \xint_UDsignfork + #1\XINT_bth_N + -{\XINT_bth_main #1}% + \krof +}% +\def\XINT_bth_N {\expandafter-\romannumeral0\XINT_bth_main }% +\def\XINT_bth_main #1\xint: +{% + \csname space\csname\expandafter\XINT_bth_loop + \romannumeral0\XINT_zeroes_foriv + #1\R{0\R}{00\R}{000\R}\R{0\R}{00\R}{000\R}\R\W + #1\xint_bye2345678\xint_bye none\endcsname +}% +\def\XINT_bth_loop #1#2#3#4#5#6#7#8% +{% + XINT_csbth_#1#2#3#4% + \csname XINT_csbth_#5#6#7#8% + \csname\XINT_bth_loop +}% +% \end{macrocode} +% \subsection{\csh{xintHexToBin}} +% \lverb|Completely rewritten for 1.2m. +% +% Attention this macro is not robust against arguments expanding after +% themselves. +% +% Only up to three zeros are removed on front of output: if the input had a +% leading zero, there will be a leading zero (and then possibly 4n of them if +% inputs had more leading zeroes) on output. +% +% Rewritten again at 1.2n for \csname governed expansion.| +% \begin{macrocode} +\def\xintHexToBin {\romannumeral0\xinthextobin }% +\def\xinthextobin #1% +{% + \expandafter\XINT_htb_checkin\romannumeral`&&@#1% + \xint_bye 23456789\xint_bye none\endcsname +}% +\def\XINT_htb_checkin #1% +{% + \xint_UDsignfork + #1\XINT_htb_N + -{\XINT_htb_main #1}% + \krof +}% +\def\XINT_htb_N {\expandafter-\romannumeral0\XINT_htb_main }% +\def\XINT_htb_main {\csname XINT_htb_cuz\csname\XINT_htb_loop}% +\def\XINT_htb_loop #1#2#3#4#5#6#7#8#9% +{% + XINT_cshtb_#1% + \csname XINT_cshtb_#2% + \csname XINT_cshtb_#3% + \csname XINT_cshtb_#4% + \csname XINT_cshtb_#5% + \csname XINT_cshtb_#6% + \csname XINT_cshtb_#7% + \csname XINT_cshtb_#8% + \csname XINT_cshtb_#9% + \csname \XINT_htb_loop +}% +\def\XINT_htb_cuz #1{% +\def\XINT_htb_cuz ##1##2##3##4% + {\expandafter#1\the\numexpr##1##2##3##4\relax}% +}\XINT_htb_cuz { }% +% \end{macrocode} +% \subsection{\csh{xintCHexToBin}} +% \lverb|The 1.08 macro had same functionality as \xintHexToBin, and slightly +% different code, the 1.2m version has the same code as \xintHexToBin except +% that it does not remove leading zeros from output: if the input had N +% hexadecimal digits, the output will have exactly 4N binary digits. +% +% Rewritten again at 1.2n for \csname governed expansion.| +% \begin{macrocode} +\def\xintCHexToBin {\romannumeral0\xintchextobin }% +\def\xintchextobin #1% +{% + \expandafter\XINT_chtb_checkin\romannumeral`&&@#1% + \xint_bye 23456789\xint_bye none\endcsname +}% +\def\XINT_chtb_checkin #1% +{% + \xint_UDsignfork + #1\XINT_chtb_N + -{\XINT_chtb_main #1}% + \krof +}% +\def\XINT_chtb_N {\expandafter-\romannumeral0\XINT_chtb_main }% +\def\XINT_chtb_main {\csname space\csname\XINT_htb_loop}% +\XINT_restorecatcodes_endinput% +% \end{macrocode} +% \StoreCodelineNo {xintbinhex} +% \cleardoublepage\let\xintbinhexnameUp\undefined +%\gardesactifs +%\let</xintbinhex>\relax +%\let<*xintgcd>\gardesinactifs +%</xintbinhex>^^A------------------------------------------------- +%<*xintgcd>^^A---------------------------------------------------- +%^^A -*- coding: utf-8; mode: doctex; -*- +% \clearpage\csname xintgcdnameUp\endcsname +% \section{Package \xintgcdnameimp implementation} +% \RaisedLabel{sec:gcdimp} +% +% \localtableofcontents +% +% The commenting is currently (\xintdocdate) very sparse. Release |1.09h| has +% modified a bit the |\xintTypesetEuclideAlgorithm| and +% |\xintTypesetBezoutAlgorithm| layout with respect to line indentation in +% particular. And they use the \xinttoolsnameimp |\xintloop| rather than the +% Plain \TeX{} or \LaTeX{}'s |\loop|. +% +% Since |1.1| the package only loads \xintcorenameimp, not \xintnameimp. And +% for the |\xintTypesetEuclideAlgorithm| and |\xintTypesetBezoutAlgorithm| +% macros to be functional the package \xinttoolsnameimp needs to be loaded +% explicitely by the user. +% +% Breaking change at |1.2p|: |\xintBezout{A}{B}| formerly had output +% |{A}{B}{U}{V}{D}| with |AU-BV=D|, now it is |{U}{V}{D}| with |AU+BV=D|. +% +% \subsection{Catcodes, \protect\eTeX{} and reload detection} +% +% The code for reload detection was initially copied from \textsc{Heiko +% Oberdiek}'s packages, then modified. +% +% The method for catcodes was also initially directly inspired by these +% packages. +% +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode64=11 % @ + \catcode35=6 % # + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \let\z\endgroup + \expandafter\let\expandafter\x\csname ver@xintgcd.sty\endcsname + \expandafter\let\expandafter\w\csname ver@xintcore.sty\endcsname + \expandafter + \ifx\csname PackageInfo\endcsname\relax + \def\y#1#2{\immediate\write-1{Package #1 Info: #2.}}% + \else + \def\y#1#2{\PackageInfo{#1}{#2}}% + \fi + \expandafter + \ifx\csname numexpr\endcsname\relax + \y{xintgcd}{\numexpr not available, aborting input}% + \aftergroup\endinput + \else + \ifx\x\relax % plain-TeX, first loading of xintgcd.sty + \ifx\w\relax % but xintcore.sty not yet loaded. + \def\z{\endgroup\input xintcore.sty\relax}% + \fi + \else + \def\empty {}% + \ifx\x\empty % LaTeX, first loading, + % variable is initialized, but \ProvidesPackage not yet seen + \ifx\w\relax % xintcore.sty not yet loaded. + \def\z{\endgroup\RequirePackage{xintcore}}% + \fi + \else + \aftergroup\endinput % xintgcd already loaded. + \fi + \fi + \fi +\z% +\XINTsetupcatcodes% defined in xintkernel.sty +% \end{macrocode} +% \subsection{Package identification} +% \begin{macrocode} +\XINT_providespackage +\ProvidesPackage{xintgcd}% + [2019/04/05 1.3e Euclide algorithm with xint package (JFB)]% +% \end{macrocode} +% \subsection{\csh{xintGCD}, \csh{xintiiGCD}} +% \lverb|& +% | +% \changed{1.3d}{} +% \lverb|Removed some braces in favor of \xint: delimiter at 1.3d (but +% \xintiiGCD was already robust against non-delimited \numexpr inputs +% thanks to using \xintiiabs{...}) and refactored the whole +% \XINT_iigcd_fork. | +% \begin{macrocode} +\def\xintGCD {\romannumeral0\xintgcd }% +\def\xintgcd #1#2{\xintiigcd {\xintNum{#1}}{\xintNum{#2}}}% +\def\xintiiGCD {\romannumeral0\xintiigcd }% +% \end{macrocode} +% \lverb|This abuses the way \xintiiabs expands.| +% \begin{macrocode} +\def\xintiigcd #1{\expandafter\XINT_iigcd\romannumeral0\xintiiabs#1\xint:}% +\def\XINT_iigcd #1#2\xint:#3% +{% + \expandafter\XINT_gcd_fork\expandafter#1% + \romannumeral0\xintiiabs#3\xint:#1#2\xint: +}% +% \end{macrocode} +% \lverb|First argument now in second position (after \xint:) but +% its first digit is also the #1.| +% \begin{macrocode} +\def\XINT_gcd_fork #1#2% +{% + \xint_UDzerofork + #1\XINT_gcd_Aiszero + #2\XINT_gcd_Biszero + 0\XINT_gcd_loop + \krof + #2% +}% +\def\XINT_gcd_AisZero #1\xint:#2\xint:{ #1}% +\def\XINT_gcd_BisZero #1\xint:#2\xint:{ #2}% +% \end{macrocode} +% \lverb|\XINT_div_prepare{#1}{#2} divides #2 by #1, and outputs +% {Quotient}{Remainder}.| +% \begin{macrocode} +\def\XINT_gcd_loop #1\xint:#2\xint: +{% + \expandafter\expandafter\expandafter\XINT_gcd_CheckRem + \expandafter\xint_secondoftwo + \romannumeral0\XINT_div_prepare {#1}{#2}\xint:#1\xint: +}% +\def\XINT_gcd_CheckRem #1% +{% + \xint_gob_til_zero #1\XINT_gcd_end0\XINT_gcd_loop #1% +}% +\def\XINT_gcd_end0\XINT_gcd_loop #1\xint:#2\xint:{ #2}% +% \end{macrocode} +% \subsection{\csh{xintLCM}, \csh{xintiiLCM}} +% \lverb|See comments of \xintiiGCD for the refactoring done at 1.3d. +% No time to make \xintiiLCM code more efficient now. +% +% Macros \xintLCM, \xintlcm only for backwards compatibility.| +% \begin{macrocode} +\def\xintLCM {\romannumeral0\xintlcm}% +\def\xintlcm #1#2{\xintiilcm{\xintNum{#1}}{\xintNum{#2}}}% +\def\xintiiLCM {\romannumeral0\xintiilcm}% +\def\xintiilcm #1{\expandafter\XINT_iilcm\romannumeral0\xintiiabs#1\xint:}% +\def\XINT_iilcm #1#2\xint:#3% +{% + \expandafter\XINT_lcm_fork\expandafter#1% + \romannumeral0\xintiiabs#3\xint:#1#2\xint: +}% +\def\XINT_lcm_fork #1#2% +{% + \xint_UDzerofork + #1\XINT_lcm_iszero + #2\XINT_lcm_iszero + 0\XINT_lcm_notzero + \krof + #2% +}% +\def\XINT_lcm_iszero #1\xint:#2\xint:{ 0}% +\def\XINT_lcm_notzero #1\xint:#2\xint: +{% + \expandafter\XINT_lcm_end\romannumeral0% + \expandafter\expandafter\expandafter\XINT_gcd_CheckRem + \expandafter\xint_secondoftwo + \romannumeral0\XINT_div_prepare {#1}{#2}\xint:#1\xint: + \xint:#1\xint:#2\xint: +}% +\def\XINT_lcm_end #1\xint:#2\xint:#3\xint:{\xintiimul {#2}{\xintiiQuo{#3}{#1}}}% +% \end{macrocode} +% \subsection{\csh{xintBezout}} +% \lverb|& +% \xintBezout{#1}{#2} +% produces {U}{V}{D} with UA+VB=D, D = PGCD(A,B) (non-positive), +% where #1 and #2 f-expand to big integers A and B. +% +% I had not checked this macro for about three years when I realized in +% January 2017 that \xintBezout{A}{B} was buggy for the cases A = 0 or B = 0. +% I fixed that blemish in 1.2l but overlooked the other blemish that +% \xintBezout{A}{B} with A multiple of B produced a coefficient U as -0 in +% place of 0. +% +% Hence I rewrote again for 1.2p. On this occasion I modified the output +% of the macro to be {U}{V}{D} with AU+BV=D, formerly it was +% {A}{B}{U}{V}{D} with AU - BV = D. This is quite breaking change! +% +% Note in particular change of sign of V. +% +% I don't know why I had designed this macro to contain {A}{B} in its output. +% Perhaps I initially intended to output {A//D}{B//D} (but forgot), as this is +% actually possible from outcome of the last iteration, with no need of +% actually dividing. Current code however arranges to skip this last update, +% as U and V are already furnished by the iteration prior to realizing that +% the last non-zero remainder was found. +% +% Also 1.2l raised InvalidOperation if both A and B vanished, but I removed +% this behaviour at 1.2p. +%| +% \begin{macrocode} +\def\xintBezout {\romannumeral0\xintbezout }% +\def\xintbezout #1% +{% + \expandafter\XINT_bezout\expandafter {\romannumeral0\xintnum{#1}}% +}% +\def\XINT_bezout #1#2% +{% + \expandafter\XINT_bezout_fork \romannumeral0\xintnum{#2}\Z #1\Z +}% +% \end{macrocode} +% \lverb|#3#4 = A, #1#2=B. Micro improvement for 1.2l.| +% \begin{macrocode} +\def\XINT_bezout_fork #1#2\Z #3#4\Z +{% + \xint_UDzerosfork + #1#3\XINT_bezout_botharezero + #10\XINT_bezout_secondiszero + #30\XINT_bezout_firstiszero + 00\xint_UDsignsfork + \krof + #1#3\XINT_bezout_minusminus % A < 0, B < 0 + #1-\XINT_bezout_minusplus % A > 0, B < 0 + #3-\XINT_bezout_plusminus % A < 0, B > 0 + --\XINT_bezout_plusplus % A > 0, B > 0 + \krof + {#2}{#4}#1#3% #1#2=B, #3#4=A +}% +\def\XINT_bezout_botharezero #1\krof#2#300{{0}{0}{0}}% +\def\XINT_bezout_firstiszero #1\krof#2#3#4#5% +{% + \xint_UDsignfork + #4{{0}{-1}{#2}}% + -{{0}{1}{#4#2}}% + \krof +}% +\def\XINT_bezout_secondiszero #1\krof#2#3#4#5% +{% + \xint_UDsignfork + #5{{-1}{0}{#3}}% + -{{1}{0}{#5#3}}% + \krof +}% +% \end{macrocode} +% \lverb|#4#2= A < 0, #3#1 = B < 0| +% \begin{macrocode} +\def\XINT_bezout_minusminus #1#2#3#4% +{% + \expandafter\XINT_bezout_mm_post + \romannumeral0\expandafter\XINT_bezout_preloop_a + \romannumeral0\XINT_div_prepare {#1}{#2}{#1}% +}% +\def\XINT_bezout_mm_post #1#2% +{% + \expandafter\XINT_bezout_mm_postb\expandafter + {\romannumeral0\xintiiopp{#2}}{\romannumeral0\xintiiopp{#1}}% +}% +\def\XINT_bezout_mm_postb #1#2{\expandafter{#2}{#1}}% +% \end{macrocode} +% \lverb|minusplus #4#2= A > 0, B < 0| +% \begin{macrocode} +\def\XINT_bezout_minusplus #1#2#3#4% +{% + \expandafter\XINT_bezout_mp_post + \romannumeral0\expandafter\XINT_bezout_preloop_a + \romannumeral0\XINT_div_prepare {#1}{#4#2}{#1}% +}% +\def\XINT_bezout_mp_post #1#2% +{% + \expandafter\xint_exchangetwo_keepbraces\expandafter + {\romannumeral0\xintiiopp {#2}}{#1}% +}% +% \end{macrocode} +% \lverb|plusminus A < 0, B > 0| +% \begin{macrocode} +\def\XINT_bezout_plusminus #1#2#3#4% +{% + \expandafter\XINT_bezout_pm_post + \romannumeral0\expandafter\XINT_bezout_preloop_a + \romannumeral0\XINT_div_prepare {#3#1}{#2}{#3#1}% +}% +\def\XINT_bezout_pm_post #1{\expandafter{\romannumeral0\xintiiopp{#1}}}% +% \end{macrocode} +% \lverb|plusplus, B = #3#1 > 0, A = #4#2 > 0| +% \begin{macrocode} +\def\XINT_bezout_plusplus #1#2#3#4% +{% + \expandafter\XINT_bezout_preloop_a + \romannumeral0\XINT_div_prepare {#3#1}{#4#2}{#3#1}% +}% +% \end{macrocode} +% \lverb|& +%( n = 0: BA1001 (B, A, e=1, vv, uu, v, u) +%: r(1)=B, r(0)=A, après n étapes {r(n+1)}{r(n)}{vv}{uu}{v}{u} +%: q(n) quotient de r(n-1) par r(n) +%: si reste nul, exit et renvoie U = -e*uu, V = e*vv, A*U+B*V=D +%: sinon mise à jour +%: vv, v = q * vv + v, vv +%: uu, u = q * uu + u, uu +%: e = -e +%: puis calcul quotient reste et itération +%) +% +% We arrange for \xintiiMul sub-routine to be called only with positive +% arguments, thus skipping some un-needed sign parsing there. For that though +% we have to screen out the special cases A divides B, or B divides A. And we +% first want to exchange A and B if A < B. These special cases are the only +% one possibly leading to U or V zero (for A and B positive which is the case +% here.) Thus the general case always leads to non-zero U and V's and assigning +% a final sign is done simply adding a - to one of them, with no fear of +% producing -0. | +% \begin{macrocode} +\def\XINT_bezout_preloop_a #1#2#3% +{% + \if0#1\xint_dothis\XINT_bezout_preloop_exchange\fi + \if0#2\xint_dothis\XINT_bezout_preloop_exit\fi + \xint_orthat{\expandafter\XINT_bezout_loop_B}% + \romannumeral0\XINT_div_prepare {#2}{#3}{#2}{#1}110% +}% +\def\XINT_bezout_preloop_exit + \romannumeral0\XINT_div_prepare #1#2#3#4#5#6#7% +{% + {0}{1}{#2}% +}% +\def\XINT_bezout_preloop_exchange +{% + \expandafter\xint_exchangetwo_keepbraces + \romannumeral0\expandafter\XINT_bezout_preloop_A +}% +\def\XINT_bezout_preloop_A #1#2#3#4% +{% + \if0#2\xint_dothis\XINT_bezout_preloop_exit\fi + \xint_orthat{\expandafter\XINT_bezout_loop_B}% + \romannumeral0\XINT_div_prepare {#2}{#3}{#2}{#1}% +}% +\def\XINT_bezout_loop_B #1#2% +{% + \if0#2\expandafter\XINT_bezout_exitA + \else\expandafter\XINT_bezout_loop_C + \fi {#1}{#2}% +}% +% \end{macrocode} +% \lverb|& +% We use the fact that the \romannumeral-`0 (or equivalent) done by \xintiiadd +% will absorb the initial space token left by \XINT_mul_plusplus in its +% output. +% +% We arranged for operands here to be always positive which is needed for +% \XINT_mul_plusplus entry point (last time I checked...). Admittedly this +% kind of optimization is not good for maintenance of code, but I can't resist +% temptation of limiting the shuffling around of tokens... +% | +% \begin{macrocode} +\def\XINT_bezout_loop_C #1#2#3#4#5#6#7% +{% + \expandafter\XINT_bezout_loop_D\expandafter + {\romannumeral0\xintiiadd{\XINT_mul_plusplus{}{}#1\xint:#4\xint:}{#6}}% + {\romannumeral0\xintiiadd{\XINT_mul_plusplus{}{}#1\xint:#5\xint:}{#7}}% + {#2}{#3}{#4}{#5}% +}% +\def\XINT_bezout_loop_D #1#2% +{% + \expandafter\XINT_bezout_loop_E\expandafter{#2}{#1}% +}% +\def\XINT_bezout_loop_E #1#2#3#4% +{% + \expandafter\XINT_bezout_loop_b + \romannumeral0\XINT_div_prepare {#3}{#4}{#3}{#2}{#1}% +}% +\def\XINT_bezout_loop_b #1#2% +{% + \if0#2\expandafter\XINT_bezout_exita + \else\expandafter\XINT_bezout_loop_c + \fi {#1}{#2}% +}% +\def\XINT_bezout_loop_c #1#2#3#4#5#6#7% +{% + \expandafter\XINT_bezout_loop_d\expandafter + {\romannumeral0\xintiiadd{\XINT_mul_plusplus{}{}#1\xint:#4\xint:}{#6}}% + {\romannumeral0\xintiiadd{\XINT_mul_plusplus{}{}#1\xint:#5\xint:}{#7}}% + {#2}{#3}{#4}{#5}% +}% +\def\XINT_bezout_loop_d #1#2% +{% + \expandafter\XINT_bezout_loop_e\expandafter{#2}{#1}% +}% +\def\XINT_bezout_loop_e #1#2#3#4% +{% + \expandafter\XINT_bezout_loop_B + \romannumeral0\XINT_div_prepare {#3}{#4}{#3}{#2}{#1}% +}% +% \end{macrocode} +% \lverb|& +% sortir U, V, D mais on a travaillé avec vv, uu, v, u dans cet ordre.$\ +% The code is structured so that #4 and #5 are guaranteed non-zero +% if we exit here, hence we can not create a -0 in output.| +% \begin{macrocode} +\def\XINT_bezout_exita #1#2#3#4#5#6#7{{-#5}{#4}{#3}}% +\def\XINT_bezout_exitA #1#2#3#4#5#6#7{{#5}{-#4}{#3}}% +% \end{macrocode} +% \subsection{\csh{xintEuclideAlgorithm}} +% \lverb|& +% Pour Euclide: +% {N}{A}{D=r(n)}{B}{q1}{r1}{q2}{r2}{q3}{r3}....{qN}{rN=0}$\ +% u<2n> = u<2n+3>u<2n+2> + u<2n+4> à la n ième étape. +% +% Formerly, used \xintiabs, but got deprecated at 1.2o.| +% \begin{macrocode} +\def\xintEuclideAlgorithm {\romannumeral0\xinteuclidealgorithm }% +\def\xinteuclidealgorithm #1% +{% + \expandafter\XINT_euc\expandafter{\romannumeral0\xintiiabs{\xintNum{#1}}}% +}% +\def\XINT_euc #1#2% +{% + \expandafter\XINT_euc_fork\romannumeral0\xintiiabs{\xintNum{#2}}\Z #1\Z +}% +% \end{macrocode} +% \lverb|Ici #3#4=A, #1#2=B| +% \begin{macrocode} +\def\XINT_euc_fork #1#2\Z #3#4\Z +{% + \xint_UDzerofork + #1\XINT_euc_BisZero + #3\XINT_euc_AisZero + 0\XINT_euc_a + \krof + {0}{#1#2}{#3#4}{{#3#4}{#1#2}}{}\Z +}% +% \end{macrocode} +% \lverb|& +% Le {} pour protéger {{A}{B}} si on s'arrête après une étape (B divise +% A). +% On va renvoyer:$\ +% {N}{A}{D=r(n)}{B}{q1}{r1}{q2}{r2}{q3}{r3}....{qN}{rN=0}| +% \begin{macrocode} +\def\XINT_euc_AisZero #1#2#3#4#5#6{{1}{0}{#2}{#2}{0}{0}}% +\def\XINT_euc_BisZero #1#2#3#4#5#6{{1}{0}{#3}{#3}{0}{0}}% +% \end{macrocode} +% \lverb|& +% {n}{rn}{an}{{qn}{rn}}...{{A}{B}}{}\Z$\ +% a(n) = r(n-1). Pour n=0 on a juste {0}{B}{A}{{A}{B}}{}\Z$\ +% \XINT_div_prepare {u}{v} divise v par u| +% \begin{macrocode} +\def\XINT_euc_a #1#2#3% +{% + \expandafter\XINT_euc_b\the\numexpr #1+\xint_c_i\expandafter.% + \romannumeral0\XINT_div_prepare {#2}{#3}{#2}% +}% +% \end{macrocode} +% \lverb|{n+1}{q(n+1)}{r(n+1)}{rn}{{qn}{rn}}...| +% \begin{macrocode} +\def\XINT_euc_b #1.#2#3#4% +{% + \XINT_euc_c #3\Z {#1}{#3}{#4}{{#2}{#3}}% +}% +% \end{macrocode} +% \lverb|r(n+1)\Z {n+1}{r(n+1)}{r(n)}{{q(n+1)}{r(n+1)}}{{qn}{rn}}...$\ +% Test si r(n+1) est nul.| +% \begin{macrocode} +\def\XINT_euc_c #1#2\Z +{% + \xint_gob_til_zero #1\XINT_euc_end0\XINT_euc_a +}% +% \end{macrocode} +% \lverb|& +% {n+1}{r(n+1)}{r(n)}{{q(n+1)}{r(n+1)}}...{}\Z +% Ici r(n+1) = 0. On arrête on se prépare à inverser +% {n+1}{0}{r(n)}{{q(n+1)}{r(n+1)}}.....{{q1}{r1}}{{A}{B}}{}\Z$\ +% On veut renvoyer: {N=n+1}{A}{D=r(n)}{B}{q1}{r1}{q2}{r2}{q3}{r3}....{qN}{rN=0}| +% \begin{macrocode} +\def\XINT_euc_end0\XINT_euc_a #1#2#3#4\Z% +{% + \expandafter\XINT_euc_end_a + \romannumeral0% + \XINT_rord_main {}#4{{#1}{#3}}% + \xint: + \xint_bye\xint_bye\xint_bye\xint_bye + \xint_bye\xint_bye\xint_bye\xint_bye + \xint: +}% +\def\XINT_euc_end_a #1#2#3{{#1}{#3}{#2}}% +% \end{macrocode} +% \subsection{\csh{xintBezoutAlgorithm}} +% \lverb|& +% Pour Bezout: objectif, renvoyer$\ +% {N}{A}{0}{1}{D=r(n)}{B}{1}{0}{q1}{r1}{alpha1=q1}{beta1=1}$\ +% {q2}{r2}{alpha2}{beta2}....{qN}{rN=0}{alphaN=A/D}{betaN=B/D}$\ +% alpha0=1, beta0=0, alpha(-1)=0, beta(-1)=1| +% \begin{macrocode} +\def\xintBezoutAlgorithm {\romannumeral0\xintbezoutalgorithm }% +\def\xintbezoutalgorithm #1% +{% + \expandafter \XINT_bezalg + \expandafter{\romannumeral0\xintiiabs{\xintNum{#1}}}% +}% +\def\XINT_bezalg #1#2% +{% + \expandafter\XINT_bezalg_fork\romannumeral0\xintiiabs{\xintNum{#2}}\Z #1\Z +}% +% \end{macrocode} +% \lverb|Ici #3#4=A, #1#2=B| +% \begin{macrocode} +\def\XINT_bezalg_fork #1#2\Z #3#4\Z +{% + \xint_UDzerofork + #1\XINT_bezalg_BisZero + #3\XINT_bezalg_AisZero + 0\XINT_bezalg_a + \krof + 0{#1#2}{#3#4}1001{{#3#4}{#1#2}}{}\Z +}% +\def\XINT_bezalg_AisZero #1#2#3\Z{{1}{0}{0}{1}{#2}{#2}{1}{0}{0}{0}{0}{1}}% +\def\XINT_bezalg_BisZero #1#2#3#4\Z{{1}{0}{0}{1}{#3}{#3}{1}{0}{0}{0}{0}{1}}% +% \end{macrocode} +% \lverb|& +% pour préparer l'étape n+1 il faut +% {n}{r(n)}{r(n-1)}{alpha(n)}{beta(n)}{alpha(n-1)}{beta(n-1)}& +% {{q(n)}{r(n)}{alpha(n)}{beta(n)}}... +% division de #3 par #2| +% \begin{macrocode} +\def\XINT_bezalg_a #1#2#3% +{% + \expandafter\XINT_bezalg_b\the\numexpr #1+\xint_c_i\expandafter.% + \romannumeral0\XINT_div_prepare {#2}{#3}{#2}% +}% +% \end{macrocode} +% \lverb|& +% {n+1}{q(n+1)}{r(n+1)}{r(n)}{alpha(n)}{beta(n)}{alpha(n-1)}{beta(n-1)}...| +% \begin{macrocode} +\def\XINT_bezalg_b #1.#2#3#4#5#6#7#8% +{% + \expandafter\XINT_bezalg_c\expandafter + {\romannumeral0\xintiiadd {\xintiiMul {#6}{#2}}{#8}}% + {\romannumeral0\xintiiadd {\xintiiMul {#5}{#2}}{#7}}% + {#1}{#2}{#3}{#4}{#5}{#6}% +}% +% \end{macrocode} +% \lverb|& +% {beta(n+1)}{alpha(n+1)}{n+1}{q(n+1)}{r(n+1)}{r(n)}{alpha(n)}{beta(n}}| +% \begin{macrocode} +\def\XINT_bezalg_c #1#2#3#4#5#6% +{% + \expandafter\XINT_bezalg_d\expandafter {#2}{#3}{#4}{#5}{#6}{#1}% +}% +% \end{macrocode} +% \lverb|{alpha(n+1)}{n+1}{q(n+1)}{r(n+1)}{r(n)}{beta(n+1)}| +% \begin{macrocode} +\def\XINT_bezalg_d #1#2#3#4#5#6#7#8% +{% + \XINT_bezalg_e #4\Z {#2}{#4}{#5}{#1}{#6}{#7}{#8}{{#3}{#4}{#1}{#6}}% +}% +% \end{macrocode} +% \lverb|r(n+1)\Z {n+1}{r(n+1)}{r(n)}{alpha(n+1)}{beta(n+1)}$\ +% {alpha(n)}{beta(n)}{q,r,alpha,beta(n+1)}$\ +% Test si r(n+1) est nul.| +% \begin{macrocode} +\def\XINT_bezalg_e #1#2\Z +{% + \xint_gob_til_zero #1\XINT_bezalg_end0\XINT_bezalg_a +}% +% \end{macrocode} +% \lverb|& +% Ici r(n+1) = 0. On arrête on se prépare à inverser.$\ +% {n+1}{r(n+1)}{r(n)}{alpha(n+1)}{beta(n+1)}{alpha(n)}{beta(n)}$\ +% {q,r,alpha,beta(n+1)}...{{A}{B}}{}\Z$\ +% On veut renvoyer$\ +% {N}{A}{0}{1}{D=r(n)}{B}{1}{0}{q1}{r1}{alpha1=q1}{beta1=1}$\ +% {q2}{r2}{alpha2}{beta2}....{qN}{rN=0}{alphaN=A/D}{betaN=B/D}| +% \begin{macrocode} +\def\XINT_bezalg_end0\XINT_bezalg_a #1#2#3#4#5#6#7#8\Z +{% + \expandafter\XINT_bezalg_end_a + \romannumeral0% + \XINT_rord_main {}#8{{#1}{#3}}% + \xint: + \xint_bye\xint_bye\xint_bye\xint_bye + \xint_bye\xint_bye\xint_bye\xint_bye + \xint: +}% +% \end{macrocode} +% \lverb|& +% {N}{D}{A}{B}{q1}{r1}{alpha1=q1}{beta1=1}{q2}{r2}{alpha2}{beta2}$\ +% ....{qN}{rN=0}{alphaN=A/D}{betaN=B/D}$\ +% On veut renvoyer$\ +% {N}{A}{0}{1}{D=r(n)}{B}{1}{0}{q1}{r1}{alpha1=q1}{beta1=1}$\ +% {q2}{r2}{alpha2}{beta2}....{qN}{rN=0}{alphaN=A/D}{betaN=B/D}| +% \begin{macrocode} +\def\XINT_bezalg_end_a #1#2#3#4{{#1}{#3}{0}{1}{#2}{#4}{1}{0}}% +% \end{macrocode} +% \subsection{\csh{xintGCDof}} +% \lverb|1.2l adds protection against items being non-terminated \the\numexpr...| +% \begin{macrocode} +\def\xintGCDof {\romannumeral0\xintgcdof }% +\def\xintgcdof #1{\expandafter\XINT_gcdof_a\romannumeral`&&@#1\xint:}% +\def\XINT_gcdof_a #1{\expandafter\XINT_gcdof_b\romannumeral`&&@#1!}% +\def\XINT_gcdof_b #1!#2{\expandafter\XINT_gcdof_c\romannumeral`&&@#2!{#1}!}% +\def\XINT_gcdof_c #1{\xint_gob_til_xint: #1\XINT_gcdof_e\xint:\XINT_gcdof_d #1}% +\def\XINT_gcdof_d #1!{\expandafter\XINT_gcdof_b\romannumeral0\xintgcd {#1}}% +\def\XINT_gcdof_e #1!#2!{ #2}% +% \end{macrocode} +% \subsection{\csh{xintLCMof}} +% \lverb|New with 1.09a| +% \lverb|1.2l adds protection against items being non-terminated \the\numexpr...| +% \begin{macrocode} +\def\xintLCMof {\romannumeral0\xintlcmof }% +\def\xintlcmof #1{\expandafter\XINT_lcmof_a\romannumeral`&&@#1\xint:}% +\def\XINT_lcmof_a #1{\expandafter\XINT_lcmof_b\romannumeral`&&@#1!}% +\def\XINT_lcmof_b #1!#2{\expandafter\XINT_lcmof_c\romannumeral`&&@#2!{#1}!}% +\def\XINT_lcmof_c #1{\xint_gob_til_xint: #1\XINT_lcmof_e\xint:\XINT_lcmof_d #1}% +\def\XINT_lcmof_d #1!{\expandafter\XINT_lcmof_b\romannumeral0\xintlcm {#1}}% +\def\XINT_lcmof_e #1!#2!{ #2}% +% \end{macrocode} +% \subsection{\csh{xintTypesetEuclideAlgorithm}} +% \lverb|& +% TYPESETTING +% +% Organisation: +% +% {N}{A}{D}{B}{q1}{r1}{q2}{r2}{q3}{r3}....{qN}{rN=0}$\ +% \U1 = N = nombre d'étapes, \U3 = PGCD, \U2 = A, \U4=B +% q1 = \U5, q2 = \U7 --> qn = \U<2n+3>, rn = \U<2n+4> +% bn = rn. B = r0. A=r(-1) +% +% r(n-2) = q(n)r(n-1)+r(n) (n e étape) +% +% \U{2n} = \U{2n+3} \times \U{2n+2} + \U{2n+4}, n e étape. +% (avec n entre 1 et N) +% +% 1.09h uses \xintloop, and \par rather than \endgraf; and \par rather than +% \hfill\break| +% \begin{macrocode} +\def\xintTypesetEuclideAlgorithm {% + \unless\ifdefined\xintAssignArray + \errmessage + {xintgcd: package xinttools is required for \string\xintTypesetEuclideAlgorithm}% + \expandafter\xint_gobble_iii + \fi + \XINT_TypesetEuclideAlgorithm +}% +\def\XINT_TypesetEuclideAlgorithm #1#2% +{% l'algo remplace #1 et #2 par |#1| et |#2| + \par + \begingroup + \xintAssignArray\xintEuclideAlgorithm {#1}{#2}\to\U + \edef\A{\U2}\edef\B{\U4}\edef\N{\U1}% + \setbox 0 \vbox{\halign {$##$\cr \A\cr \B \cr}}% + \count 255 1 + \xintloop + \indent\hbox to \wd 0 {\hfil$\U{\numexpr 2*\count255\relax}$}% + ${} = \U{\numexpr 2*\count255 + 3\relax} + \times \U{\numexpr 2*\count255 + 2\relax} + + \U{\numexpr 2*\count255 + 4\relax}$% + \ifnum \count255 < \N + \par + \advance \count255 1 + \repeat + \endgroup +}% +% \end{macrocode} +% \subsection{\csh{xintTypesetBezoutAlgorithm}} +% \lverb|& +% Pour Bezout on a: +% {N}{A}{0}{1}{D=r(n)}{B}{1}{0}{q1}{r1}{alpha1=q1}{beta1=1}$\ +% {q2}{r2}{alpha2}{beta2}....{qN}{rN=0}{alphaN=A/D}{betaN=B/D}% +% Donc 4N+8 termes: +% U1 = N, U2= A, U5=D, U6=B, q1 = U9, qn = U{4n+5}, n au moins 1$\ +% rn = U{4n+6}, n au moins -1$\ +% alpha(n) = U{4n+7}, n au moins -1$\ +% beta(n) = U{4n+8}, n au moins -1 +% +% 1.09h uses \xintloop, and \par rather than \endgraf; and no more \parindent0pt +% | +% \begin{macrocode} +\def\xintTypesetBezoutAlgorithm {% + \unless\ifdefined\xintAssignArray + \errmessage + {xintgcd: package xinttools is required for \string\xintTypesetBezoutAlgorithm}% + \expandafter\xint_gobble_iii + \fi + \XINT_TypesetBezoutAlgorithm +}% +\def\XINT_TypesetBezoutAlgorithm #1#2% +{% + \par + \begingroup + \xintAssignArray\xintBezoutAlgorithm {#1}{#2}\to\BEZ + \edef\A{\BEZ2}\edef\B{\BEZ6}\edef\N{\BEZ1}% A = |#1|, B = |#2| + \setbox 0 \vbox{\halign {$##$\cr \A\cr \B \cr}}% + \count255 1 + \xintloop + \indent\hbox to \wd 0 {\hfil$\BEZ{4*\count255 - 2}$}% + ${} = \BEZ{4*\count255 + 5} + \times \BEZ{4*\count255 + 2} + + \BEZ{4*\count255 + 6}$\hfill\break + \hbox to \wd 0 {\hfil$\BEZ{4*\count255 +7}$}% + ${} = \BEZ{4*\count255 + 5} + \times \BEZ{4*\count255 + 3} + + \BEZ{4*\count255 - 1}$\hfill\break + \hbox to \wd 0 {\hfil$\BEZ{4*\count255 +8}$}% + ${} = \BEZ{4*\count255 + 5} + \times \BEZ{4*\count255 + 4} + + \BEZ{4*\count255 }$ + \par + \ifnum \count255 < \N + \advance \count255 1 + \repeat + \edef\U{\BEZ{4*\N + 4}}% + \edef\V{\BEZ{4*\N + 3}}% + \edef\D{\BEZ5}% + \ifodd\N + $\U\times\A - \V\times \B = -\D$% + \else + $\U\times\A - \V\times\B = \D$% + \fi + \par + \endgroup +}% +\XINT_restorecatcodes_endinput% +% \end{macrocode} +% \StoreCodelineNo {xintgcd} +% \cleardoublepage\let\xintgcdnameUp\undefined +%\gardesactifs +%\let</xintgcd>\relax +%\let<*xintfrac>\gardesinactifs +%</xintgcd>^^A---------------------------------------------------- +%<*xintfrac>^^A--------------------------------------------------- +%^^A -*- coding: utf-8; mode: doctex; fill-column: 78; -*- +% \clearpage\csname xintfracnameUp\endcsname +% \section{Package \xintfracnameimp implementation} +% \RaisedLabel{sec:fracimp} +% +% \localtableofcontents +% +% The commenting is currently (\xintdocdate) very sparse. +% +% \subsection{Catcodes, \protect\eTeX{} and reload detection} +% +% The code for reload detection was initially copied from \textsc{Heiko +% Oberdiek}'s packages, then modified. +% +% The method for catcodes was also initially directly inspired by these +% packages. +% +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode64=11 % @ + \catcode35=6 % # + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \let\z\endgroup + \expandafter\let\expandafter\x\csname ver@xintfrac.sty\endcsname + \expandafter\let\expandafter\w\csname ver@xint.sty\endcsname + \expandafter + \ifx\csname PackageInfo\endcsname\relax + \def\y#1#2{\immediate\write-1{Package #1 Info: #2.}}% + \else + \def\y#1#2{\PackageInfo{#1}{#2}}% + \fi + \expandafter + \ifx\csname numexpr\endcsname\relax + \y{xintfrac}{\numexpr not available, aborting input}% + \aftergroup\endinput + \else + \ifx\x\relax % plain-TeX, first loading of xintfrac.sty + \ifx\w\relax % but xint.sty not yet loaded. + \def\z{\endgroup\input xint.sty\relax}% + \fi + \else + \def\empty {}% + \ifx\x\empty % LaTeX, first loading, + % variable is initialized, but \ProvidesPackage not yet seen + \ifx\w\relax % xint.sty not yet loaded. + \def\z{\endgroup\RequirePackage{xint}}% + \fi + \else + \aftergroup\endinput % xintfrac already loaded. + \fi + \fi + \fi +\z% +\XINTsetupcatcodes% defined in xintkernel.sty +% \end{macrocode} +% \subsection{Package identification} +% \begin{macrocode} +\XINT_providespackage +\ProvidesPackage{xintfrac}% + [2019/04/05 1.3e Expandable operations on fractions (JFB)]% +% \end{macrocode} +% \subsection{\csh{XINT_cntSgnFork}} +% \lverb|1.09i. Used internally, #1 must expand to \m@ne, \z@, or \@ne or +% equivalent. \XINT_cntSgnFork does not insert a romannumeral stopper.| +% \begin{macrocode} +\def\XINT_cntSgnFork #1% +{% + \ifcase #1\expandafter\xint_secondofthree + \or\expandafter\xint_thirdofthree + \else\expandafter\xint_firstofthree + \fi +}% +% \end{macrocode} +% \subsection{\cshnolabel{xintLen}} +% \lverb|The used formula is disputable, the idea is that A/1 and A should have +% same length. Venerable code rewritten for 1.2i, following updates to +% \xintLength in xintkernel.sty. And sadly, I forgot on this +% occasion that this macro is not supposed to count the sign... Fixed in 1.2k.| +% \begin{macrocode} +\def\xintLen {\romannumeral0\xintlen }% +\def\xintlen #1% +{% + \expandafter\XINT_flen\romannumeral0\XINT_infrac {#1}% +}% +\def\XINT_flen#1{\def\XINT_flen ##1##2##3% +{% + \expandafter#1% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \the\numexpr \XINT_abs##1+% + \XINT_len_fork ##2##3\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v + \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye-\xint_c_i + \relax +}}\XINT_flen{ }% +% \end{macrocode} +% \subsection{\csh{XINT_outfrac}} +% \lverb|& +% Months later (2014/10/22): perhaps I should document what this macro does +% before I forget? from {e}{N}{D} it outputs N/D[e], checking in passing if +% D=0 or if N=0. It also makes sure D is not < 0. I am not sure but I don't +% think there is any place in the code which could call \XINT_outfrac with a D +% < 0, but I should check.| +% \begin{macrocode} +\def\XINT_outfrac #1#2#3% +{% + \ifcase\XINT_cntSgn #3\xint: + \expandafter \XINT_outfrac_divisionbyzero + \or + \expandafter \XINT_outfrac_P + \else + \expandafter \XINT_outfrac_N + \fi + {#2}{#3}[#1]% +}% +\def\XINT_outfrac_divisionbyzero #1#2% +{% + \XINT_signalcondition{DivisionByZero}{Division of #1 by #2}{}{0/1[0]}% +}% +\def\XINT_outfrac_P#1{% +\def\XINT_outfrac_P ##1##2% + {\if0\XINT_Sgn ##1\xint:\expandafter\XINT_outfrac_Zero\fi#1##1/##2}% +}\XINT_outfrac_P{ }% +\def\XINT_outfrac_Zero #1[#2]{ 0/1[0]}% +\def\XINT_outfrac_N #1#2% +{% + \expandafter\XINT_outfrac_N_a\expandafter + {\romannumeral0\XINT_opp #2}{\romannumeral0\XINT_opp #1}% +}% +\def\XINT_outfrac_N_a #1#2% +{% + \expandafter\XINT_outfrac_P\expandafter {#2}{#1}% +}% +% \end{macrocode} +% \subsection{\csh{XINT_inFrac}}\label{src-XINT_infrac} +% \lverb|& +% Parses fraction, scientific notation, etc... and produces {n}{A}{B} +% corresponding to A/B times 10^n. No reduction to smallest terms. +% +% Extended in 1.07 to accept scientific notation on input. With lowercase +% e only. The \xintexpr parser does accept uppercase E also. Ah, by the way, +% perhaps I should at least say what this macro does? (belated addition +% 2014/10/22...), before I forget! It prepares the fraction in the internal +% format {exponent}{Numerator}{Denominator} where Denominator is at least 1. +% +% 2015/10/09: this venerable macro from the very early days (1.03, 2013/04/14) +% has gotten a lifting for release 1.2. There were two kinds of issues: +% +% 1) use of \W, \Z, \T delimiters was very poor choice as this could clash with +% user input, +% +% 2) the new \XINT_frac_gen handles macros (possibly empty) in the input as +% general as \A.\Be\C/\D.\Ee\F. The earlier version would not have expanded +% the \B or \E: digits after decimal mark were constrained to arise from +% expansion of the first token. Thus the 1.03 original code would have +% expanded only \A, \D, \C, and \F for this input. +% +% This reminded me think I should revisit the remaining earlier +% portions of code, as I was still learning TeX coding when I wrote them. +% +% Also I thought about parsing even faster the A/B[N] input, not expanding B, +% but this turned out to clash with some established uses in the documentation +% such as 1/\xintiiSqr{...}[0]. For the implementation, careful here about +% potential brace removals with parameter patterns such as like #1/#2#3[#4]for +% example. +% +% While I was at it 1.2 added \numexpr parsing of the N, which earlier was +% restricted to be only explicit digits. I allowed [] with empty N, but the +% way I did it in 1.2 with \the\numexpr 0#1 was buggy, as it did not allow #1 +% to be a \count for example or itself a \numexpr (although such inputs were +% not previously allowed, I later turned out to use them in the code itself, +% e.g. the float factorial of version 1.2f). The better way would be +% \the\numexpr#1+\xint_c_ but 1.2f finally does only \the\numexpr #1 and #1 is +% not allowed to be empty. +% +% The 1.2 \XINT_frac_gen had two locations with such a problematic \numexpr +% 0#1 which I replaced for 1.2f with \numexpr#1+\xint_c_. +% +% Regarding calling the macro with an argument A[<expression>], a / inthe +% expression must be suitably hidden for example in \firstofone type +% constructs. +% +% Note: when the numerator is found to be zero \XINT_inFrac *always* returns +% {0}{0}{1}. This behaviour must not change because 1.2g \xintFloat and +% XINTinFloat (for example) rely upon it: if the denominator on output is not +% 1, then \xintFloat assumes that the numerator is not zero. +% +% As described in the manual, if the input contains a (final) [N] part, it is +% assumed that it is in the shape A[N] or A/B[N] with A (and B) not containing +% neither decimal mark nor scientific part, moreover B must be positive and A +% have at most one minus sign (and no plus sign). Else there will be errors, +% for example -0/2[0] would not be recognized as being zero at this stage and +% this could cause issues afterwards. When there is no ending [N] part, both +% numerator and denominator will be parsed for the more general format +% allowing decimal digits and scientific part and possibly multiple leading +% signs. +% +% 1.2l fixes frailty of \XINT_infrac (hence basically of all xintfrac macros) +% respective to non terminated \numexpr input: \xintRaw{\the\numexpr1} for +% example. The issue was that \numexpr sees the / and expands what's next. +% But even \numexpr 1// for example creates an error, and to my mind this is +% a defect of \numexpr. It should be able to trace back and see that / was +% used as delimiter not as operator. Anyway, I thus fixed this problem +% belatedly here regarding \XINT_infrac. +% | +% \begin{macrocode} +\def\XINT_inFrac {\romannumeral0\XINT_infrac }% +\def\XINT_infrac #1% +{% + \expandafter\XINT_infrac_fork\romannumeral`&&@#1\xint:/\XINT_W[\XINT_W\XINT_T +}% +\def\XINT_infrac_fork #1[#2% +{% + \xint_UDXINTWfork + #2\XINT_frac_gen % input has no brackets [N] + \XINT_W\XINT_infrac_res_a % there is some [N], must be strict A[N] or A/B[N] input + \krof + #1[#2% +}% +\def\XINT_infrac_res_a #1% +{% + \xint_gob_til_zero #1\XINT_infrac_res_zero 0\XINT_infrac_res_b #1% +}% +% \end{macrocode} +% \lverb|Note that input exponent is here ignored and forced to be zero.| +% \begin{macrocode} +\def\XINT_infrac_res_zero 0\XINT_infrac_res_b #1\XINT_T {{0}{0}{1}}% +\def\XINT_infrac_res_b #1/#2% +{% + \xint_UDXINTWfork + #2\XINT_infrac_res_ca % it was A[N] input + \XINT_W\XINT_infrac_res_cb % it was A/B[N] input + \krof + #1/#2% +}% +% \end{macrocode} +% \lverb|An empty [] is not allowed. (this was authorized in 1.2, removed in +% 1.2f). As nobody reads xint documentation, no one will have noticed the +% fleeting possibility.| +% \begin{macrocode} +\def\XINT_infrac_res_ca #1[#2]\xint:/\XINT_W[\XINT_W\XINT_T + {\expandafter{\the\numexpr #2}{#1}{1}}% +\def\XINT_infrac_res_cb #1/#2[% + {\expandafter\XINT_infrac_res_cc\romannumeral`&&@#2~#1[}% +\def\XINT_infrac_res_cc #1~#2[#3]\xint:/\XINT_W[\XINT_W\XINT_T + {\expandafter{\the\numexpr #3}{#2}{#1}}% +% \end{macrocode} +% \subsection{\csh{XINT_frac_gen}} +% \lverb|Extended in 1.07 to recognize and accept scientific notation both at +% the numerator and (possible) denominator. Only a lowercase e will do here, +% but uppercase E is possible within an \xintexpr..\relax +% +% Completely rewritten for 1.2 2015/10/10. The parsing handles inputs such as +% \A.\Be\C/\D.\Ee\F where each of \A, \B, \D, and \E may need f-expansion and +% \C and \F will end up in \numexpr. +% +% 1.2f corrects an issue to allow \C and \F to be \count variable (or +% expressions with \numexpr): 1.2 did a bad \numexpr0#1 which allowed only +% explicit digits for expanded #1.| +% \begin{macrocode} +\def\XINT_frac_gen #1/#2% +{% + \xint_UDXINTWfork + #2\XINT_frac_gen_A % there was no / + \XINT_W\XINT_frac_gen_B % there was a / + \krof + #1/#2% +}% +% \end{macrocode} +% \lverb|Note that #1 is only expanded so far up to decimal mark or "e".| +% \begin{macrocode} +\def\XINT_frac_gen_A #1\xint:/\XINT_W [\XINT_W {\XINT_frac_gen_C 0~1!#1ee.\XINT_W }% +\def\XINT_frac_gen_B #1/#2\xint:/\XINT_W[%\XINT_W +{% + \expandafter\XINT_frac_gen_Ba + \romannumeral`&&@#2ee.\XINT_W\XINT_Z #1ee.%\XINT_W +}% +\def\XINT_frac_gen_Ba #1.#2% +{% + \xint_UDXINTWfork + #2\XINT_frac_gen_Bb + \XINT_W\XINT_frac_gen_Bc + \krof + #1.#2% +}% +\def\XINT_frac_gen_Bb #1e#2e#3\XINT_Z + {\expandafter\XINT_frac_gen_C\the\numexpr #2+\xint_c_~#1!}% +\def\XINT_frac_gen_Bc #1.#2e% +{% + \expandafter\XINT_frac_gen_Bd\romannumeral`&&@#2.#1e% +}% +% \end{macrocode} +% \begin{macrocode} +\def\XINT_frac_gen_Bd #1.#2e#3e#4\XINT_Z +{% + \expandafter\XINT_frac_gen_C\the\numexpr #3-% + \numexpr\XINT_length_loop + #1\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v + \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye + ~#2#1!% +}% +\def\XINT_frac_gen_C #1!#2.#3% +{% + \xint_UDXINTWfork + #3\XINT_frac_gen_Ca + \XINT_W\XINT_frac_gen_Cb + \krof + #1!#2.#3% +}% +\def\XINT_frac_gen_Ca #1~#2!#3e#4e#5\XINT_T +{% + \expandafter\XINT_frac_gen_F\the\numexpr #4-#1\expandafter + ~\romannumeral0\expandafter\XINT_num_cleanup\the\numexpr\XINT_num_loop + #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z~#3~% +}% +\def\XINT_frac_gen_Cb #1.#2e% +{% + \expandafter\XINT_frac_gen_Cc\romannumeral`&&@#2.#1e% +}% +\def\XINT_frac_gen_Cc #1.#2~#3!#4e#5e#6\XINT_T +{% + \expandafter\XINT_frac_gen_F\the\numexpr #5-#2-% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \numexpr\XINT_length_loop + #1\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v + \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \relax\expandafter~% + \romannumeral0\expandafter\XINT_num_cleanup\the\numexpr\XINT_num_loop + #3\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z + ~#4#1~% +}% +\def\XINT_frac_gen_F #1~#2% +{% + \xint_UDzerominusfork + #2-\XINT_frac_gen_Gdivbyzero + 0#2{\XINT_frac_gen_G -{}}% + 0-{\XINT_frac_gen_G {}#2}% + \krof #1~% +}% +\def\XINT_frac_gen_Gdivbyzero #1~~#2~% +{% + \expandafter\XINT_frac_gen_Gdivbyzero_a + \romannumeral0\expandafter\XINT_num_cleanup\the\numexpr\XINT_num_loop + #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z~#1~% +}% +\def\XINT_frac_gen_Gdivbyzero_a #1~#2~% +{% + \XINT_signalcondition{DivisionByZero}{Division of #1 by zero}{}{{#2}{#1}{0}}% +}% +\def\XINT_frac_gen_G #1#2#3~#4~#5~% +{% + \expandafter\XINT_frac_gen_Ga + \romannumeral0\expandafter\XINT_num_cleanup\the\numexpr\XINT_num_loop + #1#5\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\Z~#3~{#2#4}% +}% +\def\XINT_frac_gen_Ga #1#2~#3~% +{% + \xint_gob_til_zero #1\XINT_frac_gen_zero 0% + {#3}{#1#2}% +}% +\def\XINT_frac_gen_zero 0#1#2#3{{0}{0}{1}}% +% \end{macrocode} +% \subsection{\csh{XINT_factortens}} +% \lverb|This is the core macro for \xintREZ. To be used as +% \romannumeral0\XINT_factortens{...}. Output is A.N. (formerly {A}{N}) where +% A is the integer stripped from trailing zeroes and N is the number of +% removed zeroes. Only for positive strict integers! +% +% Completely rewritten at 1.3a to replace a double \xintReverseOrder by a +% direct \numexpr governed expansion to the end and back, à la 1.2. I should +% comment more... and perhaps improve again in future. +% +% Testing shows significant gain at 100 digits or more.| +% \begin{macrocode} +\def\XINT_factortens #1{\expandafter\XINT_factortens_z + \romannumeral0\XINT_factortens_a#1% + \XINT_factortens_b123456789.}% +\def\XINT_factortens_z.\XINT_factortens_y{ }% +\def\XINT_factortens_a #1#2#3#4#5#6#7#8#9% + {\expandafter\XINT_factortens_x + \the\numexpr 1#1#2#3#4#5#6#7#8#9\XINT_factortens_a}% +\def\XINT_factortens_b#1\XINT_factortens_a#2#3.% + {.\XINT_factortens_cc 000000000-#2.}% +\def\XINT_factortens_x1#1.#2{#2#1}% +\def\XINT_factortens_y{.\XINT_factortens_y}% +\def\XINT_factortens_cc #1#2#3#4#5#6#7#8#9% + {\if#90\xint_dothis + {\expandafter\XINT_factortens_d\the\numexpr #8#7#6#5#4#3#2#1\relax + \xint_c_i 2345678.}\fi + \xint_orthat{\XINT_factortens_yy{#1#2#3#4#5#6#7#8#9}}}% +\def\XINT_factortens_yy #1#2.{.\XINT_factortens_y#1.0.}% +\def\XINT_factortens_c #1#2#3#4#5#6#7#8#9% + {\if#90\xint_dothis + {\expandafter\XINT_factortens_d\the\numexpr #8#7#6#5#4#3#2#1\relax + \xint_c_i 2345678.}\fi + \xint_orthat{.\XINT_factortens_y #1#2#3#4#5#6#7#8#9.}}% +\def\XINT_factortens_d #1#2#3#4#5#6#7#8#9% + {\if#10\expandafter\XINT_factortens_e\fi + \XINT_factortens_f #9#9#8#7#6#5#4#3#2#1.}% +\def\XINT_factortens_f #1#2\xint_c_i#3.#4.#5.% + {\expandafter\XINT_factortens_g\the\numexpr#1+#5.#3.}% +\def\XINT_factortens_g #1.#2.{.\XINT_factortens_y#2.#1.}% +\def\XINT_factortens_e #1..#2.% + {\expandafter.\expandafter\XINT_factortens_c + \the\numexpr\xint_c_ix+#2.}% +% \end{macrocode} +% \subsection{\xintListWithSep{, } +% {\xintApply{ \csh}{{xintEq}{xintNotEq}{xintGt}{xintLt}{xintGtorEq} +% {xintLtorEq}{xintIsZero}{xintIsNotZero}{xintOdd} +% {xintEven}{xintifSgn}{xintifCmp}{xintifEq}{xintifGt}{xintifLt} +% {xintifZero}{xintifNotZero}{xintifOne}{xintifOdd}}}} +% +% \lverb|Moved here at 1.3. Formerly these macros were already defined in +% xint.sty or even xintcore.sty. They are slim wrappers of macros defined +% elsewhere in xintfrac. +% | +% \begin{macrocode} +\def\xintEq {\romannumeral0\xinteq }% +\def\xinteq #1#2{\xintifeq{#1}{#2}{1}{0}}% +\def\xintNotEq#1#2{\romannumeral0\xintifeq {#1}{#2}{0}{1}}% +\def\xintGt {\romannumeral0\xintgt }% +\def\xintgt #1#2{\xintifgt{#1}{#2}{1}{0}}% +\def\xintLt {\romannumeral0\xintlt }% +\def\xintlt #1#2{\xintiflt{#1}{#2}{1}{0}}% +\def\xintGtorEq #1#2{\romannumeral0\xintiflt {#1}{#2}{0}{1}}% +\def\xintLtorEq #1#2{\romannumeral0\xintifgt {#1}{#2}{0}{1}}% +\def\xintIsZero {\romannumeral0\xintiszero }% +\def\xintiszero #1{\if0\xintSgn{#1}\xint_afterfi{ 1}\else\xint_afterfi{ 0}\fi}% +\def\xintIsNotZero{\romannumeral0\xintisnotzero }% +\def\xintisnotzero + #1{\if0\xintSgn{#1}\xint_afterfi{ 0}\else\xint_afterfi{ 1}\fi}% +\def\xintOdd {\romannumeral0\xintodd }% +\def\xintodd #1% +{% + \ifodd\xintLDg{\xintNum{#1}} %<- intentional space + \xint_afterfi{ 1}% + \else + \xint_afterfi{ 0}% + \fi +}% +\def\xintEven {\romannumeral0\xinteven }% +\def\xinteven #1% +{% + \ifodd\xintLDg{\xintNum{#1}} %<- intentional space + \xint_afterfi{ 0}% + \else + \xint_afterfi{ 1}% + \fi +}% +\def\xintifSgn{\romannumeral0\xintifsgn }% +\def\xintifsgn #1% +{% + \ifcase \xintSgn{#1} + \expandafter\xint_stop_atsecondofthree + \or\expandafter\xint_stop_atthirdofthree + \else\expandafter\xint_stop_atfirstofthree + \fi +}% +\def\xintifCmp{\romannumeral0\xintifcmp }% +\def\xintifcmp #1#2% +{% + \ifcase\xintCmp {#1}{#2} + \expandafter\xint_stop_atsecondofthree + \or\expandafter\xint_stop_atthirdofthree + \else\expandafter\xint_stop_atfirstofthree + \fi +}% +\def\xintifEq {\romannumeral0\xintifeq }% +\def\xintifeq #1#2% +{% + \if0\xintCmp{#1}{#2}% + \expandafter\xint_stop_atfirstoftwo + \else\expandafter\xint_stop_atsecondoftwo + \fi +}% +\def\xintifGt {\romannumeral0\xintifgt }% +\def\xintifgt #1#2% +{% + \if1\xintCmp{#1}{#2}% + \expandafter\xint_stop_atfirstoftwo + \else\expandafter\xint_stop_atsecondoftwo + \fi +}% +\def\xintifLt {\romannumeral0\xintiflt }% +\def\xintiflt #1#2% +{% + \ifnum\xintCmp{#1}{#2}<\xint_c_ + \expandafter\xint_stop_atfirstoftwo + \else \expandafter\xint_stop_atsecondoftwo + \fi +}% +\def\xintifZero {\romannumeral0\xintifzero }% +\def\xintifzero #1% +{% + \if0\xintSgn{#1}% + \expandafter\xint_stop_atfirstoftwo + \else + \expandafter\xint_stop_atsecondoftwo + \fi +}% +\def\xintifNotZero{\romannumeral0\xintifnotzero }% +\def\xintifnotzero #1% +{% + \if0\xintSgn{#1}% + \expandafter\xint_stop_atsecondoftwo + \else + \expandafter\xint_stop_atfirstoftwo + \fi +}% +\def\xintifOne {\romannumeral0\xintifone }% +\def\xintifone #1% +{% + \if1\xintIsOne{#1}% + \expandafter\xint_stop_atfirstoftwo + \else + \expandafter\xint_stop_atsecondoftwo + \fi +}% +\def\xintifOdd {\romannumeral0\xintifodd }% +\def\xintifodd #1% +{% + \if\xintOdd{#1}1% + \expandafter\xint_stop_atfirstoftwo + \else + \expandafter\xint_stop_atsecondoftwo + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintRaw}} +% \lverb|& +% 1.07: this macro simply prints in a user readable form the fraction after its +% initial scanning. Useful when put inside braces in an \xintexpr, when the +% input is not yet in the A/B[n] form.| +% \begin{macrocode} +\def\xintRaw {\romannumeral0\xintraw }% +\def\xintraw +{% + \expandafter\XINT_raw\romannumeral0\XINT_infrac +}% +\def\XINT_raw #1#2#3{ #2/#3[#1]}% +% \end{macrocode} +% \subsection{\csh{xintiLogTen}} +% \lverb|& +% New at 1.3e +% | +% \begin{macrocode} +\def\xintiLogTen {\the\numexpr\xintilogten}% +\def\xintilogten +{% + \expandafter\XINT_ilogten\romannumeral0\xintraw +}% +\def\XINT_ilogten #1% +{% + \xint_UDzerominusfork + 0#1\XINT_ilogten_p + #1-\XINT_ilogten_z + 0-{\XINT_ilogten_p#1}% + \krof +}% +\def\XINT_ilogten_z #1[#2]{-"7FFF8000\relax}% +\def\XINT_ilogten_p #1/#2[#3]% +{% + #3+\expandafter\XINT_ilogten_a + \the\numexpr\xintLength{#1}\expandafter.\the\numexpr\xintLength{#2}.#1.#2.% +}% +\def\XINT_ilogten_a #1.#2.% +{% + #1-#2\ifnum#1>#2 + \expandafter\XINT_ilogten_aa + \else + \expandafter\XINT_ilogten_ab + \fi #1.#2.% +}% +\def\XINT_ilogten_aa #1.#2.#3.#4.% +{% + \xintiiifLt{#3}{\XINT_dsx_addzerosnofuss{#1-#2}#4;}{-1}{}\relax +}% +\def\XINT_ilogten_ab #1.#2.#3.#4.% +{% + \xintiiifLt{\XINT_dsx_addzerosnofuss{#2-#1}#3;}{#4}{-1}{}\relax +}% +% \end{macrocode} +% \subsection{\csh{xintPRaw}} +% \lverb|1.09b| +% \begin{macrocode} +\def\xintPRaw {\romannumeral0\xintpraw }% +\def\xintpraw +{% + \expandafter\XINT_praw\romannumeral0\XINT_infrac +}% +\def\XINT_praw #1% +{% + \ifnum #1=\xint_c_ \expandafter\XINT_praw_a\fi \XINT_praw_A {#1}% +}% +\def\XINT_praw_A #1#2#3% +{% + \if\XINT_isOne{#3}1\expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo + \fi { #2[#1]}{ #2/#3[#1]}% +}% +\def\XINT_praw_a\XINT_praw_A #1#2#3% +{% + \if\XINT_isOne{#3}1\expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo + \fi { #2}{ #2/#3}% +}% +% \end{macrocode} +% \subsection{\csh{xintRawWithZeros}} +% \lverb|& +% This was called \xintRaw in versions earlier than 1.07| +% \begin{macrocode} +\def\xintRawWithZeros {\romannumeral0\xintrawwithzeros }% +\def\xintrawwithzeros +{% + \expandafter\XINT_rawz_fork\romannumeral0\XINT_infrac +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_rawz_fork #1% +{% + \ifnum#1<\xint_c_ + \expandafter\XINT_rawz_Ba + \else + \expandafter\XINT_rawz_A + \fi + #1.% +}% +\def\XINT_rawz_A #1.#2#3{\XINT_dsx_addzeros{#1}#2;/#3}% +\def\XINT_rawz_Ba -#1.#2#3{\expandafter\XINT_rawz_Bb + \expandafter{\romannumeral0\XINT_dsx_addzeros{#1}#3;}{#2}}% +\def\XINT_rawz_Bb #1#2{ #2/#1}% +% \end{macrocode} +% \subsection{\csh{xintDecToString}} +% \lverb|1.3. This is a backport from polexpr 0.4. It is definitely not in +% final form, consider it to be an unstable macro.| +% \begin{macrocode} +\def\xintDecToString{\romannumeral0\xintdectostring}% +\def\xintdectostring#1{\expandafter\XINT_dectostr\romannumeral0\xintraw{#1}}% +\def\XINT_dectostr #1/#2[#3]{\xintiiifZero {#1}% + \XINT_dectostr_z + {\if1\XINT_isOne{#2}\expandafter\XINT_dectostr_a + \else\expandafter\XINT_dectostr_b + \fi}% + #1/#2[#3]% +}% +\def\XINT_dectostr_z#1[#2]{ 0}% +\def\XINT_dectostr_a#1/#2[#3]{% + \ifnum#3<\xint_c_\xint_dothis{\xinttrunc{-#3}{#1[#3]}}\fi + \xint_orthat{\xintiie{#1}{#3}}% +}% +\def\XINT_dectostr_b#1/#2[#3]{% just to handle this somehow + \ifnum#3<\xint_c_\xint_dothis{\xinttrunc{-#3}{#1[#3]}/#2}\fi + \xint_orthat{\xintiie{#1}{#3}/#2}% +}% +% \end{macrocode} +% \subsection{\csh{xintFloor}, \csh{xintiFloor}} +% \lverb|1.09a, 1.1 for \xintiFloor/\xintFloor. Not efficient if big negative +% decimal exponent. Also sub-efficient if big positive decimal exponent.| +% \begin{macrocode} +\def\xintFloor {\romannumeral0\xintfloor }% +\def\xintfloor #1% devrais-je faire \xintREZ? + {\expandafter\XINT_ifloor \romannumeral0\xintrawwithzeros {#1}./1[0]}% +\def\xintiFloor {\romannumeral0\xintifloor }% +\def\xintifloor #1% + {\expandafter\XINT_ifloor \romannumeral0\xintrawwithzeros {#1}.}% +\def\XINT_ifloor #1/#2.{\xintiiquo {#1}{#2}}% +% \end{macrocode} +% \subsection{\csh{xintCeil}, \csh{xintiCeil}} +% \lverb|1.09a| +% \begin{macrocode} +\def\xintCeil {\romannumeral0\xintceil }% +\def\xintceil #1{\xintiiopp {\xintFloor {\xintOpp{#1}}}}% +\def\xintiCeil {\romannumeral0\xinticeil }% +\def\xinticeil #1{\xintiiopp {\xintiFloor {\xintOpp{#1}}}}% +% \end{macrocode} +% \subsection{\csh{xintNumerator}} +% \begin{macrocode} +\def\xintNumerator {\romannumeral0\xintnumerator }% +\def\xintnumerator +{% + \expandafter\XINT_numer\romannumeral0\XINT_infrac +}% +\def\XINT_numer #1% +{% + \ifcase\XINT_cntSgn #1\xint: + \expandafter\XINT_numer_B + \or + \expandafter\XINT_numer_A + \else + \expandafter\XINT_numer_B + \fi + {#1}% +}% +\def\XINT_numer_A #1#2#3{\XINT_dsx_addzeros{#1}#2;}% +\def\XINT_numer_B #1#2#3{ #2}% +% \end{macrocode} +% \subsection{\csh{xintDenominator}} +% \begin{macrocode} +\def\xintDenominator {\romannumeral0\xintdenominator }% +\def\xintdenominator +{% + \expandafter\XINT_denom_fork\romannumeral0\XINT_infrac +}% +\def\XINT_denom_fork #1% +{% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \ifnum#1<\xint_c_ + \expandafter\XINT_denom_B + \else + \expandafter\XINT_denom_A + \fi + #1.% +}% +\def\XINT_denom_A #1.#2#3{ #3}% +\def\XINT_denom_B -#1.#2#3{\XINT_dsx_addzeros{#1}#3;}% +% \end{macrocode} +% \subsection{\csh{xintFrac}} +% \lverb|Useless typesetting macro.| +% \begin{macrocode} +\def\xintFrac {\romannumeral0\xintfrac }% +\def\xintfrac #1% +{% + \expandafter\XINT_fracfrac_A\romannumeral0\XINT_infrac {#1}% +}% +\def\XINT_fracfrac_A #1{\XINT_fracfrac_B #1\Z }% +\catcode`^=7 +\def\XINT_fracfrac_B #1#2\Z +{% + \xint_gob_til_zero #1\XINT_fracfrac_C 0\XINT_fracfrac_D {10^{#1#2}}% +}% +\def\XINT_fracfrac_C 0\XINT_fracfrac_D #1#2#3% +{% + \if1\XINT_isOne {#3}% + \xint_afterfi {\expandafter\xint_stop_atfirstoftwo\xint_gobble_ii }% + \fi + \space + \frac {#2}{#3}% +}% +\def\XINT_fracfrac_D #1#2#3% +{% + \if1\XINT_isOne {#3}\XINT_fracfrac_E\fi + \space + \frac {#2}{#3}#1% +}% +\def\XINT_fracfrac_E \fi\space\frac #1#2{\fi \space #1\cdot }% +% \end{macrocode} +% \subsection{\csh{xintSignedFrac}} +% \begin{macrocode} +\def\xintSignedFrac {\romannumeral0\xintsignedfrac }% +\def\xintsignedfrac #1% +{% + \expandafter\XINT_sgnfrac_a\romannumeral0\XINT_infrac {#1}% +}% +\def\XINT_sgnfrac_a #1#2% +{% + \XINT_sgnfrac_b #2\Z {#1}% +}% +\def\XINT_sgnfrac_b #1% +{% + \xint_UDsignfork + #1\XINT_sgnfrac_N + -{\XINT_sgnfrac_P #1}% + \krof +}% +\def\XINT_sgnfrac_P #1\Z #2% +{% + \XINT_fracfrac_A {#2}{#1}% +}% +\def\XINT_sgnfrac_N +{% + \expandafter-\romannumeral0\XINT_sgnfrac_P +}% +% \end{macrocode} +% \subsection{\csh{xintFwOver}} +% \begin{macrocode} +\def\xintFwOver {\romannumeral0\xintfwover }% +\def\xintfwover #1% +{% + \expandafter\XINT_fwover_A\romannumeral0\XINT_infrac {#1}% +}% +\def\XINT_fwover_A #1{\XINT_fwover_B #1\Z }% +\def\XINT_fwover_B #1#2\Z +{% + \xint_gob_til_zero #1\XINT_fwover_C 0\XINT_fwover_D {10^{#1#2}}% +}% +\catcode`^=11 +\def\XINT_fwover_C #1#2#3#4#5% +{% + \if0\XINT_isOne {#5}\xint_afterfi { {#4\over #5}}% + \else\xint_afterfi { #4}% + \fi +}% +\def\XINT_fwover_D #1#2#3% +{% + \if0\XINT_isOne {#3}\xint_afterfi { {#2\over #3}}% + \else\xint_afterfi { #2\cdot }% + \fi + #1% +}% +% \end{macrocode} +% \subsection{\csh{xintSignedFwOver}} +% \begin{macrocode} +\def\xintSignedFwOver {\romannumeral0\xintsignedfwover }% +\def\xintsignedfwover #1% +{% + \expandafter\XINT_sgnfwover_a\romannumeral0\XINT_infrac {#1}% +}% +\def\XINT_sgnfwover_a #1#2% +{% + \XINT_sgnfwover_b #2\Z {#1}% +}% +\def\XINT_sgnfwover_b #1% +{% + \xint_UDsignfork + #1\XINT_sgnfwover_N + -{\XINT_sgnfwover_P #1}% + \krof +}% +\def\XINT_sgnfwover_P #1\Z #2% +{% + \XINT_fwover_A {#2}{#1}% +}% +\def\XINT_sgnfwover_N +{% + \expandafter-\romannumeral0\XINT_sgnfwover_P +}% +% \end{macrocode} +% \subsection{\csh{xintREZ}} +% \lverb|Removes trailing zeros from A and B and adjust the N in A/B[N]. +% +% The macro really doing the job \XINT_factortens was redone at 1.3a. But +% speed gain really noticeable only beyond about 100 digits.| +% \begin{macrocode} +\def\xintREZ {\romannumeral0\xintrez }% +\def\xintrez +{% + \expandafter\XINT_rez_A\romannumeral0\XINT_infrac +}% +\def\XINT_rez_A #1#2% +{% + \XINT_rez_AB #2\Z {#1}% +}% +\def\XINT_rez_AB #1% +{% + \xint_UDzerominusfork + #1-\XINT_rez_zero + 0#1\XINT_rez_neg + 0-{\XINT_rez_B #1}% + \krof +}% +\def\XINT_rez_zero #1\Z #2#3{ 0/1[0]}% +\def\XINT_rez_neg {\expandafter-\romannumeral0\XINT_rez_B }% +\def\XINT_rez_B #1\Z +{% + \expandafter\XINT_rez_C\romannumeral0\XINT_factortens {#1}% +}% +\def\XINT_rez_C #1.#2.#3#4% +{% + \expandafter\XINT_rez_D\romannumeral0\XINT_factortens {#4}#3+#2.#1.% +}% +\def\XINT_rez_D #1.#2.#3.% +{% + \expandafter\XINT_rez_E\the\numexpr #3-#2.#1.% +}% +\def\XINT_rez_E #1.#2.#3.{ #3/#2[#1]}% +% \end{macrocode} +% \subsection{\csh{xintE}} +% \lverb|1.07: The fraction is the first argument contrarily to \xintTrunc and +% \xintRound. +% +% 1.1 modifies and moves \xintiiE to xint.sty.| +% \begin{macrocode} +\def\xintE {\romannumeral0\xinte }% +\def\xinte #1% +{% + \expandafter\XINT_e \romannumeral0\XINT_infrac {#1}% +}% +\def\XINT_e #1#2#3#4% +{% + \expandafter\XINT_e_end\the\numexpr #1+#4.{#2}{#3}% +}% +\def\XINT_e_end #1.#2#3{ #2/#3[#1]}% +% \end{macrocode} +% \subsection{\csh{xintIrr}, \csh{xintPIrr}} +% \lverb|\xintPIrr (partial Irr, which ignores the decimal part) added at 1.3.| +% \begin{macrocode} +\def\xintIrr {\romannumeral0\xintirr }% +\def\xintPIrr{\romannumeral0\xintpirr }% +\def\xintirr #1% +{% + \expandafter\XINT_irr_start\romannumeral0\xintrawwithzeros {#1}\Z +}% +\def\xintpirr #1% +{% + \expandafter\XINT_pirr_start\romannumeral0\xintraw{#1}% +}% +\def\XINT_irr_start #1#2/#3\Z +{% + \if0\XINT_isOne {#3}% + \xint_afterfi + {\xint_UDsignfork + #1\XINT_irr_negative + -{\XINT_irr_nonneg #1}% + \krof}% + \else + \xint_afterfi{\XINT_irr_denomisone #1}% + \fi + #2\Z {#3}% +}% +\def\XINT_pirr_start #1#2/#3[% +{% + \if0\XINT_isOne {#3}% + \xint_afterfi + {\xint_UDsignfork + #1\XINT_irr_negative + -{\XINT_irr_nonneg #1}% + \krof}% + \else + \xint_afterfi{\XINT_irr_denomisone #1}% + \fi + #2\Z {#3}[% +}% +\def\XINT_irr_denomisone #1\Z #2{ #1/1}% changed in 1.08 +\def\XINT_irr_negative #1\Z #2{\XINT_irr_D #1\Z #2\Z -}% +\def\XINT_irr_nonneg #1\Z #2{\XINT_irr_D #1\Z #2\Z \space}% +\def\XINT_irr_D #1#2\Z #3#4\Z +{% + \xint_UDzerosfork + #3#1\XINT_irr_indeterminate + #30\XINT_irr_divisionbyzero + #10\XINT_irr_zero + 00\XINT_irr_loop_a + \krof + {#3#4}{#1#2}{#3#4}{#1#2}% +}% +\def\XINT_irr_indeterminate #1#2#3#4#5% +{% + \XINT_signalcondition{DivisionUndefined}{indeterminate: 0/0}{}{0/1}% +}% +\def\XINT_irr_divisionbyzero #1#2#3#4#5% +{% + \XINT_signalcondition{DivisionByZero}{vanishing denominator: #5#2/0}{}{0/1}% +}% +\def\XINT_irr_zero #1#2#3#4#5{ 0/1}% changed in 1.08 +\def\XINT_irr_loop_a #1#2% +{% + \expandafter\XINT_irr_loop_d + \romannumeral0\XINT_div_prepare {#1}{#2}{#1}% +}% +\def\XINT_irr_loop_d #1#2% +{% + \XINT_irr_loop_e #2\Z +}% +\def\XINT_irr_loop_e #1#2\Z +{% + \xint_gob_til_zero #1\XINT_irr_loop_exit0\XINT_irr_loop_a {#1#2}% +}% +\def\XINT_irr_loop_exit0\XINT_irr_loop_a #1#2#3#4% +{% + \expandafter\XINT_irr_loop_exitb\expandafter + {\romannumeral0\xintiiquo {#3}{#2}}% + {\romannumeral0\xintiiquo {#4}{#2}}% +}% +\def\XINT_irr_loop_exitb #1#2% +{% + \expandafter\XINT_irr_finish\expandafter {#2}{#1}% +}% +\def\XINT_irr_finish #1#2#3{#3#1/#2}% changed in 1.08 +% \end{macrocode} +% \subsection{\csh{xintifInt}} +% \begin{macrocode} +\def\xintifInt {\romannumeral0\xintifint }% +\def\xintifint #1{\expandafter\XINT_ifint\romannumeral0\xintrawwithzeros {#1}.}% +\def\XINT_ifint #1/#2.% +{% + \if 0\xintiiRem {#1}{#2}% + \expandafter\xint_stop_atfirstoftwo + \else + \expandafter\xint_stop_atsecondoftwo + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintIsInt}} +% \lverb|Added at 1.3d only, for isint() xintexpr function.| +% \begin{macrocode} +\def\xintIsInt {\romannumeral0\xintisint }% +\def\xintisint #1% + {\expandafter\XINT_ifint\romannumeral0\xintrawwithzeros {#1}.10}% +% \end{macrocode} +% \subsection{\csh{xintJrr}} +% \begin{macrocode} +\def\xintJrr {\romannumeral0\xintjrr }% +\def\xintjrr #1% +{% + \expandafter\XINT_jrr_start\romannumeral0\xintrawwithzeros {#1}\Z +}% +\def\XINT_jrr_start #1#2/#3\Z +{% + \if0\XINT_isOne {#3}\xint_afterfi + {\xint_UDsignfork + #1\XINT_jrr_negative + -{\XINT_jrr_nonneg #1}% + \krof}% + \else + \xint_afterfi{\XINT_jrr_denomisone #1}% + \fi + #2\Z {#3}% +}% +\def\XINT_jrr_denomisone #1\Z #2{ #1/1}% changed in 1.08 +\def\XINT_jrr_negative #1\Z #2{\XINT_jrr_D #1\Z #2\Z -}% +\def\XINT_jrr_nonneg #1\Z #2{\XINT_jrr_D #1\Z #2\Z \space}% +\def\XINT_jrr_D #1#2\Z #3#4\Z +{% + \xint_UDzerosfork + #3#1\XINT_jrr_indeterminate + #30\XINT_jrr_divisionbyzero + #10\XINT_jrr_zero + 00\XINT_jrr_loop_a + \krof + {#3#4}{#1#2}1001% +}% +\def\XINT_jrr_indeterminate #1#2#3#4#5#6#7% +{% + \XINT_signalcondition{DivisionUndefined}{indeterminate: 0/0}{}{0/1}% +}% +\def\XINT_jrr_divisionbyzero #1#2#3#4#5#6#7% +{% + \XINT_signalcondition{DivisionByZero}{Vanishing denominator: #7#2/0}{}{0/1}% +}% +\def\XINT_jrr_zero #1#2#3#4#5#6#7{ 0/1}% changed in 1.08 +\def\XINT_jrr_loop_a #1#2% +{% + \expandafter\XINT_jrr_loop_b + \romannumeral0\XINT_div_prepare {#1}{#2}{#1}% +}% +\def\XINT_jrr_loop_b #1#2#3#4#5#6#7% +{% + \expandafter \XINT_jrr_loop_c \expandafter + {\romannumeral0\xintiiadd{\XINT_mul_fork #4\xint:#1\xint:}{#6}}% + {\romannumeral0\xintiiadd{\XINT_mul_fork #5\xint:#1\xint:}{#7}}% + {#2}{#3}{#4}{#5}% +}% +\def\XINT_jrr_loop_c #1#2% +{% + \expandafter \XINT_jrr_loop_d \expandafter{#2}{#1}% +}% +\def\XINT_jrr_loop_d #1#2#3#4% +{% + \XINT_jrr_loop_e #3\Z {#4}{#2}{#1}% +}% +\def\XINT_jrr_loop_e #1#2\Z +{% + \xint_gob_til_zero #1\XINT_jrr_loop_exit0\XINT_jrr_loop_a {#1#2}% +}% +\def\XINT_jrr_loop_exit0\XINT_jrr_loop_a #1#2#3#4#5#6% +{% + \XINT_irr_finish {#3}{#4}% +}% +% \end{macrocode} +% \subsection{\csh{xintTFrac}} +% \lverb|1.09i, for frac in \xintexpr. And \xintFrac is already assigned. T for +% truncation. However, potentially not very efficient with numbers in scientific +% notations, with big exponents. Will have to think it again some day. I +% hesitated how to call the macro. Same convention as in maple, but some people +% reserve fractional part to x - floor(x). Also, not clear if I had to make it +% negative (or zero) if x < 0, or rather always positive. There should be in +% fact such a thing for each rounding function, trunc, round, floor, ceil. | +% \begin{macrocode} +\def\xintTFrac {\romannumeral0\xinttfrac }% +\def\xinttfrac #1{\expandafter\XINT_tfrac_fork\romannumeral0\xintrawwithzeros {#1}\Z }% +\def\XINT_tfrac_fork #1% +{% + \xint_UDzerominusfork + #1-\XINT_tfrac_zero + 0#1{\xintiiopp\XINT_tfrac_P }% + 0-{\XINT_tfrac_P #1}% + \krof +}% +\def\XINT_tfrac_zero #1\Z { 0/1[0]}% +\def\XINT_tfrac_P #1/#2\Z {\expandafter\XINT_rez_AB + \romannumeral0\xintiirem{#1}{#2}\Z {0}{#2}}% +% \end{macrocode} +% \subsection{\csh{xintTrunc}, \csh{xintiTrunc}} +% \lverb|& +% 1.2i release notes: ever since its inception this macro was stupid for a +% decimal input: it did not handle it separately from the general fraction +% case A/B[N] with B>1, hence ended up doing divisions by powers of ten. But +% this meant that nesting \xintTrunc with itself was very inefficient. +% +% 1.2i version is better. However it still handles B>1, N<0 via adding zeros +% to B and dividing with this extended B. A possibly more efficient approach +% is implemented in \xintXTrunc, but its logic is more complicated, the code +% is quite longer and making it f-expandable would not shorten it... I decided +% for the time being to not complicate things here. +% | +% \begin{macrocode} +\def\xintTrunc {\romannumeral0\xinttrunc }% +\def\xintiTrunc {\romannumeral0\xintitrunc}% +\def\xinttrunc #1{\expandafter\XINT_trunc\the\numexpr#1.\XINT_trunc_G}% +\def\xintitrunc #1{\expandafter\XINT_trunc\the\numexpr#1.\XINT_itrunc_G}% +\def\XINT_trunc #1.#2#3% +{% + \expandafter\XINT_trunc_a\romannumeral0\XINT_infrac{#3}#1.#2% +}% +\def\XINT_trunc_a #1#2#3#4.#5% +{% + \if0\XINT_Sgn#2\xint:\xint_dothis\XINT_trunc_zero\fi + \if1\XINT_is_One#3XY\xint_dothis\XINT_trunc_sp_b\fi + \xint_orthat\XINT_trunc_b #1+#4.{#2}{#3}#5#4.% +}% +\def\XINT_trunc_zero #1.#2.{ 0}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_trunc_b {\expandafter\XINT_trunc_B\the\numexpr}% +\def\XINT_trunc_sp_b {\expandafter\XINT_trunc_sp_B\the\numexpr}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_trunc_B #1% +{% + \xint_UDsignfork + #1\XINT_trunc_C + -\XINT_trunc_D + \krof #1% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_trunc_sp_B #1% +{% + \xint_UDsignfork + #1\XINT_trunc_sp_C + -\XINT_trunc_sp_D + \krof #1% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_trunc_C -#1.#2#3% +{% + \expandafter\XINT_trunc_CE + \romannumeral0\XINT_dsx_addzeros{#1}#3;.{#2}% +}% +\def\XINT_trunc_CE #1.#2{\XINT_trunc_E #2.{#1}}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_trunc_sp_C -#1.#2#3{\XINT_trunc_sp_Ca #2.#1.}% +\def\XINT_trunc_sp_Ca #1% +{% + \xint_UDsignfork + #1{\XINT_trunc_sp_Cb -}% + -{\XINT_trunc_sp_Cb \space#1}% + \krof +}% +\def\XINT_trunc_sp_Cb #1#2.#3.% +{% + \expandafter\XINT_trunc_sp_Cc +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \romannumeral0\expandafter\XINT_split_fromright_a + \the\numexpr#3-\numexpr\XINT_length_loop + #2\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: + \xint_c_viii\xint_c_vii\xint_c_vi\xint_c_v + \xint_c_iv\xint_c_iii\xint_c_ii\xint_c_i\xint_c_\xint_bye + .#2\xint_bye2345678\xint_bye..#1% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_trunc_sp_Cc #1% +{% + \if.#1\xint_dothis{\XINT_trunc_sp_Cd 0.}\fi + \xint_orthat {\XINT_trunc_sp_Cd #1}% +}% +\def\XINT_trunc_sp_Cd #1.#2.#3% +{% + \XINT_trunc_sp_F #3#1.% +}% +\def\XINT_trunc_D #1.#2% +{% + \expandafter\XINT_trunc_E + \romannumeral0\XINT_dsx_addzeros {#1}#2;.% +}% +\def\XINT_trunc_sp_D #1.#2#3% +{% + \expandafter\XINT_trunc_sp_E + \romannumeral0\XINT_dsx_addzeros {#1}#2;.% +}% +\def\XINT_trunc_E #1% +{% + \xint_UDsignfork + #1{\XINT_trunc_F -}% + -{\XINT_trunc_F \space#1}% + \krof +}% +\def\XINT_trunc_sp_E #1% +{% + \xint_UDsignfork + #1{\XINT_trunc_sp_F -}% + -{\XINT_trunc_sp_F\space#1}% + \krof +}% +\def\XINT_trunc_F #1#2.#3#4% + {\expandafter#4\romannumeral`&&@\expandafter\xint_firstoftwo + \romannumeral0\XINT_div_prepare {#3}{#2}.#1}% +\def\XINT_trunc_sp_F #1#2.#3{#3#2.#1}% +\def\XINT_itrunc_G #1#2.#3#4.{\if#10\xint_dothis{ 0}\fi\xint_orthat{#3#1}#2}% +\def\XINT_trunc_G #1.#2#3.% +{% + \expandafter\XINT_trunc_H + \the\numexpr\romannumeral0\xintlength {#1}-#3.#3.{#1}#2% +}% +\def\XINT_trunc_H #1.#2.% +{% + \ifnum #1 > \xint_c_ + \xint_afterfi {\XINT_trunc_Ha {#2}}% + \else + \xint_afterfi {\XINT_trunc_Hb {-#1}}% -0,--1,--2, .... + \fi +}% +\def\XINT_trunc_Ha{\expandafter\XINT_trunc_Haa\romannumeral0\xintdecsplit}% +\def\XINT_trunc_Haa #1#2#3{#3#1.#2}% +\def\XINT_trunc_Hb #1#2#3% +{% + \expandafter #3\expandafter0\expandafter.% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \romannumeral\xintreplicate{#1}0#2% +}% +% \end{macrocode} +% \subsection{\csh{xintTTrunc}} +% \lverb|1.1. Modified in 1.2i, it does simply \xintiTrunc0 with no +% shortcut (the latter having been modified) +%| +% \begin{macrocode} +\def\xintTTrunc {\romannumeral0\xintttrunc }% +\def\xintttrunc {\xintitrunc\xint_c_}% +% \end{macrocode} +% \subsection{\cshnolabel{xintNum}} +% \begin{macrocode} +\let\xintnum \xintttrunc +% \end{macrocode} +% \subsection{\csh{xintRound}, \csh{xintiRound}} +% \lverb|Modified in 1.2i. +% +% It benefits first of all from the faster \xintTrunc, particularly when the +% input is already a decimal number (denominator B=1). +% +% And the rounding is now done in 1.2 style (with much delay, sorry), like of +% the rewritten \xintInc and \xintDec.| +% \begin{macrocode} +\def\xintRound {\romannumeral0\xintround }% +\def\xintiRound {\romannumeral0\xintiround }% +\def\xintround #1{\expandafter\XINT_round\the\numexpr #1.\XINT_round_A}% +\def\xintiround #1{\expandafter\XINT_round\the\numexpr #1.\XINT_iround_A}% +\def\XINT_round #1.{\expandafter\XINT_round_aa\the\numexpr #1+\xint_c_i.#1.}% +\def\XINT_round_aa #1.#2.#3#4% +{% + \expandafter\XINT_round_a\romannumeral0\XINT_infrac{#4}#1.#3#2.% +}% +\def\XINT_round_a #1#2#3#4.% +{% + \if0\XINT_Sgn#2\xint:\xint_dothis\XINT_trunc_zero\fi + \if1\XINT_is_One#3XY\xint_dothis\XINT_trunc_sp_b\fi + \xint_orthat\XINT_trunc_b #1+#4.{#2}{#3}% +}% +\def\XINT_round_A{\expandafter\XINT_trunc_G\romannumeral0\XINT_round_B}% +\def\XINT_iround_A{\expandafter\XINT_itrunc_G\romannumeral0\XINT_round_B}% +\def\XINT_round_B #1.% + {\XINT_dsrr #1\xint_bye\xint_Bye3456789\xint_bye/\xint_c_x\relax.}% +% \end{macrocode} +% \subsection{\csh{xintXTrunc}} +% \lverb@1.09j [2014/01/06] This is completely expandable but not f-expandable. +% Rewritten for 1.2i (2016/12/04): +% +% - no more use of \xintiloop from xinttools.sty +% (replaced by \xintreplicate... from xintkernel.sty), +% +% - no more use in 0>N>-D case of a dummy control sequence name via +% \csname...\endcsname +% +% - handles better the case of an input already a decimal number +% +% Need to transfer code comments into public dtx. +% @ +% \begin{macrocode} +\def\xintXTrunc #1%#2% +{% + \expandafter\XINT_xtrunc_a + \the\numexpr #1\expandafter.\romannumeral0\xintraw +}% +\def\XINT_xtrunc_a #1.% ?? faire autre chose +{% + \expandafter\XINT_xtrunc_b\the\numexpr\ifnum#1<\xint_c_i \xint_c_i-\fi #1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_b #1.#2{\XINT_xtrunc_c #2{#1}}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_c #1% +{% + \xint_UDzerominusfork + #1-\XINT_xtrunc_zero + 0#1{-\XINT_xtrunc_d {}}% + 0-{\XINT_xtrunc_d #1}% + \krof +}%[ +\def\XINT_xtrunc_zero #1#2]{0.\romannumeral\xintreplicate{#1}0}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_d #1#2#3/#4[#5]% +{% + \XINT_xtrunc_prepare_a#4\R\R\R\R\R\R\R\R {10}0000001\W + !{#4};{#5}{#2}{#1#3}% +}% +\def\XINT_xtrunc_prepare_a #1#2#3#4#5#6#7#8#9% +{% + \xint_gob_til_R #9\XINT_xtrunc_prepare_small\R + \XINT_xtrunc_prepare_b #9% +}% +\def\XINT_xtrunc_prepare_small\R #1!#2;% +{% + \ifcase #2 + \or\expandafter\XINT_xtrunc_BisOne + \or\expandafter\XINT_xtrunc_BisTwo + \or + \or\expandafter\XINT_xtrunc_BisFour + \or\expandafter\XINT_xtrunc_BisFive + \or + \or + \or\expandafter\XINT_xtrunc_BisEight + \fi\XINT_xtrunc_BisSmall {#2}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_BisOne\XINT_xtrunc_BisSmall #1#2#3#4% + {\XINT_xtrunc_sp_e {#2}{#4}{#3}}% +\def\XINT_xtrunc_BisTwo\XINT_xtrunc_BisSmall #1#2#3#4% +{% + \expandafter\XINT_xtrunc_sp_e\expandafter + {\the\numexpr #2-\xint_c_i\expandafter}\expandafter + {\romannumeral0\xintiimul 5{#4}}{#3}% +}% +\def\XINT_xtrunc_BisFour\XINT_xtrunc_BisSmall #1#2#3#4% +{% + \expandafter\XINT_xtrunc_sp_e\expandafter + {\the\numexpr #2-\xint_c_ii\expandafter}\expandafter + {\romannumeral0\xintiimul {25}{#4}}{#3}% +}% +\def\XINT_xtrunc_BisFive\XINT_xtrunc_BisSmall #1#2#3#4% +{% + \expandafter\XINT_xtrunc_sp_e\expandafter + {\the\numexpr #2-\xint_c_i\expandafter}\expandafter + {\romannumeral0\xintdouble {#4}}{#3}% +}% +\def\XINT_xtrunc_BisEight\XINT_xtrunc_BisSmall #1#2#3#4% +{% + \expandafter\XINT_xtrunc_sp_e\expandafter + {\the\numexpr #2-\xint_c_iii\expandafter}\expandafter + {\romannumeral0\xintiimul {125}{#4}}{#3}% +}% +\def\XINT_xtrunc_BisSmall #1% +{% + \expandafter\XINT_xtrunc_e\expandafter + {\expandafter\XINT_xtrunc_small_a + \the\numexpr #1/\xint_c_ii\expandafter + .\the\numexpr \xint_c_x^viii+#1!}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_small_a #1.#2!#3% +{% + \expandafter\XINT_div_small_b\the\numexpr #1\expandafter + \xint:\the\numexpr #2\expandafter!% + \romannumeral0\XINT_div_small_ba #3\R\R\R\R\R\R\R\R{10}0000001\W + #3\XINT_sepbyviii_Z_end 2345678\relax +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_prepare_b + {\expandafter\XINT_xtrunc_prepare_c\romannumeral0\XINT_zeroes_forviii }% +\def\XINT_xtrunc_prepare_c #1!% +{% + \XINT_xtrunc_prepare_d #1.00000000!{#1}% +}% +\def\XINT_xtrunc_prepare_d #1#2#3#4#5#6#7#8#9% +{% + \expandafter\XINT_xtrunc_prepare_e + \xint_gob_til_dot #1#2#3#4#5#6#7#8#9!% +}% +\def\XINT_xtrunc_prepare_e #1!#2!#3#4% +{% + \XINT_xtrunc_prepare_f #4#3\X {#1}{#3}% +}% +\def\XINT_xtrunc_prepare_f #1#2#3#4#5#6#7#8#9\X +{% + \expandafter\XINT_xtrunc_prepare_g\expandafter + \XINT_div_prepare_g + \the\numexpr #1#2#3#4#5#6#7#8+\xint_c_i\expandafter + \xint:\the\numexpr (#1#2#3#4#5#6#7#8+\xint_c_i)/\xint_c_ii\expandafter + \xint:\the\numexpr #1#2#3#4#5#6#7#8\expandafter + \xint:\romannumeral0\XINT_sepandrev_andcount + #1#2#3#4#5#6#7#8#9\XINT_rsepbyviii_end_A 2345678% + \XINT_rsepbyviii_end_B 2345678\relax\xint_c_ii\xint_c_i + \R\xint:\xint_c_xii \R\xint:\xint_c_x \R\xint:\xint_c_viii \R\xint:\xint_c_vi + \R\xint:\xint_c_iv \R\xint:\xint_c_ii \R\xint:\xint_c_\W + \X +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_prepare_g #1;{\XINT_xtrunc_e {#1}}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_e #1#2% +{% + \ifnum #2<\xint_c_ + \expandafter\XINT_xtrunc_I + \else + \expandafter\XINT_xtrunc_II + \fi #2\xint:{#1}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_I -#1\xint:#2#3#4% +{% + \expandafter\XINT_xtrunc_I_a\romannumeral0#2{#4}{#2}{#1}{#3}% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_I_a #1#2#3#4#5% +{% + \expandafter\XINT_xtrunc_I_b\the\numexpr #4-#5\xint:#4\xint:{#5}{#2}{#3}{#1}% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_I_b #1% +{% + \xint_UDsignfork + #1\XINT_xtrunc_IA_c + -\XINT_xtrunc_IB_c + \krof #1% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_IA_c -#1\xint:#2\xint:#3#4#5#6% +{% + \expandafter\XINT_xtrunc_IA_d + \the\numexpr#2-\xintLength{#6}\xint:{#6}% + \expandafter\XINT_xtrunc_IA_xd + \the\numexpr (#1+\xint_c_ii^v)/\xint_c_ii^vi-\xint_c_i\xint:#1\xint:{#5}{#4}% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_IA_d #1% +{% + \xint_UDsignfork + #1\XINT_xtrunc_IAA_e + -\XINT_xtrunc_IAB_e + \krof #1% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_IAA_e -#1\xint:#2% +{% + \romannumeral0\XINT_split_fromleft + #1.#2\xint_gobble_i\xint_bye2345678\xint_bye..% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_IAB_e #1\xint:#2% +{% + 0.\romannumeral\XINT_rep#1\endcsname0#2% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_IA_xd #1\xint:#2\xint:% +{% + \expandafter\XINT_xtrunc_IA_xe\the\numexpr #2-\xint_c_ii^vi*#1\xint:#1\xint:% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_IA_xe #1\xint:#2\xint:#3#4% +{% + \XINT_xtrunc_loop {#2}{#4}{#3}{#1}% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_IB_c #1\xint:#2\xint:#3#4#5#6% +{% + \expandafter\XINT_xtrunc_IB_d + \romannumeral0\XINT_split_xfork #1.#6\xint_bye2345678\xint_bye..{#3}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_IB_d #1.#2.#3% +{% + \expandafter\XINT_xtrunc_IA_d\the\numexpr#3-\xintLength {#1}\xint:{#1}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_II #1\xint:% +{% + \expandafter\XINT_xtrunc_II_a\romannumeral\xintreplicate{#1}0\xint:% +}% +\def\XINT_xtrunc_II_a #1\xint:#2#3#4% +{% + \expandafter\XINT_xtrunc_II_b + \the\numexpr (#3+\xint_c_ii^v)/\xint_c_ii^vi-\xint_c_i\expandafter\xint:% + \the\numexpr #3\expandafter\xint:\romannumeral0#2{#4#1}{#2}% +}% +\def\XINT_xtrunc_II_b #1\xint:#2\xint:% +{% + \expandafter\XINT_xtrunc_II_c\the\numexpr #2-\xint_c_ii^vi*#1\xint:#1\xint:% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_II_c #1\xint:#2\xint:#3#4#5% +{% + #3.\XINT_xtrunc_loop {#2}{#4}{#5}{#1}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_loop #1% +{% + \ifnum #1=\xint_c_ \expandafter\XINT_xtrunc_transition\fi + \expandafter\XINT_xtrunc_loop_a\the\numexpr #1-\xint_c_i\xint:% +}% +\def\XINT_xtrunc_loop_a #1\xint:#2#3% +{% + \expandafter\XINT_xtrunc_loop_b\romannumeral0#3% + {#20000000000000000000000000000000000000000000000000000000000000000}% + {#1}{#3}% +}% +\def\XINT_xtrunc_loop_b #1#2#3% +{% + \romannumeral\xintreplicate{\xint_c_ii^vi-\xintLength{#1}}0#1% + \XINT_xtrunc_loop {#3}{#2}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_transition + \expandafter\XINT_xtrunc_loop_a\the\numexpr #1\xint:#2#3#4% +{% + \ifnum #4=\xint_c_ \expandafter\xint_gobble_vi\fi + \expandafter\XINT_xtrunc_finish\expandafter + {\romannumeral0\XINT_dsx_addzeros{#4}#2;}{#3}{#4}% +}% +\def\XINT_xtrunc_finish #1#2% +{% + \expandafter\XINT_xtrunc_finish_a\romannumeral0#2{#1}% +}% +\def\XINT_xtrunc_finish_a #1#2#3% +{% + \romannumeral\xintreplicate{#3-\xintLength{#1}}0#1% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_sp_e #1% +{% + \ifnum #1<\xint_c_ + \expandafter\XINT_xtrunc_sp_I + \else + \expandafter\XINT_xtrunc_sp_II + \fi #1\xint:% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_sp_I -#1\xint:#2#3% +{% + \expandafter\XINT_xtrunc_sp_I_a\the\numexpr #1-#3\xint:#1\xint:{#3}{#2}% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_sp_I_a #1% +{% + \xint_UDsignfork + #1\XINT_xtrunc_sp_IA_b + -\XINT_xtrunc_sp_IB_b + \krof #1% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_sp_IA_b -#1\xint:#2\xint:#3#4% +{% + \expandafter\XINT_xtrunc_sp_IA_c + \the\numexpr#2-\xintLength{#4}\xint:{#4}\romannumeral\XINT_rep#1\endcsname0% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_sp_IA_c #1% +{% + \xint_UDsignfork + #1\XINT_xtrunc_sp_IAA + -\XINT_xtrunc_sp_IAB + \krof #1% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_sp_IAA -#1\xint:#2% +{% + \romannumeral0\XINT_split_fromleft + #1.#2\xint_gobble_i\xint_bye2345678\xint_bye..% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_sp_IAB #1\xint:#2% +{% + 0.\romannumeral\XINT_rep#1\endcsname0#2% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_sp_IB_b #1\xint:#2\xint:#3#4% +{% + \expandafter\XINT_xtrunc_sp_IB_c + \romannumeral0\XINT_split_xfork #1.#4\xint_bye2345678\xint_bye..{#3}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_xtrunc_sp_IB_c #1.#2.#3% +{% + \expandafter\XINT_xtrunc_sp_IA_c\the\numexpr#3-\xintLength {#1}\xint:{#1}% +}% +% \end{macrocode} +% \lverb@& +% @ +% \begin{macrocode} +\def\XINT_xtrunc_sp_II #1\xint:#2#3% +{% + #2\romannumeral\XINT_rep#1\endcsname0.\romannumeral\XINT_rep#3\endcsname0% +}% +% \end{macrocode} +% \subsection{\csh{xintDigits}} +% \lverb|The mathchardef used to be called \XINT_digits, but for reasons +% originating in \xintNewExpr (and now obsolete), release 1.09a uses +% \XINTdigits without underscore.| +% \begin{macrocode} +\mathchardef\XINTdigits 16 +\def\xintDigits #1#2% + {\afterassignment \xint_gobble_i \mathchardef\XINTdigits=}% +\def\xinttheDigits {\number\XINTdigits }% +% \end{macrocode} +% \subsection{\csh{xintAdd}} +% \lverb|Big change at 1.3: a/b+c/d uses lcm(b,d) as denominator.| +% \begin{macrocode} +\def\xintAdd {\romannumeral0\xintadd }% +\def\xintadd #1{\expandafter\XINT_fadd\romannumeral0\xintraw {#1}}% +\def\XINT_fadd #1{\xint_gob_til_zero #1\XINT_fadd_Azero 0\XINT_fadd_a #1}% +\def\XINT_fadd_Azero #1]{\xintraw }% +\def\XINT_fadd_a #1/#2[#3]#4% + {\expandafter\XINT_fadd_b\romannumeral0\xintraw {#4}{#3}{#1}{#2}}% +\def\XINT_fadd_b #1{\xint_gob_til_zero #1\XINT_fadd_Bzero 0\XINT_fadd_c #1}% +\def\XINT_fadd_Bzero #1]#2#3#4{ #3/#4[#2]}% +\def\XINT_fadd_c #1/#2[#3]#4% +{% + \expandafter\XINT_fadd_Aa\the\numexpr #4-#3.{#3}{#4}{#1}{#2}% +}% +\def\XINT_fadd_Aa #1% +{% + \xint_UDzerominusfork + #1-\XINT_fadd_B + 0#1\XINT_fadd_Bb + 0-\XINT_fadd_Ba + \krof #1% +}% +\def\XINT_fadd_B #1.#2#3#4#5#6#7{\XINT_fadd_C {#4}{#5}{#7}{#6}[#3]}% +\def\XINT_fadd_Ba #1.#2#3#4#5#6#7% +{% + \expandafter\XINT_fadd_C\expandafter + {\romannumeral0\XINT_dsx_addzeros {#1}#6;}% + {#7}{#5}{#4}[#2]% +}% +\def\XINT_fadd_Bb -#1.#2#3#4#5#6#7% +{% + \expandafter\XINT_fadd_C\expandafter + {\romannumeral0\XINT_dsx_addzeros {#1}#4;}% + {#5}{#7}{#6}[#3]% +}% +\def\XINT_fadd_iszero #1[#2]{ 0/1[0]}% ou [#2] originel? +\def\XINT_fadd_C #1#2#3% +{% + \expandafter\XINT_fadd_D_b + \romannumeral0\XINT_div_prepare{#2}{#3}{#2}{#2}{#3}{#1}% +}% +% \end{macrocode} +% \lverb|Basically a clone of the \XINT_irr_loop_a loop. I should modify the +% output of \XINT_div_prepare perhaps to be optimized for checking if +% remainder vanishes.| +% \begin{macrocode} +\def\XINT_fadd_D_a #1#2% +{% + \expandafter\XINT_fadd_D_b + \romannumeral0\XINT_div_prepare {#1}{#2}{#1}% +}% +\def\XINT_fadd_D_b #1#2{\XINT_fadd_D_c #2\Z}% +\def\XINT_fadd_D_c #1#2\Z +{% + \xint_gob_til_zero #1\XINT_fadd_D_exit0\XINT_fadd_D_a {#1#2}% +}% +\def\XINT_fadd_D_exit0\XINT_fadd_D_a #1#2#3% +{% + \expandafter\XINT_fadd_E + \romannumeral0\xintiiquo {#3}{#2}.{#2}% +}% +\def\XINT_fadd_E #1.#2#3% +{% + \expandafter\XINT_fadd_F + \romannumeral0\xintiimul{#1}{#3}.{\xintiiQuo{#3}{#2}}{#1}% +}% +\def\XINT_fadd_F #1.#2#3#4#5% +{% + \expandafter\XINT_fadd_G + \romannumeral0\xintiiadd{\xintiiMul{#2}{#4}}{\xintiiMul{#3}{#5}}/#1% +}% +\def\XINT_fadd_G #1{% +\def\XINT_fadd_G ##1{\if0##1\expandafter\XINT_fadd_iszero\fi#1##1}% +}\XINT_fadd_G{ }% +% \end{macrocode} +% \subsection{\csh{xintSub}} +% \lverb|Since 1.3 will use least common multiple of denominators.| +% \begin{macrocode} +\def\xintSub {\romannumeral0\xintsub }% +\def\xintsub #1{\expandafter\XINT_fsub\romannumeral0\xintraw {#1}}% +\def\XINT_fsub #1{\xint_gob_til_zero #1\XINT_fsub_Azero 0\XINT_fsub_a #1}% +\def\XINT_fsub_Azero #1]{\xintopp }% +\def\XINT_fsub_a #1/#2[#3]#4% + {\expandafter\XINT_fsub_b\romannumeral0\xintraw {#4}{#3}{#1}{#2}}% +\def\XINT_fsub_b #1{\xint_UDzerominusfork + #1-\XINT_fadd_Bzero + 0#1\XINT_fadd_c + 0-{\XINT_fadd_c -#1}% + \krof }% +% \end{macrocode} +% \subsection{\csh{xintSum}} +% \lverb|There was (not documented anymore since 1.09d, 2013/10/22) a macro +% \xintSumExpr, but it has been deleted at 1.2l. +% +% Empty items are not accepted by this macro.| +% \begin{macrocode} +\def\xintSum {\romannumeral0\xintsum }% +\def\xintsum #1{\expandafter\XINT_fsumexpr\romannumeral`&&@#1\xint:}% +\def\XINT_fsumexpr {\XINT_fsum_loop_a {0/1[0]}}% +\def\XINT_fsum_loop_a #1#2% +{% + \expandafter\XINT_fsum_loop_b \romannumeral`&&@#2\xint:{#1}% +}% +\def\XINT_fsum_loop_b #1% +{% + \xint_gob_til_xint: #1\XINT_fsum_finished\xint:\XINT_fsum_loop_c #1% +}% +\def\XINT_fsum_loop_c #1\xint:#2% +{% + \expandafter\XINT_fsum_loop_a\expandafter{\romannumeral0\xintadd {#2}{#1}}% +}% +\def\XINT_fsum_finished #1\xint:\xint:#2{ #2}% +% \end{macrocode} +% \subsection{\csh{xintMul}} +% \begin{macrocode} +\def\xintMul {\romannumeral0\xintmul }% +\def\xintmul #1{\expandafter\XINT_fmul\romannumeral0\xintraw {#1}.}% +\def\XINT_fmul #1{\xint_gob_til_zero #1\XINT_fmul_zero 0\XINT_fmul_a #1}% +\def\XINT_fmul_a #1[#2].#3% + {\expandafter\XINT_fmul_b\romannumeral0\xintraw {#3}#1[#2.]}% +\def\XINT_fmul_b #1{\xint_gob_til_zero #1\XINT_fmul_zero 0\XINT_fmul_c #1}% +\def\XINT_fmul_c #1/#2[#3]#4/#5[#6.]% +{% + \expandafter\XINT_fmul_d + \expandafter{\the\numexpr #3+#6\expandafter}% + \expandafter{\romannumeral0\xintiimul {#5}{#2}}% + {\romannumeral0\xintiimul {#4}{#1}}% +}% +\def\XINT_fmul_d #1#2#3% +{% + \expandafter \XINT_fmul_e \expandafter{#3}{#1}{#2}% +}% +\def\XINT_fmul_e #1#2{\XINT_outfrac {#2}{#1}}% +\def\XINT_fmul_zero #1.#2{ 0/1[0]}% +% \end{macrocode} +% \subsection{\csh{xintSqr}} +% \lverb|1.1 modifs comme xintMul. +% +% | +% \begin{macrocode} +\def\xintSqr {\romannumeral0\xintsqr }% +\def\xintsqr #1{\expandafter\XINT_fsqr\romannumeral0\xintraw {#1}}% +\def\XINT_fsqr #1{\xint_gob_til_zero #1\XINT_fsqr_zero 0\XINT_fsqr_a #1}% +\def\XINT_fsqr_a #1/#2[#3]% +{% + \expandafter\XINT_fsqr_b + \expandafter{\the\numexpr #3+#3\expandafter}% + \expandafter{\romannumeral0\xintiisqr {#2}}% + {\romannumeral0\xintiisqr {#1}}% +}% +\def\XINT_fsqr_b #1#2#3{\expandafter \XINT_fmul_e \expandafter{#3}{#1}{#2}}% +\def\XINT_fsqr_zero #1]{ 0/1[0]}% +% \end{macrocode} +% \subsection{\csh{xintPow}} +% \lverb|& +% 1.2f: to be coherent with the "i" convention \xintiPow should parse also its +% exponent via \xintNum when xintfrac.sty is loaded. This was not the case so +% far. Cependant le problème est que le fait d'appliquer \xintNum rend +% impossible certains inputs qui auraient pu être gérès par \numexpr. Le +% \numexpr externe est ici pour intercepter trop grand input. +% | +% \begin{macrocode} +\def\xintipow #1#2% +{% + \expandafter\xint_pow\the\numexpr \xintNum{#2}\expandafter + .\romannumeral0\xintnum{#1}\xint: +}% +\def\xintPow {\romannumeral0\xintpow }% +\def\xintpow #1% +{% + \expandafter\XINT_fpow\expandafter {\romannumeral0\XINT_infrac {#1}}% +}% +\def\XINT_fpow #1#2% +{% + \expandafter\XINT_fpow_fork\the\numexpr \xintNum{#2}\relax\Z #1% +}% +\def\XINT_fpow_fork #1#2\Z +{% + \xint_UDzerominusfork + #1-\XINT_fpow_zero + 0#1\XINT_fpow_neg + 0-{\XINT_fpow_pos #1}% + \krof + {#2}% +}% +\def\XINT_fpow_zero #1#2#3#4{ 1/1[0]}% +\def\XINT_fpow_pos #1#2#3#4#5% +{% + \expandafter\XINT_fpow_pos_A\expandafter + {\the\numexpr #1#2*#3\expandafter}\expandafter + {\romannumeral0\xintiipow {#5}{#1#2}}% + {\romannumeral0\xintiipow {#4}{#1#2}}% +}% +\def\XINT_fpow_neg #1#2#3#4% +{% + \expandafter\XINT_fpow_pos_A\expandafter + {\the\numexpr -#1*#2\expandafter}\expandafter + {\romannumeral0\xintiipow {#3}{#1}}% + {\romannumeral0\xintiipow {#4}{#1}}% +}% +\def\XINT_fpow_pos_A #1#2#3% +{% + \expandafter\XINT_fpow_pos_B\expandafter {#3}{#1}{#2}% +}% +\def\XINT_fpow_pos_B #1#2{\XINT_outfrac {#2}{#1}}% +% \end{macrocode} +% \subsection{\csh{xintFac}} +% \lverb|Factorial coefficients: variant which can be chained with other +% xintfrac macros. \xintiFac deprecated at 1.2o and removed at 1.3; \xintFac +% used by xintexpr.sty.| +% \begin{macrocode} +\def\xintFac {\romannumeral0\xintfac}% +\def\xintfac #1{\expandafter\XINT_fac_fork\the\numexpr\xintNum{#1}.[0]}% +% \end{macrocode} +% \subsection{\csh{xintBinomial}} +% \lverb|1.2f. Binomial coefficients. \xintiBinomial deprecated at 1.2o and +% removed at 1.3; +% \xintBinomial needed by xintexpr.sty.| +% \begin{macrocode} +\def\xintBinomial {\romannumeral0\xintbinomial}% +\def\xintbinomial #1#2% +{% + \expandafter\XINT_binom_pre + \the\numexpr\xintNum{#1}\expandafter.\the\numexpr\xintNum{#2}.[0]% +}% +% \end{macrocode} +% \subsection{\csh{xintPFactorial}} +% \lverb|1.2f. Partial factorial. For needs of xintexpr.sty.| +% \begin{macrocode} +\def\xintipfactorial #1#2% +{% + \expandafter\XINT_pfac_fork + \the\numexpr\xintNum{#1}\expandafter.\the\numexpr\xintNum{#2}.% +}% +\def\xintPFactorial {\romannumeral0\xintpfactorial}% +\def\xintpfactorial #1#2% +{% + \expandafter\XINT_pfac_fork + \the\numexpr\xintNum{#1}\expandafter.\the\numexpr\xintNum{#2}.[0]% +}% +% \end{macrocode} +% \subsection{\csh{xintPrd}} +% \lverb|There was (not documented anymore since 1.09d, 2013/10/22) a macro +% \xintPrdExpr, but it has been deleted at 1.2l +% | +% \begin{macrocode} +\def\xintPrd {\romannumeral0\xintprd }% +\def\xintprd #1{\expandafter\XINT_fprdexpr \romannumeral`&&@#1\xint:}% +\def\XINT_fprdexpr {\XINT_fprod_loop_a {1/1[0]}}% +\def\XINT_fprod_loop_a #1#2% +{% + \expandafter\XINT_fprod_loop_b \romannumeral`&&@#2\xint:{#1}% +}% +\def\XINT_fprod_loop_b #1% +{% + \xint_gob_til_xint: #1\XINT_fprod_finished\xint:\XINT_fprod_loop_c #1% +}% +\def\XINT_fprod_loop_c #1\xint:#2% +{% + \expandafter\XINT_fprod_loop_a\expandafter{\romannumeral0\xintmul {#1}{#2}}% +}% +\def\XINT_fprod_finished#1\xint:\xint:#2{ #2}% +% \end{macrocode} +% \subsection{\csh{xintDiv}} +% \begin{macrocode} +\def\xintDiv {\romannumeral0\xintdiv }% +\def\xintdiv #1% +{% + \expandafter\XINT_fdiv\expandafter {\romannumeral0\XINT_infrac {#1}}% +}% +\def\XINT_fdiv #1#2% + {\expandafter\XINT_fdiv_A\romannumeral0\XINT_infrac {#2}#1}% +\def\XINT_fdiv_A #1#2#3#4#5#6% +{% + \expandafter\XINT_fdiv_B + \expandafter{\the\numexpr #4-#1\expandafter}% + \expandafter{\romannumeral0\xintiimul {#2}{#6}}% + {\romannumeral0\xintiimul {#3}{#5}}% +}% +\def\XINT_fdiv_B #1#2#3% +{% + \expandafter\XINT_fdiv_C + \expandafter{#3}{#1}{#2}% +}% +\def\XINT_fdiv_C #1#2{\XINT_outfrac {#2}{#1}}% +% \end{macrocode} +% \subsection{\csh{xintDivFloor}} +% \lverb|1.1. Changed at 1.2p to not append /1[0] ending but rather output a +% big integer in strict format, like \xintDivTrunc and \xintDivRound.| +% \begin{macrocode} +\def\xintDivFloor {\romannumeral0\xintdivfloor }% +\def\xintdivfloor #1#2{\xintifloor{\xintDiv {#1}{#2}}}% +% \end{macrocode} +% \subsection{\csh{xintDivTrunc}} +% \lverb|1.1. \xintttrunc rather than \xintitrunc0 in 1.1a| +% \begin{macrocode} +\def\xintDivTrunc {\romannumeral0\xintdivtrunc }% +\def\xintdivtrunc #1#2{\xintttrunc {\xintDiv {#1}{#2}}}% +% \end{macrocode} +% \subsection{\csh{xintDivRound}} +% \lverb|1.1| +% \begin{macrocode} +\def\xintDivRound {\romannumeral0\xintdivround }% +\def\xintdivround #1#2{\xintiround 0{\xintDiv {#1}{#2}}}% +% \end{macrocode} +% \subsection{\csh{xintModTrunc}} +% \lverb|1.1. \xintModTrunc {q1}{q2} computes q1 - q2*t(q1/q2) with t(q1/q2) +% equal to the truncated division of two fractions q1 and q2. +% +% Its former name, prior to 1.2p, was \xintMod. +% +% At 1.3, uses least common multiple denominator, like \xintMod (next).| +% \begin{macrocode} +\def\xintModTrunc {\romannumeral0\xintmodtrunc }% +\def\xintmodtrunc #1{\expandafter\XINT_modtrunc_a\romannumeral0\xintraw{#1}.}% +\def\XINT_modtrunc_a #1#2.#3% + {\expandafter\XINT_modtrunc_b\expandafter #1\romannumeral0\xintraw{#3}#2.}% +\def\XINT_modtrunc_b #1#2% #1 de A, #2 de B. +{% + \if0#2\xint_dothis{\XINT_modtrunc_divbyzero #1#2}\fi + \if0#1\xint_dothis\XINT_modtrunc_aiszero\fi + \if-#2\xint_dothis{\XINT_modtrunc_bneg #1}\fi + \xint_orthat{\XINT_modtrunc_bpos #1#2}% +}% +\def\XINT_modtrunc_divbyzero #1#2[#3]#4.% +{% + \XINT_signalcondition{DivisionByZero}{Division by #2[#3] of #1#4}{}{0/1[0]}% +}% +\def\XINT_modtrunc_aiszero #1.{ 0/1[0]}% +\def\XINT_modtrunc_bneg #1% +{% + \xint_UDsignfork + #1{\xintiiopp\XINT_modtrunc_pos {}}% + -{\XINT_modtrunc_pos #1}% + \krof +}% +\def\XINT_modtrunc_bpos #1% +{% + \xint_UDsignfork + #1{\xintiiopp\XINT_modtrunc_pos {}}% + -{\XINT_modtrunc_pos #1}% + \krof +}% +% \end{macrocode} +% \lverb|Attention. This crucially uses that xint's \xintiiE{x}{e} is defined +% to return x unchanged if e is negative (and x extended by e zeroes if e >= +% 0).| +% \begin{macrocode} +\def\XINT_modtrunc_pos #1#2/#3[#4]#5/#6[#7].% +{% + \expandafter\XINT_modtrunc_pos_a + \the\numexpr\ifnum#7>#4 #4\else #7\fi\expandafter.% + \romannumeral0\expandafter\XINT_mod_D_b + \romannumeral0\XINT_div_prepare{#3}{#6}{#3}{#3}{#6}% + {#1#5}{#7-#4}{#2}{#4-#7}% +}% +\def\XINT_modtrunc_pos_a #1.#2#3#4{\xintiirem {#3}{#4}/#2[#1]}% +% \end{macrocode} +% \subsection{\csh{xintDivMod}} +% \lverb|1.2p. \xintDivMod{q1}{q2} outputs {floor(q1/q2)}{q1 - q2*floor(q1/q2)}. +% Attention that it relies on \xintiiE{x}{e} returning x if e < 0. +% +% Modified (like \xintAdd and \xintSub) at 1.3 to use a l.c.m for final +% denominator of the "mod" part.| +% \begin{macrocode} +\def\xintDivMod {\romannumeral0\xintdivmod }% +\def\xintdivmod #1{\expandafter\XINT_divmod_a\romannumeral0\xintraw{#1}.}% +\def\XINT_divmod_a #1#2.#3% + {\expandafter\XINT_divmod_b\expandafter #1\romannumeral0\xintraw{#3}#2.}% +\def\XINT_divmod_b #1#2% #1 de A, #2 de B. +{% + \if0#2\xint_dothis{\XINT_divmod_divbyzero #1#2}\fi + \if0#1\xint_dothis\XINT_divmod_aiszero\fi + \if-#2\xint_dothis{\XINT_divmod_bneg #1}\fi + \xint_orthat{\XINT_divmod_bpos #1#2}% +}% +\def\XINT_divmod_divbyzero #1#2[#3]#4.% +{% + \XINT_signalcondition{DivisionByZero}{Division by #2[#3] of #1#4}{}% + {{0}{0/1[0]}}% à revoir... +}% +\def\XINT_divmod_aiszero #1.{{0}{0/1[0]}}% +\def\XINT_divmod_bneg #1% f // -g = (-f) // g, f % -g = - ((-f) % g) +{% + \expandafter\XINT_divmod_bneg_finish + \romannumeral0\xint_UDsignfork + #1{\XINT_divmod_bpos {}}% + -{\XINT_divmod_bpos {-#1}}% + \krof +}% +\def\XINT_divmod_bneg_finish#1#2% +{% + \expandafter\xint_exchangetwo_keepbraces\expandafter + {\romannumeral0\xintiiopp#2}{#1}% +}% +\def\XINT_divmod_bpos #1#2/#3[#4]#5/#6[#7].% +{% + \expandafter\XINT_divmod_bpos_a + \the\numexpr\ifnum#7>#4 #4\else #7\fi\expandafter.% + \romannumeral0\expandafter\XINT_mod_D_b + \romannumeral0\XINT_div_prepare{#3}{#6}{#3}{#3}{#6}% + {#1#5}{#7-#4}{#2}{#4-#7}% +}% +\def\XINT_divmod_bpos_a #1.#2#3#4% +{% + \expandafter\XINT_divmod_bpos_finish + \romannumeral0\xintiidivision{#3}{#4}{/#2[#1]}% +}% +\def\XINT_divmod_bpos_finish #1#2#3{{#1}{#2#3}}% +% \end{macrocode} +% \subsection{\csh{xintMod}} +% \lverb|1.2p. \xintMod{q1}{q2} computes q1 - q2*floor(q1/q2). Attention that +% it relies on \xintiiE{x}{e} returning x if e < 0. +% +% Prior to 1.2p, that macro had the meaning now attributed to \xintModTrunc. +% +% Modified (like \xintAdd and \xintSub) at 1.3 to use a l.c.m for final +% denominator.| +% \begin{macrocode} +\def\xintMod {\romannumeral0\xintmod }% +\def\xintmod #1{\expandafter\XINT_mod_a\romannumeral0\xintraw{#1}.}% +\def\XINT_mod_a #1#2.#3% + {\expandafter\XINT_mod_b\expandafter #1\romannumeral0\xintraw{#3}#2.}% +\def\XINT_mod_b #1#2% #1 de A, #2 de B. +{% + \if0#2\xint_dothis{\XINT_mod_divbyzero #1#2}\fi + \if0#1\xint_dothis\XINT_mod_aiszero\fi + \if-#2\xint_dothis{\XINT_mod_bneg #1}\fi + \xint_orthat{\XINT_mod_bpos #1#2}% +}% +% \end{macrocode} +% \lverb|Attention to not move ModTrunc code beyond that point.| +% \begin{macrocode} +\let\XINT_mod_divbyzero\XINT_modtrunc_divbyzero +\let\XINT_mod_aiszero \XINT_modtrunc_aiszero +\def\XINT_mod_bneg #1% f % -g = - ((-f) % g), for g > 0 +{% + \xintiiopp\xint_UDsignfork + #1{\XINT_mod_bpos {}}% + -{\XINT_mod_bpos {-#1}}% + \krof +}% +\def\XINT_mod_bpos #1#2/#3[#4]#5/#6[#7].% +{% + \expandafter\XINT_mod_bpos_a + \the\numexpr\ifnum#7>#4 #4\else #7\fi\expandafter.% + \romannumeral0\expandafter\XINT_mod_D_b + \romannumeral0\XINT_div_prepare{#3}{#6}{#3}{#3}{#6}% + {#1#5}{#7-#4}{#2}{#4-#7}% +}% +\def\XINT_mod_D_a #1#2% +{% + \expandafter\XINT_mod_D_b + \romannumeral0\XINT_div_prepare {#1}{#2}{#1}% +}% +\def\XINT_mod_D_b #1#2{\XINT_mod_D_c #2\Z}% +\def\XINT_mod_D_c #1#2\Z +{% + \xint_gob_til_zero #1\XINT_mod_D_exit0\XINT_mod_D_a {#1#2}% +}% +\def\XINT_mod_D_exit0\XINT_mod_D_a #1#2#3% +{% + \expandafter\XINT_mod_E + \romannumeral0\xintiiquo {#3}{#2}.{#2}% +}% +\def\XINT_mod_E #1.#2#3% +{% + \expandafter\XINT_mod_F + \romannumeral0\xintiimul{#1}{#3}.{\xintiiQuo{#3}{#2}}{#1}% +}% +\def\XINT_mod_F #1.#2#3#4#5#6#7% +{% + {#1}{\xintiiE{\xintiiMul{#4}{#3}}{#5}}% + {\xintiiE{\xintiiMul{#6}{#2}}{#7}}% +}% +\def\XINT_mod_bpos_a #1.#2#3#4{\xintiirem {#3}{#4}/#2[#1]}% +% \end{macrocode} +% \subsection{\csh{xintIsOne}} +% \lverb|New with 1.09a. Could be more efficient. For fractions with big +% powers of tens, it is better to use \xintCmp{f}{1}. Restyled in 1.09i.| +% \begin{macrocode} +\def\xintIsOne {\romannumeral0\xintisone }% +\def\xintisone #1{\expandafter\XINT_fracisone + \romannumeral0\xintrawwithzeros{#1}\Z }% +\def\XINT_fracisone #1/#2\Z + {\if0\xintiiCmp {#1}{#2}\xint_afterfi{ 1}\else\xint_afterfi{ 0}\fi}% +% \end{macrocode} +% \subsection{\csh{xintGeq}} +% \begin{macrocode} +\def\xintGeq {\romannumeral0\xintgeq }% +\def\xintgeq #1% +{% + \expandafter\XINT_fgeq\expandafter {\romannumeral0\xintabs {#1}}% +}% +\def\XINT_fgeq #1#2% +{% + \expandafter\XINT_fgeq_A \romannumeral0\xintabs {#2}#1% +}% +\def\XINT_fgeq_A #1% +{% + \xint_gob_til_zero #1\XINT_fgeq_Zii 0% + \XINT_fgeq_B #1% +}% +\def\XINT_fgeq_Zii 0\XINT_fgeq_B #1[#2]#3[#4]{ 1}% +\def\XINT_fgeq_B #1/#2[#3]#4#5/#6[#7]% +{% + \xint_gob_til_zero #4\XINT_fgeq_Zi 0% + \expandafter\XINT_fgeq_C\expandafter + {\the\numexpr #7-#3\expandafter}\expandafter + {\romannumeral0\xintiimul {#4#5}{#2}}% + {\romannumeral0\xintiimul {#6}{#1}}% +}% +\def\XINT_fgeq_Zi 0#1#2#3#4#5#6#7{ 0}% +\def\XINT_fgeq_C #1#2#3% +{% + \expandafter\XINT_fgeq_D\expandafter + {#3}{#1}{#2}% +}% +\def\XINT_fgeq_D #1#2#3% +{% + \expandafter\XINT_cntSgnFork\romannumeral`&&@\expandafter\XINT_cntSgn + \the\numexpr #2+\xintLength{#3}-\xintLength{#1}\relax\xint: + { 0}{\XINT_fgeq_E #2\Z {#3}{#1}}{ 1}% +}% +\def\XINT_fgeq_E #1% +{% + \xint_UDsignfork + #1\XINT_fgeq_Fd + -{\XINT_fgeq_Fn #1}% + \krof +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_fgeq_Fd #1\Z #2#3% +{% + \expandafter\XINT_fgeq_Fe + \romannumeral0\XINT_dsx_addzeros {#1}#3;\xint:#2\xint: +}% +\def\XINT_fgeq_Fe #1\xint:#2#3\xint:{\XINT_geq_plusplus #2#1\xint:#3\xint:}% +\def\XINT_fgeq_Fn #1\Z #2#3% +{% + \expandafter\XINT_fgeq_Fo + \romannumeral0\XINT_dsx_addzeros {#1}#2;\xint:#3\xint: +}% +\def\XINT_fgeq_Fo #1#2\xint:#3\xint:{\XINT_geq_plusplus #1#3\xint:#2\xint:}% +% \end{macrocode} +% \subsection{\csh{xintMax}} +% \begin{macrocode} +\def\xintMax {\romannumeral0\xintmax }% +\def\xintmax #1% +{% + \expandafter\XINT_fmax\expandafter {\romannumeral0\xintraw {#1}}% +}% +\def\XINT_fmax #1#2% +{% + \expandafter\XINT_fmax_A\romannumeral0\xintraw {#2}#1% +}% +\def\XINT_fmax_A #1#2/#3[#4]#5#6/#7[#8]% +{% + \xint_UDsignsfork + #1#5\XINT_fmax_minusminus + -#5\XINT_fmax_firstneg + #1-\XINT_fmax_secondneg + --\XINT_fmax_nonneg_a + \krof + #1#5{#2/#3[#4]}{#6/#7[#8]}% +}% +\def\XINT_fmax_minusminus --% + {\expandafter-\romannumeral0\XINT_fmin_nonneg_b }% +\def\XINT_fmax_firstneg #1-#2#3{ #1#2}% +\def\XINT_fmax_secondneg -#1#2#3{ #1#3}% +\def\XINT_fmax_nonneg_a #1#2#3#4% +{% + \XINT_fmax_nonneg_b {#1#3}{#2#4}% +}% +\def\XINT_fmax_nonneg_b #1#2% +{% + \if0\romannumeral0\XINT_fgeq_A #1#2% + \xint_afterfi{ #1}% + \else \xint_afterfi{ #2}% + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintMaxof}} +% \lverb|1.2l protects \xintMaxof against items with non terminated +% \the\numexpr expressions. +% +% The macro is not compatible with an empty list.| +% \begin{macrocode} +\def\xintMaxof {\romannumeral0\xintmaxof }% +\def\xintmaxof #1{\expandafter\XINT_maxof_a\romannumeral`&&@#1\xint:}% +\def\XINT_maxof_a #1{\expandafter\XINT_maxof_b\romannumeral0\xintraw{#1}!}% +\def\XINT_maxof_b #1!#2% + {\expandafter\XINT_maxof_c\romannumeral`&&@#2!{#1}!}% +\def\XINT_maxof_c #1% + {\xint_gob_til_xint: #1\XINT_maxof_e\xint:\XINT_maxof_d #1}% +\def\XINT_maxof_d #1!% + {\expandafter\XINT_maxof_b\romannumeral0\xintmax {#1}}% +\def\XINT_maxof_e #1!#2!{ #2}% +% \end{macrocode} +% \subsection{\csh{xintMin}} +% \begin{macrocode} +\def\xintMin {\romannumeral0\xintmin }% +\def\xintmin #1% +{% + \expandafter\XINT_fmin\expandafter {\romannumeral0\xintraw {#1}}% +}% +\def\XINT_fmin #1#2% +{% + \expandafter\XINT_fmin_A\romannumeral0\xintraw {#2}#1% +}% +\def\XINT_fmin_A #1#2/#3[#4]#5#6/#7[#8]% +{% + \xint_UDsignsfork + #1#5\XINT_fmin_minusminus + -#5\XINT_fmin_firstneg + #1-\XINT_fmin_secondneg + --\XINT_fmin_nonneg_a + \krof + #1#5{#2/#3[#4]}{#6/#7[#8]}% +}% +\def\XINT_fmin_minusminus --% + {\expandafter-\romannumeral0\XINT_fmax_nonneg_b }% +\def\XINT_fmin_firstneg #1-#2#3{ -#3}% +\def\XINT_fmin_secondneg -#1#2#3{ -#2}% +\def\XINT_fmin_nonneg_a #1#2#3#4% +{% + \XINT_fmin_nonneg_b {#1#3}{#2#4}% +}% +\def\XINT_fmin_nonneg_b #1#2% +{% + \if0\romannumeral0\XINT_fgeq_A #1#2% + \xint_afterfi{ #2}% + \else \xint_afterfi{ #1}% + \fi +}% +% \end{macrocode} +% \subsection{\csh{xintMinof}} +% \lverb|1.2l protects \xintMinof against items with non terminated +% \the\numexpr expressions. +% +% The macro is not compatible with an empty list.| +% \begin{macrocode} +\def\xintMinof {\romannumeral0\xintminof }% +\def\xintminof #1{\expandafter\XINT_minof_a\romannumeral`&&@#1\xint:}% +\def\XINT_minof_a #1{\expandafter\XINT_minof_b\romannumeral0\xintraw{#1}!}% +\def\XINT_minof_b #1!#2% + {\expandafter\XINT_minof_c\romannumeral`&&@#2!{#1}!}% +\def\XINT_minof_c #1% + {\xint_gob_til_xint: #1\XINT_minof_e\xint:\XINT_minof_d #1}% +\def\XINT_minof_d #1!% + {\expandafter\XINT_minof_b\romannumeral0\xintmin {#1}}% +\def\XINT_minof_e #1!#2!{ #2}% +% \end{macrocode} +% \subsection{\csh{xintCmp}} +% \begin{macrocode} +\def\xintCmp {\romannumeral0\xintcmp }% +\def\xintcmp #1% +{% + \expandafter\XINT_fcmp\expandafter {\romannumeral0\xintraw {#1}}% +}% +\def\XINT_fcmp #1#2% +{% + \expandafter\XINT_fcmp_A\romannumeral0\xintraw {#2}#1% +}% +\def\XINT_fcmp_A #1#2/#3[#4]#5#6/#7[#8]% +{% + \xint_UDsignsfork + #1#5\XINT_fcmp_minusminus + -#5\XINT_fcmp_firstneg + #1-\XINT_fcmp_secondneg + --\XINT_fcmp_nonneg_a + \krof + #1#5{#2/#3[#4]}{#6/#7[#8]}% +}% +\def\XINT_fcmp_minusminus --#1#2{\XINT_fcmp_B #2#1}% +\def\XINT_fcmp_firstneg #1-#2#3{ -1}% +\def\XINT_fcmp_secondneg -#1#2#3{ 1}% +\def\XINT_fcmp_nonneg_a #1#2% +{% + \xint_UDzerosfork + #1#2\XINT_fcmp_zerozero + 0#2\XINT_fcmp_firstzero + #10\XINT_fcmp_secondzero + 00\XINT_fcmp_pos + \krof + #1#2% +}% +\def\XINT_fcmp_zerozero #1#2#3#4{ 0}% +\def\XINT_fcmp_firstzero #1#2#3#4{ -1}% +\def\XINT_fcmp_secondzero #1#2#3#4{ 1}% +\def\XINT_fcmp_pos #1#2#3#4% +{% + \XINT_fcmp_B #1#3#2#4% +}% +\def\XINT_fcmp_B #1/#2[#3]#4/#5[#6]% +{% + \expandafter\XINT_fcmp_C\expandafter + {\the\numexpr #6-#3\expandafter}\expandafter + {\romannumeral0\xintiimul {#4}{#2}}% + {\romannumeral0\xintiimul {#5}{#1}}% +}% +\def\XINT_fcmp_C #1#2#3% +{% + \expandafter\XINT_fcmp_D\expandafter + {#3}{#1}{#2}% +}% +\def\XINT_fcmp_D #1#2#3% +{% + \expandafter\XINT_cntSgnFork\romannumeral`&&@\expandafter\XINT_cntSgn + \the\numexpr #2+\xintLength{#3}-\xintLength{#1}\relax\xint: + { -1}{\XINT_fcmp_E #2\Z {#3}{#1}}{ 1}% +}% +\def\XINT_fcmp_E #1% +{% + \xint_UDsignfork + #1\XINT_fcmp_Fd + -{\XINT_fcmp_Fn #1}% + \krof +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_fcmp_Fd #1\Z #2#3% +{% + \expandafter\XINT_fcmp_Fe + \romannumeral0\XINT_dsx_addzeros {#1}#3;\xint:#2\xint: +}% +\def\XINT_fcmp_Fe #1\xint:#2#3\xint:{\XINT_cmp_plusplus #2#1\xint:#3\xint:}% +\def\XINT_fcmp_Fn #1\Z #2#3% +{% + \expandafter\XINT_fcmp_Fo + \romannumeral0\XINT_dsx_addzeros {#1}#2;\xint:#3\xint: +}% +\def\XINT_fcmp_Fo #1#2\xint:#3\xint:{\XINT_cmp_plusplus #1#3\xint:#2\xint:}% +% \end{macrocode} +% \subsection{\csh{xintAbs}} +% \begin{macrocode} +\def\xintAbs {\romannumeral0\xintabs }% +\def\xintabs #1{\expandafter\XINT_abs\romannumeral0\xintraw {#1}}% +% \end{macrocode} +% \subsection{\csh{xintOpp}} +% \begin{macrocode} +\def\xintOpp {\romannumeral0\xintopp }% +\def\xintopp #1{\expandafter\XINT_opp\romannumeral0\xintraw {#1}}% +% \end{macrocode} +% \subsection{\csh{xintInv}} +% \changed{1.3d}{} +% \begin{macrocode} +\def\xintInv {\romannumeral0\xintinv }% +\def\xintinv #1{\expandafter\XINT_inv\romannumeral0\xintraw {#1}}% +\def\XINT_inv #1% +{% + \xint_UDzerominusfork + #1-\XINT_inv_iszero + 0#1\XINT_inv_a + 0-{\XINT_inv_a {}}% + \krof #1% +}% +\def\XINT_inv_iszero #1]% + {\XINT_signalcondition{DivisionByZero}{Division of 1 by zero (#1])}{}{0/1[0]}}% +\def\XINT_inv_a #1#2/#3[#4#5]% +{% + \xint_UDzerominusfork + #4-\XINT_inv_expiszero + 0#4\XINT_inv_b + 0-{\XINT_inv_b -#4}% + \krof #5.{#1#3/#2}% +}% +\def\XINT_inv_expiszero #1.#2{ #2[0]}% +\def\XINT_inv_b #1.#2{ #2[#1]}% +% \end{macrocode} +% \subsection{\csh{xintSgn}} +% \begin{macrocode} +\def\xintSgn {\romannumeral0\xintsgn }% +\def\xintsgn #1{\expandafter\XINT_sgn\romannumeral0\xintraw {#1}\xint:}% +% \end{macrocode} +% \subsection{Floating point macros} +% +% For a long time the float routines dating back to releases |1.07/1.08a| +% (May-June 2013) were not modified. +% +% Since |1.2f| (March 2016) the four operations first round their arguments to +% |\xinttheDigits|-floats (or |P|-floats), not (|\xinttheDigits+2|)-floats or +% (|P+2|)-floats as was the case with earlier releases. +% +% The four operations addition, subtraction, multiplication, division have +% always produced the correct rounding of the theoretical exact value to |P| +% or |\xinttheDigits| digits when the inputs are decimal numbers with at most +% |P| digits, and arbitrary decimal exponent part. +% +% From |1.08a| to |1.2j|, |\xintFloat| (and |\XINTinFloat| which is used to +% parse inputs to other float macros) handled a fractional input |A/B| via an +% initial replacement to |A'/B'| where |A'| and |B'| were |A| and |B| +% truncated to |Q+2| digits (where asked-for precision is |Q|), and then they +% correctly rounded |A'/B'| to |Q| digits. But this meant that this rounding of +% the input could differ (by up to one unit in the last place) from the +% correct rounding of the original |A/B| to the asked-for number of +% digits (which until |1.2f| in uses as auxiliary to the macros for the basic +% operations was 2 more than the prevailing precision). +% +% Since |1.2k| all inputs are correctly rounded to the asked-for number of +% digits (this was, I think, the case in the |1.07| release -- there are no +% code comments -- but was, afaicr, not very efficiently done, and this is why +% the |1.08a| release opeted for truncation of the numerator and denominator.) +% +% Notice that in float expressions, the |/| is treated as operator, hence the +% above discussion makes a difference only for the special input form +% |qfloat(A/B)| or for an |\xintexpr A/B\relax| embedded in the float +% expression, with |A| or |B| having more digits than the prevailing float +% precision. +% +% \begin{framed} +% Internally there is no inner representation of |P|-floats as such !!!!! +% +% The input parser will again compute the length of the mantissa on each use +% !!! This is obviously something that must be improved upon before +% implementation of higher functions. +% +% Currently, special tricks are used to quickly recognize inputs having no +% denominators, or fractions whose numerators and denominators are not too +% long compared to the target precision |P|, and in particular |P|-floats or +% quotients of two such. +% +% Another long-standing issue is that float multiplication will first +% compute the |2P| or |2P-1| digits of the exact product, and then round it +% to |P| digits. This is sub-optimal for large |P| particularly as the +% multiplication algorithm is basically the schoolbook one, hence +% \emph{worse} than quadratic in the \TeX\ implementation which has extra +% cost of fetching long sequences of tokens. +% \end{framed} +% +% +% \subsection{\csh{xintFloat}} +% \lverb|& +% 1.2f and 1.2g brought some refactoring which resulted in faster treatment of +% decimal inputs. 1.2i dropped use of some old routines dating back to pre 1.2 +% era in favor of more modern \xintDSRr for rounding. Then 1.2k improves +% again the handling of denominators B with few digits. +% +% But the main change with 1.2k is a complete rewrite of the B>1 case in +% order to achieve again correct rounding in all cases. +% +% The original version from 1.07 (May 2013) computed the exact rounding +% to P digits for all inputs. But from 1.08 on (June 2013), the macro handled +% A/B input by first truncating both A and B to at most P+2 digits. This meant +% that decimal input (arbitrarily long, with scientific part) was correctly +% rounded, but in case of fractional input there could be up to 0.6 unit in +% the last place difference of the produced rounding to the input, hence the +% output could differ from the correct rounding. +% +% Example with 16 digits (the default): \xintFloat {1/17597472569900621233}$newline +% with xintfrac 1.07: 5.682634230727187e-20$newline +% with xintfrac 1.08b--1.2j: 5.682634230727188e-20$newline +% with xintfrac 1.2k: 5.682634230727187e-20$newline +% The exact value is 5.682634230727187499924124...e-20, showing that 1.07 and +% 1.2k +% produce the correct rounding. +% +% Currently the code ends in a more costly branch in about 1 case among 500, +% where it does some extra operations (a multiplication in particular). There +% is a free parameter delta (here set at 4), I have yet to make some numerical +% explorations, to see if it could be favorable to set it to a higher value +% (with delta=5, there is only 1 exceptional case in 5000, etc...). +% +% I have always hesitated about the policy of printing 10.00...0 in case of +% rounding upwards to the next power of ten. Already since 1.2f \XINTinFloat +% always produced a mantissa with exactly P digits (except for the zero +% value). Starting with 1.2k, \xintFloat drops this habit of printing +% 10.00..0 in such cases. Side note: the rounding-up detection worked when the +% input A/B was with numerator A and denominator B having each less than P+2 +% digits, or with B=1, else, it could happen that the output was a power of +% ten but not detected to be a rounding up of the original fraction. The value +% was ok, but printed 1.0...0eN with P-1 zeroes, not 10.0...0e(N-1). +% +% I decided it was not worth the effort to enhance the algorithm to detect +% with 100$% fiability all cases of rounding up to next +% power of ten, hence 1.2k dropped this. +% +% To avoid duplication of code, and any extra burden on \XINTinFloat, which is +% the macro used internally by the float macros for parsing their inputs, we +% simply make now \xintFloat a wrapper of \XINTinFloat.| +% \begin{macrocode} +\def\xintFloat {\romannumeral0\xintfloat }% +\def\xintfloat #1{\XINT_float_chkopt #1\xint:}% +\def\XINT_float_chkopt #1% +{% + \ifx [#1\expandafter\XINT_float_opt + \else\expandafter\XINT_float_noopt + \fi #1% +}% +\def\XINT_float_noopt #1\xint:% +{% + \expandafter\XINT_float_post + \romannumeral0\XINTinfloat[\XINTdigits]{#1}\XINTdigits.% +}% +\def\XINT_float_opt [\xint:#1]% +{% + \expandafter\XINT_float_opt_a\the\numexpr #1.% +}% +\def\XINT_float_opt_a #1.#2% +{% + \expandafter\XINT_float_post + \romannumeral0\XINTinfloat[#1]{#2}#1.% +}% +\def\XINT_float_post #1% +{% + \xint_UDzerominusfork + #1-\XINT_float_zero + 0#1\XINT_float_neg + 0-\XINT_float_pos + \krof #1% +}%[ +\def\XINT_float_zero #1]#2.{ 0.e0}% +\def\XINT_float_neg-{\expandafter-\romannumeral0\XINT_float_pos}% +\def\XINT_float_pos #1#2[#3]#4.% +{% + \expandafter\XINT_float_pos_done\the\numexpr#3+#4-\xint_c_i.#1.#2;% +}% +\def\XINT_float_pos_done #1.#2;{ #2e#1}% +% \end{macrocode} +% \subsection{\csh{XINTinFloat}, \csh{XINTinFloatS}, \csh{XINTiLogTen}} +% \lverb|& +% This routine is like \xintFloat but produces an output of the shape A[N] +% which is then parsed faster as input to other float macros. +% Float operations in \xintfloatexpr...\relax use internally this format. +% +% It must be used in form \XINTinFloat[P]{f}: the optional [P] is +% mandatory. +% +% Since 1.2f, the mantissa always has exactly P digits even in case of +% rounding up to next power of ten. This simplifies other routines. +% +% 1.2g added a variant \XINTinFloatS which, in case of decimal input with less +% than the asked for precision P will not add extra zeros to the mantissa. For +% example it may output 2[0] even if P=500, rather than the canonical +% representation 200...000[-499]. This is how \xintFloatMul and \xintFloatDiv +% parse their inputs, which speeds-up follow-up processing. But \xintFloatAdd +% and \xintFloatSub still use \XINTinFloat for parsing their inputs; anyway +% this will have to be changed again when inner structure will carry upfront +% at least the length of mantissa as data. +% +% Each time \XINTinFloat is called it at least computes a length. Naturally if +% we had some format for floats that would be dispensed of...$newline +% something like +% <letterP><length of mantissa>.mantissa.exponent, etc... not yet. +% +% Since 1.2k, \XINTinFloat always correctly rounds its argument, even if it +% is a fraction with very big numerator and denominator. See the discussion of +% \xintFloat. +% +% 1.3e adds \XINTiLogTen. +% | +% \begin{macrocode} +\def\XINTinFloat {\romannumeral0\XINTinfloat }% +\def\XINTinfloat + {\expandafter\XINT_infloat_clean\romannumeral0\XINT_infloat}% +% \end{macrocode} +% \lverb|Attention que ici le fait que l'on grabbe #1 est important car il +% pourrait y avoir un zéro (en particulier dans le cas où input est nul).| +% \begin{macrocode} +\def\XINT_infloat_clean #1% + {\if #1!\xint_dothis\XINT_infloat_clean_a\fi\xint_orthat{ }#1}% +% \end{macrocode} +% \lverb|Ici on ajoute les zeros pour faire exactement avec P chiffres. +% Car le #1 = P - L avec L la longueur de #2, (ou de abs(#2), ici le #2 peut +% avoir un signe) qui est < P| +% \begin{macrocode} +\def\XINT_infloat_clean_a !#1.#2[#3]% +{% + \expandafter\XINT_infloat_done + \the\numexpr #3-#1\expandafter.% + \romannumeral0\XINT_dsx_addzeros {#1}#2;;% +}% +\def\XINT_infloat_done #1.#2;{ #2[#1]}% +% \end{macrocode} +% \lverb|variant which allows output with shorter mantissas.| +% \begin{macrocode} +\def\XINTinFloatS {\romannumeral0\XINTinfloatS}% +\def\XINTinfloatS + {\expandafter\XINT_infloatS_clean\romannumeral0\XINT_infloat}% +\def\XINT_infloatS_clean #1% + {\if #1!\xint_dothis\XINT_infloatS_clean_a\fi\xint_orthat{ }#1}% +\def\XINT_infloatS_clean_a !#1.{ }% +% \end{macrocode} +% \lverb|1.3e ajoute \XINTiLogTen. Le comportement pour un input nul est non +% encore finalisé. Il changera lorsque NaN, +Inf, -Inf existeront.| +% \begin{macrocode} +\def\XINTFloatiLogTen {\the\numexpr\XINTfloatilogten}% +\def\XINTfloatilogten [#1]#2% + {\expandafter\XINT_floatilogten\romannumeral0\XINT_infloat[#1]{#2}#1.}% +\def\XINT_floatilogten #1{% + \if #10\xint_dothis\XINT_floatilogten_z\fi + \if #1!\xint_dothis\XINT_floatilogten_a\fi + \xint_orthat\XINT_floatilogten_b #1% +}% +\def\XINT_floatilogten_z 0[0]#1.{-"7FFF8000\relax}% +\def\XINT_floatilogten_a !#1.#2[#3]#4.{#3-#1+#4-1\relax}% +\def\XINT_floatilogten_b #1[#2]#3.{#2+#3-1\relax}% +% \end{macrocode} +% \lverb|début de la routine proprement dite, +% l'argument optionnel est obligatoire.| +% \begin{macrocode} +\def\XINT_infloat [#1]#2% +{% + \expandafter\XINT_infloat_a\the\numexpr #1\expandafter.% + \romannumeral0\XINT_infrac {#2}% +}% +% \end{macrocode} +% \lverb| #1=P, #2=n, #3=A, #4=B.| +% \begin{macrocode} +\def\XINT_infloat_a #1.#2#3#4% +{% +% \end{macrocode} +% \lverb|micro boost au lieu d'utiliser \XINT_isOne{#4}, mais pas bon style.| +% \begin{macrocode} + \if1\XINT_is_One#4XY% + \expandafter\XINT_infloat_sp + \else\expandafter\XINT_infloat_fork + \fi #3.{#1}{#2}{#4}% +}% +% \end{macrocode} +% \lverb|Special quick treatment of B=1 case (1.2f then again 1.2g.)$newline +% maintenant: A.{P}{N}{1} +% Il est possible que A soit nul. +% | +% \begin{macrocode} +\def\XINT_infloat_sp #1% +{% + \xint_UDzerominusfork + #1-\XINT_infloat_spzero + 0#1\XINT_infloat_spneg + 0-\XINT_infloat_sppos + \krof #1% +}% +% \end{macrocode} +% \lverb|Attention surtout pas 0/1[0] ici.| +% \begin{macrocode} +\def\XINT_infloat_spzero 0.#1#2#3{ 0[0]}% +\def\XINT_infloat_spneg-% + {\expandafter\XINT_infloat_spnegend\romannumeral0\XINT_infloat_sppos}% +\def\XINT_infloat_spnegend #1% + {\if#1!\expandafter\XINT_infloat_spneg_needzeros\fi -#1}% +\def\XINT_infloat_spneg_needzeros -!#1.{!#1.-}% +% \end{macrocode} +% \lverb|in: A.{P}{N}{1}$newline +% out: P-L.A.P.N.| +% \begin{macrocode} +\def\XINT_infloat_sppos #1.#2#3#4% +{% + \expandafter\XINT_infloat_sp_b\the\numexpr#2-\xintLength{#1}.#1.#2.#3.% +}% +% \end{macrocode} +% \lverb|#1= P-L. Si c'est positif ou nul il faut retrancher #1 à l'exposant, et +% ajouter autant de zéros. On regarde premier token. +% P-L.A.P.N.| +% \begin{macrocode} +\def\XINT_infloat_sp_b #1% +{% + \xint_UDzerominusfork + #1-\XINT_infloat_sp_quick + 0#1\XINT_infloat_sp_c + 0-\XINT_infloat_sp_needzeros + \krof #1% +}% +% \end{macrocode} +% \lverb|Ici P=L. Le cas usuel dans \xintfloatexpr.| +% \begin{macrocode} +\def\XINT_infloat_sp_quick 0.#1.#2.#3.{ #1[#3]}% +% \end{macrocode} +% \lverb|Ici #1=P-L est >0. L'exposant sera N-(P-L). #2=A. #3=P. #4=N.$newline +% 18 mars 2016. En fait dans certains contextes il est sous-optimal d'ajouter les +% zéros. Par exemple quand c'est appelé par la multiplication ou la division, +% c'est idiot de convertir 2 en 200000...00000[-499]. +% Donc je redéfinis addzeros en needzeroes. Si on appelle sous la forme +% \XINTinFloatS, on ne fait pas l'addition de zeros.| +% \begin{macrocode} +\def\XINT_infloat_sp_needzeros #1.#2.#3.#4.{!#1.#2[#4]}% +% \end{macrocode} +% \lverb|L-P=#1.A=#2#3.P=#4.N=#5.$newline +% Ici P<L. Il va falloir arrondir. Attention si on va à la puissance de 10 +% suivante. En #1 on a L-P qui est >0. L'exposant final sera N+L-P, +% sauf dans le cas spécial, il sera alors N+L-P+1. L'ajustement final +% est fait par \XINT_infloat_Y.| +% \begin{macrocode} +\def\XINT_infloat_sp_c -#1.#2#3.#4.#5.% +{% + \expandafter\XINT_infloat_Y + \the\numexpr #5+#1\expandafter.% + \romannumeral0\expandafter\XINT_infloat_sp_round + \romannumeral0\XINT_split_fromleft + (\xint_c_i+#4).#2#3\xint_bye2345678\xint_bye..#2% +}% +\def\XINT_infloat_sp_round #1.#2.% +{% + \XINT_dsrr#1\xint_bye\xint_Bye3456789\xint_bye/\xint_c_x\relax.% +}% +% \end{macrocode} +% \lverb|General branch for A/B with B>1 inputs. It achieves correct rounding +% always since 1.2k (done January 2, 2017.) This branch is never taken for A=0 +% because \XINT_infrac will have returned B=1 then.| +% \begin{macrocode} +\def\XINT_infloat_fork #1% +{% + \xint_UDsignfork + #1\XINT_infloat_J + -\XINT_infloat_K + \krof #1% +}% +\def\XINT_infloat_J-{\expandafter-\romannumeral0\XINT_infloat_K }% +% \end{macrocode} +% \lverb?A.{P}{n}{B} avec B>1.? +% \begin{macrocode} +\def\XINT_infloat_K #1.#2% +{% + \expandafter\XINT_infloat_L + \the\numexpr\xintLength{#1}\expandafter.\the\numexpr #2+\xint_c_iv.{#1}{#2}% +}% +% \end{macrocode} +% \lverb?|A|.P+4.{A}{P}{n}{B}. We check if A already has length +% <= P+4.? +% \begin{macrocode} +\def\XINT_infloat_L #1.#2.% +{% + \ifnum #1>#2 + \expandafter\XINT_infloat_Ma + \else + \expandafter\XINT_infloat_Mb + \fi #1.#2.% +}% +% \end{macrocode} +% \lverb?|A|.P+4.{A}{P}{n}{B}. We will keep only the first P+4 +% digits of A, denoted A'' in what follows. +% +% output: u=-0.A''.junk.P+4.|A|.{A}{P}{n}{B}? +% \begin{macrocode} +\def\XINT_infloat_Ma #1.#2.#3% +{% + \expandafter\XINT_infloat_MtoN\expandafter-\expandafter0\expandafter.% + \romannumeral0\XINT_split_fromleft#2.#3\xint_bye2345678\xint_bye..% + #2.#1.{#3}% +}% +% \end{macrocode} +% \lverb?|A|.P+4.{A}{P}{n}{B}.$newline +% Here A is short. We set u = P+4-|A|, and A''=A (A' = 10^u A) +% +% output: u.A''..P+4.|A|.{A}{P}{n}{B}? +% \begin{macrocode} +\def\XINT_infloat_Mb #1.#2.#3% +{% + \expandafter\XINT_infloat_MtoN\the\numexpr#2-#1.% + #3..#2.#1.{#3}% +}% +% \end{macrocode} +% \lverb?input u.A''.junk.P+4.|A|.{A}{P}{n}{B}$newline +% output |B|.P+4.{B}u.A''.P.|A|.n.{A}{B}? +% \begin{macrocode} +\def\XINT_infloat_MtoN #1.#2.#3.#4.#5.#6#7#8#9% +{% + \expandafter\XINT_infloat_N + \the\numexpr\xintLength{#9}.#4.{#9}#1.#2.#7.#5.#8.{#6}{#9}% +}% +\def\XINT_infloat_N #1.#2.% +{% + \ifnum #1>#2 + \expandafter\XINT_infloat_Oa + \else + \expandafter\XINT_infloat_Ob + \fi #1.#2.% +}% +% \end{macrocode} +% \lverb?input |B|.P+4.{B}u.A''.P.|A|.n.{A}{B}$newline +% output v=-0.B''.junk.|B|.u.A''.P.|A|.n.{A}{B}? +% \begin{macrocode} +\def\XINT_infloat_Oa #1.#2.#3% +{% + \expandafter\XINT_infloat_P\expandafter-\expandafter0\expandafter.% + \romannumeral0\XINT_split_fromleft#2.#3\xint_bye2345678\xint_bye..% + #1.% +}% +% \end{macrocode} +% \lverb?output v=P+4-|B|>=0.B''.junk.|B|.u.A''.P.|A|.n.{A}{B}? +% \begin{macrocode} +\def\XINT_infloat_Ob #1.#2.#3% +{% + \expandafter\XINT_infloat_P\the\numexpr#2-#1.#3..#1.% +}% +% \end{macrocode} +% \lverb?input v.B''.junk.|B|.u.A''.P.|A|.n.{A}{B}$newline +% output Q1.P.|B|.|A|.n.{A}{B}$newline +% Q1 = division euclidienne de A''.10^{u-v+P+3} par B''. +% +% Special detection of cases with A and B both having length at most P+4: this +% will happen when called from \xintFloatDiv as A and B (produced then via +% \XINTinFloatS) will have at most P digits. We then only need integer division +% with P+1 extra zeros, not P+3.? +% \begin{macrocode} +\def\XINT_infloat_P #1#2.#3.#4.#5.#6#7.#8.#9.% +{% + \csname XINT_infloat_Q\if-#1\else\if-#6\else q\fi\fi\expandafter\endcsname + \romannumeral0\xintiiquo + {\romannumeral0\XINT_dsx_addzerosnofuss + {#6#7-#1#2+#9+\xint_c_iii\if-#1\else\if-#6\else-\xint_c_ii\fi\fi}#8;}% + {#3}.#9.#5.% +}% +% \end{macrocode} +% \lverb?«quick» branch.? +% \begin{macrocode} +\def\XINT_infloat_Qq #1.#2.% +{% + \expandafter\XINT_infloat_Rq + \romannumeral0\XINT_split_fromleft#2.#1\xint_bye2345678\xint_bye..#2.% +}% +\def\XINT_infloat_Rq #1.#2#3.% +{% + \ifnum#2<\xint_c_v + \expandafter\XINT_infloat_SEq + \else\expandafter\XINT_infloat_SUp + \fi + {\if.#3.\xint_c_\else\xint_c_i\fi}#1.% +}% +% \end{macrocode} +% \lverb?standard branch which will have to handle undecided rounding, if too +% close to a mid-value.? +% \begin{macrocode} +\def\XINT_infloat_Q #1.#2.% +{% + \expandafter\XINT_infloat_R + \romannumeral0\XINT_split_fromleft#2.#1\xint_bye2345678\xint_bye..#2.% +}% +\def\XINT_infloat_R #1.#2#3#4#5.% +{% + \if.#5.\expandafter\XINT_infloat_Sa\else\expandafter\XINT_infloat_Sb\fi + #2#3#4#5.#1.% +}% +% \end{macrocode} +% \lverb?trailing digits.Q.P.|B|.|A|.n.{A}{B}$newline +% #1=trailing digits (they may have leading zeros.)? +% \begin{macrocode} +\def\XINT_infloat_Sa #1.% +{% + \ifnum#1>500 \xint_dothis\XINT_infloat_SUp\fi + \ifnum#1<499 \xint_dothis\XINT_infloat_SEq\fi + \xint_orthat\XINT_infloat_X\xint_c_ +}% +\def\XINT_infloat_Sb #1.% +{% + \ifnum#1>5009 \xint_dothis\XINT_infloat_SUp\fi + \ifnum#1<4990 \xint_dothis\XINT_infloat_SEq\fi + \xint_orthat\XINT_infloat_X\xint_c_i +}% +% \end{macrocode} +% \lverb?epsilon #2=Q.#3=P.#4=|B|.#5=|A|.#6=n.{A}{B}$newline +% exposant final est n+|A|-|B|-P+epsilon? +% \begin{macrocode} +\def\XINT_infloat_SEq #1#2.#3.#4.#5.#6.#7#8% +{% + \expandafter\XINT_infloat_SY + \the\numexpr #6+#5-#4-#3+#1.#2.% +}% +\def\XINT_infloat_SY #1.#2.{ #2[#1]}% +% \end{macrocode} +% \lverb?initial digit #2 put aside to check for case of rounding up to +% next power of ten, which will need adjustment of mantissa and exponent.? +% \begin{macrocode} +\def\XINT_infloat_SUp #1#2#3.#4.#5.#6.#7.#8#9% +{% + \expandafter\XINT_infloat_Y + \the\numexpr#7+#6-#5-#4+#1\expandafter.% + \romannumeral0\xintinc{#2#3}.#2% +}% +% \end{macrocode} +% \lverb?epsilon Q.P.|B|.|A|.n.{A}{B}$newline +% +% \xintDSH{-x}{U} multiplies U by 10^x. When x is negative, this means +% it truncates (i.e. it drops the last -x digits). +% +% We don't try to optimize too much macro calls here, the odds are 2 per 1000 +% for this branch to be taken. Perhaps in future I will use higher free +% parameter d, which currently is set at 4. +% +% #1=epsilon, #2#3=Q, #4=P, #5=|B|, #6=|A|, #7=n, #8=A, #9=B? +% \begin{macrocode} +\def\XINT_infloat_X #1#2#3.#4.#5.#6.#7.#8#9% +{% + \expandafter\XINT_infloat_Y + \the\numexpr #7+#6-#5-#4+#1\expandafter.% + \romannumeral`&&@\romannumeral0\xintiiiflt + {\xintDSH{#6-#5-#4+#1}{\xintDouble{#8}}}% + {\xintiiMul{\xintInc{\xintDouble{#2#3}}}{#9}}% + \xint_firstofone + \xintinc{#2#3}.#2% +}% +% \end{macrocode} +% \lverb?check for rounding up to next power of ten.? +% \begin{macrocode} +\def\XINT_infloat_Y #1{% +\def\XINT_infloat_Y ##1.##2##3.##4% +{% + \if##49\if##21\expandafter\expandafter\expandafter\XINT_infloat_Z\fi\fi + #1##2##3[##1]% +}}\XINT_infloat_Y{ }% +% \end{macrocode} +% \lverb?#1=1, #2=0.? +% \begin{macrocode} +\def\XINT_infloat_Z #1#2#3[#4]% +{% + \expandafter\XINT_infloat_ZZ\the\numexpr#4+\xint_c_i.#3.% +}% +\def\XINT_infloat_ZZ #1.#2.{ 1#2[#1]}% +% \end{macrocode} +% \subsection{\csh{xintPFloat}} +% \lverb|1.1. This is a prettifying printing macro for floats. +% +% +% The macro applies one simple rule: x.yz...eN will drop scientific notation in +% favor of pure decimal notation if -5<=N<=5. This is the default behaviour of +% Maple. The N here is as produced on output by \xintFloat. +% +% Special case: the zero value is printed 0. (with a dot) +% +% The coding got simpler with 1.2k as its \xintFloat always produces +% a mantissa with exactly P digits (no more 10.0...0eN annoying exception). +% +% | +% \begin{macrocode} +\def\xintPFloat {\romannumeral0\xintpfloat }% +\def\xintpfloat #1{\XINT_pfloat_chkopt #1\xint:}% +\def\XINT_pfloat_chkopt #1% +{% + \ifx [#1\expandafter\XINT_pfloat_opt + \else\expandafter\XINT_pfloat_noopt + \fi #1% +}% +\def\XINT_pfloat_noopt #1\xint:% +{% + \expandafter\XINT_pfloat_a + \romannumeral0\xintfloat [\XINTdigits]{#1};\XINTdigits.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_pfloat_opt [\xint:#1]% +{% + \expandafter\XINT_pfloat_opt_a \the\numexpr #1.% +}% +\def\XINT_pfloat_opt_a #1.#2% +{% + \expandafter\XINT_pfloat_a\romannumeral0\xintfloat [#1]{#2};#1.% +}% +\def\XINT_pfloat_a #1% +{% + \xint_UDzerominusfork + #1-\XINT_pfloat_zero + 0#1\XINT_pfloat_neg + 0-\XINT_pfloat_pos + \krof #1% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_pfloat_zero #1;#2.{ 0.}% +\def\XINT_pfloat_neg-{\expandafter-\romannumeral0\XINT_pfloat_pos }% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_pfloat_pos #1.#2e#3;#4.% +{% + \ifnum #3>\xint_c_v \xint_dothis\XINT_pfloat_no\fi + \ifnum #3<-\xint_c_v \xint_dothis\XINT_pfloat_no\fi + \ifnum #3<\xint_c_ \xint_dothis\XINT_pfloat_N\fi + \ifnum #3>\numexpr #4-\xint_c_i\relax \xint_dothis\XINT_pfloat_Ps\fi + \xint_orthat\XINT_pfloat_P #1#2e#3;% +}% +\def\XINT_pfloat_no #1#2;{ #1.#2}% +% \end{macrocode} +% \lverb|This is all simpler coded, now that 1.2k's \xintFloat always +% outputs a mantissa with exactly one digits before decimal mark always. +% | +% \begin{macrocode} +\def\XINT_pfloat_N #1e-#2;% +{% + \csname XINT_pfloat_N_\romannumeral#2\endcsname #1% +}% +\def\XINT_pfloat_N_i { 0.}% +\def\XINT_pfloat_N_ii { 0.0}% +\def\XINT_pfloat_N_iii{ 0.00}% +\def\XINT_pfloat_N_iv { 0.000}% +\def\XINT_pfloat_N_v { 0.0000}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_pfloat_P #1e#2;% +{% + \csname XINT_pfloat_P_\romannumeral#2\endcsname #1% +}% +\def\XINT_pfloat_P_ #1{ #1.}% +\def\XINT_pfloat_P_i #1#2{ #1#2.}% +\def\XINT_pfloat_P_ii #1#2#3{ #1#2#3.}% +\def\XINT_pfloat_P_iii#1#2#3#4{ #1#2#3#4.}% +\def\XINT_pfloat_P_iv #1#2#3#4#5{ #1#2#3#4#5.}% +\def\XINT_pfloat_P_v #1#2#3#4#5#6{ #1#2#3#4#5#6.}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_pfloat_Ps #1e#2;% +{% + \csname XINT_pfloat_Ps\romannumeral#2\endcsname #100000;% +}% +\def\XINT_pfloat_Psi #1#2#3;{ #1#2.}% +\def\XINT_pfloat_Psii #1#2#3#4;{ #1#2#3.}% +\def\XINT_pfloat_Psiii#1#2#3#4#5;{ #1#2#3#4.}% +\def\XINT_pfloat_Psiv #1#2#3#4#5#6;{ #1#2#3#4#5.}% +\def\XINT_pfloat_Psv #1#2#3#4#5#6#7;{ #1#2#3#4#5#6.}% +% \end{macrocode} +% \subsection{\csh{XINTinFloatFracdigits}} +% \lverb|1.09i, for frac function in \xintfloatexpr. This version computes +% exactly from the input the fractional part and then only converts it +% into a float with the asked-for number of digits. I will have to think +% it again some day, certainly. +% +% 1.1 removes optional argument for which there was anyhow no interface, for +% technical reasons having to do with \xintNewExpr. +% +% 1.1a renames the macro as \XINTinFloatFracdigits (from \XINTinFloatFrac) to +% be synchronous with the \XINTinFloatSqrt and \XINTinFloat habits related to +% \xintNewExpr problems. +% +% Note to myself: I still have to rethink the whole thing about what is the best +% to do, the initial way of going through \xinttfrac was just a first +% implementation.| +% \begin{macrocode} +\def\XINTinFloatFracdigits {\romannumeral0\XINTinfloatfracdigits }% +\def\XINTinfloatfracdigits #1% +{% + \expandafter\XINT_infloatfracdg_a\expandafter {\romannumeral0\xinttfrac{#1}}% +}% +\def\XINT_infloatfracdg_a {\XINTinfloat [\XINTdigits]}% +% \end{macrocode} +% \subsection{\csh{xintFloatAdd}, \csh{XINTinFloatAdd}} +% \lverb|First included in release 1.07. +% +% 1.09ka improved a bit the efficiency. However the add, sub, mul, div +% routines were provisory and supposed to be revised soon. +% +% Which didn't happen until 1.2f. Now, the inputs are first rounded to P +% digits, not P+2 as earlier. +% +% +%| +% \begin{macrocode} +\def\xintFloatAdd {\romannumeral0\xintfloatadd }% +\def\xintfloatadd #1{\XINT_fladd_chkopt \xintfloat #1\xint:}% +\def\XINTinFloatAdd {\romannumeral0\XINTinfloatadd }% +\def\XINTinfloatadd #1{\XINT_fladd_chkopt \XINTinfloatS #1\xint:}% +\def\XINT_fladd_chkopt #1#2% +{% + \ifx [#2\expandafter\XINT_fladd_opt + \else\expandafter\XINT_fladd_noopt + \fi #1#2% +}% +\def\XINT_fladd_noopt #1#2\xint:#3% +{% + #1[\XINTdigits]% + {\expandafter\XINT_FL_add_a + \romannumeral0\XINTinfloat[\XINTdigits]{#2}\XINTdigits.{#3}}% +}% +\def\XINT_fladd_opt #1[\xint:#2]%#3#4% +{% + \expandafter\XINT_fladd_opt_a\the\numexpr #2.#1% +}% +\def\XINT_fladd_opt_a #1.#2#3#4% +{% + #2[#1]{\expandafter\XINT_FL_add_a\romannumeral0\XINTinfloat[#1]{#3}#1.{#4}}% +}% +\def\XINT_FL_add_a #1% +{% + \xint_gob_til_zero #1\XINT_FL_add_zero 0\XINT_FL_add_b #1% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_FL_add_zero #1.#2{#2}%[[ +\def\XINT_FL_add_b #1]#2.#3% +{% + \expandafter\XINT_FL_add_c\romannumeral0\XINTinfloat[#2]{#3}#2.#1]% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_FL_add_c #1% +{% + \xint_gob_til_zero #1\XINT_FL_add_zero 0\XINT_FL_add_d #1% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_FL_add_d #1[#2]#3.#4[#5]% +{% + \ifnum\numexpr #2-#3-#5>\xint_c_\xint_dothis\xint_firstoftwo\fi + \ifnum\numexpr #5-#3-#2>\xint_c_\xint_dothis\xint_secondoftwo\fi + \xint_orthat\xintAdd {#1[#2]}{#4[#5]}% +}% +% \end{macrocode} +% \subsection{\csh{xintFloatSub}, \csh{XINTinFloatSub}} +% \lverb|First done 1.07. +% +% Starting with 1.2f the arguments undergo an intial rounding to the target +% precision P not P+2.| +% +% \begin{macrocode} +\def\xintFloatSub {\romannumeral0\xintfloatsub }% +\def\xintfloatsub #1{\XINT_flsub_chkopt \xintfloat #1\xint:}% +\def\XINTinFloatSub {\romannumeral0\XINTinfloatsub }% +\def\XINTinfloatsub #1{\XINT_flsub_chkopt \XINTinfloatS #1\xint:}% +\def\XINT_flsub_chkopt #1#2% +{% + \ifx [#2\expandafter\XINT_flsub_opt + \else\expandafter\XINT_flsub_noopt + \fi #1#2% +}% +\def\XINT_flsub_noopt #1#2\xint:#3% +{% + #1[\XINTdigits]% + {\expandafter\XINT_FL_add_a + \romannumeral0\XINTinfloat[\XINTdigits]{#2}\XINTdigits.{\xintOpp{#3}}}% +}% +\def\XINT_flsub_opt #1[\xint:#2]%#3#4% +{% + \expandafter\XINT_flsub_opt_a\the\numexpr #2.#1% +}% +\def\XINT_flsub_opt_a #1.#2#3#4% +{% + #2[#1]{\expandafter\XINT_FL_add_a\romannumeral0\XINTinfloat[#1]{#3}#1.{\xintOpp{#4}}}% +}% +% \end{macrocode} +% \subsection{\csh{xintFloatMul}, \csh{XINTinFloatMul}} +% \lverb|1.07. +% +% Starting with 1.2f the arguments are rounded to the target precision P not +% P+2. +% +% 1.2g handles the inputs via \XINTinFloatS which will be more efficient when +% the precision is large and the input is for example a small constant like 2. +% +% 1.2k does a micro improvement to the way the macro passes over control +% to its output routine (former version used a higher level \xintE causing +% some extra un-needed processing with two calls to \XINT_infrac where +% one was amply enough).| +% \begin{macrocode} +\def\xintFloatMul {\romannumeral0\xintfloatmul }% +\def\xintfloatmul #1{\XINT_flmul_chkopt \xintfloat #1\xint:}% +\def\XINTinFloatMul {\romannumeral0\XINTinfloatmul }% +\def\XINTinfloatmul #1{\XINT_flmul_chkopt \XINTinfloatS #1\xint:}% +\def\XINT_flmul_chkopt #1#2% +{% + \ifx [#2\expandafter\XINT_flmul_opt + \else\expandafter\XINT_flmul_noopt + \fi #1#2% +}% +\def\XINT_flmul_noopt #1#2\xint:#3% +{% + #1[\XINTdigits]% + {\expandafter\XINT_FL_mul_a + \romannumeral0\XINTinfloatS[\XINTdigits]{#2}\XINTdigits.{#3}}% +}% +\def\XINT_flmul_opt #1[\xint:#2]%#3#4% +{% + \expandafter\XINT_flmul_opt_a\the\numexpr #2.#1% +}% +\def\XINT_flmul_opt_a #1.#2#3#4% +{% + #2[#1]{\expandafter\XINT_FL_mul_a\romannumeral0\XINTinfloatS[#1]{#3}#1.{#4}}% +}% +\def\XINT_FL_mul_a #1[#2]#3.#4% +{% + \expandafter\XINT_FL_mul_b\romannumeral0\XINTinfloatS[#3]{#4}#1[#2]% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_FL_mul_b #1[#2]#3[#4]{\xintiiMul{#3}{#1}/1[#4+#2]}% +% \end{macrocode} +% \subsection{\csh{XINTinFloatInv}} +% \lverb|Added belatedly at 1.3e, to support inv() function. We use Short +% output, for rare inv(\xintexpr 1/3\relax) case. I need to think the whole +% thing out at some later date.| +% \begin{macrocode} +\def\XINTinFloatInv#1{\XINTinFloatS[\XINTdigits]{\xintInv{#1}}}% +% \end{macrocode} +% \subsection{\csh{xintFloatDiv}, \csh{XINTinFloatDiv}} +% \lverb|1.07. +% +% Starting with 1.2f the arguments are rounded to the target precision P not +% P+2. +% +% 1.2g handles the inputs via \XINTinFloatS which will be more efficient when +% the precision is large and the input is for example a small constant like 2. +% +% The actual rounding of the quotient is handled via \xintfloat (or +% \XINTinfloatS). +% +% 1.2k does the same kind of improvement in \XINT_FL_div_b as for +% multiplication: earlier code was unnecessarily high level. +% | +% \begin{macrocode} +\def\xintFloatDiv {\romannumeral0\xintfloatdiv }% +\def\xintfloatdiv #1{\XINT_fldiv_chkopt \xintfloat #1\xint:}% +\def\XINTinFloatDiv {\romannumeral0\XINTinfloatdiv }% +\def\XINTinfloatdiv #1{\XINT_fldiv_chkopt \XINTinfloatS #1\xint:}% +\def\XINT_fldiv_chkopt #1#2% +{% + \ifx [#2\expandafter\XINT_fldiv_opt + \else\expandafter\XINT_fldiv_noopt + \fi #1#2% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_fldiv_noopt #1#2\xint:#3% +{% + #1[\XINTdigits]% + {\expandafter\XINT_FL_div_a + \romannumeral0\XINTinfloatS[\XINTdigits]{#3}\XINTdigits.{#2}}% +}% +\def\XINT_fldiv_opt #1[\xint:#2]%#3#4% +{% + \expandafter\XINT_fldiv_opt_a\the\numexpr #2.#1% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_fldiv_opt_a #1.#2#3#4% +{% + #2[#1]{\expandafter\XINT_FL_div_a\romannumeral0\XINTinfloatS[#1]{#4}#1.{#3}}% +}% +\def\XINT_FL_div_a #1[#2]#3.#4% +{% + \expandafter\XINT_FL_div_b\romannumeral0\XINTinfloatS[#3]{#4}/#1e#2% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_FL_div_b #1[#2]{#1e#2}% +% \end{macrocode} +% \subsection{\csh{xintFloatPow}, \csh{XINTinFloatPow}} +% \lverb|1.07: initial version. 1.09j has re-organized the core loop. +% +% 2015/12/07. I have hesitated to map ^ in expressions to \xintFloatPow rather +% than \xintFloatPower. But for 1.234567890123456 to the power 2145678912 with +% P=16, using Pow rather than Power seems to bring only about 5$char37 $space +% gain. +% +% This routine requires the exponent x to be compatible with \numexpr parsing. +% +% 1.2f has rewritten the code for better efficiency. Also, now the argument A +% for A^x is first rounded to P digits before switching to the increased +% working precision (which depends upon x). +% +% | +% \begin{macrocode} +\def\xintFloatPow {\romannumeral0\xintfloatpow}% +\def\xintfloatpow #1{\XINT_flpow_chkopt \xintfloat #1\xint:}% +\def\XINTinFloatPow {\romannumeral0\XINTinfloatpow }% +\def\XINTinfloatpow #1{\XINT_flpow_chkopt \XINTinfloatS #1\xint:}% +\def\XINT_flpow_chkopt #1#2% +{% + \ifx [#2\expandafter\XINT_flpow_opt + \else\expandafter\XINT_flpow_noopt + \fi + #1#2% +}% +\def\XINT_flpow_noopt #1#2\xint:#3% +{% + \expandafter\XINT_flpow_checkB_a + \the\numexpr #3.\XINTdigits.{#2}{#1[\XINTdigits]}% +}% +\def\XINT_flpow_opt #1[\xint:#2]% +{% + \expandafter\XINT_flpow_opt_a\the\numexpr #2.#1% +}% +\def\XINT_flpow_opt_a #1.#2#3#4% +{% + \expandafter\XINT_flpow_checkB_a\the\numexpr #4.#1.{#3}{#2[#1]}% +}% +\def\XINT_flpow_checkB_a #1% +{% + \xint_UDzerominusfork + #1-\XINT_flpow_BisZero + 0#1{\XINT_flpow_checkB_b -}% + 0-{\XINT_flpow_checkB_b {}#1}% + \krof +}% +\def\XINT_flpow_BisZero .#1.#2#3{#3{1[0]}}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpow_checkB_b #1#2.#3.% +{% + \expandafter\XINT_flpow_checkB_c + \the\numexpr\xintLength{#2}+\xint_c_iii.#3.#2.{#1}% +}% +% \end{macrocode} +% \begin{macrocode} +\def\XINT_flpow_checkB_c #1.#2.% +{% + \expandafter\XINT_flpow_checkB_d\the\numexpr#1+#2.#1.#2.% +}% +% \end{macrocode} +% \lverb|& +% +% 1.2f rounds input to P digits, first. +% | +% \begin{macrocode} +\def\XINT_flpow_checkB_d #1.#2.#3.#4.#5#6% +{% + \expandafter \XINT_flpow_aa + \romannumeral0\XINTinfloat [#3]{#6}{#2}{#1}{#4}{#5}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpow_aa #1[#2]#3% +{% + \expandafter\XINT_flpow_ab\the\numexpr #2-#3\expandafter.% + \romannumeral\XINT_rep #3\endcsname0.#1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpow_ab #1.#2.#3.{\XINT_flpow_a #3#2[#1]}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpow_a #1% +{% + \xint_UDzerominusfork + #1-\XINT_flpow_zero + 0#1{\XINT_flpow_b \iftrue}% + 0-{\XINT_flpow_b \iffalse#1}% + \krof +}% +\def\XINT_flpow_zero #1[#2]#3#4#5#6% +{% + #6{\if 1#51\xint_dothis {0[0]}\fi + \xint_orthat + {\XINT_signalcondition{DivisionByZero}{0 to the power #4}{}{0[0]}}% + }% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpow_b #1#2[#3]#4#5% +{% + \XINT_flpow_loopI #5.#3.#2.#4.{#1\ifodd #5 \xint_c_i\fi\fi}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpow_truncate #1.#2.#3.% +{% + \expandafter\XINT_flpow_truncate_a + \romannumeral0\XINT_split_fromleft + #3.#2\xint_bye2345678\xint_bye..#1.#3.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpow_truncate_a #1.#2.#3.{#3+\xintLength{#2}.#1.}% +\def\XINT_flpow_loopI #1.% +{% + \ifnum #1=\xint_c_i\expandafter\XINT_flpow_ItoIII\fi + \ifodd #1 + \expandafter\XINT_flpow_loopI_odd + \else + \expandafter\XINT_flpow_loopI_even + \fi + #1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpow_ItoIII\ifodd #1\fi #2.#3.#4.#5.#6% +{% + \expandafter\XINT_flpow_III\the\numexpr #6+\xint_c_.#3.#4.#5.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpow_loopI_even #1.#2.#3.%#4.% +{% + \expandafter\XINT_flpow_loopI + \the\numexpr #1/\xint_c_ii\expandafter.% + \the\numexpr\expandafter\XINT_flpow_truncate + \the\numexpr\xint_c_ii*#2\expandafter.\romannumeral0\xintiisqr{#3}.% +}% +\def\XINT_flpow_loopI_odd #1.#2.#3.#4.% +{% + \expandafter\XINT_flpow_loopII + \the\numexpr #1/\xint_c_ii-\xint_c_i\expandafter.% + \the\numexpr\expandafter\XINT_flpow_truncate + \the\numexpr\xint_c_ii*#2\expandafter.\romannumeral0\xintiisqr{#3}.#4.#2.#3.% +}% +\def\XINT_flpow_loopII #1.% +{% + \ifnum #1 = \xint_c_i\expandafter\XINT_flpow_IItoIII\fi + \ifodd #1 + \expandafter\XINT_flpow_loopII_odd + \else + \expandafter\XINT_flpow_loopII_even + \fi + #1.% +}% +\def\XINT_flpow_loopII_even #1.#2.#3.%#4.% +{% + \expandafter\XINT_flpow_loopII + \the\numexpr #1/\xint_c_ii\expandafter.% + \the\numexpr\expandafter\XINT_flpow_truncate + \the\numexpr\xint_c_ii*#2\expandafter.\romannumeral0\xintiisqr{#3}.% +}% +\def\XINT_flpow_loopII_odd #1.#2.#3.#4.#5.#6.% +{% + \expandafter\XINT_flpow_loopII_odda + \the\numexpr\expandafter\XINT_flpow_truncate + \the\numexpr#2+#5\expandafter.\romannumeral0\xintiimul{#3}{#6}.#4.% + #1.#2.#3.% +}% +\def\XINT_flpow_loopII_odda #1.#2.#3.#4.#5.#6.% +{% + \expandafter\XINT_flpow_loopII + \the\numexpr #4/\xint_c_ii-\xint_c_i\expandafter.% + \the\numexpr\expandafter\XINT_flpow_truncate + \the\numexpr\xint_c_ii*#5\expandafter.\romannumeral0\xintiisqr{#6}.#3.% + #1.#2.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpow_IItoIII\ifodd #1\fi #2.#3.#4.#5.#6.#7.#8% +{% + \expandafter\XINT_flpow_III\the\numexpr #8+\xint_c_\expandafter.% + \the\numexpr\expandafter\XINT_flpow_truncate + \the\numexpr#3+#6\expandafter.\romannumeral0\xintiimul{#4}{#7}.#5.% +}% +% \end{macrocode} +% \lverb|This ending is common with \xintFloatPower. +% +% In the case of negative exponent we need to inverse the Q-digits mantissa. +% This requires no special attention now as 1.2k's \xintFloat does correct +% rounding of fractions hence it is easy to bound the total error. It can be +% checked that the algorithm after final rounding to the target precision +% computes a value Z whose distance to the exact theoretical will be less than +% 0.52 ulp(Z) (and worst cases can only be slightly worse than 0.51 ulp(Z)). +% +% In the case of the half-integer exponent (only via the expression +% interface,) the computation (which proceeds via \XINTinFloatPowerH) ends +% with a square root. This square root extraction is done with 3 guard digits +% (the power operations were done with more.) Then the value is rounded to the +% target precision. There is thus this rounding to 3 guard digits (in the case +% of negative exponent the reciprocal is computed before the square-root), +% then the square root is (computed with exact rounding for these 3 guard +% digits), and then there is the final rounding of this to the target +% precision. The total error (for positive as well as negative exponent) has +% been estimated to at worst possibly exceed slightly 0.5125 ulp(Z), and at +% any rate it is less than 0.52 ulp(Z).| +% \begin{macrocode} +\def\XINT_flpow_III #1.#2.#3.#4.#5% +{% + \expandafter\XINT_flpow_IIIend + \xint_UDsignfork + #5{{1/#3[-#2]}}% + -{{#3[#2]}}% + \krof #1% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpow_IIIend #1#2#3% + {#3{\if#21\xint_afterfi{\expandafter-\romannumeral`&&@}\fi#1}}% +% \end{macrocode} +% \subsection{\csh{xintFloatPower}, \csh{XINTinFloatPower}} +% \lverb|1.07. The core loop has been re-organized in 1.09j for some slight +% efficiency gain. The exponent B is given to \xintNum. The ^ in expressions +% is mapped to this routine. +% +% Same modifications as in \xintFloatPow for 1.2f. +% +% 1.2f adds a special private macro for allowing half-integral exponents for +% use with ^ within \xintfloatexpr. The exponent will be first truncated to +% either an integer or an half-integer. The macro is not for general use. +% +% 1.2k does anew this 1.2f handling of half-integer exponents for the +% \xintfloatexpr parser: with 1.2f's code +% the final square-root extraction was applied to a value already rounded to +% the target precision, unneedlessly losing precision. +% | +% \begin{macrocode} +\def\xintFloatPower {\romannumeral0\xintfloatpower}% +\def\xintfloatpower #1{\XINT_flpower_chkopt \xintfloat #1\xint:}% +\def\XINTinFloatPower {\romannumeral0\XINTinfloatpower }% +\def\XINTinfloatpower #1{\XINT_flpower_chkopt \XINTinfloatS #1\xint:}% +% \end{macrocode} +% \lverb|First the special macro for use by the expression parser which checks +% if one raises to an half-integer exponent. This is always with \XINTdigits +% precision. Rewritten for 1.2k in order for the final square root to keep +% three guard digits. +% +% We have to be careful that exponent #2 is not constrained by TeX bound. And +% we must allow fractions. The 1.2k variant does a rounding to nearest integer +% of half-integer, 1.2f did a truncation rather (this is done after truncation +% of #2 to fixed point with one digit after mark.) We try to recognize quickly +% the case of integer exponent, for speed, but there is overhead of going +% through \xintiTrunc1.| +% \begin{macrocode} +\def\XINTinFloatPowerH {\romannumeral0\XINTinfloatpowerh }% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINTinfloatpowerh #1#2% +{% + \expandafter\XINT_flpowerh_a\romannumeral0\xintitrunc1{#2};% + \XINTdigits.{#1}{\XINTinfloatS[\XINTdigits]}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpowerh_a #1;% +{% + \if0\xintLDg{#1}\expandafter\XINT_flpowerh_int + \else\expandafter\XINT_flpowerh_b + \fi #1.% +}% +\def\XINT_flpowerh_int #1% +{% + \if0#1\expandafter\XINT_flpower_BisZero + \else\expandafter\XINT_flpowerh_i + \fi #1% +}% +\def\XINT_flpowerh_i #10.{\expandafter\XINT_flpower_checkB_a#1.}% +\def\XINT_flpowerh_b #1.% +{% + \expandafter\XINT_flpowerh_c\romannumeral0\xintdsrr{\xintDouble{#1}}.% +}% +\def\XINT_flpowerh_c #1.% +{% + \ifodd\xintLDg{#1} %<- intentional space + \expandafter\XINT_flpowerh_d\else\expandafter\XINT_flpowerh_e + \fi #1.% +}% +\def\XINT_flpowerh_d #1.\XINTdigits.#2#3% +{% + \XINT_flpower_checkB_a #1.\XINTdigits.{#2}\XINT_flpowerh_finish +}% +\def\XINT_flpowerh_finish #1% + {\XINTinfloatS[\XINTdigits]{\XINTinFloatSqrt[\XINTdigits+\xint_c_iii]{#1}}}% +\def\XINT_flpowerh_e #1.% + {\expandafter\XINT_flpower_checkB_a\romannumeral0\xinthalf{#1}.}% +% \end{macrocode} +% \lverb|Start of macro. Check for optional argument.| +% \begin{macrocode} +\def\XINT_flpower_chkopt #1#2% +{% + \ifx [#2\expandafter\XINT_flpower_opt + \else\expandafter\XINT_flpower_noopt + \fi + #1#2% +}% +\def\XINT_flpower_noopt #1#2\xint:#3% +{% + \expandafter\XINT_flpower_checkB_a + \romannumeral0\xintnum{#3}.\XINTdigits.{#2}{#1[\XINTdigits]}% +}% +\def\XINT_flpower_opt #1[\xint:#2]% +{% + \expandafter\XINT_flpower_opt_a\the\numexpr #2.#1% +}% +\def\XINT_flpower_opt_a #1.#2#3#4% +{% + \expandafter\XINT_flpower_checkB_a + \romannumeral0\xintnum{#4}.#1.{#3}{#2[#1]}% +}% +\def\XINT_flpower_checkB_a #1% +{% + \xint_UDzerominusfork + #1-{\XINT_flpower_BisZero 0}% + 0#1{\XINT_flpower_checkB_b -}% + 0-{\XINT_flpower_checkB_b {}#1}% + \krof +}% +\def\XINT_flpower_BisZero 0.#1.#2#3{#3{1[0]}}% +\def\XINT_flpower_checkB_b #1#2.#3.% +{% + \expandafter\XINT_flpower_checkB_c + \the\numexpr\xintLength{#2}+\xint_c_iii.#3.#2.{#1}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpower_checkB_c #1.#2.% +{% + \expandafter\XINT_flpower_checkB_d\the\numexpr#1+#2.#1.#2.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpower_checkB_d #1.#2.#3.#4.#5#6% +{% + \expandafter \XINT_flpower_aa + \romannumeral0\XINTinfloat [#3]{#6}{#2}{#1}{#4}{#5}% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flpower_aa #1[#2]#3% +{% + \expandafter\XINT_flpower_ab\the\numexpr #2-#3\expandafter.% + \romannumeral\XINT_rep #3\endcsname0.#1.% +}% +\def\XINT_flpower_ab #1.#2.#3.{\XINT_flpower_a #3#2[#1]}% +\def\XINT_flpower_a #1% +{% + \xint_UDzerominusfork + #1-\XINT_flpow_zero + 0#1{\XINT_flpower_b \iftrue}% + 0-{\XINT_flpower_b \iffalse#1}% + \krof +}% +\def\XINT_flpower_b #1#2[#3]#4#5% +{% + \XINT_flpower_loopI #5.#3.#2.#4.{#1\xintiiOdd{#5}\fi}% +}% +\def\XINT_flpower_loopI #1.% +{% + \if1\XINT_isOne {#1}\xint_dothis\XINT_flpower_ItoIII\fi + \ifodd\xintLDg{#1} %<- intentional space + \xint_dothis{\expandafter\XINT_flpower_loopI_odd}\fi + \xint_orthat{\expandafter\XINT_flpower_loopI_even}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \romannumeral0\XINT_half + #1\xint_bye\xint_Bye345678\xint_bye + *\xint_c_v+\xint_c_v)/\xint_c_x-\xint_c_i\relax.% +}% +\def\XINT_flpower_ItoIII #1.#2.#3.#4.#5% +{% + \expandafter\XINT_flpow_III\the\numexpr #5+\xint_c_.#2.#3.#4.% +}% +\def\XINT_flpower_loopI_even #1.#2.#3.#4.% +{% + \expandafter\XINT_flpower_toloopI + \the\numexpr\expandafter\XINT_flpow_truncate + \the\numexpr\xint_c_ii*#2\expandafter.\romannumeral0\xintiisqr{#3}.#4.#1.% +}% +\def\XINT_flpower_toloopI #1.#2.#3.#4.{\XINT_flpower_loopI #4.#1.#2.#3.}% +\def\XINT_flpower_loopI_odd #1.#2.#3.#4.% +{% + \expandafter\XINT_flpower_toloopII + \the\numexpr\expandafter\XINT_flpow_truncate + \the\numexpr\xint_c_ii*#2\expandafter.\romannumeral0\xintiisqr{#3}.#4.% + #1.#2.#3.% +}% +\def\XINT_flpower_toloopII #1.#2.#3.#4.{\XINT_flpower_loopII #4.#1.#2.#3.}% +\def\XINT_flpower_loopII #1.% +{% + \if1\XINT_isOne{#1}\xint_dothis\XINT_flpower_IItoIII\fi + \ifodd\xintLDg{#1} %<- intentional space + \xint_dothis{\expandafter\XINT_flpower_loopII_odd}\fi + \xint_orthat{\expandafter\XINT_flpower_loopII_even}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} + \romannumeral0\XINT_half#1\xint_bye\xint_Bye345678\xint_bye + *\xint_c_v+\xint_c_v)/\xint_c_x-\xint_c_i\relax.% +}% +\def\XINT_flpower_loopII_even #1.#2.#3.#4.% +{% + \expandafter\XINT_flpower_toloopII + \the\numexpr\expandafter\XINT_flpow_truncate + \the\numexpr\xint_c_ii*#2\expandafter.\romannumeral0\xintiisqr{#3}.#4.#1.% +}% +\def\XINT_flpower_loopII_odd #1.#2.#3.#4.#5.#6.% +{% + \expandafter\XINT_flpower_loopII_odda + \the\numexpr\expandafter\XINT_flpow_truncate + \the\numexpr#2+#5\expandafter.\romannumeral0\xintiimul{#3}{#6}.#4.% + #1.#2.#3.% +}% +\def\XINT_flpower_loopII_odda #1.#2.#3.#4.#5.#6.% +{% + \expandafter\XINT_flpower_toloopII + \the\numexpr\expandafter\XINT_flpow_truncate + \the\numexpr\xint_c_ii*#5\expandafter.\romannumeral0\xintiisqr{#6}.#3.% + #4.#1.#2.% +}% +\def\XINT_flpower_IItoIII #1.#2.#3.#4.#5.#6.#7% +{% + \expandafter\XINT_flpow_III\the\numexpr #7+\xint_c_\expandafter.% + \the\numexpr\expandafter\XINT_flpow_truncate + \the\numexpr#2+#5\expandafter.\romannumeral0\xintiimul{#3}{#6}.#4.% +}% +% \end{macrocode} +% \subsection{\csh{xintFloatFac}, \csh{XINTFloatFac}} +% |Done at 1.2. At 1.3e \XINTinFloatFac outputs using \XINTinFloatS.| +% \begin{macrocode} +\def\xintFloatFac {\romannumeral0\xintfloatfac}% +\def\xintfloatfac #1{\XINT_flfac_chkopt \xintfloat #1\xint:}% +\def\XINTinFloatFac {\romannumeral0\XINTinfloatfac }% +\def\XINTinfloatfac #1{\XINT_flfac_chkopt \XINTinfloatS #1\xint:}% +\def\XINT_flfac_chkopt #1#2% +{% + \ifx [#2\expandafter\XINT_flfac_opt + \else\expandafter\XINT_flfac_noopt + \fi + #1#2% +}% +\def\XINT_flfac_noopt #1#2\xint: +{% + \expandafter\XINT_FL_fac_fork_a + \the\numexpr \xintNum{#2}.\xint_c_i \XINTdigits\XINT_FL_fac_out{#1[\XINTdigits]}% +}% +\def\XINT_flfac_opt #1[\xint:#2]% +{% + \expandafter\XINT_flfac_opt_a\the\numexpr #2.#1% +}% +\def\XINT_flfac_opt_a #1.#2#3% +{% + \expandafter\XINT_FL_fac_fork_a\the\numexpr \xintNum{#3}.\xint_c_i {#1}\XINT_FL_fac_out{#2[#1]}% +}% +\def\XINT_FL_fac_fork_a #1% +{% + \xint_UDzerominusfork + #1-\XINT_FL_fac_iszero + 0#1\XINT_FL_fac_isneg + 0-{\XINT_FL_fac_fork_b #1}% + \krof +}% +\def\XINT_FL_fac_iszero #1.#2#3#4#5{#5{1[0]}}% +% \end{macrocode} +% \lverb|1.2f XINT_FL_fac_isneg returns 0, earlier versions used 1 here.| +% \begin{macrocode} +\def\XINT_FL_fac_isneg #1.#2#3#4#5% +{% + #5{\XINT_signalcondition{InvalidOperation} + {Factorial of negative: (-#1)!}{}{0[0]}}% +}% +\def\XINT_FL_fac_fork_b #1.% +{% + \ifnum #1>\xint_c_x^viii_mone\xint_dothis\XINT_FL_fac_toobig\fi + \ifnum #1>\xint_c_x^iv\xint_dothis\XINT_FL_fac_vbig \fi + \ifnum #1>465 \xint_dothis\XINT_FL_fac_big\fi + \ifnum #1>101 \xint_dothis\XINT_FL_fac_med\fi + \xint_orthat\XINT_FL_fac_small + #1.% +}% +\def\XINT_FL_fac_toobig #1.#2#3#4#5% +{% + #5{\XINT_signalcondition{InvalidOperation} + {Factorial of too big: (#1)!}{}{0[0]}}% +}% +% \end{macrocode} +% \lverb?Computations are done with Q blocks of eight digits. When a +% multiplication has a carry, hence creates Q+1 blocks, the least significant +% one is dropped. The goal is to compute an approximate value X' to the exact +% value X, such that the final relative error (X-X')/X will be at most +% 10^{-P-1} with P the desired precision. Then, when we round X' to X'' with P +% significant digits, we can prove that the absolute error |X-X''| is bounded +% (strictly) by 0.6 ulp(X''). (ulp= unit in the last (significant) place). Let +% N be the number of such operations, the formula for Q deduces from the +% previous explanations is that 8Q should be at least P+9+k, with k the number +% of digits of N (in base 10). Note that 1.2 version used P+10+k, for 1.2f I +% reduced to P+9+k. Also, k should be the number of digits of the number N of +% multiplications done, hence for n<=10000 we can take N=n/2, or N/3, or N/4. +% This is rounded above by numexpr and always an overestimate of the actual +% number of approximate multiplications done (the first ones are exact). +% (vérifier ce que je raconte, j'ai la flemme là). +% +% We then want ceil((P+k+n)/8). Using \numexpr rounding division +% (ARRRRRGGGHHHH), if m is a positive integer, ceil(m/8) can be computed as +% (m+3)/8. Thus with m=P+10+k, this gives Q<-(P+13+k)/8. The routine actually +% computes 8(Q-1) for use in \XINT_FL_fac_addzeros. +% +% With 1.2f the formula is m=P+9+k, Q<-(P+12+k)/8, and we use now 4=12-8 rather +% than the earlier 5=13-8. Whatever happens, the value computed in +% \XINT_FL_fac_increaseP is at least 8. There will always be an extra block. +% +% Note: with Digits:=32; Maple gives for 200!:$bgroup$obeylines$obeyspaces$ttbfamily +% > factorial(200.); +% $indent 375 +% $indent 0.78865786736479050355236321393218 10 +% My 1.2f routine (and also 1.2) outputs: +% $indent 7.8865786736479050355236321393219e374 +% and this is the correct rounding because for 40 digits it computes +% $indent 7.886578673647905035523632139321850622951e374 +% $egroup +% Maple's result (contrarily to xint) is thus not the correct rounding but +% still it is less than 0.6 ulp wrong. +% ? +% \begin{macrocode} +\def\XINT_FL_fac_vbig + {\expandafter\XINT_FL_fac_vbigloop_a + \the\numexpr \XINT_FL_fac_increaseP \xint_c_i }% +\def\XINT_FL_fac_big + {\expandafter\XINT_FL_fac_bigloop_a + \the\numexpr \XINT_FL_fac_increaseP \xint_c_ii }% +\def\XINT_FL_fac_med + {\expandafter\XINT_FL_fac_medloop_a + \the\numexpr \XINT_FL_fac_increaseP \xint_c_iii }% +\def\XINT_FL_fac_small + {\expandafter\XINT_FL_fac_smallloop_a + \the\numexpr \XINT_FL_fac_increaseP \xint_c_iv }% +\def\XINT_FL_fac_increaseP #1#2.#3#4% +{% + #2\expandafter.\the\numexpr\xint_c_viii*% + ((\xint_c_iv+#4+\expandafter\XINT_FL_fac_countdigits + \the\numexpr #2/(#1*#3)\relax 87654321\Z)/\xint_c_viii).% +}% +\def\XINT_FL_fac_countdigits #1#2#3#4#5#6#7#8{\XINT_FL_fac_countdone }% +\def\XINT_FL_fac_countdone #1#2\Z {#1}% +\def\XINT_FL_fac_out #1;![#2]#3% + {#3{\romannumeral0\XINT_mul_out + #1;!1\R!1\R!1\R!1\R!% + 1\R!1\R!1\R!1\R!\W [#2]}}% +\def\XINT_FL_fac_vbigloop_a #1.#2.% +{% + \XINT_FL_fac_bigloop_a \xint_c_x^iv.#2.% + {\expandafter\XINT_FL_fac_vbigloop_loop\the\numexpr 100010001\expandafter.% + \the\numexpr \xint_c_x^viii+#1.}% +}% +\def\XINT_FL_fac_vbigloop_loop #1.#2.% +{% + \ifnum #1>#2 \expandafter\XINT_FL_fac_loop_exit\fi + \expandafter\XINT_FL_fac_vbigloop_loop + \the\numexpr #1+\xint_c_i\expandafter.% + \the\numexpr #2\expandafter.\the\numexpr\XINT_FL_fac_mul #1!% +}% +\def\XINT_FL_fac_bigloop_a #1.% +{% + \expandafter\XINT_FL_fac_bigloop_b \the\numexpr + #1+\xint_c_i-\xint_c_ii*((#1-464)/\xint_c_ii).#1.% +}% +\def\XINT_FL_fac_bigloop_b #1.#2.#3.% +{% + \expandafter\XINT_FL_fac_medloop_a + \the\numexpr #1-\xint_c_i.#3.{\XINT_FL_fac_bigloop_loop #1.#2.}% +}% +\def\XINT_FL_fac_bigloop_loop #1.#2.% +{% + \ifnum #1>#2 \expandafter\XINT_FL_fac_loop_exit\fi + \expandafter\XINT_FL_fac_bigloop_loop + \the\numexpr #1+\xint_c_ii\expandafter.% + \the\numexpr #2\expandafter.\the\numexpr\XINT_FL_fac_bigloop_mul #1!% +}% +\def\XINT_FL_fac_bigloop_mul #1!% +{% + \expandafter\XINT_FL_fac_mul + \the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)!% +}% +\def\XINT_FL_fac_medloop_a #1.% +{% + \expandafter\XINT_FL_fac_medloop_b + \the\numexpr #1+\xint_c_i-\xint_c_iii*((#1-100)/\xint_c_iii).#1.% +}% +\def\XINT_FL_fac_medloop_b #1.#2.#3.% +{% + \expandafter\XINT_FL_fac_smallloop_a + \the\numexpr #1-\xint_c_i.#3.{\XINT_FL_fac_medloop_loop #1.#2.}% +}% +\def\XINT_FL_fac_medloop_loop #1.#2.% +{% + \ifnum #1>#2 \expandafter\XINT_FL_fac_loop_exit\fi + \expandafter\XINT_FL_fac_medloop_loop + \the\numexpr #1+\xint_c_iii\expandafter.% + \the\numexpr #2\expandafter.\the\numexpr\XINT_FL_fac_medloop_mul #1!% +}% +\def\XINT_FL_fac_medloop_mul #1!% +{% + \expandafter\XINT_FL_fac_mul + \the\numexpr + \xint_c_x^viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% +}% +\def\XINT_FL_fac_smallloop_a #1.% +{% + \csname + XINT_FL_fac_smallloop_\the\numexpr #1-\xint_c_iv*(#1/\xint_c_iv)\relax + \endcsname #1.% +}% +\expandafter\def\csname XINT_FL_fac_smallloop_1\endcsname #1.#2.% +{% + \XINT_FL_fac_addzeros #2.100000001!.{2.#1.}{#2}% +}% +\expandafter\def\csname XINT_FL_fac_smallloop_-2\endcsname #1.#2.% +{% + \XINT_FL_fac_addzeros #2.100000002!.{3.#1.}{#2}% +}% +\expandafter\def\csname XINT_FL_fac_smallloop_-1\endcsname #1.#2.% +{% + \XINT_FL_fac_addzeros #2.100000006!.{4.#1.}{#2}% +}% +\expandafter\def\csname XINT_FL_fac_smallloop_0\endcsname #1.#2.% +{% + \XINT_FL_fac_addzeros #2.100000024!.{5.#1.}{#2}% +}% +\def\XINT_FL_fac_addzeros #1.% +{% + \ifnum #1=\xint_c_viii \expandafter\XINT_FL_fac_addzeros_exit\fi + \expandafter\XINT_FL_fac_addzeros + \the\numexpr #1-\xint_c_viii.100000000!% +}% +% \end{macrocode} +% \lverb|We will manipulate by successive *small* multiplications Q blocks +% 1<8d>!, terminated by 1;!. We need a custom small multiplication which +% tells us when it has create a new block, and the least significant one +% should be dropped.| +% \begin{macrocode} +\def\XINT_FL_fac_addzeros_exit #1.#2.#3#4{\XINT_FL_fac_smallloop_loop #3#21;![-#4]}% +\def\XINT_FL_fac_smallloop_loop #1.#2.% +{% + \ifnum #1>#2 \expandafter\XINT_FL_fac_loop_exit\fi + \expandafter\XINT_FL_fac_smallloop_loop + \the\numexpr #1+\xint_c_iv\expandafter.% + \the\numexpr #2\expandafter.\romannumeral0\XINT_FL_fac_smallloop_mul #1!% +}% +\def\XINT_FL_fac_smallloop_mul #1!% +{% + \expandafter\XINT_FL_fac_mul + \the\numexpr + \xint_c_x^viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% +}%[[ +\def\XINT_FL_fac_loop_exit #1!#2]#3{#3#2]}% +\def\XINT_FL_fac_mul 1#1!% + {\expandafter\XINT_FL_fac_mul_a\the\numexpr\XINT_FL_fac_smallmul 10!{#1}}% +\def\XINT_FL_fac_mul_a #1-#2% +{% + \if#21\xint_afterfi{\expandafter\space\xint_gob_til_exclam}\else + \expandafter\space\fi #11;!% +}% +\def\XINT_FL_fac_minimulwc_a #1#2#3#4#5!#6#7#8#9% +{% + \XINT_FL_fac_minimulwc_b {#1#2#3#4}{#5}{#6#7#8#9}% +}% +\def\XINT_FL_fac_minimulwc_b #1#2#3#4!#5% +{% + \expandafter\XINT_FL_fac_minimulwc_c + \the\numexpr \xint_c_x^ix+#5+#2*#4!{{#1}{#2}{#3}{#4}}% +}% +\def\XINT_FL_fac_minimulwc_c 1#1#2#3#4#5#6!#7% +{% + \expandafter\XINT_FL_fac_minimulwc_d {#1#2#3#4#5}#7{#6}% +}% +\def\XINT_FL_fac_minimulwc_d #1#2#3#4#5% +{% + \expandafter\XINT_FL_fac_minimulwc_e + \the\numexpr \xint_c_x^ix+#1+#2*#5+#3*#4!{#2}{#4}% +}% +\def\XINT_FL_fac_minimulwc_e 1#1#2#3#4#5#6!#7#8#9% +{% + 1#6#9\expandafter!% + \the\numexpr\expandafter\XINT_FL_fac_smallmul + \the\numexpr \xint_c_x^viii+#1#2#3#4#5+#7*#8!% +}% +\def\XINT_FL_fac_smallmul 1#1!#21#3!% +{% + \xint_gob_til_sc #3\XINT_FL_fac_smallmul_end;% + \XINT_FL_fac_minimulwc_a #2!#3!{#1}{#2}% +}% +% \end{macrocode} +% \lverb|This is the crucial ending. I note that I used here an \ifnum test +% rather than the gob_til_eightzeroes thing. Actually for eight digits there +% is much less difference than for only four. +% +% The "carry" situation is marked by a final !-1 rather than !-2 for no-carry. +% (a \numexpr muste be stopped, and leaving a - as delimiter is good as it +% will not arise earlier.)| +% \begin{macrocode} +\def\XINT_FL_fac_smallmul_end;\XINT_FL_fac_minimulwc_a #1!;!#2#3[#4]% +{% + \ifnum #2=\xint_c_ + \expandafter\xint_firstoftwo\else + \expandafter\xint_secondoftwo + \fi + {-2\relax[#4]}% + {1#2\expandafter!\expandafter-\expandafter1\expandafter + [\the\numexpr #4+\xint_c_viii]}% +}% +% \end{macrocode} +% \subsection{\csh{xintFloatPFactorial}, \csh{XINTinFloatPFactorial}} +% \lverb|2015/11/29 for 1.2f. Partial factorial pfactorial(a,b)=(a+1)...b, +% only for non-negative integers with a<=b<10^8. +% +% 1.2h (2016/11/20) now avoids raising \xintError:OutOfRangePFac if the +% condition 0<=a<=b<10^8 is violated. Same as for \xintiiPFactorial.| +% \begin{macrocode} +\def\xintFloatPFactorial {\romannumeral0\xintfloatpfactorial}% +\def\xintfloatpfactorial #1{\XINT_flpfac_chkopt \xintfloat #1\xint:}% +\def\XINTinFloatPFactorial {\romannumeral0\XINTinfloatpfactorial }% +\def\XINTinfloatpfactorial #1{\XINT_flpfac_chkopt \XINTinfloat #1\xint:}% +\def\XINT_flpfac_chkopt #1#2% +{% + \ifx [#2\expandafter\XINT_flpfac_opt + \else\expandafter\XINT_flpfac_noopt + \fi + #1#2% +}% +\def\XINT_flpfac_noopt #1#2\xint:#3% +{% + \expandafter\XINT_FL_pfac_fork + \the\numexpr \xintNum{#2}\expandafter.% + \the\numexpr \xintNum{#3}.\xint_c_i{\XINTdigits}{#1[\XINTdigits]}% +}% +\def\XINT_flpfac_opt #1[\xint:#2]% +{% + \expandafter\XINT_flpfac_opt_b\the\numexpr #2.#1% +}% +\def\XINT_flpfac_opt_b #1.#2#3#4% +{% + \expandafter\XINT_FL_pfac_fork + \the\numexpr \xintNum{#3}\expandafter.% + \the\numexpr \xintNum{#4}.\xint_c_i{#1}{#2[#1]}% +}% +\def\XINT_FL_pfac_fork #1#2.#3#4.% +{% + \unless\ifnum #1#2<#3#4 \xint_dothis\XINT_FL_pfac_one\fi + \if-#3\xint_dothis\XINT_FL_pfac_neg \fi + \if-#1\xint_dothis\XINT_FL_pfac_zero\fi + \ifnum #3#4>\xint_c_x^viii_mone\xint_dothis\XINT_FL_pfac_outofrange\fi + \xint_orthat \XINT_FL_pfac_increaseP #1#2.#3#4.% +}% +\def\XINT_FL_pfac_outofrange #1.#2.#3#4#5% +{% + #5{\XINT_signalcondition{InvalidOperation} + {pfactorial second arg too big: 99999999 < #2}{}{0[0]}}% +}% +\def\XINT_FL_pfac_one #1.#2.#3#4#5{#5{1[0]}}% +\def\XINT_FL_pfac_zero #1.#2.#3#4#5{#5{0[0]}}% +\def\XINT_FL_pfac_neg -#1.-#2.% +{% + \ifnum #1>\xint_c_x^viii\xint_dothis\XINT_FL_pfac_outofrange\fi + \xint_orthat {% + \ifodd\numexpr#2-#1\relax\xint_afterfi{\expandafter-\romannumeral`&&@}\fi + \expandafter\XINT_FL_pfac_increaseP}% + \the\numexpr #2-\xint_c_i\expandafter.\the\numexpr#1-\xint_c_i.% +}% +% \end{macrocode} +% \lverb|See the comments for \XINT_FL_pfac_increaseP. Case of b=a+1 should be +% filtered out perhaps. We only needed here to copy the \xintPFactorial macros and +% re-use \XINT_FL_fac_mul/\XINT_FL_fac_out. Had to modify a bit +% \XINT_FL_pfac_addzeroes. We can enter here directly with #3 equal to specify +% the precision (the calculated value before final rounding has a relative +% error less than #3.10^{-#4-1}), and #5 would hold the macro doing the final +% rounding (or truncating, if I make a FloatTrunc available) to a given number +% of digits, possibly not #4. By default the #3 is 1, but FloatBinomial calls +% it with #3=4.| +% \begin{macrocode} +\def\XINT_FL_pfac_increaseP #1.#2.#3#4% +{% + \expandafter\XINT_FL_pfac_a + \the\numexpr \xint_c_viii*((\xint_c_iv+#4+\expandafter + \XINT_FL_fac_countdigits\the\numexpr (#2-#1-\xint_c_i)% + /\ifnum #2>\xint_c_x^iv #3\else(#3*\xint_c_ii)\fi\relax + 87654321\Z)/\xint_c_viii).#1.#2.% +}% +\def\XINT_FL_pfac_a #1.#2.#3.% +{% + \expandafter\XINT_FL_pfac_b\the\numexpr \xint_c_i+#2\expandafter.% + \the\numexpr#3\expandafter.% + \romannumeral0\XINT_FL_pfac_addzeroes #1.100000001!1;![-#1]% +}% +\def\XINT_FL_pfac_addzeroes #1.% +{% + \ifnum #1=\xint_c_viii \expandafter\XINT_FL_pfac_addzeroes_exit\fi + \expandafter\XINT_FL_pfac_addzeroes\the\numexpr #1-\xint_c_viii.100000000!% +}% +\def\XINT_FL_pfac_addzeroes_exit #1.{ }% +\def\XINT_FL_pfac_b #1.% +{% + \ifnum #1>9999 \xint_dothis\XINT_FL_pfac_vbigloop \fi + \ifnum #1>463 \xint_dothis\XINT_FL_pfac_bigloop \fi + \ifnum #1>98 \xint_dothis\XINT_FL_pfac_medloop \fi + \xint_orthat\XINT_FL_pfac_smallloop #1.% +}% +\def\XINT_FL_pfac_smallloop #1.#2.% +{% + \ifcase\numexpr #2-#1\relax + \expandafter\XINT_FL_pfac_end_ + \or \expandafter\XINT_FL_pfac_end_i + \or \expandafter\XINT_FL_pfac_end_ii + \or \expandafter\XINT_FL_pfac_end_iii + \else\expandafter\XINT_FL_pfac_smallloop_a + \fi #1.#2.% +}% +\def\XINT_FL_pfac_smallloop_a #1.#2.% +{% + \expandafter\XINT_FL_pfac_smallloop_b + \the\numexpr #1+\xint_c_iv\expandafter.% + \the\numexpr #2\expandafter.% + \romannumeral0\expandafter\XINT_FL_fac_mul + \the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% +}% +\def\XINT_FL_pfac_smallloop_b #1.% +{% + \ifnum #1>98 \expandafter\XINT_FL_pfac_medloop \else + \expandafter\XINT_FL_pfac_smallloop \fi #1.% +}% +\def\XINT_FL_pfac_medloop #1.#2.% +{% + \ifcase\numexpr #2-#1\relax + \expandafter\XINT_FL_pfac_end_ + \or \expandafter\XINT_FL_pfac_end_i + \or \expandafter\XINT_FL_pfac_end_ii + \else\expandafter\XINT_FL_pfac_medloop_a + \fi #1.#2.% +}% +\def\XINT_FL_pfac_medloop_a #1.#2.% +{% + \expandafter\XINT_FL_pfac_medloop_b + \the\numexpr #1+\xint_c_iii\expandafter.% + \the\numexpr #2\expandafter.% + \romannumeral0\expandafter\XINT_FL_fac_mul + \the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% +}% +\def\XINT_FL_pfac_medloop_b #1.% +{% + \ifnum #1>463 \expandafter\XINT_FL_pfac_bigloop \else + \expandafter\XINT_FL_pfac_medloop \fi #1.% +}% +\def\XINT_FL_pfac_bigloop #1.#2.% +{% + \ifcase\numexpr #2-#1\relax + \expandafter\XINT_FL_pfac_end_ + \or \expandafter\XINT_FL_pfac_end_i + \else\expandafter\XINT_FL_pfac_bigloop_a + \fi #1.#2.% +}% +\def\XINT_FL_pfac_bigloop_a #1.#2.% +{% + \expandafter\XINT_FL_pfac_bigloop_b + \the\numexpr #1+\xint_c_ii\expandafter.% + \the\numexpr #2\expandafter.% + \romannumeral0\expandafter\XINT_FL_fac_mul + \the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)!% +}% +\def\XINT_FL_pfac_bigloop_b #1.% +{% + \ifnum #1>9999 \expandafter\XINT_FL_pfac_vbigloop \else + \expandafter\XINT_FL_pfac_bigloop \fi #1.% +}% +\def\XINT_FL_pfac_vbigloop #1.#2.% +{% + \ifnum #2=#1 + \expandafter\XINT_FL_pfac_end_ + \else\expandafter\XINT_FL_pfac_vbigloop_a + \fi #1.#2.% +}% +\def\XINT_FL_pfac_vbigloop_a #1.#2.% +{% + \expandafter\XINT_FL_pfac_vbigloop + \the\numexpr #1+\xint_c_i\expandafter.% + \the\numexpr #2\expandafter.% + \romannumeral0\expandafter\XINT_FL_fac_mul + \the\numexpr\xint_c_x^viii+#1!% +}% +\def\XINT_FL_pfac_end_iii #1.#2.% +{% + \expandafter\XINT_FL_fac_out + \romannumeral0\expandafter\XINT_FL_fac_mul + \the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)*(#1+\xint_c_iii)!% +}% +\def\XINT_FL_pfac_end_ii #1.#2.% +{% + \expandafter\XINT_FL_fac_out + \romannumeral0\expandafter\XINT_FL_fac_mul + \the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)*(#1+\xint_c_ii)!% +}% +\def\XINT_FL_pfac_end_i #1.#2.% +{% + \expandafter\XINT_FL_fac_out + \romannumeral0\expandafter\XINT_FL_fac_mul + \the\numexpr \xint_c_x^viii+#1*(#1+\xint_c_i)!% +}% +\def\XINT_FL_pfac_end_ #1.#2.% +{% + \expandafter\XINT_FL_fac_out + \romannumeral0\expandafter\XINT_FL_fac_mul + \the\numexpr \xint_c_x^viii+#1!% +}% +% \end{macrocode} +% \subsection{\csh{xintFloatBinomial}, \csh{XINTinFloatBinomial}} +% \lverb|1.2f. We compute binomial(x,y) as pfac(x-y,x)/y!, where the numerator +% and denominator are computed with a relative error at most 4.10^{-P-2}, then +% rounded (once I have a float truncation, I will use truncation rather) to +% P+3 digits, and finally the quotient is correctly rounded to P digits. This +% will guarantee that the exact value X differs from the computed one Y by at +% most 0.6 ulp(Y). (2015/12/01). +% +% 2016/11/19 for 1.2h. As for \xintiiBinomial, hard to understand why last +% year I coded this to raise an error if y<0 or y>x ! The question of the +% Gamma function is for another occasion, here x and y must be (small) +% integers.| +% \begin{macrocode} +\def\xintFloatBinomial {\romannumeral0\xintfloatbinomial}% +\def\xintfloatbinomial #1{\XINT_flbinom_chkopt \xintfloat #1\xint:}% +\def\XINTinFloatBinomial {\romannumeral0\XINTinfloatbinomial }% +\def\XINTinfloatbinomial #1{\XINT_flbinom_chkopt \XINTinfloat #1\xint:}% +\def\XINT_flbinom_chkopt #1#2% +{% + \ifx [#2\expandafter\XINT_flbinom_opt + \else\expandafter\XINT_flbinom_noopt + \fi #1#2% +}% +\def\XINT_flbinom_noopt #1#2\xint:#3% +{% + \expandafter\XINT_FL_binom_a + \the\numexpr\xintNum{#2}\expandafter.\the\numexpr\xintNum{#3}.\XINTdigits.#1% +}% +\def\XINT_flbinom_opt #1[\xint:#2]#3#4% +{% + \expandafter\XINT_FL_binom_a + \the\numexpr\xintNum{#3}\expandafter.\the\numexpr\xintNum{#4}\expandafter.% + \the\numexpr #2.#1% +}% +\def\XINT_FL_binom_a #1.#2.% +{% + \expandafter\XINT_FL_binom_fork \the\numexpr #1-#2.#2.#1.% +}% +\def\XINT_FL_binom_fork #1#2.#3#4.#5#6.% +{% + \if-#5\xint_dothis \XINT_FL_binom_neg\fi + \if-#1\xint_dothis \XINT_FL_binom_zero\fi + \if-#3\xint_dothis \XINT_FL_binom_zero\fi + \if0#1\xint_dothis \XINT_FL_binom_one\fi + \if0#3\xint_dothis \XINT_FL_binom_one\fi + \ifnum #5#6>\xint_c_x^viii_mone \xint_dothis\XINT_FL_binom_toobig\fi + \ifnum #1#2>#3#4 \xint_dothis\XINT_FL_binom_ab \fi + \xint_orthat\XINT_FL_binom_aa + #1#2.#3#4.#5#6.% +}% +\def\XINT_FL_binom_neg #1.#2.#3.#4.#5% +{% + #5[#4]{\XINT_signalcondition{InvalidOperation} + {binomial with first arg negative: #3}{}{0[0]}}% +}% +\def\XINT_FL_binom_toobig #1.#2.#3.#4.#5% +{% + #5[#4]{\XINT_signalcondition{InvalidOperation} + {binomial with first arg too big: 99999999 < #3}{}{0[0]}}% +}% +\def\XINT_FL_binom_one #1.#2.#3.#4.#5{#5[#4]{1[0]}}% +\def\XINT_FL_binom_zero #1.#2.#3.#4.#5{#5[#4]{0[0]}}% +% \end{macrocode} +% \begin{macrocode} +\def\XINT_FL_binom_aa #1.#2.#3.#4.#5% +{% + #5[#4]{\xintDiv{\XINT_FL_pfac_increaseP + #2.#3.\xint_c_iv{#4+\xint_c_i}{\XINTinfloat[#4+\xint_c_iii]}}% + {\XINT_FL_fac_fork_b + #1.\xint_c_iv{#4+\xint_c_i}\XINT_FL_fac_out{\XINTinfloat[#4+\xint_c_iii]}}}% +}% +\def\XINT_FL_binom_ab #1.#2.#3.#4.#5% +{% + #5[#4]{\xintDiv{\XINT_FL_pfac_increaseP + #1.#3.\xint_c_iv{#4+\xint_c_i}{\XINTinfloat[#4+\xint_c_iii]}}% + {\XINT_FL_fac_fork_b + #2.\xint_c_iv{#4+\xint_c_i}\XINT_FL_fac_out{\XINTinfloat[#4+\xint_c_iii]}}}% +}% +% \end{macrocode} +% \subsection{\csh{xintFloatSqrt}, \csh{XINTinFloatSqrt}} +% \lverb|First done for 1.08. +% +% The float version was developed at the same time as the integer one and even +% a bit earlier. As a result the integer variant had some sub-optimal parts. +% Anyway, for 1.2f I have rewritten the integer variant, and the float variant +% delegates all preparatory wrok for it until the last step. In particular the +% very low precisions are not penalized anymore from doing computations for at +% least 17 or 18 digits. Both the large and small precisions give quite +% shorter computation times. +% +% Also, after examining more closely the achieved precision I decided to +% extend the float version in order for it to obtain the correct rounding (for +% inputs already of at most P digits with P the precision) of the theoretical +% exact value. +% +% Beyond about 500 digits of precision the efficiency decreases swiftly, +% as is the case generally speaking with xintcore/xint/xintfrac arithmetic +% macros. +% +% Final note: with 1.2f the input is always first rounded to P significant +% places. +% +% +% | +% \begin{macrocode} +\def\xintFloatSqrt {\romannumeral0\xintfloatsqrt }% +\def\xintfloatsqrt #1{\XINT_flsqrt_chkopt \xintfloat #1\xint:}% +\def\XINTinFloatSqrt {\romannumeral0\XINTinfloatsqrt }% +\def\XINTinfloatsqrt #1{\XINT_flsqrt_chkopt \XINTinfloat #1\xint:}% +\def\XINT_flsqrt_chkopt #1#2% +{% + \ifx [#2\expandafter\XINT_flsqrt_opt + \else\expandafter\XINT_flsqrt_noopt + \fi #1#2% +}% +\def\XINT_flsqrt_noopt #1#2\xint:% +{% + \expandafter\XINT_FL_sqrt_a + \romannumeral0\XINTinfloat[\XINTdigits]{#2}\XINTdigits.#1% +}% +\def\XINT_flsqrt_opt #1[\xint:#2]%#3% +{% + \expandafter\XINT_flsqrt_opt_a\the\numexpr #2.#1% +}% +\def\XINT_flsqrt_opt_a #1.#2#3% +{% + \expandafter\XINT_FL_sqrt_a\romannumeral0\XINTinfloat[#1]{#3}#1.#2% +}% +\def\XINT_FL_sqrt_a #1% +{% + \xint_UDzerominusfork + #1-\XINT_FL_sqrt_iszero + 0#1\XINT_FL_sqrt_isneg + 0-{\XINT_FL_sqrt_pos #1}% + \krof +}%[ +\def\XINT_FL_sqrt_iszero #1]#2.#3{#3[#2]{0[0]}}% +\def\XINT_FL_sqrt_isneg #1]#2.#3% +{% + #3[#2]{\XINT_signalcondition{InvalidOperation} + {Square root of negative: -#1]}{}{0[0]}}% +}% +% \end{macrocode} +%\lverb|& +% | +% \begin{macrocode} +\def\XINT_FL_sqrt_pos #1[#2]#3.% +{% + \expandafter\XINT_flsqrt + \the\numexpr #3\ifodd #2 \xint_dothis {+\xint_c_iii.(#2+\xint_c_i).0}\fi + \xint_orthat {+\xint_c_ii.#2.{}}#100.#3.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flsqrt #1.#2.% +{% + \expandafter\XINT_flsqrt_a + \the\numexpr #2/\xint_c_ii-(#1-\xint_c_i)/\xint_c_ii.#1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flsqrt_a #1.#2.#3#4.#5.% +{% + \expandafter\XINT_flsqrt_b + \the\numexpr (#2-\xint_c_i)/\xint_c_ii\expandafter.% + \romannumeral0\XINT_sqrt_start #2.#4#3.#5.#2.#4#3.#5.#1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flsqrt_b #1.#2#3% +{% + \expandafter\XINT_flsqrt_c + \romannumeral0\xintiisub + {\XINT_dsx_addzeros {#1}#2;}% + {\xintiiDivRound{\XINT_dsx_addzeros {#1}#3;}% + {\XINT_dbl#2\xint_bye2345678\xint_bye*\xint_c_ii\relax}}.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flsqrt_c #1.#2.% +{% + \expandafter\XINT_flsqrt_d + \romannumeral0\XINT_split_fromleft#2.#1\xint_bye2345678\xint_bye..% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flsqrt_d #1.#2#3.% +{% + \ifnum #2=\xint_c_v + \expandafter\XINT_flsqrt_f\else\expandafter\XINT_flsqrt_finish\fi + #2#3.#1.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flsqrt_finish #1#2.#3.#4.#5.#6.#7.#8{#8[#6]{#3#1[#7]}}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flsqrt_f 5#1.% + {\expandafter\XINT_flsqrt_g\romannumeral0\xintinum{#1}\relax.}% +\def\XINT_flsqrt_g #1#2#3.{\if\relax#2\xint_dothis{\XINT_flsqrt_h #1}\fi + \xint_orthat{\XINT_flsqrt_finish 5.}}% +\def\XINT_flsqrt_h #1{\ifnum #1<\xint_c_iii\xint_dothis{\XINT_flsqrt_again}\fi + \xint_orthat{\XINT_flsqrt_finish 5.}}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flsqrt_again #1.#2.% +{% + \expandafter\XINT_flsqrt_again_a\the\numexpr #2+\xint_c_viii.% +}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_flsqrt_again_a #1.#2.#3.% +{% + \expandafter\XINT_flsqrt_b + \the\numexpr (#1-\xint_c_i)/\xint_c_ii\expandafter.% + \romannumeral0\XINT_sqrt_start #1.#200000000.#3.% + #1.#200000000.#3.% +}% +% \end{macrocode} +% \subsection{\csh{xintFloatE}, \csh{XINTinFloatE}} +% \lverb|1.07: The fraction is the first argument contrarily to \xintTrunc and +% \xintRound. +% +% 1.2k had to rewrite this since there is no more a \XINT_float_a macro. +% Attention about \XINTinFloatE: it is for use by xintexpr.sty, contrarily to +% other \XINTinFloat<foo> macros it inserts itself the [\XINTdigits] thing, +% and with value 0 it produces on output 0[N], not 0[0]. +% | +% \begin{macrocode} +\def\xintFloatE {\romannumeral0\xintfloate }% +\def\xintfloate #1{\XINT_floate_chkopt #1\xint:}% +\def\XINT_floate_chkopt #1% +{% + \ifx [#1\expandafter\XINT_floate_opt + \else\expandafter\XINT_floate_noopt + \fi #1% +}% +\def\XINT_floate_noopt #1\xint:% +{% + \expandafter\XINT_floate_post + \romannumeral0\XINTinfloat[\XINTdigits]{#1}\XINTdigits.% +}% +\def\XINT_floate_opt [\xint:#1]% +{% + \expandafter\XINT_floate_opt_a\the\numexpr #1.% +}% +\def\XINT_floate_opt_a #1.#2% +{% + \expandafter\XINT_floate_post + \romannumeral0\XINTinfloat[#1]{#2}#1.% +}% +\def\XINT_floate_post #1% +{% + \xint_UDzerominusfork + #1-\XINT_floate_zero + 0#1\XINT_floate_neg + 0-\XINT_floate_pos + \krof #1% +}%[ +\def\XINT_floate_zero #1]#2.#3{ 0.e0}% +\def\XINT_floate_neg-{\expandafter-\romannumeral0\XINT_floate_pos}% +% \end{macrocode} +% \lverb|& +% | +% \begin{macrocode} +\def\XINT_floate_pos #1#2[#3]#4.#5% +{% + \expandafter\XINT_float_pos_done\the\numexpr#3+#4+#5-\xint_c_i.#1.#2;% +}% +\def\XINTinFloatE {\romannumeral0\XINTinfloate }% +\def\XINTinfloate + {\expandafter\XINT_infloate\romannumeral0\XINTinfloat[\XINTdigits]}% +\def\XINT_infloate #1[#2]#3% + {\expandafter\XINT_infloate_end\the\numexpr #3+#2.{#1}}% +\def\XINT_infloate_end #1.#2{ #2[#1]}% +% \end{macrocode} +% \subsection{\csh{XINTinFloatMod}} +% \lverb|1.1. Pour emploi dans xintexpr. Code shortened at 1.2p.| +% \begin{macrocode} +\def\XINTinFloatMod {\romannumeral0\XINTinfloatmod [\XINTdigits]}% +\def\XINTinfloatmod [#1]#2#3% +{% + \XINTinfloat[#1]{\xintMod + {\romannumeral0\XINTinfloat[#1]{#2}}% + {\romannumeral0\XINTinfloat[#1]{#3}}}% +}% +% \end{macrocode} +% \subsection{\csh{XINTinFloatDivFloor}} +% \lverb|1.2p. Formerly // and /: in \xintfloatexpr used \xintDivFloor and +% \xintMod, hence did not round their operands to float precision beforehand.| +% \begin{macrocode} +\def\XINTinFloatDivFloor {\romannumeral0\XINTinfloatdivfloor [\XINTdigits]}% +\def\XINTinfloatdivfloor [#1]#2#3% +{% + \xintdivfloor + {\romannumeral0\XINTinfloat[#1]{#2}}% + {\romannumeral0\XINTinfloat[#1]{#3}}% +}% +% \end{macrocode} +% \subsection{\csh{XINTinFloatDivMod}} +% \lverb|1.2p. Pour emploi dans xintexpr, donc je ne prends pas la peine de +% faire l'expansion du modulo, qui se produira dans le \csname. +% +% Hésitation sur le quotient, faut-il l'arrondir immédiatement ? +% Finalement non, le produire comme un integer.| +% \begin{macrocode} +\def\XINTinFloatDivMod {\romannumeral0\XINTinfloatdivmod [\XINTdigits]}% +\def\XINTinfloatdivmod [#1]#2#3% +{% + \expandafter\XINT_infloatdivmod + \romannumeral0\xintdivmod + {\romannumeral0\XINTinfloat[#1]{#2}}% + {\romannumeral0\XINTinfloat[#1]{#3}}% + {#1}% +}% +\def\XINT_infloatdivmod #1#2#3{ #1,\XINTinFloat[#3]{#2}}% +% \end{macrocode} +% \subsection{\csh{xintifFloatInt}} +% \lverb|1.3a for ifint() function in \xintfloatexpr.| +% \begin{macrocode} +\def\xintifFloatInt {\romannumeral0\xintiffloatint}% +\def\xintiffloatint #1{\expandafter\XINT_iffloatint + \romannumeral0\xintrez{\XINTinFloat[\XINTdigits]{#1}}}% +\def\XINT_iffloatint #1#2/1[#3]% +{% + \if 0#1\xint_dothis\xint_stop_atfirstoftwo\fi + \ifnum#3<\xint_c_\xint_dothis\xint_stop_atsecondoftwo\fi + \xint_orthat\xint_stop_atfirstoftwo +}% +% \end{macrocode} +% \subsection{\csh{xintFloatIsInt}} +% \lverb|1.3d for isint() function in \xintfloatexpr.| +% \begin{macrocode} +\def\xintFloatIsInt {\romannumeral0\xintfloatisint}% +\def\xintfloatisint #1{\expandafter\XINT_iffloatint + \romannumeral0\xintrez{\XINTinFloat[\XINTdigits]{#1}}10}% +% \end{macrocode} +% \subsection{(WIP) \csh{XINTinRandomFloatS}, \csh{XINTinRandomFloatSdigits}} +% \lverb|1.3b. Support for random() function. +% +% Thus as it is a priori only for xintexpr usage, it expands inside \csname +% context, but as we need to get rid of initial zeros we use \xintRandomDigits +% not \xintXRandomDigits (\expanded would have a use case here). +% +% And anyway as we want to be able to use random() in +% \xintdeffunc/\xintNewExpr, it is good to have f-expandable macros, so we add +% the small overhead to make it f-expandable. +% +% We don't have to be very efficient in removing leading zeroes, as there is +% only 10$% +% chance for each successive one. Besides we use (current) internal storage +% format of the type A[N], where A is not required to be with \xintDigits +% digits, so N will simply be -\xintDigits and needs no adjustment. +% +% In case we use in future with #1 something else than \xintDigits we do +% the 0-(#1) construct. +% +% I had some qualms about doing a random float like this which means that +% when there are leading zeros in the random digits the (virtual) mantissa +% ends up with trailing zeros. That did not feel right but I checked random() +% in Python (which of course uses radix 2), and indeed this is what happens +% there. +% +% | +% \begin{macrocode} +\def\XINTinRandomFloatS{\romannumeral0\XINTinrandomfloatS}% +\def\XINTinRandomFloatSdigits{\XINTinRandomFloatS[\XINTdigits]}% +\def\XINTinrandomfloatS[#1]% +{% + \expandafter\XINT_inrandomfloatS\the\numexpr\xint_c_-(#1)\xint: +}% +\def\XINT_inrandomfloatS-#1\xint: +{% + \expandafter\XINT_inrandomfloatS_a + \romannumeral0\xintrandomdigits{#1}[-#1]% +}% +% \end{macrocode} +% \lverb|We add one macro to handle a tiny bit faster 90% of cases, after all +% we also use one extra macro for the completely improbable all 0 case.| +% \begin{macrocode} +\def\XINT_inrandomfloatS_a#1% +{% + \if#10\xint_dothis{\XINT_inrandomfloatS_b}\fi + \xint_orthat{ #1}% +}%[ +\def\XINT_inrandomfloatS_b#1% +{% + \if#1[\xint_dothis{\XINT_inrandomfloatS_zero}\fi% ] + \if#10\xint_dothis{\XINT_inrandomfloatS_b}\fi + \xint_orthat{ #1}% +}%[ +\def\XINT_inrandomfloatS_zero#1]{ 0[0]}% +% \end{macrocode} +% \subsection{(WIP) \csh{XINTinRandomFloatSixteen}} +% \lverb|1.3b. Support for qrand() function.| +% \begin{macrocode} +\def\XINTinRandomFloatSixteen% +{% + \romannumeral0\expandafter\XINT_inrandomfloatS_a + \romannumeral`&&@\expandafter\XINT_eightrandomdigits + \romannumeral`&&@\XINT_eightrandomdigits[-16]% +}% +\XINT_restorecatcodes_endinput% +% \end{macrocode} +% \StoreCodelineNo {xintfrac} +% \cleardoublepage\let\xintfracnameUp\undefined +%\gardesactifs +%\let</xintfrac>\relax +%\let<*xintseries>\gardesinactifs +%</xintfrac>^^A--------------------------------------------------- +%<*xintseries>^^A------------------------------------------------- +%^^A -*- coding: utf-8; mode: doctex; -*- +% \clearpage\csname xintseriesnameUp\endcsname +% \section{Package \xintseriesnameimp implementation} +% \RaisedLabel{sec:seriesimp} +% +% \localtableofcontents +% +% The commenting is currently (\xintdocdate) very sparse. +% +% \subsection{Catcodes, \protect\eTeX{} and reload detection} +% +% The code for reload detection was initially copied from \textsc{Heiko +% Oberdiek}'s packages, then modified. +% +% The method for catcodes was also initially directly inspired by these +% packages. +% +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode64=11 % @ + \catcode35=6 % # + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \let\z\endgroup + \expandafter\let\expandafter\x\csname ver@xintseries.sty\endcsname + \expandafter\let\expandafter\w\csname ver@xintfrac.sty\endcsname + \expandafter + \ifx\csname PackageInfo\endcsname\relax + \def\y#1#2{\immediate\write-1{Package #1 Info: #2.}}% + \else + \def\y#1#2{\PackageInfo{#1}{#2}}% + \fi + \expandafter + \ifx\csname numexpr\endcsname\relax + \y{xintseries}{\numexpr not available, aborting input}% + \aftergroup\endinput + \else + \ifx\x\relax % plain-TeX, first loading of xintseries.sty + \ifx\w\relax % but xintfrac.sty not yet loaded. + \def\z{\endgroup\input xintfrac.sty\relax}% + \fi + \else + \def\empty {}% + \ifx\x\empty % LaTeX, first loading, + % variable is initialized, but \ProvidesPackage not yet seen + \ifx\w\relax % xintfrac.sty not yet loaded. + \def\z{\endgroup\RequirePackage{xintfrac}}% + \fi + \else + \aftergroup\endinput % xintseries already loaded. + \fi + \fi + \fi +\z% +\XINTsetupcatcodes% defined in xintkernel.sty +% \end{macrocode} +% \subsection{Package identification} +% \begin{macrocode} +\XINT_providespackage +\ProvidesPackage{xintseries}% + [2019/04/05 1.3e Expandable partial sums with xint package (JFB)]% +% \end{macrocode} +% \subsection{\csh{xintSeries}} +% \begin{macrocode} +\def\xintSeries {\romannumeral0\xintseries }% +\def\xintseries #1#2% +{% + \expandafter\XINT_series\expandafter + {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% +}% +\def\XINT_series #1#2#3% +{% + \ifnum #2<#1 + \xint_afterfi { 0/1[0]}% + \else + \xint_afterfi {\XINT_series_loop {#1}{0}{#2}{#3}}% + \fi +}% +\def\XINT_series_loop #1#2#3#4% +{% + \ifnum #3>#1 \else \XINT_series_exit \fi + \expandafter\XINT_series_loop\expandafter + {\the\numexpr #1+1\expandafter }\expandafter + {\romannumeral0\xintadd {#2}{#4{#1}}}% + {#3}{#4}% +}% +\def\XINT_series_exit \fi #1#2#3#4#5#6#7#8% +{% + \fi\xint_gobble_ii #6% +}% +% \end{macrocode} +% \subsection{\csh{xintiSeries}} +% \begin{macrocode} +\def\xintiSeries {\romannumeral0\xintiseries }% +\def\xintiseries #1#2% +{% + \expandafter\XINT_iseries\expandafter + {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% +}% +\def\XINT_iseries #1#2#3% +{% + \ifnum #2<#1 + \xint_afterfi { 0}% + \else + \xint_afterfi {\XINT_iseries_loop {#1}{0}{#2}{#3}}% + \fi +}% +\def\XINT_iseries_loop #1#2#3#4% +{% + \ifnum #3>#1 \else \XINT_iseries_exit \fi + \expandafter\XINT_iseries_loop\expandafter + {\the\numexpr #1+1\expandafter }\expandafter + {\romannumeral0\xintiiadd {#2}{#4{#1}}}% + {#3}{#4}% +}% +\def\XINT_iseries_exit \fi #1#2#3#4#5#6#7#8% +{% + \fi\xint_gobble_ii #6% +}% +% \end{macrocode} +% \subsection{\csh{xintPowerSeries}} +% \lverb|& +% The 1.03 version was very lame and created a build-up of denominators. +% (this was at a time \xintAdd always multiplied denominators, by the way) +% The Horner scheme for polynomial evaluation is used in 1.04, this +% cures the denominator problem and drastically improves the efficiency +% of the macro. +% Modified in 1.06 to give the indices first to a \numexpr rather than expanding +% twice. I just use \the\numexpr and maintain the previous code after that. +% 1.08a adds the forgotten optimization following that previous change.| +% \begin{macrocode} +\def\xintPowerSeries {\romannumeral0\xintpowerseries }% +\def\xintpowerseries #1#2% +{% + \expandafter\XINT_powseries\expandafter + {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% +}% +\def\XINT_powseries #1#2#3#4% +{% + \ifnum #2<#1 + \xint_afterfi { 0/1[0]}% + \else + \xint_afterfi + {\XINT_powseries_loop_i {#3{#2}}{#1}{#2}{#3}{#4}}% + \fi +}% +\def\XINT_powseries_loop_i #1#2#3#4#5% +{% + \ifnum #3>#2 \else\XINT_powseries_exit_i\fi + \expandafter\XINT_powseries_loop_ii\expandafter + {\the\numexpr #3-1\expandafter}\expandafter + {\romannumeral0\xintmul {#1}{#5}}{#2}{#4}{#5}% +}% +\def\XINT_powseries_loop_ii #1#2#3#4% +{% + \expandafter\XINT_powseries_loop_i\expandafter + {\romannumeral0\xintadd {#4{#1}}{#2}}{#3}{#1}{#4}% +}% +\def\XINT_powseries_exit_i\fi #1#2#3#4#5#6#7#8#9% +{% + \fi \XINT_powseries_exit_ii #6{#7}% +}% +\def\XINT_powseries_exit_ii #1#2#3#4#5#6% +{% + \xintmul{\xintPow {#5}{#6}}{#4}% +}% +% \end{macrocode} +% \subsection{\csh{xintPowerSeriesX}} +% \lverb|& +% Same as \xintPowerSeries except for the initial expansion of the x parameter. +% Modified in 1.06 to give the indices first to a \numexpr rather than expanding +% twice. I just use \the\numexpr and maintain the previous code after that. +% 1.08a adds the forgotten optimization following that previous change.| +% \begin{macrocode} +\def\xintPowerSeriesX {\romannumeral0\xintpowerseriesx }% +\def\xintpowerseriesx #1#2% +{% + \expandafter\XINT_powseriesx\expandafter + {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% +}% +\def\XINT_powseriesx #1#2#3#4% +{% + \ifnum #2<#1 + \xint_afterfi { 0/1[0]}% + \else + \xint_afterfi + {\expandafter\XINT_powseriesx_pre\expandafter + {\romannumeral`&&@#4}{#1}{#2}{#3}% + }% + \fi +}% +\def\XINT_powseriesx_pre #1#2#3#4% +{% + \XINT_powseries_loop_i {#4{#3}}{#2}{#3}{#4}{#1}% +}% +% \end{macrocode} +% \subsection{\csh{xintRationalSeries}} +% \lverb|& +% This computes F(a)+...+F(b) on the basis of the value of F(a) and the +% ratios F(n)/F(n-1). As in \xintPowerSeries we use an iterative scheme which +% has the great advantage to avoid denominator build-up. This makes exact +% computations possible with exponential type series, which would be completely +% inaccessible to \xintSeries. +% #1=a, #2=b, #3=F(a), #4=ratio function +% Modified in 1.06 to give the indices first to a \numexpr rather than expanding +% twice. I just use \the\numexpr and maintain the previous code after that. +% 1.08a adds the forgotten optimization following that previous change.| +% \begin{macrocode} +\def\xintRationalSeries {\romannumeral0\xintratseries }% +\def\xintratseries #1#2% +{% + \expandafter\XINT_ratseries\expandafter + {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% +}% +\def\XINT_ratseries #1#2#3#4% +{% + \ifnum #2<#1 + \xint_afterfi { 0/1[0]}% + \else + \xint_afterfi + {\XINT_ratseries_loop {#2}{1}{#1}{#4}{#3}}% + \fi +}% +\def\XINT_ratseries_loop #1#2#3#4% +{% + \ifnum #1>#3 \else\XINT_ratseries_exit_i\fi + \expandafter\XINT_ratseries_loop\expandafter + {\the\numexpr #1-1\expandafter}\expandafter + {\romannumeral0\xintadd {1}{\xintMul {#2}{#4{#1}}}}{#3}{#4}% +}% +\def\XINT_ratseries_exit_i\fi #1#2#3#4#5#6#7#8% +{% + \fi \XINT_ratseries_exit_ii #6% +}% +\def\XINT_ratseries_exit_ii #1#2#3#4#5% +{% + \XINT_ratseries_exit_iii #5% +}% +\def\XINT_ratseries_exit_iii #1#2#3#4% +{% + \xintmul{#2}{#4}% +}% +% \end{macrocode} +% \subsection{\csh{xintRationalSeriesX}} +% \lverb|& +% a,b,initial,ratiofunction,x$\ +% This computes F(a,x)+...+F(b,x) on the basis of the value of F(a,x) and the +% ratios F(n,x)/F(n-1,x). The argument x is first expanded and it is the value +% resulting from this which is used then throughout. The initial term F(a,x) +% must be defined as one-parameter macro which will be given x. +% Modified in 1.06 to give the indices first to a \numexpr rather than expanding +% twice. I just use \the\numexpr and maintain the previous code after that. +% 1.08a adds the forgotten optimization following that previous change.| +% \begin{macrocode} +\def\xintRationalSeriesX {\romannumeral0\xintratseriesx }% +\def\xintratseriesx #1#2% +{% + \expandafter\XINT_ratseriesx\expandafter + {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% +}% +\def\XINT_ratseriesx #1#2#3#4#5% +{% + \ifnum #2<#1 + \xint_afterfi { 0/1[0]}% + \else + \xint_afterfi + {\expandafter\XINT_ratseriesx_pre\expandafter + {\romannumeral`&&@#5}{#2}{#1}{#4}{#3}% + }% + \fi +}% +\def\XINT_ratseriesx_pre #1#2#3#4#5% +{% + \XINT_ratseries_loop {#2}{1}{#3}{#4{#1}}{#5{#1}}% +}% +% \end{macrocode} +% \subsection{\csh{xintFxPtPowerSeries}} +% \lverb|& +% I am not two happy with this piece of code. Will make it more economical +% another day. +% Modified in 1.06 to give the indices first to a \numexpr rather than expanding +% twice. I just use \the\numexpr and maintain the previous code after that. +% 1.08a: forgot last time some optimization from the change to \numexpr.| +% \begin{macrocode} +\def\xintFxPtPowerSeries {\romannumeral0\xintfxptpowerseries }% +\def\xintfxptpowerseries #1#2% +{% + \expandafter\XINT_fppowseries\expandafter + {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% +}% +\def\XINT_fppowseries #1#2#3#4#5% +{% + \ifnum #2<#1 + \xint_afterfi { 0}% + \else + \xint_afterfi + {\expandafter\XINT_fppowseries_loop_pre\expandafter + {\romannumeral0\xinttrunc {#5}{\xintPow {#4}{#1}}}% + {#1}{#4}{#2}{#3}{#5}% + }% + \fi +}% +\def\XINT_fppowseries_loop_pre #1#2#3#4#5#6% +{% + \ifnum #4>#2 \else\XINT_fppowseries_dont_i \fi + \expandafter\XINT_fppowseries_loop_i\expandafter + {\the\numexpr #2+\xint_c_i\expandafter}\expandafter + {\romannumeral0\xintitrunc {#6}{\xintMul {#5{#2}}{#1}}}% + {#1}{#3}{#4}{#5}{#6}% +}% +\def\XINT_fppowseries_dont_i \fi\expandafter\XINT_fppowseries_loop_i + {\fi \expandafter\XINT_fppowseries_dont_ii }% +\def\XINT_fppowseries_dont_ii #1#2#3#4#5#6#7{\xinttrunc {#7}{#2[-#7]}}% +\def\XINT_fppowseries_loop_i #1#2#3#4#5#6#7% +{% + \ifnum #5>#1 \else \XINT_fppowseries_exit_i \fi + \expandafter\XINT_fppowseries_loop_ii\expandafter + {\romannumeral0\xinttrunc {#7}{\xintMul {#3}{#4}}}% + {#1}{#4}{#2}{#5}{#6}{#7}% +}% +\def\XINT_fppowseries_loop_ii #1#2#3#4#5#6#7% +{% + \expandafter\XINT_fppowseries_loop_i\expandafter + {\the\numexpr #2+\xint_c_i\expandafter}\expandafter + {\romannumeral0\xintiiadd {#4}{\xintiTrunc {#7}{\xintMul {#6{#2}}{#1}}}}% + {#1}{#3}{#5}{#6}{#7}% +}% +\def\XINT_fppowseries_exit_i\fi\expandafter\XINT_fppowseries_loop_ii + {\fi \expandafter\XINT_fppowseries_exit_ii }% +\def\XINT_fppowseries_exit_ii #1#2#3#4#5#6#7% +{% + \xinttrunc {#7} + {\xintiiadd {#4}{\xintiTrunc {#7}{\xintMul {#6{#2}}{#1}}}[-#7]}% +}% +% \end{macrocode} +% \subsection{\csh{xintFxPtPowerSeriesX}} +% \lverb|& +% a,b,coeff,x,D$\ +% Modified in 1.06 to give the indices first to a \numexpr rather than expanding +% twice. I just use \the\numexpr and maintain the previous code after that. +% 1.08a adds the forgotten optimization following that previous change.| +% \begin{macrocode} +\def\xintFxPtPowerSeriesX {\romannumeral0\xintfxptpowerseriesx }% +\def\xintfxptpowerseriesx #1#2% +{% + \expandafter\XINT_fppowseriesx\expandafter + {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% +}% +\def\XINT_fppowseriesx #1#2#3#4#5% +{% + \ifnum #2<#1 + \xint_afterfi { 0}% + \else + \xint_afterfi + {\expandafter \XINT_fppowseriesx_pre \expandafter + {\romannumeral`&&@#4}{#1}{#2}{#3}{#5}% + }% + \fi +}% +\def\XINT_fppowseriesx_pre #1#2#3#4#5% +{% + \expandafter\XINT_fppowseries_loop_pre\expandafter + {\romannumeral0\xinttrunc {#5}{\xintPow {#1}{#2}}}% + {#2}{#1}{#3}{#4}{#5}% +}% +% \end{macrocode} +% \subsection{\csh{xintFloatPowerSeries}} +% \lverb|1.08a. I still have to re-visit \xintFxPtPowerSeries; temporarily I +% just adapted the code to the case of floats.| +% \begin{macrocode} +\def\xintFloatPowerSeries {\romannumeral0\xintfloatpowerseries }% +\def\xintfloatpowerseries #1{\XINT_flpowseries_chkopt #1\xint:}% +\def\XINT_flpowseries_chkopt #1% +{% + \ifx [#1\expandafter\XINT_flpowseries_opt + \else\expandafter\XINT_flpowseries_noopt + \fi + #1% +}% +\def\XINT_flpowseries_noopt #1\xint:#2% +{% + \expandafter\XINT_flpowseries\expandafter + {\the\numexpr #1\expandafter}\expandafter + {\the\numexpr #2}\XINTdigits +}% +\def\XINT_flpowseries_opt [\xint:#1]#2#3% +{% + \expandafter\XINT_flpowseries\expandafter + {\the\numexpr #2\expandafter}\expandafter + {\the\numexpr #3\expandafter}{\the\numexpr #1}% +}% +\def\XINT_flpowseries #1#2#3#4#5% +{% + \ifnum #2<#1 + \xint_afterfi { 0.e0}% + \else + \xint_afterfi + {\expandafter\XINT_flpowseries_loop_pre\expandafter + {\romannumeral0\XINTinfloatpow [#3]{#5}{#1}}% + {#1}{#5}{#2}{#4}{#3}% + }% + \fi +}% +\def\XINT_flpowseries_loop_pre #1#2#3#4#5#6% +{% + \ifnum #4>#2 \else\XINT_flpowseries_dont_i \fi + \expandafter\XINT_flpowseries_loop_i\expandafter + {\the\numexpr #2+\xint_c_i\expandafter}\expandafter + {\romannumeral0\XINTinfloatmul [#6]{#5{#2}}{#1}}% + {#1}{#3}{#4}{#5}{#6}% +}% +\def\XINT_flpowseries_dont_i \fi\expandafter\XINT_flpowseries_loop_i + {\fi \expandafter\XINT_flpowseries_dont_ii }% +\def\XINT_flpowseries_dont_ii #1#2#3#4#5#6#7{\xintfloat [#7]{#2}}% +\def\XINT_flpowseries_loop_i #1#2#3#4#5#6#7% +{% + \ifnum #5>#1 \else \XINT_flpowseries_exit_i \fi + \expandafter\XINT_flpowseries_loop_ii\expandafter + {\romannumeral0\XINTinfloatmul [#7]{#3}{#4}}% + {#1}{#4}{#2}{#5}{#6}{#7}% +}% +\def\XINT_flpowseries_loop_ii #1#2#3#4#5#6#7% +{% + \expandafter\XINT_flpowseries_loop_i\expandafter + {\the\numexpr #2+\xint_c_i\expandafter}\expandafter + {\romannumeral0\XINTinfloatadd [#7]{#4}% + {\XINTinfloatmul [#7]{#6{#2}}{#1}}}% + {#1}{#3}{#5}{#6}{#7}% +}% +\def\XINT_flpowseries_exit_i\fi\expandafter\XINT_flpowseries_loop_ii + {\fi \expandafter\XINT_flpowseries_exit_ii }% +\def\XINT_flpowseries_exit_ii #1#2#3#4#5#6#7% +{% + \xintfloatadd [#7]{#4}{\XINTinfloatmul [#7]{#6{#2}}{#1}}% +}% +% \end{macrocode} +% \subsection{\csh{xintFloatPowerSeriesX}} +% \lverb|1.08a| +% \begin{macrocode} +\def\xintFloatPowerSeriesX {\romannumeral0\xintfloatpowerseriesx }% +\def\xintfloatpowerseriesx #1{\XINT_flpowseriesx_chkopt #1\xint:}% +\def\XINT_flpowseriesx_chkopt #1% +{% + \ifx [#1\expandafter\XINT_flpowseriesx_opt + \else\expandafter\XINT_flpowseriesx_noopt + \fi + #1% +}% +\def\XINT_flpowseriesx_noopt #1\xint:#2% +{% + \expandafter\XINT_flpowseriesx\expandafter + {\the\numexpr #1\expandafter}\expandafter + {\the\numexpr #2}\XINTdigits +}% +\def\XINT_flpowseriesx_opt [\xint:#1]#2#3% +{% + \expandafter\XINT_flpowseriesx\expandafter + {\the\numexpr #2\expandafter}\expandafter + {\the\numexpr #3\expandafter}{\the\numexpr #1}% +}% +\def\XINT_flpowseriesx #1#2#3#4#5% +{% + \ifnum #2<#1 + \xint_afterfi { 0.e0}% + \else + \xint_afterfi + {\expandafter \XINT_flpowseriesx_pre \expandafter + {\romannumeral`&&@#5}{#1}{#2}{#4}{#3}% + }% + \fi +}% +\def\XINT_flpowseriesx_pre #1#2#3#4#5% +{% + \expandafter\XINT_flpowseries_loop_pre\expandafter + {\romannumeral0\XINTinfloatpow [#5]{#1}{#2}}% + {#2}{#1}{#3}{#4}{#5}% +}% +\XINT_restorecatcodes_endinput% +% \end{macrocode} +% \StoreCodelineNo {xintseries} +% \cleardoublepage\let\xintseriesnameUp\undefined +%\gardesactifs +%\let</xintseries>\relax +%\let<*xintcfrac>\gardesinactifs +%</xintseries>^^A------------------------------------------------- +%<*xintcfrac>^^A-------------------------------------------------- +%^^A -*- coding: utf-8; mode: doctex; -*- +% \clearpage\csname xintcfracnameUp\endcsname +% \section{Package \xintcfracnameimp implementation} +% \RaisedLabel{sec:cfracimp} +% +% \localtableofcontents +% +% The commenting is currently (\xintdocdate) very sparse. Release |1.09m| +% (|2014/02/26|) has modified a few things: |\xintFtoCs| and +% |\xintCntoCs| insert spaces after the commas, |\xintCstoF| and +% |\xintCstoCv| authorize spaces in the input also before the commas, +% |\xintCntoCs| does not brace the produced coefficients, new macros +% |\xintFtoC|, |\xintCtoF|, |\xintCtoCv|, |\xintFGtoC|, and +% |\xintGGCFrac|. +% +% There is partial dependency on \xinttoolsnameimp due to |\xintCstoF| and +% |\xintCsToCv|. +% +% \subsection{Catcodes, \protect\eTeX{} and reload detection} +% +% The code for reload detection was initially copied from \textsc{Heiko +% Oberdiek}'s packages, then modified. +% +% The method for catcodes was also initially directly inspired by these +% packages. +% +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode64=11 % @ + \catcode35=6 % # + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \let\z\endgroup + \expandafter\let\expandafter\x\csname ver@xintcfrac.sty\endcsname + \expandafter\let\expandafter\w\csname ver@xintfrac.sty\endcsname + \expandafter + \ifx\csname PackageInfo\endcsname\relax + \def\y#1#2{\immediate\write-1{Package #1 Info: #2.}}% + \else + \def\y#1#2{\PackageInfo{#1}{#2}}% + \fi + \expandafter + \ifx\csname numexpr\endcsname\relax + \y{xintcfrac}{\numexpr not available, aborting input}% + \aftergroup\endinput + \else + \ifx\x\relax % plain-TeX, first loading of xintcfrac.sty + \ifx\w\relax % but xintfrac.sty not yet loaded. + \def\z{\endgroup\input xintfrac.sty\relax}% + \fi + \else + \def\empty {}% + \ifx\x\empty % LaTeX, first loading, + % variable is initialized, but \ProvidesPackage not yet seen + \ifx\w\relax % xintfrac.sty not yet loaded. + \def\z{\endgroup\RequirePackage{xintfrac}}% + \fi + \else + \aftergroup\endinput % xintcfrac already loaded. + \fi + \fi + \fi +\z% +\XINTsetupcatcodes% defined in xintkernel.sty +% \end{macrocode} +% \subsection{Package identification} +% \begin{macrocode} +\XINT_providespackage +\ProvidesPackage{xintcfrac}% + [2019/04/05 1.3e Expandable continued fractions with xint package (JFB)]% +% \end{macrocode} +% \subsection{\csh{xintCFrac}} +% \begin{macrocode} +\def\xintCFrac {\romannumeral0\xintcfrac }% +\def\xintcfrac #1% +{% + \XINT_cfrac_opt_a #1\xint: +}% +\def\XINT_cfrac_opt_a #1% +{% + \ifx[#1\XINT_cfrac_opt_b\fi \XINT_cfrac_noopt #1% +}% +\def\XINT_cfrac_noopt #1\xint: +{% + \expandafter\XINT_cfrac_A\romannumeral0\xintrawwithzeros {#1}\Z + \relax\relax +}% +\def\XINT_cfrac_opt_b\fi\XINT_cfrac_noopt [\xint:#1]% +{% + \fi\csname XINT_cfrac_opt#1\endcsname +}% +\def\XINT_cfrac_optl #1% +{% + \expandafter\XINT_cfrac_A\romannumeral0\xintrawwithzeros {#1}\Z + \relax\hfill +}% +\def\XINT_cfrac_optc #1% +{% + \expandafter\XINT_cfrac_A\romannumeral0\xintrawwithzeros {#1}\Z + \relax\relax +}% +\def\XINT_cfrac_optr #1% +{% + \expandafter\XINT_cfrac_A\romannumeral0\xintrawwithzeros {#1}\Z + \hfill\relax +}% +\def\XINT_cfrac_A #1/#2\Z +{% + \expandafter\XINT_cfrac_B\romannumeral0\xintiidivision {#1}{#2}{#2}% +}% +\def\XINT_cfrac_B #1#2% +{% + \XINT_cfrac_C #2\Z {#1}% +}% +\def\XINT_cfrac_C #1% +{% + \xint_gob_til_zero #1\XINT_cfrac_integer 0\XINT_cfrac_D #1% +}% +\def\XINT_cfrac_integer 0\XINT_cfrac_D 0#1\Z #2#3#4#5{ #2}% +\def\XINT_cfrac_D #1\Z #2#3{\XINT_cfrac_loop_a {#1}{#3}{#1}{{#2}}}% +\def\XINT_cfrac_loop_a +{% + \expandafter\XINT_cfrac_loop_d\romannumeral0\XINT_div_prepare +}% +\def\XINT_cfrac_loop_d #1#2% +{% + \XINT_cfrac_loop_e #2.{#1}% +}% +\def\XINT_cfrac_loop_e #1% +{% + \xint_gob_til_zero #1\xint_cfrac_loop_exit0\XINT_cfrac_loop_f #1% +}% +\def\XINT_cfrac_loop_f #1.#2#3#4% +{% + \XINT_cfrac_loop_a {#1}{#3}{#1}{{#2}#4}% +}% +\def\xint_cfrac_loop_exit0\XINT_cfrac_loop_f #1.#2#3#4#5#6% + {\XINT_cfrac_T #5#6{#2}#4\Z }% +\def\XINT_cfrac_T #1#2#3#4% +{% + \xint_gob_til_Z #4\XINT_cfrac_end\Z\XINT_cfrac_T #1#2{#4+\cfrac{#11#2}{#3}}% +}% +\def\XINT_cfrac_end\Z\XINT_cfrac_T #1#2#3% +{% + \XINT_cfrac_end_b #3% +}% +\def\XINT_cfrac_end_b \Z+\cfrac#1#2{ #2}% +% \end{macrocode} +% \subsection{\csh{xintGCFrac}} +% \begin{macrocode} +\def\xintGCFrac {\romannumeral0\xintgcfrac }% +\def\xintgcfrac #1{\XINT_gcfrac_opt_a #1\xint:}% +\def\XINT_gcfrac_opt_a #1% +{% + \ifx[#1\XINT_gcfrac_opt_b\fi \XINT_gcfrac_noopt #1% +}% +\def\XINT_gcfrac_noopt #1\xint:% +{% + \XINT_gcfrac #1+!/\relax\relax +}% +\def\XINT_gcfrac_opt_b\fi\XINT_gcfrac_noopt [\xint:#1]% +{% + \fi\csname XINT_gcfrac_opt#1\endcsname +}% +\def\XINT_gcfrac_optl #1% +{% + \XINT_gcfrac #1+!/\relax\hfill +}% +\def\XINT_gcfrac_optc #1% +{% + \XINT_gcfrac #1+!/\relax\relax +}% +\def\XINT_gcfrac_optr #1% +{% + \XINT_gcfrac #1+!/\hfill\relax +}% +\def\XINT_gcfrac +{% + \expandafter\XINT_gcfrac_enter\romannumeral`&&@% +}% +\def\XINT_gcfrac_enter {\XINT_gcfrac_loop {}}% +\def\XINT_gcfrac_loop #1#2+#3/% +{% + \xint_gob_til_exclam #3\XINT_gcfrac_endloop!% + \XINT_gcfrac_loop {{#3}{#2}#1}% +}% +\def\XINT_gcfrac_endloop!\XINT_gcfrac_loop #1#2#3% +{% + \XINT_gcfrac_T #2#3#1!!% +}% +\def\XINT_gcfrac_T #1#2#3#4{\XINT_gcfrac_U #1#2{\xintFrac{#4}}}% +\def\XINT_gcfrac_U #1#2#3#4#5% +{% + \xint_gob_til_exclam #5\XINT_gcfrac_end!\XINT_gcfrac_U + #1#2{\xintFrac{#5}% + \ifcase\xintSgn{#4} + +\or+\else-\fi + \cfrac{#1\xintFrac{\xintAbs{#4}}#2}{#3}}% +}% +\def\XINT_gcfrac_end!\XINT_gcfrac_U #1#2#3% +{% + \XINT_gcfrac_end_b #3% +}% +\def\XINT_gcfrac_end_b #1\cfrac#2#3{ #3}% +% \end{macrocode} +% \subsection{\csh{xintGGCFrac}} +% \lverb|New with 1.09m| +% \begin{macrocode} +\def\xintGGCFrac {\romannumeral0\xintggcfrac }% +\def\xintggcfrac #1{\XINT_ggcfrac_opt_a #1\xint:}% +\def\XINT_ggcfrac_opt_a #1% +{% + \ifx[#1\XINT_ggcfrac_opt_b\fi \XINT_ggcfrac_noopt #1% +}% +\def\XINT_ggcfrac_noopt #1\xint: +{% + \XINT_ggcfrac #1+!/\relax\relax +}% +\def\XINT_ggcfrac_opt_b\fi\XINT_ggcfrac_noopt [\xint:#1]% +{% + \fi\csname XINT_ggcfrac_opt#1\endcsname +}% +\def\XINT_ggcfrac_optl #1% +{% + \XINT_ggcfrac #1+!/\relax\hfill +}% +\def\XINT_ggcfrac_optc #1% +{% + \XINT_ggcfrac #1+!/\relax\relax +}% +\def\XINT_ggcfrac_optr #1% +{% + \XINT_ggcfrac #1+!/\hfill\relax +}% +\def\XINT_ggcfrac +{% + \expandafter\XINT_ggcfrac_enter\romannumeral`&&@% +}% +\def\XINT_ggcfrac_enter {\XINT_ggcfrac_loop {}}% +\def\XINT_ggcfrac_loop #1#2+#3/% +{% + \xint_gob_til_exclam #3\XINT_ggcfrac_endloop!% + \XINT_ggcfrac_loop {{#3}{#2}#1}% +}% +\def\XINT_ggcfrac_endloop!\XINT_ggcfrac_loop #1#2#3% +{% + \XINT_ggcfrac_T #2#3#1!!% +}% +\def\XINT_ggcfrac_T #1#2#3#4{\XINT_ggcfrac_U #1#2{#4}}% +\def\XINT_ggcfrac_U #1#2#3#4#5% +{% + \xint_gob_til_exclam #5\XINT_ggcfrac_end!\XINT_ggcfrac_U + #1#2{#5+\cfrac{#1#4#2}{#3}}% +}% +\def\XINT_ggcfrac_end!\XINT_ggcfrac_U #1#2#3% +{% + \XINT_ggcfrac_end_b #3% +}% +\def\XINT_ggcfrac_end_b #1\cfrac#2#3{ #3}% +% \end{macrocode} +% \subsection{\csh{xintGCtoGCx}} +% \begin{macrocode} +\def\xintGCtoGCx {\romannumeral0\xintgctogcx }% +\def\xintgctogcx #1#2#3% +{% + \expandafter\XINT_gctgcx_start\expandafter {\romannumeral`&&@#3}{#1}{#2}% +}% +\def\XINT_gctgcx_start #1#2#3{\XINT_gctgcx_loop_a {}{#2}{#3}#1+!/}% +\def\XINT_gctgcx_loop_a #1#2#3#4+#5/% +{% + \xint_gob_til_exclam #5\XINT_gctgcx_end!% + \XINT_gctgcx_loop_b {#1{#4}}{#2{#5}#3}{#2}{#3}% +}% +\def\XINT_gctgcx_loop_b #1#2% +{% + \XINT_gctgcx_loop_a {#1#2}% +}% +\def\XINT_gctgcx_end!\XINT_gctgcx_loop_b #1#2#3#4{ #1}% +% \end{macrocode} +% \subsection{\csh{xintFtoCs}} +% \lverb|Modified in 1.09m: a space is added after the inserted commas.| +% \begin{macrocode} +\def\xintFtoCs {\romannumeral0\xintftocs }% +\def\xintftocs #1% +{% + \expandafter\XINT_ftc_A\romannumeral0\xintrawwithzeros {#1}\Z +}% +\def\XINT_ftc_A #1/#2\Z +{% + \expandafter\XINT_ftc_B\romannumeral0\xintiidivision {#1}{#2}{#2}% +}% +\def\XINT_ftc_B #1#2% +{% + \XINT_ftc_C #2.{#1}% +}% +\def\XINT_ftc_C #1% +{% + \xint_gob_til_zero #1\XINT_ftc_integer 0\XINT_ftc_D #1% +}% +\def\XINT_ftc_integer 0\XINT_ftc_D 0#1.#2#3{ #2}% +\def\XINT_ftc_D #1.#2#3{\XINT_ftc_loop_a {#1}{#3}{#1}{#2, }}% 1.09m adds a space +\def\XINT_ftc_loop_a +{% + \expandafter\XINT_ftc_loop_d\romannumeral0\XINT_div_prepare +}% +\def\XINT_ftc_loop_d #1#2% +{% + \XINT_ftc_loop_e #2.{#1}% +}% +\def\XINT_ftc_loop_e #1% +{% + \xint_gob_til_zero #1\xint_ftc_loop_exit0\XINT_ftc_loop_f #1% +}% +\def\XINT_ftc_loop_f #1.#2#3#4% +{% + \XINT_ftc_loop_a {#1}{#3}{#1}{#4#2, }% 1.09m has an added space here +}% +\def\xint_ftc_loop_exit0\XINT_ftc_loop_f #1.#2#3#4{ #4#2}% +% \end{macrocode} +% \subsection{\csh{xintFtoCx}} +% \begin{macrocode} +\def\xintFtoCx {\romannumeral0\xintftocx }% +\def\xintftocx #1#2% +{% + \expandafter\XINT_ftcx_A\romannumeral0\xintrawwithzeros {#2}\Z {#1}% +}% +\def\XINT_ftcx_A #1/#2\Z +{% + \expandafter\XINT_ftcx_B\romannumeral0\xintiidivision {#1}{#2}{#2}% +}% +\def\XINT_ftcx_B #1#2% +{% + \XINT_ftcx_C #2.{#1}% +}% +\def\XINT_ftcx_C #1% +{% + \xint_gob_til_zero #1\XINT_ftcx_integer 0\XINT_ftcx_D #1% +}% +\def\XINT_ftcx_integer 0\XINT_ftcx_D 0#1.#2#3#4{ #2}% +\def\XINT_ftcx_D #1.#2#3#4{\XINT_ftcx_loop_a {#1}{#3}{#1}{{#2}#4}{#4}}% +\def\XINT_ftcx_loop_a +{% + \expandafter\XINT_ftcx_loop_d\romannumeral0\XINT_div_prepare +}% +\def\XINT_ftcx_loop_d #1#2% +{% + \XINT_ftcx_loop_e #2.{#1}% +}% +\def\XINT_ftcx_loop_e #1% +{% + \xint_gob_til_zero #1\xint_ftcx_loop_exit0\XINT_ftcx_loop_f #1% +}% +\def\XINT_ftcx_loop_f #1.#2#3#4#5% +{% + \XINT_ftcx_loop_a {#1}{#3}{#1}{#4{#2}#5}{#5}% +}% +\def\xint_ftcx_loop_exit0\XINT_ftcx_loop_f #1.#2#3#4#5{ #4{#2}}% +% \end{macrocode} +% \subsection{\csh{xintFtoC}} +% \lverb|New in 1.09m: this is the same as \xintFtoCx with empty separator. I +% had temporarily during preparation of 1.09m removed braces from \xintFtoCx, +% but I recalled later why that was useful (see doc), thus let's just here do +% \xintFtoCx {}| +% \begin{macrocode} +\def\xintFtoC {\romannumeral0\xintftoc }% +\def\xintftoc {\xintftocx {}}% +% \end{macrocode} +% \subsection{\csh{xintFtoGC}} +% \begin{macrocode} +\def\xintFtoGC {\romannumeral0\xintftogc }% +\def\xintftogc {\xintftocx {+1/}}% +% \end{macrocode} +% \subsection{\csh{xintFGtoC}} +% \lverb|New with 1.09m of 2014/02/26. Computes the common initial coefficients +% for the two fractions f and g, and outputs them as a sequence of braced +% items.| +% \begin{macrocode} +\def\xintFGtoC {\romannumeral0\xintfgtoc}% +\def\xintfgtoc#1% +{% + \expandafter\XINT_fgtc_a\romannumeral0\xintrawwithzeros {#1}\Z +}% +\def\XINT_fgtc_a #1/#2\Z #3% +{% + \expandafter\XINT_fgtc_b\romannumeral0\xintrawwithzeros {#3}\Z #1/#2\Z { }% +}% +\def\XINT_fgtc_b #1/#2\Z +{% + \expandafter\XINT_fgtc_c\romannumeral0\xintiidivision {#1}{#2}{#2}% +}% +\def\XINT_fgtc_c #1#2#3#4/#5\Z +{% + \expandafter\XINT_fgtc_d\romannumeral0\xintiidivision + {#4}{#5}{#5}{#1}{#2}{#3}% +}% +\def\XINT_fgtc_d #1#2#3#4%#5#6#7% +{% + \xintifEq {#1}{#4}{\XINT_fgtc_da {#1}{#2}{#3}{#4}}% + {\xint_thirdofthree}% +}% +\def\XINT_fgtc_da #1#2#3#4#5#6#7% +{% + \XINT_fgtc_e {#2}{#5}{#3}{#6}{#7{#1}}% +}% +\def\XINT_fgtc_e #1% +{% + \xintiiifZero {#1}{\expandafter\xint_firstofone\xint_gobble_iii}% + {\XINT_fgtc_f {#1}}% +}% +\def\XINT_fgtc_f #1#2% +{% + \xintiiifZero {#2}{\xint_thirdofthree}{\XINT_fgtc_g {#1}{#2}}% +}% +\def\XINT_fgtc_g #1#2#3% +{% + \expandafter\XINT_fgtc_h\romannumeral0\XINT_div_prepare {#1}{#3}{#1}{#2}% +}% +\def\XINT_fgtc_h #1#2#3#4#5% +{% + \expandafter\XINT_fgtc_d\romannumeral0\XINT_div_prepare + {#4}{#5}{#4}{#1}{#2}{#3}% +}% +% \end{macrocode} +% \subsection{\csh{xintFtoCC}} +% \begin{macrocode} +\def\xintFtoCC {\romannumeral0\xintftocc }% +\def\xintftocc #1% +{% + \expandafter\XINT_ftcc_A\expandafter {\romannumeral0\xintrawwithzeros {#1}}% +}% +\def\XINT_ftcc_A #1% +{% + \expandafter\XINT_ftcc_B + \romannumeral0\xintrawwithzeros {\xintAdd {1/2[0]}{#1[0]}}\Z {#1[0]}% +}% +\def\XINT_ftcc_B #1/#2\Z +{% + \expandafter\XINT_ftcc_C\expandafter {\romannumeral0\xintiiquo {#1}{#2}}% +}% +\def\XINT_ftcc_C #1#2% +{% + \expandafter\XINT_ftcc_D\romannumeral0\xintsub {#2}{#1}\Z {#1}% +}% +\def\XINT_ftcc_D #1% +{% + \xint_UDzerominusfork + #1-\XINT_ftcc_integer + 0#1\XINT_ftcc_En + 0-{\XINT_ftcc_Ep #1}% + \krof +}% +\def\XINT_ftcc_Ep #1\Z #2% +{% + \expandafter\XINT_ftcc_loop_a\expandafter + {\romannumeral0\xintdiv {1[0]}{#1}}{#2+1/}% +}% +\def\XINT_ftcc_En #1\Z #2% +{% + \expandafter\XINT_ftcc_loop_a\expandafter + {\romannumeral0\xintdiv {1[0]}{#1}}{#2+-1/}% +}% +\def\XINT_ftcc_integer #1\Z #2{ #2}% +\def\XINT_ftcc_loop_a #1% +{% + \expandafter\XINT_ftcc_loop_b + \romannumeral0\xintrawwithzeros {\xintAdd {1/2[0]}{#1}}\Z {#1}% +}% +\def\XINT_ftcc_loop_b #1/#2\Z +{% + \expandafter\XINT_ftcc_loop_c\expandafter + {\romannumeral0\xintiiquo {#1}{#2}}% +}% +\def\XINT_ftcc_loop_c #1#2% +{% + \expandafter\XINT_ftcc_loop_d + \romannumeral0\xintsub {#2}{#1[0]}\Z {#1}% +}% +\def\XINT_ftcc_loop_d #1% +{% + \xint_UDzerominusfork + #1-\XINT_ftcc_end + 0#1\XINT_ftcc_loop_N + 0-{\XINT_ftcc_loop_P #1}% + \krof +}% +\def\XINT_ftcc_end #1\Z #2#3{ #3#2}% +\def\XINT_ftcc_loop_P #1\Z #2#3% +{% + \expandafter\XINT_ftcc_loop_a\expandafter + {\romannumeral0\xintdiv {1[0]}{#1}}{#3#2+1/}% +}% +\def\XINT_ftcc_loop_N #1\Z #2#3% +{% + \expandafter\XINT_ftcc_loop_a\expandafter + {\romannumeral0\xintdiv {1[0]}{#1}}{#3#2+-1/}% +}% +% \end{macrocode} +% \subsection{\csh{xintCtoF}, \csh{xintCstoF}} +% \lverb|1.09m uses \xintCSVtoList on the argument of \xintCstoF to allow +% spaces also before the commas. And the original \xintCstoF code became the +% one of the new \xintCtoF dealing with a braced rather than comma separated +% list.| +% \begin{macrocode} +\def\xintCstoF {\romannumeral0\xintcstof }% +\def\xintcstof #1% +{% + \expandafter\XINT_ctf_prep \romannumeral0\xintcsvtolist{#1}!% +}% +\def\xintCtoF {\romannumeral0\xintctof }% +\def\xintctof #1% +{% + \expandafter\XINT_ctf_prep \romannumeral`&&@#1!% +}% +\def\XINT_ctf_prep +{% + \XINT_ctf_loop_a 1001% +}% +\def\XINT_ctf_loop_a #1#2#3#4#5% +{% + \xint_gob_til_exclam #5\XINT_ctf_end!% + \expandafter\XINT_ctf_loop_b + \romannumeral0\xintrawwithzeros {#5}.{#1}{#2}{#3}{#4}% +}% +\def\XINT_ctf_loop_b #1/#2.#3#4#5#6% +{% + \expandafter\XINT_ctf_loop_c\expandafter + {\romannumeral0\XINT_mul_fork #2\xint:#4\xint:}% + {\romannumeral0\XINT_mul_fork #2\xint:#3\xint:}% + {\romannumeral0\xintiiadd {\XINT_mul_fork #2\xint:#6\xint:}% + {\XINT_mul_fork #1\xint:#4\xint:}}% + {\romannumeral0\xintiiadd {\XINT_mul_fork #2\xint:#5\xint:}% + {\XINT_mul_fork #1\xint:#3\xint:}}% +}% +\def\XINT_ctf_loop_c #1#2% +{% + \expandafter\XINT_ctf_loop_d\expandafter {\expandafter{#2}{#1}}% +}% +\def\XINT_ctf_loop_d #1#2% +{% + \expandafter\XINT_ctf_loop_e\expandafter {\expandafter{#2}#1}% +}% +\def\XINT_ctf_loop_e #1#2% +{% + \expandafter\XINT_ctf_loop_a\expandafter{#2}#1% +}% +\def\XINT_ctf_end #1.#2#3#4#5{\xintrawwithzeros {#2/#3}}% 1.09b removes [0] +% \end{macrocode} +% \subsection{\csh{xintiCstoF}} +% \begin{macrocode} +\def\xintiCstoF {\romannumeral0\xinticstof }% +\def\xinticstof #1% +{% + \expandafter\XINT_icstf_prep \romannumeral`&&@#1,!,% +}% +\def\XINT_icstf_prep +{% + \XINT_icstf_loop_a 1001% +}% +\def\XINT_icstf_loop_a #1#2#3#4#5,% +{% + \xint_gob_til_exclam #5\XINT_icstf_end!% + \expandafter + \XINT_icstf_loop_b \romannumeral`&&@#5.{#1}{#2}{#3}{#4}% +}% +\def\XINT_icstf_loop_b #1.#2#3#4#5% +{% + \expandafter\XINT_icstf_loop_c\expandafter + {\romannumeral0\xintiiadd {#5}{\XINT_mul_fork #1\xint:#3\xint:}}% + {\romannumeral0\xintiiadd {#4}{\XINT_mul_fork #1\xint:#2\xint:}}% + {#2}{#3}% +}% +\def\XINT_icstf_loop_c #1#2% +{% + \expandafter\XINT_icstf_loop_a\expandafter {#2}{#1}% +}% +\def\XINT_icstf_end#1.#2#3#4#5{\xintrawwithzeros {#2/#3}}% 1.09b removes [0] +% \end{macrocode} +% \subsection{\csh{xintGCtoF}} +% \begin{macrocode} +\def\xintGCtoF {\romannumeral0\xintgctof }% +\def\xintgctof #1% +{% + \expandafter\XINT_gctf_prep \romannumeral`&&@#1+!/% +}% +\def\XINT_gctf_prep +{% + \XINT_gctf_loop_a 1001% +}% +\def\XINT_gctf_loop_a #1#2#3#4#5+% +{% + \expandafter\XINT_gctf_loop_b + \romannumeral0\xintrawwithzeros {#5}.{#1}{#2}{#3}{#4}% +}% +\def\XINT_gctf_loop_b #1/#2.#3#4#5#6% +{% + \expandafter\XINT_gctf_loop_c\expandafter + {\romannumeral0\XINT_mul_fork #2\xint:#4\xint:}% + {\romannumeral0\XINT_mul_fork #2\xint:#3\xint:}% + {\romannumeral0\xintiiadd {\XINT_mul_fork #2\xint:#6\xint:}% + {\XINT_mul_fork #1\xint:#4\xint:}}% + {\romannumeral0\xintiiadd {\XINT_mul_fork #2\xint:#5\xint:}% + {\XINT_mul_fork #1\xint:#3\xint:}}% +}% +\def\XINT_gctf_loop_c #1#2% +{% + \expandafter\XINT_gctf_loop_d\expandafter {\expandafter{#2}{#1}}% +}% +\def\XINT_gctf_loop_d #1#2% +{% + \expandafter\XINT_gctf_loop_e\expandafter {\expandafter{#2}#1}% +}% +\def\XINT_gctf_loop_e #1#2% +{% + \expandafter\XINT_gctf_loop_f\expandafter {\expandafter{#2}#1}% +}% +\def\XINT_gctf_loop_f #1#2/% +{% + \xint_gob_til_exclam #2\XINT_gctf_end!% + \expandafter\XINT_gctf_loop_g + \romannumeral0\xintrawwithzeros {#2}.#1% +}% +\def\XINT_gctf_loop_g #1/#2.#3#4#5#6% +{% + \expandafter\XINT_gctf_loop_h\expandafter + {\romannumeral0\XINT_mul_fork #1\xint:#6\xint:}% + {\romannumeral0\XINT_mul_fork #1\xint:#5\xint:}% + {\romannumeral0\XINT_mul_fork #2\xint:#4\xint:}% + {\romannumeral0\XINT_mul_fork #2\xint:#3\xint:}% +}% +\def\XINT_gctf_loop_h #1#2% +{% + \expandafter\XINT_gctf_loop_i\expandafter {\expandafter{#2}{#1}}% +}% +\def\XINT_gctf_loop_i #1#2% +{% + \expandafter\XINT_gctf_loop_j\expandafter {\expandafter{#2}#1}% +}% +\def\XINT_gctf_loop_j #1#2% +{% + \expandafter\XINT_gctf_loop_a\expandafter {#2}#1% +}% +\def\XINT_gctf_end #1.#2#3#4#5{\xintrawwithzeros {#2/#3}}% 1.09b removes [0] +% \end{macrocode} +% \subsection{\csh{xintiGCtoF}} +% \begin{macrocode} +\def\xintiGCtoF {\romannumeral0\xintigctof }% +\def\xintigctof #1% +{% + \expandafter\XINT_igctf_prep \romannumeral`&&@#1+!/% +}% +\def\XINT_igctf_prep +{% + \XINT_igctf_loop_a 1001% +}% +\def\XINT_igctf_loop_a #1#2#3#4#5+% +{% + \expandafter\XINT_igctf_loop_b + \romannumeral`&&@#5.{#1}{#2}{#3}{#4}% +}% +\def\XINT_igctf_loop_b #1.#2#3#4#5% +{% + \expandafter\XINT_igctf_loop_c\expandafter + {\romannumeral0\xintiiadd {#5}{\XINT_mul_fork #1\xint:#3\xint:}}% + {\romannumeral0\xintiiadd {#4}{\XINT_mul_fork #1\xint:#2\xint:}}% + {#2}{#3}% +}% +\def\XINT_igctf_loop_c #1#2% +{% + \expandafter\XINT_igctf_loop_f\expandafter {\expandafter{#2}{#1}}% +}% +\def\XINT_igctf_loop_f #1#2#3#4/% +{% + \xint_gob_til_exclam #4\XINT_igctf_end!% + \expandafter\XINT_igctf_loop_g + \romannumeral`&&@#4.{#2}{#3}#1% +}% +\def\XINT_igctf_loop_g #1.#2#3% +{% + \expandafter\XINT_igctf_loop_h\expandafter + {\romannumeral0\XINT_mul_fork #1\xint:#3\xint:}% + {\romannumeral0\XINT_mul_fork #1\xint:#2\xint:}% +}% +\def\XINT_igctf_loop_h #1#2% +{% + \expandafter\XINT_igctf_loop_i\expandafter {#2}{#1}% +}% +\def\XINT_igctf_loop_i #1#2#3#4% +{% + \XINT_igctf_loop_a {#3}{#4}{#1}{#2}% +}% +\def\XINT_igctf_end #1.#2#3#4#5{\xintrawwithzeros {#4/#5}}% 1.09b removes [0] +% \end{macrocode} +% \subsection{\csh{xintCtoCv}, \csh{xintCstoCv}} +% \lverb|1.09m uses \xintCSVtoList on the argument of \xintCstoCv to allow +% spaces also before the commas. The original \xintCstoCv code became the +% one of the new \xintCtoF dealing with a braced rather than comma separated +% list.| +% \begin{macrocode} +\def\xintCstoCv {\romannumeral0\xintcstocv }% +\def\xintcstocv #1% +{% + \expandafter\XINT_ctcv_prep\romannumeral0\xintcsvtolist{#1}!% +}% +\def\xintCtoCv {\romannumeral0\xintctocv }% +\def\xintctocv #1% +{% + \expandafter\XINT_ctcv_prep\romannumeral`&&@#1!% +}% +\def\XINT_ctcv_prep +{% + \XINT_ctcv_loop_a {}1001% +}% +\def\XINT_ctcv_loop_a #1#2#3#4#5#6% +{% + \xint_gob_til_exclam #6\XINT_ctcv_end!% + \expandafter\XINT_ctcv_loop_b + \romannumeral0\xintrawwithzeros {#6}.{#2}{#3}{#4}{#5}{#1}% +}% +\def\XINT_ctcv_loop_b #1/#2.#3#4#5#6% +{% + \expandafter\XINT_ctcv_loop_c\expandafter + {\romannumeral0\XINT_mul_fork #2\xint:#4\xint:}% + {\romannumeral0\XINT_mul_fork #2\xint:#3\xint:}% + {\romannumeral0\xintiiadd {\XINT_mul_fork #2\xint:#6\xint:}% + {\XINT_mul_fork #1\xint:#4\xint:}}% + {\romannumeral0\xintiiadd {\XINT_mul_fork #2\xint:#5\xint:}% + {\XINT_mul_fork #1\xint:#3\xint:}}% +}% +\def\XINT_ctcv_loop_c #1#2% +{% + \expandafter\XINT_ctcv_loop_d\expandafter {\expandafter{#2}{#1}}% +}% +\def\XINT_ctcv_loop_d #1#2% +{% + \expandafter\XINT_ctcv_loop_e\expandafter {\expandafter{#2}#1}% +}% +\def\XINT_ctcv_loop_e #1#2% +{% + \expandafter\XINT_ctcv_loop_f\expandafter{#2}#1% +}% +\def\XINT_ctcv_loop_f #1#2#3#4#5% +{% + \expandafter\XINT_ctcv_loop_g\expandafter + {\romannumeral0\xintrawwithzeros {#1/#2}}{#5}{#1}{#2}{#3}{#4}% +}% +\def\XINT_ctcv_loop_g #1#2{\XINT_ctcv_loop_a {#2{#1}}}% 1.09b removes [0] +\def\XINT_ctcv_end #1.#2#3#4#5#6{ #6}% +% \end{macrocode} +% \subsection{\csh{xintiCstoCv}} +% \begin{macrocode} +\def\xintiCstoCv {\romannumeral0\xinticstocv }% +\def\xinticstocv #1% +{% + \expandafter\XINT_icstcv_prep \romannumeral`&&@#1,!,% +}% +\def\XINT_icstcv_prep +{% + \XINT_icstcv_loop_a {}1001% +}% +\def\XINT_icstcv_loop_a #1#2#3#4#5#6,% +{% + \xint_gob_til_exclam #6\XINT_icstcv_end!% + \expandafter + \XINT_icstcv_loop_b \romannumeral`&&@#6.{#2}{#3}{#4}{#5}{#1}% +}% +\def\XINT_icstcv_loop_b #1.#2#3#4#5% +{% + \expandafter\XINT_icstcv_loop_c\expandafter + {\romannumeral0\xintiiadd {#5}{\XINT_mul_fork #1\xint:#3\xint:}}% + {\romannumeral0\xintiiadd {#4}{\XINT_mul_fork #1\xint:#2\xint:}}% + {{#2}{#3}}% +}% +\def\XINT_icstcv_loop_c #1#2% +{% + \expandafter\XINT_icstcv_loop_d\expandafter {#2}{#1}% +}% +\def\XINT_icstcv_loop_d #1#2% +{% + \expandafter\XINT_icstcv_loop_e\expandafter + {\romannumeral0\xintrawwithzeros {#1/#2}}{{#1}{#2}}% +}% +\def\XINT_icstcv_loop_e #1#2#3#4{\XINT_icstcv_loop_a {#4{#1}}#2#3}% +\def\XINT_icstcv_end #1.#2#3#4#5#6{ #6}% 1.09b removes [0] +% \end{macrocode} +% \subsection{\csh{xintGCtoCv}} +% \begin{macrocode} +\def\xintGCtoCv {\romannumeral0\xintgctocv }% +\def\xintgctocv #1% +{% + \expandafter\XINT_gctcv_prep \romannumeral`&&@#1+!/% +}% +\def\XINT_gctcv_prep +{% + \XINT_gctcv_loop_a {}1001% +}% +\def\XINT_gctcv_loop_a #1#2#3#4#5#6+% +{% + \expandafter\XINT_gctcv_loop_b + \romannumeral0\xintrawwithzeros {#6}.{#2}{#3}{#4}{#5}{#1}% +}% +\def\XINT_gctcv_loop_b #1/#2.#3#4#5#6% +{% + \expandafter\XINT_gctcv_loop_c\expandafter + {\romannumeral0\XINT_mul_fork #2\xint:#4\xint:}% + {\romannumeral0\XINT_mul_fork #2\xint:#3\xint:}% + {\romannumeral0\xintiiadd {\XINT_mul_fork #2\xint:#6\xint:}% + {\XINT_mul_fork #1\xint:#4\xint:}}% + {\romannumeral0\xintiiadd {\XINT_mul_fork #2\xint:#5\xint:}% + {\XINT_mul_fork #1\xint:#3\xint:}}% +}% +\def\XINT_gctcv_loop_c #1#2% +{% + \expandafter\XINT_gctcv_loop_d\expandafter {\expandafter{#2}{#1}}% +}% +\def\XINT_gctcv_loop_d #1#2% +{% + \expandafter\XINT_gctcv_loop_e\expandafter {\expandafter{#2}{#1}}% +}% +\def\XINT_gctcv_loop_e #1#2% +{% + \expandafter\XINT_gctcv_loop_f\expandafter {#2}#1% +}% +\def\XINT_gctcv_loop_f #1#2% +{% + \expandafter\XINT_gctcv_loop_g\expandafter + {\romannumeral0\xintrawwithzeros {#1/#2}}{{#1}{#2}}% +}% +\def\XINT_gctcv_loop_g #1#2#3#4% +{% + \XINT_gctcv_loop_h {#4{#1}}{#2#3}% 1.09b removes [0] +}% +\def\XINT_gctcv_loop_h #1#2#3/% +{% + \xint_gob_til_exclam #3\XINT_gctcv_end!% + \expandafter\XINT_gctcv_loop_i + \romannumeral0\xintrawwithzeros {#3}.#2{#1}% +}% +\def\XINT_gctcv_loop_i #1/#2.#3#4#5#6% +{% + \expandafter\XINT_gctcv_loop_j\expandafter + {\romannumeral0\XINT_mul_fork #1\xint:#6\xint:}% + {\romannumeral0\XINT_mul_fork #1\xint:#5\xint:}% + {\romannumeral0\XINT_mul_fork #2\xint:#4\xint:}% + {\romannumeral0\XINT_mul_fork #2\xint:#3\xint:}% +}% +\def\XINT_gctcv_loop_j #1#2% +{% + \expandafter\XINT_gctcv_loop_k\expandafter {\expandafter{#2}{#1}}% +}% +\def\XINT_gctcv_loop_k #1#2% +{% + \expandafter\XINT_gctcv_loop_l\expandafter {\expandafter{#2}#1}% +}% +\def\XINT_gctcv_loop_l #1#2% +{% + \expandafter\XINT_gctcv_loop_m\expandafter {\expandafter{#2}#1}% +}% +\def\XINT_gctcv_loop_m #1#2{\XINT_gctcv_loop_a {#2}#1}% +\def\XINT_gctcv_end #1.#2#3#4#5#6{ #6}% +% \end{macrocode} +% \subsection{\csh{xintiGCtoCv}} +% \begin{macrocode} +\def\xintiGCtoCv {\romannumeral0\xintigctocv }% +\def\xintigctocv #1% +{% + \expandafter\XINT_igctcv_prep \romannumeral`&&@#1+!/% +}% +\def\XINT_igctcv_prep +{% + \XINT_igctcv_loop_a {}1001% +}% +\def\XINT_igctcv_loop_a #1#2#3#4#5#6+% +{% + \expandafter\XINT_igctcv_loop_b + \romannumeral`&&@#6.{#2}{#3}{#4}{#5}{#1}% +}% +\def\XINT_igctcv_loop_b #1.#2#3#4#5% +{% + \expandafter\XINT_igctcv_loop_c\expandafter + {\romannumeral0\xintiiadd {#5}{\XINT_mul_fork #1\xint:#3\xint:}}% + {\romannumeral0\xintiiadd {#4}{\XINT_mul_fork #1\xint:#2\xint:}}% + {{#2}{#3}}% +}% +\def\XINT_igctcv_loop_c #1#2% +{% + \expandafter\XINT_igctcv_loop_f\expandafter {\expandafter{#2}{#1}}% +}% +\def\XINT_igctcv_loop_f #1#2#3#4/% +{% + \xint_gob_til_exclam #4\XINT_igctcv_end_a!% + \expandafter\XINT_igctcv_loop_g + \romannumeral`&&@#4.#1#2{#3}% +}% +\def\XINT_igctcv_loop_g #1.#2#3#4#5% +{% + \expandafter\XINT_igctcv_loop_h\expandafter + {\romannumeral0\XINT_mul_fork #1\xint:#5\xint:}% + {\romannumeral0\XINT_mul_fork #1\xint:#4\xint:}% + {{#2}{#3}}% +}% +\def\XINT_igctcv_loop_h #1#2% +{% + \expandafter\XINT_igctcv_loop_i\expandafter {\expandafter{#2}{#1}}% +}% +\def\XINT_igctcv_loop_i #1#2{\XINT_igctcv_loop_k #2{#2#1}}% +\def\XINT_igctcv_loop_k #1#2% +{% + \expandafter\XINT_igctcv_loop_l\expandafter + {\romannumeral0\xintrawwithzeros {#1/#2}}% +}% +\def\XINT_igctcv_loop_l #1#2#3{\XINT_igctcv_loop_a {#3{#1}}#2}%1.09i removes [0] +\def\XINT_igctcv_end_a #1.#2#3#4#5% +{% + \expandafter\XINT_igctcv_end_b\expandafter + {\romannumeral0\xintrawwithzeros {#2/#3}}% +}% +\def\XINT_igctcv_end_b #1#2{ #2{#1}}% 1.09b removes [0] +% \end{macrocode} +% \subsection{\csh{xintFtoCv}} +% \lverb|Still uses \xinticstocv \xintFtoCs rather than \xintctocv \xintFtoC.| +% \begin{macrocode} +\def\xintFtoCv {\romannumeral0\xintftocv }% +\def\xintftocv #1% +{% + \xinticstocv {\xintFtoCs {#1}}% +}% +% \end{macrocode} +% \subsection{\csh{xintFtoCCv}} +% \begin{macrocode} +\def\xintFtoCCv {\romannumeral0\xintftoccv }% +\def\xintftoccv #1% +{% + \xintigctocv {\xintFtoCC {#1}}% +}% +% \end{macrocode} +% \subsection{\csh{xintCntoF}} +% \lverb|& +% Modified in 1.06 to give the N first to a \numexpr rather than expanding +% twice. I just use \the\numexpr and maintain the previous code after that.| +% \begin{macrocode} +\def\xintCntoF {\romannumeral0\xintcntof }% +\def\xintcntof #1% +{% + \expandafter\XINT_cntf\expandafter {\the\numexpr #1}% +}% +\def\XINT_cntf #1#2% +{% + \ifnum #1>\xint_c_ + \xint_afterfi {\expandafter\XINT_cntf_loop\expandafter + {\the\numexpr #1-1\expandafter}\expandafter + {\romannumeral`&&@#2{#1}}{#2}}% + \else + \xint_afterfi + {\ifnum #1=\xint_c_ + \xint_afterfi {\expandafter\space \romannumeral`&&@#2{0}}% + \else \xint_afterfi { }% 1.09m now returns nothing. + \fi}% + \fi +}% +\def\XINT_cntf_loop #1#2#3% +{% + \ifnum #1>\xint_c_ \else \XINT_cntf_exit \fi + \expandafter\XINT_cntf_loop\expandafter + {\the\numexpr #1-1\expandafter }\expandafter + {\romannumeral0\xintadd {\xintDiv {1[0]}{#2}}{#3{#1}}}% + {#3}% +}% +\def\XINT_cntf_exit \fi + \expandafter\XINT_cntf_loop\expandafter + #1\expandafter #2#3% +{% + \fi\xint_gobble_ii #2% +}% +% \end{macrocode} +% \subsection{\csh{xintGCntoF}} +% \lverb|Modified in 1.06 to give the N argument first to a \numexpr rather +% than expanding twice. I just use \the\numexpr and maintain the previous code +% after that.| +% \begin{macrocode} +\def\xintGCntoF {\romannumeral0\xintgcntof }% +\def\xintgcntof #1% +{% + \expandafter\XINT_gcntf\expandafter {\the\numexpr #1}% +}% +\def\XINT_gcntf #1#2#3% +{% + \ifnum #1>\xint_c_ + \xint_afterfi {\expandafter\XINT_gcntf_loop\expandafter + {\the\numexpr #1-1\expandafter}\expandafter + {\romannumeral`&&@#2{#1}}{#2}{#3}}% + \else + \xint_afterfi + {\ifnum #1=\xint_c_ + \xint_afterfi {\expandafter\space\romannumeral`&&@#2{0}}% + \else \xint_afterfi { }% 1.09m now returns nothing rather than 0/1[0] + \fi}% + \fi +}% +\def\XINT_gcntf_loop #1#2#3#4% +{% + \ifnum #1>\xint_c_ \else \XINT_gcntf_exit \fi + \expandafter\XINT_gcntf_loop\expandafter + {\the\numexpr #1-1\expandafter }\expandafter + {\romannumeral0\xintadd {\xintDiv {#4{#1}}{#2}}{#3{#1}}}% + {#3}{#4}% +}% +\def\XINT_gcntf_exit \fi + \expandafter\XINT_gcntf_loop\expandafter + #1\expandafter #2#3#4% +{% + \fi\xint_gobble_ii #2% +}% +% \end{macrocode} +% \subsection{\csh{xintCntoCs}} +% \lverb|Modified in 1.09m: added spaces after the commas in the produced list. +% Moreover the coefficients are not braced anymore. A slight induced limitation +% is that the macro argument should not contain some explicit comma (cf. +% \XINT_cntcs_exit_b), hence \xintCntoCs {\macro,} with \def\macro,#1{<stuff>} +% would crash. Not a very serious limitation, I believe. | +% \begin{macrocode} +\def\xintCntoCs {\romannumeral0\xintcntocs }% +\def\xintcntocs #1% +{% + \expandafter\XINT_cntcs\expandafter {\the\numexpr #1}% +}% +\def\XINT_cntcs #1#2% +{% + \ifnum #1<0 + \xint_afterfi { }% 1.09i: a 0/1[0] was here, now the macro returns nothing + \else + \xint_afterfi {\expandafter\XINT_cntcs_loop\expandafter + {\the\numexpr #1-\xint_c_i\expandafter}\expandafter + {\romannumeral`&&@#2{#1}}{#2}}% produced coeff not braced + \fi +}% +\def\XINT_cntcs_loop #1#2#3% +{% + \ifnum #1>-\xint_c_i \else \XINT_cntcs_exit \fi + \expandafter\XINT_cntcs_loop\expandafter + {\the\numexpr #1-\xint_c_i\expandafter}\expandafter + {\romannumeral`&&@#3{#1}, #2}{#3}% space added, 1.09m +}% +\def\XINT_cntcs_exit \fi + \expandafter\XINT_cntcs_loop\expandafter + #1\expandafter #2#3% +{% + \fi\XINT_cntcs_exit_b #2% +}% +\def\XINT_cntcs_exit_b #1,{}% romannumeral stopping space already there +% \end{macrocode} +% \subsection{\csh{xintCntoGC}} +% \lverb|& +% Modified in 1.06 to give the N first to a \numexpr rather than expanding +% twice. I just use \the\numexpr and maintain the previous code after that. +% +% 1.09m maintains the braces, as the coeff are allowed to be fraction and the +% slash can not be naked in the GC format, contrarily to what happens in +% \xintCntoCs. Also the separators given to \xintGCtoGCx may then fetch the +% coefficients as argument, as they are braced.| +% \begin{macrocode} +\def\xintCntoGC {\romannumeral0\xintcntogc }% +\def\xintcntogc #1% +{% + \expandafter\XINT_cntgc\expandafter {\the\numexpr #1}% +}% +\def\XINT_cntgc #1#2% +{% + \ifnum #1<0 + \xint_afterfi { }% 1.09i there was as strange 0/1[0] here, removed + \else + \xint_afterfi {\expandafter\XINT_cntgc_loop\expandafter + {\the\numexpr #1-\xint_c_i\expandafter}\expandafter + {\expandafter{\romannumeral`&&@#2{#1}}}{#2}}% + \fi +}% +\def\XINT_cntgc_loop #1#2#3% +{% + \ifnum #1>-\xint_c_i \else \XINT_cntgc_exit \fi + \expandafter\XINT_cntgc_loop\expandafter + {\the\numexpr #1-\xint_c_i\expandafter }\expandafter + {\expandafter{\romannumeral`&&@#3{#1}}+1/#2}{#3}% +}% +\def\XINT_cntgc_exit \fi + \expandafter\XINT_cntgc_loop\expandafter + #1\expandafter #2#3% +{% + \fi\XINT_cntgc_exit_b #2% +}% +\def\XINT_cntgc_exit_b #1+1/{ }% +% \end{macrocode} +% \subsection{\csh{xintGCntoGC}} +% \lverb|& +% Modified in 1.06 to give the N first to a \numexpr rather than expanding +% twice. I just use \the\numexpr and maintain the previous code after that.| +% \begin{macrocode} +\def\xintGCntoGC {\romannumeral0\xintgcntogc }% +\def\xintgcntogc #1% +{% + \expandafter\XINT_gcntgc\expandafter {\the\numexpr #1}% +}% +\def\XINT_gcntgc #1#2#3% +{% + \ifnum #1<0 + \xint_afterfi { }% 1.09i now returns nothing + \else + \xint_afterfi {\expandafter\XINT_gcntgc_loop\expandafter + {\the\numexpr #1-\xint_c_i\expandafter}\expandafter + {\expandafter{\romannumeral`&&@#2{#1}}}{#2}{#3}}% + \fi +}% +\def\XINT_gcntgc_loop #1#2#3#4% +{% + \ifnum #1>-\xint_c_i \else \XINT_gcntgc_exit \fi + \expandafter\XINT_gcntgc_loop_b\expandafter + {\expandafter{\romannumeral`&&@#4{#1}}/#2}{#3{#1}}{#1}{#3}{#4}% +}% +\def\XINT_gcntgc_loop_b #1#2#3% +{% + \expandafter\XINT_gcntgc_loop\expandafter + {\the\numexpr #3-\xint_c_i \expandafter}\expandafter + {\expandafter{\romannumeral`&&@#2}+#1}% +}% +\def\XINT_gcntgc_exit \fi + \expandafter\XINT_gcntgc_loop_b\expandafter #1#2#3#4#5% +{% + \fi\XINT_gcntgc_exit_b #1% +}% +\def\XINT_gcntgc_exit_b #1/{ }% +% \end{macrocode} +% \subsection{\csh{xintCstoGC}} +% \begin{macrocode} +\def\xintCstoGC {\romannumeral0\xintcstogc }% +\def\xintcstogc #1% +{% + \expandafter\XINT_cstc_prep \romannumeral`&&@#1,!,% +}% +\def\XINT_cstc_prep #1,{\XINT_cstc_loop_a {{#1}}}% +\def\XINT_cstc_loop_a #1#2,% +{% + \xint_gob_til_exclam #2\XINT_cstc_end!% + \XINT_cstc_loop_b {#1}{#2}% +}% +\def\XINT_cstc_loop_b #1#2{\XINT_cstc_loop_a {#1+1/{#2}}}% +\def\XINT_cstc_end!\XINT_cstc_loop_b #1#2{ #1}% +% \end{macrocode} +% \subsection{\csh{xintGCtoGC}} +% \begin{macrocode} +\def\xintGCtoGC {\romannumeral0\xintgctogc }% +\def\xintgctogc #1% +{% + \expandafter\XINT_gctgc_start \romannumeral`&&@#1+!/% +}% +\def\XINT_gctgc_start {\XINT_gctgc_loop_a {}}% +\def\XINT_gctgc_loop_a #1#2+#3/% +{% + \xint_gob_til_exclam #3\XINT_gctgc_end!% + \expandafter\XINT_gctgc_loop_b\expandafter + {\romannumeral`&&@#2}{#3}{#1}% +}% +\def\XINT_gctgc_loop_b #1#2% +{% + \expandafter\XINT_gctgc_loop_c\expandafter + {\romannumeral`&&@#2}{#1}% +}% +\def\XINT_gctgc_loop_c #1#2#3% +{% + \XINT_gctgc_loop_a {#3{#2}+{#1}/}% +}% +\def\XINT_gctgc_end!\expandafter\XINT_gctgc_loop_b +{% + \expandafter\XINT_gctgc_end_b +}% +\def\XINT_gctgc_end_b #1#2#3{ #3{#1}}% +\XINT_restorecatcodes_endinput% +% \end{macrocode} +% \StoreCodelineNo {xintcfrac} +% \cleardoublepage\let\xintcfracnameUp\undefined +%\gardesactifs +%\let</xintcfrac>\relax +%\let<*xintexpr>\gardesinactifs +%</xintcfrac>^^A-------------------------------------------------- +%<*xintexpr>^^A--------------------------------------------------- +%^^A -*- coding: utf-8; mode: doctex; fill-column: 78; -*- +% \clearpage\csname xintexprnameUp\endcsname +% \section{Package \xintexprnameimp implementation} +% \RaisedLabel{sec:exprimp} +% \etocarticlestylenomarks +% \etocstandardlines +% \etocsetnexttocdepth {subsection} +% +% \localtableofcontents +% +% \etocsettocstyle{}{} +% +% This is release \expandafter|\xintbndlversion| of +% \expandafter|\expandafter[\xintbndldate]|. +% +% \subsection{Old comments} +% +% These general comments were last updated at the end of the |1.09x| series in +% 2014. The principles remain in place to this day but refer to +% \href{http://www.ctan.org/pkg/xint/CHANGES.html}{CHANGES.html} for some +% significant evolutions since. +% +% The first version was released in June 2013. I was greatly helped in this task +% of writing an expandable parser of infix operations by the comments provided +% in |l3fp-parse.dtx| (in its version as available in April-May 2013). One will +% recognize in particular the idea of the `until' macros; I have not looked into +% the actual |l3fp| code beyond the very useful comments provided in its +% documentation. +% +% A main worry was that my data has no a priori bound on its size; to keep the +% code reasonably efficient, I experimented with a technique of storing and +% retrieving data expandably as \emph{names} of control sequences. Intermediate +% computation results are stored as control sequences |\.=a/b[n]|. +% +% +% Roughly speaking, the parser mechanism is as follows: at any given time the +% last found ``operator'' has its associated |until| macro awaiting some news +% from the token flow; first |getnext| expands forward in the hope to construct +% some number, which may come from a parenthesized sub-expression, from some +% braced material, or from a digit by digit scan. After this number has been +% formed the next operator is looked for by the |getop| macro. Once |getop| has +% finished its job, |until| is presented with three tokens: the first one is the +% precedence level of the new found operator (which may be an end of expression +% marker), the second is the operator character token (earlier versions had here +% already some macro name, but in order to keep as much common code to expr and +% floatexpr common as possible, this was modified) of the new found operator, and +% the third one is the newly found number (which was encountered just before the +% new operator). +% +% The |until| macro of the earlier operator examines the precedence level of the +% new found one, and either executes the earlier operator (in the case of a +% binary operation, with the found number and a previously stored one) or it +% delays execution, giving the hand to the |until| macro of the operator having +% been found of higher precedence. +% +% A minus sign acting as prefix gets converted into a (unary) operator +% inheriting the precedence level of the previous operator. +% +% Once the end of the expression is found (it has to be marked by a |\relax|) +% the final result is output as four tokens (five tokens since |1.09j|) the +% first one a catcode 11 exclamation mark, the second one an error generating +% macro, the third one is a protection mechanism, the fourth one a printing +% macro and the fifth is |\.=a/b[n]|. The prefix |\xintthe| makes the output +% printable by killing the first three tokens. +% +% +% \subsection{Catcodes, \protect\eTeX{} and reload detection} +% +% The code for reload detection was initially copied from \textsc{Heiko +% Oberdiek}'s packages, then modified. +% +% The method for catcodes was also initially directly inspired by these +% packages. +% +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode64=11 % @ + \catcode35=6 % # + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \def\z {\endgroup}% + \expandafter\let\expandafter\x\csname ver@xintexpr.sty\endcsname + \expandafter\let\expandafter\w\csname ver@xintfrac.sty\endcsname + \expandafter\let\expandafter\t\csname ver@xinttools.sty\endcsname + \expandafter + \ifx\csname PackageInfo\endcsname\relax + \def\y#1#2{\immediate\write-1{Package #1 Info: #2.}}% + \else + \def\y#1#2{\PackageInfo{#1}{#2}}% + \fi + \expandafter + \ifx\csname numexpr\endcsname\relax + \y{xintexpr}{\numexpr not available, aborting input}% + \aftergroup\endinput + \else + \ifx\x\relax % plain-TeX, first loading of xintexpr.sty + \ifx\w\relax % but xintfrac.sty not yet loaded. + \expandafter\def\expandafter\z\expandafter + {\z\input xintfrac.sty\relax}% + \fi + \ifx\t\relax % but xinttools.sty not yet loaded. + \expandafter\def\expandafter\z\expandafter + {\z\input xinttools.sty\relax}% + \fi + \else + \def\empty {}% + \ifx\x\empty % LaTeX, first loading, + % variable is initialized, but \ProvidesPackage not yet seen + \ifx\w\relax % xintfrac.sty not yet loaded. + \expandafter\def\expandafter\z\expandafter + {\z\RequirePackage{xintfrac}}% + \fi + \ifx\t\relax % xinttools.sty not yet loaded. + \expandafter\def\expandafter\z\expandafter + {\z\RequirePackage{xinttools}}% + \fi + \else + \aftergroup\endinput % xintexpr already loaded. + \fi + \fi + \fi +\z% +\XINTsetupcatcodes% +% \end{macrocode} +% \subsection{Package identification} +% \lverb|& +% | +% \begin{macrocode} +\XINT_providespackage +\ProvidesPackage{xintexpr}% + [2019/04/05 1.3e Expandable expression parser (JFB)]% +\catcode`! 11 +\let\XINT_Cmp \xintiiCmp +% \end{macrocode} +% \subsection{\csh{xintexpr}, \csh{xintiexpr}, \csh{xintfloatexpr}, +% \csh{xintiiexpr}} +% \lverb|ATTENTION! 1.3d renamed \xinteval to \xintexpro etc...| +% \begin{macrocode} +\def\xintexpr {\romannumeral0\xintexpro }% +\def\xintiexpr {\romannumeral0\xintiexpro }% +\def\xintfloatexpr {\romannumeral0\xintfloatexpro }% +\def\xintiiexpr {\romannumeral0\xintiiexpro }% +% \end{macrocode} +% \subsection{\csh{xintexpro}, \csh{xintiiexpro}} +% \lverb|ATTENTION! 1.3d renamed \xinteval to \xintexpro etc...| +% \begin{macrocode} +\def\xintexpro {\expandafter\XINT_expr_wrap\romannumeral0\xintbareeval }% +\def\xintiiexpro {\expandafter\XINT_iiexpr_wrap\romannumeral0\xintbareiieval }% +% \end{macrocode} +% \subsection{\csh{xintiexpro}, \csh{xintfloatexpro}} +% \lverb|Optional argument since 1.1. +% +% ATTENTION! 1.3d renamed \xinteval to \xintexpro etc... +% +% Some renaming of macros at 1.3e here.| +% \begin{macrocode} +\def\xintiexpro #1% +{% + \ifx [#1\expandafter\XINT_iexpr_withopt\else\expandafter\XINT_iexpr_noopt + \fi #1% +}% +\def\XINT_iexpr_noopt +{% + \expandafter\XINT_iexpr_preprint\expandafter 0% + \romannumeral0\xintbareeval +}% +\def\XINT_iexpr_withopt [#1]% +{% + \expandafter\XINT_iexpr_preprint\expandafter + {\the\numexpr \xint_zapspaces #1 \xint_gobble_i\expandafter}% + \romannumeral0\xintbareeval +}% +\def\XINT_iexpr_preprint #1#2% +{% + \expandafter\XINT_expr_wrap + \csname .=\xintRound::csv {#1}{\XINT_expr_unlock #2}\endcsname +}% +\def\xintfloatexpro #1% +{% + \ifx [#1\expandafter\XINT_flexpr_withopt\else\expandafter\XINT_flexpr_noopt + \fi #1% +}% +\def\XINT_flexpr_noopt +{% + \expandafter\XINT_flexpr_preprint\expandafter\xinttheDigits + \romannumeral0\xintbarefloateval +}% +\def\XINT_flexpr_withopt [#1]% +{% + \expandafter\XINT_flexpr_preprint\expandafter + {\the\numexpr\xint_zapspaces #1 \xint_gobble_i\expandafter}% + \romannumeral0\xintbarefloateval +}% +\def\XINT_flexpr_preprint #1#2% +{% + \expandafter\XINT_flexpr_wrap + \csname .;#1.=\XINTinFloat::csv {#1}{\XINT_expr_unlock #2}\endcsname +}% +% \end{macrocode} +% \subsection{\csh{XINT_expr_wrap}, \csh{XINT_iiexpr_wrap}, \csh{XINT_flexpr_wrap}} +% \lverb|1.3e removes some leading space tokens which served nothing. There is +% no \XINT_iexpr_wrap, because \XINT_expr_wrap is used directly.| +% \begin{macrocode} +\def\XINT_expr_wrap {!\XINT_expr_usethe\XINT_protectii\XINT_expr_print}% +\def\XINT_iiexpr_wrap {!\XINT_expr_usethe\XINT_protectii\XINT_iiexpr_print}% +\def\XINT_flexpr_wrap {!\XINT_expr_usethe\XINT_protectii\XINT_flexpr_print}% +% \end{macrocode} +% \subsection{\csh{XINT_expr_usethe}, \csh{XINT_protectii}} +% \begin{macrocode} +\def\XINT_protectii #1{\noexpand\XINT_protectii\noexpand #1\noexpand }% +\protected\def\XINT_expr_usethe\XINT_protectii {\xintError:missing_xintthe!}% +% \end{macrocode} +% \subsection{\csh{XINT_expr_print}, \csh{XINT_iiexpr_print}, \csh{XINT_flexpr_print}} +% \begin{macrocode} +\def\XINT_expr_print #1{\xintSPRaw::csv {\XINT_expr_unlock #1}}% +\def\XINT_iiexpr_print #1{\xintCSV::csv {\XINT_expr_unlock #1}}% +\def\XINT_flexpr_print #1% +{% + \expandafter\xintPFloat::csv + \romannumeral`&&@\expandafter\XINT_expr_unlock_sp\string #1!% +}% +\def\XINT_expr_unlock_sp #1.;#2.=#3!{{#2}{#3}}% +% \end{macrocode} +% \subsection{\csh{xinttheexpr}, \csh{xinttheiexpr}, \csh{xintthefloatexpr}, +% \csh{xinttheiiexpr}} +% \lverb|The reason why \xinttheiexpr et \xintthefloatexpr are handled +% differently is that they admit an optional argument which acts via a custom +% «printing» stage.| +% \begin{macrocode} +\def\xinttheexpr + {\romannumeral`&&@\expandafter\XINT_expr_print\romannumeral0\xintbareeval}% +\def\xinttheiexpr + {\romannumeral`&&@\expandafter\xint_gobble_iii\romannumeral`&&@\xintiexpr}% +\def\xintthefloatexpr + {\romannumeral`&&@\expandafter\xint_gobble_iii\romannumeral`&&@\xintfloatexpr}% +\def\xinttheiiexpr + {\romannumeral`&&@\expandafter\XINT_iiexpr_print\romannumeral0\xintbareiieval}% +% \end{macrocode} +% \subsection{\csh{thexintexpr}, \csh{thexintiexpr}, \csh{thexintfloatexpr}, +% \csh{thexintiiexpr}} +% \lverb|New with 1.2h. I have been for the last three years very strict +% regarding macros with \xint or \XINT, but well.| +% \begin{macrocode} +\let\thexintexpr \xinttheexpr +\let\thexintiexpr \xinttheiexpr +\let\thexintfloatexpr\xintthefloatexpr +\let\thexintiiexpr \xinttheiiexpr +% \end{macrocode} +% \subsection{\csh{xinteval}, \csh{xintieval}, \csh{xintfloateval}, +% \csh{xintiieval}} +% \begin{macrocode} +\def\xinteval #1% + {\romannumeral`&&@\expandafter\XINT_expr_print\romannumeral0\xintbareeval#1\relax}% +\def\xintieval #1% + {\romannumeral`&&@\expandafter\xint_gobble_iii\romannumeral`&&@\xintiexpr#1\relax}% +\def\xintfloateval #1% + {\romannumeral`&&@\expandafter\xint_gobble_iii\romannumeral`&&@\xintfloatexpr#1\relax}% +\def\xintiieval #1% + {\romannumeral`&&@\expandafter\XINT_iiexpr_print\romannumeral0\xintbareiieval#1\relax}% +% \end{macrocode} +% \subsection{\csh{xintthe}} +% \begin{macrocode} +\def\xintthe #1{\romannumeral`&&@\expandafter\xint_gobble_iii\romannumeral`&&@#1}% +% \end{macrocode} +% \subsection{\csh{xintbareeval}, \csh{xintbarefloateval}, \csh{xintbareiieval}} +% \begin{macrocode} +\def\xintbareeval + {\expandafter\XINT_expr_until_end_a\romannumeral`&&@\XINT_expr_getnext }% +\def\xintbarefloateval + {\expandafter\XINT_flexpr_until_end_a\romannumeral`&&@\XINT_expr_getnext }% +\def\xintbareiieval + {\expandafter\XINT_iiexpr_until_end_a\romannumeral`&&@\XINT_expr_getnext }% +% \end{macrocode} +% \subsection{\csh{xintthebareeval}, \csh{xintthebarefloateval}, \csh{xintthebareiieval}} +% \begin{macrocode} +\def\xintthebareeval {\expandafter\XINT_expr_unlock\romannumeral0\xintbareeval}% +\def\xintthebarefloateval {\expandafter\XINT_expr_unlock\romannumeral0\xintbarefloateval}% +\def\xintthebareiieval {\expandafter\XINT_expr_unlock\romannumeral0\xintbareiieval}% +% \end{macrocode} +% \subsection{\csh{xintboolexpr}, \csh{XINT_boolexpr_print}, \csh{xinttheboolexpr}, +% \csh{thexintboolexpr}} +% \lverb|ATTENTION! 1.3d renamed \xinteval to \xintexpro etc...| +% \begin{macrocode} +\def\xintboolexpr +{% + \romannumeral0\expandafter\expandafter\expandafter + \XINT_boolexpr_done\expandafter\xint_gobble_iv\romannumeral0\xintexpro +}% +\def\XINT_boolexpr_done {!\XINT_expr_usethe\XINT_protectii\XINT_boolexpr_print}% +\def\XINT_boolexpr_print #1{\xintIsTrue::csv {\XINT_expr_unlock #1}}% +\def\xinttheboolexpr +{% + \romannumeral`&&@\expandafter\expandafter\expandafter + \XINT_boolexpr_print\expandafter\xint_gobble_iv\romannumeral0\xintexpro +}% +\let\thexintboolexpr\xinttheboolexpr +% \end{macrocode} +% \subsection{\csh{xintifboolexpr}, \csh{xintifboolfloatexpr}, \csh{xintifbooliiexpr}} +% \lverb|Do not work with comma separated expressions.| +% \begin{macrocode} +\def\xintifboolexpr #1{\romannumeral0\xintiiifnotzero {\xinttheexpr #1\relax}}% +\def\xintifboolfloatexpr #1{\romannumeral0\xintiiifnotzero {\xintthefloatexpr #1\relax}}% +\def\xintifbooliiexpr #1{\romannumeral0\xintiiifnotzero {\xinttheiiexpr #1\relax}}% +% \end{macrocode} +% \subsection{\csh{xintifsgnexpr}, \csh{xintifsgnfloatexpr}, \csh{xintifsgniiexpr}} +% \changed{1.3d}{} +% \lverb|Do not work with comma separated expressions.| +% \begin{macrocode} +\def\xintifsgnexpr #1{\romannumeral0\xintiiifsgn {\xinttheexpr #1\relax}}% +\def\xintifsgnfloatexpr #1{\romannumeral0\xintiiifsgn {\xintthefloatexpr #1\relax}}% +\def\xintifsgniiexpr #1{\romannumeral0\xintiiifsgn {\xinttheiiexpr #1\relax}}% +% \end{macrocode} +% \subsection{\csh{xintthecoords}} +% \lverb|1.1 Wraps up an even number of comma separated items into pairs of +% TikZ coordinates; for use in the following way: +% +% coordinates {\xintthecoords\xintfloatexpr ... \relax} +% +% The crazyness with the \csname and unlock is due to TikZ somewhat STRANGE +% control of the TOTAL number of expansions which should not exceed the very low +% value of 100 !! As we implemented \XINT_thecoords_b in an "inline" style for +% efficiency, we need to hide its expansions. +% +% Not to be used as \xintthecoords\xintthefloatexpr, only as +% \xintthecoords\xintfloatexpr (or \xintiexpr etc...). Perhaps \xintthecoords +% could make an extra check, but one should not accustom users to too loose +% requirements!| +% \begin{macrocode} +\def\xintthecoords #1{\romannumeral`&&@\expandafter\expandafter\expandafter + \XINT_thecoords_a + \expandafter\xint_gobble_iii\romannumeral0#1}% +\def\XINT_thecoords_a #1#2% #1=print macro, indispensible for scientific notation + {\expandafter\XINT_expr_unlock\csname.=\expandafter\XINT_thecoords_b + \romannumeral`&&@#1#2,!,!,^\endcsname }% +\def\XINT_thecoords_b #1#2,#3#4,% + {\xint_gob_til_! #3\XINT_thecoords_c ! (#1#2, #3#4)\XINT_thecoords_b }% +\def\XINT_thecoords_c #1^{}% +% \end{macrocode} +% \subsection{Locking and unlocking} +% \lverb|Some renaming and modifications here with release 1.2 to switch from +% using chains of \romannumeral-`0 in order to gather numbers, possibly +% hexadecimals, to using a \csname governed expansion. In this way no more +% limit at 5000 digits, and besides this is a logical move because the +% \xintexpr parser is already based on \csname...\endcsname storage of numbers +% as one token. +% +% The limitation at 5000 digits didn't worry me too much because it was not +% very realistic to launch computations with thousands of digits... such +% computations are still slow with 1.2 but less so now. Chains or +% \romannumeral are still used for the gathering of function names and other +% stuff which I have half-forgotten because the parser does many things. +% +% In the earlier versions we used the lockscan macro after a chain of +% \romannumeral-`0 had ended gathering digits; this uses has been replaced by +% direct processing inside a \csname...\endcsname and the macro is kept only +% for matters of dummy variables. +% +% Currently, the parsing of hexadecimal numbers needs two nested +% \csname...\endcsname, first to gather the letters (possibly with a hexadecimal +% fractional part), and in a second stage to apply \xintHexToDec to do the +% actual conversion. This should be faster than updating on the fly the number +% (which would be hard for the fraction part...).| +% \begin{macrocode} +\def\xint_gob_til_! #1!{}% ! with catcode 11 +\def\XINT_expr_lockscan#1{% not used for decimal numbers in xintexpr 1.2 +\def\XINT_expr_lockscan##1!{\expandafter#1\csname .=##1\endcsname}% +}\XINT_expr_lockscan{ }% +\def\XINT_expr_lockit#1{% +\def\XINT_expr_lockit##1{\expandafter#1\csname .=##1\endcsname}% +}\XINT_expr_lockit{ }% +\def\XINT_expr_unlock_hex_in #1% expanded inside \csname..\endcsname + {\expandafter\XINT_expr_inhex\romannumeral`&&@\XINT_expr_unlock#1;}% +\def\XINT_expr_inhex #1.#2#3;% expanded inside \csname..\endcsname +{% + \if#2>% + \xintHexToDec{#1}% + \else + \xintiiMul{\xintiiPow{625}{\xintLength{#3}}}{\xintHexToDec{#1#3}}% + [\the\numexpr-4*\xintLength{#3}]% + \fi +}% +\def\XINT_expr_unlock {\expandafter\XINT_expr_unlock_a\string }% +\def\XINT_expr_unlock_a #1.={}% +\def\XINT_expr_unexpectedtoken {\xintError:ignored }% +\let\XINT_expr_done\space +% \end{macrocode} +% \subsection{Hooks for the functioning of \cshnolabel{xintNewExpr} and +% \cshnolabel{xintdeffunc}} +% \lverb|This is new with 1.3. See \XINT_expr_redefinemacros.| +% \begin{macrocode} +\let\XINT:NEhook:one\empty +\let\XINT:NEhook:two\empty +\let\XINT:NEhook:csv\empty +\def\XINT:NEhook:twosp #1,#2,!#3{#3{#1}{#2}}% +% \end{macrocode} +% \subsection{Macros handling csv lists on output (for \cshnolabel{XINT_expr_print} et +% al. routines)} +% \localtableofcontents +% \lverb|Changed completely for 1.1, which adds the optional arguments to +% \xintiexpr and \xintfloatexpr.| +% \subsubsection{\csh{XINT_::_end}} +% \lverb|Le mécanisme est le suivant, #2 est dans des accolades et commence par +% ,<sp>. Donc le gobble se débarrasse du, et le <sp> après brace stripping +% arrête un \romannumeral0 ou \romannumeral-`0| +% \begin{macrocode} +\def\XINT_::_end #1,#2{\xint_gobble_i #2}% +% \end{macrocode} +% \subsubsection{\csh{xintCSV::csv}} +% \begin{macrocode} +\def\xintCSV::csv #1{\expandafter\XINT_csv::_a\romannumeral`&&@#1,^,}% +\def\XINT_csv::_a {\XINT_csv::_b {}}% +\def\XINT_csv::_b #1#2,{\expandafter\XINT_csv::_c \romannumeral`&&@#2,{#1}}% +\def\XINT_csv::_c #1{\if ^#1\expandafter\XINT_::_end\fi\XINT_csv::_d #1}% +\def\XINT_csv::_d #1,#2{\XINT_csv::_b {#2, #1}}% possibly, item #1 is empty. +% \end{macrocode} +% \subsubsection{\csh{xintSPRaw}, \csh{xintSPRaw::csv}} +% \begin{macrocode} +\def\xintSPRaw {\romannumeral0\xintspraw }% +\def\xintspraw #1{\expandafter\XINT_spraw\romannumeral`&&@#1[\W]}% +\def\XINT_spraw #1[#2#3]{\xint_gob_til_W #2\XINT_spraw_a\W\XINT_spraw_p #1[#2#3]}% +\def\XINT_spraw_a\W\XINT_spraw_p #1[\W]{ #1}% +\def\XINT_spraw_p #1[\W]{\xintpraw {#1}}% +\def\xintSPRaw::csv #1{\romannumeral0\expandafter\XINT_spraw::_a\romannumeral`&&@#1,^,}% +\def\XINT_spraw::_a {\XINT_spraw::_b {}}% +\def\XINT_spraw::_b #1#2,{\expandafter\XINT_spraw::_c \romannumeral`&&@#2,{#1}}% +\def\XINT_spraw::_c #1{\if ,#1\xint_dothis\XINT_spraw::_e\fi + \if ^#1\xint_dothis\XINT_::_end\fi + \xint_orthat\XINT_spraw::_d #1}% +\def\XINT_spraw::_d #1,{\expandafter\XINT_spraw::_e\romannumeral0\XINT_spraw #1[\W],}% +\def\XINT_spraw::_e #1,#2{\XINT_spraw::_b {#2, #1}}% +% \end{macrocode} +% \subsubsection{\csh{xintIsTrue::csv}} +% \begin{macrocode} +\def\xintIsTrue::csv #1{\romannumeral0\expandafter\XINT_istrue::_a\romannumeral`&&@#1,^,}% +\def\XINT_istrue::_a {\XINT_istrue::_b {}}% +\def\XINT_istrue::_b #1#2,{\expandafter\XINT_istrue::_c \romannumeral`&&@#2,{#1}}% +\def\XINT_istrue::_c #1{\if ,#1\xint_dothis\XINT_istrue::_e\fi + \if ^#1\xint_dothis\XINT_::_end\fi + \xint_orthat\XINT_istrue::_d #1}% +\def\XINT_istrue::_d #1,{\expandafter\XINT_istrue::_e\romannumeral0\xintisnotzero {#1},}% +\def\XINT_istrue::_e #1,#2{\XINT_istrue::_b {#2, #1}}% +% \end{macrocode} +% \subsubsection{\csh{xintRound::csv}} +% \lverb| +% 1.3e Emploi d'un point comme délimiteur. Dans le futur donner une signification +% à un #1 négatif dans \XINT_round::_a ? +% | +% \begin{macrocode} +\def\XINT_:::_end #1,#2#3{\xint_gobble_i #3}% +\def\xintRound::csv #1#2{\romannumeral0\expandafter\XINT_round::_a + \the\numexpr#1\expandafter.\romannumeral`&&@#2,^,}% +\def\XINT_round::_a #1.{\XINT_round::_b #1.{}}% +\def\XINT_round::_b #1.#2#3,{\expandafter\XINT_round::_c \romannumeral`&&@#3,{#1}{#2}}% +\def\XINT_round::_c #1{\if ,#1\xint_dothis\XINT_round::_e\fi + \if ^#1\xint_dothis\XINT_:::_end\fi + \xint_orthat\XINT_round::_d #1}% +\def\XINT_round::_d #1,#2{% + \expandafter\XINT_round::_e\romannumeral0\ifnum#2>\xint_c_ + \expandafter\xintround\else\expandafter\xintiround\fi {#2}{#1},{#2}}% +\def\XINT_round::_e #1,#2#3{\XINT_round::_b #2.{#3, #1}}% +% \end{macrocode} +% \subsubsection{\csh{XINTinFloat::csv}} +% \lverb|& +% 1.3e adds support for a negative specifier (\XINT_infloat::_a inserted, by +% luck formerly it started straight with \XINT_infloat::_b ...). +% +% | +% \begin{macrocode} +\def\XINTinFloat::csv #1#2{\romannumeral0\expandafter\XINT_infloat::_a + \the\numexpr #1\expandafter.\romannumeral`&&@#2,^,}% +\def\XINT_infloat::_a #1#2.% + {\expandafter\XINT_infloat::_b\the\numexpr\if#1-\XINTdigits\fi#1#2.{}}% +\def\XINT_infloat::_b #1.#2#3,{\XINT_infloat::_c #3,{#1}{#2}}% +\def\XINT_infloat::_c #1{\if ,#1\xint_dothis\XINT_infloat::_e\fi + \if ^#1\xint_dothis\XINT_:::_end\fi + \xint_orthat\XINT_infloat::_d #1}% +\def\XINT_infloat::_d #1,#2% + {\expandafter\XINT_infloat::_e\romannumeral0\XINTinfloat [#2]{#1},{#2}}% +\def\XINT_infloat::_e #1,#2#3{\XINT_infloat::_b #2.{#3, #1}}% +% \end{macrocode} +% \subsubsection{\csh{xintPFloat::csv}} +% \lverb|& +% Also extended at 1.3e to handle negative optional specifier for digits +% precision. This macro formats output. +% +% | +% \begin{macrocode} +\def\xintPFloat::csv #1#2{\romannumeral0\expandafter\XINT_pfloat::_a + \the\numexpr #1\expandafter.\romannumeral`&&@#2,^,}% +\def\XINT_pfloat::_a #1#2.% + {\expandafter\XINT_pfloat::_b\the\numexpr\if#1-\XINTdigits\fi#1#2.{}}% +\def\XINT_pfloat::_b #1.#2#3,{\expandafter\XINT_pfloat::_c \romannumeral`&&@#3,{#1}{#2}}% +\def\XINT_pfloat::_c #1{\if ,#1\xint_dothis\XINT_pfloat::_e\fi + \if ^#1\xint_dothis\XINT_:::_end\fi + \xint_orthat\XINT_pfloat::_d #1}% +\def\XINT_pfloat::_d #1,#2% + {\expandafter\XINT_pfloat::_e\romannumeral0\XINT_pfloat_opt [\xint:#2]{#1},{#2}}% +\def\XINT_pfloat::_e #1,#2#3{\XINT_pfloat::_b #2.{#3, #1}}% +% \end{macrocode} +% \subsection{\csh{XINT_expr_getnext}: fetching some number then an operator} +% \lverb|Big change in 1.1, no attempt to detect braced stuff anymore as the +% [N] notation is implemented otherwise. Now, braces should not be used at +% all; one level removed, then \romannumeral-`0 expansion.| +% \begin{macrocode} +\def\XINT_expr_getnext #1% +{% + \expandafter\XINT_expr_getnext_a\romannumeral`&&@#1% +}% +\def\XINT_expr_getnext_a #1% +{% screens out sub-expressions and \count or \dimen registers/variables + \xint_gob_til_! #1\XINT_expr_subexpr !% recall this ! has catcode 11 + \ifcat\relax#1% \count or \numexpr etc... token or count, dimen, skip cs + \expandafter\XINT_expr_countetc + \else + \expandafter\expandafter\expandafter\XINT_expr_getnextfork\expandafter\string + \fi + #1% +}% +\def\XINT_expr_subexpr !#1\fi !{\expandafter\XINT_expr_getop\xint_gobble_iii }% +% \end{macrocode} +% \lverb|1.2 adds \ht, \dp, \wd and the eTeX font things.| +% \begin{macrocode} +\def\XINT_expr_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 + \XINT_expr_unpackvar + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \expandafter\XINT_expr_getnext\number #1% +}% +\def\XINT_expr_unpackvar\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \expandafter\XINT_expr_getnext\number #1% + {\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \expandafter\XINT_expr_getop\csname .=\number#1\endcsname }% +\begingroup +\lccode`*=`# +\lowercase{\endgroup +\def\XINT_expr_getnextfork #1{% + \if#1*\xint_dothis {\XINT_expr_scan_macropar *}\fi + \if#1[\xint_dothis {\xint_c_xviii ({}}\fi + \if#1+\xint_dothis \XINT_expr_getnext \fi + \if#1.\xint_dothis {\XINT_expr_startdec}\fi + \if#1-\xint_dothis -\fi + \if#1(\xint_dothis {\xint_c_xviii ({}}\fi + \xint_orthat {\XINT_expr_scan_nbr_or_func #1}% +}}% +\def\XINT_expr_scan_macropar #1#2{\expandafter\XINT_expr_getop\csname .=#1#2\endcsname }% +% \end{macrocode} +% \subsection{\csh{XINT_expr_scan_nbr_or_func}: the integer or decimal number or hexa-decimal number or +% function name or variable name or special hacky things big parser} +% \localtableofcontents +% \lverb@1.2 release has replaced chains of \romannumeral-`0 by \csname +% governed expansion. Thus there is no more the limit at about 5000 digits for +% parsed numbers. +% +% In order to avoid having to lock and unlock in succession to handle the +% scientific part and adjust the exponent according to the number of digits of +% the decimal part, the parsing of this decimal part counts on the fly the +% number of digits it encounters. +% +% There is some slight annoyance with \xintiiexpr which should never be given +% a [n] inside its \csname.=<digits>\endcsname storage of numbers (because its +% arithmetic uses the ii macros which know nothing about the [N] notation). +% Hence if the parser has only seen digits when hitting something else than +% the dot or e (or E), it will not insert a [0]. Thus we very slightly +% compromise the efficiency of \xintexpr and \xintfloatexpr in order to be +% able to share the same code with \xintiiexpr. +% +% Indeed, the parser at this location is completely common to all, it does not +% know if it is working inside \xintexpr or \xintiiexpr. On the other hand if +% a dot or a e (or E) is met, then the (common) parser has no scrupules ending +% this number with a [n], this will provoke an error later if that was within +% an \xintiiexpr, as soon as an arithmetic macro is used. +% +% As the gathered numbers have no spaces, no pluses, no minuses, the only +% remaining issue is with leading zeroes, which are discarded on the fly. The +% hexadecimal numbers leading zeroes are stripped in a second stage by the +% \xintHexToDec macro. +% +% With 1.2, \xinttheexpr . \relax does not work anymore (it did in earlier +% releases). There must be digits either before or after the decimal mark. Thus +% both \xinttheexpr 1.\relax and \xinttheexpr .1\relax are legal. +% +% The ` syntax is here used for special constructs like `+`(..), `*`(..) where +% + or * will be treated as functions. Current implementation picks only one +% token (could have been braced stuff), here it will be + or *, and via +% \XINT_expr_op_` this then becomes a suitable +% \XINT_{expr|iiexpr|flexpr}_func_+ (or *). Documentation says to use +% `+`(...), but `+(...) is also valid. The opening parenthesis must be there, +% it is not allowed to come from expansion.@ +% +% \begin{macrocode} +\catcode96 11 % ` +\def\XINT_expr_scan_nbr_or_func #1% this #1 has necessarily here catcode 12 +{%( + \if )#1\xint_dothis \XINT_expr_gotnil \fi + \if "#1\xint_dothis \XINT_expr_scanhex_I\fi + \if `#1\xint_dothis {\XINT_expr_onliteral_`}\fi + \ifnum \xint_c_ix<1#1 \xint_dothis \XINT_expr_startint\fi + \xint_orthat \XINT_expr_scanfunc #1% +}% +\def\XINT_expr_gotnil{\expandafter\XINT_expr_getop\csname.= \endcsname}% +\def\XINT_expr_onliteral_` #1#2#3({\xint_c_xviii `{#2}}% +\catcode96 12 % ` +\def\XINT_expr_startint #1% +{% + \if #10\expandafter\XINT_expr_gobz_a\else\XINT_expr_scanint_a\fi #1% +}% +\def\XINT_expr_scanint_a #1#2% + {\expandafter\XINT_expr_getop\csname.=#1% + \expandafter\XINT_expr_scanint_b\romannumeral`&&@#2}% +\def\XINT_expr_gobz_a #1% + {\expandafter\XINT_expr_getop\csname.=% + \expandafter\XINT_expr_gobz_scanint_b\romannumeral`&&@#1}% +\def\XINT_expr_startdec #1% + {\expandafter\XINT_expr_getop\csname.=% + \expandafter\XINT_expr_scandec_a\romannumeral`&&@#1}% +% \end{macrocode} +% \subsubsection{Integral part (skipping zeroes)} +% \lverb|1.2 has modified the code to give highest priority to digits, the +% accelerating impact is non-negligeable. I don't think the doubled \string is +% a serious penalty.| +% \begin{macrocode} +\def\XINT_expr_scanint_b #1% +{% + \ifcat \relax #1\expandafter\XINT_expr_scanint_endbycs\expandafter #1\fi + \ifnum\xint_c_ix<1\string#1 \else\expandafter\XINT_expr_scanint_c\fi + \string#1\XINT_expr_scanint_d +}% +\def\XINT_expr_scanint_d #1% +{% + \expandafter\XINT_expr_scanint_b\romannumeral`&&@#1% +}% +\def\XINT_expr_scanint_endbycs#1#2\XINT_expr_scanint_d{\endcsname #1}% +% \end{macrocode} +% \lverb|With 1.2d the tacit multiplication in front of a variable name or +% function name is now done with a higher precedence, intermediate between the +% common one of * and / and the one of ^. Thus x/2y is like x/(2y), but x^2y +% is like x^2*y and 2y! is not (2y)! but 2*y!. +% +% Finally, 1.2d has moved away from the _scan macros all the business of the +% tacit multiplication in one unique place via \XINT_expr_getop. For this, the +% ending token is not first given to \string as was done earlier before +% handing over back control to \XINT_expr_getop. Earlier we had to identify +% the catcode 11 ! signaling a sub-expression here. With no \string applied +% we can do it in \XINT_expr_getop. As a corollary of this displacement, +% parsing of big numbers should be a tiny bit faster now. +% +% Extended for 1.2l to ignore underscore character _ if encountered within +% digits; so it can serve as separator for better readability.| +% \begin{macrocode} +\def\XINT_expr_scanint_c\string #1\XINT_expr_scanint_d +{% + \if _#1\xint_dothis\XINT_expr_scanint_d\fi + \if e#1\xint_dothis{[\the\numexpr0\XINT_expr_scanexp_a +}\fi + \if E#1\xint_dothis{[\the\numexpr0\XINT_expr_scanexp_a +}\fi + \if .#1\xint_dothis{\XINT_expr_startdec_a .}\fi + \xint_orthat {\endcsname #1}% +}% +\def\XINT_expr_startdec_a .#1% +{% + \expandafter\XINT_expr_scandec_a\romannumeral`&&@#1% +}% +\def\XINT_expr_scandec_a #1% +{% + \if .#1\xint_dothis{\endcsname..}\fi + \xint_orthat {\XINT_expr_scandec_b 0.#1}% +}% +\def\XINT_expr_gobz_scanint_b #1% +{% + \ifcat \relax #1\expandafter\XINT_expr_gobz_scanint_endbycs\expandafter #1\fi + \ifnum\xint_c_x<1\string#1 \else\expandafter\XINT_expr_gobz_scanint_c\fi + \string#1\XINT_expr_scanint_d +}% +\def\XINT_expr_gobz_scanint_endbycs#1#2\XINT_expr_scanint_d{0\endcsname #1}% +\def\XINT_expr_gobz_scanint_c\string #1\XINT_expr_scanint_d +{% + \if _#1\xint_dothis\XINT_expr_gobz_scanint_d\fi + \if e#1\xint_dothis{0[\the\numexpr0\XINT_expr_scanexp_a +}\fi + \if E#1\xint_dothis{0[\the\numexpr0\XINT_expr_scanexp_a +}\fi + \if .#1\xint_dothis{\XINT_expr_gobz_startdec_a .}\fi + \if 0#1\xint_dothis\XINT_expr_gobz_scanint_d\fi + \xint_orthat {0\endcsname #1}% +}% +\def\XINT_expr_gobz_scanint_d #1% +{% + \expandafter\XINT_expr_gobz_scanint_b\romannumeral`&&@#1% +}% +\def\XINT_expr_gobz_startdec_a .#1% +{% + \expandafter\XINT_expr_gobz_scandec_a\romannumeral`&&@#1% +}% +\def\XINT_expr_gobz_scandec_a #1% +{% + \if .#1\xint_dothis{0\endcsname..}\fi + \xint_orthat {\XINT_expr_gobz_scandec_b 0.#1}% +}% +% \end{macrocode} +% \subsubsection{Fractional part} +% \lverb|Annoying duplication of code to allow 0. as input. +% +% 1.2a corrects a very bad bug in 1.2 \XINT_expr_gobz_scandec_b which should +% have stripped leading zeroes in the fractional part but didn't; as a result +% \xinttheexpr 0.01\relax returned 0 =:-((( Thanks to Kroum Tzanev who +% reported the issue. Does it improve things if I say the bug was introduced +% in 1.2, it wasn't present before ?| +% \begin{macrocode} +\def\XINT_expr_scandec_b #1.#2% +{% + \ifcat \relax #2\expandafter\XINT_expr_scandec_endbycs\expandafter#2\fi + \ifnum\xint_c_ix<1\string#2 \else\expandafter\XINT_expr_scandec_c\fi + \string#2\expandafter\XINT_expr_scandec_d\the\numexpr #1-\xint_c_i.% +}% +\def\XINT_expr_scandec_endbycs #1#2\XINT_expr_scandec_d + \the\numexpr#3-\xint_c_i.{[#3]\endcsname #1}% +\def\XINT_expr_scandec_d #1.#2% +{% + \expandafter\XINT_expr_scandec_b + \the\numexpr #1\expandafter.\romannumeral`&&@#2% +}% +\def\XINT_expr_scandec_c\string #1#2\the\numexpr#3-\xint_c_i.% +{% + \if _#1\xint_dothis{\XINT_expr_scandec_d#3.}\fi + \if e#1\xint_dothis{[\the\numexpr#3\XINT_expr_scanexp_a +}\fi + \if E#1\xint_dothis{[\the\numexpr#3\XINT_expr_scanexp_a +}\fi + \xint_orthat {[#3]\endcsname #1}% +}% +% \end{macrocode} +% \begin{macrocode} +\def\XINT_expr_gobz_scandec_b #1.#2% +{% + \ifcat \relax #2\expandafter\XINT_expr_gobz_scandec_endbycs\expandafter#2\fi + \ifnum\xint_c_ix<1\string#2 \else\expandafter\XINT_expr_gobz_scandec_c\fi + \if0#2\expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi + {\expandafter\XINT_expr_gobz_scandec_b}% + {\string#2\expandafter\XINT_expr_scandec_d}\the\numexpr#1-\xint_c_i.% +}% +% \end{macrocode} +% \begin{macrocode} +\def\XINT_expr_gobz_scandec_endbycs #1#2\xint_c_i.{0[0]\endcsname #1}% +\def\XINT_expr_gobz_scandec_c\if0#1#2\fi #3\numexpr#4-\xint_c_i.% +{% + \if _#1\xint_dothis{\XINT_expr_gobz_scandec_b #4.}\fi + \if e#1\xint_dothis{0[\the\numexpr0\XINT_expr_scanexp_a +}\fi + \if E#1\xint_dothis{0[\the\numexpr0\XINT_expr_scanexp_a +}\fi + \xint_orthat {0[0]\endcsname #1}% +}% +% \end{macrocode} +% \subsubsection{Scientific notation} +% \lverb|Some pluses and minuses are allowed at the start of the scientific +% part, however not later, and no parenthesis.| +% \begin{macrocode} +\def\XINT_expr_scanexp_a #1#2% +{% + #1\expandafter\XINT_expr_scanexp_b\romannumeral`&&@#2% +}% +\def\XINT_expr_scanexp_b #1% +{% + \ifcat \relax #1\expandafter\XINT_expr_scanexp_endbycs\expandafter #1\fi + \ifnum\xint_c_ix<1\string#1 \else\expandafter\XINT_expr_scanexp_c\fi + \string#1\XINT_expr_scanexp_d +}% +\def\XINT_expr_scanexpr_endbycs#1#2\XINT_expr_scanexp_d {]\endcsname #1}% +\def\XINT_expr_scanexp_d #1% +{% + \expandafter\XINT_expr_scanexp_bb\romannumeral`&&@#1% +}% +\def\XINT_expr_scanexp_c\string #1\XINT_expr_scanexp_d +{% + \if _#1\xint_dothis \XINT_expr_scanexp_d \fi + \if +#1\xint_dothis {\XINT_expr_scanexp_a +}\fi + \if -#1\xint_dothis {\XINT_expr_scanexp_a -}\fi + \xint_orthat {]\endcsname #1}% +}% +\def\XINT_expr_scanexp_bb #1% +{% + \ifcat \relax #1\expandafter\XINT_expr_scanexp_endbycs_b\expandafter #1\fi + \ifnum\xint_c_ix<1\string#1 \else\expandafter\XINT_expr_scanexp_cb\fi + \string#1\XINT_expr_scanexp_db +}% +\def\XINT_expr_scanexp_endbycs_b#1#2\XINT_expr_scanexp_db {]\endcsname #1}% +\def\XINT_expr_scanexp_db #1% +{% + \expandafter\XINT_expr_scanexp_bb\romannumeral`&&@#1% +}% +\def\XINT_expr_scanexp_cb\string #1\XINT_expr_scanexp_db +{% + \if _#1\xint_dothis\XINT_expr_scanexp_d\fi + \xint_orthat{]\endcsname #1}% +}% +% \end{macrocode} +% \subsubsection{Hexadecimal numbers} +% \lverb|1.2d has moved most of the handling of tacit multiplication to +% \XINT_expr_getop, but we have to do some of it here, because we apply +% \string before calling \XINT_expr_scanhexI_aa. I do not insert the * +% in \XINT_expr_scanhexI_a, because it is its higher precedence variant which +% will is expected, to do the same as when a non-hexadecimal number prefixes a +% sub-expression. Tacit multiplication in front of variable or function names +% will not work (because of this \string). +% +% Extended for 1.2l to ignore underscore character _ if encountered within +% digits.| +% \begin{macrocode} +\def\XINT_expr_scanhex_I #1% #1=" +{% + \expandafter\XINT_expr_getop\csname.=\expandafter + \XINT_expr_unlock_hex_in\csname.=\XINT_expr_scanhexI_a +}% +\def\XINT_expr_scanhexI_a #1% +{% + \ifcat #1\relax\xint_dothis{.>\endcsname\endcsname #1}\fi + \ifx !#1\xint_dothis{.>\endcsname\endcsname !}\fi + \xint_orthat {\expandafter\XINT_expr_scanhexI_aa\string #1}% +}% +\def\XINT_expr_scanhexI_aa #1% +{% + \if\ifnum`#1>`/ + \ifnum`#1>`9 + \ifnum`#1>`@ + \ifnum`#1>`F + 0\else1\fi\else0\fi\else1\fi\else0\fi 1% + \expandafter\XINT_expr_scanhexI_b + \else + \if _#1\xint_dothis{\expandafter\XINT_expr_scanhexI_bgob}\fi + \if .#1\xint_dothis{\expandafter\XINT_expr_scanhex_transition}\fi + \xint_orthat % gather what we got so far, leave catcode 12 #1 in stream + {\xint_afterfi {.>\endcsname\endcsname}}% + \fi + #1% +}% +\def\XINT_expr_scanhexI_b #1#2% +{% + #1\expandafter\XINT_expr_scanhexI_a\romannumeral`&&@#2% +}% +\def\XINT_expr_scanhexI_bgob #1#2% +{% + \expandafter\XINT_expr_scanhexI_a\romannumeral`&&@#2% +}% +\def\XINT_expr_scanhex_transition .#1% +{% + \expandafter.\expandafter.\expandafter + \XINT_expr_scanhexII_a\romannumeral`&&@#1% +}% +\def\XINT_expr_scanhexII_a #1% +{% + \ifcat #1\relax\xint_dothis{\endcsname\endcsname#1}\fi + \ifx !#1\xint_dothis{\endcsname\endcsname !}\fi + \xint_orthat {\expandafter\XINT_expr_scanhexII_aa\string #1}% +}% +\def\XINT_expr_scanhexII_aa #1% +{% + \if\ifnum`#1>`/ + \ifnum`#1>`9 + \ifnum`#1>`@ + \ifnum`#1>`F + 0\else1\fi\else0\fi\else1\fi\else0\fi 1% + \expandafter\XINT_expr_scanhexII_b + \else + \if _#1\xint_dothis{\expandafter\XINT_expr_scanhexII_bgob}\fi + \xint_orthat{\xint_afterfi {\endcsname\endcsname}}% + \fi + #1% +}% +\def\XINT_expr_scanhexII_b #1#2% +{% + #1\expandafter\XINT_expr_scanhexII_a\romannumeral`&&@#2% +}% +\def\XINT_expr_scanhexII_bgob #1#2% +{% + \expandafter\XINT_expr_scanhexII_a\romannumeral`&&@#2% +}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_scanfunc}: parsing names of functions and variables} +% \begin{macrocode} +\def\XINT_expr_scanfunc +{% + \expandafter\XINT_expr_func\romannumeral`&&@\XINT_expr_scanfunc_a +}% +\def\XINT_expr_scanfunc_a #1#2% +{% + \expandafter #1\romannumeral`&&@\expandafter\XINT_expr_scanfunc_b\romannumeral`&&@#2% +}% +% \end{macrocode} +% \lverb|This handles: 1) (indirectly) tacit multiplication by a variable in +% front a of sub-expression, 2) (indirectly) tacit multiplication in front of +% a \count etc..., 3) functions which are recognized via an encountered opening +% parenthesis (but later this must be disambiguated from variables with tacit +% multiplication) 4) 5) 6) 7) acceptable components of a variable or function +% names: @, underscore, digits, letters (or chars of category code letter.) +% +% The short lived 1.2d which followed the even shorter lived 1.2c managed to +% introduce a bug here as it removed the check for catcode 11 !, which must be +% recognized if ! is not to be taken as part of a variable name. Don't know +% what I was thinking, it was the time when I was moving the handling of tacit +% mutliplication entirely to the \XINT_expr_getop side. Fixed in 1.2e. +% +% I almost decided to remove the \ifcat\relax test whose rôle is to avoid the +% \string#1 to do something bad is the escape char is a digit! Perhaps I will +% remove it at some point ! I truly almost did it, but also the case of no +% escape char is a problem (\string\0, if \0 is a count ...) +% +% The (indirectly) above means that via \XINT_expr_func then \XINT_expr_op__ +% one goes back to \XINT_expr_getop then \XINT_expr_getop_b which is the +% location where tacit multiplication is now centralized. This makes the +% treatment of tacit multiplication for situations such as <variable>\count or +% <variable>\xintexpr..\relax, perhaps a bit sub-optimal, but first the +% variable name must be gathered, second the variable must expand to its +% value.| +% \begin{macrocode} +\def\XINT_expr_scanfunc_b #1% +{% + \ifx !#1\xint_dothis{(_}\fi + \ifcat \relax#1\xint_dothis{(_}\fi + \if (#1\xint_dothis{\xint_firstoftwo{(`}}\fi + \if @#1\xint_dothis \XINT_expr_scanfunc_a \fi + \if _#1\xint_dothis \XINT_expr_scanfunc_a \fi + \ifnum \xint_c_ix<1\string#1 \xint_dothis \XINT_expr_scanfunc_a \fi + \ifcat a#1\xint_dothis \XINT_expr_scanfunc_a \fi + \xint_orthat {(_}% + #1% +}% +% \end{macrocode} +% \lverb@Comments written 2015/11/12: earlier there was an \ifcsname test for +% checking if we had a variable in front of a (, for tacit multiplication for +% example in x(y+z(x+w)) to work. But after I had implemented functions (that +% was yesterday...), I had the problem if was impossible to re-declare a +% variable name such as "f" as a function name. The problem is that here we +% can not test if the function is available because we don't know if we are in +% expr, iiexpr or floatexpr. The \xint_c_xviii causes all fetching operations +% to stop and control is handed over to the routines which will be expr, +% iiexpr ou floatexpr specific, i.e. the \XINT_{expr|iiexpr|flexpr}_op_{`|_} +% which are invoked by the until_<op>_b macros earlier in the stream. +% Functions may exist for one but not the two other parsers. Variables are +% declared via one parser and usable in the others, but naturally \xintiiexpr +% has its restrictions. +% +% Thinking about this again I decided to treat a priori cases such as x(...) +% as functions, after having assigned to each variable a low-weight macro +% which will convert this into _getop\.=<value of x>*(...). To activate that +% macro at the right time I could for this exploit the "onliteral" intercept, +% which is parser independent (1.2c). +% +% This led to me necessarily to rewrite partially the seq, add, mul, subs, +% iter ... routines as now the variables fetch only one token. I think the +% thing is more efficient. +% +% 1.2c had \def\XINT_expr_func #1(#2{\xint_c_xviii #2{#1}} +% +% In \XINT_expr_func the #2 is _ if #1 must be a variable name, or #2=` if #1 +% must be either a function name or possibly a variable name which will then +% have to be followed by tacit multiplication before the opening parenthesis. +% +% The \xint_c_xviii is there because _op_` must know in which parser +% it works. Dispendious for _. Hence I modify for 1.2d. @ +% \begin{macrocode} +\def\XINT_expr_func #1(#2{\if _#2\xint_dothis\XINT_expr_op__\fi + \xint_orthat{\xint_c_xviii #2}{#1}}% +% \end{macrocode} +% \subsection{\csh{XINT_expr_getop}: finding the next operator or closing +% parenthesis or end of expression} +% \lverb|Release 1.1 implements multi-character operators. +% +% 1.2d adds tacit mutiplication also in front of variable or functions names +% starting with a letter, not only a @ or a _ as was already the case. This is +% for (x+y)z situations. It also applies higher precedence in cases like x/2y +% or x/2@, or x/2max(3,5), or x/2\xintexpr 3\relax. +% +% In fact, finally I decide that all sorts of tacit multiplication will always +% use the higher precedence. +% +% Indeed I hesitated somewhat: with the current code one does not know if +% \XINT_expr_getop as invoked after a closing parenthesis or because a number +% parsing ended, and I felt distinguishing the two was unneeded extra stuff. +% This means cases like (a+b)/(c+d)(e+f) will first multiply the last two +% parenthesized terms. +% +% The ! starting a sub-expression must be distinguished from the post-fix ! +% for factorial, thus we must not do a too early \string. In versions < 1.2c, +% the catcode 11 ! had to be identified in all branches of the number or +% function scans. Here it is simply treated as a special case of a letter. +% +% 1.2q adds tacit multiplication in cases such as (1+1)3 or 5!7!| +% \begin{macrocode} +\def\XINT_expr_getop #1#2% this #1 is the current locked computed value +{% + \expandafter\XINT_expr_getop_a\expandafter #1\romannumeral`&&@#2% +}% +\catcode`* 11 +\def\XINT_expr_getop_a #1#2% +{% + \ifx \relax #2\xint_dothis\xint_firstofthree\fi + \ifcat \relax #2\xint_dothis\xint_secondofthree\fi + \ifnum\xint_c_ix<1\string#2 \xint_dothis\xint_secondofthree\fi + \if _#2\xint_dothis \xint_secondofthree\fi + \if @#2\xint_dothis \xint_secondofthree\fi + \if (#2\xint_dothis \xint_secondofthree\fi + \ifcat a#2\xint_dothis \xint_secondofthree\fi + \xint_orthat \xint_thirdofthree + {\XINT_expr_foundend #1}% + {\XINT_expr_precedence_*** *#1#2}% tacit multiplication with higher precedence + {\expandafter\XINT_expr_getop_b \string#2#1}% +}% +\catcode`* 12 +\def\XINT_expr_foundend {\xint_c_ \relax }% \relax is a place holder here. +% \end{macrocode} +% \lverb|? is a very special operator with top precedence which will check if +% the next token is another ?, while avoiding removing a brace pair from token +% stream due to its syntax. Pre 1.1 releases used : rather than ??, but we +% need : for Python like slices of lists.| +% \begin{macrocode} +\def\XINT_expr_getop_b #1% +{% + \if '#1\xint_dothis{\XINT_expr_binopwrd }\fi + \if ?#1\xint_dothis{\XINT_expr_precedence_? ?}\fi + \xint_orthat {\XINT_expr_scanop_a #1}% +}% +\def\XINT_expr_binopwrd #1#2'{\expandafter\XINT_expr_foundop_a + \csname XINT_expr_itself_\xint_zapspaces #2 \xint_gobble_i\endcsname #1}% +\def\XINT_expr_scanop_a #1#2#3% + {\expandafter\XINT_expr_scanop_b\expandafter #1\expandafter #2\romannumeral`&&@#3}% +\def\XINT_expr_scanop_b #1#2#3% +{% + \ifcat#3\relax\xint_dothis{\XINT_expr_foundop_a #1#2#3}\fi + \ifcsname XINT_expr_itself_#1#3\endcsname + \xint_dothis + {\expandafter\XINT_expr_scanop_c\csname XINT_expr_itself_#1#3\endcsname #2}\fi + \xint_orthat {\XINT_expr_foundop_a #1#2#3}% +}% +\def\XINT_expr_scanop_c #1#2#3% +{% + \expandafter\XINT_expr_scanop_d\expandafter #1\expandafter #2\romannumeral`&&@#3% +}% +\def\XINT_expr_scanop_d #1#2#3% +{% + \ifcat#3\relax \xint_dothis{\XINT_expr_foundop #1#2#3}\fi + \ifcsname XINT_expr_itself_#1#3\endcsname + \xint_dothis + {\expandafter\XINT_expr_scanop_c\csname XINT_expr_itself_#1#3\endcsname #2}\fi + \xint_orthat {\csname XINT_expr_precedence_#1\endcsname #1#2#3}% +}% +\def\XINT_expr_foundop_a #1% +{% + \ifcsname XINT_expr_precedence_#1\endcsname + \csname XINT_expr_precedence_#1\expandafter\endcsname + \expandafter #1% + \else + \xint_afterfi{\XINT_expr_unknown_operator {#1}\XINT_expr_getop}% + \fi +}% +\def\XINT_expr_unknown_operator #1{\xintError:removed \xint_gobble_i {#1}}% +\def\XINT_expr_foundop #1{\csname XINT_expr_precedence_#1\endcsname #1}% +% \end{macrocode} +% \subsection{Expansion spanning; opening and closing parentheses} +% \lverb|Version 1.1 had a hack inside the until macros for handling the omit +% and abort in iterations over dummy variables. This has been removed by +% 1.2c, see the subsection where omit and abort are discussed.| +% +% \begin{macrocode} +\catcode`) 11 +\def\XINT_tmpa #1#2#3#4% +{% + \def#1##1% + {% + \xint_UDsignfork + ##1{\expandafter#1\romannumeral`&&@#3}% + -{#2##1}% + \krof + }% + \def#2##1##2% + {% + \ifcase ##1\expandafter\XINT_expr_done + \or\xint_afterfi{\XINT_expr_extra_) + \expandafter #1\romannumeral`&&@\XINT_expr_getop }% + \else + \xint_afterfi{\expandafter#1\romannumeral`&&@\csname XINT_#4_op_##2\endcsname }% + \fi + }% +}% +\def\XINT_expr_extra_) {\xintError:removed }% +\xintFor #1 in {expr,flexpr,iiexpr} \do {% + \expandafter\XINT_tmpa + \csname XINT_#1_until_end_a\expandafter\endcsname + \csname XINT_#1_until_end_b\expandafter\endcsname + \csname XINT_#1_op_-vi\endcsname + {#1}% +}% +\def\XINT_tmpa #1#2#3#4#5#6% +{% + \def #1##1{\expandafter #3\romannumeral`&&@\XINT_expr_getnext }% + \def #2{\expandafter #3\romannumeral`&&@\XINT_expr_getnext }% + \def #3##1{\xint_UDsignfork + ##1{\expandafter #3\romannumeral`&&@#5}% + -{#4##1}% + \krof }% + \def #4##1##2{\ifcase ##1\expandafter\XINT_expr_missing_) + \or \csname XINT_#6_op_##2\expandafter\endcsname + \else + \xint_afterfi{\expandafter #3\romannumeral`&&@\csname XINT_#6_op_##2\endcsname }% + \fi + }% +}% +\def\XINT_expr_missing_) {\xintError:inserted \xint_c_ \XINT_expr_done }% +% \end{macrocode} +% \lverb|We should be using until_( notation to stay synchronous with until_+, +% until_* etc..., but I found that until_) was more telling.| +% \begin{macrocode} +\catcode`) 12 +\xintFor #1 in {expr,flexpr,iiexpr} \do {% + \expandafter\XINT_tmpa + \csname XINT_#1_op_(\expandafter\endcsname + \csname XINT_#1_oparen\expandafter\endcsname + \csname XINT_#1_until_)_a\expandafter\endcsname + \csname XINT_#1_until_)_b\expandafter\endcsname + \csname XINT_#1_op_-vi\endcsname + {#1}% +}% +\expandafter\let\csname XINT_expr_precedence_)\endcsname\xint_c_i +% \end{macrocode} +% \subsection{\textbar, \textbar\textbar, \&, +% \&\&, <, >, =, ==, <=, >=, !=, +, \textendash, +% \texorpdfstring{\protect\lowast}{*}, /, \textasciicircum, +% \texorpdfstring{\protect\lowast\protect\lowast}{**}, //, /:, .., ..[, ].., +% ][, ][:, :], and ++ operators} +% \localtableofcontents +% \subsubsection{Square brackets for lists, the +% !? for omit and abort, and the ++ postfix construct} +% \lverb|This is all very clever and only need setting some suitable precedence +% levels, if only I could understand what I did in 2014... just joking. Notice +% that op_) macros are defined here in the \xintFor loop. +% +% There is some clever business going on here with the letter a for handling +% constructs such as [3..5]*2 (I think...). +% +% 1.2c has replaced 1.1's private dealings with "^C" (which was done before +% dummy variables got implemented) by use of "!?". See discussion of omit and +% abort. +% | +% \begin{macrocode} +\expandafter\let\csname XINT_expr_precedence_]\endcsname\xint_c_i +\expandafter\let\csname XINT_expr_precedence_;\endcsname\xint_c_i +\let\XINT_expr_precedence_a \xint_c_xviii +\let\XINT_expr_precedence_!? \xint_c_ii +\expandafter\let\csname XINT_expr_precedence_++)\endcsname \xint_c_i +% \end{macrocode} +% \lverb|Comments added 2015/11/13 Here we have in particular the mechanism +% for post action on lists via op_] The precedence_] is the one of a closing +% parenthesis. We need the closing parenthesis to do its job, hence we can not +% define a op_]+ operator for example, as we want to assign it the precedence +% of addition not the one of closing parenthesis. The trick I used in 1.1 was +% to let the op_] insert the letter a, this letter exceptionnally also being a +% legitimate operator, launch the _getop and let it find a a*, a+, a/, a-, a^, +% a** operator standing for ]*, ]+, ]/, ]^, ]** postfix item by item list +% operator. I thought I had in mind an example to show that having defined +% op_a and precedence_a for the letter a caused a reduction in syntax for this +% letter, but it seems I am lacking now an example. +% +% 2015/11/18: for 1.2d I accelerate \XINT_expr_op_] to jump over the +% \XINT_expr_getop_a which now does tacit multiplications also in front of +% letters, for reasons of things like, (x+y)z, hence it must not see the "a". +% I could have used a catcode12 a possibly, but anyhow jumping straight to +% \XINT_expr_scanop_a skips a few expansion steps (up to the potential price +% of less conceptual programming if I change things in the future.)| +% \begin{macrocode} +\catcode`. 11 \catcode`= 11 \catcode`+ 11 +\xintFor #1 in {expr,flexpr,iiexpr} \do {% + \expandafter\let\csname XINT_#1_op_)\endcsname \XINT_expr_getop + \expandafter\let\csname XINT_#1_op_;\endcsname \space + \expandafter\def\csname XINT_#1_op_]\endcsname ##1{\XINT_expr_scanop_a a##1}% + \expandafter\let\csname XINT_#1_op_a\endcsname \XINT_expr_getop +% \end{macrocode} +% \lverb|1.1 2014/10/29 did \expandafter\.=+\xintiCeil which transformed it into +% \romannumeral0\xinticeil, which seems a bit weird. This exploited the fact +% that dummy variables macros could back then pick braced material (which in the +% case at hand here ended being {\romannumeral0\xinticeil...} and were submitted +% to two expansions. The result of this was to provide a not value which got +% expanded only in the first loop of the :_A and following macros of seq, +% iter, rseq, etc... +% +% Anyhow with 1.2c I have changed the implementation of dummy variables which +% now need to fetch a single locked token, which they do not expand. +% +% The \xintiCeil appears a bit dispendious, but I need the starting value in a +% \numexpr compatible form in the iteration loops.| +% \begin{macrocode} + \expandafter\def\csname XINT_#1_op_++)\endcsname ##1##2\relax + {\expandafter\XINT_expr_foundend \expandafter + {\expandafter\.=+\csname .=\XINT:NEhook:one\xintiCeil{\XINT_expr_unlock ##1}\endcsname }}% +}% +\catcode`. 12 \catcode`= 12 \catcode`+ 12 +% \end{macrocode} +% \lverb|1.2d adds the *** for tying via tacit multiplication, for example +% x/2y. Actually I don't need the _itself mechanism for ***, only a precedence.| +% \begin{macrocode} +\catcode`& 12 +\xintFor* #1 in {{==}{<=}{>=}{!=}{&&}{||}{**}{//}{/:}{..}{..[}{].}{]..}% + {+[}{-[}{*[}{/[}{**[}{^[}{a+}{a-}{a*}{a/}{a**}{a^}% + {][}{][:}{:]}{!?}{++}{++)}}%{***}} + \do {\expandafter\def\csname XINT_expr_itself_#1\endcsname {#1}}% +\catcode`& 7 +\expandafter\let\csname XINT_expr_precedence_***\endcsname \xint_c_viii +% \end{macrocode} +% \subsubsection{The \textbar, \&, xor, <, >, =, <=, >=, !=, //, /:, .., +, +% \textendash, \texorpdfstring{\protect\lowast}{*}, /, \textasciicircum, ..[, +% and ].. operators for expr, floatexpr and iiexpr operators} +% \lverb|1.2d needed some room between /, * and ^. Hence precedence for ^ +% is now at 9| +% \begin{macrocode} +\def\XINT_expr_defbin_c #1#2#3#4#5#6#7#8#9% +{% + \def #1##1% \XINT_expr_op_<op> ou flexpr ou iiexpr + {% keep value, get next number and operator, then do until + \expandafter #2\expandafter ##1% + \romannumeral`&&@\expandafter\XINT_expr_getnext }% + \def #2##1##2% \XINT_expr_until_<op>_a ou flexpr ou iiexpr + {\xint_UDsignfork ##2{\expandafter #2\expandafter ##1\romannumeral`&&@#4}% + -{#3##1##2}% + \krof }% + \def #3##1##2##3##4% \XINT_expr_until_<op>_b ou flexpr ou iiexpr + {% either execute next operation now, or first do next (possibly unary) + \ifnum ##2>#7% + \xint_afterfi {\expandafter #2\expandafter ##1\romannumeral`&&@% + \csname XINT_#8_op_##3\endcsname {##4}}% + \else \xint_afterfi {\expandafter ##2\expandafter ##3% + \csname .=#9#6{\XINT_expr_unlock ##1}{\XINT_expr_unlock ##4}\endcsname }% + \fi }% + \let #7#5% +}% +\def\XINT_expr_defbin_b #1#2#3#4#5% +{% + \expandafter\XINT_expr_defbin_c + \csname XINT_#1_op_#2\expandafter\endcsname + \csname XINT_#1_until_#2_a\expandafter\endcsname + \csname XINT_#1_until_#2_b\expandafter\endcsname + \csname XINT_#1_op_-#4\expandafter\endcsname + \csname xint_c_#3\expandafter\endcsname + \csname #5\expandafter\endcsname + \csname XINT_expr_precedence_#2\endcsname {#1}\XINT:NEhook:two +}% +\XINT_expr_defbin_b {expr} | {iii}{vi} {xintOR}% +\XINT_expr_defbin_b {flexpr} | {iii}{vi} {xintOR}% +\XINT_expr_defbin_b {iiexpr} | {iii}{vi} {xintOR}% +\XINT_expr_defbin_b {expr} & {iv}{vi} {xintAND}% +\XINT_expr_defbin_b {flexpr} & {iv}{vi} {xintAND}% +\XINT_expr_defbin_b {iiexpr} & {iv}{vi} {xintAND}% +\XINT_expr_defbin_b {expr} {xor}{iii}{vi} {xintXOR}% +\XINT_expr_defbin_b {flexpr}{xor}{iii}{vi} {xintXOR}% +\XINT_expr_defbin_b {iiexpr}{xor}{iii}{vi} {xintXOR}% +\XINT_expr_defbin_b {expr} < {v}{vi} {xintLt}% +\XINT_expr_defbin_b {flexpr} < {v}{vi} {xintLt}% +\XINT_expr_defbin_b {iiexpr} < {v}{vi} {xintiiLt}% +\XINT_expr_defbin_b {expr} > {v}{vi} {xintGt}% +\XINT_expr_defbin_b {flexpr} > {v}{vi} {xintGt}% +\XINT_expr_defbin_b {iiexpr} > {v}{vi} {xintiiGt}% +\XINT_expr_defbin_b {expr} = {v}{vi} {xintEq}% +\XINT_expr_defbin_b {flexpr} = {v}{vi} {xintEq}% +\XINT_expr_defbin_b {iiexpr} = {v}{vi} {xintiiEq}% +\XINT_expr_defbin_b {expr} {<=} {v}{vi} {xintLtorEq}% +\XINT_expr_defbin_b {flexpr}{<=} {v}{vi} {xintLtorEq}% +\XINT_expr_defbin_b {iiexpr}{<=} {v}{vi} {xintiiLtorEq}% +\XINT_expr_defbin_b {expr} {>=} {v}{vi} {xintGtorEq}% +\XINT_expr_defbin_b {flexpr}{>=} {v}{vi} {xintGtorEq}% +\XINT_expr_defbin_b {iiexpr}{>=} {v}{vi} {xintiiGtorEq}% +\XINT_expr_defbin_b {expr} {!=} {v}{vi} {xintNotEq}% +\XINT_expr_defbin_b {flexpr}{!=} {v}{vi} {xintNotEq}% +\XINT_expr_defbin_b {iiexpr}{!=} {v}{vi} {xintiiNotEq}% +\XINT_expr_defbin_b {expr} {//} {vii}{vii}{xintDivFloor}% CHANGED IN 1.2p! +\XINT_expr_defbin_b {flexpr}{//} {vii}{vii}{XINTinFloatDivFloor}% " +\XINT_expr_defbin_b {iiexpr}{//} {vii}{vii}{xintiiDivFloor}% " +\XINT_expr_defbin_b {expr} {/:} {vii}{vii}{xintMod}% " +\XINT_expr_defbin_b {flexpr}{/:} {vii}{vii}{XINTinFloatMod}% " +\XINT_expr_defbin_b {iiexpr}{/:} {vii}{vii}{xintiiMod}% " +\XINT_expr_defbin_b {expr} + {vi}{vi} {xintAdd}% +\XINT_expr_defbin_b {flexpr} + {vi}{vi} {XINTinFloatAdd}% +\XINT_expr_defbin_b {iiexpr} + {vi}{vi} {xintiiAdd}% +\XINT_expr_defbin_b {expr} - {vi}{vi} {xintSub}% +\XINT_expr_defbin_b {flexpr} - {vi}{vi} {XINTinFloatSub}% +\XINT_expr_defbin_b {iiexpr} - {vi}{vi} {xintiiSub}% +\XINT_expr_defbin_b {expr} * {vii}{vii}{xintMul}% +\XINT_expr_defbin_b {flexpr} * {vii}{vii}{XINTinFloatMul}% +\XINT_expr_defbin_b {iiexpr} * {vii}{vii}{xintiiMul}% +\XINT_expr_defbin_b {expr} / {vii}{vii}{xintDiv}% +\XINT_expr_defbin_b {flexpr} / {vii}{vii}{XINTinFloatDiv}% +\XINT_expr_defbin_b {iiexpr} / {vii}{vii}{xintiiDivRound}% CHANGED IN 1.1! +\XINT_expr_defbin_b {expr} ^ {ix}{ix} {xintPow}% +\XINT_expr_defbin_b {flexpr} ^ {ix}{ix} {XINTinFloatPowerH}% +\XINT_expr_defbin_b {iiexpr} ^ {ix}{ix} {xintiiPow}% +\XINT_expr_defbin_b {expr} {..[}{iii}{vi} {xintSeqA::csv}% +\XINT_expr_defbin_b {flexpr}{..[}{iii}{vi} {XINTinFloatSeqA::csv}% +\XINT_expr_defbin_b {iiexpr}{..[}{iii}{vi} {xintiiSeqA::csv}% +\def\XINT_expr_defbin_b #1#2#3#4#5% +{% + \expandafter\XINT_expr_defbin_c + \csname XINT_#1_op_#2\expandafter\endcsname + \csname XINT_#1_until_#2_a\expandafter\endcsname + \csname XINT_#1_until_#2_b\expandafter\endcsname + \csname XINT_#1_op_-#4\expandafter\endcsname + \csname xint_c_#3\expandafter\endcsname + \csname #5\expandafter\endcsname + \csname XINT_expr_precedence_#2\endcsname {#1}{}% +}% +\XINT_expr_defbin_b {expr} {..} {iii}{vi} {xintSeq::csv}% +\XINT_expr_defbin_b {flexpr}{..} {iii}{vi} {xintSeq::csv}% +\XINT_expr_defbin_b {iiexpr}{..} {iii}{vi} {xintiiSeq::csv}% +\XINT_expr_defbin_b {expr} {]..}{iii}{vi} {xintSeqB::csv}% +\XINT_expr_defbin_b {flexpr}{]..}{iii}{vi} {XINTinFloatSeqB::csv}% +\XINT_expr_defbin_b {iiexpr}{]..}{iii}{vi} {xintiiSeqB::csv}% +% \end{macrocode} +% \subsubsection{The ]+, ]\textendash, ]\texorpdfstring{\protect\lowast}{*}, ]/, ]\textasciicircum, +[, \textendash[, \texorpdfstring{\protect\lowast}{*}[, /[, and \textasciicircum[ list +% operators} +% \paragraph{\csh{XINT_expr_binop_inline_b}}\par +% \lverb|This handles acting on comma separated values (no need to bother +% about spaces in this context; expansion in a \csname...\endcsname.| +% \begin{macrocode} +\def\XINT_expr_binop_inline#1% + {\XINT_expr_binop_inline_a{\expandafter\XINT:NEhook:two\expandafter#1}}% +\def\XINT_expr_binop_inline_a + {\expandafter\xint_gobble_i\romannumeral`&&@\XINT_expr_binop_inline_b }% +\def\XINT_expr_binop_inline_b #1#2,{\XINT_expr_binop_inline_c #2,{#1}}% +\def\XINT_expr_binop_inline_c #1{% + \if ,#1\xint_dothis\XINT_expr_binop_inline_e\fi + \if ^#1\xint_dothis\XINT_expr_binop_inline_end\fi + \xint_orthat\XINT_expr_binop_inline_d #1}% +\def\XINT_expr_binop_inline_d #1,#2{,#2{#1}\XINT_expr_binop_inline_b {#2}}% +\def\XINT_expr_binop_inline_e #1,#2{,\XINT_expr_binop_inline_b {#2}}% +\def\XINT_expr_binop_inline_end #1,#2{}% +\def\XINT_expr_deflistopr_c #1#2#3#4#5#6#7#8% +{% + \def #1##1% \XINT_expr_op_<op> ou flexpr ou iiexpr + {% keep value, get next number and operator, then do until + \expandafter #2\expandafter ##1% + \romannumeral`&&@\expandafter\XINT_expr_getnext }% + \def #2##1##2% \XINT_expr_until_<op>_a ou flexpr ou iiexpr + {\xint_UDsignfork ##2{\expandafter #2\expandafter ##1\romannumeral`&&@#4}% + -{#3##1##2}% + \krof }% + \def #3##1##2##3##4% \XINT_expr_until_<op>_b ou flexpr ou iiexpr + {% either execute next operation now, or first do next (possibly unary) + \ifnum ##2>#7% + \xint_afterfi {\expandafter #2\expandafter ##1\romannumeral`&&@% + \csname XINT_#8_op_##3\endcsname {##4}}% + \else \xint_afterfi {\expandafter ##2\expandafter ##3% + \csname .=\expandafter\XINT_expr_binop_inline\expandafter + {\expandafter#6\expandafter\xint_exchangetwo_keepbraces\expandafter + {\expandafter\XINT_expr_unlock\expandafter ##4\expandafter}\expandafter}% + \romannumeral`&&@\XINT_expr_unlock ##1,^,\endcsname }% + \fi }% + \let #7#5% +}% +\def\XINT_expr_deflistopr_b #1#2#3#4% +{% + \expandafter\XINT_expr_deflistopr_c + \csname XINT_#1_op_#2\expandafter\endcsname + \csname XINT_#1_until_#2_a\expandafter\endcsname + \csname XINT_#1_until_#2_b\expandafter\endcsname + \csname XINT_#1_op_-#3\expandafter\endcsname + \csname xint_c_#3\expandafter\endcsname + \csname #4\expandafter\endcsname + \csname XINT_expr_precedence_#2\endcsname {#1}% +}% +% \end{macrocode} +% \lverb|This is for [x..y]*z syntax etc.... Attention that with 1.2d, +% precedence level of ^ raised to ix to make room for ***.| +% \begin{macrocode} +\XINT_expr_deflistopr_b {expr} {a+}{vi} {xintAdd}% +\XINT_expr_deflistopr_b {expr} {a-}{vi} {xintSub}% +\XINT_expr_deflistopr_b {expr} {a*}{vii}{xintMul}% +\XINT_expr_deflistopr_b {expr} {a/}{vii}{xintDiv}% +\XINT_expr_deflistopr_b {expr} {a^}{ix} {xintPow}% +\XINT_expr_deflistopr_b {iiexpr}{a+}{vi} {xintiiAdd}% +\XINT_expr_deflistopr_b {iiexpr}{a-}{vi} {xintiiSub}% +\XINT_expr_deflistopr_b {iiexpr}{a*}{vii}{xintiiMul}% +\XINT_expr_deflistopr_b {iiexpr}{a/}{vii}{xintiiDivRound}% +\XINT_expr_deflistopr_b {iiexpr}{a^}{ix} {xintiiPow}% +\XINT_expr_deflistopr_b {flexpr}{a+}{vi} {XINTinFloatAdd}% +\XINT_expr_deflistopr_b {flexpr}{a-}{vi} {XINTinFloatSub}% +\XINT_expr_deflistopr_b {flexpr}{a*}{vii}{XINTinFloatMul}% +\XINT_expr_deflistopr_b {flexpr}{a/}{vii}{XINTinFloatDiv}% +\XINT_expr_deflistopr_b {flexpr}{a^}{ix} {XINTinFloatPowerH}% +\def\XINT_expr_deflistopl_c #1#2#3#4#5#6#7% +{% + \def #1##1{\expandafter#2\expandafter##1\romannumeral`&&@% + \expandafter #3\romannumeral`&&@\XINT_expr_getnext }% + \def #2##1##2##3##4% + {% either execute next operation now, or first do next (possibly unary) + \ifnum ##2>#6% + \xint_afterfi {\expandafter #2\expandafter ##1\romannumeral`&&@% + \csname XINT_#7_op_##3\endcsname {##4}}% + \else \xint_afterfi {\expandafter ##2\expandafter ##3% + \csname .=\expandafter\XINT_expr_binop_inline\expandafter + {\expandafter#5\expandafter + {\expandafter\XINT_expr_unlock\expandafter ##1\expandafter}\expandafter}% + \romannumeral`&&@\XINT_expr_unlock ##4,^,\endcsname }% + \fi }% + \let #6#4% +}% +\def\XINT_expr_deflistopl_b #1#2#3#4% +{% + \expandafter\XINT_expr_deflistopl_c + \csname XINT_#1_op_#2\expandafter\endcsname + \csname XINT_#1_until_#2\expandafter\endcsname + \csname XINT_#1_until_)_a\expandafter\endcsname + \csname xint_c_#3\expandafter\endcsname + \csname #4\expandafter\endcsname + \csname XINT_expr_precedence_#2\endcsname {#1}% +}% +% \end{macrocode} +% \lverb|This is for z*[x..y] syntax etc...| +% \begin{macrocode} +\XINT_expr_deflistopl_b {expr} {+[}{vi} {xintAdd}% +\XINT_expr_deflistopl_b {expr} {-[}{vi} {xintSub}% +\XINT_expr_deflistopl_b {expr} {*[}{vii}{xintMul}% +\XINT_expr_deflistopl_b {expr} {/[}{vii}{xintDiv}% +\XINT_expr_deflistopl_b {expr} {^[}{ix} {xintPow}% +\XINT_expr_deflistopl_b {iiexpr}{+[}{vi} {xintiiAdd}% +\XINT_expr_deflistopl_b {iiexpr}{-[}{vi} {xintiiSub}% +\XINT_expr_deflistopl_b {iiexpr}{*[}{vii}{xintiiMul}% +\XINT_expr_deflistopl_b {iiexpr}{/[}{vii}{xintiiDivRound}% +\XINT_expr_deflistopl_b {iiexpr}{^[}{ix} {xintiiPow}% +\XINT_expr_deflistopl_b {flexpr}{+[}{vi} {XINTinFloatAdd}% +\XINT_expr_deflistopl_b {flexpr}{-[}{vi} {XINTinFloatSub}% +\XINT_expr_deflistopl_b {flexpr}{*[}{vii}{XINTinFloatMul}% +\XINT_expr_deflistopl_b {flexpr}{/[}{vii}{XINTinFloatDiv}% +\XINT_expr_deflistopl_b {flexpr}{^[}{ix} {XINTinFloatPowerH}% +% \end{macrocode} +% \subsubsection{The \textquotesingle and\textquotesingle, \textquotesingle +% or\textquotesingle, \textquotesingle xor\textquotesingle, and +% \textquotesingle mod\textquotesingle\ as infix operator words} +% \begin{macrocode} +\xintFor #1 in {and,or,xor,mod} \do {% + \expandafter\def\csname XINT_expr_itself_#1\endcsname {#1}}% +\expandafter\let\csname XINT_expr_precedence_and\expandafter\endcsname + \csname XINT_expr_precedence_&\endcsname +\expandafter\let\csname XINT_expr_precedence_or\expandafter\endcsname + \csname XINT_expr_precedence_|\endcsname +\expandafter\let\csname XINT_expr_precedence_mod\expandafter\endcsname + \csname XINT_expr_precedence_/:\endcsname +\xintFor #1 in {expr, flexpr, iiexpr} \do {% + \expandafter\let\csname XINT_#1_op_and\expandafter\endcsname + \csname XINT_#1_op_&\endcsname + \expandafter\let\csname XINT_#1_op_or\expandafter\endcsname + \csname XINT_#1_op_|\endcsname + \expandafter\let\csname XINT_#1_op_mod\expandafter\endcsname + \csname XINT_#1_op_/:\endcsname +}% +% \end{macrocode} +% \subsubsection{The \textbar\textbar, +% \&\&, \texorpdfstring{\protect\lowast\protect\lowast, +% \protect\lowast\protect\lowast[, ]\protect\lowast\protect\lowast}{**, **[, ]**}{} operators as synonyms} +% \begin{macrocode} +\expandafter\let\csname XINT_expr_precedence_==\expandafter\endcsname + \csname XINT_expr_precedence_=\endcsname +\expandafter\let\csname XINT_expr_precedence_&\string&\expandafter\endcsname + \csname XINT_expr_precedence_&\endcsname +\expandafter\let\csname XINT_expr_precedence_||\expandafter\endcsname + \csname XINT_expr_precedence_|\endcsname +\expandafter\let\csname XINT_expr_precedence_**\expandafter\endcsname + \csname XINT_expr_precedence_^\endcsname +\expandafter\let\csname XINT_expr_precedence_a**\expandafter\endcsname + \csname XINT_expr_precedence_a^\endcsname +\expandafter\let\csname XINT_expr_precedence_**[\expandafter\endcsname + \csname XINT_expr_precedence_^[\endcsname +\xintFor #1 in {expr, flexpr, iiexpr} \do {% + \expandafter\let\csname XINT_#1_op_==\expandafter\endcsname + \csname XINT_#1_op_=\endcsname + \expandafter\let\csname XINT_#1_op_&\string&\expandafter\endcsname + \csname XINT_#1_op_&\endcsname + \expandafter\let\csname XINT_#1_op_||\expandafter\endcsname + \csname XINT_#1_op_|\endcsname + \expandafter\let\csname XINT_#1_op_**\expandafter\endcsname + \csname XINT_#1_op_^\endcsname + \expandafter\let\csname XINT_#1_op_a**\expandafter\endcsname + \csname XINT_#1_op_a^\endcsname + \expandafter\let\csname XINT_#1_op_**[\expandafter\endcsname + \csname XINT_#1_op_^[\endcsname +}% +% \end{macrocode} +% \subsection{Macros for list selectors: [list][N], [list][:b], [list][a:], [list][a:b]} +% \localtableofcontents +% +% \lverb|Python slicing was first implemented for 1.1 (27 octobre 2014). But +% it used \xintCSVtoList and \xintListWithSep{,} to convert back and forth to +% token lists for use of \xintKeep, \xintTrim, \xintNthElt. Not very +% efficient! Also [list][a:b] was Python like but not [list][N] which counted +% items starting at one, and returned the length for N=0. +% +% Release 1.2g changed this so [list][N] now counts starting at zero and +% len(list) computes the number of items. Also 1.2g had its own f-expandable +% macros handling directly the comma separated lists. They are located into +% $xinttoolsnameimp.sty. +% +% 1.2j improved the $xinttoolsnameimp.sty macros and furthermore it made the +% Python slicing in expressions a bit more efficient still by exploiting in +% some cases that expansion happens in \csname...\endcsname and does not have +% to be f-expandable. But the f-expandable variants must be kept for use by +% \xintNewExpr and \xintdeffunc. +% | +% \begin{macrocode} +\def\XINT_tmpa #1#2#3#4#5#6% +{% + \def #1##1% \XINT_expr_op_][ + {% + \expandafter #2\expandafter ##1\romannumeral`&&@\XINT_expr_getnext + }% + \def #2##1##2% \XINT_expr_until_][_a + {\xint_UDsignfork + ##2{\expandafter #2\expandafter ##1\romannumeral`&&@#4}% + -{#3##1##2}% + \krof }% + \def #3##1##2##3##4% \XINT_expr_until_][_b + {% + \ifnum ##2>#5% + \xint_afterfi {\expandafter #2\expandafter ##1\romannumeral`&&@% + \csname XINT_#6_op_##3\endcsname {##4}}% + \else + \xint_afterfi + {\expandafter ##2\expandafter ##3\csname + .=\expandafter\xintListSel:x:csv % will be \xintListSel:f:csv in \xintNewExpr output + \romannumeral`&&@\XINT_expr_unlock ##4;% selector + \XINT_expr_unlock ##1;\endcsname % unlock already pre-positioned for \xintNewExpr + }% + \fi + }% + \let #5\xint_c_ii +}% +\xintFor #1 in {expr,flexpr,iiexpr} \do {% +\expandafter\XINT_tmpa + \csname XINT_#1_op_][\expandafter\endcsname + \csname XINT_#1_until_][_a\expandafter\endcsname + \csname XINT_#1_until_][_b\expandafter\endcsname + \csname XINT_#1_op_-vi\expandafter\endcsname + \csname XINT_expr_precedence_][\endcsname {#1}% +}% +\def\XINT_tmpa #1#2#3#4#5#6% +{% + \def #1##1% \XINT_expr_op_: + {% + \expandafter #2\expandafter ##1\romannumeral`&&@\XINT_expr_getnext + }% + \def #2##1##2% \XINT_expr_until_:_a + {\xint_UDsignfork + ##2{\expandafter #2\expandafter ##1\romannumeral`&&@#4}% + -{#3##1##2}% + \krof }% + \def #3##1##2##3##4% \XINT_expr_until_:_b + {% + \ifnum ##2>#5% + \xint_afterfi {\expandafter #2\expandafter ##1\romannumeral`&&@% + \csname XINT_#6_op_##3\endcsname {##4}}% + \else + \xint_afterfi + {\expandafter ##2\expandafter ##3\csname + .=:\XINT:NEhook:one\xintNum{\XINT_expr_unlock ##1};% + \XINT:NEhook:one\xintNum{\XINT_expr_unlock ##4}% + \endcsname + }% + \fi + }% + \let #5\xint_c_iii +}% +\xintFor #1 in {expr,flexpr,iiexpr} \do {% +\expandafter\XINT_tmpa + \csname XINT_#1_op_:\expandafter\endcsname + \csname XINT_#1_until_:_a\expandafter\endcsname + \csname XINT_#1_until_:_b\expandafter\endcsname + \csname XINT_#1_op_-vi\expandafter\endcsname + \csname XINT_expr_precedence_:\endcsname {#1}% +}% +\catcode`[ 11 \catcode`] 11 +\let\XINT_expr_precedence_:] \xint_c_iii +\def\XINT_expr_op_:] #1% +{% + \expandafter\xint_c_i\expandafter )% + \csname .=]\XINT:NEhook:one\xintNum{\XINT_expr_unlock #1}\endcsname +}% +\let\XINT_flexpr_op_:] \XINT_expr_op_:] +\let\XINT_iiexpr_op_:] \XINT_expr_op_:] +\let\XINT_expr_precedence_][: \xint_c_iii +% \end{macrocode} +% \lverb|At the end of the replacement text of \XINT_expr_op_][:, the : after +% index 0 must be catcode 12, else will be mistaken for the start of variable +% by expression parser (as <digits><variable> is allowed by the syntax and does +% tacit multiplication).| +% \begin{macrocode} +\edef\XINT_expr_op_][: #1{\xint_c_ii\noexpand\XINT_expr_itself_][#10\string :}% +\let\XINT_flexpr_op_][: \XINT_expr_op_][: +\let\XINT_iiexpr_op_][: \XINT_expr_op_][: +\catcode`[ 12 \catcode`] 12 +% \end{macrocode} +% \subsubsection{\csh{xintListSel:x:csv}} +% \lverb|1.2j. Because there is \xintKeep:x:csv which is faster than +% \xintKeep:f:csv.| +% \begin{macrocode} +\def\xintListSel:x:csv #1% +{% + \if ]\noexpand#1\xint_dothis\XINT_listsel:_s\fi + \if :\noexpand#1\xint_dothis\XINT_listxsel:_:\fi + \xint_orthat {\XINT_listsel:_nth #1}% +}% +\def\XINT_listsel:_s #1#2;#3;% +{% + \if-#1\expandafter\xintKeep:f:csv\else\expandafter\xintTrim:f:csv\fi + {#1#2}{#3}% +}% +\def\XINT_listsel:_nth #1;#2;{\xintNthEltPy:f:csv {\xintNum{#1}}{#2}}% +% \end{macrocode} +% \lverb|\XINT_listsel:_nth and \XINT_listsel:_s located in \xintListSel:f:csv.| +% \begin{macrocode} +\def\XINT_listxsel:_: #1#2;#3#4;% +{% + \xint_UDsignsfork + #1#3\XINT_listxsel:_N:N + #1-\XINT_listxsel:_N:P + -#3\XINT_listxsel:_P:N + --\XINT_listxsel:_P:P + \krof #1#2;#3#4;% +}% +\def\XINT_listxsel:_P:P #1;#2;#3;% +{% + \unless\ifnum #1<#2 \expandafter\xint_gobble_iii\fi + \xintKeep:x:csv{#2-#1}{\xintTrim:f:csv{#1}{#3}}% +}% +\def\XINT_listxsel:_N:N #1;#2;#3;% +{% + \expandafter\XINT_listxsel:_N:N_a + \the\numexpr #2-#1\expandafter;\the\numexpr#1+\xintLength:f:csv{#3};#3;% +}% +\def\XINT_listxsel:_N:N_a #1;#2;#3;% +{% + \unless\ifnum #1>\xint_c_ \expandafter\xint_gobble_iii\fi + \xintKeep:x:csv{#1}{\xintTrim:f:csv{\ifnum#2<\xint_c_\xint_c_\else#2\fi}{#3}}% +}% +\def\XINT_listxsel:_N:P #1;#2;#3;{\expandafter\XINT_listxsel:_N:P_a + \the\numexpr #1+\xintLength:f:csv{#3};#2;#3;}% +\def\XINT_listxsel:_N:P_a #1#2;% + {\if -#1\expandafter\XINT_listxsel:_O:P\fi\XINT_listxsel:_P:P #1#2;}% +\def\XINT_listxsel:_O:P\XINT_listxsel:_P:P #1;{\XINT_listxsel:_P:P 0;}% +\def\XINT_listxsel:_P:N #1;#2;#3;{\expandafter\XINT_listxsel:_P:N_a + \the\numexpr #2+\xintLength:f:csv{#3};#1;#3;}% +\def\XINT_listxsel:_P:N_a #1#2;#3;% + {\if -#1\expandafter\XINT_listxsel:_P:O\fi\XINT_listxsel:_P:P #3;#1#2;}% +\def\XINT_listxsel:_P:O\XINT_listxsel:_P:P #1;#2;{\XINT_listxsel:_P:P #1;0;}% +% \end{macrocode} +% \subsubsection{\csh{xintListSel:f:csv}} +% \lverb|1.2g. Since 1.2j this is needed only for \xintNewExpr and user +% defined functions. Some extras compared to \xintListSel:x:csv because things +% may not yet have been expanded in the \xintNewExpr context.| +% \begin{macrocode} +\def\xintListSel:f:csv #1% +{% + \if ]\noexpand#1\xint_dothis{\expandafter\XINT_listsel:_s\romannumeral`&&@}\fi + \if :\noexpand#1\xint_dothis{\XINT_listsel:_:}\fi + \xint_orthat {\XINT_listsel:_nth #1}% +}% +\def\XINT_listsel:_: #1;#2;% +{% + \expandafter\XINT_listsel:_:a + \the\numexpr #1\expandafter;\the\numexpr #2\expandafter;\romannumeral`&&@% +}% +\def\XINT_listsel:_:a #1#2;#3#4;% +{% + \xint_UDsignsfork + #1#3\XINT_listsel:_N:N + #1-\XINT_listsel:_N:P + -#3\XINT_listsel:_P:N + --\XINT_listsel:_P:P + \krof #1#2;#3#4;% +}% +\def\XINT_listsel:_P:P #1;#2;#3;% +{% + \unless\ifnum #1<#2 \xint_afterfi{\expandafter\space\xint_gobble_iii}\fi + \xintKeep:f:csv{#2-#1}{\xintTrim:f:csv{#1}{#3}}% +}% +\def\XINT_listsel:_N:N #1;#2;#3;% +{% + \unless\ifnum #1<#2 \expandafter\XINT_listsel:_N:N_abort\fi + \expandafter\XINT_listsel:_N:N_a + \the\numexpr#1+\xintLength:f:csv{#3}\expandafter;\the\numexpr#2-#1;#3;% +}% +\def\XINT_listsel:_N:N_abort #1;#2;#3;{ }% +\def\XINT_listsel:_N:N_a #1;#2;#3;% +{% + \xintKeep:f:csv{#2}{\xintTrim:f:csv{\ifnum#1<\xint_c_\xint_c_\else#1\fi}{#3}}% +}% +\def\XINT_listsel:_N:P #1;#2;#3;{\expandafter\XINT_listsel:_N:P_a + \the\numexpr #1+\xintLength:f:csv{#3};#2;#3;}% +\def\XINT_listsel:_N:P_a #1#2;% + {\if -#1\expandafter\XINT_listsel:_O:P\fi\XINT_listsel:_P:P #1#2;}% +\def\XINT_listsel:_O:P\XINT_listsel:_P:P #1;{\XINT_listsel:_P:P 0;}% +\def\XINT_listsel:_P:N #1;#2;#3;{\expandafter\XINT_listsel:_P:N_a + \the\numexpr #2+\xintLength:f:csv{#3};#1;#3;}% +\def\XINT_listsel:_P:N_a #1#2;#3;% + {\if -#1\expandafter\XINT_listsel:_P:O\fi\XINT_listsel:_P:P #3;#1#2;}% +\def\XINT_listsel:_P:O\XINT_listsel:_P:P #1;#2;{\XINT_listsel:_P:P #1;0;}% +% \end{macrocode} +% \subsubsection{\csh{xintKeep:x:csv}} +% \lverb|1.2j. This macro is used only with positive first argument. +% | +% \begin{macrocode} +\def\xintKeep:x:csv #1#2% +{% + \expandafter\xint_gobble_i + \romannumeral0\expandafter\XINT_keep:x:csv_pos + \the\numexpr #1\expandafter.\expandafter{\romannumeral`&&@#2}% +}% +\def\XINT_keep:x:csv_pos #1.#2% +{% + \expandafter\XINT_keep:x:csv_loop\the\numexpr#1-\xint_c_viii.% + #2\xint_Bye,\xint_Bye,\xint_Bye,\xint_Bye,% + \xint_Bye,\xint_Bye,\xint_Bye,\xint_Bye,\xint_bye +}% +\def\XINT_keep:x:csv_loop #1% +{% + \xint_gob_til_minus#1\XINT_keep:x:csv_finish-% + \XINT_keep:x:csv_loop_pickeight #1% +}% +\def\XINT_keep:x:csv_loop_pickeight #1.#2,#3,#4,#5,#6,#7,#8,#9,% +{% + ,#2,#3,#4,#5,#6,#7,#8,#9% + \expandafter\XINT_keep:x:csv_loop\the\numexpr#1-\xint_c_viii.% +}% +\def\XINT_keep:x:csv_finish-\XINT_keep:x:csv_loop_pickeight -#1.% +{% + \csname XINT_keep:x:csv_finish#1\endcsname +}% +\expandafter\def\csname XINT_keep:x:csv_finish1\endcsname + #1,#2,#3,#4,#5,#6,#7,{,#1,#2,#3,#4,#5,#6,#7\xint_Bye}% +\expandafter\def\csname XINT_keep:x:csv_finish2\endcsname + #1,#2,#3,#4,#5,#6,{,#1,#2,#3,#4,#5,#6\xint_Bye}% +\expandafter\def\csname XINT_keep:x:csv_finish3\endcsname + #1,#2,#3,#4,#5,{,#1,#2,#3,#4,#5\xint_Bye}% +\expandafter\def\csname XINT_keep:x:csv_finish4\endcsname + #1,#2,#3,#4,{,#1,#2,#3,#4\xint_Bye}% +\expandafter\def\csname XINT_keep:x:csv_finish5\endcsname + #1,#2,#3,{,#1,#2,#3\xint_Bye}% +\expandafter\def\csname XINT_keep:x:csv_finish6\endcsname + #1,#2,{,#1,#2\xint_Bye}% +\expandafter\def\csname XINT_keep:x:csv_finish7\endcsname + #1,{,#1\xint_Bye}% +\expandafter\let\csname XINT_keep:x:csv_finish8\endcsname\xint_Bye +% \end{macrocode} +% \subsubsection{\cshnolabel{xintKeep:f:csv}} +% \changed{1.2g}{} moved to \xinttoolsnameimp. +% \subsubsection{\cshnolabel{xintTrim:f:csv}} +% \changed{1.2g}{} moved to \xinttoolsnameimp. +% \subsubsection{\cshnolabel{xintNthEltPy:f:csv}} +% \changed{1.2g}{} moved to \xinttoolsnameimp. +% \subsubsection{\cshnolabel{xintLength:f:csv}} +% \changed{1.2g}{} moved to \xinttoolsnameimp. +% \subsubsection{\cshnolabel{xintReverse:f:csv}} +% \changed{1.2g}{} moved to \xinttoolsnameimp. +% +% \subsection{Macros for a..b list generation} +% \localtableofcontents +% +% \lverb|Ne produit que des listes d'entiers inférieurs à la borne +% de TeX ! mais sous la forme N/1[0] en ce qui concerne \xintSeq::csv.| +% +%\subsubsection{\csh{xintSeq::csv}} +%\lverb|Commence par remplacer a par ceil(a) et b par floor(b) et renvoie +% ensuite les entiers entre les deux, possiblement en décroissant, et +% extrémités comprises. Si a=b est non entier en obtient donc ceil(a) et +% floor(a). Ne renvoie jamais une liste vide. +% +% Note: le a..b dans \xintfloatexpr utilise cette routine.| +% \begin{macrocode} +\def\xintSeq::csv {\romannumeral0\xintseq::csv }% +\def\xintseq::csv #1#2% +{% + \expandafter\XINT_seq::csv\expandafter + {\the\numexpr \xintiCeil{#1}\expandafter}\expandafter + {\the\numexpr \xintiFloor{#2}}% +}% +\def\XINT_seq::csv #1#2% +{% + \ifcase\ifnum #1=#2 0\else\ifnum #2>#1 1\else -1\fi\fi\space + \expandafter\XINT_seq::csv_z + \or + \expandafter\XINT_seq::csv_p + \else + \expandafter\XINT_seq::csv_n + \fi + {#2}{#1}% +}% +\def\XINT_seq::csv_z #1#2{ #1/1[0]}% +\def\XINT_seq::csv_p #1#2% +{% + \ifnum #1>#2 + \expandafter\expandafter\expandafter\XINT_seq::csv_p + \else + \expandafter\XINT_seq::csv_e + \fi + \expandafter{\the\numexpr #1-\xint_c_i}{#2},#1/1[0]% +}% +\def\XINT_seq::csv_n #1#2% +{% + \ifnum #1<#2 + \expandafter\expandafter\expandafter\XINT_seq::csv_n + \else + \expandafter\XINT_seq::csv_e + \fi + \expandafter{\the\numexpr #1+\xint_c_i}{#2},#1/1[0]% +}% +\def\XINT_seq::csv_e #1,{ }% +% \end{macrocode} +%\subsubsection{\csh{xintiiSeq::csv}} +% \begin{macrocode} +\def\xintiiSeq::csv {\romannumeral0\xintiiseq::csv }% +\def\xintiiseq::csv #1#2% +{% + \expandafter\XINT_iiseq::csv\expandafter + {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% +}% +\def\XINT_iiseq::csv #1#2% +{% + \ifcase\ifnum #1=#2 0\else\ifnum #2>#1 1\else -1\fi\fi\space + \expandafter\XINT_iiseq::csv_z + \or + \expandafter\XINT_iiseq::csv_p + \else + \expandafter\XINT_iiseq::csv_n + \fi + {#2}{#1}% +}% +\def\XINT_iiseq::csv_z #1#2{ #1}% +\def\XINT_iiseq::csv_p #1#2% +{% + \ifnum #1>#2 + \expandafter\expandafter\expandafter\XINT_iiseq::csv_p + \else + \expandafter\XINT_seq::csv_e + \fi + \expandafter{\the\numexpr #1-\xint_c_i}{#2},#1% +}% +\def\XINT_iiseq::csv_n #1#2% +{% + \ifnum #1<#2 + \expandafter\expandafter\expandafter\XINT_iiseq::csv_n + \else + \expandafter\XINT_seq::csv_e + \fi + \expandafter{\the\numexpr #1+\xint_c_i}{#2},#1% +}% +\def\XINT_seq::csv_e #1,{ }% +% \end{macrocode} +%\subsection{Macros for a..[d]..b list generation} +% \localtableofcontents +% +% \lverb|Contrarily to a..b which is limited to small integers, this works +% with a, b, and d (big) fractions. It will produce a «nil» list, if a>b and +% d<0 or a<b and d>0.| +% +%\subsubsection{\csh{xintSeqA::csv}, \csh{xintiiSeqA::csv}, \csh{XINTinFloatSeqA::csv}} +% +% \begin{macrocode} +\def\xintSeqA::csv #1% + {\expandafter\XINT_seqa::csv\expandafter{\romannumeral0\xintraw {#1}}}% +\def\XINT_seqa::csv #1#2{\expandafter\XINT_seqa::csv_a \romannumeral0\xintraw {#2};#1;}% +\def\xintiiSeqA::csv #1{\expandafter\XINT_iiseqa::csv\expandafter{\romannumeral`&&@#1}}% +\def\XINT_iiseqa::csv #1#2{\expandafter\XINT_seqa::csv_a\romannumeral`&&@#2;#1;}% +\def\XINTinFloatSeqA::csv #1{\expandafter\XINT_flseqa::csv\expandafter + {\romannumeral0\XINTinfloat [\XINTdigits]{#1}}}% +\def\XINT_flseqa::csv #1#2% + {\expandafter\XINT_seqa::csv_a\romannumeral0\XINTinfloat [\XINTdigits]{#2};#1;}% +\def\XINT_seqa::csv_a #1{\xint_UDzerominusfork + #1-{z}% + 0#1{n}% + 0-{p}% + \krof #1}% +% \end{macrocode} +%\subsubsection{\csh{xintSeqB::csv}} +% \lverb|With one year late documentation, let's just say, the #1 is +% \XINT_expr_unlock\.=Ua;b; with U=z or n or p, a=step, b=start.| +% \begin{macrocode} +\def\xintSeqB::csv #1#2% + {\expandafter\XINT_seqb::csv \expandafter{\romannumeral0\xintraw{#2}}{#1}}% +\def\XINT_seqb::csv #1#2{\expandafter\XINT_seqb::csv_a\romannumeral`&&@#2#1!}% +\def\XINT_seqb::csv_a #1#2;#3;#4!{\expandafter\XINT_expr_seq_empty? + \romannumeral0\csname XINT_seqb::csv_#1\endcsname {#3}{#4}{#2}}% +\def\XINT_seqb::csv_p #1#2#3% +{% + \xintifCmp {#1}{#2}{,#1\expandafter\XINT_seqb::csv_p\expandafter}% + {,#1\xint_gobble_iii}{\xint_gobble_iii}% +% \end{macrocode} +% \lverb|\romannumeral0 stopped by \endcsname, XINT_expr_seq_empty? constructs +% "nil".| +% \begin{macrocode} + {\romannumeral0\xintadd {#3}{#1}}{#2}{#3}% +}% +\def\XINT_seqb::csv_n #1#2#3% +{% + \xintifCmp {#1}{#2}{\xint_gobble_iii}{,#1\xint_gobble_iii}% + {,#1\expandafter\XINT_seqb::csv_n\expandafter}% + {\romannumeral0\xintadd {#3}{#1}}{#2}{#3}% +}% +\def\XINT_seqb::csv_z #1#2#3{,#1}% +% \end{macrocode} +%\subsubsection{\csh{xintiiSeqB::csv}} +% \begin{macrocode} +\def\xintiiSeqB::csv #1#2{\XINT_iiseqb::csv #1#2}% +\def\XINT_iiseqb::csv #1#2#3#4% + {\expandafter\XINT_iiseqb::csv_a + \romannumeral`&&@\expandafter \XINT_expr_unlock\expandafter#2% + \romannumeral`&&@\XINT_expr_unlock #4!}% +\def\XINT_iiseqb::csv_a #1#2;#3;#4!{\expandafter\XINT_expr_seq_empty? + \romannumeral`&&@\csname XINT_iiseqb::csv_#1\endcsname {#3}{#4}{#2}}% +\def\XINT_iiseqb::csv_p #1#2#3% +{% + \xintSgnFork{\XINT_Cmp {#1}{#2}}{,#1\expandafter\XINT_iiseqb::csv_p\expandafter}% + {,#1\xint_gobble_iii}{\xint_gobble_iii}% + {\romannumeral0\xintiiadd {#3}{#1}}{#2}{#3}% +}% +\def\XINT_iiseqb::csv_n #1#2#3% +{% + \xintSgnFork{\XINT_Cmp {#1}{#2}}{\xint_gobble_iii}{,#1\xint_gobble_iii}% + {,#1\expandafter\XINT_iiseqb::csv_n\expandafter}% + {\romannumeral0\xintiiadd {#3}{#1}}{#2}{#3}% +}% +\def\XINT_iiseqb::csv_z #1#2#3{,#1}% +% \end{macrocode} +%\subsubsection{\csh{XINTinFloatSeqB::csv}} +% \begin{macrocode} +\def\XINTinFloatSeqB::csv #1#2{\expandafter\XINT_flseqb::csv \expandafter + {\romannumeral0\XINTinfloat [\XINTdigits]{#2}}{#1}}% +\def\XINT_flseqb::csv #1#2{\expandafter\XINT_flseqb::csv_a\romannumeral`&&@#2#1!}% +\def\XINT_flseqb::csv_a #1#2;#3;#4!{\expandafter\XINT_expr_seq_empty? + \romannumeral`&&@\csname XINT_flseqb::csv_#1\endcsname {#3}{#4}{#2}}% +\def\XINT_flseqb::csv_p #1#2#3% +{% + \xintifCmp {#1}{#2}{,#1\expandafter\XINT_flseqb::csv_p\expandafter}% + {,#1\xint_gobble_iii}{\xint_gobble_iii}% + {\romannumeral0\XINTinfloatadd {#3}{#1}}{#2}{#3}% +}% +\def\XINT_flseqb::csv_n #1#2#3% +{% + \xintifCmp {#1}{#2}{\xint_gobble_iii}{,#1\xint_gobble_iii}% + {,#1\expandafter\XINT_flseqb::csv_n\expandafter}% + {\romannumeral0\XINTinfloatadd {#3}{#1}}{#2}{#3}% +}% +\def\XINT_flseqb::csv_z #1#2#3{,#1}% +% \end{macrocode} +% \subsection{The comma as binary operator} +% \lverb|New with 1.09a. Suffices to set its precedence level to two.| +% \begin{macrocode} +\def\XINT_tmpa #1#2#3#4#5#6% +{% + \def #1##1% \XINT_expr_op_, + {% + \expandafter #2\expandafter ##1\romannumeral`&&@\XINT_expr_getnext + }% + \def #2##1##2% \XINT_expr_until_,_a + {\xint_UDsignfork + ##2{\expandafter #2\expandafter ##1\romannumeral`&&@#4}% + -{#3##1##2}% + \krof }% + \def #3##1##2##3##4% \XINT_expr_until_,_b + {% + \ifnum ##2>\xint_c_ii + \xint_afterfi {\expandafter #2\expandafter ##1\romannumeral`&&@% + \csname XINT_#6_op_##3\endcsname {##4}}% + \else + \xint_afterfi + {\expandafter ##2\expandafter ##3% + \csname .=\XINT_expr_unlock ##1,\XINT_expr_unlock ##4\endcsname }% + \fi + }% + \let #5\xint_c_ii +}% +\xintFor #1 in {expr,flexpr,iiexpr} \do {% +\expandafter\XINT_tmpa + \csname XINT_#1_op_,\expandafter\endcsname + \csname XINT_#1_until_,_a\expandafter\endcsname + \csname XINT_#1_until_,_b\expandafter\endcsname + \csname XINT_#1_op_-vi\expandafter\endcsname + \csname XINT_expr_precedence_,\endcsname {#1}% +}% +% \end{macrocode} +% \subsection{The minus as prefix operator of variable precedence level} +% \lverb|Inherits the precedence level of the previous infix operator.| +% \begin{macrocode} +\def\XINT_tmpa #1#2#3% +{% + \expandafter\XINT_tmpb + \csname XINT_#1_op_-#3\expandafter\endcsname + \csname XINT_#1_until_-#3_a\expandafter\endcsname + \csname XINT_#1_until_-#3_b\expandafter\endcsname + \csname xint_c_#3\endcsname {#1}#2% +}% +\def\XINT_tmpb #1#2#3#4#5#6% +{% + \def #1% \XINT_expr_op_-<level> + {% get next number+operator then switch to _until macro + \expandafter #2\romannumeral`&&@\XINT_expr_getnext + }% + \def #2##1% \XINT_expr_until_-<l>_a + {\xint_UDsignfork + ##1{\expandafter #2\romannumeral`&&@#1}% + -{#3##1}% + \krof }% + \def #3##1##2##3% \XINT_expr_until_-<l>_b + {% _until tests precedence level with next op, executes now or postpones + \ifnum ##1>#4% + \xint_afterfi {\expandafter #2\romannumeral`&&@% + \csname XINT_#5_op_##2\endcsname {##3}}% + \else + \xint_afterfi {\expandafter ##1\expandafter ##2% + \csname .=% + \XINT:NEhook:one#6{\XINT_expr_unlock ##3}\endcsname }% + \fi + }% +}% +% \end{macrocode} +% \lverb|1.2d needs precedence 8 for *** and 9 for ^. Earlier, precedence +% level for ^ was only 8 but nevertheless the code did also "ix" here, which I +% think was unneeded back then.| +% \begin{macrocode} +\xintApplyInline{\XINT_tmpa {expr}\xintOpp}{{vi}{vii}{viii}{ix}}% +\xintApplyInline{\XINT_tmpa {flexpr}\xintOpp}{{vi}{vii}{viii}{ix}}% +\xintApplyInline{\XINT_tmpa {iiexpr}\xintiiOpp}{{vi}{vii}{viii}{ix}}% +% \end{macrocode} +% \subsection{? as two-way and ?? as three-way conditionals with braced branches} +% \lverb|In 1.1, I overload ? with ??, as : will be used for list extraction, +% problem with (stuff)?{?(1)}{0} for example, one should put a space (stuff)?{ +% ?(1)}{0} will work. Small idiosyncrasy. (which has been removed in 1.2h, +% there is no problem anymore with (test)?{?(1)}{0}, however (test)?{?}{!}(x) +% is not accepted; but (test)?{?(x)}{!(x)} is or even with {?(}{!(}x).) +% +% syntax: ?{yes}{no} and ??{<0}{=0}{>0}. +% +% The difficulty is to recognize the second ? without removing braces as would +% be the case with standard parsing of operators. Hence the ? operator is +% intercepted in \XINT_expr_getop_b. +% +% 1.2h corrects a bug in \XINT_expr_op_? which in context like +% (test)?{\foo}{bar} would provoke expansion of \foo, or also with +% (test)?{}{bar} would result in an error. The fix also solves the +% (test)?{?(1)}{0} issue mentioned above. +% | +% \begin{macrocode} +\let\XINT_expr_precedence_? \xint_c_x +\def\XINT_expr_op_? #1#2% + {\XINT_expr_op_?checka #2!\xint_bye\XINT_expr_op_?a #1{#2}}% +\def\XINT_expr_op_?checka #1{\expandafter\XINT_expr_op_?checkb\detokenize{#1}}% +\def\XINT_expr_op_?checkb #1{\if ?#1\expandafter\XINT_expr_op_?checkc + \else\expandafter\xint_bye\fi }% +\def\XINT_expr_op_?checkc #1{\xint_gob_til_! #1\XINT_expr_op_?? !\xint_bye}% +\def\XINT_expr_op_?a #1#2#3% +{% + \xintiiifNotZero{\XINT_expr_unlock #1}{\XINT_expr_getnext #2}{\XINT_expr_getnext #3}% +}% +\let\XINT_flexpr_op_?\XINT_expr_op_? +\let\XINT_iiexpr_op_?\XINT_expr_op_? +\def\XINT_expr_op_?? !\xint_bye\xint_bye\XINT_expr_op_?a #1#2#3#4#5% +{% + \xintiiifSgn {\XINT_expr_unlock #1}% + {\XINT_expr_getnext #3}{\XINT_expr_getnext #4}{\XINT_expr_getnext #5}% +}% +% \end{macrocode} +% \subsection{! as postfix factorial operator} +% \lverb|& +% | +% \begin{macrocode} +\let\XINT_expr_precedence_! \xint_c_x +\def\XINT_expr_op_! #1{\expandafter\XINT_expr_getop + \csname .=\XINT:NEhook:one\xintFac{\XINT_expr_unlock #1}\endcsname }% +\def\XINT_flexpr_op_! #1{\expandafter\XINT_expr_getop + \csname .=\XINT:NEhook:one\XINTinFloatFac{\XINT_expr_unlock #1}\endcsname }% +\def\XINT_iiexpr_op_! #1{\expandafter\XINT_expr_getop + \csname .=\XINT:NEhook:one\xintiiFac{\XINT_expr_unlock #1}\endcsname }% +% \end{macrocode} +% \subsection{The A/B[N] mechanism} +% \lverb|Releases earlier than 1.1 required the use of braces around A/B[N] +% input. The [N] is now implemented directly. *BUT* this uses a delimited macro! +% thus N is not allowed to be itself an expression (I could add it...). +% \xintE, \xintiiE, and \XINTinFloatE all put #2 in a \numexpr. But attention +% to the fact that \numexpr stops at spaces separating digits: +% \the\numexpr 3 + 7 9\relax gives 109\relax !! Hence we have to be +% careful. +% +% \numexpr will not handle catcode 11 digits, but adding a \detokenize will +% suddenly make illicit for N to rely on macro expansion.| +% +% \begin{macrocode} +\catcode`[ 11 +\let\XINT_expr_precedence_[ \xint_c_vii +\def\XINT_expr_op_[ #1#2]{\expandafter\XINT_expr_getop + \csname .=\xintE{\XINT_expr_unlock #1}% + {\xint_zapspaces #2 \xint_gobble_i}\endcsname}% +\def\XINT_iiexpr_op_[ #1#2]{\expandafter\XINT_expr_getop + \csname .=\xintiiE{\XINT_expr_unlock #1}% + {\xint_zapspaces #2 \xint_gobble_i}\endcsname}% +\def\XINT_flexpr_op_[ #1#2]{\expandafter\XINT_expr_getop + \csname .=\XINTinFloatE{\XINT_expr_unlock #1}% + {\xint_zapspaces #2 \xint_gobble_i}\endcsname}% +\catcode`[ 12 +% \end{macrocode} +% \subsection{\csh{XINT_expr_op_`} for recognizing functions} +% \lverb|The "onliteral" intercepts is for bool, togl, protect, ... but also +% for add, mul, seq, etc... Genuine functions have expr, iiexpr and +% flexpr versions (or only one or two of the three). +% +% With 1.2c "onliteral" is also used to disambiguate variables from +% functions. However as I use only a \ifcsname test, in order to be able to +% re-define a variable as function, I move the check for being a function +% first. Each variable name now has its onliteral_<name> associated macro +% which is the new way tacit multiplication in front of a parenthesis is +% implemented. This used to be decided much earlier at the time of +% \XINT_expr_func. +% +% The advantage of our choices for 1.2c is that the same name can be used for +% a variable or a function, the parser will apply the correct interpretation +% which is decided by the presence or not of an opening parenthesis next.| +% \begin{macrocode} +\def\XINT_tmpa #1#2#3{% + \def #1##1% + {% + \ifcsname XINT_#3_func_##1\endcsname + \xint_dothis{\expandafter\expandafter + \csname XINT_#3_func_##1\endcsname\romannumeral`&&@#2}\fi + \ifcsname XINT_expr_onliteral_##1\endcsname + \xint_dothis{\csname XINT_expr_onliteral_##1\endcsname}\fi + \xint_orthat{\XINT_expr_unknown_function {##1}% + \expandafter\XINT_expr_func_unknown\romannumeral`&&@#2}% + }% +}% +\def\XINT_expr_unknown_function #1{\xintError:removed \xint_gobble_i {#1}}% +\xintFor #1 in {expr,flexpr,iiexpr} \do {% + \expandafter\XINT_tmpa + \csname XINT_#1_op_`\expandafter\endcsname + \csname XINT_#1_oparen\endcsname + {#1}% +}% +\def\XINT_expr_func_unknown #1#2#3% + {\expandafter #1\expandafter #2\csname .=0\endcsname }% +% \end{macrocode} +% \subsection{The \csh{bool()}, \csh{togl()}, \csh{protect()} pseudo ``functions''} +% \lverb|bool, togl and protect use delimited macros. They are not true +% functions, they turn off the parser to gather their "variable".| +% \begin{macrocode} +\def\XINT_expr_onliteral_bool #1)% + {\expandafter\XINT_expr_getop\csname .=\xintBool{#1}\endcsname }% +\def\XINT_expr_onliteral_togl #1)% + {\expandafter\XINT_expr_getop\csname .=\xintToggle{#1}\endcsname }% +\def\XINT_expr_onliteral_protect #1)% + {\expandafter\XINT_expr_getop\csname .=\detokenize{#1}\endcsname }% +% \end{macrocode} +% \subsection{The \csh{break()} function} +% \lverb|break is a true function, the parsing via expansion of the succeeding +% material proceeded via _oparen macros as with any other function.| +% \begin{macrocode} +\def\XINT_expr_func_break #1#2#3% + {\expandafter #1\expandafter #2\csname.=?\romannumeral`&&@\XINT_expr_unlock #3\endcsname }% +\let\XINT_flexpr_func_break \XINT_expr_func_break +\let\XINT_iiexpr_func_break \XINT_expr_func_break +% \end{macrocode} +% \subsection{The \csh{qraw()}, \csh{qint()}, \csh{qfrac()}, and +% \csh{qfloat()} ``functions''} +% +% \changed{1.2}{} adds |qint()|, |qfrac()|, |qfloat()|. +% +% \changed{1.3c}{} adds |qraw()|. Useful to limit impact on \TeX{} memory +% from abuse of |\csname|'s storage when generating many comma separated +% values from a loop. +% +% \changed{1.3e}{} |qfloat()| keeps a short mantissa if possible. +% +% \lverb|They allow the user to hand over quickly a big number to the parser, +% spaces not immediately removed but should be harmless in general. The qraw() +% does no post-processing at all apart complete expansion, useful for +% comma-separated values, but must be obedient to (non really documented) +% expected format. Each uses a delimited macro, the closing parenthesis can +% not emerge from expansion.| +% \begin{macrocode} +\def\XINT_expr_onliteral_qint #1)% + {\expandafter\XINT_expr_getop\csname .=\xintiNum{#1}\endcsname }% +\def\XINT_expr_onliteral_qfrac #1)% + {\expandafter\XINT_expr_getop\csname .=\xintRaw{#1}\endcsname }% +\def\XINT_expr_onliteral_qfloat #1)% + {\expandafter\XINT_expr_getop\csname .=\XINTinFloatSdigits{#1}\endcsname }% +\def\XINT_expr_onliteral_qraw #1)% + {\expandafter\XINT_expr_getop\csname .=#1\endcsname }% +% \end{macrocode} +% \subsection{The \csh{random()} and \csh{qrand()} ``functions''} +% \lverb|1.3b. Function-like syntax but with no argument currently, so let's +% use fast parsing which requires though the closing parenthesis to be +% explicit.| +% \begin{macrocode} +\def\XINT_expr_onliteral_random #1)% + {\expandafter\XINT_expr_getop\csname .=\XINTinRandomFloatSdigits\endcsname }% +\def\XINT_expr_onliteral_qrand #1)% + {\expandafter\XINT_expr_getop\csname .=\XINTinRandomFloatSixteen\endcsname }% +% \end{macrocode} +% \subsection{\csh{XINT_expr_op__} for recognizing variables} +% \lverb|The 1.1 mechanism for \XINT_expr_var_<varname> has been +% modified in 1.2c. The <varname> associated macro is now only expanded +% once, not twice. We arrive here via \XINT_expr_func.| +% \begin{macrocode} +\def\XINT_expr_op__ #1% op__ with two _'s + {% + \ifcsname XINT_expr_var_#1\endcsname + \expandafter\xint_firstoftwo + \else + \expandafter\xint_secondoftwo + \fi + {\expandafter\expandafter\expandafter + \XINT_expr_getop\csname XINT_expr_var_#1\endcsname}% + {\XINT_expr_unknown_variable {#1}% + \expandafter\XINT_expr_getop\csname .=0\endcsname}% + }% +\def\XINT_expr_unknown_variable #1{\xintError:removed \xint_gobble_i {#1}}% +\let\XINT_flexpr_op__ \XINT_expr_op__ +\let\XINT_iiexpr_op__ \XINT_expr_op__ +% \end{macrocode} +% \subsection{User defined variables: \csh{xintdefvar}, \csh{xintdefiivar}, +% \csh{xintdeffloatvar}} +% \changed{1.1}{} +% +% \changed{1.2p}{2017/12/01} extends |\xintdefvar| et al.\@ to accept +% simultaneous assignments to multiple variables. +% +% \changed{1.3c}{2018/06/17} +% Use \csbxint{exprSafeCatcodes} (to palliate issue with +% active semi-colon from Babel+French if in body of a \LaTeX{} document). +% +% And allow usage with both syntaxes |name:=expr;| or |name=expr;|. Also the +% colon may have catcode 11, 12, or 13 with no issue. +% Variable names may contain letters, digits, underscores, and must not start +% with a digit. Names starting with |@| or an underscore are reserved. +% +% \begin{itemize}[nosep] +% \item currently |@|, |@1|, |@2|, |@3|, and |@4| are reserved because they +% have special meanings for use in iterations, +% \item |@@|, |@@@|, |@@@@| are also reserved but +% are technically functions, not variables: a user may possibly define |@@| as +% a variable name, but if it is followed by parentheses, the function +% interpretation will be applied (rather than the variable interpretation +% followed by a tacit multiplication), +% \item since |1.2l|, the underscore |_| may be used as separator of digits in +% long numbers. +% Hence a variable whose name starts with |_| will not play well with the +% mechanism of tacit multiplication of variables by numbers: the underscore +% will be removed from input stream by the number scanner, thus creating +% an undefined or wrong variable name, or none at all if the variable +% name was an initial |_| followed by digits. +% \end{itemize} +% \lverb| +% | +% \begin{macrocode} +\catcode`* 11 +\def\XINT_expr_defvar_one #1#2% +{% + \XINT_global + \expandafter\edef\csname XINT_expr_var_#1\endcsname + {\expandafter\noexpand#2}% + \XINT_global + \expandafter\edef\csname XINT_expr_onliteral_#1\endcsname + {\XINT_expr_precedence_*** *\expandafter\noexpand#2(}% + \ifxintverbose\xintMessage{xintexpr}{Info} + {Variable "#1" \ifxintglobaldefs globally \fi + defined with value \expandafter\XINT_expr_unlock#2.}% + \fi +}% +\catcode`* 12 +\catcode`~ 13 +\catcode`: 12 +\def\XINT_expr_defvar_getname #1:#2~{\endgroup + \def\XINT_defvar_tmpa{#1}\edef\XINT_defvar_tmpc{\xintCSVLength{#1}}}% +\def\XINT_expr_defvar #1#2#3;% +{% + \xintexprRestoreCatcodes +% \end{macrocode} +% \lverb|Maybe SafeCatcodes was without effect because the colon and the rest +% are from some earlier macro definition. Give a safe definition to active +% colon (even if in math mode with a math active colon..).| +% \begin{macrocode} + \begingroup\lccode`~`: \lowercase{\let~}\empty + \edef\XINT_defvar_tmpa{#2}% + \edef\XINT_defvar_tmpa{\xint_zapspaces_o\XINT_defvar_tmpa}% + \expandafter\XINT_expr_defvar_getname + \detokenize\expandafter{\XINT_defvar_tmpa}:~% + \ifcase\XINT_defvar_tmpc\space + \xintMessage {xintexpr}{Warning} + {Aborting: not allowed to declare variable with empty name.}% + \or + \edef\XINT_defvar_tmpb{\romannumeral0#1#3\relax}% + \XINT_expr_defvar_one\XINT_defvar_tmpa\XINT_defvar_tmpb + \else + \edef\XINT_defvar_tmpb + {\expandafter\XINT_expr_unlock\romannumeral0#1#3\relax}% + \edef\XINT_defvar_tmpd{\xintCSVLength{\XINT_defvar_tmpb}}% + \ifnum\XINT_defvar_tmpc=\XINT_defvar_tmpd\space + \xintAssignArray\xintCSVtoList\XINT_defvar_tmpa\to\XINT_defvar_tmpvar + \xintAssignArray + \xintApply\XINT_expr_lockit{\xintCSVtoList\XINT_defvar_tmpb}% + \to\XINT_defvar_tmpval + \def\XINT_defvar_tmpd{1}% + \xintloop + \expandafter\XINT_expr_defvar_one + \csname XINT_defvar_tmpvar\XINT_defvar_tmpd\expandafter\endcsname + \csname XINT_defvar_tmpval\XINT_defvar_tmpd\endcsname + \ifnum\XINT_defvar_tmpd<\XINT_defvar_tmpc\space + \edef\XINT_defvar_tmpd{\the\numexpr\XINT_defvar_tmpd+1}% + \repeat + \xintRelaxArray\XINT_defvar_tmpvar + \xintRelaxArray\XINT_defvar_tmpval + \else + \xintMessage {xintexpr}{Warning} + {Aborting: mismatch between number of variables (\XINT_defvar_tmpc) + and number of values (\XINT_defvar_tmpd).}% + \fi + \fi +}% +\catcode`~ 3 +\catcode`: 11 +% \end{macrocode} +% \lverb|This SafeCatcodes is mainly in the hope that semi-colon ending the +% expression can still be sanitized.| +% \begin{macrocode} +\def\xintdefvar {\xintexprSafeCatcodes\xintdefvar_a}% +\def\xintdefiivar {\xintexprSafeCatcodes\xintdefiivar_a}% +\def\xintdeffloatvar {\xintexprSafeCatcodes\xintdeffloatvar_a}% +\def\xintdefvar_a #1={\XINT_expr_defvar\xintbareeval {#1}}% +\def\xintdefiivar_a #1={\XINT_expr_defvar\xintbareiieval {#1}}% +\def\xintdeffloatvar_a #1={\XINT_expr_defvar\xintbarefloateval {#1}}% +% \end{macrocode} +% \subsection{\csh{xintunassignvar}} +% \changed{1.2e}{} +% +% \changed{1.3d}{} +% Embarrassingly I had for a long time a misunderstanding of |\ifcsname| +% (let's blame its documentation) and I was not aware that it chooses FALSE +% branch if tested control sequence has been |\let| to |\undefined|... So +% earlier version didn't do the right thing (and had another bug: failure to +% protect |\.=0| from expansion). +% +% The |\ifcsname| tests are done in \csbXINT{_expr_op__} and +% \csbXINT{_expr_op_`}. +% \begin{macrocode} +\def\xintunassignvar #1{% + \edef\XINT_unvar_tmpa{#1}% + \edef\XINT_unvar_tmpa {\xint_zapspaces_o\XINT_unvar_tmpa}% + \ifcsname XINT_expr_var_\XINT_unvar_tmpa\endcsname + \ifnum\expandafter\xintLength\expandafter{\XINT_unvar_tmpa}=\@ne + \expandafter\xintnewdummy\XINT_unvar_tmpa + \else + \XINT_global\expandafter + \let\csname XINT_expr_var_\XINT_unvar_tmpa\endcsname\xint_undefined + \XINT_global\expandafter + \let\csname XINT_expr_onliteral_\XINT_unvar_tmpa\endcsname\xint_undefined + \ifxintverbose\xintMessage {xintexpr}{Info} + {Variable \XINT_unvar_tmpa\space has been + \ifxintglobaldefs globally \fi ``unassigned''.}% + \fi + \fi + \else + \xintMessage {xintexpr}{Warning} + {Error: there was no such variable \XINT_unvar_tmpa\space to unassign.}% + \fi +}% +% \end{macrocode} +% \subsection{seq and the implementation of dummy variables} +% \localtableofcontents +% \lverb|All of seq, add, mul, rseq, etc... (actually all of the extensive +% changes from xintexpr 1.09n to 1.1) was done around June 15-25th 2014, but the +% problem is that I did not document the code enough, and I had a hard time +% understanding in October what I had done in June. Despite the lesson, again +% being short on time, I do not document enough my current understanding of the +% innards of the beast... +% +% I added subs, and iter in October (also the [:n], [n:] list extractors), +% proving I did at least understand a bit (or rather could imitate) my earlier +% code (but don't ask me to explain \xintNewExpr !) +% +% The \XINT_expr_onliteral_seq_a parses: "expression, variable=list)" +% (when it is called the opening ( has been swallowed, and it looks for +% the ending one.) Both expression and list may themselves contain +% parentheses and commas, we allow nesting. For example "x^2,x=1..10)", +% at the end of seq_a we have {variable{expression}}{list}, in this +% example {x{x^2}}{1..10}, or more complicated +% "seq(add(y,y=1..x),x=1..10)" will work too. The variable is a single +% lowercase Latin letter. +% +% The complications with \xint_c_xviii in seq_f is for the recurrent +% thing that we don't know in what type of expressions we are, hence we +% must move back up, with some loss of efficiency (superfluous check for +% minus sign, etc...). But the code manages simultaneously expr, flexpr +% and iiexpr.| +% +% \subsubsection{All letters usable as dummy variables, \csh{xintnewdummy}} +% \lverb|The nil variable was introduced in 1.1 but isn't used under that +% name. However macros handling a..[d]..b, or for seq with dummy variable +% where omit has omitted everyting may in practice inject a nil value as +% current number. +% +% 1.2c has changed the way variables are disambiguated from functions and for +% this it has added here the definitions of \XINT_expr_onliteral_<name>. +% +% In 1.1 a letter variable say X was acting as a delimited macro looking for +% !X{stuff} and then would expand the stuff inside a \csname.=...\endcsname. I +% don't think I used the possibilities this opened and the 1.2c version has +% stuff _already_ encapsulated thus a single token. Only one expansion, not +% two is then needed in \XINT_expr_op__. +% +% I had to accordingly modify seq, add, mul and subs, but fortunately realized +% that the @, @1, etc... variables for rseq, rrseq and iter already had been +% defined in the way now also followed by the Latin letters as dummy +% variables. +% +% The 1.2e \XINT_expr_makedummy was adjoined \xintnewdummy by +% 1.2k for a public interface. It should not be used with multi-letter +% argument. The add, mul, seq, etc... can only work with one-letter long dummy +% variable. And this will almost certainly not change. +% +% Also 1.2e does the tacit multiplication x(stuff)->x*(stuff) in its higher +% precedence form. Things are easy now that variables always fetch a single +% already locked value \.=<number>. +% +% The tacit multiplication in case of the ``nil'' variable doesn't make much +% sense but we do it anyhow. +% +% 1.3e stores earlier meaning for usage by xinttrig and xintlog with +% \xintensuredummy and \xintrestoredummy as high-level interface. +% +% Do an \xintrestorevar, and patch \xintdefvar to always store previous +% meaning? +% | +% +% \begin{macrocode} +\catcode`* 11 +\def\XINT_expr_makedummy #1% +{% + \ifcsname XINT_expr_var_#1\endcsname + \XINT_global + \expandafter\let\csname XINT_expr_var_#1/old\expandafter\endcsname + \csname XINT_expr_var_#1\expandafter\endcsname + \fi + \ifcsname XINT_expr_onliteral_#1\endcsname + \XINT_global + \expandafter\let\csname XINT_expr_onliteral_#1/old\expandafter\endcsname + \csname XINT_expr_onliteral_#1\expandafter\endcsname + \fi + \XINT_global + \expandafter\def\csname XINT_expr_var_#1\endcsname ##1\relax !#1##2% + {##2##1\relax !#1##2}% + \XINT_global + \expandafter\def\csname XINT_expr_onliteral_#1\endcsname ##1\relax !#1##2% + {\XINT_expr_precedence_*** *##2(##1\relax !#1##2}% +}% +\xintApplyUnbraced \XINT_expr_makedummy {abcdefghijklmnopqrstuvwxyz}% +\xintApplyUnbraced \XINT_expr_makedummy {ABCDEFGHIJKLMNOPQRSTUVWXYZ}% +\def\xintnewdummy #1{% + \XINT_expr_makedummy{#1}% + \ifxintverbose\xintMessage {xintexpr}{Info}% + {#1 (with letter catcode) now + \ifxintglobaldefs globally \fi usable as dummy variable.}% + \fi +}% +\edef\XINT_expr_var_nil {\expandafter\noexpand\csname .= \endcsname}% +\edef\XINT_expr_onliteral_nil + {\XINT_expr_precedence_*** *\expandafter\noexpand\csname .= \endcsname (}% +\catcode`* 12 +% \end{macrocode} +% \subsubsection{\cshn{xintensuredummy}, \cshn{xintrestorelettervar}} +% \lverb|\xintensuredummy differs only in the informational message... +% Attention that this is not meant to be nested.| +% \begin{macrocode} +\def\xintensuredummy #1{% + \XINT_expr_makedummy{#1}% + \ifxintverbose\xintMessage {xintexpr}{Info}% + {#1 (with letter catcode) now + \ifxintglobaldefs globally \fi usable as dummy variable.&&J + Use \string\xintrestoredummy{#1} to restore it to its former meaning.}% + \fi +}% +\def\xintrestorelettervar #1{% + \ifcsname XINT_expr_var_#1/old\endcsname + \XINT_global + \expandafter\let\csname XINT_expr_var_#1\expandafter\endcsname + \csname XINT_expr_var_#1/old\expandafter\endcsname + \fi + \ifcsname XINT_expr_onliteral_#1/old\endcsname + \XINT_global + \expandafter\let\csname XINT_expr_onliteral_#1\expandafter\endcsname + \csname XINT_expr_onliteral_#1/old\expandafter\endcsname + \fi + \ifxintverbose\xintMessage {xintexpr}{Info}% + {Character #1 (with letter catcode) + \ifxintglobaldefs globally \fi restored to its earlier status, if any.}% + \fi +}% +% \end{macrocode} +% \subsubsection{\csh{omit()} and \csh{abort()}} +% \lverb|& attention à ce & qui est de catcode 14 dans les \lverb +% June 24 and 25, 2014. +% +% Added comments 2015/11/13: +% +% Et la documentation ? on n'y comprend plus rien. Trop +% rusé.$newline +% \def\XINT_expr_var_omit #1\relax !{1^C!{}{}{}\.=!\relax !}$newline +% \def\XINT_expr_var_abort #1\relax !{1^C!{}{}{}\.=^\relax !}$newline +% C'était accompagné de \XINT_expr_precedence_^C=0 et d'un hack au sein même +% des macros until de plus bas niveau. +% +% Le mécanisme sioux était le suivant: ^C est déclaré comme un opérateur de +% précédence nulle. Lorsque le parseur trouve un "omit" dans un seq ou autre, +% il va insérer dans le stream \XINT_expr_getop suivi du texte de +% remplacement. Donc ici on avait un 1 comme place holder, puis l'opérateur +% ^C. Celui-ci étant de précédence zéro provoque la finalisation de tous les +% calculs antérieurs dans le sous-bareeval. Mais j'ai dû hacker le until_end_b +% (et le until_)_b) qui confronté à ^C, va se relancer à zéro, le getnext va +% trouver le !{}{}{}\.=! et ensuite il y aura \relax, et le résultat sera \.=! +% pour omit ou \.=^ pour abort. Les routines des boucles seq, iter, etc... +% peuvent alors repérer le ! ou ^ et agir en conséquence (un long paragraphe +% pour ne décrire que partiellement une ou deux lignes de codes...). +% +% Mais ^C a été fait alors que je n'avais pas encore les variables muettes. Je +% dois trouver autre chose, car seq(2^C, C=1..5) est alors impossible. De +% toute façon ce ^C était à usage interne uniquement. +% +% Il me faut un symbole d'opérateur qui ne rentre pas en conflit. Bon je vais +% prendre !?. Ensuite au lieu de hacker until_end, il vaut mieux lui donner +% précédence 2 (mais ça ne pourra pas marcher à l'intérieur de parenthèses il +% faut d'abord les fermer manuellement) et lui associer un simplement un op +% spécial. Je n'avais pas fait cela peut-être pour éviter d'avoir à définir +% plusieurs macros. Le #1 dans la définition de \XINT_expr_op_!? est le +% résultat de l'évaluation forcée précédente. +% +% Attention que les premier ! doiventt être de catcode 12 sinon ils +% signalent une sous-expression qui déclenche une multiplication tacite. +% +% | +% \begin{macrocode} +\edef\XINT_expr_var_omit #1\relax !{1\string !?!\relax !}% +\edef\XINT_expr_var_abort #1\relax !{1\string !?^\relax !}% +\def\XINT_expr_op_!? #1#2\relax {\expandafter\XINT_expr_foundend\csname .=#2\endcsname}% +\let\XINT_iiexpr_op_!? \XINT_expr_op_!? +\let\XINT_flexpr_op_!? \XINT_expr_op_!? +% \end{macrocode} +% \subsubsection{The special variables @, @1, @2, @3, @4, @@, @@(1), \dots, @@@, +% @@@(1), \dots for recursion} +% \lverb|October 2014: I had completely forgotten what the @@@ etc... stuff +% were supposed to do: this is for nesting recursions! (I was mad back in +% June). @@(N) gives the Nth back, @@@(N) gives the Nth back of the higher +% recursion! +% +% 1.2c adds the needed "onliteral" now that tacit multiplication between a +% variable and a ( has a new mechanism. 1.2e does this tacit multiplication +% with higher precedence. +% +% For the record, the ~ has catcode 3 in this code.| +% +% \begin{macrocode} +\catcode`? 3 \catcode`* 11 +\def\XINT_expr_var_@ #1~#2{#2#1~#2}% +\expandafter\let\csname XINT_expr_var_@1\endcsname \XINT_expr_var_@ +\expandafter\def\csname XINT_expr_var_@2\endcsname #1~#2#3{#3#1~#2#3}% +\expandafter\def\csname XINT_expr_var_@3\endcsname #1~#2#3#4{#4#1~#2#3#4}% +\expandafter\def\csname XINT_expr_var_@4\endcsname #1~#2#3#4#5{#5#1~#2#3#4#5}% +\def\XINT_expr_onliteral_@ #1~#2{\XINT_expr_precedence_*** *#2(#1~#2}% +\expandafter\let\csname XINT_expr_onliteral_@1\endcsname \XINT_expr_onliteral_@ +\expandafter\def\csname XINT_expr_onliteral_@2\endcsname #1~#2#3% + {\XINT_expr_precedence_*** *#3(#1~#2#3}% +\expandafter\def\csname XINT_expr_onliteral_@3\endcsname #1~#2#3#4% + {\XINT_expr_precedence_*** *#4(#1~#2#3#4}% +\expandafter\def\csname XINT_expr_onliteral_@4\endcsname #1~#2#3#4#5% + {\XINT_expr_precedence_*** *#5(#1~#2#3#4#5}% +\catcode`* 12 +\def\XINT_expr_func_@@ #1#2#3#4~#5?% +{% + \expandafter#1\expandafter#2\romannumeral0\xintntheltnoexpand + {\xintNum{\XINT_expr_unlock#3}}{#5}#4~#5?% +}% +\def\XINT_expr_func_@@@ #1#2#3#4~#5~#6?% +{% + \expandafter#1\expandafter#2\romannumeral0\xintntheltnoexpand + {\xintNum{\XINT_expr_unlock#3}}{#6}#4~#5~#6?% +}% +\def\XINT_expr_func_@@@@ #1#2#3#4~#5~#6~#7?% +{% + \expandafter#1\expandafter#2\romannumeral0\xintntheltnoexpand + {\xintNum{\XINT_expr_unlock#3}}{#7}#4~#5~#6~#7?% +}% +\let\XINT_flexpr_func_@@\XINT_expr_func_@@ +\let\XINT_flexpr_func_@@@\XINT_expr_func_@@@ +\let\XINT_flexpr_func_@@@@\XINT_expr_func_@@@@ +\def\XINT_iiexpr_func_@@ #1#2#3#4~#5?% +{% + \expandafter#1\expandafter#2\romannumeral0\xintntheltnoexpand + {\XINT_expr_unlock#3}{#5}#4~#5?% +}% +\def\XINT_iiexpr_func_@@@ #1#2#3#4~#5~#6?% +{% + \expandafter#1\expandafter#2\romannumeral0\xintntheltnoexpand + {\XINT_expr_unlock#3}{#6}#4~#5~#6?% +}% +\def\XINT_iiexpr_func_@@@@ #1#2#3#4~#5~#6~#7?% +{% + \expandafter#1\expandafter#2\romannumeral0\xintntheltnoexpand + {\XINT_expr_unlock#3}{#7}#4~#5~#6~#7?% +}% +\catcode`? 11 +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_onliteral_seq}} +% \begin{macrocode} +\def\XINT_expr_onliteral_seq + {\expandafter\XINT_expr_onliteral_seq_f\romannumeral`&&@\XINT_expr_onliteral_seq_a {}}% +\def\XINT_expr_onliteral_seq_f #1#2{\xint_c_xviii `{seqx}#2)\relax #1}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_onliteral_seq_a}} +% \begin{macrocode} +\def\XINT_expr_onliteral_seq_a #1#2,% +{% + \ifcase\XINT_isbalanced_a \relax #1#2(\xint_bye)\xint_bye + \expandafter\XINT_expr_onliteral_seq_c + \or\expandafter\XINT_expr_onliteral_seq_b + \else\expandafter\xintError:we_are_doomed + \fi {#1#2},% +}% +\def\XINT_expr_onliteral_seq_b #1,{\XINT_expr_onliteral_seq_a {#1,}}% +\def\XINT_expr_onliteral_seq_c #1,#2#3% #3 pour absorber le = +{% + \XINT_expr_onliteral_seq_d {#2{#1}}{}% +}% +\def\XINT_expr_onliteral_seq_d #1#2#3)% +{% + \ifcase\XINT_isbalanced_a \relax #2#3(\xint_bye)\xint_bye + \or\expandafter\XINT_expr_onliteral_seq_e + \else\expandafter\xintError:we_are_doomed + \fi + {#1}{#2#3}% +}% +\def\XINT_expr_onliteral_seq_e #1#2{\XINT_expr_onliteral_seq_d {#1}{#2)}}% +% \end{macrocode} +% \subsubsection{\csh{XINT_isbalanced_a} for \cshnolabel{XINT_expr_onliteral_seq_a}} +% \lverb|Expands to \xint_c_mone in case a closing ) had no opening ( matching +% it, to \@ne if opening ) had no closing ) matching it, to \z@ if expression +% was balanced.| +% \begin{macrocode} +% use as \XINT_isbalanced_a \relax #1(\xint_bye)\xint_bye +\def\XINT_isbalanced_a #1({\XINT_isbalanced_b #1)\xint_bye }% +\def\XINT_isbalanced_b #1)#2% + {\xint_bye #2\XINT_isbalanced_c\xint_bye\XINT_isbalanced_error }% +% \end{macrocode} +% \lverb|if #2 is not \xint_bye, a ) was found, but there was no (. Hence error -> -1| +% \begin{macrocode} +\def\XINT_isbalanced_error #1)\xint_bye {\xint_c_mone}% +% \end{macrocode} +% \lverb|#2 was \xint_bye, was there a ) in original #1?| +% \begin{macrocode} +\def\XINT_isbalanced_c\xint_bye\XINT_isbalanced_error #1% + {\xint_bye #1\XINT_isbalanced_yes\xint_bye\XINT_isbalanced_d #1}% +% \end{macrocode} +% \lverb|#1 is \xint_bye, there was never ( nor ) in original #1, hence OK.| +% \begin{macrocode} +\def\XINT_isbalanced_yes\xint_bye\XINT_isbalanced_d\xint_bye )\xint_bye {\xint_c_ }% +% \end{macrocode} +% \lverb|#1 is not \xint_bye, there was indeed a ( in original #1. We check if +% we see a ). If we do, we then loop until no ( nor ) is to be found.| +% \begin{macrocode} +\def\XINT_isbalanced_d #1)#2% + {\xint_bye #2\XINT_isbalanced_no\xint_bye\XINT_isbalanced_a #1#2}% +% \end{macrocode} +% \lverb|#2 was \xint_bye, we did not find a closing ) in original #1. Error.| +% \begin{macrocode} +\def\XINT_isbalanced_no\xint_bye #1\xint_bye\xint_bye {\xint_c_i }% +% \end{macrocode} +% \subsubsection{\csh{XINT_allexpr_func_seqx}} +% \lverb|1.2c uses \xintthebareval, ... which strangely were not available at +% 1.1 time. This spares some tokens from \XINT_expr_seq:_d and cousins. Also now +% variables have changed their mode of operation they pick only one token which +% must be an already encapsulated value. +% +% In \XINT_allexp_seqx, #2 is the list, evaluated and encapsulated, #3 is the +% dummy variable, #4 is the expression to evaluate repeatedly. +% +% A special case is a list generated by <variable>++: then #2 is {\.=+\.=<start>}.| +% \begin{macrocode} +\def\XINT_expr_func_seqx #1#2{\XINT_allexpr_seqx \xintthebareeval }% +\def\XINT_flexpr_func_seqx #1#2{\XINT_allexpr_seqx \xintthebarefloateval}% +\def\XINT_iiexpr_func_seqx #1#2{\XINT_allexpr_seqx \xintthebareiieval }% +\def\XINT_allexpr_seqx #1#2#3#4% +{% + \expandafter \XINT_expr_getop + \csname .=\expandafter\XINT_expr_seq:_aa + \romannumeral`&&@\XINT_expr_unlock #2!{#1#4\relax !#3}\endcsname +}% +\def\XINT_expr_seq:_aa #1{\if +#1\expandafter\XINT_expr_seq:_A\else + \expandafter\XINT_expr_seq:_a\fi #1}% +% \end{macrocode} +% \subsubsection{Evaluation over list, \csh{XINT_expr_seq:_a} with break, +% abort, omit} +% \lverb|The #2 here is \...bareeval <expression>\relax !<variable name>. The #1 +% is a comma separated list of values to assign to the dummy variable. The +% \XINT_expr_seq_empty? intervenes immediately after handling of firstvalue. +% +% 1.2c has rewritten to a large extent this and other similar loops because +% the dummy variables now fetch a single encapsulated token (apart from a good +% means to lose a few hours needlessly -- as I have had to rewrite and review +% most everything, this change could make the thing more efficient if the same +% variable is used many times in an expression, but we are talking +% micro-seconds here anyhow.)| +% \begin{macrocode} +\def\XINT_expr_seq:_a #1!#2{\expandafter\XINT_expr_seq_empty? + \romannumeral0\XINT_expr_seq:_b {#2}#1,^,}% +\def\XINT_expr_seq:_b #1#2#3,{% + \if ,#2\xint_dothis\XINT_expr_seq:_noop\fi + \if ^#2\xint_dothis\XINT_expr_seq:_end\fi + \xint_orthat{\expandafter\XINT_expr_seq:_c}\csname.=#2#3\endcsname {#1}% +}% +\def\XINT_expr_seq:_noop\csname.=,#1\endcsname #2{\XINT_expr_seq:_b {#2}#1,}% +\def\XINT_expr_seq:_end \csname.=^\endcsname #1{}% +\def\XINT_expr_seq:_c #1#2{\expandafter\XINT_expr_seq:_d\romannumeral`&&@#2#1{#2}}% +\def\XINT_expr_seq:_d #1{\if #1^\xint_dothis\XINT_expr_seq:_abort\fi + \if #1?\xint_dothis\XINT_expr_seq:_break\fi + \if #1!\xint_dothis\XINT_expr_seq:_omit\fi + \xint_orthat{\XINT_expr_seq:_goon #1}}% +\def\XINT_expr_seq:_abort #1!#2#3#4#5^,{}% +\def\XINT_expr_seq:_break #1!#2#3#4#5^,{,#1}% +\def\XINT_expr_seq:_omit #1!#2#3#4{\XINT_expr_seq:_b {#4}}% +\def\XINT_expr_seq:_goon #1!#2#3#4{,#1\XINT_expr_seq:_b {#4}}% +% \end{macrocode} +% \lverb|If all is omitted or list is empty, _empty? will fetch within the ##1 +% a \endcsname token and construct "nil" via <space>\endcsname, if not ##1 +% will be a comma and the gobble will swallow the space token and the +% extra \endcsname.| +% \begin{macrocode} +\def\XINT_expr_seq_empty? #1{% +\def\XINT_expr_seq_empty? ##1{\if ,##1\expandafter\xint_gobble_i\fi #1\endcsname }}% +\XINT_expr_seq_empty? { }% +% \end{macrocode} +% \subsubsection{Evaluation over ++ generated lists with \csh{XINT_expr_seq:_A}} +% \lverb|This is for index lists generated by n++. The starting point will have +% been replaced by its ceil (added: in fact with version 1.1. the ceil was not +% yet evaluated, but _var_<letter> did an expansion of what they fetch). We use +% \numexpr rather than \xintInc, hence the indexing is limited to small +% integers. +% +% The 1.2c version of n++ produces a #1 here which is already a single +% \.=<value> token.| +% \begin{macrocode} +\def\XINT_expr_seq:_A +#1!% + {\expandafter\XINT_expr_seq_empty?\romannumeral0\XINT_expr_seq:_D #1}% +\def\XINT_expr_seq:_D #1#2{\expandafter\XINT_expr_seq:_E\romannumeral`&&@#2#1{#2}}% +\def\XINT_expr_seq:_E #1{\if #1^\xint_dothis\XINT_expr_seq:_Abort\fi + \if #1?\xint_dothis\XINT_expr_seq:_Break\fi + \if #1!\xint_dothis\XINT_expr_seq:_Omit\fi + \xint_orthat{\XINT_expr_seq:_Goon #1}}% +\def\XINT_expr_seq:_Abort #1!#2#3#4{}% +\def\XINT_expr_seq:_Break #1!#2#3#4{,#1}% +\def\XINT_expr_seq:_Omit #1!#2#3% + {\expandafter\XINT_expr_seq:_D + \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\endcsname}% +\def\XINT_expr_seq:_Goon #1!#2#3% + {,#1\expandafter\XINT_expr_seq:_D + \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\endcsname}% +% \end{macrocode} +% \subsection{\csh{add()}, \csh{mul()}} +% \lverb|1.2c uses more directly the \xintiiAdd etc... macros and has +% opxadd/opxmul rather than a single opx. This is less conceptual as I use +% explicitely the associated macro names for +, * but this makes other things +% more efficient, and the code more readable.| +% \begin{macrocode} +\def\XINT_expr_onliteral_add + {\expandafter\XINT_expr_onliteral_add_f\romannumeral`&&@\XINT_expr_onliteral_seq_a {}}% +\def\XINT_expr_onliteral_add_f #1#2{\xint_c_xviii `{opxadd}#2)\relax #1}% +\def\XINT_expr_onliteral_mul + {\expandafter\XINT_expr_onliteral_mul_f\romannumeral`&&@\XINT_expr_onliteral_seq_a {}}% +\def\XINT_expr_onliteral_mul_f #1#2{\xint_c_xviii `{opxmul}#2)\relax #1}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_func_opxadd}, \csh{XINT_flexpr_func_opxadd}, +% \csh{XINT_iiexpr_func_opxadd} and same for mul} +% |modified 1.2c.| +% \begin{macrocode} +\def\XINT_expr_func_opxadd #1#2{\XINT_allexpr_opx \xintbareeval {\xintAdd 0}}% +\def\XINT_flexpr_func_opxadd #1#2{\XINT_allexpr_opx \xintbarefloateval {\XINTinFloatAdd 0}}% +\def\XINT_iiexpr_func_opxadd #1#2{\XINT_allexpr_opx \xintbareiieval {\xintiiAdd 0}}% +\def\XINT_expr_func_opxmul #1#2{\XINT_allexpr_opx \xintbareeval {\xintMul 1}}% +\def\XINT_flexpr_func_opxmul #1#2{\XINT_allexpr_opx \xintbarefloateval {\XINTinFloatMul 1}}% +\def\XINT_iiexpr_func_opxmul #1#2{\XINT_allexpr_opx \xintbareiieval {\xintiiMul 1}}% +% \end{macrocode} +% \lverb|#1=bareeval etc, #2={Add0} ou {Mul1}, #3=liste encapsulée, #4=la variable, #5=expression| +% \begin{macrocode} +\def\XINT_allexpr_opx #1#2#3#4#5% +{% + \expandafter\XINT_expr_getop + \csname.=\romannumeral`&&@\expandafter\XINT_expr_op:_a + \romannumeral`&&@\XINT_expr_unlock #3!{#1#5\relax !#4}{#2}\endcsname +}% +\def\XINT_expr_op:_a #1!#2#3{\XINT_expr_op:_b #3{#2}#1,^,}% +% \end{macrocode} +% \lverb|#2 in \XINT_expr_op:_b is the partial result of computation so far, not +% locked. A noop with have #4=, and #5 the next item which we need to recover. +% No need to be very efficient for that in op:_noop. In op:_d, #4 is \xintAdd or +% similar.| +% \begin{macrocode} +\def\XINT_expr_op:_b #1#2#3#4#5,{% + \if ,#4\xint_dothis\XINT_expr_op:_noop\fi + \if ^#4\xint_dothis\XINT_expr_op:_end\fi + \xint_orthat{\expandafter\XINT_expr_op:_c}\csname.=#4#5\endcsname {#3}#1{#2}% +}% +\def\XINT_expr_op:_c #1#2#3#4% + {\expandafter\XINT_expr_op:_d\romannumeral0#2#1#3{#4}{#2}}% +\def\XINT_expr_op:_d #1!#2#3#4#5% + {\expandafter\XINT_expr_op:_b\expandafter #4\expandafter + {\romannumeral`&&@\XINT:NEhook:two#4{\XINT_expr_unlock#1}{#5}}}% +% \end{macrocode} +% \lverb|The replacement text had expr_seq:_b rather than expr_op:_b due to a +% left-over from copy-paste. This made add and mul fail with an empty range +% for the variable (or "nil" in the list of values). Fixed in 1.2h.| +% \begin{macrocode} +\def\XINT_expr_op:_noop\csname.=,#1\endcsname #2#3#4{\XINT_expr_op:_b #3{#4}{#2}#1,}% +\def\XINT_expr_op:_end \csname.=^\endcsname #1#2#3{#3}% +% \end{macrocode} +% \subsection{\csh{subs()}} +% \lverb|Got simpler with 1.2c as now the dummy variable fetches an +% already encapsulated value, which is anyhow the form in which we get +% it.| +% \begin{macrocode} +\def\XINT_expr_onliteral_subs + {\expandafter\XINT_expr_onliteral_subs_f\romannumeral`&&@\XINT_expr_onliteral_seq_a {}}% +\def\XINT_expr_onliteral_subs_f #1#2{\xint_c_xviii `{subx}#2)\relax #1}% +\def\XINT_expr_func_subx #1#2{\XINT_allexpr_subx \xintbareeval }% +\def\XINT_flexpr_func_subx #1#2{\XINT_allexpr_subx \xintbarefloateval}% +\def\XINT_iiexpr_func_subx #1#2{\XINT_allexpr_subx \xintbareiieval }% +\def\XINT_allexpr_subx #1#2#3#4% #2 is the value to assign to the dummy variable +{% #3 is the dummy variable, #4 is the expression to evaluate + \expandafter\expandafter\expandafter\XINT_expr_getop + \expandafter\XINT_expr_subx:_end\romannumeral0#1#4\relax !#3#2% +}% +\def\XINT_expr_subx:_end #1!#2#3{#1}% +% \end{macrocode} +% \subsection{\csh{rseq()}} +% \localtableofcontents +% +% \lverb|When func_rseq has its turn, initial segment has been scanned by +% oparen, the ; mimicking the rôle of a closing parenthesis, and stopping +% further expansion. Notice that the ; is discovered during standard parsing +% mode, it may be for example {;} or arise from expansion as rseq does not use +% a delimited macro to locate it. +% +% Here and in rrseq and iter, 1.2c adds also use of \xintthebareeval, etc...| +% \begin{macrocode} +\def\XINT_expr_func_rseq {\XINT_allexpr_rseq \xintbareeval \xintthebareeval }% +\def\XINT_flexpr_func_rseq {\XINT_allexpr_rseq \xintbarefloateval \xintthebarefloateval }% +\def\XINT_iiexpr_func_rseq {\XINT_allexpr_rseq \xintbareiieval \xintthebareiieval }% +\def\XINT_allexpr_rseq #1#2#3% +{% + \expandafter\XINT_expr_rseqx\expandafter #1\expandafter#2\expandafter + #3\romannumeral`&&@\XINT_expr_onliteral_seq_a {}% +}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_rseqx}} +% \lverb|The (#5) is for ++ mechanism which must have its closing parenthesis.| +% \begin{macrocode} +\def\XINT_expr_rseqx #1#2#3#4#5% +{% + \expandafter\XINT_expr_rseqy\romannumeral0#1(#5)\relax #3#4#2% +}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_rseqy}} +% \lverb|#1=valeurs pour variable (locked), +% #2=toutes les valeurs initiales (csv,locked), +% #3=variable, #4=expr, +% #5=\xintthebareeval ou \xintthebarefloateval ou \xintthebareiieval| +% \begin{macrocode} +\def\XINT_expr_rseqy #1#2#3#4#5% +{% + \expandafter \XINT_expr_getop + \csname .=\XINT_expr_unlock #2% + \expandafter\XINT_expr_rseq:_aa + \romannumeral`&&@\XINT_expr_unlock #1!{#5#4\relax !#3}#2\endcsname +}% +\def\XINT_expr_rseq:_aa #1{\if +#1\expandafter\XINT_expr_rseq:_A\else + \expandafter\XINT_expr_rseq:_a\fi #1}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_rseq:_a} etc\dots} +% \begin{macrocode} +\def\XINT_expr_rseq:_a #1!#2#3{\XINT_expr_rseq:_b {#3}{#2}#1,^,}% +\def\XINT_expr_rseq:_b #1#2#3#4,{% + \if ,#3\xint_dothis\XINT_expr_rseq:_noop\fi + \if ^#3\xint_dothis\XINT_expr_rseq:_end\fi + \xint_orthat{\expandafter\XINT_expr_rseq:_c}\csname.=#3#4\endcsname + {#1}{#2}% +}% +\def\XINT_expr_rseq:_noop\csname.=,#1\endcsname #2#3{\XINT_expr_rseq:_b {#2}{#3}#1,}% +\def\XINT_expr_rseq:_end \csname.=^\endcsname #1#2{}% +\def\XINT_expr_rseq:_c #1#2#3% + {\expandafter\XINT_expr_rseq:_d\romannumeral`&&@#3#1~#2{#3}}% +\def\XINT_expr_rseq:_d #1{% + \if ^#1\xint_dothis\XINT_expr_rseq:_abort\fi + \if ?#1\xint_dothis\XINT_expr_rseq:_break\fi + \if !#1\xint_dothis\XINT_expr_rseq:_omit\fi + \xint_orthat{\XINT_expr_rseq:_goon #1}}% +\def\XINT_expr_rseq:_goon #1!#2#3~#4#5{,#1\expandafter\XINT_expr_rseq:_b + \romannumeral0\XINT_expr_lockit {#1}{#5}}% +\def\XINT_expr_rseq:_omit #1!#2#3~{\XINT_expr_rseq:_b }% +\def\XINT_expr_rseq:_abort #1!#2#3~#4#5#6^,{}% +\def\XINT_expr_rseq:_break #1!#2#3~#4#5#6^,{,#1}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_rseq:_A} etc\dots} +% \lverb |n++ for rseq. With 1.2c dummy variables pick a single token.| +% \begin{macrocode} +\def\XINT_expr_rseq:_A +#1!#2#3{\XINT_expr_rseq:_D #1#3{#2}}% +\def\XINT_expr_rseq:_D #1#2#3% + {\expandafter\XINT_expr_rseq:_E\romannumeral`&&@#3#1~#2{#3}}% +\def\XINT_expr_rseq:_E #1{\if #1^\xint_dothis\XINT_expr_rseq:_Abort\fi + \if #1?\xint_dothis\XINT_expr_rseq:_Break\fi + \if #1!\xint_dothis\XINT_expr_rseq:_Omit\fi + \xint_orthat{\XINT_expr_rseq:_Goon #1}}% +\def\XINT_expr_rseq:_Goon #1!#2#3~#4#5% + {,#1\expandafter\XINT_expr_rseq:_D + \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\expandafter\endcsname + \romannumeral0\XINT_expr_lockit{#1}{#5}}% +\def\XINT_expr_rseq:_Omit #1!#2#3~%#4#5% + {\expandafter\XINT_expr_rseq:_D + \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\endcsname }% +\def\XINT_expr_rseq:_Abort #1!#2#3~#4#5{}% +\def\XINT_expr_rseq:_Break #1!#2#3~#4#5{,#1}% +% \end{macrocode} +% \subsection{\csh{iter()}} +% \localtableofcontents +% +% \lverb|Prior to 1.2g, the iter keyword was what is now called iterr, +% analogous with rrseq. Somehow I forgot an iter functioning like rseq +% with the sole difference of printing only the last iteration. Both rseq and +% iter work well with list selectors, as @ refers to the whole comma separated +% sequence of the initial values. I have thus deliberately done the backwards +% incompatible renaming of iter to iterr, and the new iter.| +% \begin{macrocode} +\def\XINT_expr_func_iter {\XINT_allexpr_iter \xintbareeval \xintthebareeval }% +\def\XINT_flexpr_func_iter {\XINT_allexpr_iter \xintbarefloateval \xintthebarefloateval }% +\def\XINT_iiexpr_func_iter {\XINT_allexpr_iter \xintbareiieval \xintthebareiieval }% +\def\XINT_allexpr_iter #1#2#3% +{% + \expandafter\XINT_expr_iterx\expandafter #1\expandafter#2\expandafter + #3\romannumeral`&&@\XINT_expr_onliteral_seq_a {}% +}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_iterx}} +% \lverb|The (#5) is for ++ mechanism which must have its closing parenthesis.| +% \begin{macrocode} +\def\XINT_expr_iterx #1#2#3#4#5% +{% + \expandafter\XINT_expr_itery\romannumeral0#1(#5)\relax #3#4#2% +}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_itery}} +% \lverb|#1=valeurs pour variable (locked), +% #2=toutes les valeurs initiales (csv,locked), +% #3=variable, #4=expr, +% #5=\xintthebareeval ou \xintthebarefloateval ou \xintthebareiieval| +% \begin{macrocode} +\def\XINT_expr_itery #1#2#3#4#5% +{% + \expandafter \XINT_expr_getop + \csname .=% + \expandafter\XINT_expr_iter:_aa + \romannumeral`&&@\XINT_expr_unlock #1!{#5#4\relax !#3}#2\endcsname +}% +\def\XINT_expr_iter:_aa #1{\if +#1\expandafter\XINT_expr_iter:_A\else + \expandafter\XINT_expr_iter:_a\fi #1}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_iter:_a} etc\dots} +% \begin{macrocode} +\def\XINT_expr_iter:_a #1!#2#3{\XINT_expr_iter:_b {#3}{#2}#1,^,}% +\def\XINT_expr_iter:_b #1#2#3#4,{% + \if ,#3\xint_dothis\XINT_expr_iter:_noop\fi + \if ^#3\xint_dothis\XINT_expr_iter:_end\fi + \xint_orthat{\expandafter\XINT_expr_iter:_c}% + \csname.=#3#4\endcsname {#1}{#2}% +}% +\def\XINT_expr_iter:_noop\csname.=,#1\endcsname #2#3{\XINT_expr_iter:_b {#2}{#3}#1,}% +\def\XINT_expr_iter:_end \csname.=^\endcsname #1#2{\XINT_expr:_unlock #1}% +\def\XINT_expr_iter:_c #1#2#3% + {\expandafter\XINT_expr_iter:_d\romannumeral`&&@#3#1~#2{#3}}% +\def\XINT_expr_iter:_d #1{% + \if ^#1\xint_dothis\XINT_expr_iter:_abort\fi + \if ?#1\xint_dothis\XINT_expr_iter:_break\fi + \if !#1\xint_dothis\XINT_expr_iter:_omit\fi + \xint_orthat{\XINT_expr_iter:_goon #1}}% +\def\XINT_expr_iter:_goon #1!#2#3~#4#5% + {\expandafter\XINT_expr_iter:_b\romannumeral0\XINT_expr_lockit {#1}{#5}}% +\def\XINT_expr_iter:_omit #1!#2#3~{\XINT_expr_iter:_b }% +\def\XINT_expr_iter:_abort #1!#2#3~#4#5#6^,{\XINT_expr_unlock #4}% +\def\XINT_expr_iter:_break #1!#2#3~#4#5#6^,{#1}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_iter:_A} etc\dots} +% \lverb |n++ for iter. With 1.2c dummy variables pick a single token.| +% \begin{macrocode} +\def\XINT_expr_iter:_A +#1!#2#3{\XINT_expr_iter:_D #1#3{#2}}% +\def\XINT_expr_iter:_D #1#2#3% + {\expandafter\XINT_expr_iter:_E\romannumeral`&&@#3#1~#2{#3}}% +\def\XINT_expr_iter:_E #1{\if #1^\xint_dothis\XINT_expr_iter:_Abort\fi + \if #1?\xint_dothis\XINT_expr_iter:_Break\fi + \if #1!\xint_dothis\XINT_expr_iter:_Omit\fi + \xint_orthat{\XINT_expr_iter:_Goon #1}}% +\def\XINT_expr_iter:_Goon #1!#2#3~#4#5% + {\expandafter\XINT_expr_iter:_D + \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\expandafter\endcsname + \romannumeral0\XINT_expr_lockit{#1}{#5}}% +\def\XINT_expr_iter:_Omit #1!#2#3~%#4#5% + {\expandafter\XINT_expr_iter:_D + \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\endcsname }% +\def\XINT_expr_iter:_Abort #1!#2#3~#4#5{\XINT_expr:_unlock #4}% +\def\XINT_expr_iter:_Break #1!#2#3~#4#5{#1}% +% \end{macrocode} +% \subsection{\csh{rrseq()}} +% \localtableofcontents +% +% \lverb|When func_rrseq has its turn, initial segment has been scanned +% by oparen, the ; mimicking the rôle of a closing parenthesis, and +% stopping further expansion.| +% \begin{macrocode} +\def\XINT_expr_func_rrseq {\XINT_allexpr_rrseq \xintbareeval \xintthebareeval }% +\def\XINT_flexpr_func_rrseq {\XINT_allexpr_rrseq \xintbarefloateval \xintthebarefloateval }% +\def\XINT_iiexpr_func_rrseq {\XINT_allexpr_rrseq \xintbareiieval \xintthebareiieval }% +\def\XINT_allexpr_rrseq #1#2#3% +{% + \expandafter\XINT_expr_rrseqx\expandafter #1\expandafter#2\expandafter + #3\romannumeral`&&@\XINT_expr_onliteral_seq_a {}% +}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_rrseqx}} +% \lverb|The (#5) is for ++ mechanism which must have its closing parenthesis.| +% \begin{macrocode} +\def\XINT_expr_rrseqx #1#2#3#4#5% +{% + \expandafter\XINT_expr_rrseqy\romannumeral0#1(#5)\expandafter\relax + \expandafter{\romannumeral0\xintapply \XINT_expr_lockit + {\xintRevWithBraces{\xintCSVtoListNonStripped{\XINT_expr_unlock #3}}}}% + #3#4#2% +}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_rrseqy}} +% \lverb|#1=valeurs pour variable (locked), +% #2=initial values (reversed, one (braced) token each) +% #3=toutes les valeurs initiales (csv,locked), +% #4=variable, #5=expr, +% #6=\xintthebareeval ou \xintthebarefloateval ou \xintthebareiieval| +% \begin{macrocode} +\def\XINT_expr_rrseqy #1#2#3#4#5#6% +{% + \expandafter \XINT_expr_getop + \csname .=\XINT_expr_unlock #3% + \expandafter\XINT_expr_rrseq:_aa + \romannumeral`&&@\XINT_expr_unlock #1!{#6#5\relax !#4}{#2}\endcsname +}% +\def\XINT_expr_rrseq:_aa #1{\if +#1\expandafter\XINT_expr_rrseq:_A\else + \expandafter\XINT_expr_rrseq:_a\fi #1}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_rrseq:_a} etc\dots} +% \lverb|Attention que ? a catcode 3 ici et dans iter.| +% \begin{macrocode} +\catcode`? 3 +\def\XINT_expr_rrseq:_a #1!#2#3{\XINT_expr_rrseq:_b {#3}{#2}#1,^,}% +\def\XINT_expr_rrseq:_b #1#2#3#4,{% + \if ,#3\xint_dothis\XINT_expr_rrseq:_noop\fi + \if ^#3\xint_dothis\XINT_expr_rrseq:_end\fi + \xint_orthat{\expandafter\XINT_expr_rrseq:_c}\csname.=#3#4\endcsname + {#1}{#2}% +}% +\def\XINT_expr_rrseq:_noop\csname.=,#1\endcsname #2#3{\XINT_expr_rrseq:_b {#2}{#3}#1,}% +\def\XINT_expr_rrseq:_end \csname.=^\endcsname #1#2{}% +\def\XINT_expr_rrseq:_c #1#2#3% + {\expandafter\XINT_expr_rrseq:_d\romannumeral`&&@#3#1~#2?{#3}}% +\def\XINT_expr_rrseq:_d #1{% + \if ^#1\xint_dothis\XINT_expr_rrseq:_abort\fi + \if ?#1\xint_dothis\XINT_expr_rrseq:_break\fi + \if !#1\xint_dothis\XINT_expr_rrseq:_omit\fi + \xint_orthat{\XINT_expr_rrseq:_goon #1}% +}% +\def\XINT_expr_rrseq:_goon #1!#2#3~#4?#5{,#1\expandafter\XINT_expr_rrseq:_b\expandafter + {\romannumeral0\xinttrim{-1}{\XINT_expr_lockit{#1}#4}}{#5}}% +\def\XINT_expr_rrseq:_omit #1!#2#3~{\XINT_expr_rrseq:_b }% +\def\XINT_expr_rrseq:_abort #1!#2#3~#4?#5#6^,{}% +\def\XINT_expr_rrseq:_break #1!#2#3~#4?#5#6^,{,#1}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_rrseq:_A} etc\dots} +% \lverb |n++ for rrseq. With 1.2C, the #1 in \XINT_expr_rrseq:_A is a single token.| +% \begin{macrocode} +\def\XINT_expr_rrseq:_A +#1!#2#3{\XINT_expr_rrseq:_D #1{#3}{#2}}% +\def\XINT_expr_rrseq:_D #1#2#3% + {\expandafter\XINT_expr_rrseq:_E\romannumeral`&&@#3#1~#2?{#3}}% +\def\XINT_expr_rrseq:_Goon #1!#2#3~#4?#5% + {,#1\expandafter\XINT_expr_rrseq:_D + \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\expandafter\endcsname + \expandafter{\romannumeral0\xinttrim{-1}{\XINT_expr_lockit{#1}#4}}{#5}}% +\def\XINT_expr_rrseq:_Omit #1!#2#3~%#4?#5% + {\expandafter\XINT_expr_rrseq:_D + \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\endcsname}% +\def\XINT_expr_rrseq:_Abort #1!#2#3~#4?#5{}% +\def\XINT_expr_rrseq:_Break #1!#2#3~#4?#5{,#1}% +\def\XINT_expr_rrseq:_E #1{\if #1^\xint_dothis\XINT_expr_rrseq:_Abort\fi + \if #1?\xint_dothis\XINT_expr_rrseq:_Break\fi + \if #1!\xint_dothis\XINT_expr_rrseq:_Omit\fi + \xint_orthat{\XINT_expr_rrseq:_Goon #1}}% +% \end{macrocode} +% \subsection{\csh{iterr()}} +% \localtableofcontents +% \begin{macrocode} +\def\XINT_expr_func_iterr {\XINT_allexpr_iterr \xintbareeval \xintthebareeval }% +\def\XINT_flexpr_func_iterr {\XINT_allexpr_iterr \xintbarefloateval \xintthebarefloateval }% +\def\XINT_iiexpr_func_iterr {\XINT_allexpr_iterr \xintbareiieval \xintthebareiieval }% +\def\XINT_allexpr_iterr #1#2#3% +{% + \expandafter\XINT_expr_iterrx\expandafter #1\expandafter #2\expandafter + #3\romannumeral`&&@\XINT_expr_onliteral_seq_a {}% +}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_iterrx}} +% \lverb|The (#5) is for ++ mechanism which must have its closing parenthesis.| +% \begin{macrocode} +\def\XINT_expr_iterrx #1#2#3#4#5% +{% + \expandafter\XINT_expr_iterry\romannumeral0#1(#5)\expandafter\relax + \expandafter{\romannumeral0\xintapply \XINT_expr_lockit + {\xintRevWithBraces{\xintCSVtoListNonStripped{\XINT_expr_unlock #3}}}}% + #3#4#2% +}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_iterry}} +% \lverb|#1=valeurs pour variable (locked), +% #2=initial values (reversed, one (braced) token each) +% #3=toutes les valeurs initiales (csv,locked), +% #4=variable, #5=expr, +% #6=\xintbareeval ou \xintbarefloateval ou \xintbareiieval| +% \begin{macrocode} +\def\XINT_expr_iterry #1#2#3#4#5#6% +{% + \expandafter \XINT_expr_getop + \csname .=% + \expandafter\XINT_expr_iterr:_aa + \romannumeral`&&@\XINT_expr_unlock #1!{#6#5\relax !#4}{#2}\endcsname +}% +\def\XINT_expr_iterr:_aa #1{\if +#1\expandafter\XINT_expr_iterr:_A\else + \expandafter\XINT_expr_iterr:_a\fi #1}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_iterr:_a} etc\dots} +% \begin{macrocode} +\def\XINT_expr_iterr:_a #1!#2#3{\XINT_expr_iterr:_b {#3}{#2}#1,^,}% +\def\XINT_expr_iterr:_b #1#2#3#4,{% + \if ,#3\xint_dothis\XINT_expr_iterr:_noop\fi + \if ^#3\xint_dothis\XINT_expr_iterr:_end\fi + \xint_orthat{\expandafter\XINT_expr_iterr:_c}% + \csname.=#3#4\endcsname {#1}{#2}% +}% +\def\XINT_expr_iterr:_noop\csname.=,#1\endcsname #2#3{\XINT_expr_iterr:_b {#2}{#3}#1,}% +\def\XINT_expr_iterr:_end \csname.=^\endcsname #1#2% + {\expandafter\xint_gobble_i\romannumeral0\xintapplyunbraced + {,\XINT_expr:_unlock}{\xintReverseOrder{#1\space}}}% +\def\XINT_expr_iterr:_c #1#2#3% + {\expandafter\XINT_expr_iterr:_d\romannumeral`&&@#3#1~#2?{#3}}% +\def\XINT_expr_iterr:_d #1{% + \if ^#1\xint_dothis\XINT_expr_iterr:_abort\fi + \if ?#1\xint_dothis\XINT_expr_iterr:_break\fi + \if !#1\xint_dothis\XINT_expr_iterr:_omit\fi + \xint_orthat{\XINT_expr_iterr:_goon #1}% +}% +\def\XINT_expr_iterr:_goon #1!#2#3~#4?#5{\expandafter\XINT_expr_iterr:_b\expandafter + {\romannumeral0\xinttrim{-1}{\XINT_expr_lockit{#1}#4}}{#5}}% +\def\XINT_expr_iterr:_omit #1!#2#3~{\XINT_expr_iterr:_b }% +\def\XINT_expr_iterr:_abort #1!#2#3~#4?#5#6^,% + {\expandafter\xint_gobble_i\romannumeral0\xintapplyunbraced + {,\XINT_expr:_unlock}{\xintReverseOrder{#4\space}}}% +\def\XINT_expr_iterr:_break #1!#2#3~#4?#5#6^,% + {\expandafter\xint_gobble_iv\romannumeral0\xintapplyunbraced + {,\XINT_expr:_unlock}{\xintReverseOrder{#4\space}},#1}% +\def\XINT_expr:_unlock #1{\XINT_expr_unlock #1}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_iterr:_A} etc\dots} +% \lverb |n++ for iterr. ? is of catcode 3 here.| +% \begin{macrocode} +\def\XINT_expr_iterr:_A +#1!#2#3{\XINT_expr_iterr:_D #1{#3}{#2}}% +\def\XINT_expr_iterr:_D #1#2#3% + {\expandafter\XINT_expr_iterr:_E\romannumeral`&&@#3#1~#2?{#3}}% +\def\XINT_expr_iterr:_Goon #1!#2#3~#4?#5% + {\expandafter\XINT_expr_iterr:_D + \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\expandafter\endcsname + \expandafter{\romannumeral0\xinttrim{-1}{\XINT_expr_lockit{#1}#4}}{#5}}% +\def\XINT_expr_iterr:_Omit #1!#2#3~%#4?#5% + {\expandafter\XINT_expr_iterr:_D + \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\endcsname}% +\def\XINT_expr_iterr:_Abort #1!#2#3~#4?#5% + {\expandafter\xint_gobble_i\romannumeral0\xintapplyunbraced + {,\XINT_expr:_unlock}{\xintReverseOrder{#4\space}}}% +\def\XINT_expr_iterr:_Break #1!#2#3~#4?#5% + {\expandafter\xint_gobble_iv\romannumeral0\xintapplyunbraced + {,\XINT_expr:_unlock}{\xintReverseOrder{#4\space}},#1}% +\def\XINT_expr_iterr:_E #1{\if #1^\xint_dothis\XINT_expr_iterr:_Abort\fi + \if #1?\xint_dothis\XINT_expr_iterr:_Break\fi + \if #1!\xint_dothis\XINT_expr_iterr:_Omit\fi + \xint_orthat{\XINT_expr_iterr:_Goon #1}}% +\catcode`? 11 +% \end{macrocode} +% \subsection{Macros handling csv lists for functions with multiple comma +% separated arguments in expressions} +% \localtableofcontents +% \lverb|These macros are used inside \csname...\endcsname. These things +% are not initiated by a \romannumeral in general, but in some cases they are, +% especially when involved in an \xintNewExpr. They will then be protected +% against expansion and expand only later in contexts governed by an +% initial \romannumeral-`0. There each new item may need to be expanded, which +% would not be the case in the use for the _func_ things. +% +% 1.2g adds (to be continued)| +% +% \subsubsection{\csh{xintANDof:csv}} +% \lverb|1.09a. For use by \xintexpr inside \csname. 1.1, je remplace +% ifTrueAelseB par iiNotZero pour des raisons d'optimisations.| +% \begin{macrocode} +\def\xintANDof:csv #1{\expandafter\XINT_andof:_a\romannumeral`&&@#1,,^}% +\def\XINT_andof:_a #1{\if ,#1\expandafter\XINT_andof:_e + \else\expandafter\XINT_andof:_c\fi #1}% +\def\XINT_andof:_c #1,{\xintiiifNotZero {#1}{\XINT_andof:_a}{\XINT_andof:_no}}% +\def\XINT_andof:_no #1^{0}% +\def\XINT_andof:_e #1^{1}% works with empty list +% \end{macrocode} +% \subsubsection{\csh{xintORof:csv}} +% \lverb|1.09a. For use by \xintexpr.| +% \begin{macrocode} +\def\xintORof:csv #1{\expandafter\XINT_orof:_a\romannumeral`&&@#1,,^}% +\def\XINT_orof:_a #1{\if ,#1\expandafter\XINT_orof:_e + \else\expandafter\XINT_orof:_c\fi #1}% +\def\XINT_orof:_c #1,{\xintiiifNotZero{#1}{\XINT_orof:_yes}{\XINT_orof:_a}}% +\def\XINT_orof:_yes #1^{1}% +\def\XINT_orof:_e #1^{0}% works with empty list +% \end{macrocode} +% \subsubsection{\csh{xintXORof:csv}} +% \lverb|1.09a. For use by \xintexpr (inside a \csname..\endcsname).| +% \begin{macrocode} +\def\xintXORof:csv #1{\expandafter\XINT_xorof:_a\expandafter 0\romannumeral`&&@#1,,^}% +\def\XINT_xorof:_a #1#2,{\XINT_xorof:_b #2,#1}% +\def\XINT_xorof:_b #1{\if ,#1\expandafter\XINT_xorof:_e + \else\expandafter\XINT_xorof:_c\fi #1}% +\def\XINT_xorof:_c #1,#2% + {\xintiiifNotZero {#1}{\if #20\xint_afterfi{\XINT_xorof:_a 1}% + \else\xint_afterfi{\XINT_xorof:_a 0}\fi}% + {\XINT_xorof:_a #2}% + }% +\def\XINT_xorof:_e ,#1#2^{#1}% allows empty list (then returns 0) +% \end{macrocode} +% \subsubsection{Generic csv routine (\csh{XINT_oncsv:_a})} +% \lverb|1.1. generic routine. up to the loss of some efficiency, especially +% for Sum:csv and Prod:csv, where \XINTinFloat will be done twice for each +% argument. +% +% FIXME: DOCUMENT BETTER. HOW IS THIS CALLED? WHAT IS MEANING OF ARGUMENTS? IS +% THERE ANY POST-PROCESSING OF FINAL RESULT?| +% \begin{macrocode} +\def\XINT_oncsv:_empty #1,^,#2{#2}% +\def\XINT_oncsv:_end ^,#1#2#3#4{#1}% +\def\XINT_oncsv:_a #1#2#3% + {\if ,#3\expandafter\XINT_oncsv:_empty\else\expandafter\XINT_oncsv:_b\fi #1#2#3}% +\def\XINT_oncsv:_b #1#2#3,% + {\expandafter\XINT_oncsv:_c \expandafter{\romannumeral`&&@#2{#3}}#1#2}% +\def\XINT_oncsv:_c #1#2#3#4,{\expandafter\XINT_oncsv:_d \romannumeral`&&@#4,{#1}#2#3}% +\def\XINT_oncsv:_d #1% + {\if ^#1\expandafter\XINT_oncsv:_end\else\expandafter\XINT_oncsv:_e\fi #1}% +\def\XINT_oncsv:_e #1,#2#3#4% + {\expandafter\XINT_oncsv:_c\expandafter {\romannumeral`&&@#3{#4{#1}}{#2}}#3#4}% +% \end{macrocode} +% \subsubsection{\csh{xintMaxof:csv}, \csh{xintiiMaxof:csv}} +% \lverb|1.09i. Rewritten for 1.1. Compatible avec liste vide donnant valeur par +% défaut. Pas compatible avec items manquants. +% ah je m'aperçois au dernier moment que je n'ai pas en effet de \xintiiMax. +% Je devrais le rajouter. En tout cas ici c'est uniquement pour xintiiexpr, +% dans il faut bien sûr ne pas faire de xintNum, donc il faut un iimax.| +% \begin{macrocode} +\def\xintMaxof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintmax + \expandafter\xint_firstofone\romannumeral`&&@#1,^,{0/1[0]}}% +\def\xintiiMaxof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintiimax + \expandafter\xint_firstofone\romannumeral`&&@#1,^,0}% +% \end{macrocode} +% \subsubsection{\csh{xintMinof:csv}, \csh{xintiiMinof:csv}} +% \lverb|1.09i. Rewritten for 1.1. For use by \xintiiexpr.| +% \begin{macrocode} +\def\xintMinof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintmin + \expandafter\xint_firstofone\romannumeral`&&@#1,^,{0/1[0]}}% +\def\xintiiMinof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintiimin + \expandafter\xint_firstofone\romannumeral`&&@#1,^,0}% +% \end{macrocode} +% \subsubsection{\csh{xintSum:csv}, \csh{xintiiSum:csv}} +% \lverb|1.09a. Rewritten for 1.1. For use by \xintexpr.| +% \begin{macrocode} +\def\xintSum:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintadd + \expandafter\xint_firstofone\romannumeral`&&@#1,^,{0/1[0]}}% +\def\xintiiSum:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintiiadd + \expandafter\xint_firstofone\romannumeral`&&@#1,^,0}% +% \end{macrocode} +% \subsubsection{\csh{xintPrd:csv}, \csh{xintiiPrd:csv}} +% \lverb|1.09a. Rewritten for 1.1. For use by \xintexpr.| +% \begin{macrocode} +\def\xintPrd:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintmul + \expandafter\xint_firstofone\romannumeral`&&@#1,^,{1/1[0]}}% +\def\xintiiPrd:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintiimul + \expandafter\xint_firstofone\romannumeral`&&@#1,^,1}% +% \end{macrocode} +% \subsubsection{\csh{xintGCDof:csv}, \csh{xintLCMof:csv}} +% \changed{1.09a}{} +% Non-integer arguments are replaced by integers as |\xintGCD| and |\xintLCM| +% apply |\xintNum|. +% \changed{1.1}{} +% As with other "csv" macros, the (list) argument needs to be expanded in case +% it arises within a macro created from \csbxint{NewExpr}. +% \changed{1.3d}{} +% No more usage of the integer-only \xintgcdnameimp macros, replaced by direct +% coding here, in order to extend scope to fractions (and produce fractions). +% Hesitation about allowing empty input, and what to return then. +% \begin{macrocode} +\def\xintGCDof:csv #1{\expandafter\XINT_gcdof:_a\romannumeral`&&@#1,^,{1/1[0]}}% +\def\XINT_gcdof:_a #1% + {\if ,#1\expandafter\XINT_oncsv:_empty\else\expandafter\XINT_gcdof:_b\fi #1}% +% \end{macrocode} +% This abuses the way |\xintiiabs| works in order to avoid fetching whole +% argument again. +% \begin{macrocode} +\def\XINT_gcdof:_b #1,% + {\expandafter\XINT_gcdof:_c\romannumeral0\xintiiabs#1\xint:}% +\def\XINT_gcdof:_c #1\xint:#2,% + {\expandafter\XINT_gcdof:_d\romannumeral0\xintiiabs#2\xint:#1\xint:}% +\def\XINT_gcdof:_d #1% + {\if ^#1\expandafter\XINT_gcdof:_end\else\expandafter\XINT_gcdof:_e\fi #1}% +% \end{macrocode} +% \lverb|\xintMod will apply \xintRaw on its arguments, and will output in +% normalized format. But in exceptional case with a one-item or one item and +% then zeros, the output is (absolute value of) this item, not necessarily in +% A/B[N] format.| +% \begin{macrocode} +\def\XINT_gcdof:_e#1#2\xint:#3\xint: +{% + \if0#1\expandafter\XINT_gcdof:_f\fi + \expandafter\XINT_gcdof:_e\romannumeral0\xintmod{#3}{#1#2}\xint:#1#2\xint: +}% +\def\XINT_gcdof:_f + \expandafter\XINT_gcdof:_e\romannumeral0\xintmod#1#2\xint:#3\xint:#4,% +{% + \expandafter\XINT_gcdof:_d\romannumeral0\xintiiabs#4\xint:#1\xint: +}% +% \end{macrocode} +% \lverb|As for others :csv macros here expansion in the case of \xintNewExpr +% crafted macros is triggered by (an equivalent to) \romannumeral-`0. Else it +% happens inside \csname...\endcsname, and there is no triggering +% \romannumeral, attention to not leave a space upfront.| +% \begin{macrocode} +\def\XINT_gcdof:_end ^\xint:#1\xint:#2{#1}% +% \end{macrocode} +% \lverb|For least common multiple, we will use \xintInv, but this requires to +% make sure fractional input is in raw format.| +% \begin{macrocode} +\def\xintLCMof:csv #1{\expandafter\XINT_lcmof:_a\romannumeral`&&@#1,^,{0/1[0]}}% +\def\XINT_lcmof:_a #1% + {\if ,#1\expandafter\XINT_oncsv:_empty\else\expandafter\XINT_lcmof:_b\fi #1}% +\def\XINT_lcmof:_b #1,% + {\expandafter\XINT_lcmof:_c\romannumeral0\xintiiabs\xintRaw{#1}\xint:}% +\def\XINT_lcmof:_c #1{\if0#1\expandafter\XINT_lcmof:_zero\fi + \expandafter\XINT_lcmof:_d\romannumeral0\XINT_inv #1}% +% \end{macrocode} +% \lverb|We can do \xintiiabs^, but \xintiiabs\xintRaw{^} would throw +% an error. So we need to delay applying \xintRaw to new item.| +% \begin{macrocode} +\def\XINT_lcmof:_d #1\xint:#2,% + {\expandafter\XINT_lcmof:_e\romannumeral0\xintiiabs#2\xint:#1\xint:}% +\def\XINT_lcmof:_e #1% + {\if ^#1\expandafter\XINT_lcmof:_end\else\expandafter\XINT_lcmof:_f\fi #1}% +% \end{macrocode} +% \lverb|As soon as we hit against a zero item, the l.c.m is known to be zero +% itself. Else we need to inverse it, but this requires full A/B[N] raw format, +% hence the \xintraw.| +% \begin{macrocode} +\def\XINT_lcmof:_f#1#2\xint: +{% + \if0#1\expandafter\XINT_lcmof:_zero\fi + \expandafter\XINT_lcmof:_g\romannumeral0\expandafter\XINT_inv + \romannumeral0\xintraw{#1#2}\xint: +}% +\def\XINT_lcmof:_g #1#2\xint:#3\xint: +{% + \if0#1\expandafter\XINT_lcmof:_h\fi + \expandafter\XINT_lcmof:_g\romannumeral0\xintmod{#3}{#1#2}\xint:#1#2\xint: +}% +\def\XINT_lcmof:_h + \expandafter\XINT_lcmof:_g\romannumeral0\xintmod#1#2\xint:#3\xint:#4,% +{% + \expandafter\XINT_lcmof:_e\romannumeral0\xintiiabs#4\xint:#1\xint: +}% +\def\XINT_lcmof:_zero #1^,#2{0/1[0]}% +% \end{macrocode} +% \lverb|We need this \romannumeral0 to remove the up-front space token which +% will be left by \XINT_inv, in case of \csname..\endcsname expansion.| +% \begin{macrocode} +\def\XINT_lcmof:_end ^\xint:#1\xint:#2{\romannumeral0\XINT_inv #1}% +% \end{macrocode} +% \subsubsection{\csh{xintiiGCDof:csv}, \csh{xintiiLCMof:csv}} +% \changed{1.1a}{} +% For \csbxint{iiexpr}. Requires the \xintgcdnameimp provided macros. +% \begin{macrocode} +\def\xintiiGCDof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintiigcd + \expandafter\xint_firstofone\romannumeral`&&@#1,^,1}% +\def\xintiiLCMof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintiilcm + \expandafter\xint_firstofone\romannumeral`&&@#1,^,0}% +% \end{macrocode} +% \subsubsection{\csh{XINTinFloatdigits}, \csh{XINTinFloatSqrtdigits}, +% \csh{XINTinFloatFacdigits}, \csh{XINTiLogTendigits}} +% \lverb|For \xintNewExpr matters, mainly. +% +% At 1.3e I add \XINTinFloatSdigits and use it at various places. I also modified +% \XINTinFloatFac to use S(hort) output format. +% +% Also added \XINTiLogTendigits| +% \begin{macrocode} +\def\XINTinFloatdigits {\XINTinFloat [\XINTdigits]}% +\def\XINTinFloatSdigits {\XINTinFloatS [\XINTdigits]}% +\def\XINTinFloatSqrtdigits {\XINTinFloatSqrt[\XINTdigits]}% +\def\XINTinFloatFacdigits {\XINTinFloatFac [\XINTdigits]}% +\def\XINTFloatiLogTendigits{\XINTFloatiLogTen[\XINTdigits]}% +% \end{macrocode} +% \subsubsection{\csh{XINTinFloatMaxof:csv}, \csh{XINTinFloatMinof:csv}} +% \lverb|1.09a. Rewritten for 1.1. For use by \xintfloatexpr. Name changed in +% 1.09h. Changed at 1.3e to use \XINTinFloatSdigits.| +% \begin{macrocode} +\def\XINTinFloatMaxof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintmax + \expandafter\XINTinFloatSdigits\romannumeral`&&@#1,^,{0[0]}}% +\def\XINTinFloatMinof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintmin + \expandafter\XINTinFloatSdigits\romannumeral`&&@#1,^,{0[0]}}% +% \end{macrocode} +% \subsubsection{\csh{XINTinFloatSum:csv}, \csh{XINTinFloatPrd:csv}} +% \lverb|1.09a. Rewritten for 1.1. For use by \xintfloatexpr. Modified at 1.3e +% to use \XINTinFloatSdigits.| +% \begin{macrocode} +\def\XINTinFloatSum:csv #1{\expandafter\XINT_oncsv:_a\expandafter\XINTinfloatadd + \expandafter\XINTinFloatSdigits\romannumeral`&&@#1,^,{0[0]}}% +\def\XINTinFloatPrd:csv #1{\expandafter\XINT_oncsv:_a\expandafter\XINTinfloatmul + \expandafter\XINTinFloatSdigits\romannumeral`&&@#1,^,{1[0]}}% +% \end{macrocode} +% \subsection{Auxiliary wrappers for function macros} +% \begin{macrocode} +\def\XINT:expr:one:and:opt #1,#2,#3!#4#5% +{% + \if\relax#3\relax\expandafter\xint_firstoftwo\else + \expandafter\xint_secondoftwo\fi + {#4}{#5[\xintNum{#2}]}{#1}% +}% +\def\XINT:expr:tacitzeroifonearg #1,#2,#3!#4#5% +{% + \if\relax#3\relax\expandafter\xint_firstoftwo\else + \expandafter\xint_secondoftwo\fi + {#4{0}}{#5{\xintNum{#2}}}{#1}% +}% +\def\XINT:iiexpr:tacitzeroifonearg #1,#2,#3!#4% +{% + \if\relax#3\relax\expandafter\xint_firstoftwo\else + \expandafter\xint_secondoftwo\fi + {#4{0}}{#4{#2}}{#1}% +}% +\def\XINT:expr:totwo #1#2{#1,#2}% +\def\XINT:expr:two:to:two #1,#2,!#3% +{% + \expandafter\XINT:expr:totwo\romannumeral`&&@#3{#1}{#2}% +}% +\let\XINT:flexpr:two:to:two\XINT:expr:two:to:two +\let\XINT:iiexpr:two:to:two\XINT:expr:two:to:two +% \end{macrocode} +% \def\auxiliarymacro#1{ \noexpand\cshn{#1()}} +% \edef\zzz{The \xintListWithSep{, }{\xintApply\auxiliarymacro +% {{num}{reduce}{preduce}{abs}{sgn}{frac}{floor}{ceil}{sqr}{sqrt}{sqrtr}{float} +% {sfloat}{ilog10}{inv}{round}{trunc}{mod}{quo}{rem}{divmod}{gcd}{lcm}{max}{min} +% {`+`} +% {`*`} +% {?}{!}{not}{all}{any}{xor}{if}{ifsgn}{ifint}{ifone}{even}{odd}{isint}{isone} +% {first}{last}{len}{reversed}{factorial}{binomial}}} +% and \noexpand\cshn{randrange()} functions} +% \expandafter\subsection\expandafter{\zzz} +% \begin{macrocode} +\def\XINT_expr_func_num #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintNum{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_num\XINT_expr_func_num +\let\XINT_iiexpr_func_num\XINT_expr_func_num +\def\XINT_expr_func_reduce #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintIrr{\XINT_expr_unlock #3}[0]\endcsname +}% +\let\XINT_flexpr_func_reduce\XINT_expr_func_reduce +\def\XINT_expr_func_preduce #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintPIrr{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_preduce\XINT_expr_func_preduce +\def\XINT_expr_func_abs #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintAbs{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_abs\XINT_expr_func_abs +\def\XINT_iiexpr_func_abs #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiiAbs{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_sgn #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintSgn{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_sgn\XINT_expr_func_sgn +\def\XINT_iiexpr_func_sgn #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiiSgn{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_frac #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintTFrac{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_flexpr_func_frac #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\XINTinFloatFracdigits{\XINT_expr_unlock #3}\endcsname +}% +% \end{macrocode} +% \lverb|no \XINT_iiexpr_func_frac| +% \begin{macrocode} +\def\XINT_expr_func_floor #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintFloor{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_floor\XINT_expr_func_floor +% \end{macrocode} +% \lverb|The floor and ceil functions in \xintiiexpr require protect(a/b) or, +% better, \qfrac(a/b); else the / will be executed first and do an integer +% rounded division.| +% \begin{macrocode} +\def\XINT_iiexpr_func_floor #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiFloor{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_ceil #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintCeil{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_ceil\XINT_expr_func_ceil +\def\XINT_iiexpr_func_ceil #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiCeil{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_sqr #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintSqr{\XINT_expr_unlock #3}\endcsname +}% +\def\XINTinFloatSqr#1{\XINTinFloatMul{#1}{#1}}% revoir après +\def\XINT_flexpr_func_sqr #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\XINTinFloatSqr{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_iiexpr_func_sqr #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiiSqr{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_? #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiiIsNotZero{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_? \XINT_expr_func_? +\let\XINT_iiexpr_func_? \XINT_expr_func_? +\def\XINT_expr_func_! #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiiIsZero{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_! \XINT_expr_func_! +\let\XINT_iiexpr_func_! \XINT_expr_func_! +\def\XINT_expr_func_not #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiiIsZero{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_not \XINT_expr_func_not +\let\XINT_iiexpr_func_not \XINT_expr_func_not +\def\XINT_expr_func_odd #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintOdd{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_odd\XINT_expr_func_odd +\def\XINT_iiexpr_func_odd #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiiOdd{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_even #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintEven{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_even\XINT_expr_func_even +\def\XINT_iiexpr_func_even #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiiEven{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_isint #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintIsInt{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_flexpr_func_isint #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintFloatIsInt{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_iiexpr_func_isint\XINT_expr_func_isint % ? perhaps rather always 1 +\def\XINT_expr_func_isone #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintIsOne{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_isone\XINT_expr_func_isone +\def\XINT_iiexpr_func_isone #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiiIsOne{\XINT_expr_unlock #3}\endcsname +}% +% REVOIR nuple +\def\XINT_expr_func_nuple #1#2#3% + {\expandafter #1\expandafter #2\csname.=\XINT_expr_unlock #3\endcsname }% +\let\XINT_flexpr_func_nuple\XINT_expr_func_nuple +\let\XINT_iiexpr_func_nuple\XINT_expr_func_nuple +\def\XINT_expr_func_factorial #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:expr:one:and:opt + \romannumeral`&&@\XINT_expr_unlock#3,,!\xintFac\XINTinFloatFac + \endcsname +}% +\def\XINT_flexpr_func_factorial #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:expr:one:and:opt + \romannumeral`&&@\XINT_expr_unlock#3,,!\XINTinFloatFacdigits\XINTinFloatFac + \endcsname +}% +\def\XINT_iiexpr_func_factorial #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiiFac{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_sqrt #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:expr:one:and:opt + \romannumeral`&&@\XINT_expr_unlock#3,,!\XINTinFloatSqrtdigits\XINTinFloatSqrt + \endcsname +}% +\let\XINT_flexpr_func_sqrt\XINT_expr_func_sqrt +\def\XINT_iiexpr_func_sqrt #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiiSqrt{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_iiexpr_func_sqrtr #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiiSqrtR{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_inv #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintInv{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_flexpr_func_inv #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\XINTinFloatInv{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_round #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:expr:tacitzeroifonearg + \romannumeral`&&@\XINT_expr_unlock #3,,!\xintiRound\xintRound + \endcsname +}% +\let\XINT_flexpr_func_round\XINT_expr_func_round +\def\XINT_iiexpr_func_round #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:iiexpr:tacitzeroifonearg + \romannumeral`&&@\XINT_expr_unlock #3,,!\xintiRound + \endcsname +}% +\def\XINT_expr_func_trunc #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:expr:tacitzeroifonearg + \romannumeral`&&@\XINT_expr_unlock #3,,!\xintiTrunc\xintTrunc + \endcsname +}% +\let\XINT_flexpr_func_trunc\XINT_expr_func_trunc +\def\XINT_iiexpr_func_trunc #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:iiexpr:tacitzeroifonearg + \romannumeral`&&@\XINT_expr_unlock #3,,!\xintiTrunc + \endcsname +}% +% \end{macrocode} +% \lverb|Hesitation at 1.3e about using \XINTinFloatSdigits and \XINTinFloatS. +% Finally I add a sfloat() function. It helps for xinttrig.sty.| +% \begin{macrocode} +\def\XINT_expr_func_float #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:expr:one:and:opt + \romannumeral`&&@\XINT_expr_unlock #3,,!\XINTinFloatdigits\XINTinFloat + \endcsname +}% +\let\XINT_flexpr_func_float\XINT_expr_func_float +\def\XINT_expr_func_sfloat #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:expr:one:and:opt + \romannumeral`&&@\XINT_expr_unlock #3,,!\XINTinFloatSdigits\XINTinFloatS + \endcsname +}% +\let\XINT_flexpr_func_sfloat\XINT_expr_func_sfloat +% \XINT_iiexpr_func_sfloat not defined +\expandafter\def\csname XINT_expr_func_ilog10\endcsname #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:expr:one:and:opt + \romannumeral`&&@\XINT_expr_unlock #3,,!\xintiLogTen\XINTFloatiLogTen + \endcsname +}% +\expandafter\def\csname XINT_flexpr_func_ilog10\endcsname #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:expr:one:and:opt + \romannumeral`&&@\XINT_expr_unlock #3,,!\XINTFloatiLogTendigits\XINTFloatiLogTen + \endcsname +}% +\expandafter\def\csname XINT_iiexpr_func_ilog10\endcsname #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintiiLogTen{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_divmod #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:expr:two:to:two + \romannumeral`&&@\XINT_expr_unlock #3,!\xintDivMod + \endcsname +}% +% \end{macrocode} +% \lverb|\XINTinFloatDivMod a un output déjà comma separated| +% \begin{macrocode} +\def\XINT_flexpr_func_divmod #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\XINTinFloatDivMod + \endcsname +}% +\def\XINT_iiexpr_func_divmod #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:expr:two:to:two + \romannumeral`&&@\XINT_expr_unlock #3,!\xintiiDivMod + \endcsname +}% +\def\XINT_expr_func_mod #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\xintMod + \endcsname +}% +\def\XINT_flexpr_func_mod #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\XINTinFloatMod + \endcsname +}% +\def\XINT_iiexpr_func_mod #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\xintiiMod + \endcsname +}% +\def\XINT_expr_func_binomial #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\xintBinomial + \endcsname +}% +\def\XINT_flexpr_func_binomial #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\XINTinFloatBinomial + \endcsname +}% +\def\XINT_iiexpr_func_binomial #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\xintiiBinomial + \endcsname +}% +\def\XINT_expr_func_pfactorial #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\xintPFactorial + \endcsname +}% +\def\XINT_flexpr_func_pfactorial #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\XINTinFloatPFactorial + \endcsname +}% +\def\XINT_iiexpr_func_pfactorial #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\xintiiPFactorial + \endcsname +}% +\def\XINT_expr_func_randrange #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:expr:randrange + \romannumeral`&&@\XINT_expr_unlock #3,,!% + \endcsname +}% +\let\XINT_flexpr_func_randrange\XINT_expr_func_randrange +\def\XINT_iiexpr_func_randrange #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:iiexpr:randrange + \romannumeral`&&@\XINT_expr_unlock #3,,!% + \endcsname +}% +\def\XINT:expr:randrange #1,#2,#3!% +{% + \if\relax#3\relax\expandafter\xint_firstoftwo\else + \expandafter\xint_secondoftwo\fi + {\xintiiRandRange{\XINT:NEhook:one\xintNum{#1}}}% + {\xintiiRandRangeAtoB{\XINT:NEhook:one\xintNum{#1}}% + {\XINT:NEhook:one\xintNum{#2}}}% +}% +\def\XINT:iiexpr:randrange #1,#2,#3!% +{% + \if\relax#3\relax\expandafter\xint_firstoftwo\else + \expandafter\xint_secondoftwo\fi + {\xintiiRandRange{#1}}{\xintiiRandRangeAtoB{#1}{#2}}% +}% +\def\XINT_expr_func_quo #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\xintiQuo + \endcsname +}% +\let\XINT_flexpr_func_quo\XINT_expr_func_quo +\def\XINT_iiexpr_func_quo #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\xintiiQuo + \endcsname +}% +\def\XINT_expr_func_rem #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\xintiRem + \endcsname +}% +\let\XINT_flexpr_func_rem\XINT_expr_func_rem +\def\XINT_iiexpr_func_rem #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\xintiiRem + \endcsname +}% +\def\XINT_expr_func_gcd #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintGCDof:csv{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_gcd\XINT_expr_func_gcd +\def\XINT_iiexpr_func_gcd #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintiiGCDof:csv{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_lcm #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintLCMof:csv{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_lcm\XINT_expr_func_lcm +\def\XINT_iiexpr_func_lcm #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintiiLCMof:csv{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_max #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintMaxof:csv{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_iiexpr_func_max #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintiiMaxof:csv{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_flexpr_func_max #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\XINTinFloatMaxof:csv{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_min #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintMinof:csv{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_iiexpr_func_min #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintiiMinof:csv{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_flexpr_func_min #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\XINTinFloatMinof:csv{\XINT_expr_unlock #3}\endcsname +}% +\expandafter +\def\csname XINT_expr_func_+\endcsname #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintSum:csv{\XINT_expr_unlock #3}\endcsname +}% +\expandafter +\def\csname XINT_flexpr_func_+\endcsname #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\XINTinFloatSum:csv{\XINT_expr_unlock #3}\endcsname +}% +\expandafter +\def\csname XINT_iiexpr_func_+\endcsname #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintiiSum:csv{\XINT_expr_unlock #3}\endcsname +}% +\expandafter +\def\csname XINT_expr_func_*\endcsname #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintPrd:csv{\XINT_expr_unlock #3}\endcsname +}% +\expandafter +\def\csname XINT_flexpr_func_*\endcsname #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\XINTinFloatPrd:csv{\XINT_expr_unlock #3}\endcsname +}% +\expandafter +\def\csname XINT_iiexpr_func_*\endcsname #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintiiPrd:csv{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_all #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintANDof:csv{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_all\XINT_expr_func_all +\let\XINT_iiexpr_func_all\XINT_expr_func_all +\def\XINT_expr_func_any #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintORof:csv{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_any\XINT_expr_func_any +\let\XINT_iiexpr_func_any\XINT_expr_func_any +\def\XINT_expr_func_xor #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintXORof:csv{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_xor\XINT_expr_func_xor +\let\XINT_iiexpr_func_xor\XINT_expr_func_xor +\def\XINT_expr_func_len #1#2#3% +{% + \expandafter#1\expandafter#2\csname.=% + \XINT:NEhook:csv\xintLength:f:csv{\XINT_expr_unlock#3}\endcsname +}% +\let\XINT_flexpr_func_len \XINT_expr_func_len +\let\XINT_iiexpr_func_len \XINT_expr_func_len +% \end{macrocode} +% \lverb|1.2k has \xintFirstItem:f:csv for improved +% \xintNewExpr compatibility.| +% \begin{macrocode} +\def\XINT_expr_func_first #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintFirstItem:f:csv{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_first\XINT_expr_func_first +\let\XINT_iiexpr_func_first\XINT_expr_func_first +% \end{macrocode} +% \lverb|1.2k has \xintLastItem:f:csv for efficiency and improved +% \xintNewExpr compatibility.| +% \begin{macrocode} +\def\XINT_expr_func_last #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintLastItem:f:csv{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_last\XINT_expr_func_last +\let\XINT_iiexpr_func_last\XINT_expr_func_last +% \end{macrocode} +% \lverb|1.2c I hesitated but left the function "reversed" from 1.1 with +% this name, not "reverse". But the inner not public macro got renamed +% into \xintReverse::csv. 1.2g opts for the name \xintReverse:f:csv, and +% rewrites it for direct handling of csv lists. 2016/03/17.| +% \begin{macrocode} +\def\XINT_expr_func_reversed #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:csv\xintReverse:f:csv{\XINT_expr_unlock #3}\endcsname +}% +\let\XINT_flexpr_func_reversed\XINT_expr_func_reversed +\let\XINT_iiexpr_func_reversed\XINT_expr_func_reversed +\def\xintiiifNotZero: #1,#2,#3,{\xintiiifNotZero{#1}{#2}{#3}}% +\def\XINT_expr_func_if #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\xintiiifNotZero:% + \romannumeral`&&@\XINT_expr_unlock #3,\endcsname +}% +\let\XINT_flexpr_func_if\XINT_expr_func_if +\let\XINT_iiexpr_func_if\XINT_expr_func_if +\def\xintifInt: #1,#2,#3,{\xintifInt{#1}{#2}{#3}}% +\def\XINT_expr_func_ifint #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\xintifInt:% + \romannumeral`&&@\XINT_expr_unlock #3,\endcsname +}% +\let\XINT_iiexpr_func_ifint\XINT_expr_func_ifint +\def\xintifFloatInt: #1,#2,#3,{\xintifFloatInt{#1}{#2}{#3}}% +\def\XINT_flexpr_func_ifint #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\xintifFloatInt:% + \romannumeral`&&@\XINT_expr_unlock #3,\endcsname +}% +\def\xintifOne: #1,#2,#3,{\xintifOne{#1}{#2}{#3}}% +\def\XINT_expr_func_ifone #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\xintifOne:% + \romannumeral`&&@\XINT_expr_unlock #3,\endcsname +}% +\let\XINT_flexpr_func_ifone\XINT_expr_func_ifone +\def\xintiiifOne: #1,#2,#3,{\xintiiifOne{#1}{#2}{#3}}% +\def\XINT_iiexpr_func_ifone #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\xintiiifOne:% + \romannumeral`&&@\XINT_expr_unlock #3,\endcsname +}% +\def\xintiiifSgn: #1,#2,#3,#4,{\xintiiifSgn{#1}{#2}{#3}{#4}}% +\def\XINT_expr_func_ifsgn #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\xintiiifSgn:% + \romannumeral`&&@\XINT_expr_unlock #3,\endcsname +}% +\let\XINT_flexpr_func_ifsgn\XINT_expr_func_ifsgn +\let\XINT_iiexpr_func_ifsgn\XINT_expr_func_ifsgn +% \end{macrocode} +% \subsection{f-expandable versions of the \cshnolabel{xintSeqB::csv} and alike +% routines, for \cshnolabel{xintNewExpr}} +% \localtableofcontents +% \subsubsection{\csh{xintSeqB:f:csv}} +% \lverb|Produces in f-expandable way. If the step is zero, gives empty result +% except if start and end coincide.| +% \begin{macrocode} +\def\xintSeqB:f:csv #1#2% + {\expandafter\XINT_seqb:f:csv \expandafter{\romannumeral0\xintraw{#2}}{#1}}% +\def\XINT_seqb:f:csv #1#2{\expandafter\XINT_seqb:f:csv_a\romannumeral`&&@#2#1!}% +\def\XINT_seqb:f:csv_a #1#2;#3;#4!{% + \expandafter\xint_gobble_i\romannumeral`&&@% + \xintifCmp {#3}{#4}\XINT_seqb:f:csv_bl\XINT_seqb:f:csv_be\XINT_seqb:f:csv_bg + #1{#3}{#4}{}{#2}}% +\def\XINT_seqb:f:csv_be #1#2#3#4#5{,#2}% +\def\XINT_seqb:f:csv_bl #1{\if #1p\expandafter\XINT_seqb:f:csv_pa\else + \xint_afterfi{\expandafter,\xint_gobble_iv}\fi }% +\def\XINT_seqb:f:csv_pa #1#2#3#4{\expandafter\XINT_seqb:f:csv_p\expandafter + {\romannumeral0\xintadd{#4}{#1}}{#2}{#3,#1}{#4}}% +\def\XINT_seqb:f:csv_p #1#2% +{% + \xintifCmp {#1}{#2}\XINT_seqb:f:csv_pa\XINT_seqb:f:csv_pb\XINT_seqb:f:csv_pc + {#1}{#2}% +}% +\def\XINT_seqb:f:csv_pb #1#2#3#4{#3,#1}% +\def\XINT_seqb:f:csv_pc #1#2#3#4{#3}% +\def\XINT_seqb:f:csv_bg #1{\if #1n\expandafter\XINT_seqb:f:csv_na\else + \xint_afterfi{\expandafter,\xint_gobble_iv}\fi }% +\def\XINT_seqb:f:csv_na #1#2#3#4{\expandafter\XINT_seqb:f:csv_n\expandafter + {\romannumeral0\xintadd{#4}{#1}}{#2}{#3,#1}{#4}}% +\def\XINT_seqb:f:csv_n #1#2% +{% + \xintifCmp {#1}{#2}\XINT_seqb:f:csv_nc\XINT_seqb:f:csv_nb\XINT_seqb:f:csv_na + {#1}{#2}% +}% +\def\XINT_seqb:f:csv_nb #1#2#3#4{#3,#1}% +\def\XINT_seqb:f:csv_nc #1#2#3#4{#3}% +% \end{macrocode} +%\subsubsection{\csh{xintiiSeqB:f:csv}} +% \lverb|Produces in f-expandable way. If the step is zero, gives empty result +% except if start and end coincide. +% +% 2015/11/11. I correct a typo dating back to release 1.1 (2014/10/29): the +% macro name had a "b" rather than "B", hence was not functional (causing +% \xintNewIIExpr to fail on inputs such as #1..[1]..#2).| +% \begin{macrocode} +\def\xintiiSeqB:f:csv #1#2% + {\expandafter\XINT_iiseqb:f:csv \expandafter{\romannumeral`&&@#2}{#1}}% +\def\XINT_iiseqb:f:csv #1#2{\expandafter\XINT_iiseqb:f:csv_a\romannumeral`&&@#2#1!}% +\def\XINT_iiseqb:f:csv_a #1#2;#3;#4!{% + \expandafter\xint_gobble_i\romannumeral`&&@% + \xintSgnFork{\XINT_Cmp {#3}{#4}}% + \XINT_iiseqb:f:csv_bl\XINT_seqb:f:csv_be\XINT_iiseqb:f:csv_bg + #1{#3}{#4}{}{#2}}% +\def\XINT_iiseqb:f:csv_bl #1{\if #1p\expandafter\XINT_iiseqb:f:csv_pa\else + \xint_afterfi{\expandafter,\xint_gobble_iv}\fi }% +\def\XINT_iiseqb:f:csv_pa #1#2#3#4{\expandafter\XINT_iiseqb:f:csv_p\expandafter + {\romannumeral0\xintiiadd{#4}{#1}}{#2}{#3,#1}{#4}}% +\def\XINT_iiseqb:f:csv_p #1#2% +{% + \xintSgnFork{\XINT_Cmp {#1}{#2}}% + \XINT_iiseqb:f:csv_pa\XINT_iiseqb:f:csv_pb\XINT_iiseqb:f:csv_pc {#1}{#2}% +}% +\def\XINT_iiseqb:f:csv_pb #1#2#3#4{#3,#1}% +\def\XINT_iiseqb:f:csv_pc #1#2#3#4{#3}% +\def\XINT_iiseqb:f:csv_bg #1{\if #1n\expandafter\XINT_iiseqb:f:csv_na\else + \xint_afterfi{\expandafter,\xint_gobble_iv}\fi }% +\def\XINT_iiseqb:f:csv_na #1#2#3#4{\expandafter\XINT_iiseqb:f:csv_n\expandafter + {\romannumeral0\xintiiadd{#4}{#1}}{#2}{#3,#1}{#4}}% +\def\XINT_iiseqb:f:csv_n #1#2% +{% + \xintSgnFork{\XINT_Cmp {#1}{#2}}% + \XINT_seqb:f:csv_nc\XINT_seqb:f:csv_nb\XINT_iiseqb:f:csv_na {#1}{#2}% +}% +% \end{macrocode} +%\subsubsection{\csh{XINTinFloatSeqB:f:csv}} +% \lverb|Produces in f-expandable way. If the step is zero, gives empty result +% except if start and end coincide. This is all for \xintNewExpr.| +% \begin{macrocode} +\def\XINTinFloatSeqB:f:csv #1#2{\expandafter\XINT_flseqb:f:csv \expandafter + {\romannumeral0\XINTinfloat [\XINTdigits]{#2}}{#1}}% +\def\XINT_flseqb:f:csv #1#2{\expandafter\XINT_flseqb:f:csv_a\romannumeral`&&@#2#1!}% +\def\XINT_flseqb:f:csv_a #1#2;#3;#4!{% + \expandafter\xint_gobble_i\romannumeral`&&@% + \xintifCmp {#3}{#4}\XINT_flseqb:f:csv_bl\XINT_seqb:f:csv_be\XINT_flseqb:f:csv_bg + #1{#3}{#4}{}{#2}}% +\def\XINT_flseqb:f:csv_bl #1{\if #1p\expandafter\XINT_flseqb:f:csv_pa\else + \xint_afterfi{\expandafter,\xint_gobble_iv}\fi }% +\def\XINT_flseqb:f:csv_pa #1#2#3#4{\expandafter\XINT_flseqb:f:csv_p\expandafter + {\romannumeral0\XINTinfloatadd{#4}{#1}}{#2}{#3,#1}{#4}}% +\def\XINT_flseqb:f:csv_p #1#2% +{% + \xintifCmp {#1}{#2}% + \XINT_flseqb:f:csv_pa\XINT_flseqb:f:csv_pb\XINT_flseqb:f:csv_pc {#1}{#2}% +}% +\def\XINT_flseqb:f:csv_pb #1#2#3#4{#3,#1}% +\def\XINT_flseqb:f:csv_pc #1#2#3#4{#3}% +\def\XINT_flseqb:f:csv_bg #1{\if #1n\expandafter\XINT_flseqb:f:csv_na\else + \xint_afterfi{\expandafter,\xint_gobble_iv}\fi }% +\def\XINT_flseqb:f:csv_na #1#2#3#4{\expandafter\XINT_flseqb:f:csv_n\expandafter + {\romannumeral0\XINTinfloatadd{#4}{#1}}{#2}{#3,#1}{#4}}% +\def\XINT_flseqb:f:csv_n #1#2% +{% + \xintifCmp {#1}{#2}% + \XINT_seqb:f:csv_nc\XINT_seqb:f:csv_nb\XINT_flseqb:f:csv_na {#1}{#2}% +}% +% \end{macrocode} +% \subsection{\csh{xintdeffunc}, \csh{xintdefiifunc}, +% \csh{xintdeffloatfunc}} +% +% \changed{1.2c}{2015/11/12} +% \lverb|Note: it is possible to have same name assigned both to a variable +% and a function: things such as add(f(f), f=1..10) are possible.| +% +% \changed{1.2f}{2016/03/08} +% \lverb|Comma separated expressions allowed (formerly this required using +% parenthesis \xintdeffunc foo(x,..):=(.., .., ..);| +% +% \changed{1.3c}{2018/06/17} +% \lverb|Usage of \xintexprSafeCatcodes to be compatible with an active +% semi-colon at time of use; the colon was not a problem (see ##3) already.| +% +% \begin{macrocode} +\def\XINT_tmpa #1#2#3#4% +{% + \def #1##1(##2)##3=##4;{% + \edef\XINT_deffunc_tmpa {##1}% + \edef\XINT_deffunc_tmpa {\xint_zapspaces_o \XINT_deffunc_tmpa}% + \def\XINT_deffunc_tmpb {0}% + \def\XINT_deffunc_tmpc {(##4)}% + \edef\XINT_deffunc_tmpd {##2}% + \ifnum\xintLength:f:csv{\XINT_deffunc_tmpd}>\xint_c_ + \xintFor ####1 in {\XINT_deffunc_tmpd}\do + {\edef\XINT_deffunc_tmpb {\the\numexpr\XINT_deffunc_tmpb+\xint_c_i}% + \edef\XINT_deffunc_tmpc {subs(\unexpanded\expandafter{\XINT_deffunc_tmpc},% + ####1=################\XINT_deffunc_tmpb)}% + }% + \fi +% \end{macrocode} +% \lverb|Something like this must be done before the NewFunc, else recursive +% definitions are impossible as the function will be unknown.| +% \begin{macrocode} + \ifnum\XINT_deffunc_tmpb=\xint_c_ + \expandafter\XINT_expr_defuserfunc_none\csname + \else + \expandafter\XINT_expr_defuserfunc\csname + \fi + XINT_#2_func_\XINT_deffunc_tmpa\expandafter\endcsname + \expandafter{\XINT_deffunc_tmpa}{#2}% + \expandafter#3\csname XINT_#2_userfunc_\XINT_deffunc_tmpa\endcsname + [\XINT_deffunc_tmpb]{\XINT_deffunc_tmpc}% + \ifxintverbose\xintMessage {xintexpr}{Info} + {Function \XINT_deffunc_tmpa\space for \string\xint #4 parser + associated to \string\XINT_#2_userfunc_\XINT_deffunc_tmpa\space + with \ifxintglobaldefs global \fi meaning \expandafter\meaning + \csname XINT_#2_userfunc_\XINT_deffunc_tmpa\endcsname}% + \fi + \xintexprRestoreCatcodes + }% +}% +\def\xintdeffunc {\xintexprSafeCatcodes\xintdeffunc_a}% +\def\xintdefiifunc {\xintexprSafeCatcodes\xintdefiifunc_a}% +\def\xintdeffloatfunc {\xintexprSafeCatcodes\xintdeffloatfunc_a}% +\XINT_tmpa\xintdeffunc_a {expr} \XINT_NewFunc {expr}% +\XINT_tmpa\xintdefiifunc_a {iiexpr}\XINT_NewIIFunc {iiexpr}% +\XINT_tmpa\xintdeffloatfunc_a{flexpr}\XINT_NewFloatFunc{floatexpr}% +\def\XINT_expr_defuserfunc #1#2#3% +{% + \XINT_global + \def #1##1##2##3{\expandafter ##1\expandafter ##2% + \csname.=\XINT:expr:userfunc{#3}{#2}{\XINT_expr_unlock ##3}\endcsname + }% +}% +\def\XINT:expr:userfunc #1#2#3% +{% + \csname XINT_#1_userfunc_#2\expandafter\endcsname + \romannumeral0\xintcsvtolistnonstripped{#3}% +}% +\def\XINT_expr_defuserfunc_none #1#2#3% +{% + \XINT_global + \def #1##1##2##3{\expandafter ##1\expandafter ##2% + \csname.=\XINT:expr:userfunc:none{#3}{#2}\endcsname + }% +}% +\def\XINT:expr:userfunc:none #1#2{\csname XINT_#1_userfunc_#2\endcsname}% +% \end{macrocode} +% \subsection{\csh{xintdefefunc}, \csh{xintdefiiefunc}, \csh{xintdeffloatefunc}} +% \lverb|Added at 1.3e. Please consider the whole business of \xintdeffunc, +% \xintdefefunc, \xintNewExpr as somewhat like a work in progress, it is +% complex indeed.| +% \begin{macrocode} +\def\XINT_tmpa #1#2#3#4% +{% + \def #1##1(##2)##3=##4;{% + \edef\XINT_defefunc_tmpa {##1}% + \edef\XINT_defefunc_tmpa {\xint_zapspaces_o \XINT_defefunc_tmpa}% + \def\XINT_defefunc_tmpb {0}% + \def\XINT_defefunc_tmpc {(##4)}% + \edef\XINT_defefunc_tmpd {##2}% + \ifnum\xintLength:f:csv{\XINT_defefunc_tmpd}>\xint_c_ + \xintFor ####1 in {\XINT_defefunc_tmpd}\do + {\edef\XINT_defefunc_tmpb {\the\numexpr\XINT_defefunc_tmpb+\xint_c_i}% + \edef\XINT_defefunc_tmpc {subs(\unexpanded\expandafter{\XINT_defefunc_tmpc},% + ####1=################\XINT_defefunc_tmpb)}% + }% + \fi +% \end{macrocode} +% \lverb|No recursivity allowed here with the function to be defined.| +% \begin{macrocode} + \expandafter#3\csname XINT_#2_userefunc_\XINT_defefunc_tmpa\endcsname + [\XINT_defefunc_tmpb]{\XINT_defefunc_tmpc}% + \edef\XINT_defefunc_tmpd{\xintLength:f:csv + {\expandafter\meaning\csname + XINT_#2_userfunc_\XINT_defefunc_tmpa\endcsname}}% +% \end{macrocode} +% \lverb|We try to distinguish wheter the function is supposed to deliver only +% one value or more than two. And we separate the cases of 0, 1 or 2 variables +% which can be set-up a bit better for usage in other definitions, in +% generator environments. But there are many shortcomings. I don't have a very +% clear view of all the complex situation, in fact. +% | +% \begin{macrocode} + \ifcase\XINT_defefunc_tmpb\space + \expandafter\XINT_expr_defuserefunc_none\csname + \or +% \ifnum\XINT_defefunc_tmpd=\xint_c_i + \expandafter\XINT_expr_defuserefunc_one\csname +% \else +% \expandafter\XINT_expr_defuserefunc_onetocsv\csname +% \fi + \or +% \ifnum\XINT_defefunc_tmpd=\xint_c_i + \expandafter\XINT_expr_defuserefunc_two\csname +% \else +% \expandafter\XINT_expr_defuserefunc_twotocsv\csname +% \fi + \else +% \ifnum\XINT_defefunc_tmpd=\xint_c_i + \expandafter\XINT_expr_defuserefunc_many\csname +% \else +% \expandafter\XINT_expr_defuserefunc_manytocsv\csname +% \fi + \fi + XINT_#2_func_\XINT_defefunc_tmpa\expandafter\endcsname + \expandafter{\XINT_defefunc_tmpa}{#2}% + \ifxintverbose\xintMessage {xintexpr}{Info} + {Function \XINT_defefunc_tmpa\space for \string\xint #4 parser + associated to \string\XINT_#2_userefunc_\XINT_defefunc_tmpa\space + with \ifxintglobaldefs global \fi meaning \expandafter\meaning + \csname XINT_#2_userefunc_\XINT_defefunc_tmpa\endcsname}% + \fi + \xintexprRestoreCatcodes + }% +}% +\def\xintdefefunc {\xintexprSafeCatcodes\xintdefefunc_a}% +\def\xintdefiiefunc {\xintexprSafeCatcodes\xintdefiiefunc_a}% +\def\xintdeffloatefunc {\xintexprSafeCatcodes\xintdeffloatefunc_a}% +\XINT_tmpa\xintdefefunc_a {expr} \XINT_NewFunc {expr}% +\XINT_tmpa\xintdefiiefunc_a {iiexpr}\XINT_NewIIFunc {iiexpr}% +\XINT_tmpa\xintdeffloatefunc_a{flexpr}\XINT_NewFloatFunc{floatexpr}% +\def\XINT_expr_defuserefunc_none #1#2#3% +{% + \expandafter\XINT_expr_defuserefunc_none_a + \csname XINT_#3_userefunc_#2\endcsname +}% +\def\XINT_expr_defuserefunc_none_a #1#2% +{% + \XINT_global + \def #2##1##2##3{\expandafter ##1\expandafter ##2\csname.=#1\endcsname}% +}% +% \end{macrocode} +% \lverb|Je définis une macro auxiliaire qui fait l'expansion mais tout cela +% pour éviter le très léger overhead de \xintExpandArgs... c'est idiot et le +% devient encore plus pour deux arguments. Mais c'est aussi dû à +% \xintApply::csv que l'on veut utiliser commodément +% dans \XINT:NE:userefunc:one_a.| +% \begin{macrocode} +\def\XINT_expr_defuserefunc_one #1#2#3% +{% + \expandafter\XINT_expr_defuserefunc_one_a + \csname XINT_#3_userefunc_#2\expandafter\endcsname + \csname XINT_#3_userefunc:f_#2\endcsname #1{#2}{#3}% +}% +\def\XINT_expr_defuserefunc_one_a #1#2#3#4#5% +{% + \XINT_global + \def #2##1{\expandafter#1\expandafter{\romannumeral`&&@##1}}% + \XINT_global + \def #3##1##2##3% + {% + \expandafter ##1\expandafter ##2% + \csname.=\XINT:expr:userefunc:one{#5}{#4}{\XINT_expr_unlock##3}\endcsname + }% +}% +\def\XINT:expr:userefunc:one #1#2#3% +{% + \csname XINT_#1_userefunc_#2\expandafter\endcsname\expandafter + {\romannumeral`&&@#3}% +}% +\def\XINT_expr_defuserefunc_two #1#2#3% +{% + \expandafter\XINT_expr_defuserefunc_two_a + \csname XINT_#3_userefunc:f_#2\endcsname #1{#2}{#3}% +}% +% \end{macrocode} +% \lverb|Le fait que \xintExpandArgs demande que les arguments sont regroupés +% explique pourquoi plus bas j'ai dû faire \XINT:NE:userefunc:two. +% +% \xintExpandArgs#1{{##1}{##2}} +% +% Mais bon finalement je rajouter encore un helper d'expansion. Que j'ai +% peut-être d'ailleurs déjà... C'est un peu de l'abus la macro auxiliaire +% userefunc:f pour chaque userefunc, mais je dois gérer le problème que les +% noms de macros ici peuvent contenir des chiffres. +% +% Il y a de la perte dans le grabbing de l'argument qui aura lieu et qu'on +% pourrait optimiser, mais je commence à sérieusement fatiguer pour 1.3e.| +% \begin{macrocode} +\def\XINT_expr_defuserefunc_two_a #1#2#3#4% +{% + \XINT_global + \def #1##1##2{\xintExpandArgs{XINT_#4_userefunc_#3}{{##1}{##2}}}% + \XINT_global + \def #2##1##2##3% + {% + \expandafter ##1\expandafter ##2% + \csname.=\XINT:expr:userefunc:two{#4}{#3}{\XINT_expr_unlock##3}\endcsname + }% +}% +\def\XINT:expr:userefunc:two #1#2#3% +{% + \expandafter\XINT:expr:userefunc:two_a + \csname XINT_#1_userefunc_#2\expandafter\endcsname + \romannumeral`&&@#3,% +}% +\def\XINT:expr:userefunc:two_a #1#2,#3,{#1{#2}{#3}}% +% \end{macrocode} +% \lverb|Paradoxically the general case is code faster. But this is explained +% because we try to hook into special handlers for one or two variables (see +% "Mysterious stuff" subsection in NewExpr.| +% \begin{macrocode} +\def\XINT_expr_defuserefunc_many #1#2#3% +{% + \XINT_global + \def #1##1##2##3% + {% + \expandafter ##1\expandafter ##2% + \csname.=\XINT:expr:userefunc{#3}{#2}{\XINT_expr_unlock##3}\endcsname + }% +}% +\def\XINT:expr:userefunc #1#2#3% +{% + \csname XINT_#1_userefunc_#2\expandafter\endcsname + \romannumeral0\xintcsvtolistnonstripped{#3}% +}% +% \end{macrocode} +% \subsection{\csh{xintunassignexprfunc}, \csh{xintunassigniiexprfunc}, \csh{xintunassignfloatexprfunc}} +% See the \csbxint{unassignvar} for the embarrassing explanations why I had +% not done that earlier. A bit lazy here, no warning if undefining something +% not defined, and attention no precaution respective built-in functions. +% \begin{macrocode} +\def\XINT_tmpa #1{\expandafter\def\csname xintunassign#1func\endcsname ##1{% + \edef\XINT_unfunc_tmpa{##1}% + \edef\XINT_unfunc_tmpa {\xint_zapspaces_o\XINT_unfunc_tmpa}% + \XINT_global\expandafter + \let\csname XINT_#1_func_\XINT_unfunc_tmpa\endcsname\xint_undefined + \XINT_global\expandafter + \let\csname XINT_#1_userfunc_\XINT_unfunc_tmpa\endcsname\xint_undefined + \XINT_global\expandafter + \let\csname XINT_#1_userefunc_\XINT_unfunc_tmpa\endcsname\xint_undefined + \ifxintverbose\xintMessage {xintexpr}{Info} + {Function \XINT_unfunc_tmpa\space for \string\xint #1 parser now + \ifxintglobaldefs globally \fi undefined.}% + \fi}}% +\XINT_tmpa{expr}\XINT_tmpa{iiexpr}\XINT_tmpa{floatexpr}% +% \end{macrocode} +% \subsection{\csh{xintNewFunction}} +% \lverb|1.2h (2016/11/20). Syntax is \xintNewFunction{<name>}[nb of +% arguments]{expression with #1, #2,... as in \xintNewExpr}. This defines +% a function for all three parsers but the expression parsing is delayed until +% function execution. Hence the expression admits all constructs, contrarily +% to \xintNewExpr or \xintdeffunc. +% +% | +% \begin{macrocode} +\def\XINT_expr_wrapit #1{\expandafter\XINT_expr_wrap\csname.=#1\endcsname}% +\def\xintNewFunction #1#2[#3]#4% +{% + \edef\XINT_newfunc_tmpa {#1}% + \edef\XINT_newfunc_tmpa {\xint_zapspaces_o \XINT_newfunc_tmpa}% + \def\XINT_newfunc_tmpb ##1##2##3##4##5##6##7##8##9{#4}% + \begingroup + \ifcase #3\relax + \toks0{}% + \or \toks0{##1}% + \or \toks0{##1##2}% + \or \toks0{##1##2##3}% + \or \toks0{##1##2##3##4}% + \or \toks0{##1##2##3##4##5}% + \or \toks0{##1##2##3##4##5##6}% + \or \toks0{##1##2##3##4##5##6##7}% + \or \toks0{##1##2##3##4##5##6##7##8}% + \else \toks0{##1##2##3##4##5##6##7##8##9}% + \fi + \expandafter + \endgroup\expandafter + \XINT_global\expandafter + \def\csname XINT_expr_macrofunc_\XINT_newfunc_tmpa\expandafter\endcsname + \the\toks0\expandafter{\XINT_newfunc_tmpb + {\XINT_expr_wrapit{##1}}{\XINT_expr_wrapit{##2}}{\XINT_expr_wrapit{##3}}% + {\XINT_expr_wrapit{##4}}{\XINT_expr_wrapit{##5}}{\XINT_expr_wrapit{##6}}% + {\XINT_expr_wrapit{##7}}{\XINT_expr_wrapit{##8}}{\XINT_expr_wrapit{##9}}}% + \expandafter\XINT_expr_newfunction + \csname XINT_expr_func_\XINT_newfunc_tmpa\expandafter\endcsname + \expandafter{\XINT_newfunc_tmpa}{eval}\xintbareeval + \expandafter\XINT_expr_newfunction + \csname XINT_iiexpr_func_\XINT_newfunc_tmpa\expandafter\endcsname + \expandafter{\XINT_newfunc_tmpa}{iieval}\xintbareiieval + \expandafter\XINT_expr_newfunction + \csname XINT_flexpr_func_\XINT_newfunc_tmpa\expandafter\endcsname + \expandafter{\XINT_newfunc_tmpa}{floateval}\xintbarefloateval + \ifxintverbose + \xintMessage {xintexpr}{Info} + {Function \XINT_newfunc_tmpa\space for the expression parsers is + associated to \string\XINT_expr_macrofunc_\XINT_newfunc_tmpa\space + with \ifxintglobaldefs global \fi meaning \expandafter\meaning + \csname XINT_expr_macrofunc_\XINT_newfunc_tmpa\endcsname}% + \fi +}% +\def\XINT_expr_newfunction #1#2#3#4% +{% + \XINT_global + \def#1##1##2##3{\expandafter ##1\expandafter ##2\romannumeral0% + \XINT:expr:macrofunc{#4}{#3}{#2}{\XINT_expr_unlock##3}}% +}% +\def\XINT:expr:macrofunc #1#2#3#4% +{% + #1\csname XINT_expr_macrofunc_#3\expandafter\endcsname + \romannumeral0\xintcsvtolistnonstripped{#4}\relax +}% +\catcode`~ 12 +\def\XINT:newexpr:macrofunc #1{% +\def\XINT:newexpr:macrofunc ##1##2##3##4% +{% + \expandafter#1\csname.=~XINT:newexpr:macrofunc:a{##2}{##3}% + {\xintCSVtoListNonStripped{##4}}\endcsname +}% +}\XINT:newexpr:macrofunc { }% +\catcode`~ 3 +\def\XINT:newexpr:macrofunc:a #1#2#3% +{% + \expandafter\XINT_expr_unlock\romannumeral0\csname xintbare#1\endcsname + \csname XINT_expr_macrofunc_#2\endcsname#3\relax +}% +% \end{macrocode} +% \subsection{\csh{xintNewExpr}, \csh{xintNewIExpr}, \csh{xintNewFloatExpr}, +% \csh{xintNewIIExpr}} +% \localtableofcontents +% \lverb|& +% There was an \xintNewExpr already in 1.07 from May 2013, which was +% modified in September 2013 to work with the # macro parameter character, +% and then refactored into a more powerful version in June 2014 for 1.1 +% release of 2014/10/28. List handling causes special +% challenges, addressed by \xintApply::csv, \xintApply:::csv, ... next. +% +% Comments finally added 2015/12/11 (with later edits): +% +% The whole point is to expand completely macros when they have only numerical +% arguments and to inhibit this expansion if not. This is done in a recursive +% way: the catcode 12 ~ is used to register a macro name whose expansion must +% be inhibited. Any argument itself starting with such a ~ will +% force use of ~ for the macro which receives it. +% +% In this context the catcode 12 $$ is used to signal a "virtual +% list" argument. It triggers insertion of \xintApply::csv or +% \xintApply:::csv for delayed handling later. This succeeds into handling +% inputs such as [#1..[#2]..#3][#4:#5]... +% +% A final +% \scantokens converts the "~" prefixed names into real control sequences. +% +% For this whole mechanism we need to have everything expressed using +% exclusively f-expandable macros. We avoid \csname...\endcsname like +% construct, but if absolutely needed perhaps we will do it ultimately. +% +% For the iterating loops seq, iter, etc..., and dummy variables, we have no +% macros to our disposal to handle the case where the list +% of indices is not explicit. Moreover omit, abort, break can not work with +% non numerical data. Thus the whole mechanism is currently not appicable to +% them. It does work when the macro parameters (or variables for \xintdeffunc) +% do not intervene in the list of values to iterate over. But we can not delay +% expansion of dummy variables. +% +% Comments added 2018/02/28: +% +% At 1.3 of February 2018, there was important refactoring. Earlier, +% \XINT_expr_redefinemacros was a very big macro which made aliases of the +% dozens of macros (most from xintfrac and some defined especially by xintexpr +% for acting on csv lists primarily) involved in the expression rendering and +% then redefined them all to expand to their original selves only when applied +% to purely numeric arguments. At 1.3 only very few such re-definitions are +% made, as what is redefined are a limited number of core wrapper macros. +% +% Only when the original macros have one or two arguments is it examined if +% they can expand immediately (this includes case of function having possibly +% only one, or possibly two arguments). For macros applying to three or more +% or an undefined number of arguments, we don't complicate matters into +% checking if expansion is possible, and we delay that expansion +% automatically (but if() and ifsgn() do check if first argument is numeric +% and expand to suitable branch in that case). +% +% In particular any function defined by \xintdeffunc or \xintNewFunction (it +% is then basically only a macro abstraction) when used in new function +% definitions will never be expanded immediately, because the detection of +% whether they are applied to only numerical data has not yet been added. +% (this might be added in future). +% +% Some aspects of the 1.3 refactoring have made recursive definition via +% \xintdeffunc possible (of course they always were via \xintNewFunction as +% the latter is but a wrapper of a standard TeX macro definition, where +% \xintexpr parsing is not at all involved). +% +% A somewhat complicated layer (not modified at 1.3) is devoted to making +% possible the parsing of constructs such as [#1..[#2]..#3][#4:#5] or +% [#1..#2]*#3 and it seems to work. At 1.3, even esoteric construct such as +% [divmod(#1,#2)]*#3 is parsable by \xintNewExpr. (In \xintNewFloatExpr, don't +% forget \empty token so that square brackets are not mistaken for optional +% argument of \xintthefloatexpr; same for \xintdeffloatfunc.) +% +% Side note: I wonder if I really had a good idea to define these list +% operations [..]*foo or foo^[...] which do not seem to occur in other +% languages with the meanings I used. And they caused me lots of efforts for +% support at \xintNewExpr level... +% +% The catcode 12 dollar sign is used to signal when a macro can not be +% expanded but would produce a csv list. Furthermore some cases require +% f-expandable macros as the original code expanding in \xintexpr is in +% \csname context and did not need f-expandability. +% +% As mentioned above, currently syntax with dummy variables can not go through +% where the values iterated over are not explicit; and omit, abort, break +% mechanisms are not parsable with non purely numerical data, in part because +% they are not implemented internally via pure f-expansion. +% | +% \subsubsection{\csh{xintApply::csv} and \csh{xintApply:::csv}} +% \lverb|Serve in particular to support things such as +% +% \xintdeffunc foo(x):=seq(sqr(i), i=0..x); +% +% ... as far as I still understand what is going on here! The most complicated +% is for list operations; many things involving sequences don't go through +% \xintNewExpr, especially with functions of more than one variable. +% +% | +% \begin{macrocode} +\def\xintApply::csv #1#2% + {\expandafter\XINT_applyon::_a\expandafter {\romannumeral`&&@#2}{#1}}% +\def\XINT_applyon::_a #1#2{\XINT_applyon::_b {#2}{}#1,,}% +\def\XINT_applyon::_b #1#2#3,{\expandafter\XINT_applyon::_c \romannumeral`&&@#3,{#1}{#2}}% +\def\XINT_applyon::_c #1{\if #1,\expandafter\XINT_applyon::_end + \else\expandafter\XINT_applyon::_d\fi #1}% +\def\XINT_applyon::_d #1,#2{\expandafter\XINT_applyon::_e\romannumeral`&&@#2{#1},{#2}}% +\def\XINT_applyon::_e #1,#2#3{\XINT_applyon::_b {#2}{#3, #1}}% +\def\XINT_applyon::_end #1,#2#3{\xint_secondoftwo #3}% +\def\xintApply:::csv #1#2#3% + {\expandafter\XINT_applyon:::_a\expandafter{\romannumeral`&&@#2}{#1}{#3}}% +\def\XINT_applyon:::_a #1#2#3{\XINT_applyon:::_b {#2}{#3}{}#1,,}% +\def\XINT_applyon:::_b #1#2#3#4,% + {\expandafter\XINT_applyon:::_c \romannumeral`&&@#4,{#1}{#2}{#3}}% +\def\XINT_applyon:::_c #1{\if #1,\expandafter\XINT_applyon:::_end + \else\expandafter\XINT_applyon:::_d\fi #1}% +\def\XINT_applyon:::_d #1,#2#3% + {\expandafter\XINT_applyon:::_e\expandafter + {\romannumeral`&&@\xintApply::csv {#2{#1}}{#3}},{#2}{#3}}% +\def\XINT_applyon:::_e #1,#2#3#4{\XINT_applyon:::_b {#2}{#3}{#4, #1}}% +\def\XINT_applyon:::_end #1,#2#3#4{\xint_secondoftwo #4}% +% \end{macrocode} +% \subsubsection{Mysterious stuff} +% \lverb|~ and $$ of catcode 12 in what follows. There was some refactoring at +% 1.3e, particulary \XINT:NE:userefunc was added.| +% \begin{macrocode} +\catcode`~ 12 +\catcode`$ 12 % $ +\def\xint_dfork #1$#2#3\krof {#2}% $ +\def\xint_ddfork #1$$#2#3\krof {#2}% $$ +\def\XINT:NE:RApply::csv #1#2#3#4% + {~xintApply::csv{~expandafter #2~xint_exchangetwo_keepbraces{#4}}{#3}}% +\def\XINT:NE:LApply::csv #1#2#3{~xintApply::csv{#2{#3}}}% +\def\XINT:NE:RLApply:::csv #1{~xintApply:::csv}% +\def\XINT:NE:two#1{\XINT:NE:two_{#1}{\detokenize{#1}}}% +\def\XINT:NE:two_#1#2#3#4% + {\expandafter\XINT:NE:two_a\romannumeral`&&@#4!{#3}{#1}{#2}}% +\def\XINT:NE:two_a#1#2!#3#4#5% + {\expandafter\XINT:NE:two_b\romannumeral`&&@#3!#1{#4}{#5}{#1#2}}% +\def\XINT:NE:two_b#1#2!#3#4#5{\XINT:NE:two_fork_dd#1#3{#4}{#5}{#1#2}}% +\def\XINT:NE:two_fork_dd #1#2{% + \xint_ddfork + #1#2\XINT:NE:RLApply:::csv + #1$\XINT:NE:RApply::csv% $ + $#2\XINT:NE:LApply::csv% $ + $${\XINT:NE:two_fork_nn #1#2}% $$ + \krof +}% +\def\XINT:NE:two_fork_nn #1#2#3#4{% + \if #1##\xint_dothis{#4}\fi + \if #1~\xint_dothis{#4}\fi + \if #2##\xint_dothis{#4}\fi + \if #2~\xint_dothis{#4}\fi + \xint_orthat{#3}% +}% +% \end{macrocode} +% \lverb|Problème pour autoriser ici qu'une liste arrive comme argument qui +% potentiellement en donnerait deux mais pour le moment on ne sait pas. Donc +% j'impose le prérequis que \XINT:NE:twosp soit toujours suivi de deux items +% exactement. +% +% Il y a eu des modifications à 1.3e car j'ai supprimé des choses que je ne +% comprenais pas puis je les ai remises lorsque je comprenais mais sans doute +% pas pareil (certains tests passent et pas avant) et ensuite je ne comprenais +% plus à nouveau.| +% \begin{macrocode} +\def\XINT:NE:twosp#1#2,#3#4,!#5% +{% + \XINT:NE:two_fork_dd#1#3{#5}{\detokenize{#5}}{#1#2}{#3#4}% +}% +\def\XINT:NE:one#1#2{\expandafter\XINT:NE:one_a\romannumeral`&&@#2!#1}% +\def\XINT:NE:one_a#1#2!#3% +{% + \if ###1\xint_dothis {\detokenize{#3}}\fi + \if ~#1\xint_dothis {\detokenize{#3}}\fi + \if $#1\xint_dothis {~xintApply::csv{\detokenize{#3}}}\fi %$ + \xint_orthat #3{#1#2}% +}% +% \end{macrocode} +% \lverb|\xintExpandArgs is defined in xinttools.sty (I don't recall why; not +% for reasons internal to xint I guess). Attention here that user function +% names may contain digits, so we don't use a \detokenize or ~ approach.| +% \begin{macrocode} +\def\XINT:NE:userfunc #1#2#3% + {~xintExpandArgs{XINT_#1_userfunc_#2}{\xintCSVtoListNonStripped{#3}}}% +\def\XINT:NE:userfunc:none #1#2{~!{XINT_#1_userfunc_#2}}% +% \end{macrocode} +% \lverb|\XINT:NE:userefunc et al. added at 1.3e. For one and two I can not +% use \XINT:NE:one due to possible digits in names. For more than two nothing +% special done with mysterious "Apply" macros above. +% +% Should they ever use $ in +% output? Je crois que j'ai des problèmes en particulier car j'utilise le most +% liste dans plusieurs sens il y a en particulier la confusion possible pour +% liste dans le sens restreint devant être géré par les opérations genre ]* ou +% celui avec les seq() ou finalement la liste des arguments d'une fonction. +% +% When expansion of the user func can not happend on the spot, the version +% which will be expanded later one must first expand its argument for +% efficiency because the functions from \XINT_NewFunc do not do that and we +% must thus have an auxiliary variant expanding its argument.| +% \begin{macrocode} +\def\XINT:NE:userefunc:one#1#2#3% + {\expandafter\XINT:NE:userefunc:one_a\romannumeral`&&@#3!{#1}{#2}}% +\def\XINT:NE:userefunc:one_a#1#2!#3#4% +{% + \if ###1\xint_dothis {~!{XINT_#3_userefunc:f_#4}}\fi + \if ~#1\xint_dothis {~!{XINT_#3_userefunc:f_#4}}\fi +% \end{macrocode} +% \lverb|Quickly checked this \csname presentation ok for \xintApply::csv.| +% \begin{macrocode} + \if $#1\xint_dothis {~xintApply::csv~!{XINT_#3_userefunc:f_#4}}\fi %$ + \xint_orthat {\csname XINT_#3_userefunc_#4\endcsname}% + {#1#2}% +}% +\def\XINT:NE:twosp#1#2,#3#4,!#5% +{% + \XINT:NE:two_fork_dd#1#3{#5}{\detokenize{#5}}{#1#2}{#3#4}% +}% +\def\XINT:NE:userefunc:two#1#2#3% + {\expandafter\XINT:NE:userefunc:two_a\romannumeral`&&@#3,!{#1}{#2}}% +% \end{macrocode} +% \lverb|Je ne peux pas faire ~xintExpandArgs{XINT_#5_userefunc_#6} à cause du +% fait que j'ai {#1#2}{#3#4} pas {{#1#2}{#3#4}} à cause de la première +% branche, celle qui s'étend.| +% \begin{macrocode} +\def\XINT:NE:userefunc:two_a#1#2,#3#4,!#5#6% +{% + \XINT:NE:two_fork_dd#1#3{\csname XINT_#5_userefunc_#6\endcsname}% + {~!{XINT_#5_userefunc:f_#6}}% + {#1#2}{#3#4}% +}% +\def\XINT:NE:userefunc#1#2#3% +{% + \expandafter\XINT:NE:userefunc_a\romannumeral`&&@#3,2,3,4,5,6,7,8,9,!% + {#1}{#2}{#3}% +}% +\def\XINT:NE:userefunc_a#1#2,#3#4,#5#6,#7#8,#9% +{% + \XINT:NE:userefunc_b{#1#3#5#7#9}% +}% +\def\XINT:NE:userefunc_b#1#2,#3#4,#5#6,#7#8,#9% +{% + \XINT:NE:userefunc_c{#1#3#5#7#9}% +}% +\def\XINT:NE:iftilde #1~#2#3\relax{\unless\if !#21\fi}% +\def\XINT:NE:ifdollar #1$#2#3\relax{\unless\if !#21\fi}%$ +\def\XINT:NE:ifhash#1{% +\def\XINT:NE:ifhash##1#1##2##3\relax{\unless\if !##21\fi}% +}\expandafter\XINT:NE:ifhash\string#% +\def\XINT:NE:userefunc_c#1#2!% +{% + \if0\XINT:NE:iftilde #1~!\relax\XINT:NE:ifdollar #1$!\relax%$ + \XINT:NE:ifhash #1##!\relax 0% + \expandafter\XINT:NE:userefunc_x + \else + \expandafter\XINT:NE:userefunc_p + \fi +}% +\def\XINT:NE:userefunc_x#1#2% + {\csname XINT_#1_userefunc_#2\expandafter\endcsname + \romannumeral0\xintcsvtolistnonstripped}% +\def\XINT:NE:userefunc_p #1#2#3% + {~xintExpandArgs{XINT_#1_userefunc_#2}{\xintCSVtoListNonStripped{#3}}}% +% \end{macrocode} +% \lverb|Back to older stuff.| +% \begin{macrocode} +\def\XINT:NE:oneopt#1[#2]#3% + {\expandafter\XINT:NE:oneopt_a\romannumeral`&&@#3!{#2}#1}% +\def\XINT:NE:oneopt_a#1#2!#3#4% + {\expandafter\XINT:NE:oneopt_b\romannumeral`&&@#3!#1#4{#1#2}}% +\def\XINT:NE:oneopt_b#1#2!#3#4% + {\expandafter\XINT:NE:oneopt_fork#1#3#4{#1#2}}% +\def\XINT:NE:oneopt_fork#1#2#3#4{% + \if1\if###11\else\if~#11\else\if###21\else\if~#21\else0\fi\fi\fi\fi + \xint_dothis {\detokenize{#3}[#4]}\fi + \if $#2\xint_dothis {~xintApply::csv{\detokenize{#3}[#4]}}\fi %$ + \xint_orthat{#3[#4]}% +}% pas complétement général, mais bon +\def\XINT:NE:csv #1{\detokenize{#1}}% radicalement fainéant +\def\XINT:newexpr:one:and:opt #1,#2,#3!#4#5% +{% + \if\relax#3\relax\expandafter\xint_firstoftwo\else + \expandafter\xint_secondoftwo\fi + {\XINT:NE:one#4}{\XINT:NE:oneopt#5[\XINT:NE:one\xintNum{#2}]}{#1}% +}% +\def\XINT:newexpr:tacitzeroifonearg #1,#2,#3!#4#5% +{% + \if\relax#3\relax\expandafter\xint_firstoftwo\else + \expandafter\xint_secondoftwo\fi + {\XINT:NE:two#4{0}}{\XINT:NE:two#5{\XINT:NE:one\xintNum{#2}}}{#1}% +}% +\def\XINT:newiiexpr:tacitzeroifonearg #1,#2,#3!#4% +{% + \if\relax#3\relax\expandafter\xint_firstoftwo\else + \expandafter\xint_secondoftwo\fi + {\XINT:NE:two#4{0}}{\XINT:NE:two#4{#2}}{#1}% +}% +\def\XINT:newexpr:insertdollar~{$noexpand$}% +\def\XINT:newexpr:two:to:two #1,#2,!#3% +{% + \XINT:NE:two_ + {\expandafter\XINT:expr:totwo\romannumeral`&&@#3}% + {$noexpand$expandafter~XINT:expr:totwo~romannumeral-`0\detokenize{#3}}% + {#1}{#2}% +}% +\def\XINT:newflexpr:two:to:two #1,#2,!#3% +{% + \XINT:NE:two_ + {#3}% + {\expandafter\XINT:newexpr:insertdollar\detokenize{#3}}% + {#1}{#2}% +}% +\def\xintiiifNotZeroNE:#1#2,#3,#4,% +{% + \if1\if###11\else\if~#11\else\if$#11\else0%$ + \fi\fi\fi + \xint_dothis{~xintiiifNotZero}\fi + \xint_orthat\xintiiifNotZero + {#1#2}{#3}{#4}% +}% +\def\xintifIntNE:#1#2,#3,#4,% +{% + \if1\if###11\else\if~#11\else\if$#11\else0%$ + \fi\fi\fi + \xint_dothis{~xintifInt}\fi + \xint_orthat\xintifInt + {#1#2}{#3}{#4}% +}% +\def\xintifFloatIntNE:#1#2,#3,#4,% +{% + \if1\if###11\else\if~#11\else\if$#11\else0%$ + \fi\fi\fi + \xint_dothis{~xintifFloatInt}\fi + \xint_orthat\xintifFloatInt + {#1#2}{#3}{#4}% +}% +\def\xintiiifOneNE:#1#2,#3,#4,% +{% + \if1\if###11\else\if~#11\else\if$#11\else0%$ + \fi\fi\fi + \xint_dothis{~xintiiifOne}\fi + \xint_orthat\xintiiifOne + {#1#2}{#3}{#4}% +}% +\def\xintifOneNE:#1#2,#3,#4,% +{% + \if1\if###11\else\if~#11\else\if$#11\else0%$ + \fi\fi\fi + \xint_dothis{~xintifOne}\fi + \xint_orthat\xintifOne + {#1#2}{#3}{#4}% +}% +\def\xintiiifSgnNE:#1#2,#3,#4,#5,% +{% + \if1\if###11\else\if~#11\else\if$#11\else0%$ + \fi\fi\fi + \xint_dothis{~xintiiifSgn}\fi + \xint_orthat\xintiiifSgn + {#1#2}{#3}{#4}{#5}% +}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_redefinemacros}} +% \lverb|Completely refactored at 1.3.| +% \begin{macrocode} +\def\XINT_expr_redefinemacros {% + \let\XINT:NEhook:one \XINT:NE:one + \let\XINT:NEhook:two \XINT:NE:two + \let\XINT:NEhook:csv \XINT:NE:csv + \let\XINT:NEhook:twosp\XINT:NE:twosp + \let\XINT:expr:userfunc \XINT:NE:userfunc + \let\XINT:expr:userfunc:none \XINT:NE:userfunc:none + \let\XINT:expr:userefunc \XINT:NE:userefunc + \let\XINT:expr:userefunc:one \XINT:NE:userefunc:one + \let\XINT:expr:userefunc:two \XINT:NE:userefunc:two + \let\XINT:expr:macrofunc \XINT:newexpr:macrofunc + \let\XINT:expr:one:and:opt \XINT:newexpr:one:and:opt + \let\XINT:expr:one:or:two:nums \XINT:newexpr:one:or:two:nums + \let\XINT:iiexpr:one:or:two: \XINT:newiiexpr:one:or:two: + \let\XINT:expr:tacitzeroifonearg \XINT:newexpr:tacitzeroifonearg + \let\XINT:iiexpr:tacitzeroifonearg \XINT:newiiexpr:tacitzeroifonearg + \let\XINT:expr:two:to:two \XINT:newexpr:two:to:two + \let\XINT:flexpr:two:to:two \XINT:newflexpr:two:to:two + \let\xintiiifNotZero: \xintiiifNotZeroNE: + \let\xintifInt: \xintifIntNE: + \let\xintifFloatInt: \xintifFloatIntNE: + \let\xintiiifOne: \xintiiifOneNE: + \let\xintifOne: \xintifOneNE: + \let\xintiiifSgn: \xintiiifSgnNE: + \let\xintSeqNumeric::csv \xintSeq::csv + \let\xintiiSeqNumeric::csv \xintiiSeq::csv + \let\XINTinFloatSeqNumeric::csv \XINTinFloatSeq::csv + \let\xintSeqBNumeric::csv \xintSeqB::csv + \let\xintiiSeqBNumeric::csv \xintiiSeqB::csv + \let\XINTinFloatSeqBNumeric::csv\XINTinFloatSeqB::csv + \def\xintSeq::csv + {\XINT:NE:two_\xintSeqNumeric::csv{$noexpand$xintSeq::csv}}% + \def\xintiiSeq::csv + {\XINT:NE:two_\xintiiSeqNumeric::csv{$noexpand$xintiiSeq::csv}}% + \def\XINTinFloatSeq::csv + {\XINT:NE:two_\XINTinFloatSeqNumeric::csv{$noexpand$XINTinFloatSeq::csv}}% + \def\xintSeqB::csv + {\XINT:NE:two_\xintSeqBNumeric::csv{$noexpand$xintSeqB:f:csv}}% + \def\xintiiSeqB::csv + {\XINT:NE:two_\xintiiSeqBNumeric::csv{$noexpand$xintiiSeqB:f:csv}}% + \def\XINTinFloatSeqB::csv + {\XINT:NE:two_\XINTinFloatSeqBNumeric::csv{$noexpand$XINTinFloatSeqB:f:csv}}% + \def\xintListSel:x:csv {~xintListSel:f:csv }% + \def\XINTinRandomFloatSdigits{~XINTinRandomFloatSdigits }% + \def\XINTinRandomFloatSixteen{~XINTinRandomFloatSixteen }% + \def\xintiiRandRange{~xintiiRandRange }% + \def\xintiiRandRangeAtoB{~xintiiRandRangeAtoB }% +}% +% \end{macrocode} +% \subsubsection{\csh{XINT_expr_redefineprints}} +% \lverb|This is used by \xintNewExpr and prior to 1.3e not by \xintdeffunc, +% presumably to avoid some supposedly unneeded overhead. Now also used by +% \xintdeffunc see some comment further below for why. +% | +% \begin{macrocode} +\def\XINT_expr_redefineprints +{% + \def\XINT_flexpr_noopt + {% + \expandafter + \XINT_flexpr_preprint\expandafter-\romannumeral0\xintbarefloateval + }% + \def\XINT_flexpr_preprint ##1##2% + {% + \expandafter\XINT_flexpr_wrap + \csname .;##1.=\XINT_expr_unlock##2\endcsname + }% + \def\XINT_expr_unlock_sp ##1.;##2##3.=##4!% + {% + \if -##2\expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi + \XINTdigits{{##2##3}}{##4}% + }% + \def\XINT_expr_print ##1{\expandafter + \xintSPRaw::csv\expandafter{\romannumeral`&&@\XINT_expr_unlock ##1}}% + \def\XINT_iiexpr_print ##1{\expandafter + \xintCSV::csv\expandafter{\romannumeral`&&@\XINT_expr_unlock ##1}}% + \def\XINT_boolexpr_print ##1{\expandafter + \xintIsTrue::csv\expandafter{\romannumeral`&&@\XINT_expr_unlock ##1}}% + \def\xintCSV::csv {~xintCSV::csv }% + \def\xintSPRaw::csv {~xintSPRaw::csv }% + \def\xintPFloat::csv {~xintPFloat::csv }% + \def\xintIsTrue::csv {~xintIsTrue::csv }% + \def\xintRound::csv {~xintRound::csv }% +}% +% \end{macrocode} +% \subsubsection{\cshnolabel{xintNewExpr}, ..., at last.} +% \lverb|& +% 1.2c modifications to accomodate \XINT_expr_deffunc_newexpr etc.. +% +% 1.2f adds token \XINT_newexpr_clean to be able to have a different +% \XINT_newfunc_clean.| +% \begin{macrocode} +\def\xintNewExpr {\XINT_NewExpr\XINT_expr_redefineprints\xint_firstofone + \xinttheexpr\XINT_newexpr_clean}% +\def\xintNewFloatExpr{\XINT_NewExpr\XINT_expr_redefineprints\xint_firstofone + \xintthefloatexpr\XINT_newexpr_clean}% +\def\xintNewIExpr {\XINT_NewExpr\XINT_expr_redefineprints\xint_firstofone + \xinttheiexpr\XINT_newexpr_clean}% +\def\xintNewIIExpr {\XINT_NewExpr\XINT_expr_redefineprints\xint_firstofone + \xinttheiiexpr\XINT_newexpr_clean}% +\def\xintNewBoolExpr {\XINT_NewExpr\XINT_expr_redefineprints\xint_firstofone + \xinttheboolexpr\XINT_newexpr_clean}% +\def\XINT_newexpr_clean #1>{\noexpand\romannumeral`&&@}% +% \end{macrocode} +% \lverb|1.2c for \xintdeffunc, \xintdefiifunc, \xintdeffloatfunc. +% +% At 1.3, NewFunc does not use a comma delimited pattern anymore.| +% \begin{macrocode} +\def\XINT_NewFunc + {\XINT_NewExpr\XINT_expr_redefineprints\xint_gobble_i\xintthebareeval\XINT_newfunc_clean}% +\def\XINT_NewFloatFunc + {\XINT_NewExpr\XINT_expr_redefineprints\xint_gobble_i\xintthebarefloateval\XINT_newfunc_clean}% +\def\XINT_NewIIFunc + {\XINT_NewExpr\XINT_expr_redefineprints\xint_gobble_i\xintthebareiieval\XINT_newfunc_clean}% +\def\XINT_newfunc_clean #1>{}% +% \end{macrocode} +% \lverb|1.2c adds optional logging. For this needed to pass to _NewExpr_a the +% macro name as parameter. +% +% Up to and including 1.2c the definition was global. Starting with 1.2d it is +% done locally. +% +% Modified at 1.3c so that \XINT_NewFunc et al. do not execute the +% \xintexprSafeCatcodes, as it is now already done earlier by \xintdeffunc: +% and as already #2 was either \xint_firstofone (for \xintNewExpr et al.) or +% \xint_gobble_i (for \XINT_NewFunc et al.) we can use that #2. This is only +% to avoid doing twice the catcodes, as anyhow there is an \endgroup coming +% later, so external \xintexprRestoreCatcodes would not have been compromised. +% +% Modified at 1.3e: \XINT_NewFunc et al. do issue \XINT_expr_redefineprints. +% I suppose I did not use it formely as I considered it unneeded overhead, +% but this meant that \xintdeffunc foo(x):=\xintfloatexpr bar(x)\relax; was +% impossible. And in fact this is convenient for xinttrig.sty to transfer +% float functions to normal functions. +% | +% \begin{macrocode} +\def\XINT_NewExpr #1#2#3#4#5#6[#7]% +{% + \begingroup + \ifcase #7\relax + \toks0 {\endgroup\XINT_global\def#5}% + \or \toks0 {\endgroup\XINT_global\def#5##1}% + \or \toks0 {\endgroup\XINT_global\def#5##1##2}% + \or \toks0 {\endgroup\XINT_global\def#5##1##2##3}% + \or \toks0 {\endgroup\XINT_global\def#5##1##2##3##4}% + \or \toks0 {\endgroup\XINT_global\def#5##1##2##3##4##5}% + \or \toks0 {\endgroup\XINT_global\def#5##1##2##3##4##5##6}% + \or \toks0 {\endgroup\XINT_global\def#5##1##2##3##4##5##6##7}% + \or \toks0 {\endgroup\XINT_global\def#5##1##2##3##4##5##6##7##8}% + \or \toks0 {\endgroup\XINT_global\def#5##1##2##3##4##5##6##7##8##9}% + \fi + #2\xintexprSafeCatcodes + \XINT_expr_redefinemacros + #1% + \XINT_NewExpr_a #2#3#4#5% +}% +% \end{macrocode} +% \lverb|& attention que & est de catcode 14 +% +% 1.2d's \xintNewExpr makes a local definition. In earlier releases, the +% definition was global. +% +% \the\toks0 inserts the \endgroup, but this will happen +% after \XINT_tmpa has already been expanded... +% +% The $%1 is \xint_firstofone for \xintNewExpr, \xint_gobble_i +% for \xintdeffunc. +% +% The ~ action was modified at 1.3e for ~! constructs (userefunc:f macros). +% | +% \begin{macrocode} +\catcode`~ 13 \catcode`@ 14 \catcode`\% 6 \catcode`# 12 \catcode`$ 11 @ $ +\def\XINT_NewExpr_a %1%2%3%4%5@ +{@ + \def\XINT_tmpa %%1%%2%%3%%4%%5%%6%%7%%8%%9{%5}@ + \def~%%1{\if !%%1\noexpand~\else $noexpand$%%1\fi}@ + \catcode`: 11 \catcode`_ 11 + \catcode`# 12 \catcode`~ 13 \escapechar 126 + \endlinechar -1 \everyeof {\noexpand }@ + \edef\XINT_tmpb + {\scantokens\expandafter{\romannumeral`&&@\expandafter + %2\XINT_tmpa{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}\relax}@ + }@ + \escapechar 92 \catcode`# 6 \catcode`$ 0 @ $ + \def~%%1{\expandafter\noexpand\csname %%1\endcsname}@ + \edef\XINT_tmpa %%1%%2%%3%%4%%5%%6%%7%%8%%9@ + {\scantokens\expandafter{\expandafter%3\meaning\XINT_tmpb}}@ + \the\toks0\expandafter + {\XINT_tmpa{%%1}{%%2}{%%3}{%%4}{%%5}{%%6}{%%7}{%%8}{%%9}}@ + %1{\ifxintverbose + \xintMessage{xintexpr}{Info}@ + {\string%4\space now with @ + \ifxintglobaldefs global \fi meaning \meaning%4}@ + \fi}@ +}@ +\catcode`% 14 +\XINT_setcatcodes % clean up to avoid surprises if something changes +% \end{macrocode} +% \subsubsection{\csh{ifxintexprsafecatcodes}, \csh{xintexprSafeCatcodes}, \csh{xintexprRestoreCatcodes}} +% \changed{1.3c}{2018/06/17} +% \lverb|Added \ifxintexprsafecatcodes to allow nesting| +% \begin{macrocode} +\newif\ifxintexprsafecatcodes +\let\xintexprRestoreCatcodes\empty +\def\xintexprSafeCatcodes +{% + \unless\ifxintexprsafecatcodes + \edef\xintexprRestoreCatcodes {% + \catcode59=\the\catcode59 % ; + \catcode34=\the\catcode34 % " + \catcode63=\the\catcode63 % ? + \catcode124=\the\catcode124 % | + \catcode38=\the\catcode38 % & + \catcode33=\the\catcode33 % ! + \catcode93=\the\catcode93 % ] + \catcode91=\the\catcode91 % [ + \catcode94=\the\catcode94 % ^ + \catcode95=\the\catcode95 % _ + \catcode47=\the\catcode47 % / + \catcode41=\the\catcode41 % ) + \catcode40=\the\catcode40 % ( + \catcode42=\the\catcode42 % * + \catcode43=\the\catcode43 % + + \catcode62=\the\catcode62 % > + \catcode60=\the\catcode60 % < + \catcode58=\the\catcode58 % : + \catcode46=\the\catcode46 % . + \catcode45=\the\catcode45 % - + \catcode44=\the\catcode44 % , + \catcode61=\the\catcode61 % = + \catcode96=\the\catcode96 % ` + \catcode32=\the\catcode32\relax % space + \noexpand\xintexprsafecatcodesfalse + }% + \fi + \xintexprsafecatcodestrue + \catcode59=12 % ; + \catcode34=12 % " + \catcode63=12 % ? + \catcode124=12 % | + \catcode38=4 % & + \catcode33=12 % ! + \catcode93=12 % ] + \catcode91=12 % [ + \catcode94=7 % ^ + \catcode95=8 % _ + \catcode47=12 % / + \catcode41=12 % ) + \catcode40=12 % ( + \catcode42=12 % * + \catcode43=12 % + + \catcode62=12 % > + \catcode60=12 % < + \catcode58=12 % : + \catcode46=12 % . + \catcode45=12 % - + \catcode44=12 % , + \catcode61=12 % = + \catcode96=12 % ` + \catcode32=10 % space +}% +\let\XINT_tmpa\undefined \let\XINT_tmpb\undefined \let\XINT_tmpc\undefined +\ifdefined\RequirePackage\expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi +{\RequirePackage{xinttrig}% +\RequirePackage{xintlog}}% +{\input xinttrig.sty +\input xintlog.sty +}% +\XINT_restorecatcodes_endinput% +% \end{macrocode} +% \StoreCodelineNo {xintexpr} +% \cleardoublepage\let\xintexprnameUp\undefined +%\gardesactifs +%\let</xintexpr>\relax +%\let<*xinttrig>\gardesinactifs +%</xintexpr>^^A-------------------------------------------------- +%<*xinttrig>^^A--------------------------------------------------- +%^^A -*- coding: utf-8; mode: doctex; fill-column: 78; -*- +% \clearpage\csname xinttrignameUp\endcsname +% \section{Package \xinttrignameimp implementation} +% \RaisedLabel{sec:trigimp} +% \etocarticlestylenomarks +% \etocsetnexttocdepth {subsubsection} +% +% \localtableofcontents +% +% The original was done in January 15 and 16, 2019. It provided |asin()| and +% |acos()| based on a Newton algorithm approach. Then during March 25-31 I +% revisited the code, adding more inverse trigonometrical functions (with a +% modified algorithm, quintically convergent), extending the precision range +% (so that the package reacts to the \csbxint{Digits} value at time of load, +% or reload), and replaced high level range reduction by some optimized lower +% level coding. +% +% This led me next to improve upon the innards of \csbxint{deffunc} and +% \csbxint{NewExpr}, and to add to \xintexprnameimp the \csbxint{defefunc} +% macro (see user documentation). +% +% Finally on April 5, 2019 I pushed the idea of the algorithm for the arcsine +% function to its logical limit obtaining the method finally in use here. +% +% Almost all of the code remains written at high level, and in particular it +% is not easily feasible from this interface to execute computations with +% guard digits. Expect the last one or two digits to be systematically off. +% +% Also, small floating-point inputs are handled quite sub-optimally both for +% the direct and inverse functions; substantial gains are possible. I added +% the ilog10() function too late to consider using it here with the high level +% interface. +% +% \subsection{Catcodes, \protect\eTeX{} and reload detection} +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode64=11 % @ + \catcode35=6 % # + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \catcode94=7 % ^ + \def\z{\endgroup}% + \def\empty{}\def\space{ }\newlinechar10 + \expandafter\let\expandafter\w\csname ver@xintexpr.sty\endcsname + \expandafter + \ifx\csname PackageInfo\endcsname\relax + \def\y#1#2{\immediate\write-1{Package #1 Info:^^J% + \space\space\space\space#2.}}% + \else + \def\y#1#2{\PackageInfo{#1}{#2}}% + \fi + \expandafter + \ifx\csname numexpr\endcsname\relax + \y{xinttrig}{\numexpr not available, aborting input}% + \aftergroup\endinput + \else + \ifx\w\relax % xintexpr.sty not yet loaded. + \y{xinttrig}% + {Loading should be via \ifx\x\empty\string\usepackage{xintexpr.sty} + \else\string\input\space xintexpr.sty \fi + rather, aborting}% + \aftergroup\endinput + \fi + \fi +\z% +\catcode`_ 11 \XINT_setcatcodes \catcode`? 12 +% \end{macrocode} +% \subsection{Library identification} +% \begin{macrocode} +\ifcsname xintlibver@trig\endcsname + \expandafter\xint_firstoftwo +\else + \expandafter\xint_secondoftwo +\fi +{\immediate\write-1{Reloading xinttrig library using Digits=\xinttheDigits.}}% +{\expandafter\gdef\csname xintlibver@trig\endcsname{2019/04/05 1.3e}% +\XINT_providespackage +\ProvidesPackage{xinttrig}% +[2019/04/05 1.3e Trigonometrical functions for xintexpr (JFB)]% +}% +% \end{macrocode} +% \subsection{Ensure used letters are dummy letters} +% \begin{macrocode} +\xintFor* #1 in {iDTVtuwxyzX}\do{\xintensuredummy{#1}}% +% \end{macrocode} +% \subsection{\csh{xintreloadxinttrig}} +% \begin{macrocode} +\def\xintreloadxinttrig + {\edef\XINT_restorecatcodes_now{\XINT_restorecatcodes}% + \XINT_setcatcodes\catcode`? 12 + \input xinttrig.sty + \XINT_restorecatcodes_now}% +% \end{macrocode} +% \subsection{Auxiliary variables (only temporarily needed, but left free to re-use)} +% \lverb|& +% These variables don't have really private names but this does not matter +% because only their actual values will be stored in the functions defined +% next. Nevertheless they are not unassigned, and are left free to use as is. +% | +% \subsubsection{\cshn{twoPi}, \cshn{threePiover2}, \cshn{Pi}, \cshn{Piover2}} +% \lverb|& +% We take them with 60 digits +% and force conversion to \xintDigits setting via "0 + " syntax. +% | +% \begin{macrocode} +\xintdeffloatvar twoPi := 0 + + 6.28318530717958647692528676655900576839433879875021164194989;% +\xintdeffloatvar threePiover2 := 0 + + 4.71238898038468985769396507491925432629575409906265873146242;% +\xintdeffloatvar Pi := 0 + + 3.14159265358979323846264338327950288419716939937510582097494;% +\xintdeffloatvar Piover2 := 0 + + 1.57079632679489661923132169163975144209858469968755291048747;% +% \end{macrocode} +% \subsubsection{\cshn{oneDegree}, \cshn{oneRadian}} +% \begin{macrocode} +\xintdeffloatvar oneDegree := 0 + + 0.0174532925199432957692369076848861271344287188854172545609719;% Pi/180 +\xintdeffloatvar oneRadian := 0 + + 57.2957795130823208767981548141051703324054724665643215491602;% 180/Pi +% \end{macrocode} +% \subsubsection{Inverse factorial coefficients: \cshn{invfact2}, ..., \cshn{invfact44}} +% \lverb|& +% Pre-compute 1/n! for n = 2, ..., 44 +% +% The following example (among many, see below) shows that we must be careful +% when pre-computing the 1/i!. +%( Consider 35!=10333147966386144929666651337523200000000. +%: With \xintDigit:=26; \xintfloateval{35!} obtains 1.0333147966386144929666651e40 +%: which is the correct rounding to 26 digits. But \xintfloateval{1/35!} obtains +%: 9.6775929586318909920898167e-41 which differs by 3ulps from the correct rounding +%: of 1/35! to 26 places which is 9.6775929586318909920898164e-41. The problem +%: isn't in the factorial computations, but in the fact that the rounding of the +%: inverse of a quantity which is itself a rounding is not necessarily the rounding +%: of the exact inverse of the original. +%) +% Here is a little program to explore this phenomenon systematically: +% +%( \xintDigits:=55;$% +%: \edef\tempNlist{\xintSeq{2}{39}}% +%: \xintFor*#1in{\tempNlist}\do{$% we precompute some rounding here to +%: $% speed up things in the next double loop. +%: \expandafter\edef\csname invfact#1\endcsname {\xintfloatexpr 1/#1!\relax}$% +%: }$% +%: \xintFor*#1in{\xintSeq{4}{50}}\do{$% +%: \xintDigits:=#1;$% +%: \xintFor*#2in{\tempNlist}\do{$% +%: (D=#1, N=#2) +%: $% attention to !== which is parsed as negation operator != followed by = (sigh...) +%: \xintifboolfloatexpr{(1/#2!)==0+\csname invfact#2\endcsname}$% +%: {ok} +%: {mismatch: \xintfloateval{1/#2!} vs (exact) +%: \xintfloateval{0+\csname invfact#2\endcsname}}$% +%: \par +%: }$% +%: }$% +%) +% +% We can see that for D=16, the problem is there with N=22, 25, 26, 27, +% 28...and more. If we were to use 1/i! directly in the \xintdeffloatefunc of +% sin_aux(X) and cos_aux(X) we would have this problem. +% +% If we use \xintexpr1/i!\relax encapsulation in the function declaration the +% rounding will be delayed to actual use of the function... which is bad, so +% we need it to happen now. We could use (0+\xintexpr1/i!\relax) inside the +% declaration of the sine and cosine series, which will give the expected +% result but for readability we use some temporary variables. We could use +% seq(0+\xintexpr1/i!\relax, i = 2..44) but opt for an rseq. The semi-colon +% must be braced to hide it from \xintdeffloatvar grabbing of the delimited +% argument. +% | +% \begin{macrocode} +\xintdeffloatvar invfact\xintListWithSep{, invfact}{\xintSeq{2}{44}}% + := seq(0+x, x=\xintexpr rseq(1/2{;}@/i, i=3..44)\relax);% need to hide inner ; +% \end{macrocode} +% \subsection{The sine and cosine series} +% \subsubsection{\cshn{sin_aux()}, \cshn{cos_aux()}} +% \lverb|& +% Should I rather use successive divisions by (2n+1)(2n), or rather +% multiplication by their precomputed inverses, in a modified Horner scheme ? +% The \ifnum tests are executed at time of definition. +% +% Criteria for truncated series using π/4, actually 0.79. +% +% Small values of the variable X are very badly handled here because a much +% shorter truncation of the sine series should be used. +% | +% \begin{macrocode} +\xintdeffloatefunc sin_aux(X) := 1 - X(invfact3 - X(invfact5 +\ifnum\XINTdigits>4 + - X(invfact7 +\ifnum\XINTdigits>6 + - X(invfact9 +\ifnum\XINTdigits>8 + - X(invfact11 +\ifnum\XINTdigits>10 + - X(invfact13 +\ifnum\XINTdigits>13 + - X(invfact15 +\ifnum\XINTdigits>15 + - X(invfact17 +\ifnum\XINTdigits>18 + - X(invfact19 +\ifnum\XINTdigits>21 + - X(invfact21 +\ifnum\XINTdigits>24 + - X(invfact23 +\ifnum\XINTdigits>27 + - X(invfact25 +\ifnum\XINTdigits>30 + - X(invfact27 +\ifnum\XINTdigits>33 + - X(invfact29 +\ifnum\XINTdigits>36 + - X(invfact31 +\ifnum\XINTdigits>39 + - X(invfact33 +\ifnum\XINTdigits>43 + - X(invfact35 +\ifnum\XINTdigits>46 + - X(invfact37 +\ifnum\XINTdigits>49 + - X(invfact39 +\ifnum\XINTdigits>53 + - X(invfact41 +\ifnum\XINTdigits>59 + - X(invfact43 + )\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi));% +% \end{macrocode} +% \lverb|Criteria on basis of π/4, we actually used 0.79 to choose the +% transition values and this makes them a bit less favourable at 24, 26, +% 29...and some more probably. Again this is very bad for small X.| +% \begin{macrocode} +\xintdeffloatefunc cos_aux(X) := 1 - X(invfact2 - X(invfact4 +\ifnum\XINTdigits>3 + - X(invfact6 +\ifnum\XINTdigits>5 + - X(invfact8 +\ifnum\XINTdigits>7 + - X(invfact10 +\ifnum\XINTdigits>9 + - X(invfact12 +\ifnum\XINTdigits>12 + - X(invfact14 +\ifnum\XINTdigits>14 + - X(invfact16 +\ifnum\XINTdigits>17 + - X(invfact18 +\ifnum\XINTdigits>20 + - X(invfact20 +\ifnum\XINTdigits>23 + - X(invfact22 +\ifnum\XINTdigits>25 + - X(invfact24 +\ifnum\XINTdigits>28 + - X(invfact26 +\ifnum\XINTdigits>32 + - X(invfact28 +\ifnum\XINTdigits>35 + - X(invfact30 +\ifnum\XINTdigits>38 + - X(invfact32 +\ifnum\XINTdigits>41 + - X(invfact34 +\ifnum\XINTdigits>44 + - X(invfact36 +\ifnum\XINTdigits>48 + - X(invfact38 +\ifnum\XINTdigits>51 + - X(invfact40 +\ifnum\XINTdigits>55 + - X(invfact42 +\ifnum\XINTdigits>58 + - X(invfact44 + )\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi)\fi));% +% \end{macrocode} +% \subsubsection{Make \cshnnolabel{sin\_aux()} and \cshnnolabel{cos\_aux()} +% known to \cshnolabel{xintexpr}} +% \lverb|We need them shortly for the asin() in an \xintexpr variant. +% We short-circuit the high level interface as it will not be needed to +% add some \xintFloat wrapper. +% | +% \begin{macrocode} +\expandafter\let\csname XINT_expr_func_sin_aux\expandafter\endcsname + \csname XINT_flexpr_func_sin_aux\endcsname +\expandafter\let\csname XINT_expr_func_cos_aux\expandafter\endcsname + \csname XINT_flexpr_func_cos_aux\endcsname +% \end{macrocode} +% \subsubsection{\cshn{sin_()}, \cshn{cos_()}} +% \lverb|& +% Use this only between -pi/4 and pi/4 +% | +% \begin{macrocode} +\xintdeffloatefunc sin_(x) := x * sin_aux(sqr(x));% +% \end{macrocode} +% \lverb|& +% Use this only between -pi/4 and pi/4 +% | +% \begin{macrocode} +\xintdeffloatefunc cos_(x) := cos_aux(sqr(x));% +% \end{macrocode} +% \subsection{Range reduction for sine and cosine using degrees} +% +% Notice that even when handling radians it is much better to convert to +% degrees and then do range reduction there, because this can be done in the +% fixed point sense. I lost 1h puzzled about some mismatch of my results with +% those of Maple (at 16 digits) near -π. Turns out that Maple probably adds π +% in the floating point sense causing catastrophic loss of digits when one is +% near -π. On the other hand my sin(x) function will first convert to degrees +% then add 180 without any loss of floating point precision, even for a result +% near zero, then convert back to radians and use the sine series. +% +% \subsubsection{Core level macro \csh{XINT_mod_ccclx_i}} +% \lverb|& +% input: \the\numexpr\XINT_mod_ccclx_i k.N. (delimited by dots) +% +% output: (N times 10^k) modulo 360. (with a final dot) +% +% Attention N must be non-negative (I could make it accept negative +% but the fact that numexpr / is not periodical in numerator +% adds overhead). +% +% 360 divides 9000 hence 10^{k} is 280 for k at least 3 and the additive +% group generated by it modulo 360 is the set of multiples of 40. +% | +% \begin{macrocode} +\def\XINT_mod_ccclx_i #1.% input <k>.<N>. k is a non-negative exponent +{% + \expandafter\XINT_mod_ccclx_e\the\numexpr + \expandafter\XINT_mod_ccclx_j\the\numexpr1\ifcase#1 \or0\or00\else000\fi.% +}% +\def\XINT_mod_ccclx_j 1#1.#2.% #2=N is a non-negative mantissa +{% + (\XINT_mod_ccclx_ja {++}#2#1\XINT_mod_ccclx_jb 0000000\relax +}% 1 2345678 +\def\XINT_mod_ccclx_ja #1#2#3#4#5#6#7#8#9% +{% + #9+#8+#7+#6+#5+#4+#3+#2\xint_firstoftwo{+\XINT_mod_ccclx_ja{+#9+#8+#7}}{#1}% +}% +\def\XINT_mod_ccclx_jb #1\xint_firstoftwo#2#3{#1+0)*280\XINT_mod_ccclx_jc #1#3}% +% \end{macrocode} +% \lverb|& +% Attention that \XINT_cclcx_e wants non negative input because \numexpr +% division is not periodical ... +% | +% \begin{macrocode} +\def\XINT_mod_ccclx_jc +#1+#2+#3#4\relax{+80*(#3+#2+#1)+#3#2#1.}% +\def\XINT_mod_ccclx_e#1.{\expandafter\XINT_mod_ccclx_z\the\numexpr(#1+180)/360-1.#1.}% +\def\XINT_mod_ccclx_z#1.#2.{#2-360*#1.}% +% \end{macrocode} +% \subsubsection{\cshn{sind_()}, \cshn{cosd_()}, and support macros \csh{xintSind}, \csh{xintCosd}} +% \lverb|& +% +% sind_() coded directly at macro level with a macro \xintSind (ATTENTION! it +% requires a positive argument) +% which will suitably use \XINT_flexpr_func_sin_ defined from \xintdeffloatefunc +% | +% \begin{macrocode} +\def\XINT_flexpr_func_sind_ #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintSind{\XINT_expr_unlock#3}\endcsname +}% +% \end{macrocode} +% \lverb|& +% Must be f-expandable for nesting macros from \xintNewExpr +% +% ATTENTION ONLY FOR POSITIVE ARGUMENTS +% | +% \begin{macrocode} +\def\xintSind#1{\romannumeral`&&@\expandafter\xintsind + \romannumeral0\XINTinfloatS[\XINTdigits]{#1}}% +\def\xintsind #1[#2#3]% +{% + \xint_UDsignfork + #2\XINT_sind + -\XINT_sind_int + \krof#2#3.#1..%<< attention extra dot +}% +\def\XINT_sind #1.#2.% NOT TO BE USED WITH VANISHING (OR NEGATIVE) #2. +{% + \expandafter\XINT_sind_a + \romannumeral0\xinttrunc{\XINTdigits}{#2[#1]}% +}% +\def\XINT_sind_a{\expandafter\XINT_sind_i\the\numexpr\XINT_mod_ccclx_i0.}% +\def\XINT_sind_int +{% + \expandafter\XINT_sind_i\the\numexpr\expandafter\XINT_mod_ccclx_i +}% +\def\XINT_sind_i #1.% range reduction inside [0, 360[ +{% + \ifcase\numexpr#1/90\relax + \expandafter\XINT_sind_A + \or\expandafter\XINT_sind_B\the\numexpr-90+% + \or\expandafter\XINT_sind_C\the\numexpr-180+% + \or\expandafter\XINT_sind_D\the\numexpr-270+% + \else\expandafter\XINT_sind_E\the\numexpr-360+% + \fi#1.% +}% +% \end{macrocode} +% \lverb|& +% #2 will be empty in the "integer branch". Notice that a single dot "." is +% valid as input to the xintfrac macros. During developing phase I did many +% silly mistakes due to wanting to use too low-level interface, e.g. I would +% use something like #2[-\XINTdigits] with #2 the fractional digits, but there +% maybe some leading zero and then xintfrac.sty will think the whole thing is +% zero due to the requirements of my own core format A[N].... +% +% The "userefunc" auxiliary macros do not pre-expand their arguments (but the +% macros which end up used in other ones defined from \csbxintdeffunc do). +% +% Multiplication is done exactly but anyway currently float multiplication +% goes via exact multiplication after rounding arguments ; as here integer +% part has at most three digits, doing exact multiplication will prove +% not only more accurate but probably faster. +% | +% \begin{macrocode} +\def\XINT_sind_A#1{% +\def\XINT_sind_A##1.##2.% +{% + \expandafter\XINT_flexpr_userefunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% +}% +}\expandafter +\XINT_sind_A\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% +\def\XINT_sind_B#1{\xint_UDsignfork#1\XINT_sind_B_n-\XINT_sind_B_p\krof #1}% +\def\XINT_tmpa#1{% +\def\XINT_sind_B_n-##1.##2.% +{% + \expandafter\XINT_flexpr_userefunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% +}% +\def\XINT_sind_B_p##1.##2.% +{% + \expandafter\XINT_flexpr_userefunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% +}% +}\expandafter +\XINT_tmpa\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% +\def\XINT_sind_C#1{\xint_UDsignfork#1\XINT_sind_C_n-\XINT_sind_C_p\krof #1}% +\def\XINT_tmpa#1{% +\def\XINT_sind_C_n-##1.##2.% +{% + \expandafter\XINT_flexpr_userefunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% +}% +\def\XINT_sind_C_p##1.##2.% +{% + \xintiiopp\expandafter\XINT_flexpr_userefunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% +}% +}\expandafter +\XINT_tmpa\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% +\def\XINT_sind_D#1{\xint_UDsignfork#1\XINT_sind_D_n-\XINT_sind_D_p\krof #1}% +\def\XINT_tmpa#1{% +\def\XINT_sind_D_n-##1.##2.% +{% + \xintiiopp\expandafter\XINT_flexpr_userefunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% +}% +\def\XINT_sind_D_p##1.##2.% +{% + \xintiiopp\expandafter\XINT_flexpr_userefunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% +}% +}\expandafter +\XINT_tmpa\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% +\def\XINT_sind_E#1{% +\def\XINT_sind_E-##1.##2.% +{% + \xintiiopp\expandafter\XINT_flexpr_userefunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% +}% +}\expandafter +\XINT_sind_E\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% +% \end{macrocode} +% \lverb|The cosd_ auxiliary function| +% \begin{macrocode} +\def\XINT_flexpr_func_cosd_ #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintCosd{\XINT_expr_unlock#3}\endcsname +}% +% \end{macrocode} +% \lverb|& +% ATTENTION ONLY FOR POSITIVE ARGUMENTS +% | +% \begin{macrocode} +\def\xintCosd#1{\romannumeral`&&@\expandafter\xintcosd + \romannumeral0\XINTinfloatS[\XINTdigits]{#1}}% +\def\xintcosd #1[#2#3]% +{% + \xint_UDsignfork + #2\XINT_cosd + -\XINT_cosd_int + \krof#2#3.#1..%<< attention extra dot +}% +\def\XINT_cosd #1.#2.% NOT TO BE USED WITH VANISHING (OR NEGATIVE) #2. +{% + \expandafter\XINT_cosd_a + \romannumeral0\xinttrunc{\XINTdigits}{#2[#1]}% +}% +\def\XINT_cosd_a{\expandafter\XINT_cosd_i\the\numexpr\XINT_mod_ccclx_i0.}% +\def\XINT_cosd_int +{% + \expandafter\XINT_cosd_i\the\numexpr\expandafter\XINT_mod_ccclx_i +}% +\def\XINT_cosd_i #1.% +{% + \ifcase\numexpr#1/90\relax + \expandafter\XINT_cosd_A + \or\expandafter\XINT_cosd_B\the\numexpr-90+% + \or\expandafter\XINT_cosd_C\the\numexpr-180+% + \or\expandafter\XINT_cosd_D\the\numexpr-270+% + \else\expandafter\XINT_cosd_E\the\numexpr-360+% + \fi#1.% +}% +% \end{macrocode} +% \lverb|#2 will be empty in the "integer" branch, but attention in general +% branch to handling of negative integer part after the subtraction of 90, +% 180, 270, or 360, and avoid abusing A[N] notation which yes speeds up +% xintfrac parsing but has its pitfalls.| +% \begin{macrocode} +\def\XINT_cosd_A#1{% +\def\XINT_cosd_A##1.##2.% +{% + \expandafter\XINT_flexpr_userefunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% +}% +}\expandafter +\XINT_cosd_A\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% +\def\XINT_cosd_B#1{\xint_UDsignfork#1\XINT_cosd_B_n-\XINT_cosd_B_p\krof #1}% +\def\XINT_tmpa#1{% +\def\XINT_cosd_B_n-##1.##2.% +{% + \expandafter\XINT_flexpr_userefunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% +}% +\def\XINT_cosd_B_p##1.##2.% +{% + \xintiiopp\expandafter\XINT_flexpr_userefunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% +}% +}\expandafter +\XINT_tmpa\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% +\def\XINT_cosd_C#1{\xint_UDsignfork#1\XINT_cosd_C_n-\XINT_cosd_C_p\krof #1}% +\def\XINT_tmpa#1{% +\def\XINT_cosd_C_n-##1.##2.% +{% + \xintiiopp\expandafter\XINT_flexpr_userefunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% +}% +\def\XINT_cosd_C_p##1.##2.% +{% + \xintiiopp\expandafter\XINT_flexpr_userefunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% +}% +}\expandafter +\XINT_tmpa\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% +\def\XINT_cosd_D#1{\xint_UDsignfork#1\XINT_cosd_D_n-\XINT_cosd_D_p\krof #1}% +\def\XINT_tmpa#1{% +\def\XINT_cosd_D_n-##1.##2.% +{% + \xintiiopp\expandafter\XINT_flexpr_userefunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% +}% +\def\XINT_cosd_D_p##1.##2.% +{% + \expandafter\XINT_flexpr_userefunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% +}% +}\expandafter +\XINT_tmpa\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% +\def\XINT_cosd_E#1{% +\def\XINT_cosd_E-##1.##2.% +{% + \expandafter\XINT_flexpr_userefunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% +}% +}\expandafter +\XINT_cosd_E\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% +% \end{macrocode} +% \subsection{\cshn{sind()}, \cshn{cosd()}} +% \begin{macrocode} +\xintdeffloatefunc sind(x) := ifsgn(x, if(x>=-45, sin_(x*oneDegree), -sind_(-x)), + 0, + if(x<=45, sin_(x*oneDegree), sind_(x)));% +\xintdeffloatefunc cosd(x) := ifsgn(x, if(x>=-45, cos_(x*oneDegree), cosd_(-x)), + 1, + if(x<=45, cos_(x*oneDegree), cosd_(x)));% +% \end{macrocode} +% \subsection{\cshn{sin()}, \cshn{cos()}} +% \lverb|& +% For some reason I did not define sin() and cos() in January 2019 ?? +% | +% \begin{macrocode} +\xintdeffloatefunc sin(x):= if(abs(x)<0.79, sin_(x),% + ifsgn(x, -sind_(-x*oneRadian), + 0, + sind_(x*oneRadian)) + );% +\xintdeffloatefunc cos(x):= if(abs(x)<0.79, cos_(x), cosd_(abs(x*oneRadian)));% +% \end{macrocode} +% \subsection{\cshn{sinc()}} +% \lverb|& +% Should I also consider adding (1-cos(x))/x^2 ? +% | +% \begin{macrocode} +\xintdeffloatefunc sinc(x):= + if(abs(x)<0.79, sin_aux(sqr(x)), sind_(abs(x)*oneRadian)/abs(x));% +% \end{macrocode} +% \subsection{\cshn{tan()}, \cshn{tand()}, \cshn{cot()}, \cshn{cotd()}} +% \lverb|The 0 in cot(x) is a dummy place holder, 1/0 would raise an error at +% time of definition...| +% \begin{macrocode} +\xintdeffloatefunc tand(x):= sind(x)/cosd(x);% +\xintdeffloatefunc cotd(x):= cosd(x)/sind(x);% +\xintdeffloatefunc tan(x) := ifsgn(x, if(x>-0.79, sin(x)/cos(x), -cotd(90+x*oneRadian)), + 0, + if(x<0.79, sin(x)/cos(x), cotd(90-x*oneRadian)) + );% +\xintdeffloatefunc cot(x) := if(abs(x)<0.79, cos(x)/sin(x), + ifsgn(x, -tand(90+x*oneRadian), + 0, + tand(90-x*oneRadian)) + );% +% \end{macrocode} +% +% \subsection{\cshn{sec()}, \cshn{secd()}, \cshn{csc()}, \cshn{cscd()}} +% \begin{macrocode} +\xintdeffloatefunc sec(x) := inv(cos(x));% +\xintdeffloatefunc csc(x) := inv(sin(x));% +\xintdeffloatefunc secd(x):= inv(cosd(x));% +\xintdeffloatefunc cscd(x):= inv(sind(x));% +% \end{macrocode} +% \subsection{Core routine for inverse trigonometry} +% \lverb|& +% Compute asin(x) +% +% The approach I shall first describe (which is only a first step towards our +% final approach) converges quintically but requires an initial square root +% computation. However, when used for atan(x), we then do not have to do any +% such square root extraction. See code next. +% +% The algorithm (for this first approach): we have 0 <= t < 0.72, +% let t1 = t*(1+t^2/6). We also have +% u = sqrt(1 - t^2). We seek a = Arcsin t with t = sin(a). +% +% Then t1 < Arcsin t and the difference (we don't know it!) δ_1 is < 0.02. +% We compute D = t*cos(t1)-u*sin(t1). This computation is done "exactly" via +% the \xintexpr encapsulation. In other terms we use doubled precision. +% Anyhow, currently (1.3e) the Float macros of xintfrac.sty for multiplication +% do go via such exact multiplication when the mantissas have the expected +% sizes. So we can't gain but only lose due to catastrophic subtraction in +% using float operations here. +% +% Thus D is sin(a-t1) = sin(δ_1). And δ_1 = Arcsin D, but D is small! +% We then use again two terms of the Arcsin series and define +% t2 = t1 + D * (1 + D^2/6). Let δ_2 = a - t2. Then δ_2 is of the order of +% the neglected term 3*(δ_1)^5/40. +% +% ©copyright J.F. Burnol, March 30, 2019. This surely has a name. +% +% The algorithm is quintically convergent! I must have thought about this some +% many years ago, but I like it a lot and I found it again on March 30, 2019. +% One can do the same to go from exp to log. Basically the idea is that we can +% improve the Newton Method for any function f for which knowing target value +% of f implies one also knows target value of its derivative. In fact I +% obtained the quintic algorithm by combining the Newton formula with the one +% from using f(x)/f'(a) and not f(x)/f'(x) in the update to cancel the two +% quadratic errors. +% +% One iteration (t2) gives about 9 digits, two iterations (t3) 49 digits ! +% And if we want hepta-convergence we only need to use one more term +% of the Arcsin series in the update of the t_n... really this is very nice. +% +% And actually (t2) already gives 30 digits of floating point precision for +% input t<0.1. Let's confirm this: +%( > Digits := 60: +%: > t0 := 0.1; t1 := t0*(1+t0^2/6); u0 := sqrt(1-t0^2); D1 :=t0*cos(t1)-u0*sin(t1); +%: t0 := 0.1 +%: +%: t1 := 0.100166666666666666666666666666666666666666666666666666666667 +%: +%: u0 := 0.994987437106619954734479821001206005178126563676806079117605 +%: +%: -6 +%: D1 := 0.7544948931296072722324333622021201414040837652959011668 10 +%: +%: > t2 := t1 + D1*(1+D1^2/6); +%: t2 := 0.100167421161559796345523179452674980956388959919827205633117 +%: +%: > a := arcsin(0.1); +%: a := 0.100167421161559796345523179452693318568675972229629541391024 +%: > t2/a; +%: 0.999999999999999999999999999999816930374423480281306812814173 +%) +% +% Each iteration costs a computation of one cos and one sine done at the full +% final precision. This is stupid because we should compute at an evolving +% precision, but anyhow this is not our problem anymore as our final algorithm +% is not a loop but it does exactly one iteration for all inputs. As +% examplified above it remains true that we could improve its speed for small +% inputs by using shorter auxiliary series (see below). +% +% In January I used a loop via an iter() construct, with some subs() to avoid +% repeating computations. This can only be done in an \xintNewFunction. Here +% is how it looked after some optimization for the stopping criteria, after +% replacing generic Newton algorithm by a specific quintic one for arcsine: +% +%( \begingroup +%: \edef\x{\endgroup +%: \noexpand\xintNewFunction{asin_l}[2]{% +%: iter(##1*(1+sqr(##1)/6);% +%: $% FIXME : réfléchir au critère d'arrêt. +%: $% +%: $% Je n'utilise pas abs(D) pour un micro-gain est-ce que le risque en vaut la +%: $% chandelle ? (avec abs(D) on pourrait utiliser la fonction avec un #1 négatif) +%: $% +%: $% Am I sure rounding errors could not cause neverending loop? +%: $% Such things should be done with increased precision and rounded at end. +%: subs((D<\ifcase\numexpr2+\XINTdigits-5*(\XINTdigits/5)\relax +%: 3.68\or2.32\or1.47\or0.923\or0.582\fi +%: e-\the\numexpr\XINTdigits/5\relax)% +%: ?{break(@+D*(1+sqr(D)/6))}{@+D*(1+sqr(D)/6)},% +%: D=\noexpand\xintexpr +%: subs(##1*cos_aux(X) - ##2*@*sin_aux(X), X=sqr(@))% +%: \relax +%: ),% +%: i=1++)% dummy iteration index, not used but needed by iter() +%: }}\x +%) +% +% I don't have time to explain the final algorithm below and how the +% transition values were chosen or why (the series below is enough up to 59 +% digits of precision). It does only one iteration, in all cases. Using it for +% arcsine requires a preliminary square root extraction, but for arctangent +% one can arrange things as I did in order to avoid having to compute a square +% root! +% +% +% ©copyright J.F. Burnol, April 5, 2019. This surely has a name. +% +% Certainly I can do similar things to compute logarithms. +% | +% \begin{macrocode} +\xintdeffloatefunc asin_aux(X) := 1 +\ifnum\XINTdigits>3 % actually 4 would achieve 1ulp in place of <0.5ulp + + X(1/6 +\ifnum\XINTdigits>9 + + X(3/40 +\ifnum\XINTdigits>16 + + X(5/112 +\ifnum\XINTdigits>25 + + X(35/1152 +\ifnum\XINTdigits>35 + + X(63/2816 +\ifnum\XINTdigits>46 + + X(231/13312 + )\fi)\fi)\fi)\fi)\fi)\fi;% +\xintdeffloatefunc asin_o(D, T) := T + D*asin_aux(sqr(D));% +\xintdeffloatefunc asin_n(V, T, t, u) :=% V is square of T + asin_o (\xintexpr t*cos_aux(V) - u*T*sin_aux(V)\relax, T);% +\xintdeffloatefunc asin_m(T, t, u) := asin_n(sqr(T), T, t, u);% +\xintdeffloatefunc asin_l(t, u) := asin_m(t*asin_aux(sqr(t)), t, u);% +% \end{macrocode} +% \subsection{\cshn{asin()}, \cshn{asind()}} +% \lverb|& +% Only non-negative arguments t and u for asin_a(t,u), and asind_a(t,u). +% | +% \begin{macrocode} +\xintdeffloatefunc asin_a(t, u) := + if(t<u, asin_l(t, u), Piover2 - asin_l(u, t));% +\xintdeffloatefunc asind_a(t, u):= + if(t<u, asin_l(t, u) * oneRadian, 90 - asin_l(u, t) * oneRadian);% +\xintdeffloatefunc asin(t) := ifsgn(t, -asin_a(-t, sqrt(1-sqr(t))), + 0, + asin_a(t, sqrt(1-sqr(t))));% +\xintdeffloatefunc asind(t) := ifsgn(t, -asind_a(-t, sqrt(1-sqr(t))), + 0, + asind_a(t, sqrt(1-sqr(t))));% +% \end{macrocode} +% \subsection{\cshn{acos()}, \cshn{acosd()}} +% \begin{macrocode} +\xintdeffloatefunc acos(t) := Piover2 - asin(t);% +\xintdeffloatefunc acosd(t):= 90 - asind(t);% +% \end{macrocode} +% \subsection{\cshn{atan()}, \cshn{atand()}} +% \lverb|& +% This involves no square root! +% +% TeX hackers note 1: +% +% The subs( , x = ..) mechanism has no utility in a function definition, +% there is no parallel mechanism at the underlying macros, so in fact +% the substituted things will remain unevaluated if they involve +% indeterminates, so this is exactly like not trying to make things +% more efficient at all. +% +% Currently, the only way is thus to employ auxiliary functions like is done +% next. Contrarily to TeX macros, we must define the functions one after the +% other in the correct order, so the auxiliaries come first. +% +% TeX hackers note 2: +% +% The if(,,) and ifsgn(,,,) tests when used numerically compute all ; but when +% used into a \xintdeffloatefunc, they are converted to macros with basically +% \firstofthree, \secondofthree, \thirdofthree behaviour so then only the +% actually executed branch will do computations. +% +% For numeric computations the ? and ?? operators are used for this effect, +% but they can not be used in \xintdeffloatefunc if the test involves unknown +% variables; as explained above fortunately then if(,,) and ifsgn(,,) work. +% +% radians +% | +% \begin{macrocode} +\xintdeffloatefunc atan_b(t, w, z):=% + 0.5 * if(w< 0, Pi - asin_a(2z * t, -w*z), asin_a(2z * t, w*z));% +\xintdeffloatefunc atan_a(t, T) := atan_b(t, 1-T, inv(1+T));% +\xintdeffloatefunc atan(t):= ifsgn(t,-atan_a(-t, sqr(t)), 0, atan_a(t, sqr(t)));% +% \end{macrocode} +% \lverb|& +% degrees +% | +% \begin{macrocode} +\xintdeffloatefunc atand_b(t, w, z) := + 0.5 * if(w< 0, 180 - asind_a(2z * t, -w*z), asind_a(2z * t, w*z));% +\xintdeffloatefunc atand_a(t, T) := atand_b(t, 1-T, inv(1+T));% +\xintdeffloatefunc atand(t):= ifsgn(t,-atand_a(-t, sqr(t)), 0, atand_a(t, sqr(t)));% +% \end{macrocode} +% \subsection{\cshn{Arg()}, \cshn{atan2()}, \cshn{Argd()}, \cshn{atan2d()}, \cshn{pArg()}, \cshn{pArgd()}} +% \lverb|& +% Arg(x,y) function from -π (excluded) to +π (included) +% | +% \begin{macrocode} +\xintdeffloatefunc Arg(x, y):= + if(y>x, + if(y>-x, Piover2 - atan(x/y), + if(y<0, -Pi + atan(y/x), Pi + atan(y/x))), + if(y>-x, atan(y/x), -Piover2 + atan(x/-y)) + );% +% \end{macrocode} +% \lverb|& +% atan2(y,x) = Arg(x,y) ... (some people have atan2 with arguments reversed +% but the convention here seems the most often encountered) +% | +% \begin{macrocode} +\xintdeffloatefunc atan2(y,x) := Arg(x, y);% +% \end{macrocode} +% \lverb|& +% Argd(x,y) function from -180 (excluded) to +180 (included) +% | +% \begin{macrocode} +\xintdeffloatefunc Argd(x, y):= + if(y>x, + if(y>-x, 90 - atand(x/y), + if(y<0, -180 + atand(y/x), 180 + atand(y/x))), + if(y>-x, atand(y/x), -90 + atand(x/-y)) + );% +% \end{macrocode} +% \lverb|& +% atan2d(y,x) = Argd(x,y) +% | +% \begin{macrocode} +\xintdeffloatefunc atan2d(y,x) := Argd(x, y);% +% \end{macrocode} +% \lverb|& +% pArg(x,y) function from 0 (included) to 2π (excluded) +% I hesitated between pArg, Argpos, and Argplus. Opting for pArg in the end. +% | +% \begin{macrocode} +\xintdeffloatefunc pArg(x, y):= + if(y>x, + if(y>-x, Piover2 - atan(x/y), Pi + atan(y/x)), + if(y>-x, if(y<0, twoPi + atan(y/x), atan(y/x)), + threePiover2 + atan(x/-y)) + );% +% \end{macrocode} +% \lverb|& +% pArgd(x,y) function from 0 (included) to 360 (excluded) +% | +% \begin{macrocode} +\xintdeffloatefunc pArgd(x, y):= + if(y>x, + if(y>-x, 90 - atan(x/y)*oneRadian, 180 + atan(y/x)*oneRadian), + if(y>-x, if(y<0, 360 + atan(y/x)*oneRadian, atan(y/x)*oneRadian), + 270 + atan(x/-y)*oneRadian) + );% +% \end{macrocode} +% \subsection{Synonyms: \cshn{tg()}, \cshn{cotg()}} +% \lverb|These are my childhood notations and I am attached to them. In +% radians only. We skip some overhead here by using a \let at core level.| +% \begin{macrocode} +\expandafter\let\csname XINT_flexpr_func_tg\expandafter\endcsname + \csname XINT_flexpr_func_tan\endcsname +\expandafter\let\csname XINT_flexpr_func_cotg\expandafter\endcsname + \csname XINT_flexpr_func_cot\endcsname +% \end{macrocode} +% \subsection{Let the functions be known to the \cshnolabel{xintexpr} parser} +% \lverb|See xint.pdf for some explanations (as well as code comments in +% xintexpr.sty). In fact it is this context which led to my addition at 1.3e of +% \xintdefefunc to the \xintexpr syntax. | +% \begin{macrocode} +\xintFor #1 in {sin, cos, tan, sec, csc, cot, + asin, acos, atan}\do +{% + \xintdefefunc #1(x) := \xintfloatexpr #1(sfloat(x))\relax;% + \xintdefefunc #1d(x):= \xintfloatexpr #1d(sfloat(x))\relax;% +}% +\xintFor #1 in {Arg, pArg, atan2}\do +{% + \xintdefefunc #1(x, y) := \xintfloatexpr #1(sfloat(x), sfloat(y))\relax;% + \xintdefefunc #1d(x, y):= \xintfloatexpr #1d(sfloat(x), sfloat(y))\relax;% +}% +\xintdefefunc tg(x) := \xintfloatexpr tg(sfloat(x))\relax;% +\xintdefefunc cotg(x):= \xintfloatexpr cotg(sfloat(x))\relax;% +\xintdefefunc sinc(x):= \xintfloatexpr sinc(sfloat(x))\relax;% +% \end{macrocode} +% \lverb|Restore used dummy variables to their status prior to the package reloading. +% On first loading this is not needed naturally, because this is done +% immediately at end of xintexpr.sty.| +% \begin{macrocode} +\xintFor* #1 in {iDTVtuwxyzX}\do{\xintrestorelettervar{#1}}% +% \end{macrocode} +% \StoreCodelineNo {xinttrig} +% \cleardoublepage\let\xinttrignameUp\undefined +%\gardesactifs +%\let</xinttrig>\relax +%\let<*xintlog>\gardesinactifs +%</xinttrig>^^A-------------------------------------------------- +%<*xintlog>^^A--------------------------------------------------- +%^^A -*- coding: utf-8; mode: doctex; fill-column: 78; -*- +% \clearpage\csname xintlognameUp\endcsname +% \section{Package \xintlognameimp implementation} +% \RaisedLabel{sec:logimp} +% \etocarticlestylenomarks +% \etocsetnexttocdepth {subsubsection} +% +% \localtableofcontents +% +% \etocsettocstyle{}{} +% +% I almost included extended precision implementation for 1.3e but +% was a bit short on time; besides I hesitated between using poormanlog +% at starting point or not. For up to 50 digits, it would help reduce +% considerably the needed series for the logarithm. For more digits +% I should rather apply my copyrighted method of the arcsine (it must +% be in literature). +% +% \subsection{Catcodes, \protect\eTeX{} and reload detection} +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode64=11 % @ + \catcode35=6 % # + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \catcode94=7 % ^ + \def\z{\endgroup}% + \def\empty{}\def\space{ }\newlinechar10 + \expandafter\let\expandafter\w\csname ver@xintexpr.sty\endcsname + \expandafter\let\expandafter\x\csname ver@xintlog.sty\endcsname + \expandafter + \ifx\csname PackageInfo\endcsname\relax + \def\y#1#2{\immediate\write-1{Package #1 Info:^^J% + \space\space\space\space#2.}}% + \else + \def\y#1#2{\PackageInfo{#1}{#2}}% + \fi + \expandafter + \ifx\csname numexpr\endcsname\relax + \y{xintlog}{\numexpr not available, aborting input}% + \aftergroup\endinput + \else + \ifx\w\relax % xintexpr.sty not yet loaded. + \y{xintlog}% + {Loading should be via \ifx\x\empty\string\usepackage{xintexpr.sty} + \else\string\input\space xintexpr.sty \fi + rather, aborting}% + \aftergroup\endinput + \else + \ifx\x\relax % first loading (initiated from xintexpr.sty) + \else + \ifx\x\empty % LaTeX first loading, \ProvidesPackage not yet seen + \else + \y{xintlog}{Already loaded, aborting}% + \aftergroup\endinput + \fi + \fi + \fi + \fi +\z% +% \end{macrocode} +% \lverb|Attention to catcode regime when loading below poormanlog. It (v0.04) +% uses ^ with its normal catcode but \XINT_setcatcodes would set it to letter. +% +% This file can only be loaded from xintexpr.sty and it restores catcodes near +% its end. To play it safe and be hopefully immune to whatever is done in +% poormanlog or in xinttrig.sty which is loaded before, we will switch to +% standard catcode regime here. +% +% As I learned the hard way (I never use my user macros), at the worst moment +% when wrapping up the final things for 1.3e release, +% \xintexprSafeCatcodes MUST be followed by some \xintexprRestoreCatcodes +% quickly, else next time it is used (for example by \xintdefvar) the +% \xintexprRestoreCatcodes will restore an obsolete catcode regime...| +% \subsection{Library identification} +% \begin{macrocode} +\xintexprSafeCatcodes\catcode`_ 11 +\XINT_providespackage +\ProvidesPackage{xintlog}% +[2019/04/05 1.3e Logarithms and exponentials for xintexpr (JFB)]% +% \end{macrocode} +% \subsection{Loading of \cshn{poormanlog} package} +% \lverb|Attention to catcode regime when loading poormanlog.| +% \begin{macrocode} +\ifdefined\RequirePackage + \RequirePackage{poormanlog}% +\else + \input poormanlog.tex +\fi +% \end{macrocode} +% \lverb|\XINT_setcatcodes switches to the standard catcode regime of +% xint*.sty files. And we need the xintexpr catcode for ! too. +% +% See remark above about \xintexprRestoreCatcodes.| +% \begin{macrocode} +\xintexprRestoreCatcodes\csname XINT_setcatcodes\endcsname\catcode`\! 11 +% \end{macrocode} +% \subsection{Support macros for natural logarithm and exponential} +% \begin{macrocode} +\def\xintLog#1{\xintMul{\PoorManLogBaseTen{#1}}{23025850923[-10]}}% +\def\XINTinFloatLog#1{\XINTinFloatMul{\PoorManLogBaseTen{#1}}{23025850923[-10]}}% +\def\xintExp#1{\PoorManPowerOfTen{\xintMul{#1}{434294481903[-12]}}}% +\def\XINTinFloatExp#1{\PoorManPowerOfTen{\XINTinFloatMul{#1}{434294481903[-12]}}}% +% \end{macrocode} +% \subsection{The \cshn{log()}, \cshn{exp()}, and \cshn{pow()} function} +% \lverb|The log10() and pow10() are already defined by poormanlog.| +% \begin{macrocode} +\def\XINT_expr_func_log #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintLog{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_flexpr_func_log #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\XINTinFloatLog{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_exp #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\xintExp{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_flexpr_func_exp #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \XINT:NEhook:one\XINTinFloatExp{\XINT_expr_unlock #3}\endcsname +}% +\def\XINT_expr_func_pow #1#2#3% +{% + \expandafter #1\expandafter #2\csname.=% + \expandafter\XINT:NEhook:twosp + \romannumeral`&&@\XINT_expr_unlock #3,!\PoorManPower + \endcsname +}% +\let\XINT_flexpr_func_pow\XINT_expr_func_pow +% \end{macrocode} +% \lverb|We don't worry about setting catcodes as this file is theoretically +% only loadable from xintexpr.sty itself.| +% \StoreCodelineNo {xintlog} +% \cleardoublepage\let\xintlognameUp\undefined +% \MakePercentComment +%</xintlog>------------------------------------------------------ +%<*dtx>----------------------------------------------------------- +\iffalse +% grep -c -e "^{%" xint*sty +xint.sty:190 +xintbinhex.sty:53 +xintcfrac.sty:183 +xintcore.sty:274 +xintexpr.sty:285 +xintfrac.sty:468 +xintgcd.sty:48 +xintkernel.sty:15 +xintlog.sty:5 +xintseries.sty:48 +xinttools.sty:140 +xinttrig.sty:31 +\fi +% grep -o "^{%" xint*sty | wc -l +\def\totala{ 1740} +\iffalse +% grep -c -e "^}%" xint*sty +xint.sty:189 +xintbinhex.sty:52 +xintcfrac.sty:183 +xintcore.sty:271 +xintexpr.sty:312 +xintfrac.sty:470 +xintgcd.sty:50 +xintkernel.sty:16 +xintlog.sty:5 +xintseries.sty:48 +xinttools.sty:139 +xinttrig.sty:32 +\fi +% grep -o "^}%" xint*sty | wc -l +\def\totalb{ 1767} +\cleardoublepage +\section{Cumulative line count} + +\def\mymacro #1{\mymacroaux #1} +\def\mymacroaux #1#2{\strut \csname #1nameimp\endcsname:& \dtt{ #2.}\tabularnewline } +\indent +\begin{tabular}[t]{r@{}r} +\xintApplyInline\mymacro\storedlinecounts +\end{tabular} +\def\mymacroaux #1#2{#2}% +% +\parbox[t]{10cm}{Total number of code lines: + \dtt{\the\numexpr + \xintListWithSep+{\xintApply\mymacro\storedlinecounts}\relax }. + \ifdefined\totala + (but \dtt{\the\numexpr \totala+\totalb\relax} lines among them + start either with \{\% or with \}\%.)\fi + + Each package starts with circa \dtt{50} lines dealing with catcodes, + package identification and reloading management, also for Plain + \TeX\strut. Version {\xintbndlversion} of {\xintbndldate}.\par +} + +\CheckSum {33274}% 1.3e +% 31601 pour 1.3d, 31122 pour 1.3c +% 31069 pour 1.3b, 30482 pour 1.3a, 30621 pour 1.3, 30988 pour 1.2q, +% 30982 pour 1.2p, 30524 pour 1.2o, 30303 pour 1.2h, 30403 pour 1.2i, +% 30750 pour 1.2j, 30677 pour 1.2k, 30931 pour 1.2l, 30439 pour 1.2m, +% 30253 pour 1.2n +\makeatletter\check@checksum +\Finale +%% End of file xint.dtx |