% -*- 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: <11-06-2022 at 19:36:36 CEST>} %</dtx> %<*xintdrv|sourcedrv|alldrv> %% --------------------------------------------------------------- \def\xintdocdate {2022/06/11} \def\xintbndldate{2022/06/10} \def\xintbndlversion {1.4m} %</xintdrv|sourcedrv|alldrv> %<readme>% README %<changes>% CHANGE LOG %<readme|changes>% xint 1.4m %<readme|changes>% 2022/06/10 %<readme|changes> %<readme|changes> Source: xint.dtx 1.4m 2022/06/10 (doc 2022/06/11) %<readme|changes> Author: Jean-Francois Burnol %<readme|changes> Info: Expandable operations on big integers, decimals, fractions %<readme|changes> License: LPPL 1.3c %<readme|changes> %<*!readme&!changes&!dohtmlsh&!makefile> %% --------------------------------------------------------------- %% The xint bundle 1.4m 2022/06/10 %% Copyright (C) 2013-2022 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&!makefile> %<*dtx> \bgroup\catcode2 0 \catcode`\\ 12 ^^Biffalse %</dtx> %<*readme>-------------------------------------------------------- Description =========== It is possible to use the package both with Plain (`\input xintexpr.sty`) or with the LaTeX macro format (`\usepackage{xintexpr}`). The basic aim is provide *expandable* computations on (arbitrarily big) integers, fractions, and floating point numbers (at a user chosen precision). The four operations and the square-root extraction achieve the *correct rounding* for the given arbitrary precision. Exponential (natural and to the base ten), logarithm (also to the base 10), fractional powers, direct and inverse trigonometrical functions are available up to 62 digits of precision. The syntax supports dummy variables (to generate sequences of values) and nested structures. Support for user-declared functions and variables is implemented. Here is an example of everyday typical calculation by `xintexpr` users: \xinteval{reduce(add(1/i^3, i=1..25))} It expands to: 2560976152652211536408111110189/2131858131361319942957376000000 Usage on the command line ========================= One can use `xintexpr` as an interactive calculator on the command line. See the [xintsession](http://ctan.org/pkg/xintsession) package. >>> 2^100; @_1 1267650600228229401496703205376 >>> cos(1); @_2 0.5403023058681397 >>> &fp=32 (/usr/local/texlive/2021/texmf-dist/tex/generic/xint/xintlog.sty) (/usr/local/texlive/2021/texmf-dist/tex/generic/xint/xinttrig.sty) fp mode (log and trig reloaded at Digits=32) >>> cos(1); @_3 0.54030230586813971740093660744298 >>> 3^1000; @_4 1.3220708194808066368904552597521e477 >>> &exact exact mode (floating point evaluations use 32 digits) >>> 3^1000; @_5 132207081948080663689045525975... (trimmed for this README) Installation ============ `xint` is included in [TeXLive](http://tug.org/texlive/) (hence [MacTeX](http://tug.org/mactex/) also) and in [MikTeX](http://www.miktex.org/). Thus, use the package manager to update your distribution. Direct installation of both the macro files and the documentation into a TDS-compliant hierarchy is available via [`xint.tds.zip`](http://mirror.ctan.org/install/macros/generic/xint.tds.zip) and usage of `unzip`. For example, on a macOS system, installation in user repertory: unzip xint.tds.zip -d ~/Library/texmf Admin privileges may be needed if the target repertory requires it. Else, one can download `xint.dtx` from https://www.ctan.org/tex-archive/macros/generic/xint and execute `etex xint.dtx` which will extract all macro files (those with extension `.sty`). One then only needs to move them to a location where `TeX` can find them. To build the documentation one can execute `latex` directly on `xint.dtx` (at least three times, perhaps more, so `latexmk` is recommended) then `dvipdfmx` or directly `pdflatex`. The resulting `xint.pdf` includes both the user manual and the commented source code, with hyperlinks. For those on Unix-like systems the recommended way is to fetch also `Makefile` from the location above (or to rename the extracted `Makefile.mk` into `Makefile`), then one can execute `make xint.pdf` (user manual only), or `make sourcexint.pdf` or `make xint-all.pdf`. These targets will require `latexmk`. Further help can be obtained via `make help` or from the comments in extracted files `xint.tex`, `sourcexint.tex`, and `xint-all.tex`. Documentation ============= `README.md`: this file `CHANGES.html`: change log as relevant to end users (`texdoc --list xint`) `xint.pdf`: user manual `sourcexint.pdf`: commented source code (`texdoc --list xint` or `texdoc sourcexint`) License ======= Copyright (C) 2013-2022 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 files `xint.dtx` and `Makefile` and extracted files inclusive of the macro files `xint*sty` as well as derived documentation files such as `xint.pdf`, `sourcexint.pdf` and `CHANGES.html` See `xint.pdf` for contact information. %</readme>-------------------------------------------------------- %<*changes>------------------------------------------------------- `1.4m (2022/06/10)` ---- The fix of a compatibility bug with `miniltx` and the already in place documentation improvements (in particular, hyperlinked macro names in code lines) motivated release `1.4m`. With some hesitation I decided to not revert the removals and breaking changes listed here and which had been already acted in preparation of an hypothetic future `1.5`. ### Removed - **xintexpr**: `\xintdefefunc` et al., deprecated at `1.4` have been removed. - **xintexpr**: `\thexintexpr` et al., deprecated at `1.4b` have been removed. Use `\xinttheexpr` et al. - **xintlog**: `\poormanloghack` which was a no-op since `1.4e` has been removed. - **xintfrac**: `\xintFrac`, `\xintFwOver`, `\xintSignedFrac`, `\xintSignedFwOver` now raise errors. They were deprecated at `1.4g`, check the documentation for the new names `\xintTeXFrac` et al. ### Breaking changes - **xintexpr**: `\xinttheboolexpr` now outputs `true` or `false` (to match TeX conventions) and not the `True` or `False` employed since `1.4` (inside expressions `true`, `false`, `True` and `False` are all recognized keywords anyhow). - The `\pdfstrcmp/\strcmp` engine primitive is required. With `LuaTeX` it is emulated via `Lua` code basically copied over from `LaTeX3`. Not sure if this is breaking as the package already requires the `\expanded` primitive. Only used so far by (as expected) `\xintiiCmp`, and macros which will end up calling it. ### Bug fixes - **xintexpr**: with `\input xintexpr.sty\relax` in `(pdf)eTeX` plus `miniltx` (naturally, if `miniltx` was already loaded), and with versions up to `1.4k` the `xinttrig` and `xintlog` aborted their own `xintexpr`-triggered input erroneously thinking the latter had not yet been loaded, and emitted only a very discrete message to the log file. With `1.4l` it became worse as `\input xintexpr\relax` auto-repeated itself about six times until `TeX` called it quits. ### Improvements - Documentation: most macros are hyperlinked in the source code to the code line of their definitions. Furthermore, from the place of the definition the main macros will link to either their descriptions in the user manual (in `xint-all.pdf`) or in the implementation part (`sourcexint.pdf`). Conversely inside `xint-all.pdf` the macro descriptions are linked towards their implementation. You may notice some time lag with some pdf viewers on opening the heavily hyperlinked `sourcexint.pdf` compared to previous releases. - Not sure if that counts as an improvement, but I have shortened the wording of the expandable error messages, which had been last modified at `1.4g`. `1.4l (2022/05/29)` ---- ### Bug fixes - **xintkernel**: ever since `1.4`, loading anyone of the `xint*sty` packages left the catcode of the character of ascii code `1` to the internal custom value `3`. - **xintfrac**: the `\xintPFloat` checks for an output being an integer in decimal notation or a number with a one-digit trimmed mantissa could fail if `\xintPFloatMinTrimmed` (added at `1.4k`) was large enough, e.g. equal to the target precision. Then, the outputs always kept trailing zeros, as expected in general but not for those special cases. - **xintlog**, **xinttrig**: since `1.4e` the message emitted if `\usepackage{xintlog}` or `\usepackage{xinttrig}` was encountered in place of the correct `\usepackage{xintexpr}` was wrong. It advised to use `\input xintexpr.sty\relax`, which would have failed with LaTeX. The warning is corrected and now the macro file in place of aborting will (be it with or without LaTeX) trigger the loading of `xintexpr` (hence of itself after it). - The possibility to run `latex` directly on `xint.dtx` had been broken since `1.4i`. ### New features - **xintfrac**: `\xintRawBraced` as a public alias to an **xintfrac** entry point to its core input handler. Experimental additions `\xintSignBit` and `\xintFloatBraced`. Deprecate `\xintTeXfromSci` in favor of new name `\xintTeXFromSci`, and remove its `\expanded` wrapper (so it is not f-expandable anymore). Add `\xintTeXFromScifracmacro`. - **xintfrac**, **xintexpr**: `\xintFracToSci` and `\xintFracToDecimal` now behave like all other **xintfrac** macros in terms of allowed arguments and f-expandability and have been moved back to **xintfrac**. ### Documentation - Renewed random shuffling of large parts of the documentation has greatly improved it. - Simpler build flow to produce a `pdf` containing both user manual and source code. Removal of dependency on `grep` binary for such builds or the one of `sourcexint.pdf`. Fix of various obsoleted comments in extracted files involved in the documentation build process. `1.4k (2022/05/18)` ---- ### Breaking changes - **xintfrac**: the longstanding (but documented as undecided and unstable) way of `\xintFloat` to output the zero value was `0.e0` and it has now been modified into `0.0e0`. Now customizable via `\xintFloatZero`. - **xintfrac**/**xintexpr**: the behaviour of `\xintPFloat` (hence of `\xintfloateval`) has again changed: when the output is an integer (not using scientific notation) it does not get postfixed by `.0`. This applies in particular for the zero value, now printed `0`. Similarly, in the case of scientific notation with a single-digit (trimmed) mantissa, no `.0` is used. Customizable via `\xintPFloatIntSuffix`, `\xintPFloatLengthOneSuffix`, and `\xintPFloatZero`. Also, `\xintPFloat` trims trailing zeros from the full significand only if there are, by default, at least `4` of them, see `\xintPFloatMinTrimmed`. - **xintfrac**/**xintexpr**: macro definition of `\xintFracToSci` migrated from the former to the latter (see `1.4l` for update). - **xintexpr**: `\xintexpr{Safe,Restore}Catcodes` pairs now behave like a "last in first out" stack. Check the `pdf` documentation for details. ### Bug fixes - **xintexpr**: the `\xintexpr{Safe,Restore}Catcodes` were documented at user level, but also used by the package `\xintdefvar` or `\xintdeffunc`. This could result in some bad interaction due to the somewhat strange (but documented) behaviour of nested `\xintexpr{Safe,Restore}Catcodes` (which has now been modified). - **xintexpr**: ever since `1.4`, `\xintdefufunc` (but not `\xintdeffunc`) forgot to reset the catcodes to their status prior to the sanitization done by the macro at the start of its execution. ### New features - **xintfrac**: `\xintPFloatZero`, `\xintPFloatIntSuffix`, `\xintPFloatLengthOneSuffix`, `\xintPFloatNoSciEmax`, `\xintPFloatNoSciEmin` and `\xintPFloatMinTrimmed` customize the output of `\xintPFloat`, hence also of `\xintfloateval` (and of `\xinteval` when scientific notation was used in the expression). Also added `\xintFloatZero`. - **xintfrac**: `\xintFloatToDecimal`. - **xintexpr**: `\xintFracToDecimal`, an alternative to the default `\xintFracToSci` configuration of `\xintexprPrintOne`. - **xintexpr**: long awaited syntax `\xintieval[D]{...}` and `\xintfloateval[Q]{...}` now implemented. The legacy syntax with `\xintieval{[D]...}` and `\xintfloateval{[Q]...}` is kept for backwards compatibility. `1.4j (2021/07/13)` ---- ### Bug fixes - **xinttools**: a brace removal bug affected the venerable `\xintSeq` if producing a single number (e.g. `\xintSeq{10}{10}` expanded to `10` not `{10}`). Thanks to Christophe Poulain for report. `1.4i (2021/06/11)` ---- ### New features - **xintexpr**: the concept of simultaneous assignments is extended: in case of more variables than values the extraneous variables do not cause an error message but are simply set to the `nil` value; in case of more values than variables, the last variable is defined to be the ople concatenating all the extra values. - **xintexpr**: built-in functions usable with arbitrarily many arguments such as `max()`, `gcd()`, or `len()` are now again usable with a single numeric argument: since `1.4` a lone argument had to be a `nutple` (which was automatically unpacked). It can now again be a number. ### Bug fixes - **xintexpr**: simultaneous assignments via `\xintdefvar` to 10 or more variables was broken if the right hand side was an ople (of length at least 10, as it had prior to this release to match the number of variables). - **xintexpr**: the mechanism which allows to define variables with names already in use for pre-existing functions was broken for some built-in functions: those handling syntax with dummy variables (currently `subs()`, `subsm()`, `subsn()`, `seq()`, `add()`, `mul()`, `ndseq()`, `ndmap()`, `ndfillraw()`) and the so-called "pseudo" functions (currently `bool()`, `togl()`, `protect()`, `qint()`, `qfrac()`, `qfloat()`, `qraw()`, `random()`, `qrand()`, `rbit()`). For example the function `seq()` was broken if the user had defined a variable `seq`. `1.4h (2021/05/27)` ---- ### Bug fixes - **xintexpr**: the recent `1.4g` introduced a bug breaking input of the type `<operator><space token><macro>`. - **xintexpr**: since `1.4` (`2020/01/31`) the `omit` and `abort` keywords were broken if used inside a substitution, itself nested in a `seq()` or similar construct. - **xintexpr**: since `1.4c` the `\xintthespaceseparated` (added at `1.4a`) inserted two, not one, spaces at one specific location near the end of its output. A bit cosmetic problem, fixed nevertheless. `1.4g (2021/05/25)` ---- ### Breaking changes - **xintexpr**: the parsing of power operators `**` and `^` now proceeds in a right associative way: `2^3^4==2^(3^4)`. - **xintexpr**: single-character operators `&`, `|`, and `=` (deprecated since `1.1`) have been removed. Use `&&`, `||` and `==` respectively. ### Deprecated - **xintfrac**: old typesetting macros dating back to `1.03` and `1.04` releases `\xintFrac`, `\xintSignedFrac`, `\xintFwOver`, `\xintSignedFwOver` are deprecated. Please use the new names `\xintTeXFrac`, `\xintTeXsignedFrac`, `\xintTeXOver`, `\xintTeXsignedOver`. The old names will emit warnings. ### New features - Messages written to the terminal and log file during the handling of recovery from exceptions use a new mechanism; when in interactive mode, the user is prompted only once, not thrice, to enter `<return>` for recovery and continued processing. - **xintfrac**: `\xintTeXfromSci` (added about 7 or 8 years too late) to help typesetting values output by `\xintfloateval` in a more useful way than `\xintTeXFrac` (formerly `\xintFrac`). ### Bug fixes - **xintexpr**: with **xintbinhex** loaded, `"` is recognized as prefix for hexadecimal input; but a bug (present ever since this support for hexadecimal input was added) caused syntax such as `"\macro` to break the parser. Also, leading zeros such as in `"0000A` where not properly trimmed since `1.2m`. - **xintexpr**: authorize `x! == y` without parentheses. Formerly the parser mis-interpreted `!` as first character of the `!=` not-equal-to comparison operator, subsequently causing breakage when finding the second `=`. - **xintexpr**: various error situations were badly handled. - `\xinteval{1/0}` did not recover gracefully due to longstanding bug in **xintfrac**. - `\xintfloateval{1/0}` did not recover gracefully either... due to some other reason. - recovery from encountering an unknown variable name was broken since `1.4`; also, with an unknown function name if in `\xintfloatexpr`. - `\xinteval{_4}` caused an infinite loop (with underscore `_` having its normal catcode). This was unexpected, as the `_` is documented to be ignored if in-between digits (and is ignored if last after some digits). It will be now ignored also if encountered upfront. A similar problem existed with variable names starting with a `_` (of normal catcode), which however are clearly not legal. The (normal catcode) `_` will then be ignored as well if encountered in front of a variable or function name (but not inside of course). - ``\xinteval{\catcode`@}`` crashed (one had to use an added `\the` or `\number`). - illegal ``\xinteval{/3}`` was not intercepted and ultimately caused low-level errors (same with `^`). Surely, further situations remain where bad input will crash parser. `1.4f (2021/05/10)` ---- ### Breaking changes - **xintexpr**: `\xintieval{[-D]...}`, which rounds to a multiple of `1eD` for `D` positive now *does not insert the trailing zeros* (as done at `1.4e`) *nor a scientific part* `eD` (as prior to `1.4e`). The use case envisioned is for the quantized value to be used with an appropriate unit, for example `k` for `D=3` or `M` for `D=6` etc... Sorry for the very long process which was needed to reach this final decision. - **xintexpr**: for Digits beyond the officially supported range for accurate math functions, i.e. for `D>62`, computations were still done and printed with full number of digits, but the extra digits were meaningless; they now operate on and output mantissas limited to `min(D,64)` digits. - **xintexpr**: for powers `a^b` with Digits at most `8`, the number `a` is now float-rounded to Digits before computation, as is done for `Digits>8`; previously `9` significant digits were kept. - **xintexpr**: further changes in the computation of powers, see the bug fixes below. - **xintexpr**: the `float_()` function got renamed into `float_dgt()`. ### Bug fixes - **xintexpr**: the documentation said `float_()` function had been renamed `float_dgt()` but actually that was not yet the case. - **xintexpr**: powers `a^b` (with exponent `b` neither integer nor half-integer) stopped being accurate regarding the last digits for `|b|` about `1000` and beyond. Except for `0.8<a<1.25` for which accuracy was maintained up to about `|b|=10^7`. Fixed via keeping the same suitable number of extra digits for internal computations of logarithms, independently of whether `a` is close to `1` or not. - **xintexpr**: powers `a^b` in `\xinteval` with `|b|` an integer at least `10000` were paradoxically computed with less accuracy than in `\xintfloateval`... although they were documented to be handled exactly the same in the two parsers. - **xintexpr**: powers `a^b` for Digits at most `8` unconditionally used `log10()/pow10()` approach but due to the limited accuracy of the poorman logarithm (`9` fractional digits) this was inaccurate already for `b` about `100`. So, the handling is now as for Digits at least `9`, i.e. integer and half-integer exponents are handled via the legacy `\xintFloatPower/\xintFloatSqrt` allowing arbitrarily big exponents. It is advised to split big powers with non integer non half integer exponents into a product; this is not done internally to avoid costly overhead for possibly rare use cases. - **xintexpr**: the invalid input `(-1)^2.5` triggered an undefined control sequence error if Digits was at most `8`. `1.4e (2021/05/05)` ---- ### Breaking changes - **xintlog**: `\poormanloghack` now a no-op. - **xinttrig**: loading the package does not define left-over variables holding the values of the inverse factorials used in the sine and cosine series. - **xintexpr**: the output format of `\xinteval`, which uses `\xintFracToSci,` has changed. In particular, if the number has a power of ten part, it is not output with an integer mantissa, but with a scientific mantissa `d.d...` with always at least one digit after the decimal mark (possibly `0`) and trailing zeros are trimmed out. This is the same output format as used for `\xintfloateval`, apart of course from the fact that the mantissa lengths are not limited. - **xintexpr**: the output format of `\xintfloateval`, which uses `\xintPFloat`, changed. The `\xintfloatexprPrintOne` macro has changed its signature to `[#1]{#2}` i.e. its first argument will be within brackets not braces. - **xintexpr**: when using `\xintieval{[D]...}` optional `[D]` with a negative `D`, which triggers quantization to a positive power of ten, the output (if not the zero value) will be an integer with `N=abs(D)` explicit trailing zeros, not an integer mantissa followed by `eN`. - **xintexpr**: `\xinteval` will not compute powers `a^N` exactly if `N` in absolute value is at least the (rounded) quotient of `10000` by the number of digits of `a`; it will then use the logarithm/exponential (in base 10) approach, according to the prevailing Digits setting (at `1.4f` this got modified again and integer exponents large enough to trigger floating point evaluation are handled exactly as in `\xintfloateval`, i.e. using the legacy **xintfrac** `\xintFloatPower`, not the logarithm/exponential approach which loses accuracy for exponents of the order of `100000000` and beyond). - **xintexpr**: `\xintdeffloatvar` now always rounds the assigned value to the target precision. Formerly, inputs actually involving no float operations, such as for example a sub-expression `\xintexpr1/20!\relax` (in contrast to `1/20!`), or an explicit single number having more digits than the precision, got stored "as is" in the defined variable, without pre-rounding to the Digits precision. - **xintfrac**:`\xintPFloat` and `\xintFracToSci` have both been modified. The macro `\xintFracToSciE` does not exist anymore, as `\xintFracToSci` in the case of scientific exponents hands over the process to `\xintPFloat` (without the rounding to Digits, of course). ### New features - **xintlog**: now working up to `62` digits. The legacy faster `poormanlog`-based macros are kept for computations with Digits up to `8`. Fractional powers are now available both in `xinteval` and `xintfloateval`, per default. - **xinttrig**: now working up to `62` digits and with increased accuracy. Special faster (or not as slow if you prefer) mode at `8` digits or less. - **xintexpr**: the constraints on the `\xintexprPrintOne` replacement macro, which defaults to `\xintFracToSci`, have been much simplified. - **xintexpr**: `\xintiexprPrintOne` (defaults to `\xintDecToString`) - **xintfrac**: `\xintPFloatE` may be redefined as a macro which fetches the scientific exponent as a mandatory argument delimited with a dot, and outputs a suitable formatted result (f-expandably), also delimited with a dot which will be removed by internal processing. The default however simply expands to the letter `e`. - **xintfrac**: `\xintDecToStringREZ` is like `\xintDecToString` but starts by removing trailing zeroes. ### Bug fixes - **xintfrac**, **xintexpr**: it was not possible to use `\xinttheDigits` in the right hand side of an `\xintDigits` assignment. For example: `\xintDigits*:=\numexpr\xinttheDigits+4;`. This is now allowed, and the same applies to the macro interface, for example `\xintSetDigits*{\xinttheDigits+4}`. `1.4d (2021/03/29)` ---- ### Breaking changes - `quo()` and `rem()` in `\xintiiexpr/\xintiieval` renamed to `iquo()` and `irem()`. - The output of `gcd()` and `lcm()` as applied to fractions is now always in lowest terms. - The log message to report a variable creation (if `\xintverbosetrue`) does not use (double) quotes anymore around the name. By the way, quotes were never used for function names. ### Bug fixes - Ever since `1.3` the `quo()` and `rem()` functions in `\xintexpr` (not the ones in `\xintiiexpr`) were broken as their (officially deprecated) support macros had been removed! They had somewhat useless definitions anyway. They have now been officially removed from the syntax. Their siblings in `\xintiieval` were renamed to `iquo()` and `irem()`. - Sadly, `gcd()` was broken in `\xintexpr` since `1.4`, if the first argument vanished. And `gcd()` was broken in `\xintiiexpr` since `1.3d` if *any* argument vanished. I did have a unit test! (which obviously was too limited ...) Further, the `\xintGCDof` and `\xintLCMof` **xintfrac** macros were added at `1.4` but did not behave like other **xintfrac** macros with respect to parsing their arguments: e.g. `\xintGCDof{2}{03}` gave an unexpected non-numeric result. - The `first()` and `last()` functions, if used as arguments to numerical functions such as `sqr()` inside an `\xintdeffunc` caused the defined function to be broken. `1.4c (2021/02/20)` ---- ### Bug fixes - Fix `1.4` regression which broke syntax `varname(...)` which supposedly is allowed and inserts a tacit multiplication. `1.4b (2020/02/25)` ---- All changes regard the **xintexpr** module. ### Future - `&`, `|`, (as Boolean operators) and `=` (as equality test) have long been deprecated in favour of `&&`, `||` and `==`. They will be removed at next major release. - At next major release the power operators `**` and `^` will turn from left to right associative. I.e. `2**2**3` will give `256`, not `64`. This is to match with Python and l3fp. - `\thexintexpr` et al. (introduced at `1.2h` but not documented anymore for some time) will be removed at next major release. The original `\xinttheexpr` et al. have always been so much better names. Besides, since `1.4`, `\xintexpr` can be used directly in typesetting flow. ### New features - Function `zip()` is modeled on Python's function of the same name. - Function `flat()` removes all nesting to produce a "one-dimensional" list having the exact same leaves (some possibly empty) as the original (in the same order). - Chaining of comparison operators (e.g. `x<y<z`) as in Python (but all comparisons are done even if one is found false) and l3fp. - It was possible since `1.4`'s `\xintFracToSciE` to configure the separator between mantissas and exponents in the output of `\xinteval` but strangely there was no way to customize the output of `\xintfloateval`. The added `\xintPFloatE` fixes this. ### Bug fixes - `\xintieval{[D]...}` with a negative `D` (a feature added at `1.4a`) used erroneously a catcode 12 `e` in output, which moreover remained immuned to the `\xintFracToSciE` setting. `1.4a (2020/02/19)` ---- All changes regard the **xintexpr** module. ### Breaking changes - The macros implementing customization of `\xintthealign` have modified meanings and names. ### New features - `\xintthespaceseparated` (serves to provide suitable input to PS-Tricks `\listplot`). - The optional argument `[D]` to `\xintieval/\xintiexpr` can be negative, with the same meaning as the non-negative case, i.e. rounding to an integer multiple of `10^(-D)`. The same applies to the functions `trunc()` and `round()`. And to the `\xintTrunc`, `\xintRound`, `\xintiTrunc`, and `\xintiRound` macros of **xintfrac**. ### Bug fixes - Usage of `round()` and `trunc()` within `\xintdeffunc` got broken at `1.4`. - `add()` and `mul()` were supposedly accepting the `omit`, `abort` and `break()` keywords since `1.4` but this was broken. `1.4 (2020/01/31)` ---- ### Breaking changes Please note that this list may still be incomplete. If not otherly specified all items regard the **xintexpr** module. - The `\expanded` primitive (TeXLive 2019) is **required**. This does not affect the macro layer **xintcore**, **xint**, **xintfrac**, **xinttools** (yet). - Formerly square brackets `[...]` were, on their own, not different from parentheses (and thus disappeared from the output), but they are now a genuine constructor of nested lists. For example `\xinteval{1, [2, [3, 4]], 5}` produces `1, [2, [3, 4]], 5` (recall this is free bloatware). - The output of `\xinteval` has changed (besides containing brackets). It does not use anymore the so-called *raw* **xintfrac** format, i.e. things such as `A/B[N]` (which can still be used in input but are discouraged in **xintexpr** context), but scientific notation `AeN/B`. As formerly, the denominator is printed only if `B>1` and the scientific part is dropped if the exponent vanishes. In this way the output of `\xinteval` can be pasted to alternative software. - The output format of `\xinthe\xintboolexpr` also has changed. It uses `True` and `False` (which are accepted on input), and this can easily be configured otherwise (also `true` and `false` are accepted on input). - The "broadcasting" (as it turned out, à la `NumPy`) of scalar operations on one-dimensional "lists", e.g `3*[1,3,5,7]+10` acting itemwise is **dropped**. It is hoped to implement such operations again in stronger form in future releases. Pre-existing alternative syntax is available, also to produce the bracketed (cf. next item) `[13,19,25,31]` which will be the output in future. - The `divmod()` function now produces on output such a bracketed pair, but simultaneous assignment such as `\xintdefvar xq, xr = divmod(a,b);` will work transparently. - The syntax for using conditionals in function declarations has changed. Now, one *must* use the `?` and `??` short-circuit boolean branching operators whereas in the past it was explained that the syntax had to use the `if()` and `ifsgn()` functions. - Macros `\xintGCD`, `\xintLCM`, `\xintGCDof` and `\xintLCMof` formerly provided by **xintgcd** got moved to **xintfrac** (which is not loaded by **xintgcd**). Moreover, they were extended to handle general fractions on input but this also means that their output is now obiding by the raw **xintfrac** format. The integer only `\xintiiGCD`, `\xintiiLCM` also got moved out of **xintgcd**, but to **xint** which is now loaded automatically by **xintgcd**. The few remaining macros of **xintgcd** at least do not need other imports as **xintgcd** now loads also automatically **xinttools** which is a dependency for two of them. ### Improvements and new features Please note that this list is currently incomplete. For more information look at the user manual and the documented source code `sourcexint.pdf`. Unless otherwise specified all changes commented upon here regard **xintexpr**. Important: all the new syntax is to be considered experimental. The author may change some names in future release, or even the interface (whether to use semi-colons or colons etc...). - The `\csname` encapsulation technique used since **xintexpr** initial release (`1.07 2013/05/25`) to move around possibly large data during expansion-only operations is replaced with methods based on the `\expanded` engine primitive. The latter is available in all major engines since TeXLive 2019. Formerly, and with default memory settings, one would typically saturate the string pool memory after about of the order of 50,000 independent floating point evaluations of expressions of average complexity on 16-digits numbers. There is thus no string pool memory impact at all but one can now hit TeX's main memory limit (which typically stands at 5,000,000 words) from defining large variables or generating on the fly large data. TeX distributions have a configuration file allowing to enlarge TeX memory parameters and regenerate the (eTeX based) formats. - The package supports input and output of arbitrarily *nested lists*, a.k.a. *oples* or *nlists*, with `[...]` as the constructor of *bracketed lists*, a.k.a *nut-ples*. Operations on these objects (as briefly surveyed in later items) are inspired from syntax and functionalities of `NumPy`'s *ndarrays*. Our *oples* (hence also their packaged form *nut-ples*) may have *leaves* at varying depths rather than obeying an N-dimensional hyperrectangular shape. But the syntax does provide specific constructors for *ndlists* (i.e. hyperrectangular *oples* or *nut-ples*). In a (distant?) future, perhaps **xintexpr** itself or a third-party package will provide an interface, say `\xintstorearray`, `\xintgetarray`, to store (which can not be expandable) and retrieve (which can be expandable and thus be embedded inside expressions parsed by `\xintexpr`, `\xintiiexpr` or `\xintfloatexpr`) such *ndlists* from TeX memory. This is why the package does not use the word *ndarray* and reserves it for such memory stored objects. - The `*` serves as *unpacking* operator on *nut-ples*, i.e. reversing the `[]` bracketing of an *ople*. - *oples* have no exact equivalent in `Python`. For example **xintexpr** allows `foo(Var1, x)` if `foo` is a function of 4 variables and `Var1` is a variable producing a length 3 *ople*, or `foo(Var2)` if `Var2` is a variable producing a length 4 *ople*. Python would require here to use explicitly the `*`-unpacking notation on some "packed" objects. Variable and function values may be *oples* (even *nil*), but in function declarations variables must stand for *one-ples*, i.e. either *numbers* or *nut-ples* (as there is no non-ambiguous way to split e.g. 5 arguments into two separate *oples*). - Simultaneous assignment to at least two variables via `\xintdefvar` et al. automatically unpacks the assigned value if it is a *one-ple*. If this value was in fact a *number*, low-level errors will result shortly afterwards as no check is done if the unpacking was illicit. (update: this last remark does not apply since the `1.4i` extension to the concept of simultaneous assignments) - The `NumPy` concept and syntax for nested slicing and item selection are implemented. Currently *stepping* and the *Ellipsis object* are not yet available. Only so-called basic slicing is currently supported. (The author has not yet read the section of `NumPy` documentation on so-called *advanced indexing*). - The *broadcasting* of scalar operations, such as itemwise addition or multiplication of *nut-ples* of the same shape is **not yet implemented**. - Slicing and indexing apply also at top level to the *oples* with behaviour conforming to intuitive expectations (see user manual); if it turns out the *ople* is in fact a *nut-ple*, the top-level slicing/indexing switches to the `Python/NumPy` conventions, i.e. it operates inside the brackets for slicing and removes brackets if indexing. - The syntax `ndseq(expression in x, y, ..., x = values; y = values; ...)` constructs a (bracketed) *ndlist* by evaluation the expression on all possible Cartesian n-uples, where the first variable indexes the first axis, the second the next, etc... - The `ndmap(foo, values1; values2; ...; valuesN)` syntax constructs a (bracketed) *ndlist* by evaluating the function `foo` on all elements of the cartesian product of the given (one-dimensional) value lists. - The two concepts of `\xintdeffunc` (for recursive definitions) and `\xintdefefunc` (for functions which expand immediately in other function declarations) have been merged. The `\xintdefefunc` et al. are deprecated and kept as aliases for `\xintdeffunc` et al. - `\xintdefufunc` allows to define so-called *universal functions*, i.e. functions `foo` such that `foo(myople)` will apply itemwise at arbitrary depth in the nested structure. The function `foo` is allowed to produce from a scalar an *ople*... - The variables in function declarations can now be multi-letter words. - The last positional variable in a function declaration can be prefixed with a `*` meaning exactly as in Python (*variadic* function argument) that it stands for a one-dimensional *nut-ple* receiving all remaining arguments from the function call beyond the first positional ones. It is thus an optional argument, but syntax for named optional arguments with default values is not yet implemented. - Dummy variables used in constructors can also be multi-letter words, if they have been declared as such. - In variable and function declarations, if the expression contains inner semi-colons, it is not needed anymore to brace them to avoid mis-interpretation as the final semi-colon which is mandated by the syntax to serve as expression terminator. - `subsm(expression, var1 = value1; var2 = value2; ...)` provides a leaner syntax for multiple substitutions; they must be independent, though. - `subsn(expression, var1 = value1; var2 = value2; ...)` provides a leaner syntax for nested substitutions, i.e., each `valueJ` may be an expression using the dummy variables `varK` with `K>J`. And finally of course the evaluated expression can refer to all variables. - `\xintthealign\xintexpr...\relax` (or with `\xintfloatexpr` or `\xintiiexpr` or `\xintboolexpr`...) will use a TeX alignment to display *oples*. The output (for regular N-dimensional lists) looks very similar to what `Python/NumPy` produces in interactive session. This is entirely configurable and can also be set-up to be used for writing into external files. Attention that `\xintthealign` only works if followed by `\xintexpr` et al., not by `\xinteval{}`. - It is now possible to use `\xintexpr...\relax` directly for typesetting. The syntax `\xinteval{...}` or `\xintthe\xintexpr...\relax` is needed only if one wants the expansion to give the explicit digits, but `\xintexpr...\relax` by itself will typeset as would have the other ones. Further it can be used in so-called moving arguments, because when output to an external file it uses only characters with standard catcodes (and produces the same protected and re-tokenizable result it would in an `\edef`.) As formerly, `\xintexpr...\relax` is the preferred way to include an expression into another one. Using `\xinteval` is a waste because it forces the outer parser to re-digest all the digits (or now also the square brackets). - The output format of `\xintfloateval` with scientific notation has not changed (apart from possible presence of bracketed lists), but the author hesitates because the *prettifying* it does by default is not really adapted to display of arrays (see `\xintthealign`). Anyway, this is configurable by the user. It is possible to specify whether to use `e` or `E`. - Function declarations are able to parse a much wider part of the syntax, but some severe limitations remain. Refer to the user manual for related information. - We have made an effort on some error messages, and when working interactively in a shell it may even be sometimes possible to insert for example a correct variable or function name in place of the not recognized one. But don't expect miracles when trying to intervene in the midst of a purely expandable expansion... ### Bug fixes Bugs? Those identified in `1.3f` were almost features. As per `1.4` the code base of **xintexpr** received multiple successive core refactorings and added numerous new features, and our test suite although significantly enlarged is not yet extensive enough. Please report bugs by mail. ### TODO - The long delayed overhaul of how floating point numbers are handled is delayed again. It has remained basically identical to its initial provisory version from `1.07 2013/05/25` (which was based upon what was originally only a set of expandable macros for computations with big integers), and suffers from the author lack of knowledge of the notion of "data type" in modern programming. Indeed, he never took a CS class, and disables JavaScript in his browser (or allows only select non-tracking scripts, a rare beast in modern days). - Prior to integrating all of `NumPy`, it is envisioned to start with matrix algebra first. `1.3f (2019/09/10)` ---- ### Improvements and new features - **xintfrac**: `\xintDigits = P;` syntax (i.e. without a colon) is now accepted in addition to `\xintDigits := P;`. Document that the ending semi-colon can not be an active character and that it has always been allowed to use in its place a non-expanding token e.g. `\xintDigits := 32\relax`. Add `\xintSetDigits`. - **xintexpr**: add starred variants `\xintDigits*` and `\xintSetDigits*` which execute `\xintreloadxinttrig`. Revert 1.3e ban on usage of `\xinteval` et al. inside expressions by `\xintdeffunc`. And make them usable also inside macro definitions via `\xintNewExpr`. ### Bug fixes - **xintexpr**: fix bug preventing usage of `\xintdefefunc` to define a function without variables. Fix some issue with `\xintfloatexpr[D]..\relax` if used inside an expression parsed by `\xintdeffunc` et al. `1.3e (2019/04/05)` ---- ### Breaking changes - (_reverted at 1.3f_) When defining functions, sub-expressions can only use the `\xint(float)expr...\relax` syntax. One can not use there the `\xint(float)eval` wrappers. ### 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)` ---- ### Breaking 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)` ---- ### Breaking 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)` ---- ### Breaking 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)` ---- ### Breaking 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)` ---- ### Breaking 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)` ---- ### Breaking 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)` ---- ### Breaking 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)` ---- ### Breaking 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)` ---- ### Breaking 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)` ---- ### Breaking 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)` ---- ### Breaking 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>------------------------------------------------------ %<*dates>------------------------------------------------------- `1.4m (2022/06/10)` `1.4l (2022/05/29)` `1.4k (2022/05/18)` `1.4j (2021/07/13)` `1.4i (2021/06/11)` `1.4h (2021/05/27)` `1.4g (2021/05/25)` `1.4f (2021/05/10)` `1.4e (2021/05/05)` `1.4d (2021/03/29)` `1.4c (2021/02/20)` `1.4b (2020/02/25)` `1.4a (2020/02/19)` `1.4 (2020/01/31)` `1.3f (2019/09/10)` `1.3e (2019/04/05)` `1.3d (2019/01/06)` `1.3c (2018/06/17)` `1.3b (2018/05/18)` `1.3a (2018/03/07)` `1.3 (2018/03/01)` `1.2q (2018/02/06)` `1.2p (2017/12/05)` `1.2o (2017/08/29)` `1.2n (2017/08/06)` `1.2m (2017/07/31)` `1.2l (2017/07/26)` `1.2k (2017/01/06)` `1.2j (2016/12/22)` `1.2i (2016/12/13)` `1.2h (2016/11/20)` `1.2g (2016/03/19)` `1.2f (2016/03/12)` `1.2e (2015/11/22)` `1.2d (2015/11/18)` `1.2c (2015/11/16)` `1.2b (2015/10/29)` `1.2a (2015/10/19)` `1.2 (2015/10/10)` `1.1c (2015/09/12)` `1.1b (2015/08/31)` `1.1a (2014/11/07)` `1.1 (2014/10/28)` `1.09n (2014/04/01)` `1.09m (2014/02/26)` `1.09kb (2014/02/13)` `1.09k (2014/01/21)` `1.09j (2014/01/09)` `1.09i (2013/12/18)` `1.09h (2013/11/28)` `1.09g (2013/11/22)` `1.09f (2013/11/04)` `1.09e (2013/10/29)` `1.09d (2013/10/22)` `1.09c (2013/10/09)` `1.09b (2013/10/03)` `1.09a (2013/09/24)` `1.08b (2013/06/14)` `1.08a (2013/06/11)` `1.08 (2013/06/07)` `1.07 (2013/05/25)` `1.06b (2013/05/14)` `1.06 (2013/05/07)` `1.05 (2013/05/01)` `1.04 (2013/04/25)` `1.03 (2013/04/14)` `1.0 (2013/03/28)` %</dates>------------------------------------------------------ %<*makefile>------------------------------------------------------ # This file: Makefile.mk (generated from xint.dtx) # "make --file=Makefile.mk help" # Starting with xint 1.3c, Latexmk is used for easier compilation of # sourcexint.pdf as the latter then included indices. These indices # got removed at 1.3e but usage of Latexmk is maintained for the build. # 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 It is recommended to work with xint.dtx and Makefile moved to some otherwise empty temporary repertory. make help displays this help using the more pager. make helpless displays this help using the less pager. make doc produces all documentation, requires Latexmk and Pandoc. make all produces all documentation, then creates xint.tds.zip. make xint.tds.zip same as "make all" make xint.pdf extracts files and produces xint.pdf (user manual), using latex and dvipdfmx. Requires Latexmk. make sourcexint.pdf extracts files and produces sourcexint.pdf (source code), using latex and dvipdfmx. Requires Latexmk. make xint-all.pdf extracts files and produces xint-all.pdf (manual + code), using latex and dvipdfmx. Requires Latexmk. make CHANGES.html requires Pandoc. make clean removes auxiliary files and repertories. make cleanall removes all files, leaving only xint.dtx (and Makefile). ==== INSTALLING The following has been tested on a TeXLive installation: make installhome creates xint.tds.zip, and unzips it in <TEXMFHOME> make installlocal creates xint.tds.zip, unzips it in <TEXMFLOCAL> and then does texhash <TEXMFLOCAL> Depending on access rights "sudo make installlocal" might be needed. In case of doubt run first "make doc" then "make installlocal". If the latter fails, then try "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> Might need "sudo". endef .PHONY: help helpless all doc 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. Notice that if "make -f Makefile.mk" is executed, this will # actually extract again Makefile.mk which will be overwritten but this # does not seem to be problematic. extracted = $(packages) xint.tex sourcexint.tex xint-all.tex\ README.md CHANGES.md xint-dates.txt doHTMLs.sh filesfortex = $(packages) filesforsource = xint.dtx Makefile filesfordoc = xint.pdf sourcexint.pdf README.md CHANGES.html auxiliaryfiles = xint.dvi xint.aux xint.toc xint.log\ sourcexint.dvi sourcexint.aux sourcexint.toc sourcexint.log\ xint-all.dvi xint-all.aux xint-all.toc xint-all.log all: $(extracted) doc xint.tds.zip @echo 'make all done.' $(extracted): xint.dtx etex xint.dtx doc: xint.pdf sourcexint.pdf CHANGES.html @echo 'make doc done.' xint.pdf: xint.dtx xint.tex latexmk xint.tex dvipdfmx xint.dvi sourcexint.pdf: xint.dtx sourcexint.tex latexmk sourcexint.tex dvipdfmx sourcexint.dvi xint-all.pdf: xint.dtx xint-all.tex latexmk xint-all.tex dvipdfmx xint-all.dvi CHANGES.html: CHANGES.md 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)\ xint-all.fls xint-all.fdb_latexmk\ sourcexint.fls sourcexint.fdb_latexmk\ xint.fls xint.fdb_latexmk cleanall: clean rm -f $(extracted) CHANGES.html xint-dates.txt \ xint.pdf sourcexint.pdf xint-all.pdf xint.tds.zip xint.zip Makefile.mk %</makefile>$----------------------------------------------------- %<*dohtmlsh>------------------------------------------------------ #! /bin/sh # <s>README.html and</s> CHANGES.html from <s>README.md and </s>CHANGES.md # tested with pandoc 1.13.1 # updated 2022 for usage with pandoc 2.18 and its strange CSS obsessed by mobile devices # 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: 0; margin-left : 10%; margin-right : 15%; margin-top: 4ex; font-size: 20px; font-family: serif; max-width: 100%; padding: 0; } pre {white-space: pre-wrap;} code {white-space: pre-wrap;} a:link { color: blue; } a:visited { color: green; } a:hover { text-decoration: underline; color: hotpink } a:active { color: brown; } #TOC {float: right; position: relative; top: 100px; margin-bottom: 100px; margin-left: 20px;}' CHANGES.md %</dohtmlsh>------------------------------------------------------ %<*xintdrv>----------------------------------------------------------- %% To extract files: %% (but this is probably already done as you read this one) %% etex xint.dtx %% %% Then execute: %% make --file=Makefile.mk xint.pdf %% %% Alternative for build without `make': %% latexmk xint.tex %% dvipdfmx xint.dvi %% %% One can also tell latexmk to use xelatex or pdflatex. %% Or use one of them directly enough times on xint.tex. %% %% To produce the documented source code sourcexint.pdf: %% make --file=Makefile.mk sourcexint.pdf %% (check sourcexint.tex for alternatives to `make') %% %% To produce xint-all.pdf with both user doc and source code: %% make --file=Makefile.mk xint-all.pdf %% (check xint-all.tex for alternatives to `make') \NeedsTeXFormat{LaTeX2e} \ProvidesFile{xint.tex}% [\xintbndldate\space v\xintbndlversion\space xint documentation (JFB)]% \PassOptionsToClass{a4paper,fontsize=10pt}{scrartcl} \chardef\NoSourceCode 1 \input xint.dtx %%% Local Variables: %%% mode: latex %%% TeX-PDF-from-DVI: "Dvipdfmx" %%% End: %</xintdrv>----------------------------------------------------------- %<*sourcedrv>----------------------------------------------------------- %% To extract files: %% (but this is probably already done as you read this one) %% etex xint.dtx %% %% Then execute: %% make --file=Makefile.mk sourcexint.pdf %% %% Alternative for build without `make': %% latexmk sourcexint.tex %% dvipdfmx sourcexint.dvi %% %% One can intruct latexmk (see its documentation) to use xelatex %% or pdflatex, or use them directly on sourcexint.tex. \NeedsTeXFormat{LaTeX2e} \ProvidesFile{sourcexint.tex}% [\xintbndldate\space v\xintbndlversion\space xint commented code (JFB)]% \PassOptionsToClass{a4paper,fontsize=10pt}{scrartcl} \chardef\NoSourceCode=0\chardef\dosourcexint=1 \input xint.dtx %%% Local Variables: %%% mode: latex %%% TeX-PDF-from-DVI: "Dvipdfmx" %%% End: %</sourcedrv>----------------------------------------------------------- %<*alldrv>----------------------------------------------------------- %% To extract files: %% (but this is probably already done as you read this one) %% etex xint.dtx %% %% Then execute: %% make --file=Makefile.mk xint-all.pdf %% %% Alternative for build without `make': %% latexmk xint-all.tex %% dvipdfmx xint-all.dvi %% %% One can intruct latexmk (see its documentation) to use xelatex %% or pdflatex, or use them directly on xint-all.tex. %% %% Another way is to run latex (enough times, then dvipdfmx) or %% pdflatex directly on source file xint.dtx. The produced xint.pdf %% will then combine user manual and commented source code. \NeedsTeXFormat{LaTeX2e} \ProvidesFile{xint-all.tex}% [\xintbndldate\space v\xintbndlversion\space xint user plus source doc (JFB)]% \PassOptionsToClass{a4paper,fontsize=10pt}{scrartcl} \chardef\NoSourceCode=0 \input xint.dtx %%% Local Variables: %%% mode: latex %%% TeX-PDF-from-DVI: "Dvipdfmx" %%% End: %</alldrv>----------------------------------------------------------- %<*dtx>----------------------------------------------------------- ^^Bfi^^Begroup \chardef\noetex 0 \ifx\numexpr\undefined\chardef\noetex 1 \fi % changed 2021/05/30: do not extract files at all if not using etex \ifnum\noetex=1 \chardef\extractfiles 3 % no extract, no typeset \else \ifx\PassOptionsToClass\undefined \chardef\extractfiles 0 % no LaTeX2e: probably 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}{scrartcl}% \else % latex/pdflatex/xelatex on xint.tex or sourcexint.tex or xint-all.tex \chardef\extractfiles 2 % no extractions, but typeset \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{* Rename Makefile.mk to Makefile if the latter is absent^^J}% \Msg{* (or use --file=Makefile.mk option of "make")^^J}% \Msg{* then "make help" will provide information.^^J}% \Msg{* In particular:^^J}% \Msg{* - the "doc" target builds xint.pdf and sourcexint.pdf,^^J}% \Msg{* - the "xint.tds.zip" target additionally prepares a TDS-compliant^^J}% \Msg{*\space\space\space archive.^^J}% \Msg{* Building with "make" requires "Latexmk".^^J}% \Msg{* The target "CHANGES.html" requires "Pandoc".^^J}% \Msg{*^^J}% \Msg{* Instructions for builds without "make" are in file xint.tex.^^J}% \Msg{*^^J}% \Msg{* Happy TeXing!^^J}% \Msg{*^^J}% \Msg{********************************************************************^^J}% }% \ifx\XeTeXinterchartoks\undefined\else \expandafter\def\expandafter\MessageDeFin\expandafter{\MessageDeFin \Msg{* ATTENTION! extraction with xetex must be made with -8bit option.^^J}% \Msg{* Extracted file Makefile.mk is invalid if this was not the case.^^J}% \Msg{********************************************************************^^J}% }% \fi \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}} \file{xint-dates.txt}{\from{xint.dtx}{dates}} % pure tex will use ^^I notation for TAB character, don't want that. % anyway, since 2021/05/30, tex xint.dtx has been made a no-op. % there is a problem with xelatex, it generates ^^I if not with -8bit \file{Makefile.mk}{\from{xint.dtx}{makefile}} \file{doHTMLs.sh}{\from{xint.dtx}{dohtmlsh}} \usepreamble\defaultpreamble \usepostamble\defaultpostamble \file{xint.tex}{\from{xint.dtx}{xintdrv}} \file{sourcexint.tex}{\from{xint.dtx}{sourcedrv}} \file{xint-all.tex}{\from{xint.dtx}{alldrv}} \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 \ifnum\extractfiles=1 % direct run on xint.dtx \expandafter\def\expandafter\MessageDeFin\expandafter{\MessageDeFin \Msg{* Direct (*)latex run on xint.dtx: repeat as necessary. *^^J}% \Msg{********************************************************************^^J}% }% \fi \ifnum\extractfiles=3 % \newlinechar10 \errhelp{Extraction must be done via an engine with e-TeX extensions.^^J% Please try again, using etex rather.^^J% (if with xetex, use -8bit option).}% \errmessage{Extraction aborted (must be done with etex)}% \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 %----------------------------------------------------------------- % \makeatletter % counts used in particular in the samples from the documentation of the % xintseries.sty package \newcount\cnta \newcount\cntb \newcount\cntc \ifdefined\dosourcexint \chardef\NoSourceCode 0 \else \chardef\dosourcexint 0 \fi % \dosourcexint=1 means producing only source code. % It is set in sourcexint.tex. Prior to 1.4l it was % set in the call with latexmk + \input syntax. % % \dosourcexint=0 and \NoSourceCode=1 : include only user doc % \dosourcexint=0 and \NoSourceCode=0 : combine user doc and source code % \dosourcexint=1 and \NoSourceCode=1 : never happens but would mean to do % nothing! % default is to assume latex + dvipdfmx \chardef\Withdvipdfmx 1 \RequirePackage{ifpdf} \RequirePackage{ifxetex} \ifpdf \chardef\Withdvipdfmx 0 \fi \ifxetex\chardef\Withdvipdfmx 0 % they are used at some locations in this doc \let\pdfsetrandomseed\setrandomseed \let\pdfuniformdeviate\uniformdeviate \let\pdfresettimer\resettimer \let\pdfelapsedtime\elapsedtime \fi % 2019/09/10 % Get rid of HARASSMENT by KOMA-Script % Must be located before \documentclass \def\class@shoulddisablepackagewarning@list{tocloft.} \ifnum\Withdvipdfmx=1 \def\pgfsysdriver{pgfsys-dvipdfm.def} \documentclass [dvipdfm, dvipdfmx, dvipdfmx-outline-open]{scrartcl} \else \documentclass {scrartcl} \fi %%% START OF CUSTOM doc.sty LOADING (May 21, 2022) % % For some legacy reason (because I started like this and it % worked to my satisfaction) I had used scrdoc.cls all those % years, without in fact needing most of its features. % % It loads ltxdoc class, from which again I need very little. On % testing May 20, 2022 the upcoming LaTeX 2022-06-01 I had some % problems with ltxdoc not having suitable interface for rolling % back to doc=V2. % % I did experiment with indices for sourcexint.pdf from 2018 to % 2019 but it made the build process significantly lengthier, % created heavy-sized PDF, had various issues in my context % (possibly the kind of issues doc V3 addresses about indexing % non-macro things, hyperlinks,...), and these indices basically % had not any real use as PDF search proves efficient enough, % and the structures of local tables of contents makes for % agreeable enough navigation via the input mark-up using % sectioning commands. % % Thus it turns out I need very little of doc.sty, and almost % nothing of ltxdoc.cls and scrdoc.cls. % % Let's load the doc=V2 version to avoid having to work around % hypdoc loading interfering with my use of hyperref and as said % above I don't need the hyperlinked cross-referencing as I have % it via my own mark-up to a sufficiently good enough extent, % and this holds for many many years. And I will not now change % my mark-up. \ifdefined\IfFormatAtLeastTF \IfFormatAtLeastTF{2022/06/01}% {% \IfFileExists{doc-2021-06-01.sty}% {\usepackage{doc}[=v2]}% % Why on earth do I lose my time doing this? {\GenericError {(xint build doc)\@spaces}% {xint build error: % Your LaTeX installation seems to be broken, format is\MessageBreak 2022-06-01 or later but `doc' package in its `v2' version\MessageBreak seems to not be available. \space Will try with `doc' but if\MessageBreak its `v3' is used there will be an option clash error\MessageBreak regarding hyperref.}% {}% {Please make sure `doc' package matches your LaTeX format.}% \usepackage{doc}% }% }% {\usepackage{doc}}% \else \usepackage{doc} \fi %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % MACROS OF doc.sty WILL BE HACKED (2022/06/06) FOR THE IMPLEMENTATION PART % % First we want to turn CodelineNo into a real LaTeX counter % This will spare defining an extra counter for the hyperlinks with \hyperref \begingroup\let\newcount\@gobble\@definecounter{CodelineNo}\endgroup % Let's now reenact the doc.sty default for \theCodeLineNo \def\theCodelineNo{\reset@font\scriptsize\arabic{CodelineNo}} % But as we will reset CodelineNo at each style file we need some unique id \def\theHCodelineNo{\the\value{section}.\the\value{CodelineNo}} % This is all for now. % The further hacks are to be found after the \StopEventually (i.e. a few % thousands lines down from here if you don't have access to the private % sources, which is probably the case if you are not the author). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % As explained above I was formerly using scrdoc hence ltxdoc indirectly. % Let's emulate here the little I appear to need from ltxdoc.cls and % srcdoc.cls. % \AtBeginDocument{\MakeShortVerb{\|}} \DeclareFontShape{OT1}{cmtt}{bx}{n}{<-> ssub * cmtt/m/n}{} \DeclareFontFamily{OMS}{cmtt}{\skewchar\font 48} % '60 \DeclareFontShape{OMS}{cmtt}{m}{n}{<-> ssub * cmsy/m/n}{} \DeclareFontShape{OMS}{cmtt}{bx}{n}{<-> ssub * cmsy/b/n}{} \DeclareFontShape{OT1}{cmss}{m}{it}{<->ssub*cmss/m/sl}{} \ifnum\NoSourceCode=1 \OnlyDescription \fi \CodelineNumbered \EnableCrossrefs % but this will be hacked % \setcounter{StandardModuleDepth}{1} % we don't use this mechanism currently \def\cmd#1{\cs{\expandafter\cmd@to@cs\string#1}} \def\cmd@to@cs#1#2{\char\number`#2\relax} % Here I am loading doc=v2 but formerly I was using ltxdoc via scrdoc % which I dropped at release 1.4l (2022-05-29) and without much % thinking I had kept this. \DeclareRobustCommand\cs[1]{\texttt{\bslash#1}} % As I may have the * active, or macro names with _ or ^, I should % add \detokenize. But see below for a redefinition anyhow. % % More urgent is that I am also using hyperref and this definition gives wrong % bookmarks if \cs is used in section titles. As I had very very few usags of % \cs in the whole of xint.dtx, it took me a while to realize the problem % here. Turns out that doc=v3 by default loads hypdoc which includes this % configuation for hyperref compatibility: \AtBeginDocument{% \pdfstringdefDisableCommands{\def\cs#1{\textbackslash\detokenize{#1}}}% }% % As I have not loaded hyperref yet I must delay it to AtBeginDocument. % Late May, early June 2022 I added to my custom \verb automated detection % of potential hyperlinks. So I decided to replace \cs ltxdoc definition % by suitable \verb usage. It is not important to be efficient here, % I can leave some \expandafter, in fact there are a handful of uses. \DeclareRobustCommand\cs[1]{\expandafter\verb\expandafter~\bslash#1~} % As my \verb does a verbatimizing \scantokens I don't need to worry % here about active characters but I need in the PDF string, hence % the \detokenize above. \providecommand\marg[1]{% {\ttfamily\char`\{}\meta{#1}{\ttfamily\char`\}}} \providecommand\oarg[1]{% {\ttfamily[}\meta{#1}{\ttfamily]}} \providecommand\parg[1]{% {\ttfamily(}\meta{#1}{\ttfamily)}} % \@addtoreset{CodelineNo}{part}% No need for this here % \def\partname{File}% \partname is "fixed" somewhere further down anyhow % No need for this, anyhow I don't build the indices (I did in 2018-2019 only). % \gdef\codeline@wrindex#1{\if@filesw % \begingroup % \let\protect\noexpand % \immediate\write\@indexfile % {\string\indexentry{#1}% % {\filesep\number\c@CodelineNo}}% % \endgroup\fi} % \let\filesep\@empty % There is very little we seem to need from the scrdoc extras: page geometry % is set by geometry package and a4paper option from xint.tex file. So it % seems I only need the hologo loading: \usepackage{hologo} \DeclareRobustCommand*{\eTeX}{\hologo{eTeX}}% \DeclareRobustCommand*{\LuaTeX}{\hologo{LuaTeX}}% % %%% end of ltxdoc+srcdoc emulation. See after \StopEventually for doc.sty hacks. % Remove from sectioning commands insertion of marks, because we % will do it ourself. \usepackage{etoolbox} \patchcmd{\@sect}% {\expandafter\csname#1mark\expandafter\endcsname\expandafter{\@currentheadentry}}% {}{}{\Error@CouldNotApplyFirstPatch@sect} \patchcmd{\@sect}% {\expandafter\csname#1mark\expandafter\endcsname\expandafter{\@currentheadentry}}% {}{}{\Error@CouldNotApplySecondPatch@sect} % This one now needed too, Jeudi 30 janvier 2020 % \expandafter \ifx \csname #1mark\endcsname \@gobble \@mkboth {}{}\else % \csname #1mark\expandafter \endcsname \expandafter {\@currentheadentry }\fi % \@gobble est long donc simplement \def\partmark #1{}% \pagestyle{headings} \ifxetex \else \usepackage[T1]{fontenc} % je suis passé à utf8 le 28 février 2016 \usepackage[utf8]{inputenc} % (2016/12/08): utilisé où ? % (2018/05/22): utilisé dans les commentaires de la division de xint.sty \DeclareUnicodeCharacter{03B4}{\ensuremath{\delta}}%δ % pour exemple de \xintnewdummy \DeclareUnicodeCharacter{03BE}{\ensuremath{\xi}}%ξ % (2019/03/31): utilisé dans mes commentaires de xinttrig.sty \DeclareUnicodeCharacter{03C0}{\ensuremath{\pi}}%π % (2019/04/24): utilisé dans un commentaire de xintlog.sty \DeclareUnicodeCharacter{2260}{\ensuremath{\neq}}%≠ \fi \usepackage{multicol} \usepackage{geometry} \AtBeginDocument {\ttzfamily % package newtxtt is 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} \fi \usepackage{pifont}% for \ding{73} (hollow star) % needed also for build of sourcexint.pdf \usepackage{xinttools} \usepackage{enumitem} \usepackage{varioref} \usepackage{xspace} \usepackage[para]{footmisc} \usepackage{picture} \usepackage{graphicx} \usepackage[english]{babel} % 2022/06/05 % \usepackage{csquotes} \def\myenquote#1{{\sffamily\textquotedblleft}#1{\sffamily\textquotedblright}} % 2022/05/24, commenting out this at it appears to not be used anywhere now. % \usepackage[autolanguage,np]{numprint} % \AtBeginDocument{\npthousandsep{,\hskip .5pt plus .1pt minus .1pt}} % But surprisingly it is via numprint that I was loading array package % whose extended syntax for tabular preambles is required! \usepackage{array} \usepackage[dvipsnames,svgnames]{xcolor} %%% DEFINITIONS OF COLORS USED IN DOCUMENT % color for the \xintname, \xintexprname, etc macros \definecolor{xintnamecolor}{RGB}{228,57,0} \colorlet{XINTNAMECOLOR}{xintnamecolor} % color for their analogs \xintnameimp, etc... in implementation part \colorlet{xintnameimpcolor}{blue} \colorlet{XINTNAMEIMPCOLOR}{xintnameimpcolor} % colors for hyperref \definecolor{xinturlcolor}{RGB}{38,128,192} \colorlet{xintlinkcolor}{blue} % colors for custom \verb and everbatim/everbatim* environments % % the commented-out legacy colors used in xint.pdf for many years up to % xint 1.4j (2021/07/13) (I should retrieve since when exactly) % % \colorlet{verbcolor}{jfbrown} % \colorlet{verbsoftwrapiconcolor}{blue} % \colorlet{everbatimfgcolor}{Brown} % \colorlet{everbatimbgcolor}{yellow!5} % \colorlet{everbatimxfgcolor}{OrangeRed} % % https://contrast-ratio.com/#rgb%28165%2C100%2C10%29-on-white % says the contrast ratio on white is 4.74 and I do see the contrast % is less strong than % for the DarkBlue/Beige and Maroon/White combinations seen below % \colorlet{verbcolor}{jfbrown} % I will simply use also Maroon \colorlet{verbcolor}{Maroon} \colorlet{digitsttcolor}{verbcolor} \colorlet{verbsoftwrapiconcolor}{DarkBlue} \colorlet{everbatimfgcolor}{DarkBlue} % % According to % https://contrast-ratio.com/#rgb%2811%2C35%2C139%29-on-rgb%28245%2C244%2C220%29 % the DarkBlue on Beige % gives a contrast-ratio of 11.58 which confirmed my intuition it is not bad % "Passes AAA level for any size text and AA for user interface components and % graphical objects" % % memo: with Apple ColorPicker it seems one needs to select "sRVB" (I guess % "sRGB" in English) for values matching xcolor RGB input or the above html % page rgb(R,G,B) input, also this did not work % 100%, most probably due to the window transparency by default on my mac? \colorlet{everbatimbgcolor}{Beige} % % https://contrast-ratio.com/#rgb%28128%2C31%2C19%29-on-white % gives 9.89 contrast ratio which is a bit less but still AAA \colorlet{everbatimxfgcolor}{Maroon} % % colors for margin notes \colorlet{marginnotecolor}{PineGreen} \colorlet{marginwarningcolor}{Red} % colors for toc \colorlet{tocstylesectioncolor}{cyan} \colorlet{tocstylesectionimpcolor}{RoyalPurple} \colorlet{tocstylebundlesectioncolor}{xintnamecolor} % colors for macro code and comments \colorlet{privatecommentcolor}{cyan} \colorlet{macrocodecommentcolor}{gray} \colorlet{macrocodenewmacrocolor}{verbcolor} \colorlet{macrocodelinktouserdoccolor}{xintnamecolor}% and bold face \colorlet{macrocodelinktosectioncolor}{DarkBlue}% and bold face \colorlet{macrocodelinktocodelinecolor}{DarkBlue} \colorlet{macrocodenoncscolor}{Green} % colors for the implementation part and the modified macrocode macros % are to be found after \StopEventually \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 % ========== \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} % HYPERREF % ======== \usepackage{hyperref} % 2022/06/10 reduce clutter in console and log output, there are already % enough messages telling we have to execute latex once more \catcode`_ 11 \def\perhapshyperref[#1]{\ifcsname r@#1\endcsname \xint_afterfi{\hyperref[#1]}\fi} \catcode`_ 8 \hypersetup{% linktoc=all,% breaklinks=true,% colorlinks=true,% urlcolor=xinturlcolor,% linkcolor=xintlinkcolor,% pdfauthor={Jean-Fran\c cois Burnol},% pdftitle={The xintexpr and allied packages},% pdfsubject={Arithmetic with TeX},% pdfkeywords={Expansion, arithmetic, TeX},% pdfstartview=FitH,% pdfpagemode=UseNone,% } \usepackage{hypcap} \ifnum\dosourcexint=1 \hypersetup{pdftitle={The xintexpr and allied packages source code}} \fi \usepackage{bookmark} % This is for having similarly named labels to get hyperlinks either to the % user documentation or to the implementation part. From source mark-up with % \csbxint, \csbXINT, \csb, or automated ones from |...| and the custom \verb % However in the user manual I have so far (2022/06/11) used manually typed-in % \label's in contrast to the almost exclusively automated ones of the implementation % part. So for time being I keep an empty prefix here in place of something % reasonable such as usr-. \let\xintdoclabelprefix\empty \def\xintimplabelprefix{src-} % used by \csbxint etc... \let\xintlabelprefix\xintdoclabelprefix % FONTS % ===== \usepackage[zerostyle=a,straightquotes,scaled=0.95]{newtxtt} \usepackage{newtxmath} \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\tocstylesectionbracedcolor{{tocstylesectioncolor}} \def\tocstyleMARGEPAGENO {1.5em}% changera pour la partie implémentation \def\tocstylesectionVSKIP{\vskip\bigskipamount} \etocsetstyle{section}{} {\normalfont} {\etociffirst{}{\tocstylesectionVSKIP}% \rightskip \tocstyleMARGEPAGENO\relax \parfillskip -\tocstyleMARGEPAGENO\relax \bfseries \leftskip \leftmarginii \noindent\llap % \llap {\makebox[\leftmarginii][l]% et \leftmargini le 12/10/2014 {\expandafter\textcolor\tocstylesectionbracedcolor{\etocnumber}}}% \strut\etocname \mdseries\nobreak\leaders\etoctoclineleaders\hfill\nobreak\strut \makebox[\tocstyleMARGEPAGENO][r]{\etocpage}\par \let\ETOCsectionnumber\etocthenumber }% {}% \newdimen\tocstyleLEFTMARGIN \AtBeginDocument{\tocstyleLEFTMARGIN \dimexpr 5\fontcharwd\font`X\relax} \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 \tocstyleLEFTMARGIN % 12 octobre 2014 \ifinmanualmaintoc \rightskip \tocstyleMARGEPAGENO \else \rightskip \tocstyleMARGEPAGENO plus 2em minus 1em \fi \parfillskip -\tocstyleMARGEPAGENO\relax } {} {\noindent \etocifnumbered{\llap{\makebox[\tocstyleLEFTMARGIN][l]{\ttzfamily\bfseries\etoclink {\ifinmanualmaintoc\expandafter\textcolor\tocstylesectionbracedcolor {\normalfont\bfseries\ETOCsectionnumber}\fi .\expandafter\gobbletodot\etocthenumber}}}}{\kern-\tocstyleLEFTMARGIN}% \strut\etocname\nobreak \unless\ifinmanualmaintoc\leaders\etoctoclineleaders\fi \hfill\nobreak \strut\makebox[\tocstyleMARGEPAGENO][r]{\small\etocpage}\endgraf } {\end{multicols}\endgroup }% \etocsetstyle{subsubsection} {\begingroup\normalfont\small \leftskip\dimexpr\leftmargini+1em\relax } {} {\noindent \llap{\makebox[\dimexpr\leftmargini+1em\relax][l]% {\ttzfamily\bfseries\etoclink {\tocstylesubsubsectionHOOK.\expandafter\gobbletodot\etocthenumber}}}% \strut\etocname\nobreak \leaders\etoctoclineleaders \hfill\nobreak \strut\makebox[\tocstyleMARGEPAGENO][r]{\small\etocpage}\endgraf } {\endgroup }% % 2018/02/28 % quick hack to get style I want in "User defined functions" section of manual \let\tocstylesubsubsectionHOOK\empty \etocsetlevel{table}{6} \addtocontents{toc}{\protect\hypersetup{hidelinks}} % ===================== % MISCELLANEOUS MARK-UP % ===================== \def\digitstt #1{\begingroup\color{digitsttcolor}#1\endgroup} \let\dtt\digitstt % \fexpan 22 octobre 2013 \newcommand\fexpan {\perhapshyperref[ssec:expansions]{\textit{f}-expan}} % \xexpan ajouté 28 mai 2022 \newcommand\xexpan {\perhapshyperref[ssec:expansions]{\textit{x}-expan}} % Septembre 2015 % Address updated to github repo's one, May 2018 % They did s/master/main/ already a few years back, May 2022 \def\liiibigint {\href{https://github.com/latex3/latex3/tree/main/l3trial/l3bigint}{l3bigint}} % May 2022 \def\liiistrformat % {\href{https://github.com/latex3/latex3/tree/main/l3experimental/l3str}{l3str}} {\href{https://ctan.org/pkg/l3experimental}{l3str-format}} %\def\liiistrformatnew % {\href{https://github.com/latex3/latex3/tree/main/l3trial/l3str-format-new}{l3str-format-new}} % Margin Notes % ============ % Nothing here can be used in vertical mode directly. \def\MyMarginNote {\@ifnextchar[\@MyMarginNote{\@MyMarginNote[]}}% \let\inmarg\MyMarginNote % \smash needs \hbox here since LaTeX 2018/12/01 % https://github.com/latex3/latex2e/issues/108 \def\@MyMarginNote [#1]#2{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\color{marginnotecolor}\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 \hbox{\smash{\hbox to 0pt {\color{marginnotecolor}%\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 \hbox{\smash{\hbox to 0pt {\hss\color{marginnotecolor}% \itshape \xintListWithSep{\,}{#1}\ $\star$\quad }}}% \vskip\dp\strutbox }\strut\@esphack} \def\xtype #1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginnotecolor}% \itshape \xintListWithSep{\,}{#1}\ \ding{73}\quad }}}% \vskip\dp\strutbox }\strut\@esphack} \def\ntype #1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginnotecolor}% \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 \hbox{\smash{\hbox to 0pt {\hss\color{marginnotecolor}% \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 \hbox{\smash{\hbox to 0pt {\hss\color{marginwarningcolor}% \normalfont\small\bfseries \hsize 1.5cm\rightskip.5cm minus.5cm \vtop{\noindent Changed at #1!}\ }}}% \vskip\dp\strutbox }\strut\@esphack} \def\DNU#1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginwarningcolor}% \normalfont\small\bfseries \hsize 1.5cm\rightskip.5cm minus.5cm \vtop{\noindent Do not use! #1}\ }}}% \vskip\dp\strutbox }\strut\@esphack} \def\UNSTABLE#1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginwarningcolor}% \normalfont\small\bfseries \hsize 1.5cm\rightskip.5cm minus.5cm \vtop{\noindent Unstable! #1}\ }}}% \vskip\dp\strutbox }\strut\@esphack} \def\unstable#1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginwarningcolor}% \normalfont\small\bfseries \hsize 1.5cm\rightskip.5cm minus.5cm \vtop{\noindent unstable? #1}\ }}}% \vskip\dp\strutbox }\strut\@esphack} \def\DEPRECATED #1{\@bsphack \vadjust{\vskip-\dp\strutbox \hbox{\smash{\hbox to 0pt {\hss\color{marginnotecolor}% \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 \hbox{\smash{\hbox to 0pt {\hss\color{marginwarningcolor}% \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 \hbox{\smash{\hbox to 0pt {\hss\color{marginnotecolor}% \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} % \centeredline: OUR OWN LITTLE MACRO FOR CENTERING LINES % ======================================================= % 7 mars 2013 % Note (2020): now a package \usepackage{centeredline} % \leftedline % =========== % 12 octobre 2014 % Note (2020): somewhat obsoleted for many years by my usage of % everbatim and everbatim* environments. \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@ } % verbatim macros and environments % ================================ % % June 2013, then October 2014. % ----------------------------- % \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 % \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\verbcolorcmd{\color{verbcolor}} \def\verbsoftwrapiconcolorcmd{\color{verbsoftwrapiconcolor}} \def\restoreMicroFont {\def\MicroFont {\ttfamily\makestarlowast \ifinlefted\else\verbcolorcmd\fi }} \restoreMicroFont \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 (\ttfamily), 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{% % 2022/06/04 % automated hyperlink detection % - \detokenize needed due to * \active from \makestarlowast in \MicroFont % - gobbling first char rather than checking if it is backslash % (and there is an \@empty first so gobbling two tokens) % mark-up using \csbxint is better way as it allow hyphenation after xint % Usage of \xintlabelprefix to modify behaviour in implementation part. % This will NOT WORK if the catcodes were already frozen... \ifcsname r@\xintlabelprefix\detokenize\expandafter{\xint_gobble_ii##1}\endcsname \hyperref[\xintlabelprefix\detokenize\expandafter{\xint_gobble_ii##1}]{##1}% \egroup \else % this will add \discretionary's for wrapping at end of line \@vobeyspaces\everyeof{\relax}\endlinechar\m@ne \expandafter\@@jfverb_a\scantokens\expandafter{##1}% \fi}% % 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 } \DeclareFontFamily{U}{MdSymbolC}{} \DeclareFontShape {U}{MdSymbolC}{m}{n}{<-> MdSymbolC-Regular}{} \newbox\SoftWrapIcon \def\SetSoftWrapIcon{% \setbox\SoftWrapIcon\hb@xt@\z@ {\kern.5ex%\hb@xt@\z@%\fontdimen2\font %{ \smash{\lower3pt\hbox{% \verbsoftwrapiconcolorcmd\usefont{U}{MdSymbolC}{m}{n}\char 151 }}%\hss}% \hss}% } \AtBeginDocument {\SetSoftWrapIcon }% ok car ttzfamily déjà fait \catcode`_ 8 % everbatim environment % ===================== \def\restoreMacroFont {\def\MacroFont {\ttfamily \ifinlefted\else\color{everbatimfgcolor}\fi }} \restoreMacroFont % 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... % 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) \catcode`_ 11 \def\everbatim {\s@everbatim\@everbatim} \@namedef{everbatim*}{\s@everbatim\@everbatimx} % Note: one can not use everbatim inside itself or everbatim* inside itself \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 \@topsepadd \z@skip \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 } % 27 mai 2022, plus de \small \def\everbatimtop {\MacroFont }% \let\everbatimhook\empty \def\everbatimeverypar{\strut {\color{everbatimbgcolor}\vrule\@width\linewidth }% \kern-\linewidth \kern\everbatimindent } \def\everbatimindent {\z@}% voir plus loin atbegindocument \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 #1X#2\end{everbatimY}]% {#2\end{everbatim*}% % No group here: this allows executed code to make macro % definitions which may reused in later uses of everbatim. % refactored 2022/01/11, rather than passing \newlinechar value % as was done formerly via everbatim* (see above) and fetching it here as #1 % it is thus assumed executed contents do not terminate a scope \edef\everbatimrestorenewlinechar{\newlinechar\the\newlinechar\relax}% \newlinechar 13 % refactored 2022/01/11 to fix a \parskip issue % attention, \parskip thus set to zero for execution of contents % reason: avoid extra space if everbatim* is in an \item of a list % between verbatim and output of execution, if it starts a paragraph % a \vskip-\parskip approach (cf former \everbatimundoparskip) % would be no good in case contents create a display \edef\everbatimrestoreparskip{\parskip\the\parskip\relax}% \parskip\z@skip % execution of the contents (expected to be LaTeX code...) \everbatimxprehook \scantokens {#2}% \everbatimrestorenewlinechar \everbatimrestoreparskip \everbatimxposthook % input after \end{everbatim*} on same line in source is allowed }% % L'espace venant du endofline final mis par \scantokens sera inhibé si #2 se % termine par un % ou un \x, etc... \let\everbatimbottom\empty \def\endeverbatim{\if@newlist \leavevmode\fi\endtrivlist} \@namedef{endeverbatim*}{\endeverbatim} % There is an issue with how to inhibit the \parskip if execution % of contents generate a paragraph. Because the design is aimed at % keeping output close to verbatim input. % Even in a document with zero \parskip overall, the \parskip will possibly % be reset to some annoying high value e.g. if we are in an \item of a list % environment. % In this documentation, many usage of everbatim* are indeed inside such % \item's. The former (2020) approach was to do: % \@namedef{endeverbatim*}{\endeverbatim\aftergroup\everbatimundoparskip} % \def\everbatimundoparskip{\vbox{}\kern-\baselineskip\kern-\parskip\leavevmode} % but it had its problems if executed contents start a display, with % not enough vertical whitespace then % Also if source had two everbatim* environments one after the other, % the first one not producing any ouput, this caused overlap. % The new approach (Feb 2022) is much simpler and avoids these problems. % These definitions are provisory and get overwritten below in order % to avoid color stack overflow problems with latex + dvipdfmx, and xelatex \def\everbatimxprehook {\colorlet{everbsavedcolor}{.}% \color{everbatimxfgcolor}}% \def\everbatimxposthook{\color{everbsavedcolor}} % actual definitions: {\sbox0{\color{everbatimxfgcolor}\xdef\@tempa{\current@color}}} \ifpdf \edef\everbatimxprehook {\pdfcolorstack\noexpand\@pdfcolorstack push{\@tempa}\relax} \def\everbatimxposthook{\pdfcolorstack\@pdfcolorstack pop\relax} \else % Le 24 juin 2021 je vérifie que ceci est encore nécessaire avex xelatex % (sinon color leak de OrangeRed à partir de la page 97 dans la doc) % et aussi pour dvipdfmx (sinon color stack overflow au moment de la page 98 % lors du passage par dvipdfmx) \ifxetex \edef\everbatimxprehook{\special{color push \@tempa}} \def\everbatimxposthook{\special{color pop}} \else \ifnum\Withdvipdfmx=1 \edef\everbatimxprehook{\special{color push \@tempa}} \def\everbatimxposthook{\special{color pop}} \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. % Le "" redonne à { et } leurs catcodes normaux mais attention c'est % alors à utiliser avec un terminateur ;! pour la partie concernée \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 % \printnumber % ============ \catcode`_ 11 \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 \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... % =========================== % The underscore and caret things are for 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}}}} % For some legacy reasons rather than doing: % \pdfstringdefDisableCommands{% % \def\csa#1{\textbackslash\detokenize{#1}}% % \def\csan#1{\detokenize{#1}}% % }% % I defined years ago variants for usage within section titles. These % variants will get redefined in implementation section to automatically % insert \label's and use \csa and \csan. Here in user manual, they simply % use \csa or \csan, but are careful to do \texorpdfstring. \newcommand\csh[1] {\texorpdfstring{\csa{#1}}{\textbackslash\detokenize{#1}}} % This one is actually never used inside the user manual, only encountered % in the implementation part. \newcommand\cshn[1] {\texorpdfstring{\csan{#1}}{\detokenize{#1}}} % Let's preserve these meanings for when I will want to use them in sections % of the implementation part but not insert labels. \let\cshnolabel\csh \let\cshnnolabel\cshn % 2022/06/10 % If producing xint-all.pdf add hyperlinks from user documentation % to source code. Should have I used some superscript? Less trouble % and less work intensive for TeX I guess than the centered align. % \def\myalign@vbox#1{\leavevmode\vbox{\baselineskip\z@skip \lineskip.75ex% % \ialign{\hfil##\hfil\crcr#1\crcr}}} % %%\def\oalign#1{\leavevmode\vtop{\baselineskip\z@skip \lineskip.25ex% % %% \ialign{##\crcr#1\crcr}}} % \myalign@vbox{\hyperref[\xintimplabelprefix\detokenize{#1}]{\usebox\sourcelinkbox}\cr % \csa{#1}}% \def\myalign@vbox#1{%\leavevmode \vbox{% \@tempboxa is not used by \smash... and I hope \hyperref too \baselineskip\z@skip\lineskip.75ex\relax \sbox\@tempboxa{\csa{#1}}% \hbox to\wd\@tempboxa{\hss \hyperref[\xintimplabelprefix\detokenize{#1}]{\usebox\sourcelinkbox}% \hss}% \box\@tempboxa }% }% \newsavebox\sourcelinkbox % \familydefault already configured % trying to add some \vphantom{X} has no impact it seems on the % size of the clickable area (tested with Skim and Preview on mac os) % so using \small not \footnotesize \sbox\sourcelinkbox{\color{macrocodelinktosectioncolor}% \normalfont\small\itshape source} \def\cswithsourcelink#1{\smash{\myalign@vbox{#1}}}% % the references should exist on second LaTeX pass % and we don't want complications in tables of contents \def\csperhapswithlink#1{\ifx\thepage\relax\csa{#1}\else \ifcsname r@\xintimplabelprefix\detokenize{#1}\endcsname \cswithsourcelink{#1}% \else \csa{#1}% \fi\fi } \ifnum\dosourcexint=0 \ifnum\NoSourceCode=0 \renewcommand\csh[1] {\texorpdfstring {\csperhapswithlink{#1}} {\textbackslash\detokenize{#1}}% } % \renewcommand\cshn[1] % but it is used nowhere in user manual \fi\fi % The "b" is there originally for "blue" in fact, from the hyperlink. \DeclareRobustCommand\csb [1] {\perhapshyperref[\xintlabelprefix\detokenize{#1}]% {{\char92 \endlinechar-1 \makestarlowast \catcode`_ 12 \catcode`^ 12 \scantokens\expandafter{\detokenize{#1}}}}} \DeclareRobustCommand\csbn[1] {\perhapshyperref[\xintlabelprefix\detokenize{#1}]% {{\endlinechar-1 \makestarlowast \catcode`_ 12 \catcode`^ 12 \scantokens\expandafter{\detokenize{#1}}}}} \DeclareRobustCommand\csbxint[1] {\perhapshyperref[\xintlabelprefix\detokenize{xint#1}]% {{\char92\mbox{xint}\-\endlinechar-1 \makestarlowast \catcode`_ 12 \catcode`^ 12 \scantokens\expandafter{\detokenize{#1}}}}} \DeclareRobustCommand\csbXINT[1] {\perhapshyperref[\xintlabelprefix\detokenize{XINT#1}]% {{\char92\mbox{XINT}\-\endlinechar-1 \makestarlowast \catcode`_ 12 \catcode`^ 12 \scantokens\expandafter{\detokenize{#1}}}}} % 2022/06/08, I finally add this % although this is is not immediately useful as I have interiorized for years % not to use \csbxint et al. in section titles... \pdfstringdefDisableCommands{% \let\csb\cs % \cs already in DisableCommands, I hope its redefinition is done % first, well yes one has to chase \ltx@GlobalAppendToMacro % all the way to ltxcmds... \let\csbn\detokenize \def\csbxint#1{\textbackslash xint\detokenize{#1}}% \def\csbXINT#1{\textbackslash XINT\detokenize{#1}}% }% % \func, \funcdesc, \keyword, \keyworddesc, \prec, \precdesc, \oper, \operdesc % ============================================================================ \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[\texttt{#1}]\hypertarget{\detokenize{prec-#1}}{}\leavevmode}% %\let\var\relax % défini par koma-script-source-doc que scrdoc % utilise avec LaTeX 2022/06/01 % mais finalement je n'utilise plus scrdoc/ltxdoc % mais doc directement. \newcommand\var[1]{\hyperlink{\detokenize{var-#1}}{#1}} \newcommand\vardesc[1]{\item[#1]\hypertarget{\detokenize{var-#1}}{}}% \newcommand\oper[1]{\hyperlink{\detokenize{oper-#1}}{#1}} \newcommand\operdesc[1]{\item[\texttt{#1}]\hypertarget{\detokenize{oper-#1}}{}}% % \xintname, \xintnameimp etc... % ============================== \xintForpair #1#2 in {(\space bundle,bundle), (kernel,kernel), (tools,tools), (core,core),(,xint),(binhex,binhex),(gcd,gcd),% (frac,frac),(series,series),(cfrac,cfrac),(expr,expr),% (trig, trig), (log, log)} \do {% \expandafter\def\csname xint#1name\endcsname {\texorpdfstring {\perhapshyperref[sec:#2]% {{\color{xintnamecolor}\MakeNameUp {\mbox{xint}\-#1} {xint#1}% }% }% }% {xint#1}% \xspace }% \expandafter\def\csname xint#1nameimp\endcsname {\texorpdfstring {\perhapshyperref[sec:#2imp]% {{\color{xintnameimpcolor}\MakeNameUp {\mbox{xint}\-#1} {xint#1}% }% }% }% {xint#1}% \xspace }% }% \def\DOCxintfrontpage {\perhapshyperref[frontpage]{{\color{xintnamecolor}TOC}}}% \ifnum\dosourcexint=1 % sourcexint.pdf \gdef\DOCxintfrontpage {\perhapshyperref[frontpage]{{\color{xintnameimpcolor}TOC}}}% \else \ifnum\NoSourceCode=0 % xint-all.pdf % Not using \hypersetup with linkcolor because a few pages are with % a TOC à cheval on two pages, and my eTOCs are configured to do % \hypersetup{hidelinks} \protected\def\DOCxintfrontpage {\smash{\vbox{\hbox{\perhapshyperref[partiii]{{\color{xintnameimpcolor}TOC}}}% \kern1ex \hbox{\perhapshyperref[frontpage]{{\color{xintnamecolor}TOC}}}}}}% \fi\fi \protected\def\MakeNameUp#1#2{% \ifcsname #2nameUp\endcsname \expandafter\@firstoftwo\else \expandafter\@secondoftwo \fi % \ifinheader 2020/01/30 {\ifinheader\fbox{\textup{#1}}\else#1\fi}% {#1}% } \newif\ifinheader % doit être protégé \protected\def\inheadertrue{\let\ifinheader\iftrue} % \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}% } % It seems I need this for a bookmark in xint-all.pdf % reaching the top of the page where Part III starts % 2022/06/10 \newcommand\RaisedTarget[2][6]{% \vspace*{-#1\baselineskip}% \hypertarget{#2}{}% \vspace*{#1\baselineskip}% } % begin{document} % =============== % \ttzfamily done at begin document \DeclareRobustCommand\ctanpackage[1]{\href{https://ctan.org/pkg/#1}{#1}} \makeatother \begin{document}\thispagestyle{empty} \pdfbookmark[1]{Title page}{TOP} \def\partname{Part} \addto\captionsenglish{\def\partname{Part}} \ifnum\dosourcexint=1 \noindent\begin{minipage}[t][8\baselineskip][c]{\linewidth} \normalfont\Huge \centering The \xintexprnameimp and allied packages source code\par \else \begingroup \normalfont\Huge \centering The \xintexprname and allied packages\par \endgroup \fi \RaisedLabel{frontpage} \normalsize\ttzfamily {\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 } \ifnum\dosourcexint=1 \end{minipage} \else \medskip \fi % 31 janvier 2020 % 2022/06/10 no need for \texorpdfstring here \def\DOCxintexprintro {\perhapshyperref[part:1]{{\color{xintnamecolor}% \MakeNameUp{Start here}% {Start here}% }% }% }% \def\DOCxintexprmacros {\perhapshyperref[sec:oldxintexpr]{{\color{xintnamecolor}% \MakeNameUp{xintexpr (old doc)}% {xintexpr (old doc)}% }% }% }% \def\DOCexamples {\perhapshyperref[sec:examples]{{\color{xintnamecolor}% \MakeNameUp{Examples}{Examples}% }% }% }% % 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 % Update Friday, June 25 2021 % I finally take the time to go to the root of this: the culprit is everbatim % when its output crosses pagebreaks, but the same of course happens with % verbatim. % I opened ticket https://github.com/latex3/latex2e/issues/600 \def\xintRunningHeader{{\inheadertrue\catcode`,12\relax \DOCxintfrontpage, \DOCxintexprintro, \xintexprname, \DOCxintexprmacros, \xinttrigname, \xintlogname, \xinttoolsname, \DOCexamples, \csname xint bundlename\endcsname}} \markboth{\makebox[0pt]{\xintRunningHeader}}{\makebox[0pt]{\xintRunningHeader}} % 18 mai 2019, turned into an environment 27 mai 2022 \newenvironment{TeXnote}{\par\small\medskip\noindent\textbf{\TeX-hackers note: }}{\par\medskip} % Skips safely. \ifnum\dosourcexint=1 \catcode`+ 0 \catcode0 9 % n'importe quoi sauf 15 (car ^^@) \catcode`\\ 12 +expandafter+iffalse+fi \fi % \makeatletter \etocsetlevel{toctobookmark}{6} \etocsetlevel{table}{2}% subsection \let\orig@etocbelowtocskip\etocbelowtocskip \let\orig@etocinnertopsep\etocinnertopsep \let\orig@etoctoclineleaders\etoctoclineleaders \renewcommand*{\etocbelowtocskip}{0pt} \renewcommand*{\etocinnertopsep}{0pt} \renewcommand*{\etoctoclineleaders} {\hbox{\normalfont\normalsize\hbox to 1ex {\hss.\hss}}} \etocsettocstyle{}{} \etocsettagdepth {part1A}{subsection} \etocsettagdepth {part1B}{section} \etocsettagdepth {macros}{none} \etocsettagdepth {implementation}{none} \etocsettocdepth{subsection} %% Legacy etoc style for part, with an improvement to get "Part" %% hyperlinked %% Also some hack to let the TOC of xint-all.pdf fit on one page %% `part': \etocsetstyle{part} {\ifnum\dosourcexint=0 \ifnum\NoSourceCode=0 % both true only for xint-all.pdf \def\etocbelowtocskip{\z@skip}% \def\etocabovetocskip{\z@skip}% \def\etocsepminusone{\bigskipamount}% \def\etocsepzero{\medskipamount}% \def\tocstylesectionVSKIP{\vskip\smallskipamount}% \fi\fi \addpenalty\@M\etocskipfirstprefix} {\addpenalty\@secpenalty} {% \begingroup \etocfontminusone \addvspace{\etocsepminusone}% \parindent \z@ \leftskip \etocminusoneleftmargin \rightskip \etocminusonerightmargin \parfillskip \@flushglue % original from etoc : %\vbox{\etocifnumbered{\etocpartname\enspace\etocnumber.\quad}{}...} \vbox{\etocifnumbered{\etoclink{\etocpartname\enspace\etocthenumber.}\quad}{}% \etocname \baselineskip\etocbaselinespreadminusone\baselineskip \par}% \addpenalty\@M \addvspace{\etocsepzero}% \endgroup} {}% % THIS IS THE FIRST HALF OF THE TOC ON PAGE 1 \tableofcontents % May 23 2022, some hack to replace the \etocmulticolstyle and % have same output except that Part line will use full line width % % Formerly I used this but the Part was then folded... % \etocmulticolstyle [2]{\parskip\z@skip%\raggedcolumns % \setlength{\columnsep}{\leftmarginii}% % \setlength{\columnseprule}{0pt}% % }% % \etocsetstyle{part}% @minusone in etoc.sty {\if1\ifnum\dosourcexint=1 0\fi\ifnum\NoSourceCode=1 0\fi1% xint-all.pdf \def\etocbelowtocskip{\z@skip}% \def\etocabovetocskip{\z@skip}% \def\etocsepminusone{\bigskipamount}% \def\etocsepzero{\medskipamount}% \fi \addpenalty\@M\etocskipfirstprefix} % May 23, 2022 % Small hack to configure to our taste the TOC for the pdf combining % the user manual and the source code. We want a Part III in the TOC, % and the sections of Part II with a multicols. We can not open the % multicols in the `part' style and have it closed in the 4th argument % of \etocsettyle, as it needs to be closed when Part III will be % typeset. Thanks to \etocskipfirstprefix we can simply close it % in the "EtocPrefix", this \end{multicols} will be skipped for the % first one. % % However, as this closes a group we will use \etocglobaldefs for this % toc else \etocname, etc... would not have the good meanings. I think % there must be some hack like this in etoc manual. {\end{multicols}% \addpenalty\@secpenalty\addvspace{\etocbelowtocskip}% } {% % \kern and not \vskip to avoid multicolumn balncing columns \def\tocstylesectionVSKIP{\kern\smallskipamount}% \if1\ifnum\dosourcexint=1 0\fi\ifnum\NoSourceCode=1 0\fi1% % xint-all.pdf only % quite a challenge to get everything on single page, but not too cramped... \def\tocstylesectionVSKIP{\kern.75\smallskipamount}% \fi \begingroup % adapted from etoc.sty default Part style \etocfontminusone \addvspace{\etocsepminusone}% \parindent \z@ \leftskip \etocminusoneleftmargin \rightskip \etocminusonerightmargin \parfillskip \@flushglue % \etoclink is handy else only the number get hyperlinked \vbox{\etocifnumbered{\etoclink{\etocpartname\enspace\etocthenumber.\quad}}{}\etocname \baselineskip\etocbaselinespreadminusone\baselineskip \par}% \addpenalty\@M\addvspace{\etocsepzero}% \endgroup % now emulate what \etocmulticolstyle would have set-up \let\etocoldpar\par% surely fishy by now but I am copying from % how \etocsettocstyle is used by \etocmulticolstyle \addvspace{\etocabovetocskip}% configured below \multicolpretolerance\etocmulticolpretolerance \multicoltolerance\etocmulticoltolerance \setlength{\columnsep}{\etoccolumnsep}% \setlength{\multicolsep}{\etocmulticolsep}% \begin{multicols}{2}[\parskip\z@skip%\raggedcolumns \setlength{\columnsep}{\leftmarginii}% \setlength{\columnseprule}{0pt}% \etocoldpar %\addvspace{\etocinnertopsep} \addvspace{\etocabovetocskip}]% }% {\end{multicols}\addvspace{\etocbelowtocskip}}% % this macro is defined by etoc for use in its own display styles % like the one from \etocmulticolstyle. We use it manually above. \renewcommand*\etocabovetocskip{\bigskipamount} \makeatother \etocsettocstyle{}{} \etocsettagdepth {part1A}{none} \etocsettagdepth {part1B}{none} \etocsettagdepth {macros} {section} \ifnum\dosourcexint=1 % sourcexint.pdf \etocsettagdepth {implementation}{section} \else \ifnum\NoSourceCode=1 % xint.pdf \etocsettagdepth {implementation}{part} \else % xint-all.pdf \etocsettagdepth {implementation}{section} \fi \fi % seems unneeded now %\vspace*{2\baselineskip} % THIS IS THE SECOND HALF OF THE TOC ON PAGE 1, WITH PARTS II AND III \etocglobaldefs \tableofcontents \etoclocaldefs \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!5}% \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.1666}} \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) {\ctanpackage{bnumexpr}}; \node [block, below of=core] (xint) {\xintname}; \node [block, left of=xint, xshift=-1cm] (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) {\ctanpackage{polexpr}}; \node [block, below of=polexpr] (session) {rlwrap etex \ctanpackage{xintsession}}; \node [block, below of=expr, yshift=-.5cm] (trig) {\xinttrigname}; \node [block, left of=trig] (log) {\xintlogname}; \node [block, left of=log, xshift=-1cm] (poormanlog) {\ctanpackage{poormanlog}}; \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]}] (xint) -- (gcd); \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]}] (poormanlog) -- (log); \path [line,-{Stealth[length=5mm]}] (expr) -- (polexpr); \path [line,-{Stealth[length=5mm]}] (expr) -- (session); \path [line,-{Stealth[length=5mm]}] (polexpr) -- (session); \path [line,-{Stealth[length=5mm]}] (trig.south) to [out=-90,in=180] (session.west); \path [line,-{Stealth[length=5mm]}] (log.south) to [out=-90,in=180] (session.west); \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); % at 1.4 xintgcd loads xinttools \path [line,-{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{\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 \ctanpackage{bnumexpr} is a separate (\LaTeX{} only) package by the author which uses (by default) \xintcorename as its mathematical engine. \ctanpackage{polexpr} handles definitions and algebraic operatione on one-variable polynomials, as well as root localization to arbitrary precision. It works both with Plain \TeX\ and with \LaTeX. \xinttrigname and \xintlogname are loaded automatically by \xintexprname; they should not be loaded directly via a separate |\usepackage| (in \LaTeX). \ctanpackage{poormanlog} is a \TeX{} and \LaTeX{} package by the author which is loaded automatically by \xintlogname. \ctanpackage{xintsession} is invoked on the command line as |etex xintsession| (or, if available, |rlwrap etex xintsession|). It loads \xintbinhexname automatically (but this is not indicated above graphically). \par \end{addmargin} \vfill \clearpage \etocdepthtag.toc {part1A} \csname Start herenameUp\endcsname \part{The \xintexprname package} \RaisedLabel[12]{part:1} \etocsetnexttocdepth{section} \localtableofcontents \section {Introduction} \localtableofcontents \begin{framed} \emph{\emph{\textsc{Jürgen Gilg}}'s interest into what he called \emph{|"XINT"|} was instrumental in keeping the author motivated over the years. % \emph pas compatible avec plusieurs paragraphes ! We exchanged on many topics extending beyond \TeX{} and often reacted similarly to private and public events. I knew he was a very kind and devoted person, who took care of the needs of others prior to his own, although he never mentioned it. % Jürgen suffered a sudden, unexpected, and deadly stroke in May 2022. I will miss his friendship profoundly.} \end{framed} \subsection{Basic usage and purpose} \begin{itemize} \item To use with |etex|, |pdftex|, ..., i.e.\@ with \TeX{} engines activating the e\TeX{} extensions: \begin{everbatim} \input xintexpr.sty \end{everbatim} \item To use with the \LaTeX{} macro layer (|latex|, |pdflatex|, ...): \begin{everbatim} \usepackage{xintexpr} \end{everbatim} \end{itemize} Some random examples: \begin{everbatim*} $\sqrt{13}, \cos(1), \exp(13.3) = \xintfloateval{sqrt(13), cos(1), exp(13.3)}$\par \end{everbatim*} \begin{everbatim*} \begin{center} \xintDigits*:=32;% this sets the precision to 32 digits for the math functions \begin{minipage}{34\fontcharwd\font`0} \xintfloateval{sqrt(13), cos(1), exp(13.3)}\par \end{minipage}% \end{center} \end{everbatim*} \begin{everbatim*} $2^{1000}=\printnumber{\xinteval{2^1000}}$\par% exact computations \end{everbatim*} \begin{everbatim*} % dummy variables \[\sum_{i=1}^{50}\frac1i=\xintTeXFrac{\xinteval{reduce(add(1/i, i=1..50))}}\] \end{everbatim*} \begin{everbatim*} \[\sum_{i=1}^{50}\frac1{i^2}=\xintTeXFrac{\xinteval{reduce(add(1/i^2, i=1..50))}}\] \end{everbatim*} Computations are done expandably. This means that for example \begin{everbatim} \typeout{\xinteval{sqrt(13, 70)}} \end{everbatim} will compute on the fly while writing out to the log file (|\typeout| is the \LaTeX\ idiom), here the square root of \dtt{13} correctly rounded to \dtt{70} significant digits. Indeed, \xintexprname is a package to do expandable computations, either exactly with arbitrarily big inputs (fractions, arbitrarily long decimal expansions, ...), or in the sense of floating point numbers (logarithm, exponential, sine, cosine, ...). The math functions are implemented up to \dtt{62} digits of precision. The square root (as well of course as the four operations) achieve correct rounding in arbitrary precision (i.e.\@ even with more than \dtt{62} digits, and may even handle thousands of digits but reasonable range is not beyond a few hundreds). The syntax to modify the precision used for floating point evaluations is \begin{everbatim} \xintDigits*:= <Number>; \end{everbatim}\smallskip \begin{footnotesize} For reasons of the history of the package, one usually will want to use indeed the |*| (see \csbxint{Digits}), as the more lightweight variant without it does let the four operations and the square root obey the new setting but it does not recalibrate the \xinttrigname and \xintlogname libraries and their built-in constants.\par \end{footnotesize} The current precision is available as \csbxint{theDigits}, and defaults to \dtt{16}, but in this documentation I might be using simply |Digits| to refer to it. The table of \hyperref[tab:precedences]{built-in operators} and the one of \hyperref[tab:functions]{built-in functions} will give a quick overview of the available syntax. \subsection{\ctanpackage{xintsession}} The simplest way\footnote{I am assuming here in the displayed example a Unixen system, i.e. Mac OS or Linux, adapt to your environment.} to test the syntax is to work interactively on the command line (this feature is available since April 2021, the version of \ctanpackage{xintsession} used here is |1.3a|): \begin{everbatim} rlwrap etex xintsession [...welcome banner...] Magic words: `&pause' (or `;'), `&help', `&bye', `&exact', `&fp', `&int', `&pol'. \jobname is xintsession Transcript will go to log and to xintsession-210609_12h00.tex Starting in exact mode (floating point evaluations use 16 digits) >>> 2^100; @_1 1267650600228229401496703205376 >>> cos(1); @_2 0.5403023058681397 >>> &fp=32 (/usr/local/texlive/2021/texmf-dist/tex/generic/xint/xintlog.sty) (/usr/local/texlive/2021/texmf-dist/tex/generic/xint/xinttrig.sty) fp mode (log and trig reloaded at Digits=32) >>> cos(1); @_3 0.54030230586813971740093660744298 >>> 3^1000; @_4 1.3220708194808066368904552597521e477 >>> &exact exact mode (floating point evaluations use 32 digits) >>> 3^1000; @_5 13220708194808066368904552597521443659654220327521481676649203682268285 9734670489954077831385060806196390977769687258235595095458210061891186534272525 7953674027620225198320803878014774228964841274390400117588618041128947815623094 4380615661730540866744905061781254803444055470543970388958174653682549161362208 3026856377858229022841639830788789691855640408489893760937324217184635993869551 6765018940588109060426089671438864102814350385648747165832010614366132173102768 902855220001 >>> &bye Did I say something wrong? Session transcript written on xintsession-210609_12h00.tex ) No pages of output. Transcript written on xintsession.log. \end{everbatim} \subsection{\ctanpackage{polexpr}} The package \ctanpackage{polexpr} enriches the \csbxint{eval} syntax (but not the one of \csbxint{floateval}) with a polynomial type with associated constructor |pol([c0,c1,...])|, and polynomial specific functions such as |polgcd(pol1, pol2, ...)|. Full usage of polynomials (and algebraic notations |c_0 + c_1 x + c_2 x^2 + ...| for input and also output) goes through a dedicated |\poldef| parser which is based upon \csbxint{defvar}/\csbxint{deffunc} and is a necessary step to then access via a dedicated macro interface operations such as identifying all rational roots and isolating all real roots to arbitrary precision. The simplest manner to experiment with \ctanpackage{polexpr} is via the |&pol| mode of \ctanpackage{xintsession}. \subsection{\ctanpackage{bnumexpr}} This small package loads \xintcorename and provides the functionality of the integer-only \csbxint{iiexpr}/\csbxint{iieval} parser, but dropping support for nested structures, functions, variables, boolean branching, etc...\@ It includes by default support for hexadecimal input (with |"| prefix) and output based upon \xintbinhexname. Compared to |\the\numexpr| it adds support for arbitrarily large integers, powers with |**| and |^|, factorials via |!| postfix operator, floored division and associated modulo, and comma separated multi-item expressions. It also offers a user-level interface to add extra infix or postfix operators. \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. Else, \href{https://ctan.org/pkg/xint}{CTAN} access provides |xint.tds.zip| which has all source code and documentation in a TDS-compliant archive, only waiting to be |unzip -d <DIR>| into some suitable hierarchical structure. The |README.md| at \href{https://ctan.org/pkg/xint}{CTAN} lists some alternatives. \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 a ``|\printnumber|'' macros, not provided by the package, and which is coded like this (with some extra decorations): \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 }% | This macro triggers ``\fexpan sion'' of its argument (and indeed \csbxint{eval} and friends expand completely under such triggering), then it goes through the computation result character by character inserting \TeX\ potential break points in-between them. % \begin{everbatim*} \printnumber{\xintiieval{100!^3}}\newline \end{everbatim*}% \subsection{The package documentation} With \TeX\ distributions providing a |"texdoc"| or similar utility, \centeredline{|texdoc --list xint|} will offer the choice to visualize one of those files: \begin{enumerate}[nosep] \item |xint.pdf| (this file) \item |sourcexint.pdf| (commented (hmm...) source code) \item |CHANGES.html| \item |README.md| \end{enumerate} Warning: I don't have the time to maintain perfectly such large documentation. It currently combines old documentation which never really got updated and may be locally obsolete with more recent stuff mostly written on occasion of the |1.4| release of January 2020 and the |1.4e| one of May 2021, and the intervening changes might also have made some of it not completely accurate, despite my best efforts. Bug reports and feature requests are most welcome. The section formerly included with this documentation and documenting the changes since the |1.4| release has been removed as it was too time-consuming to maintain it here. Please refer to |CHANGES.html| for the detailed listing: \centeredline{|texdoc --list xint| then select |CHANGES.html|} On the internet: \centeredline{\url{http://mirrors.ctan.org/macros/generic/xint/CHANGES.html}} % A one-page condensed ``timeline'' is to be found at the start of |sourcexint.pdf|. \clearpage \expandafter\let\csname Start herenameUp\endcsname\undefined \csname xintexprnameUp\endcsname \section{Syntax reference and user guide} \RaisedLabel{sec:expr} \localtableofcontents \subsection{The three parsers} \xintexprname provides three numerical expression parsers corresponding to these three respective tasks: \begin{description}[noitemsep] \item[\csa{xinteval}:] exact evaluations with fractions, decimal fixed point numbers, numbers in scientific notation, with no size limitation, \item[\csa{xintiieval}:] evaluations allowing only integers with no size limitation, \item[\csa{xintfloateval}:] evaluations with floating points numbers according to the prevailing precision (see \csbxint{Digits*}), \end{description} and two secondary ones which act like the exact evaluator then round the output to a given number of fractional digits, or convert them to |false| or |true|\CHANGED{1.4m} according to whether they vanish or do not vanish. \begin{framed} Please note the following: \begin{itemize}[noitemsep] \item Although \csbxint{eval} manipulates arbitrarily long integers or fractions it also accepts scientific notation on input, as well as all the mathematical functions (evaluated using the prevailing digits precision), and (depending on customization) can thus produce also scientific notation on output. \item So far, individual operations and the printing routine of \csbxint{eval} do not automatically reduce fractions to their lowest terms. \end{itemize} \end{framed} % They are designed to be compatible with expansion only context. All % computations ultimately rely on (and reduce to) usage of the |\numexpr| % primitive from \eTeX{}% % % % \footnote{It can handle only integers, and they must be at most % $2^{31}-1={}$\dtt{\the\numexpr"7FFFFFFF\relax}. Thus some work has to be done % to handle arbitrarily big integers or arbitrary float precision.}. % % % These \eTeX{} extensions date % back to 1999 and are by default incorporated into the |pdftex| % etc...\@ executables from major modern \TeX{} installations for more than % fifteen years now. The interface is: \begin{itemize} \item \csbxint{eval}\marg{expression} handles integers, decimal numbers, numbers in scientific notation and fractions. The algebraic computations are done \emph{exactly}, and in particular \oper{/} simply constructs fractions. Use \oper{//} for floored division. \begin{everbatim*} \xinteval{add(x/(x+1), x = 1000..1014)}\par \end{everbatim*} In this example, the fraction obtained by addition is already irreducible, but this is not always the case, as pointed above Arbitrarily long numbers are allowed in the input. The space character (contrarily to the situation inside |\numexpr|) and also the underscore character (as allowed in Python too) can serve to separate groups of digits for better readability. But the package currently provides no macros to let the output be formatted with such separators. \begin{everbatim*} \xinteval{123_456_789_012^5} \end{everbatim*} \item \csbxint{ieval}\oarg{D}\marg{expression} is the same parser as \csbxint{eval}, i.e. accepts the same inputs and does all computations exactly in the same manner, but it then rounds its final result to the nearest integer, or, in case there is an optional argument |[D]|, to: \begin{itemize} \item if |D>0|: the nearest fixed point number with |D| digits after the decimal mark, \item if |D=0|: the nearest integer (as for \csbxint{ieval} with no optional argument), \item if |D<0|: the rounded quotient by |10^(-D)|. \end{itemize} Prior to |1.4k| the optional argument \oarg{D} had to be located \emph{within} the braces at the start of the expression. The legacy syntax is and will keep being allowed. \item \csbxint{iieval}\marg{expression} executes computations \emph{on (big) integers only.} It is (only slightly) faster than \csbxint{eval} for the same expression. Attention: the forward slash \oper{/} does the \emph{rounded} integer division to match behaviour of |\numexpr|. The \oper{//} operator does floored division as in \csbxint{eval}. The \oper{/:} is the associated modulo operator (we could easily let the catcode 12 |%| character be an alias, but using such an unusual percent character would be a bit cumbersome in a \TeX{} workflow, if only for matters of syntax highlighting in \TeX-aware text editors). \begin{everbatim*} % add the i^5 only if i is a multiple of 7 \xintiieval{add((i/:7)?{omit}{i^5}, i=1000..1020)} \end{everbatim*} \item \csbxint{floateval}\oarg{Q}\marg{expression} does floating point computations with a given precision |P|, as specified via a prior assignment |\xintDigits:=P\relax | (the value |P| can be recovered via \csbxint{theDigits}). Its optional argument |[Q]|, if present, means to do a \emph{final} float rounding to a mantissa of |Q| digits (this thus makes sense only if |Q<P|). A negative |Q| is allowed and means to round to |P+Q| digits only. Prior to |1.4k| the optional argument \oarg{Q} had to be located \emph{within} the braces at the start of the expression. The legacy syntax is and will keep being allowed. The infix operator \oper{/} will compute the correct rounding of the exact fraction. The operator \oper{//} is floored division and \oper{/:} is its associated modulo (see also \func{divmod}). \begin{everbatim*} \begingroup \xintDigits:=64\relax \xintfloateval{sqrt(3)} \endgroup \end{everbatim*} The four basic operations and the square root achieve \emph{correct rounding.}\footnote{when the inputs are already floating point numbers with at most |P|-digits mantissas.} On output, \csbxint{floateval} uses \csbxint{PFloat} for each numeric leaf. This can be modified (cf.\@ \csbxint{floatexprPrintOne}). \end{itemize} % The user can define variables and functions. Definition of functions is either % per parser (\csbxint{deffunc}, \csbxint{deffloatfunc}, ...), but there are % some restrictions, or generic (\csbxint{NewFunction}) but the latter is only % syntactic sugar for function-like disguise of a \TeX{} macro having not done % any pre-parsing. There is a core syntax: \begin{itemize}[nosep] \item \csbxint{expr}\meta{expression}|\relax|, \item \csbxint{iexpr}\meta{expression}|\relax|, \item \csbxint{iiexpr}\meta{expression}|\relax|, \item \csbxint{floatexpr}\meta{expression}|\relax|, \item \csbxint{boolexpr}\meta{expression}|\relax|. \end{itemize} \csbxint{boolexpr}\meta{expression}|\relax| does all computations like \csbxint{expr} then converts all (non-empty) leaves% % \footnote{Currently, empty leaves are output using \csbxint{exprEmptyItem}, i.e.\@ default to \dtt{\xintexprEmptyItem}. This may change.} % to |true| or |false| (cf.\@ \csbxint{boolexprPrintOne}). There is no |\xintbooleval|.\CHANGED{1.4m}\footnote{This was |True| and |False| prior to |1.4m|.} Formerly the \csbxint{expr}|...\relax| legacy syntax had to be prefixed by |\xintthe| in order to appear make it to \TeX{} typesetting engine, else would raise (deliberately) an error. The |\xintthe| prefix is optional since |1.4|. In an |\edef| these constructs expand to some braced nested data, all computations having been completely done, which is prefixed with some |\protected| \myenquote{typesetter} macros. In an |\edef|, \csbxint{eval} (in contrast to \csbxint{expr}), or \csbxint{floateval} (in contrast to \csbxint{floatexpr}) expand the \myenquote{typesetting macros} and the final complete expansion consists of explicit digits and other characters such as those of scientific notation or square brackets.% % \footnote{\csbxint{eval} and \csbxint{expr} both expand completely in exactly two steps. And \csbxint{expr} expands fully under \fexpan sion (of the |\romannumeral0| or |-`0| type). As per \csbxint{eval} attention that it may expand to nothing, then naturally \fexpan sion propagates to tokens following up in the input stream.} In \LaTeX\ it is possible to use the core syntax \csbxint{expr}\meta{expression}|\relax| also in so-called moving arguments, because when written out to a file the final expansion outcome uses only standard catcodes and thus will get retokenized and expand as expected if it has been written to an external file which is then reloaded. One needs \csbxint{eval} et al.\@ only if one really wants the final digits (and other characters), for example in a context where \TeX{} expects a number or a dimension. As alternative to \csbxint{eval}\marg{expression}, an equivalent is \csbxint{the}\csbxint{expr}\meta{expression}|\relax|. Similarly \csbxint{the} can prefix all other core parsers. And one can also use \csbxint{theexpr} as shortcut for \csbxint{the}\csbxint{expr}. Doing exact computations with fractions leads very quickly to very big results (and furthermore one needs to use explicitly the |reduce()| function to convert the fractions into smallest terms). Thus most probably what you want is \csbxint{floateval} and \csbxint{floatexpr}. \subsection{Output customization} \subsubsection{\csh{xintfloatexprPrintOne} et al{.} for numerical values} \label{xintexprEmptyItem} \label{xintexprPrintOne} \label{xintiexprPrintOne} \label{xintiiexprPrintOne} \label{xintfloatexprPrintOne} \label{xintboolexprPrintOne} The package provides only minimal facilities for formatting the output from \csbxint{eval} or \csbxint{floateval} or\dots. And this output may well consist of comma separated values, even nested ones with, by default, square brackets. First we explain how to influence the handling of individual \myenquote{leaves}. Here are the default definitions to this effect: \begin{everbatim} \def\xintexprEmptyItem{[]} % (all parsers) \def\xintexprPrintOne #1{\xintFracToSci{#1}} % \xinteval \def\xintiexprPrintOne #1{\xintDecToString{#1}} % \xintieval \def\xintiiexprPrintOne#1{#1} % \xintiieval \def\xintfloatexprPrintOne [#1]#2{\xintPFloat[#1]{#2}} % \xintfloateval \def\xintboolexprPrintOne#1{\xintiiifNotZero{#1}{True}{False}} \end{everbatim} They can be re-defined to one's wishes. \LaTeX\ users will want to use |\renewcommand| for this. \begin{TeXnote} \begin{itemize} \item Actually, the defaults are more done in the style \begin{everbatim} \let\xintexprPrintOne\xintFracToSci \end{everbatim} thus sparing grabbing the argument |#1|. And one can do \begin{everbatim} \def\xintexprPrintOne{\xintFracToSci} \end{everbatim} too. \item |\xintexprPrintOne| defaults in truth to some private variant of \csbxint{FracToSci} with exactly the same output but able to understand only certain limited types of inputs as used internally. This private variant is not \fexpan dable. \item |\xintfloatexprPrintOne| defaults in fact to a private variant of \csbxint{PFloat} which assumes the optional argument |[P]| is present as it will be the case always in this context. This optional argument |[P]| is the optional argument |[Q]| of \csbxint{floateval} (or |Digis+Q| if |Q<0|). \item The typesetter for \csbxint{iiexpr} simply prints ``as is'', but this may change in future, if some internal format is used requiring a conversion step. \end{itemize} \end{TeXnote} Here is a possibly not up-to-date list of macros of interest, whose documentations you might consider reading (the first two require math mode): \begin{itemize}[nosep] \item \csbxint{TeXFromSci}, \item \csbxint{TeXFrac}, \item \csbxint{DecToString}, \item \csbxint{PRaw}, \item \csbxint{FracToSci}, \item \csbxint{FracToDecimal}, \item \csbxint{PFloat}, \item and \csbxint{FloatToDecimal}. \end{itemize} Naming scheme, as one can see, has been pretty much incoherent, apologies. Among packages providing macros formatting numeric values, there are \ctanpackage{numprint} and its macro |\np| (or |\numprint| without the option |np|), and \ctanpackage{siunitx} and its |\num|, and possibly more packages not known to the author.% % \footnote{There does not seems to be yet a \LaTeX\ user level interface to the \liiistrformat\ package, part of |l3experimental|, which provides an implementation of the Python |format| function.} % These macros are suitable in combination with \csbxint{Float} as in the example below to customize the \csbxint{floateval} output. % 27 mai 2022, en effet \num{1/7} ne marche pas et \numprint{1/7} non plus Numerical output from \csbxint{eval} is more challenging as individual values may naturally contain the |/| character for fractions which the above mentioned packages will not know how to handle, as far as I know. Here an example, with \LaTeX{} and |\num| from \ctanpackage{siunitx}: \begin{everbatim} \def\xintfloatexprPrintOne[#1]#2{\num{\xintFloat[#1]{#2}}} \end{everbatim} We used |\def| with delimited parameters because the optional argument will always be present at time of use, and further the macro will be submitted to |\expanded|, but \LaTeX2e commands with optional arguments defined via |\newcommand| are not compatible with being submitted to |\expanded|. \begin{TeXnote} |\num| is a |\protected| macro, hence it will remain intact in the |\expanded| phase. The argument |\xintFloat[#1]{#2}| will thus expand before |\num| itself. In the case at hand |\num| is a macro which would anyhow have triggered expansion of its argument before further processing. \end{TeXnote} With the |\numprint| macro from \ctanpackage{numprint}, one can do this: \begin{everbatim} \protected\def\xintfloatexprPrintOne[#1]#2{\numprint{\xintPFloat[#1]{#2}}} \end{everbatim} For the |\protected| see the explanations in fine print. The other difference is usage of \csbxint{PFloat} rather than \csbxint{Float}. This is because (in my limited testing) |\numprint| with not silently remove a zero scientific exponent but it will typeset it, for example as $1.5\cdot10^0$. So we use our own \csbxint{PFloat} poor man \myenquote{prettifier}. The current behaviour of \csbxint{floateval} corresponds to this set-up: \begin{everbatim} \def\xintfloatexprPrintOne [#1]#2{\xintPFloat[#1]{#2}} \end{everbatim} and to this default configuration of \csbxint{PFloat}: \begin{everbatim} \def\xintPFloatE{e} \def\xintPFloatZero{0} \def\xintPFloatIntSuffix{} \def\xintPFloatLengthOneSuffix{} \def\xintPFloatNoSciEmax{5} \def\xintPFloatNoSciEmin{-4} \def\xintPFloatMinTrimmed{4} \end{everbatim} With the custom replacement \begin{everbatim} \def\xintfloatexprPrintOne{\xintFloatToDecimal} \end{everbatim} the \csbxint{floateval} output will use decimal fixed point notation, i.e.\@ no scientific exponents, and as many zeros as are needed (but no more, as trailing zeros will be removed from the significant digits). Here is an example comparing outputs from the default configuration and custom ones: \begingroup % DÉBUT DU GROUPE POUR DES EXEMPLES \begin{everbatim*} \xintfloateval{exp(-32.456)/2000} (default, i.e. PFloat)\newline \def\xintfloatexprPrintOne{\xintFloatToDecimal}% \xintfloateval{exp(-32.456)/2000} (FloatToDecimal)\newline \def\xintfloatexprPrintOne[#1]#2{\xintTeXFromSci{\xintFloat[#1]{#2}}}% $\xintfloateval{exp(-32.456)/2000}$ (TeXFromSci on Float)\par % math mode required \end{everbatim*} Some examples showing now the effect of sensible customizations on \csbxint{eval}: \begin{everbatim*} \xinteval{exp(-32.456)/2000} (default, i.e. FracToSci)\newline \def\xintexprPrintOne{\xintFracToDecimal}% \xinteval{exp(-32.456)/2000} (FracToDecimal)\newline \def\xintexprPrintOne#1{\xintTeXFromSci{\xintFracToSci{#1}}}% $\xinteval{exp(-32.456)/2000}$ (TexFromSci on FracToSci)\par % math mode required \end{everbatim*} Notice that the |/2000| denominator remains ``as is'' in the output, in conformity with the documented behaviour of \csbxint{FracToSci} in the first example and of \csbxint{FracToDecimal} for the second example. This has not changed since |1.4| (the handling of the numerator part has changed at |1.4e| and again slightly at |1.4k|, the zero value being now always printed as \dtt{0} and not \dtt{0} or \dtt{0.0} depending on the input) but is to be considered unstable and undecided so far. A slightly more costly typesetter could be for example: \begin{everbatim} \def\xintexprPrintOne#1{\xintDecToStringREZ{\xintIrr{#1}}} \end{everbatim} Then \begin{itemize}[nosep] \item the fraction (inclusive of its power of ten part) will be reduced to lowest terms (see \csbxint{Irr}), \item next the trailing zeros will be moved as an exponent (positive or negative) to the numerator, \item this numerator with a power of ten part will be printed in decimal fixed point notation, with as few zeros as are needed, \item and finally the denominator |B|, which has been trimmed of trailing zeros, will be printed as |/B| or not at all if |B=1|. \end{itemize} With the use case above: \begin{everbatim*} \def\xintexprPrintOne#1{\xintDecToStringREZ{\xintIrr{#1}}} \xinteval{exp(-32.456)/2000}\par \end{everbatim*} This trailing |/2| is somewhat of a pain, but as documented and mentioned already \csbxint{DecToStringREZ} currently has not been educated to identify its presence and handle it. Slightly faster (see \csbxint{PIrr}) is \begin{everbatim} \def\xintexprPrintOne#1{\xintDecToStringREZ{\xintPIrr{#1}}} \end{everbatim} which with the used example produces the same output. One can also consider this for math mode: \begin{everbatim*} \def\xintexprPrintOne#1{\xintTeXFromSci{\xintDecToStringREZ{\xintIrr{#1}}}} $\xinteval{exp(-32.456)/2000}$\par \end{everbatim*} See our hesitations about what \csbxint{TeXFromSci} should do with denominators. \begin{TeXnote} One can hope that in future \csbxint{DecToString} will identify denominators being products of only two's and five's, but even then of course \csbxint{TeXFromSci} will have to decide how to handle other denominators. \end{TeXnote} \endgroup % FIN DU GROUPE POUR LES EXEMPLES \begin{TeXnote} The macro used as customization of \csbxint{exprPrintOne} (whose default is a private variant of \csbxint{FracToSci} with exactly same output) must understand the internal \xintfracname format |A/B[N]|, but with the |/B| and |[N]| parts being only optional. This is not a problem when using for this task (nested) macros of \xintfracname, as they of course accept such inputs as argument and in fact much more general ones. In particular one can benefit from \csbxint{Raw}, or \csbxint{RawBraced}, to convert the argument into a well defined shape (|A/B[N]| for the former and |{N}{A}{B}| for the latter) and then work from there. The macro used by \csbxint{floatexprPrintOne} has the guarantee that the |[P]| will be always present at expansion time. The customization should be compatible with being exposed to |\expanded| (which is like expansion in an |\edef|), either from being completely expandable or at the opposite from being |\protected|. \LaTeX2e commands defined via |\newcommand| as macros with one optional parameter are not compatible with this requirement. Attention! The interface requirements described above for the macros customizing the behaviours of \csbxint{exprPrintOne} and \csbxint{floatexprPrintOne} may change at any release... as they depend on some internal structures and it is not certain backwards compatiblity will be maintained systematically in case of evolution. \end{TeXnote} \subsubsection{\csh{xintthealign} for output of general oples} \label{xintthealign} With \csbxint{thealign} one can get nested data use a \TeX{} alignment in the output. Here is an example : \begin{everbatim*} \xintthealign\xintexpr ndseq(1/(i+j), i = 1..10; j=1..10)\relax \end{everbatim*} Attention, this \csa{xintthealign} must be a prefix to \csbxint{expr}, or \csbxint{floatexpr} etc..., but there will be low-level \TeX\ errors if it is used to prefix \csbxint{eval} et al. or \csbxint{theexpr} et al. It is possible to customize the behaviour of |\xintthealign|. For example: \begin{everbatim} \protected\def\xintexpralignbegin {\halign\bgroup\tabskip2ex\hfil##&&##\hfil\cr}% \def\xintexpralignend {\crcr\egroup}% removed \protected at 1.4c \protected\def\xintexpralignlinesep {,\cr}% separates "lines" \protected\def\xintexpralignleftsep {&}% at left of first item in a "line" % (after "left bracket") \protected\def\xintexpraligninnersep {,&}% at the left of non-first items \protected\def\xintexpralignrightsep {&}% at right of last item in a "line" % (before "right bracket") \protected\def\xintexpralignleftbracket {[}% \protected\def\xintexpralignrightbracket{]}% \end{everbatim} The above definitions use |\protected| with no strong reason, as the replacement tokens are not expanding anyhow, but the idea is that this allows to execute a computation via an |\edef| and later one can change the meaning of the auxiliary macros depending on what one wants to do with the expansion result. \begin{TeXnote} \csa{xintexpralignend} is expanded once, after the body has been submitted to exhaustive expansion (|\expanded| induced), and prior to the expansion of \csa{xintexpralignbegin}. \end{TeXnote} Although we will try to keep stable the way \myenquote{regular arrays} as in the above example are rendered by default,\UNSTABLE{} the |\xintthealign| macro (and its associated customizability) is to be considered work-in-progress and may experience breaking changes. Use for example this for outputting to a file or a terminal:% % {\catcode`^ 12 \footnote{With the |xetex| engine this will need its |-8bit| option else the |^^J| in |\xintexpralignlinesep| will be printed literally instead of being converted into a line separator in the file or terminal output.}} \begin{everbatim} % Better here without \protected. % We assume here \newlinechar has the LaTeX setting. \def\xintexpralignbegin {}% \def\xintexpralignend {}% \def\xintexpralignlinesep {,^^J}% separates "lines" \def\xintexpralignleftsep { }% at left of first item in a "line" (after brackets) \def\xintexpraligninnersep {, }% at the left of non-first items \def\xintexpralignrightsep { }% at right of last item in a "line" (before brackets) \def\xintexpralignleftbracket {[}% \def\xintexpralignrightbracket{]}% \end{everbatim} In the \LaTeX{} example next using a |pmatrix| environment, |\noexpand| rather than |\protected| is used. This environment will not break across pages, contrarily to the display produced by the default \csbxint{thealign} configuration which uses \TeX{}'s |\halign|. %\kern10\baselineskip %\hbox{Big empty space here} %\kern-11\baselineskip \begin{everbatim*} \[ \def\xintexpralignbegin {\begin{pmatrix}}% \def\xintexpralignend {\end{pmatrix}}% \def\xintexpralignlinesep {\noexpand\\}% needed to counteract an internal \expanded \def\xintexpraligninnersep {&}% \let\xintexpralignleftbracket\empty \let\xintexpralignleftsep\empty \let\xintexpralignrightbracket\empty \let\xintexpralignrightsep\empty % by default amsmath matrices can have 10 columns at most % (cf amsmath documentation for what to do to allow more) l.c.m.=\xintthealign\xintiiexpr ndmap(lcm, 1..12; 1..10)\relax \] \end{everbatim*} \subsection{Built-in operators and their precedences} The parser implements precedence rules based on concepts which are summarized below (only for binary infix operators): \begin{itemize}[noitemsep] \item an infix operator has two associated precedence levels, say |L| for left and |R| for right, \item the parser proceeds from left to right, pausing each time it has found a new number and an operator following it, \item the parser compares the left-precedence |L| of the new found operator to the right-precedence |R_last| of the last delayed operation (which already has one argument and would like to know if it can use the new found one): if |L| is at most equal to it, the delayed operation is now executed, else the new-found operation is kept around to be executed first, once it will have gathered its arguments, of which only one is known at this stage. \end{itemize} This means for example in the case of the multiplication \oper{\lowast} and the division operators \oper{/}, \oper{//}, \oper{/:} that they are parsed in a left-associative way because they all share the same (left and right) precedence level. This is the case with the analogous operators from the Python language, as well. At |1.4g| the power operators were changed to act in a right associative way. Again, this matches the behaviour of e.g.\@ Python:% \begin{everbatim*} \xinteval{2^-3^4} \end{everbatim*} \makeatletter \def\@floatboxreset{\@setminipage}% faudra contrôler celui-là \makeatother \begin{table}[htbp] \edef\Ampersand{\string&}% \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 syntax elements whose execution is done prior to 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 the \oper{\empty\lowast} unpacking operator, \item and intrinsic constituents of numbers: decimal mark \oper{\strut.}, \oper{e} and \oper{E} of scientific notation, hexadecimal prefix \oper{"}. \end{itemize}\par\kern-\baselineskip\relax}% \\\hline\hline Precedence&``Operators'' at this level\strut\\ \hline \prec{20}& postfix \oper{!} and branching \oper{?}, \oper{??} operators\strut\\\hline % \prec{-}& minus sign as unary operator inherits the right-\hskip0pt precedence of the infix operator it follows, if that precedence is higher than the one of binary \oper{+} and \oper{-}, else it inherits the latter\strut\\\hline % \prec{18} (17)& \oper{\string^} and \oper{\lowast\lowast} are synonymous; they act in a right-associative way (\textcolor[named]{Red}{\bfseries Changed at 1.4g!})\strut\\\hline % \prec{16} (14)& \hyperref[ssec:tacit multiplication]{Tacit multiplication} has an elevated (left) precedence\strut\\\hline % \prec{14}& \oper{\lowast}, \oper{/}, \oper{//} (floored division), and \oper{/:} (associated modulo, alias \oper{'mod'})\strut\\\hline % \prec{12}& \oper{+}, \oper{-}\strut\\\hline % \prec{10}& \oper{<}, \oper{>}, \oper{==}, \oper{<=}, \oper{>=}, \oper{!=} (they can be chained)\strut\\\hline % \prec{8}& Boolean conjunction \oper{\Ampersand\Ampersand} and its alias \oper{'and'}\strut\\\hline % \prec{6}& Boolean disjunction \oper{\string|\string|} and its alias \oper{'or'}. Also \oper{'xor'} and \oper{\strut..}, \oper{..[}, \oper{{]..}}, and \oper{:} have this precedence\strut\\\hline % \prec{4}& the brackets for slicers and extractors \oper{\empty[}, \oper{\empty]}\strut\\\hline % \prec{3}& the comma \oper{,}\strut\\\hline % \prec{2}& the bracketers \oper{[}, \oper{]} construct nestable \myenquote{arrays}\strut\\\hline % \prec{1}& the parentheses \oper{(}, \oper{)}, and the semi-colon \oper{;} in \func{iter}, \func{rseq}, and further structures\strut\\\hline % \hline % \multicolumn{2}{|p{.6\textwidth}|}{% \begin{itemize}[nosep] \item Binary operators have a left and a right precedence, which for most coincide. The right precedence is indicated within parentheses. \item \hyperref[ssec:tacit multiplication]{Tacit multiplication} has an elevated left precedence level: |(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. \end{itemize} }\\\hline \end{tabular} \caption{Precedence levels} \label{tab:precedences} \etoctoccontentsline {table}{\protect\emph{Table of precedence levels of operators}} \restorehtdpstrutbox \end{table} The entries of \autoref{tab:precedences} are hyperlinked to the more detailed discussion at each level. In these entries the number within parentheses indicates the right-\hskip0pt precedence, if it differs from the left. \begin{description} %[parsep=0pt, listparindent=\leftmarginiii] % [parsep=0pt,align=left,itemindent=0pt, % leftmargin=\leftmarginii, labelwidth=\leftmarginii, labelsep=0pt, % labelindent=0pt, listparindent=\leftmarginiii] \edef\Ampersand{\string&}% \precdesc{$\infty$} At this highest level of precedence, one finds: \begin{description} \item[{\hyperref[ssec:builtinfunctions]{functions} and \hyperref[ssec:uservariables]{variables}}] Functions (even the logic functions \func{!} and \func{?} whose names consist 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.) \operdesc{\empty\lowast} Python-like \myenquote{unpacking} prefix operator. Sometimes one needs to use it as function |*()| (but I can't find an example right now) but most of the time parentheses are unneeded. \operdesc{\strut.} is decimal mark; the number scanner treats it as an inherent, optional and unique component of a being formed number. |\xintexpr 0.^2+2^.0\relax| is interpreted as |0^2+2^0| and thus produces \dtt{\xintexpr 0.^2+2^.0\relax}. Since release |1.2| an isolated decimal mark is illegal input in the \xintexprname parsers (it remains legal as argument to the macros of \xintfracname). \operdesc{e} scientific notation. \operdesc{E} scientific notation. For output, see \csbxint{PFloatE}. \operdesc{"} prefix for hexadecimal input. Only uppercase letters, and one optional |.| separating integer and fractional hexadecimal parts. This functionality \centeredline{\fbox{requires to load explicitly package \xintbinhexname.}}% \begin{everbatim*} \xintexpr "FEDCBA9876543210\relax\newline \xintexpr ".FEDCBA9876543210\relax\newline \xintexpr 16^5-("F75DE.0A8B9+"8A21.F5746+16^-5)\relax \end{everbatim*} It is possible that in future the |"| prefix could be dropped in favour of |0x| prefix. This would free |"| to be used for input of \myenquote{string}-like entities. \end{description} \precdesc{20} The postfix operators |!| and the branching conditionals |?|, |??|. \begin{description} \operdesc{!} computes the factorial of an integer. \operdesc{?} 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.} \operdesc{??} 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{-} As unary operator, the minus sign inherits as precedence the minimum of |12| (which is the precedence for addition and subtraction) and of the (right-) precedence of the operators preceding it (if any). \begin{everbatim*} \xintexpr -3-4*-5^-7, (-3)-(4*(-(5^(-7))))\relax\newline \xintexpr -3^-4*-5-7, (-((3^(-4))*(-5)))-7\relax\newline |2^-10| gives \xintexpr 2^-10\relax\space \end{everbatim*}and is thus perfectly legal, no need for parentheses. The |+| character as prefix unary operator is simply ignored during input parsing. \precdesc{18} \begin{description} \operdesc{\string^} \operdesc{\lowast\lowast} Both compute powers. They act in a right associative way. \begin{everbatim*} \xintiiexpr 2^3^4\relax \end{everbatim*} \end{description} % et: % *2^-3^-4; % (@_1) 0.991479137495678 % *2**-3**-4; % (@_2) 0.991479137495678 % Python: % >>> 2**-3**-4; % 0.9914791374956781 \precdesc{16} see \hyperref[ssec:tacit multiplication]{Tacit multiplication}. \precdesc{14} \begin{description} \operdesc{\lowast} multiplication \operdesc{/} division: \begin{itemize} \item in \csbxint{eval}: exact division in the field of rational numbers (not automatically reduced to lowest terms), \item in \csbxint{floateval}: correct rounding of the exact division; the two operands are, if necessary, float-rounded before the fraction is evaluated and rounded (to obtain the correcty rounded |A/B| without prior rounding of |A| and |B| see \func{qfloat}), \item in \csbxint{iieval}: for compatibility with the legacy behaviour of |/| in |\numexpr|, it rounds the exact fraction \emph{with half-integers going towards the infinity of the same sign}. \end{itemize} The division is left-associative. Example: \begin{everbatim*} \xintexpr reduce(100/50/2)\relax \end{everbatim*} \operdesc{//} floored division (and thus produces an integer, see \func{divmod} for details) \operdesc{/:} the associated modulo (see \func{divmod} and \func{mod}) Left-associativity applies to the division operators: \begin{everbatim*} \xintexpr 100000/:13, 100000 'mod' 13\relax, \xintexpr 100000/:13/13\relax \end{everbatim*} Nothing special needs to be done in contexts such as \LaTeX3 |\ExplSyntaxOn| where |:| is of catcode letter, but if |:| is an active character (for example in \LaTeX\ with babel+french) one needs to use input such as |/\string :| (or replace it with usage of the function \func{mod}). \operdesc{'mod'} is same as \oper{/:}. \fbox{Attention:}\IMPORTANTf{} with \ctanpackage{polexpr} loaded, which allows |'| in variable and function names, |'mod'| can not follow a variable name. Add parentheses around the variable, or use |/:|. \end{description} \precdesc{12} \begin{description} \operdesc{+} addition \operdesc{-} subtraction. According to the general left-associativity rule in case of equal precedence, it is left associative: \begin{everbatim*} \xintiiexpr 100-50-2\relax \end{everbatim*} \end{description} \precdesc{10} Comparison operators are (as in Python) all at the same level of precedence, use parentheses for disambiguation. \begin{description} \operdesc{<} |a<b| evaluates to \dtt{1} if the strict inequality holds to \dtt{0} if not. \operdesc{>} |a>b| evaluates to \dtt{1} if the strict inequality holds to \dtt{0} if not. \operdesc{==} |a==b| evaluates to \dtt{1} if equality holds to \dtt{0} if not. \operdesc{<=} |a<=b| evaluates to \dtt{1} if left hand side is at most equal to right hand side, to \dtt{0} if not. \operdesc{>=} |a>=b| evaluates to \dtt{1} if left hand side is at least equal to right hand side, to \dtt{0} if not. \operdesc{!=} |a!=b| evaluates to \dtt{1} if they differ, to \dtt{0} if not. \end{description} Comparisons can be chained arbitrarily, e.g., |x < y <= z != t| is equivalent to |x < y 'and' y <= z 'and' z != t| (and also to |all(x<y, y<=z, z!=t)|), except that if |y| and |z| involve computations, they are evaluated only once. Currently there is no short-circuit here, i.e.\@ even if some intermediate comparison turns out false (in fact |0|), all the remaining conditionals will still be evaluated. \begin{everbatim*} \xintifboolexpr{1<=2!=3<4>1}{true}{\error}, \xintifboolexpr{1<=2>=3<4>1}{\error}{false}, \xintifboolexpr{3 != 3! == 6 != 4! == 24}{true}{\error} \end{everbatim*} \precdesc{8} \begin{description} \operdesc{\Ampersand\Ampersand} logical conjunction. Evaluates to \dtt{1} if both sides are non-zero, to \dtt{0} if not. \operdesc{'and'} same as \verb+&&+. See also the \func{all} multi-arguments function. \fbox{Attention:}\IMPORTANTf{} with \ctanpackage{polexpr} loaded, which allows |'| in variable and function names, |'and'| can not follow a variable name. Add parentheses around the variable, or use |&&|. \end{description} \precdesc{6} \begin{description} \operdesc{\string|\string|} logical (inclusive) disjunction. Evaluates to \dtt{1} if one or both sides are non-zero, to \dtt{0} if not. \operdesc{'or'} same as as \verb+||+. See also the \func{any} multi-arguments function. \fbox{Attention:}\IMPORTANTf{} with \ctanpackage{polexpr} loaded, which allows |'| in variable and function names, |'or'| can not follow a variable name. Add parentheses around the variable, or use \verb=||=. \operdesc{'xor'} logical (exclusive) disjunction. \fbox{Attention:}\IMPORTANTf{} with \ctanpackage{polexpr} loaded, which allows |'| in variable and function names, |'xor'| can not follow a variable name. Add parentheses around the variable, or use the \func{xor} function syntax. \operdesc{\strut..} \operdesc{..[} \operdesc{{]..}} Syntax for arithmetic progressions. See \autoref{ssec:arithseq}. \operdesc{:} This is a separator involved in |[a:b]| Python-like slicing syntax. \end{description} \precdesc{4} \begin{description} \operdesc{\empty[} \operdesc{\empty]} Involved in Python-like slicing |[a:b]| and extracting |[N]| syntax. And its extension à la NumPy |[a:b,N,c:d,...,:]|. Ellipsis |...| is not yet implemented. The \myenquote{step} parameter as in |[a:b:step]| is not yet implemented. \end{description} \precdesc{3} \begin{description} \operdesc{,} The comma separates expressions (or function arguments).% % \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.} % \begin{everbatim*} \xintiiexpr 2^3,3^4,5^6\relax \end{everbatim*} \end{description} \precdesc{2} \begin{description} \operdesc{[} \operdesc{]} The bracketers construct nestable \myenquote{array-like} structures. Arbitrary (heterogeneous) nesting is allowed. For output related matters see \csbxint{thealign} (its usage is optional, without it rendering is \myenquote{one-dimensional}). Output shape of non-homogeneous arrays is to be considered unstable at this time. \end{description} \precdesc{1} \begin{description} \operdesc{(} \operdesc{)} The parentheses serve as mandatory part of the syntax for functions, and to disambiguate precedences.% % \footnote{It is not apt to describle the opening parenthesis as an operator, but the closing parenthesis is analogous to a postfix unary operator. It has lowest precedence which means that when it is encountered all postponed operations are executed to finalize its operand. The start of this operand was decided by the opening parenthesis.} % They do not construct any nested structure. \operdesc{;} The semi-colon as involved as part of the syntax of \func{iter}, \func{rseq}, \func{ndseq}, \func{ndmap} has the same precedence as a closing parenthesis. \end{description} \item[|\relax|] This is the expression terminator for \csbxint{expr} et al. It may arise from expansion during the parsing itself. As alternative to \csbxint{expr} (et al.) use \csbxint{eval} (et al.) which have the usual macro interface (with one mandatory argument). \end{description} The |;| also serves as syntax terminator for \csbxint{defvar} and \csbxint{deffunc}. It can in this rôle not arise from expansion as the expression body up to it is fetched by a delimited macro. But this is done in a way which does not require any specific hiding for inner semi-colons as involved in the syntax of \func{iter}, etc... \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{!, ?, \textasciigrave\lowast\textasciigrave, \textasciigrave+\textasciigrave, 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, flat, float, float\string_dgt, floor, frac, gcd, if, ifint, ifone, ifsgn, ilog10, iquo, irem, isint, isone, iter, iterr, inv, last, lcm, len, log, log10, max, min, mod, mul, ndmap, ndseq, ndfillraw, not, num, nuple, odd, pArg, pArgd, pfactorial, pow, pow10, preduce, qfloat, qfrac, qint, qrand, qraw, random, randrange, rbit, reduce, reversed, round, rrseq, rseq, sec, secd, seq, sgn, sin, sinc, sind, sqr, sqrt, sqrtr, subs, subsm, subsn, tan, tand, tg, togl, trunc, unpack, xor, zip} \to\Functions \cnta\Functions{0} \cntb\xinttheexpr ceil(\cnta/7)\relax\space \newcommand\builtinfunction[1]{\expandafter\expandafter\expandafter\func \expandafter\expandafter\expandafter{\Functions{#1}}}% \centeredline{\begin{tabular}{|*{7}{p{2cm}|}} \hline \xintFor* #1 in {\xintSeq{1}{\cntb}}\do {\builtinfunction{#1}& \builtinfunction{#1+\cntb}&% \builtinfunction{#1+2*\cntb}&% \builtinfunction{#1+3*\cntb}&% \builtinfunction{#1+4*\cntb}&% \builtinfunction{#1+5*\cntb}&% \ifnumgreater{#1+6*\cntb}{\cnta} {} {\builtinfunction{#1+6*\cntb}}% \\\hline}% \end{tabular}} \caption{Functions (click on names)}\label{tab:functions} \etoctoccontentsline {table}{\protect\emph{Table of functions in expressions}} \etocsetnexttocdepth{subsubsection} \localtableofcontents \end{table} Miscellaneous notes: \begin{itemize}[nosep] \item since release |1.3d| \func{gcd} and \func{lcm} are extended to apply to fractions too, and 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 also for |xetex| since \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. \item Functions may be called with \emph{oples} as arguments as long as the total length is the number of arguments the function expects. \end{itemize} \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. 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\relax \xintthefloatexpr random()\relax\newline \xintthefloatexpr random()\relax\par \end{everbatim*} \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}.% \begin{everbatim*} % still with 37 digits as prevailing float precision \xintthefloatexpr qrand(), random()\relax\newline \xintDigits:=16\relax \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*} \funcdesc[]{rbit} returns a random |0| or |1|. \end{description} \subsubsection{Functions with one 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(10e7/2), reduce(10e7/2)\relax \end{everbatim*} \funcdesc{abs} absolute value \funcdesc{sgn} sign. See also \csbxint{ifsgnexpr}. \funcdesc{inv} inverse. \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}$; 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 \oper{!} 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. 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. 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} belongs 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} except 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. \funcdesc{float\string_dgt} is like \func{float} and avoids \func{float}'s check whether it used with its second optional argument. This is useful in the context of converting function definitions done via \csbxint{deffunc} (see explanations there) to functions usable in \csbxint{floateval}. \funcdesc{nuple} is currently same as |[...]|.\DNU{(1.4)} Reserved for possible alternative meaning in future. \begin{everbatim*} \xinteval{nuple(1,2,3)} \end{everbatim*} \funcdesc{unpack} is alternative for |*| unpacking operator. \begin{everbatim*} \xinteval{unpack([1,2,3])} \end{everbatim*} \funcdesc[ople]{flat} removes all nesting to produce a (non-bracketed) ople having the same leaves (some possibly empty) but located at depth 1. \begin{everbatim*} \xinteval{flat([[[[1,[],3],[4,[[[5,6,[]],[8,9],[[],11]],12],[13,14]]], [[],16]]], [])} \end{everbatim*} I almost\unstable{} delayed indefinitely release because I was hesitating on the name: perhaps better with |flattened()|, but long names add (negligible, but still) overhead compared to short names. For this reason, consider that name may change. \end{description} \subsubsection{Functions with an alphanumeric 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 \ctanpackage{etoolbox}% % % % \footnote{\url{https://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 \ctanpackage{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 an integer multiple of |10^(-n)| (i.e. it \emph{quantizes}). The case of negative |n| is new with |1.4a|. Positive |n| corresponds to conversion to a fixed point number with |n| digits after decimal mark. \begin{everbatim*} \xinteval{round(-2^30/3^5,12), round(-2^30/3^5,-3)} \end{everbatim*} \funcdesc[{x[, n]}]{trunc} Truncates its first argument to an integer multiple of |10^(-n)|. The case of negative |n| is new with |1.4a|. \begin{everbatim*} \xinteval{trunc(-2^30/3^5,12), trunc(-2^30/3^5,-3)} \end{everbatim*} \funcdesc[{x[, n]}]{float} Rounds its first argument to a floating point number, with a precision given by the second argument, which must be positive. \begin{everbatim*} \xinteval{float(-2^30/3^5,12), float(-2^30/3^5, 1)} \end{everbatim*} % AUCTeX EXTREMEMENT PENIBLE AVEC L'INDENTATION FORCEE SOUS M-q For this example and earlier ones if the parser had been \csbxint{floateval}, not \csbxint{eval}, the first argument (here |2^30/3^5|) would already have been computed as floating point number with numerator and denominator rounded separately first to the prevailing precision. To avoid that, use |\xintexpr...\relax| wrapper. Then the rounding or truncation will be applied to an exact fraction. \funcdesc[{x[, n]}]{sfloat} It is the same as \func{float}, 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}$. 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\relax \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 \myenquote{empty range} error in first case if |A| is zero or negative and in second case if |B <= A|. Attention that the arguments are first converted to integers using \csbxint{Num} (i.e.\@ truncated towards zero). 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[m, n]{iquo} Only available in |\xintiiexpr/\xintiieval| context. Computes the Euclidean quotient. Matches with the remainder defined in next item. See \csbxint{iiQuo}. \funcdesc[m, n]{irem} Only available in |\xintiiexpr/\xintiieval| context. Computes the Euclidean remainder. Attention that, following mathematical definition, it is always non-negative. See \csbxint{iiRem}. \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 used parser. If non-zero, it has the same sign as |g|. Prior to |1.2p| it computed |f - g*trunc(f/g)|. The \oper{/:} and \oper{'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. \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 as a bracketed pair 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|. \emph{Those examples behave as in |1.3f| because assignments to multiple variables tacitly unpack if this is necessary.} \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\relax \xintthefloatexpr if(12345678//23==537000, 1, 0), 12345678//23\relax\newline \xintthefloatexpr if(float(12345678//23)==537000, 1, 0)\relax\par \xintDigits := 16\relax \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 \dtt{4} digits of floating point 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. \funcdesc[\TeX-macro, n-uple]{ndfillraw} The second argument is |[N1, N2, ..., Nk]|. The construct fills an |N1xN2x...xNk| hyperrectangular nested list by evaluating the given |macro| as many times as needed. The expansion result goes directly into internal data and must thus comply with what is expected internally for an individual numeric leaf (at |1.4|, \xintfracname raw format worked for |\xintexpr| or |\xintfloatexpr|, but not |\xintiiexpr|, and this may have changed since).\DNU{} This is an experimental function serving to generate either constant or random arrays. Attention that % % BORDEL \textbf{\sffamily...} NON, {\bfseries\sffamily ...} NON % LaTeX Font Warning: Font shape `T1/cmss/b/n' undefined % (Font) using `T1/cmss/m/n' instead on input line 1826. % % ceci est ok {\fontseries{bx}\sffamily\TeX-macro} % https://github.com/latex3/latex2e/issues/277 {\fontseries{bx}\sffamily \TeX-macro} stands here for any expandable \TeX{} \emph{macro}, and an |\xintexpr|-ession at this location thus requires an explicit |\xinteval| wrapping. \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 \oper{?} operator. \funcdesc[x,yes,no]{ifint} (twofold-way conditional)\mbox{} checks if |x| is an integer and in that case chooses the ``yes'' branch.% 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.% 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 \oper{??} operator. \end{description} \subsubsection{Functions with an arbitrary number of arguments} The functions \func{all}, \func{any}, \func{xor}, \func{\textasciigrave+\textasciigrave}, \func{\textasciigrave\lowast\textasciigrave}, \func{max}, \func{min}, \func{gcd}, \func{lcm}, \func{first}, \func{last}, \func{reversed} and \func{len} work both with \myenquote{open} and \myenquote{packed} lists (aka |nutples|). Since |1.4|, when used with a single argument which is a |nutple|, it is automatically unpacked. But from |1.4| to |1.4h| these functions could not be used with a single numeric argument: either they had at least two arguments, or only one and it had to be a |nutple|. At |1.4i| it is again possible to use them with a lone numeric argument. In the specific case of \func{reversed} with a |nutple| argument the output is then repacked so that the output is a |nutple| if and only if the input was one (the reversal does not propagate to deeper nested |nutple|'s, it applies only at depth one). \begin{description} % [parsep=0pt,align=left, % leftmargin=0pt, itemindent=0pt, % labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, % listparindent=\leftmarginiii] \funcdesc[stuff]{qraw} It\DNU{} injects directly tokens to represent internally numerical data. Will break at any release modifying the internal data format specifications (which are not always documented). \funcdesc[x, y, ...]{all} inserts a logical |AND| in-between its arguments and evaluates the resulting logical assertion (as with all functions, all arguments are evaluated). \begin{everbatim*} \xinteval{all(1,1,1), all([1,0,1]), all([1,1,1])} \end{everbatim*} \funcdesc[x, y, ...]{any} inserts a logical |OR| in-between its arguments and evaluates the resulting logical assertion, \begin{everbatim*} \xinteval{any(0,0,0), any([1,0,1]), any([0,0,0])} \end{everbatim*} \funcdesc[x, y, ...]{xor} inserts a logical |XOR| in-between its arguments and evaluates the resulting logical assertion, \begin{everbatim*} \xinteval{xor(1,1,1), xor([1,0,1]), xor([1,1,1])} \end{everbatim*} \funcdesc[x, y, ...]{\textasciigrave+\textasciigrave} adds (left ticks mandatory): \begin{everbatim*} \xinttheexpr `+`(1,3,19), `+`(1**2,3**2,sqr(19)), `+`([1**2,3**2,sqr(19)])\relax \end{everbatim*} \funcdesc[x, y, ...]{\textasciigrave\lowast\textasciigrave} multiplies (left ticks mandatory): \begin{everbatim*} \xinttheexpr `*`(1,3,19), `*`(1^2,3^2,19^2), `*`([1^2,3^2,19^2])\relax \end{everbatim*} \funcdesc[x, y, ...]{max} maximum of the (arbitrarily many) arguments, \begin{everbatim*} \xinttheexpr max(1,3,19), min([1,3,19])\relax \end{everbatim*} \funcdesc[x, y, ...]{min} minimum of the (arbitrarily many) arguments, \begin{everbatim*} \xinttheexpr min(1,3,19), min([1,3,19])\relax \end{everbatim*} \funcdesc[x, y, ...]{gcd} computes the positive generator of the fractional ideal of rational numbers $x\mathbb Z + y\mathbb Z + ... \subset \mathbb Q$. Since |1.4d| the output is always in lowest terms. This example shows how to reduce an n-uple to its primitive part: \begin{everbatim*} \xinteval{gcd(7/300, 11/150, 13/60)}\newline $(7/300, 11/150, 13/60)\to (\xinteval{subsn(seq(reduce(x/D), x = L), D=gcd(L); L=7/300, 11/150, 13/60)})$\newline \xintexpr gcd([7/300, 11/150, 13/60])\relax\par \end{everbatim*} MEMO Perhaps a future release will provide a |primpart()| function as built-in functionality. In case of strict integers, using a |\xintiiexpr...\relax| wrapper is advantageous as the integer-only |gcd()| is more efficient. % % ceci semble encore à peu près exact à 1.4d : % (about |6X|) than the one accepting general fractional inputs. % As \csbxint{iiexpr} accepts only strict integers, doing this may require wrapping the argument in \func{num}. \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$. \begin{everbatim*} \xinttheexpr lcm([7/300, 11/150, 13/60])\relax \end{everbatim*} As for \func{gcd}, since |1.4d| the output is always in lowest terms. % Memo 1.4d: This % function got (I did not tests extensively) a |4X| speed gain for inputs being % only integers For strict integers it is slightly advantageous to use a sub \csbxint{iiexpr}-ession. % % je disais à 1.4: % (about |9X|) than the one accepting general fractional inputs. % mais à 1.4d c'est seulement 2X : le lcm pour les fractions % a quadruplé sa vitesse ! % \funcdesc[x, y, ...]{first} first item of the list or nutple argument: \begin{everbatim*} \xintiiexpr first([last(-7..3), [58, 97..105]])\relax \end{everbatim*} \funcdesc[x, y, ...]{last} last item of the list or nutple argument: \begin{everbatim*} \xintiiexpr last([-7..3, 58, first(97..105)])\relax \end{everbatim*} \funcdesc[x, y, ...]{reversed} reverses the order of the comma separated list or inside a nutple: \begin{everbatim*} \xintiieval{reversed(reversed(1..5), reversed([1..5]))} \end{everbatim*} The above is correct as \xintexprname functions may produce oples and this is the case here. \funcdesc[x, y, ...]{len} computes the number of items in a comma separated list or inside a nutple (at first level only: it is not a counter of leaves). \begin{everbatim*} \xinttheiiexpr len(37.5), len(1..50, [101..150], 1001..1050), len([1..10])\relax \end{everbatim*} \funcdesc[\lowast nutples]{zip} behaves similarly to the Python function of the same name: i.e. it produces \emph{an ople of nutples, where the i-th nutple contains the i-th element from each of the argument nutples. The ople ends when the shortest input nutple is exhausted. With a single nutple argument, it returns an ople of 1-nutples. With no arguments, it returns the empty ople.} As there is no exact match in \xintexprname of the concept of \myenquote{iterator} object,% % \footnote{% Speaking of iterators, I have some ideas about this: as \csbxint{expr} does not have the global expression in its hands it is difficult to organize globally expandably the idea of iterator, but locally via syntax like the one for \func{seq} this is feasible. When one thinks about it, \func{seq} is closely related to the iterator idea.} % there is a significant difference here that (for example) the |zip(x,x,x)| Python idiom to cluster the iterator |x| into successive chunks of length 3 does not apply. Consider for this reason even the name of the function as work-in-progress, susceptible to change.\unstable{} \begin{everbatim*} \xintiieval{zip([1..9], [0, 1, 2], [11..29], [111..139])} \end{everbatim*} See also \csbxint{thespaceseparated} for some possible usage in combination with \func{flat}. \end{description} \subsubsection{Functions requiring dummy variables} \hypertarget{ssec:dummies}{} The pseudo-functions \xintFor #1 in {subs, seq, subsm, subsn, iter, add, mul, rseq, iterr, rrseq, iterr, ndseq, ndmap, ndfillraw} \do {\func{#1}\xintifForLast{}{, }} use delimited macros for some tasks: \begin{itemize} \item for all of them, whenever a |<varname>=| chunk must be parsed into a (non-assigned) variable name, then the equal sign must be visible, \item and if the syntax is with |,<varname>=| the initial comma also must be visible (spaces do not matter), \item for all of them but \func{ndmap} and \func{ndfillraw} the final closing parenthesis must be visible. \end{itemize} Although delimited macros involving commas are used to locate |,<varname=| this is done in a way silently ignoring commas located inside correctly balanced parentheses. Thus, as the examples will show, nesting works as expected. The semi-colons involved in the syntax may arise from expansion alone. For \func{rseq}, \func{iter}, \func{rrseq} and \func{iterr} the |,<varname>=| part may also be created from the expansion which will generate the initial comma separated values delimited by a semi-colon. Prior to |1.4|, semi-colons needed to be braced or otherwise hidden when located in an expression parsed by \csbxint{defvar} or \csbxint{deffunc}, to not be confused with the expression terminator. \func{seq}, \func{rseq}, \func{iter}, \func{rrseq}, \func{iterr} and also \func{add}, \func{mul}, but not \func{subs} admit the \keyword{omit}, \keyword{abort}, and \func{break} keywords. This is a new feature at |1.4| for \func{add} and \func{mul}. In the case of a potentially infinite list generated by the |<integer>++| syntax, use of \keyword{abort} or of \func{break} is mandatory, naturally. All lowercase and uppercase Latin letters are pre-configured for usage as dummy variables. In Unicode engines one can use \csbxint{newdummy} to turn any letter into a usable dummy variable. And since |1.4|, \csbxint{newdummy} works (in all engines) to turn a multi-letter word into a dummy variable. In the descriptions, |varname| stands for such a dummy variable, either single-letter or word. \begin{description} % [parsep=0pt,align=left, % leftmargin=0pt, itemindent=0pt, % labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, % listparindent=\leftmarginiii] \funcdesc[expr, varname=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|. \func{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. But \func{subs} is helpless in function definitions: all places where a variable is substituted will receive the complete recipe to compute the variable, rather than evaluate only once. One should rather define auxiliary functions to compute intermediate results. Or one can use \func{seq}. See the documentation of \csbxint{deffunc}. \funcdesc[expr, varname=values]{add} addition \begin{everbatim*} \xintiiexpr add(x^3,x=1..20), add(x(x+1), x=1,3,19)\relax\newline \xintiiexpr add(x^3, x = 1..[2]..20)\relax\newline % add only odd cubes \xintiiexpr add((odd(x))?{x^3}{omit}, x = 1..20)\relax\par % add only odd cubes \end{everbatim*} At |1.4| (fixed at |1.4a|), the keywords \keyword{omit} (as in example above), \keyword{abort} and \func{break} are allowed. The meaning of \func{break} is specific: its argument serves as last operand for the addition, not as ultimate value. \begin{everbatim*} \xintiiexpr add((x>10)?{break(1000)}{x}, x = 1..15)\relax \end{everbatim*} The |@| special variable holds the so-far accumulated value. Initially its value is zero. \begin{everbatim*} \xintiiexpr add(1 + @, i=1..10)\relax % iterates x <- 2x+1 \end{everbatim*} See \func{\textasciigrave+\textasciigrave} for syntax simply adding items of a list without usage of a dummy variable. \funcdesc[expr, varname=values]{mul} multiplication \begin{everbatim*} \xintiiexpr mul(x^2, x = 1, 3, 19, 37..50)\relax \end{everbatim*} The |@| special variable holds the so-far accumulated value. Initially its value is one. At |1.4| (fixed at |1.4a|), the keywords \keyword{omit}, \keyword{abort} and \func{break} are allowed. The meaning of \func{break} is specific: its argument serves as last operand for the multiplication, not as ultimate value. \begin{everbatim*} \xintiieval{mul((i==100)?{break(i^4)}{i}, i = 98, 99, 100)} \end{everbatim*} See \func{\textasciigrave\lowast\textasciigrave} for syntax without a dummy variable. \funcdesc[expr, varname=values]{seq} comma separated values generated according to a formula \begin{everbatim*} \xintiiexpr seq(x(x+1)(x+2)(x+3),x=1..10), `*`(seq(3x+2,x=1..10))\relax \end{everbatim*} \begin{everbatim*} \smallskip \leavevmode\vbox{\xintthealign\xintiiexpr [seq([seq(i^2+j^2, i=0..j)], j=0..10)]\relax} \end{everbatim*} \funcdesc[initial value; expr, varname=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*} Prior to |1.4| the above example had to be written with |[@]|. This is still possible (|@| stands for an ople with two items, bracketing then extracting is like extracting directly), but it is leaner to drop the extra \myenquote{packing}. \funcdesc[initial value; expr, varname=values]{iter} is exactly like |rseq|, except that it only prints the last iteration. \hypertarget{BrentSalamin}{} |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:= 87\relax % we target 84 digits, and use 3 guard digits \xintdeffloatfunc BS(a, b, t, p):= 0.5*(a+b), sqrt(a*b), t-p*sqr(a-b), \xintiiexpr 2p\relax; \xinteval {trunc(% I feel truncation is better than rounding to display decimals of π \xintfloatexpr iter(1, sqrt(0.5), 1, 1; % initial values % this 43 is 84/2 + 1 (@[0]-@[1]<2e-43)?% stopping criteria; takes into account that the % exit computation (break() argument) doubles % number of exact digits (roughly) {break(sqr(@[0]+@[1])/@[2])} % ... do final computation, {BS(@)}, % else do iteration i=1++) % This generates infinite iteration. The i is not used. \relax % this 83 is 84 - 1 (there is a digit known to be 3 actually, before decimal mark) , 83)% closing parenthesis of trunc() }...% some dots following end of \xinteval argument \xintDigits:=16\relax \end{everbatim*}\newline You can try with |\xintDigits:=1004\relax| and |2e-501| in place of |\xintDigits:=87\relax| and |2e-43|, but be patient for some seconds for the result. Of course don't truncate the final result to only \dtt{83} fractional decimal digits but \dtt{1000}...\@ and better to wrap the whole thing in |\message| or |\immediate\write128| or |\edef| because it will then run in the right margin. Prior to |1.4| the above example had to use notation such as |[@][0]|; this would still work but |@[0]| is leaner. \funcdesc[initial values; expr, varname=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 a list of items in case the initial value is a list and not a single item.% % \footnote{Prior to |1.4|, one could use |@| in |rrseq()| and |iterr()| as an alias to |@1|. This undocumented feature is dropped and |@| will break |rrseq()| and |iterr()|.} % Using |rrseq()| with |@1| etc...\@ accessors may be perhaps a bit more efficient than using |rseq()| with a list as staring value and constructs such as |@[0]|, |@[1]| (or rather |@[-1]|, |@[-2]| to mimick what |@1|, |@2|, |@3|, |@4| and |@@(integer)| do in |rrseq()|. \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, varname=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*} \funcdesc[expr, var1=value1; var2=value2; ....; varN=valueN{[;]}]{subsm} Simultaneous substitutions. The assigned values must not involve the variables. An optional final semi-colon is allowed. \begin{everbatim*} \xintiieval{subsm(x+2y+3z+4t, x=1; y=10; z=100; t=1000;)} \end{everbatim*} \funcdesc[expr, var1=value1; var2=value2; ....; varN=valueN{[;]}]{subsn} Simultaneous substitutions. The assigned values may involve all variables located further to its right. An optional final semi-colon is allowed. \begin{everbatim*} \xintiieval{subsn(x+y+z+t, x=20y; y=20z; z=20t; t=1)} \end{everbatim*} \funcdesc[function, values1; values2; ....; valuesN{[;]}]{ndmap} % Construction of a nested list (a priori having |N| dimensions) from function values. The function must be an |N|-variable function (or a function accepting arbitrarily many arguments), but it is not constrained to produce only scalar values. Only in the latter case is the output really an |N|-dimensional \myenquote{|ndlist|} type object. An optional final semi-colon in the input before the closing parenthesis is allowed. \begin{everbatim*} \xintdeffunc foo(a,b,c,d) = a+b+c+d; \begin{multicols}{2} \xintthealign\xintexpr ndmap(foo, 1000,2000,3000; 100,200,300; 10,20,30; 1,2,3)\relax \end{multicols} \end{everbatim*} \funcdesc[expr, var1=values1; var2=values2; ....; varN = valuesN{[;]}]{ndseq} % Constructs a nested list (a priori having |N| dimensions) from substitutions in an expression involving |N| (dummy) variables. The expression is not constrained to produce only scalar values. Only in the latter case is the output really an |N|-dimensional \myenquote{|ndlist|} type object. An optional final semi-colon in the input before the closing parenthesis is allowed. \begin{everbatim*} \begin{multicols}{2} \xintthealign\xintexpr ndseq(a+b+c+d, a=1000,2000,3000; b=100,200,300; c=10,20,30; d=1,2,3;)\relax \end{multicols}% in case of page break, this makes amusing zigzag rendering \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 are recognized: \begin{description} \keyworddesc{abort} it is a pseudo-variable which indicates to stop here and now. \keyworddesc{omit} it is a pseudo-variable which says to omit this value and go to next one. \funcdesc[stuff]{break} says to abort and insert |stuff| as last value. \keyworddesc{<integer>++} serves to generate a potentially infinite list. In conjunction with an \keyword{abort} or \func{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(@1, i)}{@2+@1}, i=1++)\relax \end{everbatim*}% . If one also wants the previous Fibonacci number one only has to use |break(@2, @1, i)| in the above example. \end{description} \subsection{Generators of arithmetic progressions} \label{ssec:arithseq} \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*} \xintexpr 1.5+0.4..2.3+1.1\relax; \xintexpr 1.9..3.4\relax; \xintexpr 2..3\relax \end{everbatim*} The step of replacing $a$ by its ceil and $b$ by its floor is a kind of silly overhead, but $a$ and $b$ are allowed to be themselves the result of computations and there is no notion of \myenquote{int} type in \csbxint{eval}. The solution is, when $a$ and $b$ are given explicit integers to temporarily switch to the \csbxint{iiexpr} parser: \begin{everbatim*} \xintexpr \xintiiexpr 1..10\relax\relax \end{everbatim*} On the other hand integers from |\xintexpr 1..10\relax| are already in raw \xintfracname format for example |3/1[0]| which speeds up their usage in the macros internally involved in computations...\@ thus perhaps what one gains on one side is lost on the other side. \item |a..[d]..b| generates \myenquote{real} numbers along arithmetic progression of reason |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*} \xintexpr 1.5..[1.01]..11.23\relax \end{everbatim*} At |1.4|, this generator behaves in \csbxint{floatexpr} exactly as in \csbxint{expr}, i.e.\@ \emph{exactly}. This is breaking change. \begin{everbatim*} \xintDigits:=6; \xintexpr\xintfloatexpr 100..[1.23456]..110\relax\relax \xintDigits:=16; \end{everbatim*} This demonstration embedded the float expression in the exact parser only to avoid the rounding to the prevailing precision on output, thus we can see that internally additions are done exactly and not with \dtt{6} digits mantissas (in this example). \end{itemize} \subsection{Python slicing and indexing of one-di\-men\-sional sequences} \label{ssec:lists} We denote here by \emph{list} or \emph{sequence} a general \emph{ople}, either given as a variable or explicitly. \emph{In the former case the parentheses are optional}.% % \footnote{Even for an \myenquote{open list}, if it is given as a \emph{variable} then the indexing or slicing will not apply to its last item but to itself as an entity.} \begin{itemize} \item |(list)[n]| returns the |n+1|th item if |n>=0|. If |n<0| it enumerates items from the tail. Items are numbered as in Python, the first element corresponding to |n=0|. \begin{everbatim*} \xintexpr (0..10)[6], (0..10)[-1], (0..10)[23*18-22*19]\relax \end{everbatim*} This also works for singleton \emph{oples} which are in fact a \emph{number}: \begin{everbatim*} \xintexpr (7)[0], (7)[-1], 9, (7)[-2], 9\relax \end{everbatim*} In the example above the parentheses serve to disambiguate from the raw \xintfracname format such as |7[-1]| which, although discouraged, is accepted on input. And we used a trick to show that |(7)[-2]| returns |nil|. The behaviour changes for singleton \emph{oples} which are not \emph{numbers}. They are thus \emph{nutples}, or equivalently they are the bracketing (bracing, packing) of another \emph{ople}. In this case, the meaning of the syntax for item indexing is, as in Python, item \emph{extraction}: \begin{everbatim*} \xintexpr [0,1,2,3,4,5][2], [0,1,2,3,4,5][-3]\relax\newline \xintexpr [0,[1,2,3,4,5],6][1][-1]\relax \end{everbatim*} \item |(list)[:n]| produces the first |n| elements if |n>0|, or suppresses the last \verb+|n|+ elements if |n<0|. \begin{everbatim*} \xintiiexpr (0..10)[:6]\relax\ and \xintiiexpr (0..10)[:-6]\relax \end{everbatim*} As above, the meaning change for \emph{nutples} and fits with expectations from Python regarding its sequence types: \begin{everbatim*} \xintiiexpr [0..10][:6]\relax\ and \xintiiexpr [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*} \xintiiexpr (0..10)[6:]\relax\ and \xintiiexpr (0..10)[-6:]\relax \end{everbatim*} As above, the meaning change for \emph{nutples} and fit with expectations from Python with \emph{tuple} or \emph{list} types: \begin{everbatim*} \xintiiexpr [0..10][6:]\relax\ and \xintiiexpr [0..10][-6:]\relax \end{everbatim*} \item Finally, |(list)[a:b]| also works according to the Python ``slicing'' rules (inclusive of negative indices). Notice though that stepping is currently not supported. \begin{everbatim*} \xinttheiiexpr (1..20)[6:13]\relax\ = \xinttheiiexpr (1..20)[6-20:13-20]\relax \newline \xinttheiiexpr [1..20][6:13]\relax\ = \xinttheiiexpr [1..20][6-20:13-20]\relax \end{everbatim*} \item It is naturally possible to execute such slicing operations one after the other (the syntax is simplified compared to before |1.4|): \begin{everbatim*} \xintexpr (1..50)[13:37][10:-10]\relax\newline \xintexpr (1..50)[13:37][10:-10][-1]\relax \end{everbatim*} \end{itemize} \subsection{NumPy like nested slicing and indexing for arbitrary oples and nutples} I will give one illustrative example and refer to the NumPy documentation for more. Notice though that our interpretation of the syntax is more general than NumPy's concepts (of basic slicing/indexing): \begin{itemize} \item slicing and itemizing apply also to non-bracketed objects i.e.\@ \emph{oples}, \item the leaves do not have to be all at the same depth, \item there are never any out-of-range index errors: out-of-range indices are silently ignored. \end{itemize} \begin{everbatim*} \begin{multicols}{3} \xintdefvar myArray = ndseq(a+b+c, a=100,200,300; b=40,50,60; c=7,8,9); myArray = \xintthealign\xintexpr myArray\relax \columnbreak mySubArray = \xintthealign\xintexpr myArray[0:2,0:2,0:2]\relax myExtractedSubArray = \xintthealign\xintexpr myArray[0:2,0:2,0:2][0]\relax \columnbreak myExtractedSubArray = \xintthealign\xintexpr myArray[0:2,0:2,0:2][0,1]\relax \noindent firstExtractedScalar = \xintexpr myArray[0:2,0:2,0:2][0,1,0]\relax\newline secondExtractedScalar = \xintexpr myArray[0,1,0]\relax\par \end{multicols} \end{everbatim*} As said before, \emph{stepping} is not yet implemented. Also the NumPy extension to Python for item selection (i.e.\@ via a |tuple| of comma separated indices) is not yet implemented. \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} \centeredline{\textcolor{Red}{\textbf{!!!!ATTENTION!!!!}}} Explicit digits prefixing a variable, or a function, whose name starts with an |e| or |E| will trap the parser into trying to build a number in scientific notation. So the |*| must be explicitly inserted. \begin{everbatim} \xintdefiivar e := (2a+4b+6d+N)/:7;% \xintdefiivar f := (c+11d+22*e)//451;% 22e would raise errors \end{everbatim} I don't think I will fix this anytime soon... \end{framed} \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 with a division operator as the last seen operator, as multiplication is mathematically associative. \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{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. Since |1.2p| simultaneous assignments are possible. Since |1.4| simultaneous assignments are possible with a right-hand-side being a |nutple| which will be automatically unpacked. \begin{everbatim*} \xintdefvar myPi:=3.141592653589793238462643;% $myPi = \xinteval{myPi}$\newline % (there is already built-in Pi variable) \xintdefvar x_1, x_2, x_3 := 10, 20, 30;% $x_1 = \xinteval{x_1}, x_2 = \xinteval{x_2}, x_3 = \xinteval{x_3}$\newline \xintdefvar x_1, x_2, x_3 := [100, 200, 300];% $x_1 = \xinteval{x_1}, x_2 = \xinteval{x_2}, x_3 = \xinteval{x_3}$\par \end{everbatim*} Simultaneous assignments with more variables than values do not raise an error but simply set the extra variables to the \dtt{nil} value. \begin{everbatim*} \xintdefiivar a, b, c := [1, 2];% will be automatically unpacked The value of a is \xinteval{a}, the one of b is \xinteval{b} and the one of c is \xinteval{c}. \end{everbatim*} \begin{everbatim*} \xintdefiivar a, b, c := 314;% The value of a is \xinteval{a}, the one of b is \xinteval{b} and the one of c is \xinteval{c}. \end{everbatim*} Notice that \dtt{nil} variables must be used with caution as they break arithmetic operations if used as operands to them. And they are not the same as the \dtt{None} variables, which can also be input as |[]|. Simultaneous assignments with less variables than values do not raise an error but set the last variable to be the ople concatenating the remaining values. \begin{everbatim*} \xintdefiivar seq := 1..10;% \xintdefiivar a, seq := seq;% \xintdefiivar b, seq := seq;% \xintdefiivar c, d, seq := seq;% The value of a is \xinteval{a}, the one of b is \xinteval{b}, the one of c is \xinteval{c}, the one of d is \xinteval{d}, the one of seq is \xinteval{seq}. \end{everbatim*} In the above we define a variable |seq| but there is a built-in function \func{seq}. It is indeed allowed to use the same name for both a variable and a function.% % \footnote{But until a bugfix added at release |1.4i|, some built-in function names (those implementing syntax with dummy variables, and the so-called \myenquote{pseudo}-functions) were fragile under such overloading.} But for safety we will unassign |seq| now: \begin{everbatim*} \xintunassignvar{a}\xintunassignvar{b}\xintunassignvar{c}\xintunassignvar{d}% \xintunassignvar{seq}% \end{everbatim*}% Single letter names |a..z| and |A..Z| are pre-declared by the package for use as a special type of variables called ``dummy variables''. Unnassigning them restores this initial meaning. See further \csbxint{unassignvar} and \csbxint{newdummy}. Since |1.4| even assigned variables can be used in the call signatures of function declarations. Regarding the manipulation of an \myenquote{open list} as above, there is no way to obtain with only one use of the variable both its last item and the reduction of the variable to its truncated self. One can do rather: \begin{everbatim*} \xintdefiivar mylist := 1..10;% \xintdefiivar z, mylist := last(mylist), mylist[:-1];% The value of z is \xinteval{z} and mylist is now \xinteval{mylist}.\par \end{everbatim*} This uses twice |mylist| and is about the same as doing it in two steps: \begin{everbatim*} \xintdefiivar w := last(mylist);% \xintdefiivar mylist := mylist[:-1];% The value of w is \xinteval{w} and mylist is now \xinteval{mylist}.% \xintunassignvar{z}\xintunassignvar{w}\xintunassignvar{mylist}\par \end{everbatim*} It is recommended generally speaking to work with \myenquote{closed (i.e. bracketed) lists} because only them and numbers can be arguments to functions (but see \csbxint{deffunc} and the notion of variadic last argument). For more on the Python-like slicing used above see \autoref{ssec:lists} and \autoref{sssec:opleslicing}. For more information relative to variables versus arguments see \autoref{sssec:funcargs}. \begin{itemize}[noitemsep] \item For catcodes issues (particularly, for the semi-colon used to delimit the fetched expression), see the discussion of \csbxint{exprSafeCatcodes}. \item Both syntaxes |\xintdefvar foo := <expr>;| and |\xintdefvar foo = <expr>;| are accepted. \item Spaces in the variable name or around the equal sign are removed and are immaterial. \item 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 |x0|, |x1|, \dots, |x10| for future usage. \end{itemize} Legal variable names are composed of letters, digits, |_| and |@| and characters. A variable name must start with a letter. Variable names starting with a |@| or |_| are reserved for internal usage.% % \footnote{The process of variable declaration does not check that these rules are met, and breakage will arise on use, if rules are not followed. For example, prior to |1.4g|, using a variable (illegally) declared with a name starting with a (normal, catcode 8) |_| triggered an infinite loop.} As |x_1x_2| or even |x_1x| are licit variable names, and as the parser does not trace back its steps, input syntax must be |x_1*x_2| if the aim is to multiply such variables. Using \csa{xintdefvar}, \csa{xintdefiivar}, or \csa{xintdeffloatvar} means that the variable value will be computed using respectively \csa{xintexpr}, \csa{xintiiexpr} or \csa{xintfloatexpr}. It can then be used in all three parsers, as long as the parser understands the format. Currently this means that variables using \csa{xintdefvar} or \csa{xintdeffloatvar} can be used freely either with \csa{xintexpr} or \csa{xintfloatexpr} but not with \csa{xintiiexpr}, and variables defined via \csa{xintdefiivar} can be used in all parsers. When defining a variable with \csa{xintdeffloatvar} it (or generally speaking its numerical leaves) is rounded to \csbxint{theDigits} precision. So the variable holds the same value as would be printed via \csbxint{floateval} for the same computation. Prior to |1.4e|, this was the case only if the variable definition actually involved some computation. However the \csbxint{floatexpr}|..\relax| wrapper by itself induces no rounding. If it is encountered in the typesetting flow, the print-out will be rounded to \csbxint{theDigits} precision, but this is an effet of behaving like \csbxint{floateval} in this context. \begin{everbatim*} % Since 1.4e, \xintdeffloatvar always rounds (to \xinttheDigits) \xintdeffloatvar e:=2.7182818284590452353602874713526624977572470936999595749669676;% 1) \xintexpr e\relax\newline % shows the recorded value: it is rounded \xintunassignvar{e} 2) \xintfloatexpr % when used in typesetting flow, acts like \xintfloateval: 2.7182818284590452353602874713526624977572470936999595749669676 \relax\newline % the print-out is rounded. 3) \xintexpr \xintfloatexpr 2.7182818284590452353602874713526624977572470936999595749669676 \relax \relax\newline % % but we can see via the \xintexpr wrapper all the digits were there rounding % can be forced using an extra 0+, the float() function, or the [D] option. % tidbit: comparison operators do not pre-round, so 1.2345678 is not same as % (1.2345678+0) in low precision. % \begingroup\xintDigits:=4;% 4) \xintifboolfloatexpr{1.2345 == 1.23456} {\error}{Different! Comparisons do not pre-round to Digits precision.}\newline 5) \xintifboolfloatexpr{1.2345 == 1.2345 + 0} {\error}{Different! Right hand side rounded from operation, left hand side not rounded.}\par \endgroup \end{everbatim*} % not so exciting example % 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\relax % \xintthefloatexpr[16] e, e^1000, e^1000000\relax (e rounded to 24 digits first)\newline % \xintDigits:=16\relax % \xintthefloatexpr e, e^1000, e^1000000\relax (e rounded to 16 digits first)\par % \end{everbatim*} After issuing \csbxint{verbosetrue} the values of defined variables are written out to the log (and terminal). As in this example: \begin{everbatim} Package xintexpr Info: (on line 1) Variable myPi defined with value {3141592653589793238462643[-24]}. Package xintexpr Info: (on line 2) Variable x_1 defined with value {10}. Package xintexpr Info: (on line 2) Variable x_2 defined with value {20}. Package xintexpr Info: (on line 2) Variable x_3 defined with value {30}. Package xintexpr Info: (on line 3) Variable List defined with value {0}{1}{3}{6}{10}{15}{21}{28}{36}{45}{55} . Package xintexpr Info: (on line 4) Variable Nuple defined with value {{0}{1}{9}{36}{100}{225}{441}{784}{1296 }{2025}{3025}}. Package xintexpr Info: (on line 5) Variable FourthPowers defined with value {{0}{1}{81}{1296}{10000}{50625}{ 194481}{614656}{1679616}{4100625}{9150625}}. \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 without waiting the end of the scope one issues \csa{xintunassignvar}\marg{variable}. 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*} \xintunassignvar{e}% % 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. Starting with |1.4|, it is allowed to use \csa{xintnewdummy} with multi-letter names (obeying the condition for being a variable name). \subsubsection{\csh{xintensuredummy}, \csh{xintrestorevariable}} \label{xintensuredummy} \label{xintrestorevariable} Use \begin{everbatim} \xintensuredummy{<character>} ... ... code using the (catcode 11) character as a dummy variable ... \xintrestorevariable{<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\tocstylesubsubsectionHOOK#1#2#3{} \etocsetnexttocdepth{subsubsection} \localtableofcontents \let\tocstylesubsubsectionHOOK\empty \subsubsection{\csh{xintdeffunc}} \label{xintdeffunc} Here is an example: \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)|.) \begin{framed} \begin{itemize} \item The ending semi-colon is allowed to be of active catcode, as |\xintdeffunc| temporarily resets catcodes before parsing the expression. But this will fail if the whole thing is inside a macro definition. Then the used semi-colon must be the standard one. \item Semi-colons used inside the expression need not be hidden inside braces. (new with |1.4|) \item The colon before the equal sign is optional and its (reasonable) catcode does not matter. \end{itemize} \end{framed} 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 variable names used in the function signature may be multi-letter words. It is also allowed for them to already be in use for previously declared variables. Their meanings will get restored for usage after the function declaration. \item A function can be declared with at most nine arguments. It can be declared as a function with no arguments. \item If in the function declaration the last argument is prefixed by |*|, it stands for a |nutple| which will gather all arguments of the function call beyond the first positional ones. See \autoref{sssec:funcargs} for additional explanations on such \myenquote{variadic} arguments. \item Recursive definitions are possible; for them to not generate error or fall in infinite loops, the use of the short-circuit conditionals |?| and |??| is \emph{mandatory}. \item If a function is used in another definition it will check if it is applied to numerical arguments and if this is the case will expand fully. \item The previous item has an exception for functions with no arguments; they never expand immediately in other function definitions (else they would be almost like variables). This provides a way to define functions with parameters: simply let their definition use some functions with no arguments. \item A function declared via \csbxint{deffunc} remains \fbox{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 with scalar values like this: \begin{everbatim} \xintdeffloatfunc foo(x) := float_dgt(\xintexpr foo(x)\relax); \end{everbatim} The \func{float\string_dgt} wrapper (which was renamed at |1.4e|) is in order for the float variant to produce an already-rounded value, possibly speeding-up usage if used as input for other functions. Using \func{float} here would work the same but the produced function would incorporate a routine to check (at time of use, because at time of definition it is impossible to tell what will be the case) if it is applied to one or two arguments. \item 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 inner \func{float} above is not mandatory but recommended: the macro associated to the user float function |bar(x)| may use many times its argument |x| and does not worry about rounding it, because its expectation is that it is already rounded; 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. Here it is not needed to use \func{float\string_dgt}, because it will be identified at time of definition that \func{float} is used without optional argument. An external \func{float\string_dgt} could be added but is not a priori necessary, except perhaps if the |bar()| function has been defined at a low level using support macros producing output with garbage extra digits, which usually would be rounded out in input to other float functions. \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 \csbxint{verbosetrue}. Here it is (it has at |1.4| an extra external brace pair compared to what happened with earlier releases): \begin{everbatim} Function e for \xintexpr parser associated to \XINT_expr_userfunc_e with me aning macro:#1->{\xintAdd {\xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\x intDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\ xintAdd {\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 above is not entirely true. At |1.4|, \csbxint{deffunc} is more powerful and digests more of the syntax but it may have to store it in such a way that usage will be done via a sub-expression: hence it is not the case that the original expression has been \emph{entirely} parsed. See \csbxint{NewFunction} for related discussion. The main difficulty of \csbxint{deffunc} is with the pseudo-functions \func{seq}, \func{iter}, etc..., which admit the keywords \keyword{omit}, \keyword{abort}, \func{break}. We have no alternative for them, if the iterated over values are not entirely numerical than to postpone expansion, but this means simply storing for later a possibly big sub-expression. At |1.4| we did some obstinate work to make this working but: \begin{itemize} \item this means that the stored function body has not been entirely parsed, parsing will happen on the fly at each execution for small or large bits, \item there remains a main stumbling-block. If the variables used in the function declaration are used only in the iterated over values or the initial values, then the mechanism may work. If however they are used not only in those values iterated over but directly in the expression which the generators map to the iterated over values, then it will break certainly. Indeed at this stage the variables are simply names, and it is impossible to transfer the mechanism which converts these names into numerical arguments for delayed usage by the declared function. Except if one is ready to basically freeze the entire thing; which then is not any different at all than using \csbxint{NewFunction}. \end{itemize} Conclusion: if some \csbxint{deffunc} break, check if it does not fit the above criterion before reporting...\@ and recall \csbxint{NewFunction} is your friend. It has the big advantage of declaring a function for all parsers simultaneously! A special note on \func{subs}: it is and has always been hopeless in \csbxint{deffunc} context. All it does (if it works at all) after being malaxed by \csbxint{deffunc} is to copy over at the indicated places the \emph{recipe} to compute something. Thus at every location where that something is needed it will be evaluated from scratch again. Yes, this is disappointing. But...\@ on the other hand the more general \func{seq} does work, or pretends to work. Let me illustrate to make thinks clear. We start with this: \begin{everbatim*} \xintverbosetrue \xintdeffunc foo(x,y,z) = subs(S + S^2, S = x+y+z); \xintdeffunc bar(x,y,z) = seq(S + S^2, S = x+y+z); \xintexpr foo(100,10,1), bar(100,10,1)\relax \xintverbosefalse \end{everbatim*} It produces in the log: \begin{everbatim} Package xintexpr Info: (on line 2) Function foo for \xintexpr parser associated to \XINT_expr_userfunc_foo wit h meaning macro:#1#2#3->{\xintAdd {\xintAdd {\xintAdd {#1}{#2}}{#3}}{\xintPow { \xintAdd {\xintAdd {#1}{#2}}{#3}}{2}}} Package xintexpr Info: (on line 3) Function bar for \xintexpr parser associated to \XINT_expr_userfunc_bar wit h meaning macro:#1#2#3->\expanded \bgroup \expanded {\unexpanded {\XINT_expr_se q:_b {\xintbareeval S + S^2\relax !S}}{\xintAdd {\xintAdd {#1}{#2}}{#3}}^} \end{everbatim} Even without understanding all details one sees that in the first case the |\xintAdd {\xintAdd {#1}{#2}}{#3}}| appears twice, and in the second case only once. But in the second case we have a yet to evaluate expression. So the second approach is not much different in its effect than using the more simple-minded \csbxint{NewFunction}. Besides one gets a feeling why the function arguments can not appear in the expression but only in the iterated over values, because there is no way to understand what |x|, |y|, |z| are supposed to mean without adding extra structure showing they map to |#1|, |#2|, |#3|. The above remarks apply to \func{subsm} and \func{subsn}. Even if they do work in \csbxint{deffunc} context (warning, testing at |1.4| release has remained minimal), they will not bring added efficiency if the substituted values are to be used multiple times. They may still be useful to visually simplify the input of a big expression by expressing it in terms of smaller constituents. Another workaround if one wants genuine (not \myenquote{macro}-) functions for some expression where the same thing is used multiple times is to define helper functions computing the intermediate data. One can see illustrations of this in the code source of \xinttrigname (or in the matrix multiplication example at the end of this chapter). \subsubsection{\csh{xintdefiifunc}} \label{xintdefiifunc} With \csbxint{deffunc} the created function is known by the \csbxint{expr} parser only. 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}. Note: the optional argument |[Q]| accepted by \csbxint{floatexpr} does not work with \csbxint{deffloatfunc}. It is still possible to wrap the expression in |float(expression,Q)|, if it evaluates to a scalar. \subsubsection{\csh{xintdefufunc}, \csh{xintdefiiufunc}, \csh{xintdeffloatufunc}} \label{xintdefufunc} \label{xintdefiiufunc} \label{xintdeffloatufunc} This allows to define so-called \myenquote{Universal functions}. This is terminology borrowed from |NumPy|. Here is an example: \begin{everbatim*} \xintdefiivar Array = ndmap(lcm, 1..5; 1..10; 1..10); Array = \xintthealign\xintiiexpr Array\relax \xintdefiiufunc foo(x) = x^3; \begin{figure}[htbp] \caption{Output of a universal function acting on an array}\label{fig:ufunc} \centeredline{$\vcenter{\xintthealign\xintiiexpr foo(Array)\relax}$} \end{figure} See \autopageref{fig:ufunc} for the output. \end{everbatim*} The function can be applied to any nested strucure: \begin{everbatim*} \xintiiexpr foo([1, [2, [3, [4, [5, 6, 7, 8, 9, 10]]]]])\relax \end{everbatim*} It must be defined as function acting on scalars, but its value type is not constrained. \begin{everbatim*} \xintdefiivar Array = [1..10]; \xintdefiiufunc foo(x) = [1..x]; \xintthealign\xintiiexpr foo(Array)\relax \end{everbatim*} It is even allowed to produce oples and act on oples: \begin{everbatim*} \xintdefiivar Ople = 1..10; \xintdefiiufunc bar(x) = x, x^2, x^3; \xintiiexpr bar(Ople)\relax \end{everbatim*} \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*} \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}. \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 {\xintS ub {\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} \begin{framed} The meanings written out to the log for more complicated functions may sometimes use the same character at different locations but with different catcodes.\IMPORTANTf It may thus be impossible to retokenize it (even after having removed the extra spaces from the added line breaks). This is in contrast with variable values which are always output in the log in the benign way, using digits, braces and some characters of catcode 12. \end{framed} \subsubsection{\csh{ifxintglobaldefs} conditional} \label{xintglobaldefstrue} \label{xintglobaldefsfalse} \label{ifxintglobaldefs} If true user defined variables (\csbxint{defvar}, ...) and functions (\csbxint{deffunc}, ..., \csbxint{NewFunction}) for the expression parsers, as well as macros obtained via \csbxint{NewExpr} et al.\@ have global scope. If false (default) they have local scope. \subsubsection{\csh{xintNewFunction}} \label{xintNewFunction} This is syntactic sugar which allows to use notation of functions for what is nothing more in disguise than a \TeX{} macro. Here is an example: \begin{everbatim*} \xintNewFunction {foo}[3]{add(mul(x+i, i=#1..#2),x=1..#3)} \end{everbatim*} We now have a genuine function |foo()| of three variables which can be used in \emph{all three parsers}. \begin{everbatim*} \xintexpr seq(foo(0, 3, j), j= 1..10)\relax \end{everbatim*} Each time the created \myenquote{macro-function} |foo()| will be encountered the corresponding replacement text 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). It differs fundamentally from \csbxint{deffunc} as it realizes no pre-parsing whatsoever of the associated sub-expression; using it shortens the input but not the parsing time (which however is most of the time negligible compared to actual numerical computations). Use it for syntax which \csbxint{deffunc} does not parse successfully. \subsection{Examples of user defined functions} \subsubsection{Example with vectors and matrices} \label{sssec:csv} Suppose we want to manipulate 3-dimensional vectors, which will be represented as |nutples| of length 3. And let's add a bit of matrix algebra. \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); \xintdeffunc DetMat(M) = Det3(*M); \xintdeffunc RowMat(U, V, W) := [U, V, W]; \xintdeffunc ColMat(U, V, W) := [[U[0], V[0], W[0]], [U[1], V[1], W[1]], [U[2], V[2], W[2]]]; \xintdeffunc MatMul(A, B) := [[A[0,0]*B[0,0]+A[0,1]*B[1,0]+A[0,2]*B[2,0], A[0,0]*B[0,1]+A[0,1]*B[1,1]+A[0,2]*B[2,1], A[0,0]*B[0,2]+A[0,1]*B[1,2]+A[0,2]*B[2,2]], [A[1,0]*B[0,0]+A[1,1]*B[1,0]+A[1,2]*B[2,0], A[1,0]*B[0,1]+A[1,1]*B[1,1]+A[1,2]*B[2,1], A[1,0]*B[0,2]+A[1,1]*B[1,2]+A[1,2]*B[2,2]], [A[2,0]*B[0,0]+A[2,1]*B[1,0]+A[2,2]*B[2,0], A[2,0]*B[0,1]+A[2,1]*B[1,1]+A[2,2]*B[2,1], A[2,0]*B[0,2]+A[2,1]*B[1,2]+A[2,2]*B[2,2]]]; \xintdefvar vec1, vec2, vec3 := [1, 1, 1], [1, 1/2, 1/4], [1, 1/3, 1/9]; \xintdefvar mat1 = RowMat(vec1, vec2, vec3); \xintdefvar mat2 = ColMat(vec1, vec2, vec3); \xintdefvar mat12 = MatMul(mat1,mat2); \xintdefvar mat21 = MatMul(mat2,mat1); Some computations (|align| executes multiple times hence we pre-computed!): \begin{align*} M_1 &= \vcenter{\xintthealign \xintexpr mat1\relax}&&\qquad M_2 . M_1 = \vcenter{\xintthealign \xintexpr mat21\relax}\\[3\jot] M_2 &= \vcenter{\xintthealign \xintexpr mat2\relax}&&\qquad M_1 . M_2 = \vcenter{\xintthealign \xintexpr mat12\relax} \end{align*} $$ \det(M_1) = \xinteval{DetMat(mat1)},\quad \det(M_1.M_2) = \xinteval{reduce(DetMat(mat12))},\quad \det(M_2.M_1) = \xinteval{reduce(DetMat(mat21))} $$ \end{everbatim*}% For some hair-raising experience check the \csbxint{verbosetrue} output in the log...\@ here is an alternative with two (three, counting |dprod()|) helper functions: \begin{everbatim*} % annoying that Tr also starts Trace, but Spur is available % well Sp also starts Spectrum. Big problems. \xintdeffunc Tr(M) := [[M[0,0], M[1,0], M[2,0]], [M[0,1], M[1,1], M[2,1]], [M[0,2], M[1,2], M[2,2]]]; \xintdeffunc MatMul_a(r1, r2, r3, c1, c2, c3) := [[dprod(r1, c1), dprod(r1, c2), dprod(r1, c3)], [dprod(r2, c1), dprod(r2, c2), dprod(r2, c3)], [dprod(r3, c1), dprod(r3, c2), dprod(r3, c3)]]; \xintdeffunc MatMul(A, B) := MatMul_a(*A, *Tr(B)); \end{everbatim*} And once we have the transpose and the scalar product of vectors, we can simply use \func{ndmap} for a lean syntax (this would extend to arbitrary dimension): \begin{everbatim*} \xintdeffunc MatMul(A, B) = ndmap(dprod, *A; *Tr(B)); \xintdefvar mat1212 = MatMul(mat12, mat12); \begingroup \def\xintexprPrintOne #1{\xintTeXFrac{#1}}% \def\xintexpralignbegin {\begin{pmatrix}}% \def\xintexpralignend {\end{pmatrix}}% \def\xintexpralignlinesep {\noexpand\\[2\jot]}% counteract an internal \expanded \def\xintexpraligninnersep {&}% \let\xintexpralignleftbracket\empty \let\xintexpralignleftsep\empty \let\xintexpralignrightbracket\empty \let\xintexpralignrightsep\empty $$ \xintthealign \xintexpr mat1\relax \cdot \xintthealign \xintexpr mat2\relax \cdot \xintthealign \xintexpr mat1\relax \cdot \xintthealign \xintexpr mat2\relax = \xintthealign \xintexpr mat12\relax ^2 = \xintthealign \xintexpr mat1212\relax$$ $$ \det(M_1\cdot M_2 \cdot M_1 \cdot M_2) = \xinteval{reduce(DetMat(mat1212))}$$ \endgroup \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\relax \xintthefloatexpr Rump(77617,33096)#\cr \xintiloop [8+1] \xintiloopindex &\relax\CR \ifnum\xintiloopindex<40 \repeat } \end{everbatim*} \subsubsection{Examples of recursive definitions} \label{sssec:recursive} Recursive definitions \emph{require} using the short-circuit branching operators. \begin{everbatim*} \xintdeffunc GCD(a,b):=(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*} There is already a built-in \func{gcd} (which accepts arbitrarily many arguments): \begin{everbatim*} \xinttheexpr gcd(385/102, 605/238)\relax \end{everbatim*} Our second example is modular exponentiation: \begin{everbatim*} \xintdefiifunc powmod_a(x, m, n) := isone(m)? % m=1, return x modulo n { x /: n } % m > 1 test if odd or even and do recursive call { odd(m)? { x*sqr(powmod_a(x, m//2, n)) /: n } { sqr(powmod_a(x, m//2, n)) /: n } } ; \xintdefiifunc powmod(x, m, n) := (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| behaved the same until |3.8| release), but zealous users will add the necessary code for negative exponents, after having defined another function for modular inverse! 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... \subsection {Links to some (old) 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} % ça va sans dire % 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{Oples and nutples: the \texttt{1.4} terminology} \label{oples} \emph{Skip this on first reading, else you will never start using the package.} \fbox{SKIP THIS!} (understood?) In this section I will describe a mathematical terminology which models how the parser handles the input syntax with numbers, commas, and brackets, and how it maps internally to \TeX\ specific concept, particularly braces and macro arguments. \etocsetnexttocdepth{subsubsection} \localtableofcontents \subsubsection{Base terminology} We start with a set $\mathcal{A}$ of \emph{atoms}, which represent numeric data. In \TeX{} syntax such \emph{atoms} are always braced, more precisely, currently they look like % \centeredline{\dtt{\{raw format within \TeX{} braces\}}} % The \TeX{} braces are not set-theoretical braces here, they are simply used for \TeX nical reasons (one could imagine using rather some terminator token, but ultimately support macros for built-in and user defined functions rely on \TeX\ macros with undelimited parameters, at least so far). Our category $\mathcal{C}$ of \myenquote{oples} is the smallest collection of \emph{totally ordered finite sets} verifying these properties: \begin{enumerate} \item The empty set \dtt{$\emptyset$} is an \emph{ople}, i.e.\@ it belongs to $\mathcal{C}$. \item Each singleton set \dtt{$\{O\}$} whose element \dtt{$O$} is either an \emph{atom} $a\in\mathcal{A}$ or an \emph{ople} qualifies as an \emph{ople}. \item $\mathcal{C}$ is stable by concatenation. \end{enumerate} Notes: \begin{itemize} \item We refer to the empty set \dtt{$\emptyset$} via the variable \emph{nil}.% % \footnote{There is actually a built-in variable with this name. At |1.4|, |\xintexpr\relax| is legal and also generates the \emph{nil}.} \item It is convenient to accept the empty set as being also an \emph{atom}. If this is done, then we may refer to the original \emph{atoms} (elements of $\mathcal{A}$) as \emph{non empty numerical data}. \item Concatenation is represented in the syntax by the comma. Thus repeated commas are like only one and |nil| is a neutral element. \item A singleton \emph{ople} \dtt{$\{a\}$} whose single element is a (non-empty) \emph{atom} is called a \emph{number}.% % \footnote{This has to be taken in a general sense, for example with \ctanpackage{polexpr}, polynomials are represented by such \myenquote{numbers}.} % \item The operation of constructing \dtt{$\{O\}$} from the \emph{ople} \dtt{$O$} is called \emph{bracing} (set theory, \TeX), or \emph{bracketing} (\xintexprname input syntax, Python |lists|), or \emph{packing} (as a reverse to Python's unpacking of sequence type objects). In the expression input syntax it corresponds to enclosing \dtt{$O$} within square brackets: \dtt{$[O]$}. \item A braced \emph{ople} is called a \emph{nutple}. Among them \dtt{\{nil\}} (aka $\{\emptyset\}$) is a bit special. It is called the \emph{none-ple}.% % \footnote{Prior to version |1.4j| of this documentation it was called the \emph{not-ple}.} % It is not \dtt{nil}.% % \footnote{There is (experimental) a pre-defined \myenquote{\dtt{None}} variable which stands for the \emph{none-ple}. It can also be input as |[]|.} \end{itemize} Each \emph{ople} has a \emph{length} which is its cardinality as set. The singleton |oples| are called \emph{one-ples}. There are thus two types of \emph{one-ples}: \begin{itemize} \item \emph{numbers} \dtt{$\{a\}$}, $a \in \mathcal{A}$, \item \emph{nutples} \dtt{$\{O\}$}, $O \in \mathcal{C}$. \end{itemize} If we consider the empty set |nil| on the same footing as |atoms|, the two types have only one common object which is the \emph{none-ple}. As a rule arithmetic operations will either break or silently convert the \emph{none-ple} to the zero value: \begin{everbatim*} \xinteval{3+[], 5^[], 10*[]} \end{everbatim*}. But attention that \csbxint{iieval} in contrast to \csbxint{eval} is broken by such inputs. \subsubsection{Items (and sub-items) versus elements} In order to illustrate these concepts, let us consider how one should interpret notation such as |3,5,7,9| when it arises in an \csbxint{expr}|ession|: \begin{description} \item[tempting vocabulary:] Each of |3|, |5|, |7|, and |9| is an \emph{item}, or \emph{element} of the (comma separated) \emph{list}. In other terms we have here a list with 4 items. \item[rigorous vocabulary:] each one of |3|, |5|, |7|, |9| stands for an \emph{ople} (of the \emph{one-ple} type) and |3,5,7,9| stands for their \emph{concatenation}. \end{description} It is important to understand that in an \csbxint{expr}|ession|, there is no difference between |3,5,7| and |3,,,,5,,,,,,,,,7|. So the view of the comma as separator is misleading. In other terms, the comma is NOT a separator but the (associative) operator of concatenation of totally ordered sets, and the number |3| for example represents a (singleton) set. If we want to refer to |3| or |5| or |7| or |9| as \myenquote{the items of the (open) list |3,5,7,9|} (and probably this documentation already has such utterances, due to legacy reasons from the pre-|1.4| internal model), we \emph{must} realize that this clashes with using the word \emph{item} as synonymous to \emph{element} in the set-theoretical sense. To repeat, any ople \dtt{$O$} is a finite totally ordered set: if not the empty set, it has \emph{elements} \dtt{$a_1$}, \dots, \dtt{$a_k$}, and the above means that its \emph{items} are the singleton oples (aka one-ples) \dtt{$I_1=\{a_1\}$}, \dots, \dtt{$I_k=\{a_k\}$}. Each \dtt{$a_j$} may be an |atom|, then \dtt{$I_j$} is a |number|, or \dtt{$a_j$} is an |ople| (possibly the empty set), then \dtt{$I_j$} is a |nutple| whose depth is one more than the one of the ople \dtt{$a_j$}. Thus we can refer to \myenquote{items} but must then understand they are not \myenquote{elements}: \myenquote{items} are \myenquote{singleton sub-sets}. The cardinality (aka length) of an ople is also the number of its items. It would be tempting to use the terminology \myenquote{sub-item} to keep in mind they are \myenquote{sub-sets} but this would again create confusion: a |nutple| has only one item which is itself; and we need some terminology to refer to the individual numbers in the |nutple| given in input as |[1,2,3]| for example. It is natural to refer to |1|, |2|, |3| as \myenquote{sub-items} of |[1,2,3]| as the latter may be an \myenquote{item} (it is in particular an \myenquote{item} of itself, the unique one at that). We distinguish the |oples| of length zero (there is only one, the empty set) or at least two as those which can never be an \myenquote{item}. Those of length one, the |one-ples|, are exactly those which can be \myenquote{items}. Among them some may have \myenquote{sub-items}, they are the |nutples| with the exception of the |none-ple|. And the others do not have \myenquote{sub-items}, they are the |numbers| and the |none-ple| (whose input syntax is either |[]| or the variable |None|).% % \footnote{% A note on the \csbxint{verbosetrue} regime: for a variable defined to be |3,5,7,9|, it will say that its value is |{3}{5}{7}{9}|, because it does not keep the external set-theoretical braces. The braces here are only \TeX{} braces, and |{3}| is an |atom|. The |number| would be |{{3}}| with the external braces being set-theoretical and also used internally as \TeX{} braces. From the four numbers |{{3}}|, ..., |{{9}}| concatenation gives |{{3}{5}{7}{9}}|, which is the |ople| |3,5,7,9|. But the log view drops deliberately the external braces. If the variable is defined to be the |nutple| |[3,5,7,9]|, then the log view will be |{{3}{5}{7}{9}}| (up to details on how exactly the numeric quantities are coded) and the actual internal \TeX{} entity will be |{{{3}{5}{7}{9}}}|, where the two external layers of braces are both set-theoretical and \TeX nical braces.} \subsubsection{Oples as trees} We say that the empty set |nil| and \emph{atoms} are \emph{leaves}. We associate with any \emph{ople} a tree. The root is the ople. In the case of the |nil| ople, there is nothing else than the root, which we then consider also a \emph{leaf}. Else the children at top level are the successive \emph{elements} (not \myenquote{items}!) of the ople.% % \footnote{\label{fn:alttree}% We could also consider a tree for which the children of the root node would be its items and recursively; in that case the leaves would be |numbers| and possibly the |None|. The tree of the |nil| would be the empty tree, the tree of |None| would have a single node and no edges. Such a tree would match the input syntax (of course applying the rule that iterated commas are like only one). The tree which is described in this section matches more directly the internal syntax, hence is more useful to the author, who is also the sole reader who extracts some benefit from reading this documentation once in a while.} % Among the elements some are \emph{atoms} giving \emph{leaves} of the tree, others are \emph{nutples} which in turn have children. In the special case of the \emph{none-ple} we consider it has a child, which is the empty set and this is why we consider the empty set |nil| to be also a potential \emph{leaf}. We then proceed recursively. We thus obtain from the root \emph{ople} a tree whose vertices are either \emph{oples} or \emph{leaves}. Only the empty set |nil| is both a \emph{leaf} and an \emph{ople}. Considering the empty set |nil| as an \emph{atom} fits with the \xintexprname internal implementation based on \TeX: |nil| is an empty pair of braces |{}|, whereas an \emph{atom} is a braced representation of a numeric value using digits and other characters. We construct \emph{oples} by putting one after the other such constituents and bracing them, and then repeating the process recursively. It has also an impact on the definition of the \emph{depth} (a.k.a as \emph{maximal dimension}) of an \emph{ople}. For example the \emph{ople} $\{\emptyset A_1A_2\}$ with three elements, among them the empty set and two atoms is said to have depth $1$, or to have maximal dimension $1$. And $\{\{\emptyset\}A_1A_2\}$ is of depth $2$ because it has a leaf (the empty set) which is a child of a child of the \emph{ople}. NumPy \emph{ndarrays} have a more restricted structure for example $\{\{A_{00}A_{01}\}\{A_{10}A_{11}\}\}$ is a $2$-dimensional array, where all leaves are at the same depth. When slicing empties the array from its atoms, NumPy keeps the shape information but prints the array as $[]$. This will not be the case with \xintexprname, which has no other way to indicate the shape than display it. \begin{everbatim*} \xinteval{[[],[]]} \end{everbatim*} \begin{everbatim*} \xinteval{[[0,1],[10,11]][:,2:]} \end{everbatim*} \subsubsection{Ople slicing and indexing} \label{sssec:opleslicing} \myenquote{Set-theoretical} slicing of an \emph{ople} means replacing it with one of its subsets. This applies also if it is a \emph{number}. Then it can be sliced only to itself or to the empty set (indeed it has only one element, which is an atom). Similarly the \emph{none-ple} can only be sliced to give itself or the empty set. And more generally a \emph{nutple} is a singleton so also can only be set-sliced to either the empty set or itself. \xintexprname extends \myenquote{Python-like} slicing to act on \emph{oples}: \begin{itemize}[nosep] \item if they are not \emph{nutples} set-theoretical slicing applies, \item if they are \emph{nutples} (only case having a one-to-one correspondence in Python) then the slicing happens \emph{within brackets}: i.e.\@ the \emph{nutple} is unpacked then the set-theoretical slicing is applied, then the result is \emph{repacked} to produce a new \emph{nutple}. \end{itemize} With these conventions the \emph{none-ple} for example is invariant under slicing: unpacking it gives the empty set, which has only the empty set as subset and repacking gives back the \emph{none-ple}. Slicing a general \emph{nutple} returns a \emph{nutple} but now of course in general distinct from the first one. The input syntax for Python slicing is to postfix a variable or a parenthesized ople with |[a:b]|. See \autoref{ssec:lists} for more. There are never any out-of-range errors when slicing or indexing. All operations are licit and resolved by the |nil|, a.k.a. empty set. \myenquote{Set-theoretical} item indexing of an \emph{ople} means reducing it to a subset which is a singleton. It is thus a special case of set-theoretical slicing (which is the general process of selecting a subset as replacement of a set). \xintexprname extends \myenquote{Python-like} indexing to act on \emph{oples}: \begin{itemize}[nosep] \item if they are not \emph{nutples} set-theoretical item indexing applies, \item if they are \emph{nutples} (only case having a one-to-one correspondence in Python) then the meaning becomes \emph{extracting}: i.e.\@ the \emph{nutple} is unpacked then the set-theoretical indexing is applied, but the result is \emph{not repacked}. \end{itemize} For example when applied to the \emph{none-ple} we always obtain the |nil|. Whereas as we saw slicing the \emph{none-ple} always gives back the \emph{none-ple}. Indexing is denoted in the syntax by postfixing by |[N]|. Thus for \emph{nutples} (which are analogous to Python objects), there is genuine difference between the |[N]| extractor and the |[N:N+1]| slicer. But for \emph{oples} which are either |nil|, a \emph{number}, or of length at least 2, there is no difference. \subsubsection{Nested slicing of oples} Nested slicing is a concept from NumPy, which is extended by \xintexprname to trees of varying depths. We have a chain of slicers and extractors. I will describe only the case of slicers and letting them act on a |nutple|. The first slicer gives back a new |nutple|. The second slicer will be applied to each of one of its remaining elements. However some of them may be \emph{atoms} or the empty set. In the NumPy context all leaves are at the same depth thus this can happen only when we have reached beyond the last dimension (axis). This is not permitted by NumPy and generates an error. \xintexprname does not generate an error. But any attempt to slice an \emph{atom} or the empty set (as element of its container) removes it. Recall we call them \emph{leaves}. We can not slice leaves. We can only slice non-leaf elements: such items are necessarily |nutples|. The procedure then applies recursively. If we handle an extractor rather than a slicer, the procedure is similar: we can not extract out of an \emph{atom} or the empty set. They are thus removed. Else we have a |nutple|. It is thus unpacked and replaced by the selected element. This element may be an atom or the empty set and any further slicer or extractor will remove them, or it is a |nutple| and the procedure applies with the next slicer/extractor. \xintexprname allows to apply such a |[a:b,c:d,N,e:f,...]| chain of slicing/extracting also to an \emph{ople}, which is not a \emph{nutple}. We simply apply the first step as has been described previously and successive steps will only get applied to either \emph{nutples} or \emph{leaves}, the latter getting silently removed by any attempted operation. \subsubsection{Function arguments versus variables} \label{sssec:funcargs} In a function declaration with \csbxint{deffunc}, the call signature is parsed as a comma separated list, so here it is not true that repeated commas are like only one: repeated commas are not allowed and will break the function declaration. When \xintexprname parses a function call, it first constructs the ople which is delimited by the opening and closing parentheses, then it applies the function body, after having mapped the successive items (not the elements) of the parsed ople to the variables appearing in the function call signature. Hence the arguments in the call signature stand for |one-ples| (i.e.\@ either |numbers| or |nutples|). Let me explain why we can not define a function |foo(A,B)| of two oples: the function call will evaluate as an ople what is enclosed within the parentheses. It is then impossible in general to split this uniquely into two oples |A| and |B|, except if for example we know a priori the length of |A|. We could imagine defining a declarative interface for a |foo(A,B)| with |A| preset to have \dtt{37} items or at least a pre-defined number of items but this is extraneous layer for a functionality no-one will use. The alternative would be to consider that declaring |foo(A,B)| means |A| will pick-up always the first item and |B| all the remaining ones, and thus will be an ople; here, there are some \TeX nical implementation reasons which have dissuaded the author to do this. In its place, a special syntax |foo(A,*B)| for the declaration of the function is available. It means that |B| stands for the |nutple| which receives as items all arguments in the function call beyond the first one already assigned to |A|. More generally, the last positional argument in a function declaration can have the form |*|\meta{argname}. This then means that \meta{argname} represents a |nutple| which will receive as items all arguments in the function call remaining after the earlier positional arguments have been assigned. The declared function body is free to again use the syntax |*|\meta{argname} which will unpack it and thus produce the ople concatenating all such optional arguments. With \csbxint{defvar} one can define a variable with value an |ople| of arbitrary cardinality. Such a variable can be used in a function call, it will then occupy the place of as many arguments as its cardinality (which is its number of elements, hence of its associated items). For example if function |foo| was declared as a function of 5 arguments |f(a,b,c,d,e)| it is legitimate to use it as |f(A,B)| if |A| is an ople-valued variable of length three and |B| of length two. The actual arguments |a,b,c,d,e| will be made to match the three items of |A| and the two items of |B|. \subsubsection{Final words on leaves} In case things were too clear, let's try to add a bit of confusion with an extra word on \emph{leaves}. When we discuss informally (particularly to compare with NumPy) an input such as \begin{everbatim} [[1, 2], [3, 4]] \end{everbatim} we may well refer to |1|, |2|, |3|, and |4| as being \myenquote{the leaves of the 2d array}. But obviously we have here numbers and previously we explained that a number is not a \emph{leaf}, its \emph{atom} is. Well, the point here is that we must make a difference between the input form as above and the actual constructed \emph{ople} the parser will obtain out of it. In the input we do have numbers. The comma is a \emph{concatenator}, it is not a separator for enumeration! The \emph{ople} which corresponds to it has a \TeX{} representation like this: \begin{everbatim} {{{1}{2}}{{3}{4}}} \end{everbatim} where we don't have the \emph{numbers} anymore (which would look like |{{1}}|, |{{2}}|, ...) but numeric \emph{atoms} |{1}|, |{2}|, |{3}|, |{4}| where the braces are \TeX{} braces and \textbf{not} set-theoretical braces (the other braces are both). Hence we should see the above as the |ople| $\{\{A_{00}A_{01}\}\{A_{10}A_{11}\}\}$ with atoms $A_{00}=\{1\}$, ..., being the \emph{leaves} of the tree associated to (or which is) the \emph{ople}. Numbers may be called the \emph{leaves} of the \textbf{input}, but once parsed, the input becomes an \emph{ople} which is (morally) a tree whose leaves are \emph{atoms} (and the empty set). This discussion can also be revisited with footnote %%\footref{fn:alttree} \ref{fn:alttree} in mind. \subsubsection{Farewell, thanks for your visit!} I hope this is clear to everyone. If not, maybe time to say this section is not needed to understand almost all of the manual, but I needed to write it to be able to maintain in future my own software. \subsection{Expansion (for geeks only)} As mentioned already, the parsers are compatible with expansion-only context. Also, they expand the expression piece by piece: the normal mode of operation of the parsers is to unveil the parsed material token by token. Unveiling is a process combining space swallowing, brace removal (one level generally), and \fexpan sion. For example a closing parenthesis after some function arguments does not have to be immediately visible, it and the arguments themselves may arise from \fexpan sion (applied before grabbing each successive token). Even the ending |\relax| may arise from expansion. Even though the \csbxint{eval} user interface means that the package has at some point the entire expression in its hands, it immediately re-inserts it into token stream with an additional postfixed |\relax| and from this point on has lost any ways (a simple-minded delimited macro won't do because the expression is allowed to contain sub-\csbxint{expr}essions, even nested) to manipulate formally again the whole thing; it can only re-discover it one token at a time. This general behaviour (which allows much more freedom in assembling expressions than is usually the case with familiar programming languages such as Python, although admittedly that freedom will prove useful only to power-\TeX users and possibly does not have that many significant use cases) has significative exceptions. These exceptions are mostly related to \myenquote{pseudo}-functions. A \myenquote{pseudo}-function will grab some of its arguments via delimited macros. For example |subs(expr1,x=expr2)| needs to see the comma, equal sign and closing parenthesis. But it has mechanisms to allow |expr1| and |expr2| to possess their own commas and parentheses. Inner semi-colons on the other hand currently always can originate from expansion. Defining functions or variables requires a visible semi-colon acting as delimiter of the expression, but inner semi-colons do not need to be hidden within braces or macros. The expansion stops only when the ending |\relax| has been found (it is then removed from the token stream). For catcode related matters see \csbxint{exprSafeCatcodes}. A word of warning on the bracketed optional argument of respectively \csbxint{floatexpr} and \csbxint{iexpr}. When defining macros which will hand over some argument to one of these two parsers, the argument may potentially start with a left square bracket |[| (e.g. argument could be |[1, 2, 3]|) and this will break the parser. The fix is to use in the macro definition |\xintfloatexpr\empty|. This extra |\empty| token will prevent the parser from thinking there is an optional argument and it will then disappear during expansion. \begin{footnotesize} If comparing to other languages able to handle floating point numbers or big integers, such as Python, one should take into account that what the \xintname packages manipulate are streams of ascii bytes, one per digit. At no time (due to expandability) is it possible to store intermediate results in an arithmetic CPU register; each elementary operation via |\the\numexpr| will output digit tokens (hence as many bytes), not things such as handles to memory locations where some numbers are stored as memory words. The process can never put aside things but can only possibly permute them with upcoming tokens, to use them later, or, via combinations of |\expanded| and |\unexpanded| or some other more antiquated means grab some tokens and shift the expansion to some distant locations to later come back. The process is a never-ending one-dimensional one...\par \end{footnotesize} \subsection{Known bugs/features (last updated at \texttt{1.4m})} \begin{description} \item[{\cs{xinteval}\char`\{\cs{xintLength}\char`\{\cs{par}\cs{par}\cs{par}\char`\}\char`\}} complains about a Runaway argument:]\mbox{} |\xintLength{\par\par\par}| has no issue as |\xintLength| is a |\long| macro but this is not the case of |\xinteval|. Most macros of a non arithmetic nature in \xintkernelname and \xinttoolsname are declared |\long| but absolutely none in \xintexprname, and its dependencies \xintname, etc... % As a remark in passing, I could not use the \LaTeX{} |\item| directly:% % \footnote{For those who wonder my custom |\verb| employs a |\scantokens| approach, so it can be used in the argument of a macro, for example \verb+\footnote{\verb|\verb|}+.} % \begin{everbatim} Runaway argument? {|\xinteval {\xintLength { ! Paragraph ended before \@item was complete. <to be read again> \par l.4434 \item[{|\xinteval{\xintLength{\par \par\par}| complains about a Runawa... \end{everbatim} This is the reason I guess why everything is a priori |\long| in the \LaTeX3 interface except if asked for otherwise (as far as I know). Although most macros are dealing with inputs which can only be with digits and some other character tokens, it would still be quite some work to chase all top-level ones. Besides, in pratice, it does help better locate ill-formed input. \item[|if(100>0,(100,125),(100,128))| breaks my code:] % This is a feature. This is a syntax error, as the comma serves to contatenate "oples" (see \autoref{oples}), and parentheses do not create analogs of "tuples", so this input is parsed the same as \begin{everbatim} if(100>0,100,125,100,128) \end{everbatim} which is an error as \func{if} requires exactly three arguments, not five. Use: \begin{everbatim} if(100>0,[100,125],[100,128]) \end{everbatim} which will expand to the "tuple" |[100,125]|. \item[{\cs{xintdeffunc} |foo(x):= gcd((x>0)?{[x,125]}{[x,128]});| creates a broken function:}] % Bug. Normally \func{gcd} (and other multi-arguments functions) work both with open lists of arguments or bracketed lists ("nutples") and the above syntax would work perfectly fine in numerical context. But the presence of the \oper{?} breaks in \csbxint{deffunc} context the flexibility of \func{gcd}. Currently working alternatives: \begin{everbatim} \xintdeffunc foo(x) := gcd(if(x>0, [x,125], [x,128])); \xintdeffunc foo(x) := if(x>0, gcd(x,125), gcd(x,128)); \xintdeffunc foo(x) := if(x>0, gcd([x,125]), gcd([x,128])); \xintdeffunc foo(x) := gcd((x>0)?{x,125}{x,128}); \xintdeffunc foo(x) := (x>0)?{gcd(x,125)}{gcd(x,128)}; \xintdeffunc foo(x) := (x>0)?{gcd([x,125])}{gcd([x,128])}; \end{everbatim} The same problem will arise with an \oper{??} nested inside \func{gcd} or similar functions, in an \csbxint{deffunc}. \item[{\cs{xinteval}|{0^-.5}| says "0 raised to power -1"}] % Feature. Half integer exponents are handled via a square-root extraction, so here \xintexprname wanted to first raise \dtt{0} to power \dtt{-1}, as reported. \item[{Comparison operator |==| crashes with nutples}] % Not yet implemented... \item[{I liked the ``broadcasting'' |[1..10]^10| syntax, but it was removed at 1.4}] % Patience...\@ |seq(x^10,x=1..10)| is alternative (add external |[..]| to get a nutple). \item[{|1e\numexpr5+2\relax| crashes}] % Not clear yet if bug or feature. The syntax accepted in the scientific part is limited, and failure is expected: hitting a |\numexpr| when parsing a number triggers insertion of a tacit multiplication and then |1e| is missing the scientific exponent. The same happens with |1e(2+3)|. Use syntax such as |1e\the\numexpr5+2\relax|, or |1e\xinteval{5+2}| (although here this relies on output format of |\xinteval| using integer notation with no decoration in this case). \item[{|seq(1e-i,i=1..5)| crashes}] % Not clear if bug or feature. Use |seq(1e\xinteval{-i},i=1..5)| or, as a possibly faster way |seq(1e\xintiieval{-i},i=\xintiiexpr1..5\relax)|. \item[{\keyword{omit}/\keyword{abort} if nested and not last in the sub-expression cause a crash}] % For example |seq(subs((i)?{i}{abort},t=i)+10, i=-2, -1, 0, 1)| crashes, due to the presence of the |+10|. This is a longstanding limitation, applying ever since |omit/abort| were added to the syntax at |1.1|. Even without the |+10| the nested case was broken by a |1.4| regression and got fixed only at |1.4h|. The non-nested case |seq((i)?{i}{abort}+10, i=-2, -1, 0, 1)| works and the \myenquote{must be last in expression if nested} limitation is currently considered a feature. \item[{|seq([i,i\string^2], i=1..10)| crashes with Ooops, looks like we are missing a ]. Aborting!}] % The cause is that the square brackets do not hide the comma from |seq()| parsing. This will probably remain ``wont-fix''. Work-arounds: either use an extra pair of parentheses |seq(([i,i^2]), ...)| or hide the inner comma within braces |seq([i{,}i^2], ...)|. \end{description} The list stops here, but there are certainly other pending bugs in my bug-log, and many more I am not yet aware of. In particular it is already mentioned in the \csbxint{deffunc} documentation that it can not parse currently the entirety of the available purely numerical syntax, some (documented or not, known or not) limitations apply. \clearpage \etocdepthtag.toc {part1B} \let\xintexprnameUp\undefined \csname xintexpr (old doc)nameUp\endcsname \section{The macros of \xintexprname (ancient documentation, mostly)}% \RaisedLabel{sec:oldxintexpr} \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 |1.4| release from |2020/01/31| maintains the same general architecture but needed adapting all the code base for the switch from |\csname| to |\expanded| techniques. On this occasion the mechanism for defining functions was substantially strengthened. The parser core mechanisms were improved too. The package loads automatically \xintfracname and \xinttoolsname. This section should be trimmed to contain only information not already covered in \autoref{sec:expr}. \subsection{The \csh{xintexpr} expressions} \label{xintexpr} \label{xinttheexpr} \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). Contrarily to a |\numexpr| expression, it is printable as is without a prefix |\the| or |\number| (don't use them with |\xintexpr| this will raise an error). But one can use |\xintthe| prefix if one does need the explicit digits and other characters as in the final typesetted result. As an alternative and equivalent syntax to \begin{everbatim} \xintexpr round(<expression>, D)\relax \end{everbatim} there is \begin{everbatim} \xintiexpr [D] <expression> \relax \end{everbatim} For |D>0| this produces a decimal number with |D| figures after the decimal mark, which is the rounding of the expression. For |D=0| the rounding to an integer is produced. For |D<0| (and this was changed at |1.4f|), the rounded quotient of the expression by \verb=1e|D|= is produced. \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 macros from \xintfracname, or more generally to macros which expand their arguments, one must use the |\xinttheexpr...\relax| or |\xintthe\xintexpr...\relax| forms. \item one should not use |\xintthe\xintexpr...\relax| as a sub-constituent of another expression 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} The information now following is possibly in need of updates. \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 a protected form. 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|. \item See also \csbxint{ifboolexpr} (\autoref{xintifboolexpr}) and the \func{bool} and \func{togl} functions in \autoref{sec:expr}. Here is an example. Well in fact the example ended up using only \csbxint{boolexpr} so it was modified to use \csbxint{ifboolexpr}. \catcode`| 12 % \begin{everbatim*} \xintdeffunc A(p,q,r) = p && (q || r) ; \xintdeffunc B(p,q,r) = p || (q && r) ; \xintdeffunc C(p,q,r) = xor(p, q, r) ; \centeredline{\normalcolor \begin{tabular}{ccrclcl} \xintFor* #1 in {{False}{True}} \do {% \xintFor* #2 in {{False}{True}} \do {% \xintFor* #3 in {{False}{True}} \do {% #1 &AND &(#2 &OR )&is&\textcolor[named]{OrangeRed} {\xintifboolexpr{A(#1,#2,#3)}{true}{false}}\\ #1 &OR &(#2 &AND )&is&\textcolor[named]{OrangeRed} {\xintifboolexpr{B(#1,#2,#3)}{yes}{no}}\\ #1 &XOR & #2 &XOR  &is&\textcolor[named]{OrangeRed} {\xintifboolexpr{C(#1,#2,#3)}{oui}{non}}\\ }}} \end{tabular}% } \end{everbatim*}\catcode`| 13 \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\relax| 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, even thousands of digits. % \begin{everbatim*} \xintDigits:=48\relax \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 one 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} The main problems are caused by active characters, because \csbxint{expr} et al.\@ expand forward whatever comes from token stream; they apply |\string| only in a second step. For example the catcode of |&| from |&&| Boolean disjunction is not really important as long as it is not active, or comment, or escape...\@ or brace...\@ or ignored...\@ in brief, as long as it is reasonable, and in particular whether |@| is of catcode letter or other does not matter. It is always possible to insert manually the |\string| in the expression before a problematic (but reasonable) character catcode, or even to use |\detokenize| for a big chunk. \subsubsection{\csh{xintexprSafeCatcodes}} \label{xintexprSafeCatcodes} Some problems with active characters can be resolved on the fly by prefixing them by |\string| but some aspects of the parsing done by \csbxint{expr} involves delimited macros which need the comma, equality sign and closing parenthesis to have their standard catcodes. So \csbxint{exprSafeCatcodes} is provided as a utility to set in one go catcodes of many characters to \csbxint{expr}-safely compatible values. This is a non-expandable step as it changes catcodes. % 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. \csbxint{defvar}, \csbxint{deffunc}, et al., use it, and then they restore catcodes to the prior state via \csbxint{exprRestoreCatcodes}. % 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. % \csbxint{deffunc} is more lenient than \csbxint{defvar} regarding catcodes of % characters in expression bodies as it does some |\scantokens| which will reset % compatible catcodes. % Even if used in a context where catcodes are already set, \csbxint{deffunc}, % \csbxint{defvar} and variants ignore completely the colon in |:=| so it can % have any (reasonable) catcode. Moreover it is optional. % The semi-colon in the syntax of \csbxint{Digits} is no real problem either % (cf. \csbxint{Digits} documentation). \subsubsection{\csh{xintexprRestoreCatcodes}} \label{xintexprRestoreCatcodes} Restores the catcodes to the state prevailing at the time of the last executed \csbxint{exprSafeCatcodes} (if located at the same \LaTeX\ environment or \TeX\ grouping level). Prior to |1.4k|, in a situation like the following: \begin{everbatim} \xintexprSafeCatcodes ....stuff possibly changing catcodes \xintexprSafeCatcodes ....stuff possibly changing catcodes \xintexprSafeCatcodes ....stuff possibly changing catcodes \xintexprRestoreCatcodes \end{everbatim} On exit, the catcodes recovered their status as prior to the \emph{first} \csbxint{exprSafeCatcodes}. Since |1.4k|, they are set to what they were prior to the \emph{last} \csbxint{exprSafeCatcodes}, i.e. the mechanism is now similar to a ``last in, first out'' stack. Note that no global assignments are made so the behaviour can be modified by usage of \TeX\ groups or \LaTeX\ environments: e.g. if an \csbxint{exprSafeCatcodes} is issued inside a \LaTeX\ environment it does not have to be paired by \csbxint{exprRestoreCatcodes} explicitly, the catcode scope is limited by the environment. \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, ..., except that they % should not be \emph{active}, as for example are |!?;:| with |babel-french|.% % % % \footnote{Furthermore, although \csbxint{expr} uses \csa{string}, it is % escape-char agnostic. It should work with any \csa{escapechar} setting % including -1.} but the characters % |+|, |-|, |*|, |/|, |^|, |!|, |&|, \verb+|+, |?|, |:|, |<|, |>|, %|=|, |(|, |)|, |"|, |[|, |]|, |;|, in the expression should not be \myenquote{active} (except on purpose) as everything is expanded along the way, and |\xintexpr| will choke on typesetting related commands. One can use |\string| to prefix a problematic character. 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''. \subsection{Expandability, \csh{xintexpro}} As is the case with all other package macros |\xintexpr| \fexpan ds (in two steps) to its final (somewhat protected) 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. The once expanded |\xintexpr| is |\romannumeral0\xintexpro|. And there are similarly |\xintiexpro| |\xintiiexpro| and |\xintfloatexpro|. 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 outer ``environment'' is the |\xintiiexpr| one. \subsection{\csh{xintDigits*}, \csh{xintSetDigits*}} \label{xintDigits*} \label{xintSetDigits*} These starred variants of \csbxint{Digits} and \csbxint{SetDigits} execute \csbxint{reloadxinttrig} and \csbxint{reloadxintlog}. \subsection{\csh{xintiexpr}, \csh{xinttheiexpr}} \label{xintiexpr}\label{xinttheiexpr} Equivalent\etype{x} to doing |\xintexpr round(...)\relax| (more precisely, |round| is applied to each leaf item of the |ople| independently of its depth). Intermediate calculations are exact, only the final output gets rounded. Half integers are rounded towards $+\infty$ for positive numbers and towards $-\infty$ for negative ones. An optional parameter |D| within brackets, immediately after |\xintiexpr| is allowed: it instructs (for |D>0|) the expression to do its final rounding to the nearest value with that many digits after the decimal mark, 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 ...| and rounds to an integer. The case of negative |D| gives quantization to an integer multiple of \dtt{1e-D}. This was modified at |1.4f| and the produced value is now the rounded quotient by \dtt{1e-D} (i.e. no trailing zeros nor scientific exponent in the output). If truncation rather than rounding is needed on can use |\xintexpr trunc(...)\relax| for truncation to an integer or |\xintexpr trunc(...,D)\relax| for quantization to an integer multiple or \dtt{1eD} (if |D>0|, for |D<0| the analog would be |trunc((...)/1e-D)|). But this works only for a single scalar value. \begin{framed} When defining a macro doing something such as |\xintiexpr #1\relax|, it is recommended to rather use |\xintiexpr\empty #1\relax|, as the |#1| may start with a |[| which without the |\empty| would be interpreted by |\xintiexpr| as the start of the optional |[D]|. \end{framed} \subsection{\csh{xintiiexpr}, \csh{xinttheiiexpr}} \label{xintiiexpr}\label{xinttheiiexpr} 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 an 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 \end{everbatim*} The above went through because no actual operations were carried out. But it is dangerous because the ``printer'' for \csbxint{theiiexpr} could choke on such values. By default however it does nothing. In the next example there will be an addition. So we firt apply |round| to get integers (the second argument of |round| and |trunc| tells how many digits from after the decimal mark one should keep.) \begin{everbatim*} \xinttheiiexpr round(\xintFloatSqrt [20]{2},19) + round(\xintFloatSqrt [20]{3},19)\relax \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). \subsection{\csh{xintboolexpr}, \csh{xinttheboolexpr}} \label{xintboolexpr}\label{xinttheboolexpr} Equivalent\etype{x} to doing |\xintexpr ...\relax| and returning |true| if the result does not vanish, and |false| if the result is zero. As |\xintexpr|, this can be used on comma separated lists of expressions, and even bracketed lists. It can be customized, one only needs to modify the following: \begin{everbatim} \def\xintboolexprPrintOne#1{\xintiiifNotZero{#1}{true}{talse}}% \end{everbatim} Not only are |true| and |false| usable in input, also |True| and |False| are pre-declared variables. There is 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} \csbxint{floatexpr}|...\relax|\etype{x} is exactly like |\xintexpr...\relax| but with the four binary operations and the power function 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 |[Q]| is allowed at the very start of the expression: \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, in the sense of rounding the values to shorter mantissas). 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. |\xintDigits:=36\relax|\xintDigits:=36\relax % \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. \begin{framed} When defining a macro doing something such as |\xintfloatexpr #1\relax|, it is recommended to rather use |\xintfloatexpr\empty #1\relax|, as the |#1| may start with a |[| which without the |\empty| would be interpreted by |\xintfloatexpr| as the start of the optional |[Q]|. \end{framed} \subsection{\csh{xinteval}, \csh{xintieval}, \csh{xintiieval}, \csh{xintfloateval}} \label{xinteval}\label{xintieval}\label{xintiieval}\label{xintfloateval} \csbxint{eval}\etype{x} is an \fexpan dable macro which is basically defined in such a way that |\xinteval|\marg{expression} behaves like \csbxint{theexpr}\marg{expression}|\relax|. It expands completely in two steps and delivers its output using digits, the dot |.| as decimal separator, the letter |e| for scientific notation, the slash |/| for fractions, as well as commas in case of multi-items expression and square brackets |[| and |]| for nesting. \csbxint{ieval}\etype{x} is similarly related to \csbxint{theiexpr}. It admits an optional argument |[D]| which may be located in the expected location from conventions of \LaTeX2e macros with optional argument, but had been long constrained (until |1.4k|) to be inside the braces at the start of the expression. \begin{everbatim*} \xintieval[7]{355/113} = \xintieval{[7]355/113} \end{everbatim*} \begin{framed} When defining a macro doing something such as |\xintieval{#1}|, it is recommended to rather use |\xintieval{\empty #1}|, as the |#1| may start with a |[| which without the |\empty| would be interpreted by |\xintieval| as the start of the optional |[D]|. \end{framed} \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}. It admits an optional argument |[Q]| which may be located either outside (since |1.4k|) or inside the braces. \begin{everbatim*} \xintfloateval [7]{355/113} = \xintfloateval{[7] 355/113} \end{everbatim*} When negative, the optional argument tells how many digits to remove from the prevailing precision: \begin{everbatim*} \xintfloateval[-2]{355/113}= \xintfloateval{[-2]355/113} has \xinttheDigits\ minus 2 digits. \end{everbatim*} \begin{framed} When defining a macro doing something such as |\xintfloateval{#1}|, it is recommended to rather use |\xintfloateval{\empty #1}|, as the |#1| may start with a |[| which without the |\empty| would be interpreted by |\xintfloateval| as the start of the optional |[Q]|. \end{framed} The \csbxint{eval} et al. macros have the advantage that they can be nested within things such as the |\num| macro of \href{http://ctan.org/pkg/siunitx}{siunitx}, which would choke on some of the syntax elements which are allowed inside \csb{xinttheexpr}|...\relax|, such as brackets. Hidden inside the braces as argument to \csbxint{eval} et al., they do not cause a breakage of |\num| anymore. And regarding \csbxint{ieval} and \csbxint{floateval} one sees here the advantage that their respective optional arguments can (and had to until |1.4k|) be located within the braces too... \subsection{Using an expression parser within another one} This was already illustrated before. In the following: \begin{everbatim*} \xintfloatexpr \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*} \xintfloatexpr 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*} \xintiiexpr round(\xintfloatexpr 3.14^10\relax)\relax % or trunc \end{everbatim*} \subsection{The \csh{xintthecoords} macro} \label{xintthecoords} It converts (in two expansion steps) the expansion result of \csbxint{floatexpr} (or \csbxint{expr} or \csbxint{iiexpr}) into the |(a, b) (c, d) ...| format for list of coordinates as expected by the |TikZ| |coordinates| syntax.% \begin{everbatim*} \begin{figure}[htbp] \centering\begin{tikzpicture}[scale=10]\xintDigits:=8\relax \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 output of next expression into the %%% (x1, y1) (x2, y2) ... %%% format \xintthecoords\xintfloatexpr %%% This syntax -1+[0..4]/2 is currenty dropped at xint 1.4 %%% seq((x^2-1,mul(x-t,t=-1+[0..4]/2)),x=-1.2..[0.1]..+1.2)\relax %%% Use this: seq((x^2-1,mul(x-t,t=seq(-1+u/2, u=0..4))),x=-1.2..[0.1]..+1.2) \relax }; \end{tikzpicture} \caption{Coordinates with \csbxint{thecoords}.} \end{figure} \end{everbatim*} % Notice: if x goes not take exactly value 1 or -1, the origin appears slightly % off the curve, not MY fault!!! It is currently undecided how \csa{xintthecoords} should handle bracketed data.\UNSTABLE{} Currently, it (or |TikZ|) will break it the input contains nested structures. One can use it with \func{flat} which removes all nesting. And in combination with \func{zip} it is easy to plot data given by some mechanism in separate lists of x- and y-coordinates (see an example in next section) \subsection{The \csh{xintthespaceseparated} macro} \label{xintthespaceseparated} It converts (in two expansion steps) the expansion result of \csbxint{floatexpr} (or \csbxint{expr} or \csbxint{iiexpr}) into the space separated format suitable for usage with |PS-Tricks| |\listplot| macro. Here is for example some syntax (the replacement text of |\foo|, which is used here only to show that indeed complete expansion is attained in two steps) which can be used as argument to |\listplot|. Using 4 fractional decimal digits is sufficient when unit is the centimeter (it gives a fixed point precision of one micron, amply enough for plots...). \begin{everbatim*} \oodef\foo{% \xintthespaceseparated \xintiexpr[4]\xintfloatexpr seq((i, log10(i)), i=1..[0.5]..10)\relax\relax }\meaning\foo \end{everbatim*} Here we don't really need the inner |\xintfloatexpr...\relax| because the \func{log10} function works the same in the exact parser |\xintexpr| but in general this is recommended. It is currently undecided how \csa{xintthespaceseparated} should handle bracketed data.\UNSTABLE{} Currently, it (or |\listplot|) will break if the input contains nested structures. One can use it with \func{flat} which removes all nesting. And in combination with \func{zip} it is easy to plot data given by some mechanism in separate lists of x- and y-coordinates. \begin{everbatim*} % let's imagine we have something like this \def\Xcoordinates{1, 3, 5, 7, 9} \def\Ycoordinates{1, 9, 25, 49, 81} % then: |\xintthespaceseparated\xintexpr flat(zip([\Xcoordinates], [\Ycoordinates]))\relax| is suitable to use as argument to |\listplot|, as it expands to \xintthespaceseparated\xintexpr flat(zip([\Xcoordinates], [\Ycoordinates]))\relax \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. The expression argument must be a single one, comma separated sub-expressions will cause low-level errors. \subsection{The \csh{xintNewExpr}, \csh{xintNewIIExpr}, \csh{xintNewFloatExpr}, \csh{xintNewIExpr}, and \csh{xintNewBoolExpr} macros} \label{xintNewExpr} \label{xintNewIIExpr} \label{xintNewFloatExpr} \label{xintNewIExpr} \label{xintNewBoolExpr} \csbxint{NewExpr} 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 (if it succeeds) 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 documentation is much shortened here because \csbxint{NewExpr} and \csbxint{deffunc} are very much related one with the other. \begin{framed} ATTENTION! The original spirit of \csbxint{NewExpr} was to define a (possibly very big) macro using only \xintfracname, and this means in particular that it must be used only with arguments compatible with the \xintfracname input format.\IMPORTANTf Thus an |\xintexpr| declared variable has no chance to work, it must be wrapped explicitly in |\xinteval{...}| to be fetched as argument to a macro constructed by \csbxint{NewExpr}. \end{framed} They share essentially the same limitations. Notice though that \csbxint{NewFloatExpr} accepts and recognizes the optional argument |[Q]| of \csbxint{floatexpr}, contrarily to \csbxint{deffloatfunc}. Use an |\empty| in case the contents are not known in advance. Historical note: prior to |1.4|, \xintexprname used a |\csname..\endcsname| encapsulation technique which impacted the string pool memory. The \csbxint{NewExpr} was designed as a method to pre-parse the expression and produce one single, gigantic, nested usage of the relevant \xintfracname macros. This way, only those macros were expanded which had nil impact on the \TeX{} string pool. Later on it was found that this mechanism could be employed to define functions. Basically underneath |98%| of \csbxint{NewExpr} and \csbxint{deffunc} are using the same shared code. \xintDigits:= 16\relax \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 may use |\xintthe| prefix to turn into explicit digits, (for example in arguments to some macros which expand their arguments). The |\the| \TeX\ primitive prefix would not work here. \item (ctd.) One can embed a |\numexpr...\relax| (with its |\relax|!) inside an |\xintiiexpr...\relax| without |\the| or |\number|, but the reverse situation requires usage of |\xintthe| or \csbxint{eval} user interface, \item |\numexpr -(1)\relax| is illegal. In contrast |\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.) In contrast |\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 \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 \def\everbhook{\catcode`@ 14 }% % à propos après donc de nombreuses années j'ai fait finalement % un bug report https://github.com/latex3/latex2e/issues/823 \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 |;-)|. \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{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{https://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 \expandafter\let\csname xintexpr (old doc)nameUp\endcsname\undefined \csname xinttrignameUp\endcsname \section{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/05|) of \xintexprname. It is automatically loaded by \xintexprname. At |1.4e| (|2021/05/05|) the accuracy was significantly increased: formerly the high-level user interface used to define the functions had as consequences that intermediate steps of the computations could not operate with guard digits, and as a result the last two digits were most of the time off (at least the last one). Now, computations are done internally in extended precision, and the accuracy is high up to the last digits, with faithful rounding and high probability of correct rounding. And the maximal number of digits was raised slightly to \dtt{62} digits. At \dtt{8} digits a special, faster, mode is used, which is less accurate. But faster. \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. Jürgen passed away in 2022. I will miss our friendship which was born and grew from numerous and regular exchanges on topics not limited to this package or even the \TeX\ world. Let's now continue to \myenquote{take care and keep motivated}! \subsection{\csh{xintreloadxinttrig}}\label{xintreloadxinttrig} The library is loaded automatically by \xintexprname at start-up. It is then configured for \dtt{16} digits. To work for example with \dtt{48} digits, execute \csbxint{SetDigits*}|{48}| or \csbxint{Digits*}|:=48;| (the ending |;| can be replaced by a |\relax| in case of problems due to it being active, e.g.\@ with \LaTeX\ and some languages). With the non-starred variant \csbxint{Digits}|:=48;|\IMPORTANTf{} it is needed to issue \csbxint{reloadxinttrig} to recalibrate the functions provided by the library (and the exponential/logarithm functions will only be updated if also \csbxint{reloadxintlog} is used). % 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} Their values (with more digits) 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$ \end{description} \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). As the output is rounded -\var{Pi} is 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 |Argd(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} \xintdeffloatfunc radians(x) := x * oneDegree; \xintdeffloatfunc degrees(x) := x * oneRadian; \xintdeffunc radians(x) := float_dgt(x * oneDegree); \xintdeffunc degrees(x) := float_dgt(x * oneRadian); \end{everbatim} The \func{float\string_dgt} does a float rounding to \csbxint{theDigits} precision (recall that |*| is mapped to exact multiplication in \csbxint{deffunc}). \subsection{Important implementation notes} \label{ssec:trignotes} \begin{itemize} \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; refer to |sourcexint.pdf|. \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 |sind()| and |cosd()| functions with such large float numbers is meaningless. \item See |sourcexint.pdf| for some comments on limitations of the range reduction implementation. % \item Regarding |sin()| and |cos()|, \xinttrigname converts their argument to % degrees by multiplication by (pre-rounded) $180/\pi$, then does range % reduction modulo $360$ and finally goes back to radians in the appropriate % octants to use usual Taylor series (roughly said). For large floats, the % output value will thus be one of |sind(40n)|, |cosd(40n)|, |n=0..8|. If the % unit in the last place of original variable was for example \dtt{1e9} the % final result means nothing at all: the unit in the last place interval % extends above possibly astronomical numbers of intervals of length $2\pi$. % This intrinsic problem is not a by-product of conversion problems to and % from degrees, it is an in-built inadequacy of the concept of floating point % numbers to provide meaning to evaluating trigonometrical functions. The % argument should be treated 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 (rather severe) implementation complications such as deciding how to % make the transition to randomness. Too lazy for that. % Opting for a random value also raises the question of how to deal with % multiple such evaluations at the same argument in a single expression. I % would argue again that as it is evil to consider meaningless quantities, it % is not a problem if new compilations give different results, or even single % compilation gives different results in various parts of the same formula, % that's the whole point of randomness! As said already, I got too lazy to % consider seriously implementing such a non-standard philosophy, despite its % compelling soundness. % \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} \subsection{Some example evaluations} \noindent \begin{everbatim*} \xintDigits* := 48\relax Digits at \xinttheDigits:\newline $sind(17)\approx\xintfloateval{sind(17)}$\newline $cosd(17)\approx\xintfloateval{cosd(17)}$\newline $tand(17)\approx\xintfloateval{tand(17)}$\newline $sind(43)\approx\xintfloateval{sind(43)}$\newline $cosd(43)\approx\xintfloateval{cosd(43)}$\newline $tand(43)\approx\xintfloateval{tand(43)}$\newline $asind(0.3)\approx\xintfloateval{asind(0.3)}$\newline $acosd(0.3)\approx\xintfloateval{acosd(0.3)}$\newline $atand(3)\approx\xintfloateval{atand(3)}$\newline $tan(atan(7))\approx\xintfloateval{tan(atan(7))}$\newline $asind(sind(25))\approx\xintfloateval{asind(sind(25))}$\par\medskip \noindent\xintDigits* := 24\relax Digits at \xinttheDigits:\newline $sind(17)\approx\xintfloateval{sind(17)}$\newline $cosd(17)\approx\xintfloateval{cosd(17)}$\newline $tand(17)\approx\xintfloateval{tand(17)}$\newline $sind(43)\approx\xintfloateval{sind(43)}$\newline $cosd(43)\approx\xintfloateval{cosd(43)}$\newline $tand(43)\approx\xintfloateval{tand(43)}$\newline $asind(0.3)\approx\xintfloateval{asind(0.3)}$\newline $acosd(0.3)\approx\xintfloateval{acosd(0.3)}$\newline $atand(3)\approx\xintfloateval{atand(3)}$\newline $tan(atan(7))\approx\xintfloateval{tan(atan(7))}$\newline $asind(sind(25))\approx\xintfloateval{asind(sind(25))}$\par \xintDigits* := 16\relax \end{everbatim*} \clearpage \let\xinttrignameUp\undefined \csname xintlognameUp\endcsname \def\n{|{N}|} \def\m{|{M}|} \def\x{|{x}|} \section{The \xintlogname package} \RaisedLabel{sec:log} This package provides logarithms, exponentials and fractional powers for use with \xintexprname. This package was first included in release |1.3e| (|2019/04/05|) of \xintexprname. It is automatically loaded by \xintexprname. At release |1.4e| (|2021/05/05|) it was substantially extended to cover usage with mantissas of up to \dtt{62} digits. At |Digits| set to \dtt{8} or less, the old faster but less accurate macros based on \ctanpackage{poormanlog} are used. These macros compute logarithms and exponentials with about \dtt{8} or \dtt{9} nine digits of \emph{fixed point} precision. \begin{TeXnote} There is thus, for |Digits=8| or less a systematic loss of rounding precision in the floating point sense for logarithms of inputs close to \dtt{1}: e.g. |log10(1.0011871)| is produced as |5.15245e-4| which stands for |0.000515145| having indeed \dtt{9} correct fractional digits, but only \dtt{6} correct digits in the floating point sense. Situation is worse for |log()| as it applies a conversion factor and does not remove the trailing junk digits, which we don't have for |log10()|. Check |sourcexint.pdf| and \ctanpackage{poormanlog} README for more info. \end{TeXnote} \localtableofcontents \subsection{\csh{xintreloadxintlog}}\label{xintreloadxintlog} The library is loaded automatically by \xintexprname at start-up. It is then configured for \dtt{16} digits. To work for example with \dtt{48} digits, execute \csbxint{SetDigits*}|{48}| or \csbxint{Digits*}|:=48;| (the ending |;| can be replaced by a |\relax| in case of problems due to it being active, e.g.\@ with \LaTeX\ and some languages). With the non-starred variant \csbxint{Digits}|:=48;|\IMPORTANTf{} it is needed to issue \csbxint{reloadxintlog} to recalibrate the functions provided by the library (and the trigonometric functions will only be updated if also \csbxint{reloadxinttrig} is used). \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 \funcdesc{exp} exponential function \funcdesc[x, y]{pow} computes $x^y$ either via the formula |pow10(y*log10(x))| (applied with some internally increased accuracy), for |y| neither an integer nor an half-integer; or via the legacy \csbxint{FloatPower} and \csbxint{FloatSqrt} macros if the exponent is integer or half-integer. Integer exponents trigger an exact evalution in \csbxint{eval} if the output will not exceed (or will only slightly exceed) \dtt{10000} digits (separately for numerator and denominator), else the power is computed in the floating point sense. \end{description} \begin{everbatim*} \xintfloateval{log(2), exp(1), 2^(1/3), 2^10000} \end{everbatim*} \pdfstringdefDisableCommands{\let\cs\empty} \subsection{Some information on how powers are computed} For powers |a^b| or |a**b| in \csbxint{floateval} the following rules apply: \begin{enumerate}[noitemsep] \item a check is made if exponent is integer or half-integer, \item if this is the case legacy \csbxint{FloatPower} (combined with \csbxint{FloatSqrt} for half-integer case) are used to evaluate the power (and |a| can be negative if exponent is integer), \item else the power is computed as |pow10(b*log10(a))| (but keeping some extra digits in intermediate evaluations; in particular |b| is not float-rounded, but |a| is). \end{enumerate} The reason is that the log/exp approach loses accuracy for very big exponents (say for exponents of the order of \dtt{100000000} or more). Here is an example of a precise computation with a very large exponent (\dtt{\xintiieval{12^16}}): \begin{everbatim*} $\xintTeXFromSci{\xintfloateval{1.00000001^\xintiiexpr 12^16\relax}}$\newline \xintDigits:=48;%\xintreloadxintlog is not done as log10/pow10 will not be used $\xintTeXFromSci{\xintfloateval{1.00000001^12^16}}$\newline \xintDigits:=64;%\xintreloadxintlog is not done as log10/pow10 will not be used $\xintTeXFromSci{\xintfloateval{1.00000001^12^16}}$\newline \xintDigits:=80;%\xintreloadxintlog is not done as log10/pow10 will not be used $\xintTeXFromSci{\xintfloateval{1.00000001^12^16}}$ \xintDigits:=16;% \end{everbatim*} Notes: \begin{itemize}[noitemsep] \item in the case with \dtt{16} digits precision, we ensured |12^16| got computed exactly with all its \dtt{18} digits and was not rounded to only \dtt{16} digits (and confirmation is that the result matches the second one at \dtt{48} digits), \item the |1.4g| right associativity of powers is taken into account to drop parentheses. \end{itemize} As the legacy \csbxint{FloatPower} and \csbxint{FloatSqrt} work in arbitrary precision, the result for integer or half-integer exponents is produced with a full-size mantissa, even if |Digits| is more than \dtt{62} (as is examplified above). In the |10^(b*log10(a))| branch the mantissa size is limited to the minimum of |Digits| and of \dtt{64}. Its last digits will start being wrong if |b| becomes about (in absolute value) \dtt{100000000}. If you really need to compute powers with exponents that large or larger, it is recommended to decompose the exponent as a sum of the nearest integer or half-integer and a fractional part and express the power as a product. This is not done automatically as it would add some overhead in general for some a priori very rare use cases. % And recall that the decimal exponents of final and % intermediate results should obey the \TeX\ bound for integers anyhow, i.e. be % at most (in absolute value) \dtt{\number"7FFFFFFF}, add some safety margin... In \csbxint{eval}, this is as in \csbxint{floateval} but for one difference: integer exponents will trigger an exact evaluation, as long as: \begin{itemize} \item the exponent absolute value is at most \dtt{9999}, \item it is evaluated a priori, based on the length of the input, that the output will have at most \dtt{10000} digits (or only a bit more), separately for numerator and denominator. \end{itemize} The check for integralness of exponent is not on its mathematical value but on its internal representation, for speed. So |6/3| is not recognized as being an integer exponent in \csbxint{eval}; but in \csbxint{floateval}, the |6/3| will have been computed and recognized as |2|. Also |2.00| or |200e-2| is recognized as an integer in both parsers. Similar remarks apply to half-integer case. To compute exactly higher powers than |2^9999| or |9^9999| or |99^5000| or |999^3333|, etc..., use \csbxint{iieval}. See \csbxint{iiPow} for related comments if you don't want to melt your CPU. If |Digits| is at most \dtt{8}, logarithms are computed faster but with less accuracy; internally, using \dtt{9} \emph{fixed point fractional digits}. And powers |a^b| lose accuracy in last digits quickly as |b| rises. Here is what was observed with some random tests: \begin{itemize}[noitemsep] \item for |b| neither integer nor half-integer and |1<b<10|, roughly \dtt{8} correct digits for between \dtt{80}\% and \dtt{90}\% of cases and in the remaining cases only a \dtt{1ulp} error. \item for |b| neither integer nor half-integer and |10^e<b<10^(e+1)|, roughly \dtt{8-e} digits are correct for about \dtt{90}\% of cases and there is a one unit error in the last of those digits in the remaining cases. \end{itemize} To maintain higher accuracy, split the input as |a^n a^h| with |n| integer or half-integer nearest to |b|. After having considered (and implemented) the method, decision was made to not incorporate it as it would induce serious overhead generally speaking. The |a^b| with fractional exponent |b| such that |abs(b)<10| are currently computed with at most \dtt{1ulp} error in the vast majority of cases it seems, which is largely precise enough for plots, and then speed matters most. Larger exponents can be handled (since |1.4f|) via manually implementing the splitting trick, as described above. The documentation of the legacy macro \csbxint{FloatPower} (which is used for powers with integer and half-integer exponents) explains it has a guaranteed error bound of |0.52ulp|, in arbitrary precision. Generally speaking, the math functions added at |1.4e| target even smaller errors (but only up to \dtt{62} digits), something of the order of |0.505ulp|, and in practice they seem to achieve even better than \dtt{99\%} of correct rounding probability (at least in their natural ranges, and it varies according to the value of |Digits|). Perhaps in future I will re-examine whether it is worthwile to increase a bit the theoretical accuracy of \csbxint{FloatPower}, as I have not had the time to really measure systematically its pratical accuracy, all anecdotical evidence showing it is good. \clearpage \let\xintlognameUp\undefined \csname xinttoolsnameUp\endcsname \def\n{|{N}|} \def\m{|{M}|} \def\x{|{x}|} \section{Macros of the \xinttoolsname package} \RaisedLabel{sec:tools} 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. \autoref{sec:examples} gives additional (some quite dated) examples of use of macros of this package. \xinttoolsname is automatically loaded by \xintexprname. \localtableofcontents \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 \myenquote{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{xintNthOnePy}} \label{xintNthOnePy} \csa{xintNthOnePy\x}\marg{list}\etype{\numx f} gets (expandably) the |x|th item of the \meta{list}, adding a brace pair if there wasn't one. Attention, items are counted starting at zero. For negative index, behaves as \csbxint{NthElt}. If the index is out of range, the empty output is returned. If the input list was empty (had no items) the empty output is returned. \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|\xtype{} 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 some code online posted 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|\xtype{} 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 As stated in previous item the first iteration follows some non-expandable internal dealings. This means for example that in \LaTeX{}, one can not inject a |\multicolumn| in the first iteration. Sometimes one way work around this by injecting father |&\multicolumn| or |\\ \multicolumn|. \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 \def\n{|{N}|} \def\m{|{M}|} \def\x{|{x}|} \csname ExamplesnameUp\endcsname \section {Additional (old) examples with \xinttoolsname or \xintexprname or both} \RaisedLabel{sec:examples} Note: \xintexprname.sty automatically loads \xinttoolsname.sty. The examples given here start to feel dated and are currently in need of some rewrite to better illustrate newer features of the package. \localtableofcontents \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 floored division). 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|, |2^64|, and the index are respectively \xinttheiiexpr subs(iterr(0,1;(@1>N)?{break(@1,N,i)}{@1+@2},i=1++),N=2^64)\relax. \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{\xintiiexpr iterr(#1,#1;even(i)? {(@2<=1)?{break(@1,i//2)} {odd(@2)?{3@2+1}{@2//2}}} {(@1>@2)?{@1}{@2}},i=0++)\relax } With initial value 1161, the maximal intermediate value and the number of steps needed to reach 1 are respectively \syrMax{1161}.\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{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*} % clean up possible left-over mess from previous examples \let\IsPrime\undefined \let\SmallestFactor\undefined \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} % 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 % % With xint 1.4 we should use ? and ?? (although in the case at hand ifsgn() % and if() would be ok but I should not say that). % \xintdefiifunc powmod_a(x, m, n) := isone(m)? % m=1, return x modulo n { x /: n } % m > 1 test if odd or even and do recursive call { odd(m)? { x*sqr(powmod_a(x, m//2, n)) /: n } { sqr(powmod_a(x, m//2, n)) /: n } } ; \xintdefiifunc powmod(x, m, n) := (m)?{powmod_a(x, m, n)}{1}; %% Syntax used before xint 1.4: % \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); % 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 % prior to 1.4 we had \xintthe#1 here but the actual tokens represented % by this #1 when isPseudoPrime() function expands have changed and % the correct way is now \xintiieval{#1} to hand over explicit digits to % the \IsVerySmallPrime macro. {\IsVerySmallPrime{\xintiieval{#1}}} {(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 \xintiiexpr 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 (link removed) The version here is like |code 3| on (link removed) (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{00}\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 (link removed) 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. 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}}}% % may \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|. \clearpage \expandafter\let\csname ExamplesnameUp\endcsname\undefined \csname xint bundlenameUp\endcsname \def\xintRunningHeader{{\inheadertrue\catcode`,12\relax \DOCxintfrontpage, \csname xint bundlename\endcsname, \xintkernelname, \xintcorename, \xintname, \xintfracname, \xintbinhexname, \xintgcdname, \xintseriesname, \xintcfracname}} \markboth{\makebox[0pt]{\xintRunningHeader}}{\makebox[0pt]{\xintRunningHeader}} \etocdepthtag.toc {macros} \addtocontents{toc}{\gdef\string\tocstylesectionbracedcolor{{tocstylebundlesectioncolor}}} \def\etocaftertochook{\addvspace{\bigskipamount}} \part{The macro layer for expandable computations: \xintcorename, \xintname, \xintfracname, and some extras} \RaisedLabel[15]{sec:bundle} \begin{framed} WARNING ! The documentation is getting old, and is in need of rewrites for many sections, particularly for examples. We do try to keep updated the description of macros provided by the packages. \end{framed} \etocsetnexttocdepth{section} \localtableofcontents \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://mirrors.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 \ctanpackage{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{https://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{https://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 \ctanpackage{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{https://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\relax|} % 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 (when |Q<0| it indicates rather by how many digits one should reduce the mantissa lengths via a final rounding). \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. See \xintlogname for fractional powers and \xinttrigname for trigonometrical functions. 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 and will be referred too in this manual as \xexpan sion. 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 \ctanpackage{etoolbox}% % \footnote{\url{https://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. \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 from \xintfracname having |Float| in their names deliver a number in the scientific notation as described in the documentation of \csbxint{Float}. The exception is \csbxint{PFloat} which does some customizable pretty printing of the result. \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|. \end{framed} \subsection{\csh{ifcase}, \csh{ifnum}, \texorpdfstring{...\@}{...} 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 \ctanpackage{etoolbox}% % \footnote{\url{https://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{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. It conveys some short information on the cause of the problem,% % \footnote{The wording of these messages has been last modified at |1.4m|.\CHANGED{1.4m}} % then an optimistic statement about a possible recovery if the user (in interactive mode) simply hits the |<return>| key. % In non-interactive (|nonstopmode|) the \TeX{} run goes on uninterrupted and the error data will be found in the compilation log. Often, \xintname will fall-back to using a zero value. This is still an experimental feature.% % \footnote{Customizable handlers, error traps, error flags are implemented in embryonic form but without user interface since |1.2l| release. This is not ready yet.} % \footnote{The |1.4g| new formatting implementation benefited from a May 2021 thread at the \LaTeX3 site where expandable error messages were discussed, with in particular contributions of |@blefloch| and |@Skillmon|.} The encouragements will be slightly better formatted if the run is with \LaTeX\ compared to Plain \eTeX: Plain by default does not set the |\newlinechar| which allows to issue linebreaks in messages at chosen locations. In the examples here, \ctanpackage{xintsession} is used, and it loads \xintname in a way activating the nicer |\newlinechar| formatted messages, even though it runs (a priori, but not necessarily) under Plain \eTeX. \begin{everbatim} >>> 1/0; Runaway argument? ! xint error: Division by zero: 1/0. ! Paragraph ended before \xint<...> is done, but will resume: hit <return> at the ? prompt to try fixing the error above which has been encountered before expansion was complete. <to be read again> \par ... l.602 \xintsession \endinput%^^M ? @_1 0 >>> (-1)^3.2; Runaway argument? ! xint error: Fractional power 32/1[-1] of negative -1[0]. ! Paragraph ended before \xint<...> is done, but will resume: hit <return> at the ? prompt to try fixing the error above which has been encountered before expansion was complete. <to be read again> \par ... l.602 \xintsession \endinput%^^M ? @_2 0 >>> cos 1); Runaway argument? ! xint error: `cos1' unknown, say `Isome_var' or I use 0. ! Paragraph ended before \xint<...> is done, but will resume: hit <return> at the ? prompt to try fixing the error above which has been encountered before expansion was complete. <to be read again> \par ... l.602 \xintsession \endinput%^^M ? Runaway argument? ! xint error: Extra ) removed. Hit <return>, fingers crossed. ! Paragraph ended before \xint<...> is done, but will resume: hit <return> at the ? prompt to try fixing the error above which has been encountered before expansion was complete. <to be read again> \par ... l.602 \xintsession \endinput%^^M ? @_3 0 >>> 3=4; Runaway argument? ! xint error: Expected an operator but got `='. Ignoring. ! Paragraph ended before \xint<...> is done, but will resume: hit <return> at the ? prompt to try fixing the error above which has been encountered before expansion was complete. <to be read again> \par ... l.602 \xintsession \endinput%^^M ? @_4 12 >>> &bye \end{everbatim} In the last example, tacit multiplication was applied as \xintexprname was looking for an operator, got some invalid input and then a number. 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 |\relax| being swallowed by a non-terminated |\numexpr|: \begin{everbatim} \xintexpr 3 + \numexpr 5+4\relax followed by some LaTeX code... \end{everbatim} The correct input is \begin{everbatim} \xintexpr 3 + \numexpr 5+4\relax\relax \end{everbatim} But people in their right mind will have done \begin{everbatim} \xintexpr 3 + 5 + 4\relax \end{everbatim} A few will have done the computation in their heads. In such cases low-level errors will 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. \subsection{Package namespace, catcodes} This section reviews (probably with some omissions) important miscellany regarding control sequence names and catcode matters and is basically in its entirety a \begin{TeXnote} \begin{itemize} \item The bundle packages force the |\space| and |\empty| control sequences into having their default meanings as in Plain \TeX{} or \LaTeX2e formats. \item Private macros (or internally used |\count| registers, and one private |\toks|) have names starting with |\xint_| or |\XINT_|. Some, for legacy or technical reasons, have |\xint| or |\XINT| prefix with no underscore. \item All public macros have their names starting with |\xint| except for: the \xintkernelname provided \hyperref[odef]{|\odef|}, \hyperref[oodef]{|\oodef|}, \hyperref[fdef]{|\fdef|}. If macros with these names already exist \xinttoolsname will not overwrite them. Their meanings are also available under the names \csbxint{odef}, \csbxint{oodef}, etc... \item Whether in arguments of \xintfracname macros or inside \csbxint{expr}essions active characters will cause naturally problems, one thinks in particular of characters made active by |babel| languages such as |babel-french| for |!?;:|, and for example the |!| if used as factorial operator will cause breakage. Prefixing with |\string| is one option, and there is also |\detokenize|. \item Precautions are not needed (but see next item) for \csbxint{defvar} and \csbxint{deffunc} as they use automatically \csbxint{exprSafeCatcodes} and \csbxint{exprRestoreCatcodes} to temporarily set catcodes to safe values. \item \csbxint{exprSafeCatcodes} and \csbxint{exprRestoreCatcodes} can be employed at user level too. They should be used in case of need before and after macro definitions themselves using \csbxint{expr}, \csbxint{defvar} or \csbxint{deffunc}. Indeed the latter two won't be able to ``fix'' problematic characters already present at definition time when expansion is later done. In the \LaTeX\ preamble, |babel| has not yet activated (normally) characters, so these precautions should be unneeded there. \item For the \xintfracname macros to be able to parse their inputs, standard catcodes in the argument are assumed for the digits (of course), the plus and minus signs, the dot, the letter |e|, the forward slash, the square brackets. Spaces should be avoided although they may go unnoticed sometimes. \item For the \xintexprname expressions there is more leeway: the digit tokens must have their standard catcodes, the letters must have their standard catcodes for variable and function names to be recognized, but other characters may mostly have unusual catcodes, if non-letter and not extremes. A few syntax elements are implemented via delimited macros and normal catcodes must be in effect for the comma, the equal sign and the closing parenthesis for those to work. Spaces are gobbled. The |e| of scientific notation may be |E| on input, \xintfracname macros on the other hand will not recognize the |E|. \item At loading time the catcode configuration may be arbitrary as long as it satisfies the following requirements: \begin{itemize}[nosep] \item \dtt{\%} has its normal category code, \item \dtt{\char92} has its normal category code, \item Latin letters have their normal category code "letter", \item Digits have their normal category code "other". \end{itemize} Nothing more is assumed, for example |{| and |}| may have unusual catcodes at package loading time. This will be admittedly unusual especially in \LaTeX\ as |\usepackage{xintexpr}| would then have had to be replaced by something such as |\usepackage<xintexpr>|... \item Loading the packages causes no insertion of space tokens. \item The previous two items also apply to usage of \csbxint{reloadxintlog} and of \csbxint{reloadxinttrig}. \end{itemize} \end{TeXnote} \subsection{Origins of the package} \label{ssec:origins} |2013/03/28.| Package |bigintcalc| by \textsc{Heiko Oberdiek} already provides expandable arithmetic operations on \myenquote{big integers}, i.e. integers beyond the \TeX\ bound $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 correspondence 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. \clearpage \expandafter\let\csname xint bundlenameUp\endcsname\undefined \csname xintkernelnameUp\endcsname \section{Macros of the \xintkernelname package} \RaisedLabel{sec:kernel} 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. \localtableofcontents \subsection{\csh{odef}, \csh{oodef}, \csh{fdef}} \label{odef} \label{oodef} \label{fdef} \label{xintodef} \label{xintoodef} \label{xintfdef} \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. \xintkernelname will not define these macros if the control sequence names already exist. It provides them always under the names |\xintodef|, |\xintoodef| and |\xintfdef| respectively. \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}} \xinttoolsname provides a variant \csbxint{RevWithBraces} which keeps brace pairs in the output, and \fexpan ds its input first. For inputs consisting only digit tokens, see \csbxint{ReverseDigits} from \xintname. \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{xintFirstItem}} \label{xintFirstItem} \csa{xintFirstItem}\marg{list}\etype{n} returns the first item of its argument, one pair of braces removed. If the list has no items the output is empty. It does no expansion. For this and the next similar ones, see |sourcexint.pdf| for comments on limitations. \subsection{\csh{xintLastItem}} \label{xintLastItem} Added at |1.2i|. \csa{xintLastItem}\marg{list}\etype{n} returns the last item of its argument, one pair of braces removed. 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{xintFirstOne}} \label{xintFirstOne} \csa{xintFirstOne}\marg{list}\etype{n} returns the first item as a braced item. i.e.\@ if it was braced the braces are kept, else the braces are added. It looks like using \csbxint{FirstItem} within braces, but the difference is when the input was empty. Then the output is empty. It does no expansion, which should be obtained via suitable |\expandafter|'s. \subsection{\csh{xintLastOne}} \label{xintLastOne} \csa{xintLastOne}\marg{list}\etype{n} returns the last item as a braced item. i.e.\@ if it was braced the braces are kept, else the braces are added. It looks like using \csbxint{LastItem} within braces, but the difference is when the input was empty. Then the output is empty. It does no expansion, which should be obtained via suitable |\expandafter|'s. \subsection{\csh{xintReplicate}, \csh{xintreplicate}} \label{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} available on an online site.} And \csa{xintReplicate}|{x}| integrates the \csa{romannumeral} prefix. 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.} \subsection{\csh{xintGobble}, \csh{xintgobble}} \label{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|. And \csa{xintGobble}|{x}| integrates the \csa{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.% 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 \myenquote{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 \myenquote{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.% % \begin{everbatim*} %\xintdefiifunc mod3(x):= x 'mod' 3; \xintNewIIExpr\ModThree[1]{#1 'mod' 3} \pdfsetrandomseed 87654321 \xintdefiivar BadDigits:=qraw(% \romannumeral\xintreplicate{504}{{\ModThree{\pdfuniformdeviate "C000000}}}% );% \pdfsetrandomseed 87654321 \xintdefiivar GoodDigits:=qraw(% \romannumeral\xintreplicate{504}{{\ModThree{\xintUniformDeviate{"C000000}}}}% );% 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) % !(i) (logical not) is short-cut for the vanishing test i==0, but it would be % simpler to use (i)?{i is not zero}{i is zero} with permuted branches \xinttheiiexpr iter(0,0,0;(!(i))?{[@][0]+1,[@][1],[@][2]} {(isone(i))?{[@][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]+1,[@][1],[@][2]} {(isone(i))?{[@][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 \begin{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:% % \InputIfFileExists{JFBUORDI}{}{}% \ifdefined\JFBUORDI \footnote{% \if0\pdfstrcmp{IMAC}{\JFBUORDI}Timings done during dvi build on a computer with a |2.8GHz| % %quadri-core cpu, old but still kicking, and with a locally compiled |latex| binary.\else \if0\pdfstrcmp{MBA}{\JFBUORDI}Timings done during dvi build on a computer with a |2GHz| % %dual-core cpu, old but still kicking, and with a locally compiled |latex| binary.\else %\error DOCUMENTATION SEEMINGLY BUILT NOT ON AN AUTHOR-OWNED SYSTEM, BUT \string\JFBUORDI\space IS DEFINED, WEIRD!\fi\fi } \else \footnote{These timings are done during a build on a computer not belonging to the author.} \fi % \begin{everbatim*} \pdfsetrandomseed 12345678 \pdfresettimer \romannumeral\xintreplicate{100} {\fdef\foo{\xintiiPow{\xintUniformDeviate{100000000}}{10}}}% \the\dimexpr\pdfelapsedtime sp\relax\space (with \string\xintUniformDeviate)\newline \pdfsetrandomseed 12345678 \pdfresettimer \romannumeral\xintreplicate{100} {\fdef\foo{\xintiiPow{\pdfuniformdeviate 100000000}{10}}}% \the\dimexpr\pdfelapsedtime sp\relax\space (with \string\pdfuniformdeviate)\par \end{everbatim*} 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. \end{TeXnote} \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} 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} 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. 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}. \localtableofcontents \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. \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. 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{iiSqrt}, \csbxint{iiSqrtR}, \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 \myenquote{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 \myenquote{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|. 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. \etocsetnexttocdepth{subsubsection} \localtableofcontents \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{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^{-\text{|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{\text{|N|}}$ is $\text{|M|}-\frac{\text{|d|}}{\text{|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 \myenquote{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 \myenquote{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{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}}} At |1.3d|, this macro (which is used by the \func{gcd} function in \csbxint{iiexpr}) was copied over to \xintname, thus removing a partial dependency of \xintexprname on \xintgcdname. At |1.4| \xintgcdname requires \xintname and the latter is thus the one providing the macro. \subsection{\csh{xintiiLCM}} \label{xintiiLCM} |\xintiiLCM|\n\m\etype{ff} computes the least common multiple. It is positive, except if one of |N| or |M| vanish, in which case the macro returns zero. % \leftedline{\csa{xintiiLCM}|{10000}{1113}|\dtt{=\xintiiLCM{10000}{1113}}} % \leftedline{|\xintiiLCM{123456789012345}{9876543210321}=|\dtt {\xintiiLCM{123456789012345}{9876543210321}}} At |1.3d|, this macro (which is used by the \func{lcm} function in \csbxint{iiexpr}) was copied over to \xintname, thus removing a partial dependency of \xintexprname on \xintgcdname. At |1.4| \xintgcdname requires \xintname and the latter is thus the one providing the macro. \subsection{\csh{xintiiGCDof}}\label{xintiiGCDof} \csa{xintiiGCDof}|{{a}{b}{c}...}|\etype{f{$\to$}{\lowast f}} computes the greatest common divisor of the integers |a|, |b|, \dots{}. It is a support macro for the |gcd()| function of the \csbxint{iiexpr} parser. It replaces the \csbxint{GCDof} which was formerly provided by \xintgcdname and is now available via \xintfracname in a version handling also fractions. \subsection{\csh{xintiiLCMof}}\label{xintiiLCMof} \csa{xintiiLCMof}|{{a}{b}{c}...}|\etype{f{$\to$}{\lowast f}} computes the least common multiple of the integers |a|, |b|, \dots{}. It is a support macro for the |lcm()| function of the \csbxint{iiexpr} parser. It replaces the \csbxint{LCMof} which was formerly provided by \xintgcdname and is now available via \xintfracname in a version handling also fractions. \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{(WIP) \csh{xintRandomDigits}}\label{xintRandomDigits} \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} |\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. 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*} \begin{TeXnote} the digits are produced eight by eight by the same method which would result from \csbxint{UniformDeviate}|{100000000}| but with less overhead. \end{TeXnote} % \subsection{\csh{\xintOneRandomDigit}}\label{xintOneRandomDigit} \subsection{(WIP) \csh{xintXRandomDigits}}\label{xintXRandomDigits} |\xintXRandomDigits{N}|\xtype{\numx} expands under exhaustive expansion (|\edef|, |\write|, |\csname| ...) to |N| random decimal digits. The argument must be non-negative. 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). \begin{TeXnote} the digits are produced eight by eight by the same method which would result from \csbxint{UniformDeviate}|{100000000}| but with less overhead. \end{TeXnote} \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|. \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... \begin{TeXnote} the digits are produced eight by eight by the same method which would result from \csbxint{UniformDeviate}|{100000000}| but with less overhead. \end{TeXnote} \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|. \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*} \begin{TeXnote} the digits are produced eight by eight by the same method which would result from \csbxint{UniformDeviate}|{100000000}| but with less overhead. \end{TeXnote} \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: 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. \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 At |1.4g|, old legacy typesetting macros |\xintFrac|, |\xintSignedFrac|, |\xintFwOver| and |\xintSignedFwOver| were renamed into \csbxint{TeXFrac}, \csbxint{TeXsignedFrac}, \csbxint{TeXOver}, \csbxint{TeXsignedOver}. The old names will raise errors\CHANGED{1.4m} and will be removed completely soon. \localtableofcontents \subsection{\csh{xintTeXFromSci}}\label{xintTeXFromSci} Experimental.\xtype{} This typesetting math-mode-only macro expects an input which is already in, or will expand to, decimal or scientific notation. A trailing |/B| is accepted and will be handled differently according to whether it follows some scientific exponent |eN| part or not. It was formerly |\xintTeXfromSci|. Old name deprecated at |1.4l|. Also it used to be \fexpan dable but is now only \xexpan dable. Use |\expanded| if needed. This macro can be used as a typesetting wrapper for \csbxint{eval} or \csbxint{floateval} output: it expects its input (after expansion) to have been already \myenquote{prettified} for example via the removal of trailing zeros, usage of fixed point notation if scientific exponent is small, etc\dots\ % It simply transforms the |e<exponent>| part, if actually present, into |\cdot 10^{exponent}|. A fractional part |/B| if found in the expansion of the input must be last and will be tranformed into |\cdot B^{-1}| if there was a scientific part, else the output will be using |\frac{A}{B}| (or the \TeX\ equivalent in place of |\frac|) with |A| the numerator. \begin{TeXnote} \begin{itemize} \item I am hesitating whether the |\frac{A}{B}| branch choice should require |A| to be an integer, or will also, as currently, be done with |A| being a number in decimal notation. Please advise. \item The package does: \begin{everbatim} \ifdefined\frac \protected\def\xintTeXFromScifracmacro#1#2{\frac{#2}{#1}}% \else \protected\def\xintTeXFromScifracmacro#1#2{{#2\over#1}}% \fi \end{everbatim} Customize as desired. Notice the interversion of arguments. \end{itemize} \end{TeXnote} Example: \begin{everbatim*} $\xintTeXFromSci{\xintfloateval{1.1^10000/5}}$, $\xintTeXFromSci{\xinteval{1.1^10000/5}}$\par \end{everbatim*} The above examples are in the case of a single numerical value. To handle more complex outputs from \csbxint{eval} or \csbxint{floateval} one will need to proceed via a redefinition of \csbxint{floatexprPrintOne} and/or \csbxint{exprPrintOne} like this: \begin{everbatim*} \[\def\xintfloatexprPrintOne[#1]#2{\xintTeXFromSci{\xintPFloat[#1]{#2}}} \xintfloateval[10]{2^100, 3^100, 13^100}\] \end{everbatim*} \par\vskip-\belowdisplayskip \begin{everbatim*} \[\def\xintexprPrintOne#1{\xintTeXFromSci{\xintFracToSci{#1}}} \xinteval{sqrt(2^101,60), 355/113, 6.02e23/1000}\] \end{everbatim*}% attention à l'espace TeX est en mode horizontal après display This will however make then impossible, due to the added \TeX\ mark-up in the output, the nesting of \csbxint{floateval}/\csbxint{eval} inside one another. The core \csbxint{expr}|...\relax| syntax remains usable and is anyhow the recommended way for such nesting as it is more efficient. Some similar effect is also possible without \csbxint{TeXFromSci}, simply by a customization of \csbxint{PFloatE} like this: \begin{everbatim*} \begingroup \def\xintPFloatE#1.{\cdot10^{#1}.}% $\xintfloateval{1.1^10000/5}$, $\xinteval{1.1^10000/5}$ \endgroup\newline \end{everbatim*}% This method is simpler-minded but will leave the trailing |/B|'s \myenquote{as is}, even if the numerator has no scientific exponent part. The presence of extra \TeX\ mark-up in the output has the consequences on nesting which were mentioned above. \subsection{\csh{xintTeXFrac}}\label{xintTeXFrac} This is a typesetting \LaTeX{} only macro\etype{\Ff}, math mode only as it expands to |\frac{A}{B}10^n| for an input which ends up parsed into raw format |A/B[n]|. If the denominator |B| is \dtt{1}, the output is |A\cdot 10^n|. If the exponent |n| is \dtt{0}, the |[\cdot]10^n| part is omitted. \begin{everbatim*} $\xintTeXFrac {178.000/25600000}$, $\xintTeXFrac {178.000/1}$, $\xintTeXFrac {3.5/5.7}$\newline \end{everbatim*}% The input, if in a fraction form, is not simplified in any way, except for transforming numerator and denominator into integers, separating a power of ten part. Macros such as \csbxint{Irr}, \csbxint{PIrr}, \csbxint{REZ} can be inserted to wrap the input and help simplify it. The minus sign ends up in the numerator. It is the new name since |1.4g| of |\xintFrac|. The old name now raises a \TeX{} error.\CHANGED{1.4m} \subsection{\csh{xintTeXsignedFrac}}\label{xintTeXsignedFrac} This is as \csbxint{TeXFrac}\etype{\Ff} except that a negative fraction has the sign ending up in front, not in the numerator. \begin{everbatim*} $\xintTeXFrac {-355/113}=\xintTeXsignedFrac {-355/113}$\newline \end{everbatim*}% It is the new name since |1.4g| of |\xintSignedFrac|. The old name now raises a \TeX{} error.\CHANGED{1.4m} \subsection{\csh{xintTeXOver}}\label{xintTeXOver} This does the same as \csa{xintTeXFrac}\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). \begin{everbatim*} $\xintTeXOver {178.000/25600000}$, $\xintTeXOver {178.000/1}$, $\xintTeXOver {3.5/5.7}$\newline \end{everbatim*}% It is the new name since |1.4g| of |\xintFwOver|. The old name now raises a \TeX{} error.\CHANGED{1.4m} \subsection{\csh{xintTeXsignedOver}}\label{xintTeXsignedOver} This is as \csbxint{TeXOver}\etype{\Ff} except that a negative fraction has the sign put in front, not in the numerator. \begin{everbatim*} $\xintTeXOver{-355/113}=\xintTeXsignedOver{-355/113}$\newline \end{everbatim*}% It is the new name since |1.4g| of |\xintSignedFwOver|. The old name now raises a \TeX{} error.\CHANGED{1.4m} \subsection{\csh{xintLen}}\label{xintLenFrac} The \csbxint{Len} macro\etype{\Ff} from \xintname 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). \subsection{\csh{xintNum}}\label{xintNumFrac} The \csbxint{Num} \etype{\Ff} from \xintname is transformed into a synonym to \csbxint{TTrunc}. 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{xintRawBraced}}\label{xintRawBraced} This macro expands and parses its input\etype{\Ff} |f| as all \xintfracname macros and produces as output |{N}{A}{B}| (with \TeX\ braces) where \csbxint{Raw} would have returned |A/B[N]|. \subsection{\csh{xintNumerator}}\label{xintNumerator} The input data\etype{\Ff} is parsed as if by \csbxint{Raw} into |A/B[N]| and then |A| is returned 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]| and then |B| is returned 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*} \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. (|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{xintDecToStringREZ}}\label{xintDecToStringREZ} \csa{xintDecToStringREZ}\etype{\Ff} uses fixed point (decimal) notation for the output. The |REZ| means that it trims (REmoves) trailing Zeros. The name is a bit strange, because it its not limited to \emph{decimal numbers} but accepts the same kind of inputs as most other \xintfracname macros. The parsing of this input transforms it first into an internal format having a numerator |A|, a denominator |B| and a power of ten exponent |N|, standing for the fraction |A/B| times \dtt{10} to the power |N|. Then the following recipe applies: \begin{itemize}[noitemsep] \item the zero value is printed as \dtt{\xintDecToStringREZ{0}} (no decimal point). \item trailing zeros of |A| and |B| are removed and |N| is adjusted, \item if the new |B| is not \dtt{1}, it will appear in the output as |/B|, \item fixed point decimal notation is used for |AeN|: \begin{itemize}[noitemsep] \item if |N| is non-negative, the output is an integer with |N| trailing zeros (and no decimal mark) \item if |N| is negative a decimal point is used, and if |AeN| is less than one in absolute value, output will start with \dtt{0.} (i.e. a decimal mark). \end{itemize} \end{itemize} The following should be noted: \begin{enumerate}[noitemsep] \item the fraction |AeN/B| or even |A/B| is not pre-reduced into lowest terms, \item the macro does not check if |B| contains only powers of \dtt{2} and \dtt{5}, so |1/2| is printed as \dtt{\xintDecToString{1/2}}, not as \dtt{0.5}. \end{enumerate} The definitive behaviour remains to be decided regarding these last two points. \begin{everbatim*} \xintDecToStringREZ{0}, \xintDecToStringREZ{1/2}, \xintDecToStringREZ{0.5000}\newline \xintDecToStringREZ{1.23456789e5}, \xintDecToStringREZ {1.23456789e-3}\newline \xintDecToStringREZ{12345e-1}, \xintDecToStringREZ {12345e-2}, \xintDecToStringREZ{12345e-3}\newline \xintDecToStringREZ{12345e-4}, \xintDecToStringREZ {12345e-5}, \xintDecToStringREZ{12345e-6}\newline \xintDecToStringREZ{1.234567890000e12}, \xintDecToStringREZ{1.23456000e-5/10}\newline \xintDecToStringREZ{70/14} % is not reduced to lowest terms \end{everbatim*} See \csbxint{FloatToDecimal} for a variant which first rounds the input to some given number of significant digits. \subsection{\csh{xintDecToString}}\label{xintDecToString} \csa{xintDecToString}\etype{\Ff} uses fixed point notation for the output. Is behaviour remains somewhat undecided in so far as whether it should identify inputs which correspond to decimal numbers (i.e. fractions with only powers of two and five in their denominator, once reduced to lowest terms). As with \csbxint{DecToStringREZ}, the name is a bit strange as inputs are in no way limited to decimal numbers but are of the most general type accepted by the \xintfracname macros. It is the same macro as \csbxint{DecToStringREZ} except that it does not remove trailing zeros, in fact \csbxint{DecToStringREZ}|{f}| is defined as \csbxint{DecToString}|{|\csbxint{REZ}|{f}}|. \begin{everbatim*} \xintDecToString{0}, \xintDecToString{1/2}, \xintDecToString{0.5000}\newline \xintDecToString{1.23456789e5}, \xintDecToString {1.23456789e-3}\newline \xintDecToString{12345e-1}, \xintDecToString {12345e-2}, \xintDecToString{12345e-3}% \newline \xintDecToString{12345e-4}, \xintDecToString {12345e-5}, \xintDecToString{12345e-6}% \newline \xintDecToString{1.234567890000e12}, \xintDecToString{1.23456000e-5/10}\newline \xintDecToString{70/14} \end{everbatim*} Since |1.4e|, \csbxint{DecToString} is the default for \csbxint{iexprPrintOne}, which governs the \csbxint{ieval} output format: in this use case there is never a |/B| fractional part and the output is always either an integer (if \csbxint{ieval} was used without optional argument) or a decimal string \begin{everbatim} \def\xintiexprPrintOne{\xintDecToString} \end{everbatim} Any replacement of \csbxint{DecToString} as the expansion of \csbxint{iexprPrintOne} should obey the following blueprint: \begin{itemize}[noitemsep] \item to\xtype{} be expandable, but not necessarily \fexpan dable, \item to accept on input |A| or |A[N]|. \end{itemize} \subsection{\csh{xintFracToSci}}\label{xintFracToSci} \csa{xintFracToSci}\etype{\Ff} was initially at |1.4| a private macro which served as default customization of \csbxint{exprPrintOne} and, despite being documented in the user manual, was not supposed to be used at user level (not being \fexpan dable it could not be nested within macros of \xintfracname, and besides accepted a limited range of inputs). It has been upgraded at |1.4l| to behave like all other \xintfracname macros. Here is what it does: \begin{itemize}[noitemsep,nosep] \item it first parses the input like any other \xintfracname macro and convert it into the ``raw'' |A/B[N]| format, \item it then produces this output: |A/B| if |N=0| (and |/B| is omitted if not |1|), and for |N| not zero, the output numerator will be |AeN| written in scientific notation exactly like it would by \csbxint{PFloat} but without of course prior rounding to a given number of digits; the trailing zeros in the significand will be removed always (the \csbxint{PFloatMinTrimmed} configuration is ignored). Then this value in scientific notation (or in decimal fixed point notation if the scientific exponent is in the \csbxint{PFloatNoSciEmin} to \csbxint{PFloatNoSciEmax} range) will be attached to a trailing denominator |/B| (omitted if it is |/1|). \end{itemize} Please note: \begin{itemize} \item there is no reduction of the fraction |A/B| to lowest terms, \item trailing zeros in the integer denominator |B| are not moved and incorporated into the final scientific exponent, \item no attempt is made to check if |B| is a product of only |2|'s and |5|'s and thus could be integrated into some pure decimal notation for the numerator or at least its significand. \end{itemize} Changes of \csbxint{PFloat} at |1.4k| have an impact here. In particular the zero value will give \dtt{0} whether the input was some |0|, |0e-5|, |0/3|, |0.00|, etc\dots, whereas at |1.4e| it would have been \dtt{0.0} for cases triggering some \csbxint{PFloat} subroutine. The general blueprint is still to be considered \emph{unstable}. The output routine of \csbxint{eval} is customizable via redefining \csbxint{exprPrintOne} whose current default is (equivalent to): \begin{everbatim} \def\xintexprPrintOne{\xintFracToSci} \end{everbatim} \subsection{\csh{xintFracToDecimal}} \label{xintFracToDecimal} \csa{xintFracToDecimal}\etype{\Ff} is a variant of \csbxint{FracToSci} which differs from it in so far as it outputs a numerator using decimal notation, i.e. with as many zeros as are needed (and no more) and no scientific exponent. The denominator goes through ``as is'' except if it is |1|, then it is omitted. In other terms its behaviour is currently intermediate between \csbxint{DecToString} and \csbxint{DecToStringREZ}, as it does not remove trailing zeros of the denominator. Consider its behaviour as \emph{unstable}. It can be used to customize \csbxint{exprPrintOne}: \begin{everbatim} \def\xintexprPrintOne{\xintFracToDecimal} \end{everbatim} It was initially at |1.4k| a private macro which served as an alternative to \csb{xintFracToSci} default customization of \csbxint{exprPrintOne} and, despite being documented in the user manual, was not supposed to be used at user level (not being \fexpan dable it could not be nested within macros of \xintfracname, and besides accepted a limited range of inputs). It has been upgraded at |1.4l| to behave like all other \xintfracname macros. \subsection{\csh{xintTrunc}}\label{xintTrunc} \csa{xintTrunc}|{x}{f}|\etype{\numx\Ff} returns the start of the decimal expansion of the fraction |f|, truncated to: \begin{itemize} \item if |x>0|, |x| digits after the decimal mark, \item if |x=0|, an integer, \item if |x<0|, an integer multiple of |10^{-x}| (in scientific notation). \end{itemize} The output is the sole digit token \dtt{0} if and only if the input was exactly zero; else it contains always either a decimal mark (even if |x=0|) or a scientific part and it conserves the sign of |f| (even if the truncated value represents the zero value). Truncation is done towards zero. \begin{everbatim*} \begin{multicols}{2} \noindent\xintFor* #1 in {\xintSeq[-1]{7}{-14}}:{\xintTrunc{#1}{-11e12/7}\newline}% \xintTrunc{10}{1e-11}\newline \xintTrunc{10}{1/65536}\par \end{multicols} \end{everbatim*} \begin{framed} \textbf{Warning:} \emph{it is not yet decided is the current 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 after decimal mark). If \xintfracname distinguished zero, positive zero, and negative zero then 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} \subsection{\csh{xintXTrunc}}\label{xintXTrunc} \csa{xintXTrunc}|{x}{f}|\xtype{\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: \begin{itemize} \item if |x>0|, |x| digits after the decimal mark, \item if |x=0|, an integer, \item if |x<0|, an integer multiple of |10^{-x}| (in scientific notation). \end{itemize} The output is the sole digit token \dtt{0} if and only if the input was exactly zero; else it contains always either a decimal mark (even if |x=0|) or a scientific part and it conserves the sign of |f| (even if the rounded value represents the zero value). \begin{everbatim*} \begin{multicols}{2} \noindent\xintFor* #1 in {\xintSeq[-1]{7}{-14}}:{\xintRound{#1}{-11e12/7}\newline}% \xintRound{10}{1e-11}\newline \xintRound{10}{1/65536}\newline \end{multicols} \end{everbatim*}% Rounding is done with half-way numbers going towards infinity of the same sign. \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. Attention that leading zeros are automatically removed: the output is in strict integer format. \begin{everbatim*} \begin{multicols}{2} \noindent\xintFor* #1 in {\xintSeq[-1]{7}{-14}}:{\xintiTrunc{#1}{-11e12/7}\newline}% \xintiTrunc{10}{1e-11}\newline \xintiTrunc{10}{1/65536}\par \end{multicols} \end{everbatim*} \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. The output has no leading zeroes, it is always in strict integer format. \begin{everbatim*} \begin{multicols}{2} \noindent\xintFor* #1 in {\xintSeq[-1]{7}{-14}}:{\xintiRound{#1}{-11e12/7}\newline}% \xintiRound{10}{1e-11}\newline \xintiRound{10}{1/65536}\par \end{multicols} \end{everbatim*} \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{xintSignBit}}\label{xintSignBit} Expands to \dtt{1} for negative input, to \dtt{0} else.\etype{\Ff} Added at |1.4l|. \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. \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. \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. \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. \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 the exponent |x| possibly also, but if only \xintfracname is loaded it will be truncated to an integer. At |1.4e| the behaviour of the macro is enhanced if \xintexprname is loaded, at it then becomes the support macro for powers |a^b|, |a**b| (and the \func{pow} function) in \csbxint{eval}: it now handles also non-integer exponents. Also, if the exponent is an integer, it checks a priori if an exact evaluation would produce more than about \dtt{10000} digits and then does in its place a floating point evaluation. The check whether the exponent is integer is not on the mathematical value but on the format (for reasons of efficiency). So |4/2| will not be recognized as integer and it will thus trigger usage of the floating point evaluations; however |2.0| will be recognized as an integer, as of course |2|. If the exponent is considered an integer it is then checked if it is less than \dtt{10000} (in absolute value) and if the output would contain less than \dtt{10000} digits (separately for numerator and denominator) and only then is the power computed exactly. Else it is computed as by \csbxint{FloatPower} (but the output uses raw |A[N]| format not scientific notation). Use \csbxint{iiPow} (on integers only, not fractions) for exact powers with larger exponents. Also, a check is done whether the exponent is half-integer. Again this check is not on the value but on the format, so |2.5| is an half integer, as is |25e-1|, or |2.50| but |5/2| is not considered an half-integer (for reasons of internal efficiency). If the exponent is half-integer the power is computed by combining suitably \csbxint{FloatPower} with \csbxint{FloatSqrt} (but the output uses raw |A[N]| format not scientific notation). If the exponent is neither an integer nor an half-integer, the power is computed using logarithm and exponential based approach (and uses raw |A[N]| output format). If |Digits| is at most \dtt{8} (which triggers \ctanpackage{poormanlog} usage, for very fast logarithms but only with about \dtt{8} or \dtt{9} accurate fractional digits) this will start being inaccurate in the last digit already with fractional exponents |x > 10|. It is recommended to split then the exponent into an integer or half-integer part and a fractional part. Powers with integer or half-integer exponents, even very big, are always computed accurately, for any value of |Digits|. % Note: in all cases where the macro has been % extended at |1.4e| to proceed via a floating point evaluation, the output is % in raw |A[N]| format. Within an \csbxint{iiexpr}|..\relax| the infix operators |^| and |**| are mapped to \csbxint{iiPow} and powers are always computed exactly even if they would produce more than \dtt{10000} digits and melt your CPU; within an \csbxint{expr}-ession |^| and |**| are mapped to \csbxint{Pow} as described here. \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{xintGCD}}\label{xintGCD} The greatest common divisor of its two arguments, which are possibly \emph{fractions}.\etype{\Ff\Ff} Prior to |1.4| a macro of the same name existed in \xintgcdname. But it truncated its two arguments to integers via \csbxint{Num}. See \csbxint{iiGCD} for the integer only variant. \subsection{\csh{xintLCM}}\label{xintLCM} The least common multiple of its two arguments, which are possibly \emph{fractions}.\etype{\Ff\Ff} Prior to |1.4| a macro of the same name existed in \xintgcdname. But it truncated its two arguments to integers via \csbxint{Num}. See \csbxint{iiLCM} for the integer only variant. \subsection{\csh{xintGCDof}}\label{xintGCDof} \csa{xintGCDof}|{{a}{b}{c}...}|\etype{f{$\to$}{\lowast\Ff}} computes the greatest common divisor of |a|, |b|, \dots{}. The arguments are allowed to be \emph{fractions}: the macro produces the non-negative generator of the fractional ideal they generate. The list argument may be a macro as it is \fexpan ded first. If all arguments vanish, then also the output. Prior to |1.4| a macro of the same name existed in \xintgcdname. But it truncated all its arguments to integers via \csbxint{Num} and then proceeded with integer only computations. See \csbxint{iiGCDof} for the integer only variant. % Semble encore vrai à 1.4d % Mais je n'ai testé que sur un exemple... % (which is about |6X| faster than this one for integer arguments). \subsection{\csh{xintLCMof}}\label{xintLCMof} \csa{xintLCMof}|{{a}{b}{c}...}|\etype{f{$\to$}{\lowast\Ff}} computes the least common multiple of |a|, |b|, \dots{}. The arguments are allowed to be \emph{fractions}: the macro produces the non-negative generator of the intersection of the corresponding fractional ideals. The list argument may be a macro, it is \fexpan ded first. If one of the item vanishes, then also the output. Prior to |1.4| a macro of the same name existed in \xintgcdname. But it truncated all its arguments to integers via \csbxint{Num}. See \csbxint{iiLCMof} for the integer only variant. % Avant 1.4d on avait ceci : % (which is about |9X| faster han this one for integer arguments). % mais à 1.4d le lcm des fractions est environ 4X fois plus efficace, % en ce qui concerne son emploi avec des entiers (testé sur un seul exemple) % donc le gain de faire \xintiiexpr n'est plus que 2X ! \subsection{\csh{xintDigits}, \csh{xinttheDigits}} \label{xintDigits} \label{xinttheDigits} The syntax |\xintDigits := N;| or (recommended) |\xintDigits := N\relax| assigns the value of |N| to the number of digits to be used by floating point operations (this uses internally a |\mathchardef| assignement, and |N| stands for (or expands to) a legal \TeX\ number). The default is |16|. The maximal value is |32767|. Accepted syntax includes also |\xintDigits = N;| or |\xintDigits = N\relax|, i.e.\@ the colon before the equality sign is optional. % \begin{framed} \xintexprname adds\IMPORTANTf{} the variant \csbxint{Digits*} which executes \csbxint{reloadxinttrig} and \csbxint{reloadxintlog}. A priori, you want \csbxint{Digits*}|:=N\relax|. Use |\xintDigits:=N\relax| only if not needing trigonometric or logarithm/exponential functions and wanting to avoid the overhead of reloading their librairies. Perhaps for a local temporary configuration. \end{framed} Spaces do not matter as long as they do not occur in-between digits: \begin{everbatim*} \xintDigits := 24\relax\xinttheDigits, % \xintDigits:=36 \relax\xinttheDigits, % \xintDigits:= 16 \relax and \xinttheDigits. \end{everbatim*} As shown above |\xinttheDigits|\etype{} expands to the stored value. % It has always been the case that an active colon |:| was allowed. An ending active semi-colon |;| is \emph{not} compatible: it can and will cause low-level \TeX{} errors. This is why the alternative syntax \begin{everbatim} \xintDigits:= N\relax \end{everbatim} is recommended (with or without the semi-colon). This is hopefully the syntax now in use in most examples from the documentation. % This % restriction always applied, but never got properly documented prior to % |1.3f| release... It is possible to use |\string;| but then there can not be % any space separating it from the digits. Actually, any non-expanding token can be used in place of the |\relax|. This non-expanding ending token (for example a full stop) will get removed from the token stream. \begin{everbatim*} \xintDigits = 24\def\xinttheDigits, % only for showing it works! don't do that! \xintDigits := 36.\xinttheDigits, % one can use a dot in place of semi-colon \xintDigits = 16\relax and \xinttheDigits.\par % with \relax, even better \end{everbatim*} \subsection{\csh{xintSetDigits}} \label{xintSetDigits} To be used as |\xintSetDigits|\marg{expression}\ntype{\numx} where the expression will be fed to |\numexpr|. It is a shortcut for doing |\xintDigits := \numexpr|\meta{expression}|\relax \relax|. \begin{everbatim*} \xintSetDigits{1+2+3+4+5}The value is now \xinttheDigits. \xintSetDigits{2*8}The value is now \xinttheDigits.\par \end{everbatim*} \begin{framed} The \xintexprname-added variant \csbxint{SetDigits*} is the preferred usage as it does the extra work to update the math functions from \xinttrigname and \xintlogname. \end{framed} \subsection{\csh{xintFloat}} \label{xintFloat} \label{xintFloatZero} 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 one exception to the general description: the zero value, which gets output as \dtt{\xintFloat{0}}. This was changed at |1.4k|, until then it was using \dtt{0.e0} as output. Customize via \csh{xintFloatZero} whose default definition is: \begin{everbatim} \def\xintFloatZero{0.0e0} \end{everbatim} \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{xintFloatBraced}} \label{xintFloatBraced} The experimental macro |\xintFloatBraced[P]{f}|\etype{{\upshape[\numx]}\Ff} does like \csbxint{Float} but its output consists of three \TeX-braced groups \centeredline{\marg{sign bit}\marg{scientific exponent}\marg{full width mantissa with decimal point}} It is provided for users knowing how to pick one or the other of these constituents from usage of auxiliary macros. Or one can use \csbxint{Assign}: \begin{everbatim*} \begingroup \xintAssign\xintFloatBraced[7]{-3.1234e-14}\to\A\B\C \string\A\ has meaning \meaning\A\newline \string\B\ has meaning \meaning\B\newline \string\C\ has meaning \meaning\C\par \endgroup \end{everbatim*} Some aspects are undecided: \begin{itemize}[noitemsep] \item should the first item be rather |-1|, |0|, or |1|? or |-|, nothing, nothing? \item in case of zero value the output ignores \csbxint{FloatZero}, it uses a zero exponent and full width fractional mantissa \dtt{\csname xint_gobble_ii\expandafter\endcsname\romannumeral0\xintfloatbraced{0}} (here no |[P]| and \csbxint{theDigits} has value \dtt{\xinttheDigits}), should it be otherwise? \item should the mantissa be without the decimal separator ? should it incorporate the sign ? \item in case the mantissa is without separator, should the exponent be biased to match it? \end{itemize} \subsection{\csh{xintFloatToDecimal}} \label{xintFloatToDecimal} |\xintFloatToDecimal [P]{f}|\etype{{\upshape[\numx]}\Ff} does float rounding on input like \csbxint{Float} then outputs the number using decimal notation, i.e. with as many zeros as are needed (and no more) and no scientific exponent. In other terms it behaves (and is essentially defined) as: \begin{everbatim} \xintDecToStringREZ{\xintFloat[optional P]{<input>}} \end{everbatim} Examples: \begin{everbatim*} \xintFloatToDecimal{6.02e23}\newline \xintFloatToDecimal{6.02000000000000e23}\newline \xintFloatToDecimal[20]{1/7e10}\newline \xintFloatToDecimal[30]{1/7e10} \end{everbatim*} See \csbxint{DecToString}. \subsection{\csh{xintPFloat}} \label{xintPFloat} |\xintPFloat [P]{f}|\etype{{\upshape[\numx]}\Ff} is like \csbxint{Float} but ``pretty-prints'' the output. This macro was initially added at |1.1| as a (very primitive) "prettifying printer" for floating point number, and was then somewhat influenced by Maple, for example the zero value was printed as "\dtt{0.}". Then at |1.4e| there was breaking change and the rules became somewhat similar to observed Python behaviour: mantissas trimmed of trailing zeros (whether or not scientific notation was used in the output) and integers printed with a trailing "\dtt{.0}", in particular the zero value was printed as "\dtt{0.0}". |1.4k| brought some breaking changes, which are reversible via customizing macros: \begin{itemize} \item Integers (when scientific notation is dropped according to criteria mentioned next) without a "\dtt{.0}" suffix. \item Same for the zero value, now "\dtt{\xintPFloat{0}}". \item Significands are trimmed of trailing zeros only if that removes at least \dtt{4} zeros. The rationale is that automatic removal of trailing zeros (which was influenced at |1.4e| from practice with Python in interactive mode) proves annoying visually with aligned values in tables, as this creates voids, so we want to do this only when really the presence of trailing zeros is not some kind of numerical fluke. \end{itemize} These changes impact the \csbxint{floateval} output as \csbxint{floatexprPrintOne} defaults to using \csbxint{PFloat}. \begin{framed} In\IMPORTANTf\ this documentation ``trailing zeros'' refers not to how the input looked like, but to the corresponding mantissa of width |P| or \csbxint{theDigits}. \end{framed} The default rules are thus now: \begin{enumerate}[nolistsep] \item The input is float-rounded to either |Digits| or the optional argument. \item zero is printed as \dtt{\xintPFloat{0}}. \item \dtt{x.yz...eN} is printed in decimal fixed point if $-4\leq\text{|N|}\leq+5$ else it is printed in scientific notation. \item Trailing zeros of the mantissa are trimmed if, and only if there are at least \dtt{4} of them. \item In case of fixed point output format, and the value is an integer, the integer is printed with no decimal mark. \item In case of scientific notation output format, and the mantissa has only one digit, no decimal mark is used. \end{enumerate} % The old rules were: % \begin{enumerate}[nosep] % \item The input is float-rounded to either |Digits| or the optional argument, % \item zero is printed as \dtt{0.}, % \item \dtt{x.yz...eN} is printed ``as is'' if the exponent |N| is at least % \dtt{6} or at most \dtt{-6}, % \item else fixed point decimal notation is used, % \item and there is no trimming of trailing zeroes. % \end{enumerate} \begingroup\color{everbatimxfgcolor} \begin{multicols}2 \def\test #1{\item #1${}\to{}$\xintPFloat{#1}}% \string\xintDigits\ at \xinttheDigits \begin{itemize}[nosep,font=\normalcolor] \test {0} \test {1.2340000e-7}\test {1.2340000e-6}\test {1.2340000e-5}\test {1.2340000e-4} \test {1.2340000e-3}\test {1.2340000e-2}\test {1.2340000e-1} \test {1.2340000e0}\test {1.2340000e1}\test {1.2340000e2}\test {1.2340000e3} \test {1.2340000e4}\test {1.2340000e5}\test {1.2340000e6}\test {1.2340000e7} \test {1e-7/7}\test {1e-6/7}\test {1e-5/7}\test {1e-4/7} \test {1e-3/7}\test {1e-2/7}\test {1e-1/7} \test {1e0/7}\test {1e1/7}\test {1e2/7}\test {1e3/7} \test {1e4/7}\test {1e5/7}\test {1e6/7}\test {1e7/7} \end{itemize} \end{multicols} \endgroup \subsubsection{Customizing macros of \csh{xintPFloat}} \label{xintPFloatE} \label{xintPFloatZero} \label{xintPFloatIntSuffix} \label{xintPFloatLengthOneSuffix} \label{xintPFloatNoSciEmin} \label{xintPFloatNoSciEmax} \label{xintPFloatMinTrimmed} A number of macros allow to customize the behaviour of \csbxint{PFloat}: \begin{itemize} \item \csa{xintPFloatE} allows to modify the separator of the scientific notation. Here is its default: % \footnote{For \TeX perts: it is allowed to define \csa{xintPFloatE} as a macro which grabs the exponent as an argument delimited by a dot, and produces \fexpan dably an output also delimited by a dot (it will removed via further internal processing).} % \begin{everbatim} \def\xintPFloatE{e} \end{everbatim} \item \csa{xintPFloatZero} says how to print the zero value. The default: \begin{everbatim} \def\xintPFloatZero{0} \end{everbatim} \item \csa{xintPFloatIntSuffix} is postfixed to integer values (when scientific notation is not used). Its default at |1.4k| is to add nothing. It replaces the formerly hard-coded "\dtt{.0}" from |1.4e| (prior to that trailing zeros from the full significand of |P| or \csbxint{theDigits} digits were not trimmed). \begin{everbatim} \def\xintPFloatIntSuffix{} \end{everbatim} \item \csa{xintPFloatLengthOneSuffix} is postfixed to trimmed mantissas having only one digit, when scientific notation is used. Its default at |1.4k| is to add nothing. It replaces formerly hard-coded "\dtt{.0}". \begin{everbatim} \def\xintPFloatLengthOneSuffix{} \end{everbatim} \item \csa{xintPFloatNoSciEmax} is the maximal scientific exponent which will trigger use of decimal fixed point notation and \csa{xintPFloatNoSciEmin} is the minimal one. Their defaults at |1.4k| are the same as the formerly hard-coded behaviour from |1.4e|: \begin{everbatim} \def\xintPFloatNoSciEmax{5} \def\xintPFloatNoSciEmin{-4} \end{everbatim} For example (with the package default width of \dtt{16} digits for mantissas of floating point numbers): \begin{everbatim*} \begingroup \def\xintPFloatNoSciEmin{-20} \xintPFloat{1e-19/7}\newline \xintPFloat{1e-20/7}\par \def\xintPFloatNoSciEmax{19} \xintPFloat{1e20/7}\newline \xintPFloat{1e21/7}\par \endgroup \end{everbatim*} \item \csa{xintPFloatMinTrimmed} is the minimal number of trailing zeros which have to be present to activate actual trimming. The default definition is: \begin{everbatim} \def\xintPFloatMinTrimmed{4} \end{everbatim} Defining it to expand to \dtt{-1} or \dtt{0} will enable the trimming of trailing zeros always, and setting it to a value at least equal to |P| (or \csbxint{theDigits} if no |[P]|) will prevent it altogether. This setting is ignored for the case of an integer value, if the criteria for using fixed point notation are met, and for the case of a one-digit mantissa in scientific notation. \end{itemize} To mimick approximately the Python behaviour in interactive sessions, one can use the following configuration: \begin{everbatim} \def\xintPFloatZero{0.0}% \def\xintPFloatIntSuffix{.0}% \def\xintPFloatLengthOneSuffix{.0}% \def\xintPFloatNoSciEmax{15}% \def\xintPFloatNoSciEmin{-4}% \def\xintPFloatMinTrimmed{-1}% \end{everbatim} \begingroup\color{everbatimxfgcolor} \def\xintPFloatZero{0.0}% \def\xintPFloatIntSuffix{.0}% \def\xintPFloatLengthOneSuffix{.0}% \def\xintPFloatNoSciEmax{15}% \def\xintPFloatNoSciEmin{-4}% \def\xintPFloatMinTrimmed{-1}% \def\test#1{#1${}\to{}$\xintPFloat{#1}\newline}% \test{0.} \test{1234.} \test{6e100} \test{1234567812345678.12345678} \test{12345678123456781.2345678} \test{12345678.12340} \test{12345678.123400} \test{0.1234567812345678} \test{0.00012345678123456785} \test{0.000012345678123456785}\par \endgroup % The above using the default \csbxint{Digits} setting of \dtt{16} digits. This can not naturally match exactly CPython which uses internally radix |2| not |10|, and has (by default) mantissas with \dtt{53=1+52} bits. Same, but playing with \ctanpackage{xintsession} in its |&fp| mode: \begin{everbatim} >>> &fp fp mode (16 digits) >>> \\def\xintPFloatZero{0.0} (executing \\def\xintPFloatZero {0.0} in background) ) Runaway argument? def\xintPFloatZero {0.0}\message { }\xs_fetch_aa \endinput ! File ended while scanning use of \\. <inserted text> \par <*> xintsession^^M ? S OK, entering \scrollmode... *\xintsession You are back to the xintexpr interactive session! (current mode: fp (Digits=16), with Digits=16) ">>> " means central computing is waiting for input "... " means that multi-line input continues. Use `;' to terminate it. Say `&bye' at any time to terminate the session and the TeX run. >>> \def\xintPFloatZero{0.0} (executing \def \xintPFloatZero {0.0} in background) >>> \def\xintPFloatIntSuffix{.0}\def\xintPFloatLengthOneSuffix{.0} (executing \def \xintPFloatIntSuffix {.0}\def \xintPFloatLengthOneSuffix {.0} i n background) >>> \def\xintPFloatNoSciEmax{15}\def\xintPFloatNoSciEmin{-4} (executing \def \xintPFloatNoSciEmax {15}\def \xintPFloatNoSciEmin {-4} in back ground) >>> \def\xintPFloatMinTrimmed{-1} (executing \def \xintPFloatMinTrimmed {-1} in background) >>> 0., 1234., 6e100; @_1 0.0, 1234.0, 6.0e100 >>> 1234567812345678.12345678; @_2 1234567812345678.0 >>> 12345678123456781.2345678; @_3 1.234567812345678e16 >>> 12345678.12340; @_4 12345678.1234 >>> 12345678.123400; @_5 12345678.1234 >>> 0.1234567812345678; @_6 0.1234567812345678 >>> 0.00012345678123456785; @_7 0.0001234567812345679 >>> 0.000012345678123456785; @_8 1.234567812345679e-5 >>> &bye \end{everbatim} This is with version |0.4alpha (2021-11-01)| of \ctanpackage{xintsession}. Probably some ``magic'' shortcuts will be added in future to its interface for this kind of tasks, in place of the |\def|. % \subsection{\csh{xintFloatE}}\label{xintFloatE} % %! {\small New with |1.097|.} % |\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*} % There is since |1.4b| an unfortunate proximity in name with \csbxint{PFloatE} % despite the two things having absolutely nothing in common. \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 will be truncated to an 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)|. \emph{For integer exponents} this is the support macro which is used for the |^| (or |**|) infix operators in \csbxint{floateval}, or also in \csbxint{eval} for very big integer exponents. It is also used in \csbxint{floateval} and \csbxint{eval} for half-integer exponents, via a combination with the \csbxint{FloatSqrt} square-root extraction. The macro itself was \emph{NOT} modified at |1.4e|: when used directly it still starts by truncating the exponent to an integer... As for other user-level floating-point macros, its output is handled by \csbxint{Float}, i.e. it uses scientific notation. The |0.52 ulp(Z)| guaranteed error bound applies also to the \csbxint{floateval} evaluations for the half-integer exponent case. It is valid only when |f| already had a mantissa of at most |P| digits and was not modified by the initial rounding done by the macro to reduce |f| to |P| digits. The integer exponent |g| may have more than |P| (or |Digits|) digits, it is handled exactly. And as said above its absolute value may exceed the \TeX\ bound. % Notice that this is a bound on the distance from % |f'^g| to |Z|, where |f'| is the rounded value of the original input |f|; % 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\relax \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\relax \np{\xintthefloatexpr (1+1e-8)^\xintiiexpr 12^16\relax\relax}}\newline % \np{\xintthefloatexpr (1+1e-8)^\xintiiexpr 12^16\relax\relax}\newline % {\xintDigits:=27\relax \np{\xintthefloatexpr (1+1e-8)^12^16\relax}}\newline % {\xintDigits:=48\relax \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{\text{|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\relax \clearpage \let\xintfracnameUp\undefined \csname xintbinhexnameUp\endcsname \def\n{|{N}|} \def\m{|{M}|} \def\x{|{x}|} \section{Macros of the \xintbinhexname package} \RaisedLabel{sec:binhex} 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. \localtableofcontents \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|. This zero-fills to 4N digits the input, hence gives here a leading zero in output: \begin{everbatim*} \xintBinToHex{0001111}\par \end{everbatim*} Chaining, we end up with 4N-3 digits, as three binary zeroes are trimmed: \begin{everbatim*} \xintHexToBin{\xintBinToHex{0001111}}\par \end{everbatim*} But this will always reproduce the initial input zero-filled to length 4N: \begin{everbatim*} \xintCHexToBin{\xintBinToHex{0001111}}\par \end{everbatim*} 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 \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} This package was included in the original release |1.0| (|2013/03/28|) of the \xintname bundle. At |1.3d| macros \csbxint{iiGCD} and \csbxint{iiLCM} are copied over to \xintname, hence \func{gcd} and \func{lcm} functions in \csbxint{iiexpr} were available simply from loading only \xintexprname, and the \xintgcdname dependency got removed. \begin{framed} From |1.1| to |1.3f| the package loaded only \xintcorename, not \xintname and neither \xinttoolsname. But at |1.4| it loads automatically both \xintname and \xinttoolsname (the latter being a requirement since |1.09h| of the \csbxint{TypesetEuclideAlgorithm} and \csbxint{TypesetBezoutAlgorithm} macros). The macros \csbxint{iiGCD} and \csbxint{iiLCM} got relocated into \xintname. \IMPORTANTf The macros \csbxint{GCD}, \csbxint{LCM}, \csbxint{GCDof}, and \csbxint{LCMof} are \emph{removed}: \xintfracname provides under these names more powerful macros handling general fractions and not only integers. \end{framed} \localtableofcontents \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. \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. \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} 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 \localtableofcontents \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} = \xintTeXFrac\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|: \[\xintTeXFrac\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}=\xintTeXFrac\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= \xintTeXFrac\z=\xintTeXFrac{\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=\xintTeXFrac{\z}=\xintTeXFrac{\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 \text{|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 =\xintTeXFrac{\xintIrr{\xintPowerSeries {0}{20}{\geom}{\f}}} =\xintTeXFrac{\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} = \xintTeXFrac {\xintIrr {\xintPowerSeries {1}{20}{\coefflog}{\f}}}\] \[ \log 2 \approx \sum_{n=1}^{50} \frac1{n\cdot 2^n} = \xintTeXFrac {\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} = \xintTeXFrac{\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 \text{|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 \edef\foo{\the\multicolsep} \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} \multicolsep\foo\relax \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\xintTeXFrac{\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{\text{|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 $\text{|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 \text{|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\relax|, 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{https://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} 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}.) \localtableofcontents % 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 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*} \[ \xintTeXFrac {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*} \[ \xintTeXFrac {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*} \[\xintTeXFrac {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*} \[ \xintTeXFrac{\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*} \[\xintTeXFrac{\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\xintTeXFrac{\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*} \[\xintTeXFrac{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*} \[\xintTeXFrac{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{|$$\xintTeXOver{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{$\xintTeXFrac{#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*} \[\xintTeXFrac{915286/188421}\to \xintListWithSep{,}{\xintApply\xintTeXFrac{\xintFtoCv{915286/188421}}}\] \end{everbatim*} \begin{everbatim*} \[\xintTeXFrac{915286/188421}\to \xintListWithSep{,}{\xintApply\xintTeXFrac{\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]{$\xintTeXFrac{#1}=[\xintFtoCs{#1}]$\vtop to 6pt{}}|} % Next, we use the following code: % \leftedline{|$\xintTeXFrac{49171/18089}\to{}$|} % \leftedline{|\xintListWithSep {, }{\xintApply{\mymacro}{\xintFtoCv{49171/18089}}}|} It produces:\par \noindent$ \xintTeXFrac{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 \[\xintTeXFrac{\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}}% \[\xintTeXFrac{\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 }% \[\xintTeXFrac{\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*} \[\xintTeXFrac{\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{\xintTeXFrac} {\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. 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 trigger 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{TeXFrac} 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\xintTeXOver}{\\\xintTeXOver}{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*} \[ \xintTeXsignedFrac{-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*} \[\xintTeXFrac{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}= \xintTeXsignedFrac{\xintCstoF {-1,3,-5,7,-9,11,-13}}=\xintTeXsignedFrac{\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}}= \xintTeXFrac{\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*} \[ \xintTeXFrac{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}} = \xintTeXFrac{\xintGCtoF {1+\xintPow{1.5}{3}/{1/7}+{-3/5}/\xintiiFac {6}}} = \xintTeXFrac{\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}} = \xintTeXFrac{\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\xintTeXFrac{\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\xintTeXFrac {\xintGCtoCv{3+{-2}/{7/2}+{3/4}/12+{-56}/3}}}\] \[\xintListWithSep{,}{\xintApply\xintTeXFrac{\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\xintTeXFrac{\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\xintTeXFrac{\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}} = \xintTeXFrac{\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*} \[ \xintTeXFrac{\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\xintTeXFrac {\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}}=\xintTeXsignedFrac{\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= \xintTeXFrac{\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$. \ifnum\NoSourceCode=1 \clearpage \def\xintRunningHeader{{\inheadertrue\catcode`,12\relax \DOCxintfrontpage, \DOCxintexprintro, \csname xint bundlename\endcsname}} \part{The \xintexprname and allied packages source code (not included, see \textcolor{verbcolor}{\texttt{sourcexint.pdf}})} \markboth{\makebox[0pt]{\xintRunningHeader}}{\makebox[0pt]{\xintRunningHeader}} \vspace{1cm} \begin{framed} %\small % not now that there is the Part which is rather large This documentation has been compiled without including the commented source code, which is available in the separate file |sourcexint.pdf|, and will open in a PDF viewer via: % \centeredline{|texdoc sourcexint.pdf|} To produce a file |xint.pdf| including both the user documentation and the source code: \begin{itemize} \item acquire |xint.dtx| from \centeredline{\url{https://www.ctan.org/tex-archive/macros/generic/xint}} \item execute |latex xint.dtx| sufficiently many times (at least three), then |dvipdfmx|, or use |pdflatex|. \end{itemize} For those on Unix-like systems, you can (recommended) alternatively also download a file |Makefile| from the above location then execute |make xint-all.pdf|. This requires |latexmk| and will do automatically the needed number of passes. Without the |Makefile| one can first execute |etex| on |xint.dtx| to extract files then run \centeredline{|make --file=Makefile.mk xint-all.pdf|} Other |make| targets include |xint.pdf| (without implementation part) and |sourcexint.pdf|. Run |make help| for help. Further build alternatives are explained in extracted file |xint-all.tex|. The file\NewWithf{1.4m} with both user manual and implementation (i.e. either |xint.pdf| from direct runs of |(pdf)latex| on |xint.dtx| or |xint-all.pdf| if using |make|) will contain hyperlinks from the user documentation to the implementation part and back. And the macros inside the code lines are hyperlinked to the location of their definition. \end{framed} \fi \clearpage \let\xintcfracnameUp\undefined \ifnum\dosourcexint=1 +fi +catcode`\ 0 \catcode0 15 % retour à la normale, peu importe \catcode`\+ 12 \makeatletter \@gobble\fi \StopEventually{\end{document}\endinput} \makeatletter \let\csh\cshnolabel % \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 !!! \AddToHook{env/macrocode/before}{\par@beforemacrocode} \def\par@beforemacrocode{\par} % for \csbxint etc... \let\xintlabelprefix\xintimplabelprefix \def\xintdocMacrocodeFallbackColorCmd{\normalcolor} \def\xintdocPrivateColorCmd{\color{privatecommentcolor}}% \def\xintdocPublicColorCmd{\normalcolor} % stuff going to .toc file (and hence possibly impacting all TOCs regarding the looks % of titles originating in the implementation part) \etocdepthtag.toc {implementation} \addtocontents{toc}{\gdef\string\tocstylesectionbracedcolor{{tocstylesectionimpcolor}}} % reset/set TOC parameters which may have been altered for typesetting the manual % as we aim to get same layout in sourcexint.pdf and xint-all.pdf. But I have % not tried to compensate the difference coming from on one hand \maketitle % and on the other hand \part. I am not *that* of a maniac. % ...hmm finally yes I am a maniac and I used minipages... \etocignoredepthtags \etocsettocstyle {}{} \inmanualmaintocfalse % already the case anyhow \let\etocaftertochook\empty \etocsetnexttocdepth{section} % make room for some small text on TOC page under the TOC \def\tocstylesectionVSKIP{\vskip\medskipamount} \ifnum\dosourcexint=1 % sourcexint.pdf \medskip \tableofcontents \else \ifnum\NoSourceCode=0 % xint-all.pdf % reset those two which are used by multicol style (perhaps unneeded) \let\etocbelowtocskip \orig@etocbelowtocskip \let\etocinnertopsep \orig@etocinnertopsep % this one needs to be reset as it is modified for the TOCs of the user % manual. This way TOCs of Part III will be in xint-all.pdf as in % sourcexint.pdf \let\etoctoclineleaders\orig@etoctoclineleaders \fi \bookmark[dest=imp,level=part]{Implementation} \begin{minipage}[t][8\baselineskip][c]{\linewidth} \RaisedTarget{imp} \part{The \xintexprnameimp and allied packages source code} \RaisedLabel[15]{partiii} \end{minipage} % ne fonctionn pas ici % \RaisedLabel[15]{partiii} % \smash n'est pas \long... mais \smash<space> l'est mais \makesm@sh ne l'est pas % bon de tout façon plus de \par ici % \protected à cause du \smash sinon % ! TeX capacity exceeded, sorry [input stack size=10000]. % <inserted text> % \protect \foreignlanguage {english}{\protect \bbl@restore@ac... % l.97 ...er}}{\makebox[0pt]{\xintImpRunningHeader}} % Not using \hypersetup with linkcolor because a few pages are with % a TOC à cheval on two pages, and my eTOCs are configured to do % \hypersetup{hidelinks} \protected\def\DOCxintfrontpage {\smash{\vbox{\hbox{\perhapshyperref[frontpage]{{\color{xintnamecolor}TOC}}}% \kern1ex \hbox{\perhapshyperref[partiii]{{\color{xintnameimpcolor}TOC}}}}}}% \medskip \localtableofcontents \fi \medskip \etocsettocdepth{subsubsection}% 2015/09/15 % this is a parameter of the custom tocstyling for sections which we % set to this value only after having typeset the main TOC of sourcexint.pdf % or TOC of Part III of xint-all.pdf \def\tocstyleMARGEPAGENO{1.25em} % modify the page headers \def\xintImpRunningHeader{{\inheadertrue\catcode`,12\relax \DOCxintfrontpage, \xintkernelnameimp, \xinttoolsnameimp, \xintcorenameimp, \xintnameimp, \xintbinhexnameimp, \xintgcdnameimp, \xintfracnameimp, \xintseriesnameimp, \xintcfracnameimp, \xintexprnameimp, \xinttrignameimp, \xintlognameimp}} \markboth{\makebox[0pt]{\xintImpRunningHeader}}{\makebox[0pt]{\xintImpRunningHeader}} \def\etocaftertochook{\addvspace{\bigskipamount}} \section{An introduction and a brief timeline} This is \expandafter|\xintbndlversion| of \expandafter|\xintbndldate|. The |CHANGES.html| contains a detailed history of the evolution of the packages: \centeredline{Internet: \url{http://mirrors.ctan.org/macros/generic/xint/CHANGES.html}} \edef\foo{\columnsep\the\columnsep} \columnsep5\fontcharwd\font`X\relax \begin{multicols}{2}\small\raggedcolumns\columnsep9\fontcharwd\font`X\relax At |1.4m| I added hyperlinks to the macro code. Each instance of a macro in the code is linked with target the location of its definition (via |\def| or |\let| or variants). This has been done via a heist on \ctanpackage{doc} (|v2| version) automated indexing which has been transformed here into automated hyperlinking. The details are commented upon in the next section. Furthermore the codeline where the macro is defined will link to its description in the user manual, if available, inside |xint-all.pdf| which combines user manual and source code. In |sourcexint.pdf| the link is more modestly targeting the sectioning heading referencing the macro name, if available. Again in |xint-all.pdf| the macros documented in the user manual have a link \emph{source} to their source code. The sad truth however is that my code is poorly documented. On two counts: \begin{itemize}[nosep] \item scarcity at times, \item occasional excessive verbosity, \item generally inadequate or irrelevant contents. \end{itemize} The macro comments have had a distinct tendency to record the changes across releases or even those occurring during pre-release development phase, rather than explaining the interface, or perhaps an algorithm. As I am aware of that, I have a mechanism of \myenquote{private comments} which are removed by the |dtx| build script. But then I sometimes use it en masse as it would be too much work to clean-up the existing comments, and as a result the code is not commented at all anymore... A typical example is with \csbxint{iiSquareRoot} which is amply documented in the private sources but only 10\% of it could be of any value to any other reader than myself and it would be simply the description of what |#1|, |#2|, ... stand for. As a result I converted at some point (perhaps even originally) everything into private comments. Extracting the useful parts describing the macro parameters and checking they are actually still valid would be very time-consuming. The real problem here is that the actual underlying algorithms are rarely if ever described. But rest assured this is all only school mathematics anyway. \end{multicols} \foo %\normalsize \begin{itemize} \item Release |1.4m| of |2022/06/09| is mainly a documentation upgrade, with proud hyperlinked macros in the code, and various documentation enhancements. It is also fixing a longstanding incompatibility with \ctanpackage{miniltx} of which the author was unaware. It also inaugurates usage of the engine string comparison primitive. \item Release |1.4i| of |2021/06/11|: extension of the «simultaneous assignments» concept (backwards compatible). \item Release |1.4g| of |2021/05/25|: powers are now parsed in a right associative way. Removal of the single-character operators |&|, \verb=|=, and |=| (deprecated at |1.1|). Reformatted expandable error messages. \item Release |1.4e| of |2021/05/05|: logarithms and exponentials up to 62 digits, trigonometry still mainly done at high level but with guard digits so all digits up to the last one included can be trusted for faithful rounding and high probability of correct rounding. \item Release |1.4| of |2020/01/31|: \xintexprnameimp overhaul to use |\expanded| based expansion control. Many new features, in particular support for input and output of nested structures. Breaking changes, main ones being the (provisory) drop of |x*[a, b,...]|, |x+[a, b,...]| et al.\@ syntax and the requirement of |\expanded| primitive (currently required only by \xintexprnameimp). \item Release |1.3e| of |2019/04/05|: packages \xinttrignameimp, \xintlognameimp; \csa{xintdefefunc} ``non-protected'' variant of \csbxint{deffunc} (at |1.4| the two got merged and \csa{xintdefefunc} became a deprecated alias for \csbxint{deffunc}). Indices removed from |sourcexint.pdf|. % 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. \item Release |1.3d| of |2019/01/06|: fix 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, indices added to |sourcexint.pdf|. 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|: fix of |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. \item Release |1.09g| of |2013/11/22|: the \xinttoolsnameimp package is extracted from \xintnameimp; addition of \csbxint{loop} and \csbxint{iloop}. \item Release |1.09c| of |2013/10/09|: \csbxint{For}, \csa{xintNewNumExpr} (ancestor of \csbxint{NewExpr}/\csbxint{deffunc} mechanism). \item Release |1.09a| of |2013/09/24|: support for functions by \xintexprnameimp. \item Release |1.08| of |2013/06/07|: the \xintbinhexnameimp package. \item Release |1.07| of |2013/05/25|: support for floating point numbers added to \xintfracnameimp and first release of the \xintexprnameimp package (provided \csbxint{expr} and \csbxint{floatexpr}). \item Release |1.04| of |2013/04/25|: the \xintcfracnameimp package. \item Release |1.03| of |2013/04/14|: the \xintfracnameimp and \xintseriesnameimp packages. \item Release |1.0| of |2013/03/28|: initial release of the \xintnameimp and \xintgcdnameimp packages. \end{itemize} %\clearpage \section{Custom macrocode environment} I have always used the monospaced \ctanpackage{newtxtt} typeface, more precisely its |newtxttz| variant with variable interword spacing and allowed hyphenation, both for the user manual and for the code comments. But as the code itself is also rendered with |newtxtt|, naturally using this time the monospace typeface preventing hyphenation, and with a verbatim rendering obeying spaces and linebreaks, it is somewhat of an issue to help better separate visually the comments from the code. I long used a special color (\textcolor{Purple}{which was Purple for a long time}), not for all code comments but for those which in the source were inside a custom verbatim environment% % \footnote{I used to employ a Plain \TeX\ mark-up with a macro |\lverb| (meaning \myenquote{long |\verb|}), but I converted this into an environment at the time of adding the hacks described next.} % which allows free-flowing of horizontal whitespace and soft-wrapping at linebreaks.% % \footnote{Some special mark-up at starts of lines such as \expandafter|\@percentchar(| and \expandafter|\@percentchar)| serves to delimit portions where whitespace is obeyed as in regular verbatim.} % Using this verbatim rendering spared me the tedious task of escaping macros or other special characters inside my code comments. But other paragraphs of code comments% % \footnote{I do employ the standard |dtx| mark-up for such code comments, i.e. with these comments on lines with a \expandafter|\@percentchar| as their first character; but the part of |xint.dtx| giving the user manual is a regular \LaTeX\ document, as this is easier to manage on the long term. Also the present comments are input as if in a regular \LaTeX\ document.} % were typed-in as normal \LaTeX-markup with occasional usage of the \verb+|+ escape for short verbatim and some custom |\cs|-type macros enhanced for hyperlinks. So I ended up in a situation with some paragraphs of code comments all uniformly colorized (apart from rare hyperlinks allowed by an escape inside) and others in black containing some colored short verbatim and some hyperlinks. To try to alleviate this I modified my custom verbatim to work with an active backslash character |\| in order to gather the control sequence name, check if it corresponds to a labeled reference in the implementation if yes insert the usage of |\hyperref| to link to it. Those familiar with |doc.sty| will have recognized immediately that it too activates the |\| in order to insert suitable indexing commands.% % \footnote{The |sourcexint.pdf| documentation included automated indices thanks to by \ctanpackage{doc}, but only during 2018-2019. I felt the indices made the build process quite longer, produced very big PDFs and, in view of the capabilities of the modern \textcolor{verbcolor}{PDF} viewers had a limited interest in the case at hand. Besides, they were some limitations such as requiring user intervention for macros created via |\csname| constructs. This limitation can not be overcome easily, especially when furthermore, as in \xintexprnameimp, this is done sometimes via loops applying some templates, as it would seem for that one has to emulate \TeX{} itself. This limitation applies naturally also to the hacks described in this section!} I had actually never really looked into |doc.sty| code, but I started wondering if one could not indeed divert its indexing facility into an automated generation of hyperlinks: i.e. hyperlinking from macro names to the line where they are first defined.% % \footnote{The recently released |V3| of \ctanpackage{doc} is about hyperlinking, I have to check better its documentation but I don't think it creates hyperlinks from code lines to code lines as we will do here.} In this section I will display and comment the hacks I have done to convert the |doc.sty| macros into achieving automatic hyperlinking inside the code lines, from the places of use of a macro to the place of its definition, and from the place of its definition to the user documentation (if building |xint-all.pdf|), if available. Using the colored links of \ctanpackage{hyperref} this already provides a kind of minimal syntax highlighting to the code lines, which we will enhance via colorizing the inline comments (i.e. \textcolor{macrocodecommentcolor}{everything following a \@percentchar{} in the source code}), and also colorizing \textcolor{macrocodenoncscolor}{the tokens not involved in control sequence names}. Horrified readers will see I have completely botchered not only the indexing facilities but also this business of \myenquote{modules} which is in a part of \ctanpackage{doc}umentation I haven't read yet. And, now that you are appalled enough let's admit that the |sourcexint.pdf| documentation never has made any usage of the |macro| and |environment| environments from |doc.sty|, so I have not even tested if they survive the mistreatment here.% % \footnote{Of course I did use those facilities for some of my \LaTeX\ packages... but for \textcolor{verbcolor}{sourceint.pdf} I have always used the \LaTeX\ sectioning commands rather. With a hack which will be described at the end of this section to introduce suitable hyperlink targets for those names entered into the comma separated section titles.} \begin{everbatim*} % \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. % doc.sty does \AtBeginDocument{\let\macro@font\MacroFont} and formerly I % overwrote \macro@font to use a newtxtt font with a slashed 0 in the % implementation part. % 2022/05/17 removes this, but I still need to redefine \macro@font to remove some % stuff I formerly added to \MacroFont and which is only useful for the user manual. \def\macro@font {\ttfamily } \end{everbatim*} The |\makestarlowast| makes the \textcolor{verbcolor}{*} active to be lowered like this |*|. Formerly I hacked |\macrocode| or used |\macro@font| (which comes before |\dospecials| in |\macro@code| but the |*| is not a special character) but it seems now cleaner to use the \LaTeX\ environment hooks. \begin{everbatim*} % no problem as * is not "special" so the active catcode will not be reset \AddToHook{env/macrocode/begin}{\makestarlowast} \end{everbatim*} Let's continue benefiting from modern hooks to work around vertical spacing issues \centeredline{\url{https://github.com/latex3/latex2e/issues/563}} % Updated 2021/05/24 to work-around macrocode bug % https://github.com/latex3/latex2e/issues/563 % which shows when I have some \subsection directly % followed by macrocode, then next time there is some actual % text the spacing to next macrocode block will be wrong. \begin{everbatim*} \AddToHook{env/macrocode/after}{\@nobreakfalse} \end{everbatim*} % I suspect the \par\medskip which was in \lverb code % below was a poorman workaround, dating back to 2014 % or earlier. % % macrocode has another strange problem which is % that it reacts differently if one leaves a "blank line" % above it in the comments, or use there \par. I consider % this to be another bug of macrocode (which is inherited % from the usage of the \trivlist mechanism). % The presence of \par will add \partopsep space. % \setlength{\partopsep}{0pt} \begin{everbatim*} \AddToHook{env/macrocode/begin}{\partopsep0pt\relax} \end{everbatim*} As explained above I make the \% active in order to colorize comments so here I do need to overwrite the core delimited macro |\xmacro@code|. \begin{everbatim*} \begingroup \catcode`\|=\z@ \catcode`\[=\@ne \catcode`\]=\tw@ \catcode`\{=12 \catcode`\}=12 % Let % be active to use a color for it and gray-out % comments left in code (there are few) \catcode`\%=13 \catcode`\ =\active \catcode`\\=\active |gdef|xmacro@code#1% \end{macrocode}[#1|end[macrocode]] |endgroup \end{everbatim*} I will give a document wide definition to the active \%, other places where I need an active \% like my |lverb| environment use |\let| at the appropriate time to give it another meaning. The redefinition makes it change the color, and for this it opens a scope limiting group, which gets closed via the active end of line, suitably locally altered. \begin{everbatim*} \begingroup\catcode`\%=\active\catcode`\^^M 13 \gdef%{\begingroup\color{macrocodecommentcolor}\@percentchar\odef {\expandafter\endgroup }}\endgroup \end{everbatim*} The |\odef| in the above code is an \xintkernelnameimp utility. \begin{everbatim*} \texttt{\meaning\odef} \end{everbatim*} Let's mention already that there better should not be a |\def\foo| in a comment as no mechanism has been added here to prevent the macrocode to believe this is an actual definition (whose detection method is described below). For hyperlinking I turn |CodelineNo| into a regular \LaTeX\ counter. The next few lines were actually executed right after having loaded |doc v2|: \begin{everbatim} % First we want to turn CodelineNo into a real LaTeX counter % This will spare defining an extra counter for the hyperlinks with \hyperref \begingroup\let\newcount\@gobble\@definecounter{CodelineNo}\endgroup % Let's now reenact the doc.sty default for \theCodeLineNo \def\theCodelineNo{\reset@font\scriptsize\arabic{CodelineNo}} % But as we will reset CodelineNo at each style file we need some unique id \def\theHCodelineNo{\the\value{section}.\the\value{CodelineNo}} \end{everbatim} % si on écrit "further" au lieu de "also", TeX induit une ligne vide après % celle donnant ce texte. À mon avis c'est un bug de comportement de TeX % que j'ai déjà rencontré plusieurs fois. The \xintnameimp packages use |@|, |:|, |?|, |^| and |_| as letters, and \xintexprnameimp also uses |!| as letter. \begin{everbatim*} \def\xintMakePrivateLetters{\catcode`: 11 \catcode`? 11 \catcode`@ 11 \catcode`^ 11 \catcode`_ 11 } \def\xintexprMakePrivateLetters{\xintMakePrivateLetters \catcode`! 11 } \let\MakePrivateLetters\xintMakePrivateLetters \end{everbatim*} The whole idea is to colorize things so we executed the following in the preamble after having loaded \ctanpackage{xcolor} in order to have all such settings in one place only. \begin{everbatim} \definecolor{xintnamecolor}{RGB}{228,57,0} \colorlet{verbcolor}{Maroon} % \colorlet{privatecommentcolor}{cyan} \colorlet{macrocodecommentcolor}{gray} \colorlet{macrocodenewmacrocolor}{verbcolor} \colorlet{macrocodelinktouserdoccolor}{xintnamecolor}% and bold face \colorlet{macrocodelinktosectioncolor}{DarkBlue}% and bold face \colorlet{macrocodelinktocodelinecolor}{DarkBlue} \colorlet{macrocodenoncscolor}{Green} \def\xintdocMacrocodeFallbackColorCmd{\normalcolor} \end{everbatim} Let's overwrite the |macrocode| |\everypar| and use for this |\init@crossref| as suitable hook. We need this to \begin{itemize}[nosep] \item make the \% active (after the |\macro@code| has done |\dospecials| already), in order to colorize the inline comments, \item reset the color, because we will place an overall |\color| command in a \myenquote{before} hook to colorize the non control sequence tokens, \item insert a suitable |\refstepcounter|. This would not be needed if using an |\hypertarget/\hyperlink| approach. \end{itemize} In passing we start the destruction of FM's work by not including the |\check@module| inside the |\everypar|. I had used it as an entry-point hook before actually deciding to overwrite the |\everypar| and remove |\check@module| altogether from it. \begin{everbatim*} \odef\init@crossref{\init@crossref% \everypar{\refstepcounter{CodelineNo}% \llap{{\xintdocMacrocodeFallbackColorCmd\theCodelineNo}\ \hskip\@totalleftmargin}% }% \catcode`\%\active }% \end{everbatim*} In the environment the backslash is active and is given the meaning of |\scan@macro|. Let's modify this meaning \begin{itemize}[nosep] \item to not insert itself yet, \item and to prepare for collecting not only a name but also spaces (for reasons explained below). \end{itemize} \begin{everbatim*} \def\scan@macro{% % we do not insert it yet % \special@escape@char \step@checksum % \ifscan@allowed \let\macro@namepart\@empty % we need this for reasons explained below \let\macro@spacepart\@empty \def\next{\futurelet\next\macro@switch}% % \else \let\next\@empty \fi \next } % unchanged: % \def\macro@switch{\ifcat\noexpand\next a% % \let\next\macro@name % \else \let\next\short@macro \fi % \next} \end{everbatim*} We do not bother with \myenquote{short} control sequences: \begin{everbatim*} \def\short@macro#1{\special@escape@char#1} \end{everbatim*} The |\macro@name| is not modified but |\more@macroname| gets overwritten: \begin{everbatim*} % \def\macro@name#1{\edef\macro@namepart{\macro@namepart#1}% % \futurelet\next\more@macroname} % \def\more@macroname{\ifcat\noexpand\next a% % \let\next\macro@name % \else \let\next\macro@finish \fi % \next} \def\more@macroname{\ifcat\noexpand\next a% \expandafter\macro@name % we keep the \next for usage later and start filtering out of the way spaces % this is caused by necessity of handling things such as \let<space>\foo\bar % but also not be fooled by \let<space>#6\macro \else \expandafter\macro@gatherspaces \fi } \end{everbatim*} Now a simple |\futurelet| loop will gather consecutive active spaces which may separate a |\def| or |\let| from the control sequence which is getting defined in the source code: \begin{everbatim*} \def\macro@gatherspaces{% \ifx\next\@xobeysp \expandafter\macro@gatherspaces@i \else \expandafter\macro@finish \fi}% \def\macro@gatherspaces@i#1{% \odef\macro@spacepart{\macro@spacepart#1}% #1 = active space \futurelet\next\macro@gatherspaces}% \end{everbatim*} We need to collect those spaces in order to have a peek at what is coming next. Some code comments, but I am not going to comment my comments... \begin{everbatim} % We do not want \expandafter\def\csname to consider it defines \csname % We de no want \expanded{\edef\expandafter\noexpand\csname...} % to consider it defines \noexpand. We do not want this input % expandafter\def\expandafter#1\expandafter{\romannumeral % to consider it defines \expandafter or \romannumeral. % We do not want \ifdefined\odef\else to be interpreted as definition % of \else \end{everbatim} When we scan a |\def| or |\let| or... we toggle a boolean that says that what comes next will either insert a \LaTeX\ |\label| (and the counter |CodelineNo| is suitably |\refstepcounter|ed in |\everypar| to create an hypertarget), or an |\hyperref|. I also use a \LaTeX\ counter simply to be able to boast about the number of defined macros at the end of the |PDF|.% % \footnote{But I needed to make a manual estimate of a correction due to the many macros defined in \xintexprnameimp via |\csname| constructors. On June 6, 2022, I estimated there are at least about |452| of them and I since correct the macro counter with this addition at the end of source file for \xintexprnameimp.} % \begin{everbatim*} \newif\iflabelmacro@allowed \newcounter{xintMacroCnt} \def\xintimplabelprefix{src-} \let\xintdoclabelprefix\empty \let\xintlabelprefix\xintimplabelprefix \end{everbatim*} Now to the crux of the matter. The core of our hacks is in |\macro@finish|. We will need the |_| to be of catcode letter there. \begin{everbatim} \catcode`_ 11 % \def\macro@finish{% \iflabelmacro@allowed \end{everbatim} % Some control sequence names should never create hyperlinking. I hesitate about what to do with |\empty| and |\space|: \xintkernelnameimp does define them if they do not exist (which seems improbable) but we know what they are anyhow. Let's be careful here with how |\in@| works and add suitable delimiters to avoid sub-matches. \begin{everbatim} \expandafter\in@\expandafter{\expandafter.\macro@namepart,}% {.csname,.expandafter,.noexpand,.else,% .t,.w,.x,.y,.z,.XINT_x,.XINT_y,% .XINT_tmpa,.XINT_tmpb,.XINT_tmpc,.XINT_tmpd,.XINT_tmpe,% _ is letter here .XINT_expr_defbin_b,.XINT_expr_defbin_c,.XINT_expr_defbin_d,% .empty,.space,}% \end{everbatim} % If the thing is not excluded we check via a custom flag if we created already a |\label|, if not we create the |\label| and step the macro counter. In the latter case we will try to link to a target in the user manual (which may be available naturally only if we are creating |xint-all.pdf|) or to a label from a sectioning title in the implementation part. The latter situation is a bit silly because it will mean a link to a place perhaps only a few lines above the location of the macro definition but well. For some macros I wrote a very long incipit and then the link is useful as it jumps back to its start and allows to read the whole thing again in a never ending cycle. A link to the user documentation part will be colorized {\textbf{\textcolor{macrocodelinktouserdoccolor}{\bslash likethis}}} whereas hyperlinking to the nearby section will look {\textbf{\textcolor{macrocodelinktosectioncolor}{\bslash likethat}}}. If no such target exists we use \textcolor{macrocodenewmacrocolor}{\bslash this\string_color} to highlight the new macro (it is currently the same highlighting as for |\verb| usage in the code comments). It is then not a link but a target only. Finally, things excluded from the mechanism are rendered using a fall-back color, which currently is simply the color from {\xintdocMacrocodeFallbackColorCmd\string\normalcolor}, i.e. the black color. \begin{everbatim} \ifin@ {\xintdocMacrocodeFallbackColorCmd\special@escape@char\macro@namepart}% \else \ifcsname alreadydefined-\macro@namepart\endcsname \end{everbatim} Contrarily to |doc.sty| we have not yet typeset the |\| so we insert it via |\special@escape@char| (this makes me realize I have not yet checked if I use a special catcode zero character anywhere in the sources; I surely do in the sources for this documentation, but probably not for the actual packages). \begin{everbatim} \hyperref[xintmacro-\macro@namepart]{\special@escape@char\macro@namepart}% \else \end{everbatim} We rarely define things twice but it happens sometimes when a macro needs a space token. Unfortunately LaTeX's |\label| has no mechanism to tell if a label has already been used and if we issue a second |\label| with same name it will complain at some later stage. We can not use |CodelineNo| as how are we going then to refer to it? So we set up a flag to signal the |\label| has been created. \begin{everbatim} % this will make a rather large number of macro names in the string pool... \global\expandafter\let\csname alreadydefined-\macro@namepart\endcsname\@empty \label{xintmacro-\macro@namepart}% \end{everbatim} I considered a |\hypertarget/\hyperlink| method, but use finally |\label| and |\hyperref|. It is actually fun to see a gigantic |.aux| file allowing to get the information and to have the possibility to count again with |grep| for example. \begin{everbatim} \stepcounter{xintMacroCnt}% % try to link to a label in user documentation if building xint-all.pdf \ifcsname r@\xintdoclabelprefix\macro@namepart\endcsname {\hypersetup{linkcolor=macrocodelinktouserdoccolor}% \hyperref[\xintdoclabelprefix\macro@namepart]% {\textbf{\special@escape@char\macro@namepart}}}% \else % try to link to a labeled section in implementation part \ifcsname r@\xintimplabelprefix \macro@namepart\endcsname {\hypersetup{linkcolor=macrocodelinktosectioncolor}% \hyperref[\xintimplabelprefix\macro@namepart]% {\textbf{\special@escape@char\macro@namepart}}}% \else \textcolor{macrocodenewmacrocolor}{\special@escape@char\macro@namepart}% \fi\fi \fi \fi \end{everbatim} In all cases we now turn off the toggle for |\label| creation. Except if we were dealing with |\expandafter|, then we do keep it on. But only if what is coming next is a control sequence. \begin{everbatim} \labelmacro@allowedfalse \expandafter\in@\expandafter{\expandafter.\macro@namepart,}{.expandafter,}% \ifin@ \ifx\next\scan@macro\labelmacro@allowedtrue\fi \fi \else % end of \labelmacro@allowedtrue branch \end{everbatim} Now we return to the original |\macro@finish| code, with some check of the macro name to detect when it is |\def| or a cousin, and if it is we turn on the toggle to associate a |\label| or an |\hyperref| to the next control sequence. However we do this only if the next token is the catcode zero character. For this to work we have moved away the spaces beforehand. I hesitated about adding |\chardef| and |\mathchardef| but this would have the effect of adding hyperlinks for the |\xint_c_i| et al. constants, whose names are anyhow pretty much explicit. An end of line separating |\def| from the actual control sequence will cause the code to not activate the labelling process. \begin{everbatim} \ifx\next\scan@macro \expandafter\in@\expandafter{\expandafter.\macro@namepart,}% {.def,.edef,.let,.gdef,.xdef,.odef,.oodef,.fdef,}% \ifin@\labelmacro@allowedtrue\fi \fi \end{everbatim} If the reference exists, use it. The link will use color like in this example: \hyperref[xintmacro-xint\string_dothis]{\bslash xint\string_dothis}. In development, I had an alternative method not using |\label/\hyperref| but |\hypertarget/\hyperlink|. But here arose the question about how to know if a target existed (possibly located later in the source code). And it seems the answer would have been to use a mechanisme like the commented-out |\ifnot@exclude| below or the above |\in@| direct usages, but with a big list of all words we know will not have been associated with a target in the other branch. I.e. basically the \TeX\ primitives in the code, or also the constants |\xint_c_|\meta{roman numeral} which deliberately were not set-up to configure (as we did not handle |\chardef| or |\mathchardef| or |\newcount| to turn the toggle on. And if were to use a double-pass system via the |.aux| file, then what was the point. In view of this I opted for the |\label/\hyperref| even though it makes for very large |.aux| file and a lot of noise in the console output and in the log. \begin{everbatim} \ifcsname r@xintmacro-\macro@namepart\endcsname \hyperref[xintmacro-\macro@namepart]{\special@escape@char\macro@namepart}% \else {\xintdocMacrocodeFallbackColorCmd\special@escape@char\macro@namepart}% \fi \fi \end{everbatim} We do not use any index, but this could be reenacted. The |\short@macro| which then would needs to be resurrected as well. The |xint| source code contains no definition of such short (i.e.\@ one non-letter character following the backslash or escape character) macros anyhow. \begin{everbatim} % \ifnot@excluded % \edef\@tempa{\noexpand\SpecialIndex{\bslash\macro@namepart}}% % \@tempa % \fi \end{everbatim} And to conclude we now produce the fetched spaces. And after the |\scan@macro| definition we reset the catcode of |_| (this code is not part of the |xint*.sty| style files where the |_| anyhow is of catcode |letter|, but of the user documentation). \begin{everbatim} \macro@spacepart }% \catcode`_ 8 \end{everbatim} % I could not use everbatim* with pieces... so lets actually make the definition % now \catcode`_ 11 \def\macro@finish{% \iflabelmacro@allowed \expandafter\in@\expandafter{\expandafter.\macro@namepart,}% {.csname,.expandafter,.noexpand,.else,% .t,.w,.x,.y,.z,.XINT_x,.XINT_y,% .XINT_tmpa,.XINT_tmpb,.XINT_tmpc,.XINT_tmpd,.XINT_tmpe,% _ is letter here .XINT_expr_defbin_b,.XINT_expr_defbin_c,.XINT_expr_defbin_d,% .empty,.space,}% \ifin@ {\xintdocMacrocodeFallbackColorCmd\special@escape@char\macro@namepart}% \else \ifcsname alreadydefined-\macro@namepart\endcsname \hyperref[xintmacro-\macro@namepart]{\special@escape@char\macro@namepart}% \else % this will make a rather large number of macro names in the string pool... \global\expandafter\let\csname alreadydefined-\macro@namepart\endcsname\@empty \label{xintmacro-\macro@namepart}% \stepcounter{xintMacroCnt}% % try to link to a labeled reference in the user documentation (xint-all.pdf) \ifcsname r@\xintdoclabelprefix\macro@namepart\endcsname {\hypersetup{linkcolor=macrocodelinktouserdoccolor}% \hyperref[\xintdoclabelprefix\macro@namepart]% {\special@escape@char\macro@namepart}}% \else % try to link to a labeled section in implementation part \ifcsname r@\xintimplabelprefix\macro@namepart\endcsname {\hypersetup{linkcolor=macrocodelinktosectioncolor}% \hyperref[\xintimplabelprefix\macro@namepart]% {\textbf{\special@escape@char\macro@namepart}}}% \else \textcolor{macrocodenewmacrocolor}{\special@escape@char\macro@namepart}% \fi\fi \fi \fi \labelmacro@allowedfalse \expandafter\in@\expandafter{\expandafter.\macro@namepart,}{.expandafter,}% \ifin@ \ifx\next\scan@macro\labelmacro@allowedtrue\fi \fi \else % end of labelmacro@allowedtrue branch \ifx\next\scan@macro \expandafter\in@\expandafter{\expandafter.\macro@namepart,}% {.def,.edef,.let,.gdef,.xdef,.odef,.oodef,.fdef,}% \ifin@\labelmacro@allowedtrue\fi \fi \ifcsname r@xintmacro-\macro@namepart\endcsname \hyperref[xintmacro-\macro@namepart]{\special@escape@char\macro@namepart}% \else {\xintdocMacrocodeFallbackColorCmd\special@escape@char\macro@namepart}% \fi \fi % \ifnot@excluded % \edef\@tempa{\noexpand\SpecialIndex{\bslash\macro@namepart}}% % \@tempa % \fi \macro@spacepart }% \catcode`_ 8 There is one last topic. We want to colorize the tokens more in the macrocode. At some point before the hacks into |doc.sty| I had decided to issue one single top-level |\color| command at start of the implementation part in order to unify the looks of the two types of comments which were described at start of this section. So I needed to colorize the |macrocode| environments back to the black normal color. Now I need to colorize it to some color, knowing that control sequences will be rendered with their own individual colors, either {\xintdocMacrocodeFallbackColorCmd the normal color}, or the \textcolor{macrocodelinktocodelinecolor}{color for a link to a code line}, possibly the \textbf{\textcolor{macrocodelinktouserdoccolor}{color for a link to the user documentation}}, or the \textbf{\textcolor{macrocodelinktosectioncolor}{color for a link to a sectioning title in the implementation part}} (normally immediately a few lines above), or the \textcolor{macrocodenewmacrocolor}{color for being a target} (then it is not a link), and that comments have been configured \textcolor{macrocodecommentcolor}{to be rendered in their own color}. So what remains are \textcolor{macrocodenoncscolor}{the non commented out and non-control sequences token}. What is next is done in order to: \begin{enumerate}[noitemsep] \item not induce spacing changes in the output compared to no color commands \item not cause a color stack overflow from |\normalcolor| or a |\color| at top level with |dvipdfmx| (same problem in |xetex|). \end{enumerate} % I had encountered the color stack overflow with |dvipdfmx| (and |xetex| also) already many years ago for the |everbatim*| environment which is used in the user manual and in this section to display \TeX{} code and execute it. So I only needed to copy the method and find the correct hooks to use for the |macrocode|, turns out the good choices are |env/macrocode/before| to set the color and |env/macrocode/end| to unset it (not |after| which causes extra vertical spacing). \begin{everbatim*} {\sbox0{\color{macrocodenoncscolor}\xdef\foo{\current@color}}} \ifpdf \edef\xintdoc@macrocode@pushcolor {\pdfcolorstack\noexpand\@pdfcolorstack push{\foo}\relax} \def\xintdoc@macrocode@popcolor{\pdfcolorstack\@pdfcolorstack pop\relax} \else \ifxetex \edef\xintdoc@macrocode@pushcolor{\special{color push \foo}} \def\xintdoc@macrocode@popcolor{\special{color pop}} \else \ifnum\Withdvipdfmx=1 \edef\xintdoc@macrocode@pushcolor{\special{color push \foo}} \def\xintdoc@macrocode@popcolor{\special{color pop}} \fi\fi\fi \AddToHook{env/macrocode/before}{\xintdoc@macrocode@pushcolor} \AddToHook{env/macrocode/end}{\xintdoc@macrocode@popcolor} % let's use some more quiet color for links inside the code \AddToHook{env/macrocode/begin}{\hypersetup{linkcolor=macrocodelinktocodelinecolor}} % let code line numbers really be fully in the margin \MacroIndent\z@ \end{everbatim*} This concludes this section devoted to how the documentation is formatted. Now enjoy the nice colors and hyperlinking! Ah wait I had forgotten one piece. In order to minimize the mark-up I have hacked into sectioning commands to add automatically labels. And an old commented out part seems to indicate I experimented with inserting automatically |macro| environments too, but I must have encountered problems and dropped the idea.% % \footnote{It seems to me now that I have read \ctanpackage{doc} documentation that I had initially completely mis-understood what |\DescribeMacro| was supposed to be used for... or perhaps I intended to do something like the present |\@sect| hack to serve in the user manual part?} % \begin{everbatim*} % HACK OF \@sect % ============== % goal is to add labels but without having to modify currently % existing mark-up in sources. But KOMA 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{\xintdoclabelprefix\detokenize{##1}}}% \let\csh\cshintitle \let\cshn\cshnintitle #8% \endgroup}% }% \def\cshintitle#1{\csa{#1}% \label{\xintlabelprefix\detokenize{#1}}% %\expandafter\DescribeMacro\csname#1\endcsname } % \csan: no backslash \def\cshnintitle#1{\csan{#1}\label{\xintlabelprefix\detokenize{#1}}} \end{everbatim*} The |\csa| is defined this way: \begin{everbatim} \DeclareRobustCommand\csa[1] {{\ttzfamily\char92\endlinechar-1 \makestarlowast \catcode`_ 12 \catcode`^ 12 \scantokens\expandafter{\detokenize{#1}}}} \end{everbatim} And the |\csh| is defined like this: \begin{everbatim} \newcommand\csh[1] {\texorpdfstring{\csa{#1}}{\textbackslash\detokenize{#1}}} \end{everbatim} for use like in this example from \xintkernelnameimp: \begin{everbatim} % \subsubsection{\csh{XINTrestorecatcodes}, \csh{XINTsetcatcodes}, % \csh{XINTrestorecatcodesendinput}} \end{everbatim} Finally before the |\endinput| of each style file I insert |\StoreCodeLineNo{xint...}| in order to prepare the last page of |sourcexint.pdf|. \begin{everbatim*} \def\storedlinecounts {} \def\StoreCodelineNo #1{% \edef\storedlinecounts{\storedlinecounts {{#1}{\the\c@CodelineNo}{\the\c@xintMacroCnt}}% }% \global\c@CodelineNo \z@ \global\c@xintMacroCnt \z@ } \end{everbatim*} % I guess this is where |\check@module| could have been % used... maybe I should read its documentation... % awful complications...3 hours on this.. for ONLY FOUR instances in xintexpr % which I had to search for in source and none in the other files... currently... \def\FixInterMacrocodeVspace{% \def\par@beforemacrocode{\gdef\par@beforemacrocode{\par}}% \edef\xintdoc@macrocode@pushcolor{\xdef\noexpand\xintdoc@macrocode@pushcolor {\xintdoc@macrocode@pushcolor}}% \def\macro@font{\ttfamily\unskip\unskip\unskip\unskip\unskip\unskip \global\def\macro@font{\ttfamily}% \xintdoc@macrocode@pushcolor % ai hésité à le mettre au début de \@item }% \let\saved@@item\@item \def\@item[##1]{\let\saved@addpenalty\addpenalty \let\addpenalty\@gobble \saved@@item[{##1}]% \let\addpenalty\saved@addpenalty \global\let\@item\saved@@item}% }% % This is obsolete it is when I was issueing at top level a \color not black. % This is executed in a group %\renewcommand\etocbeforetitlehook{\normalcolor} % lverb environment (formerly \lverb|...|) % ================= % % This started as "long \verb" with same syntax, to be used in the code % comments and spare endless hassle of adding mark-up for verbatim stuff. It % also used \MicroFont like the custom \verb mainly used in user manual but % also in sourcexint for parts written "normally" (but using anyhow monospace % font with variable space and hyphenation) which use |...| mark-up. % % It was turned into an environment June 3, 2022 (1.4m) and a mechanism with % active backslash was added to identify control sequence names and add % hyperlinks if available (labels are autogenerated from sectioning headings). % % lverb is a verbatim environment with free flowing of whitespace. % It MUST be used with % characters at start of lines: % %\begin{lverb} % all lines start with % and preferably with %<space> %\end{lverb} % % There must not be a space between % and \end{lverb} % % Inside the environment: % - % is active and must be exclusively located at start of lines % - \ is active and identifies control sequence names, with the _, :, ^, ?, % and @ as letters. The \ should not follow immediately the %, except for % the end of the environment %\end{lverb} % % It would arguably be better to have used specific mark-up in source but % * then we need some way to have catcode 1 and 2 characters % * well, I added no mark-up. I could spend one hour % TeX-programming to reconstruct the source with mark-up % but... % - $ is a catcode 0 escape % - space and end of lines are normal, text flows normally and uses the % newtxttz font currently % - & serves as comment character % - (, :, and ) serve to enter, continue, and exit a sub-mode which does obey % spaces and lines. One can use & at end of a line to let it flow with the % next one if desired. They must immediately follow the % at start of line. % - A dash after the % (%-) inserts a \par % - also the * is active via \makestarlowast Apart from %, \, $, and & special % characters are like in verbatim. So a macro \oneargcs is defined if one % needs an escape for a macro with one parameter: \catcode`_ 11 \def\oneargcs{\catcode`{1\catcode`}2 \onearg_cs} \def\onearg_cs#1#2{#1{#2}\catcode`{12\catcode`}12\relax} % This \oneargcs is to be used as $oneargcs$<cs name>{<arg>} {\catcode32\active% \gdef\myobeyspaces{\catcode32\active\def {\leavevmode\kern\fontcharwd\font`X}}} % % Let \ fetch control sequences names in lverb environments. % For this the characters _, ^, : and ? are considered letters. % \XINT_sptoken is defined in xinttools which is loaded here % even if only typesetting sourcexint.pdf % \xint_dothis/\xint_orthat in xintkernel loaded by xinttools \def\lverbbackslash{\bgroup\toks@{}\futurelet\lverb_token\lverb_bs}% \def\lverb_bs{% \ifx\lverb_token\XINT_sptoken\xint_dothis{\lverb_bs_end}\fi % \ifx\lverb_token\lverbpercent should never happen \ifcat\noexpand\lverb_token\relax\xint_dothis{\lverb_bs_end}\fi \ifcat\lverb_token a\xint_dothis{\lverb_bs_i}\fi \if\lverb_token _\xint_dothis{\lverb_bs_i}\fi \if\lverb_token ^\xint_dothis{\lverb_bs_i}\fi % TODO quel mark-up pour autoriser : and ? sans espace pour ponctuation % TODO anglo-saxonne ? % A bit cumbersome but $null or $empty can be used if : is used for % punctuation and not as last letter of a cs, such as \foo$empty: % I checked all instances with : and ? as last character found % by this and added $empty in sources (June 3, 2022). \if\lverb_token :\xint_dothis{\lverb_bs_i}\fi \if\lverb_token ?\xint_dothis{\lverb_bs_i}\fi \xint_orthat{\lverb_bs_end}% }% \def\lverb_bs_i#1{\toks@\expandafter{\the\toks@#1}\futurelet\lverb_token\lverb_bs}% \def\lverb_bs_end{\expandafter\lverbcs\expandafter{\the\toks@}\egroup}% \let\lverbcs\cs % The % is active in the environment % Some complications to change color of private lines and then restore % (the ^^M is not active), so we split into two steps _a and _b \newif\ifprivatecolorison \def\lverbpercent {\catcode32\active\lverbpercent_a}% \def\lverbpercent_a #1{% \if\XINT_sptoken\detokenize{#1}\xint_dothis{% \catcode32 10 \ifprivatecolorison\xintdocPublicColorCmd\fi \privatecolorisonfalse }\fi % The %! mark-up is used for private things which are trimmed by the % build-script out of the dtx. \if!\detokenize{#1}\xint_dothis{% \ifprivatecolorison \else \xintdocPrivateColorCmd \privatecolorisontrue \fi \lverbpercent_b }\fi \xint_orthat{\lverbpercent_b{#1}}% }% \def\lverbpercent_b#1{% \if\XINT_sptoken\detokenize{#1}\xint_dothis{\catcode32 10 }\fi % Special mark-up after % to control linewrap % %- says to start a new paragraph \if-\detokenize{#1}\xint_dothis{\par #1}\fi % %( start an obeylines+obeyspaces context \if(\detokenize{#1}\xint_dothis{\par\bgroup\myobeyspaces\obeylines}\fi \if:\detokenize{#1}\xint_dothis{}\fi % I don't remember why this, it seems I want to kill next indentation % after the obeylines context \if)\detokenize{#1}\xint_dothis{\egroup\everypar{\hskip-\parindent\everypar{}}}\fi % Introduce a \par token if we have two empty commented-out lines % Or if we have a % at the end of the input line \ifx#1\lverbpercent\xint_dothis{\catcode32 10 \par #1}\fi % For tranformation of lverb into environment mark-up 2022/06/03 % The reason for the \detokenize{#1} upfront is that in original % private sources there might a wrapper environment which has made % the % alias to \lverbpercent already but not made the \ active % and then %\begin{lverb} may be encountered with a % catcode 0 backslash. If I did \if\@backslashchar\detokenize{#1} % there would be trouble. This test identifies %\end in a % somewhat fragile way but by convention my mark-up will never % have %\ except for %\end{lverb} \if\detokenize{#1}\@backslashchar\xint_dothis{\lverb@end}\fi \xint_orthat{\catcode32 10 #1}% } \catcode`_ 8 % \long\def\lverb \def\lverb@end end#1lverb#2{\end{lverb}} \newenvironment{lverb} {% \relax\ifhanged\else\par\smallskip\fi \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}% \catcode`\\ \active \begingroup\lccode`\~`\\\lowercase{\endgroup\let~\lverbbackslash}% \LverbFont \ignorespaces }{\par} % This \@lverb was used before conversion into an environment % \def\@lverb #1{\catcode`#1\active % \lccode`\~`#1\lowercase{\def~}{\egroup\par}}% \def\LverbFont {% % pas concluant \itshape (June 3, 2022) % pas concluant \bfseries %\xintdocPublicColorCmd \makestarlowast } % privatecodecomments % =================== % This is used in the xint*sty files (before being embedded in dtx) % with %! lines. Those lines are removed from public xint.dtx before % upload to CTAN. \newenvironment{privatecodecomments} {\par \textbf{\textcolor{red}{COMMENTAIRES PRIVÉS.}}\par \makestarlowast \begingroup\lccode`\~`\%\lowercase{\endgroup\let~\lverbpercent}% \catcode`\%\active} {\par \textbf{\textcolor{red}{FIN DES COMMENTAIRES PRIVÉS.}}\par} % \changed % ======== % updated 2021/05/29 to use \xintreleasedate (always) and put % second argument if non empty within square brackets. % 2022/06/05 now says "Modified at", and does not display the optional % argument, which contains actual date of the comment. % I wonder if I should keep displaying release date. % 2022/06/10 adds the \ifinchanged \newif\ifhanged \newcommand\changed[2][]{% \par\smallskip\noindent \textbf{Modified at #2\space(\xintreleasedate{#2})%\if\relax\detokenize{#1}\relax %\else\space[commented #1]\fi .}% \hangindent\parindent \hangedtrue % This is absolutely NOT robust. By the way I added a hook to env/macrocode/before % to do \par. \everypar\expandafter\expandafter\expandafter {\expandafter\the\expandafter\everypar \expandafter\everypar\expandafter{\the\everypar}% \hangedfalse}% } % \added % ====== % new 2022/05/16 \newcommand\added[2][]{% \par\smallskip\noindent \textbf{Added at #2\space(\xintreleasedate{#2})\if\relax\detokenize{#1}\relax \else\space[on #1]\fi.}% \hangindent\parindent \hangedtrue % This is absolutely NOT robust. By the way I added a hook to env/macrocode/before % to do \par. \everypar\expandafter\expandafter\expandafter {\expandafter\the\expandafter\everypar \expandafter\everypar\expandafter{\the\everypar}% \hangedfalse}% } % hoping the \hangedfalse will not accumulate % \xintreleasedate % ================ % added 2021/05/29 % xint-dates.txt is produced from CHANGES.md by grep via Makefile rule % 1.09 (2013/09/23) aajouté manuellement car pas dans CHANGES.md % (il y avait un bug "a stray underscore in a code line of xintexpr.sty must % be removed" et CTAN a annoncé seulement 1.09a) % \begingroup\endlinechar-1 \catcode`\`=\active \def`#1 (#2)`{\expandafter\gdef\csname xintreleasedate_#1\endcsname{#2}} `1.09 (2013/09/23)`% pas dans CHANGES.md car remplacé immédiatement par 1.09a \@@input xint-dates.txt \endgroup \def\xintreleasedate#1{% \ifcsname xintreleasedate_#1\endcsname \csname xintreleasedate_#1\endcsname \else \immediate\write128{Pas de date pour #1 en ligne \the\inputlineno}% \error \fi } \expandafter\edef\csname xintreleasedate_\xintbndlversion\endcsname{\xintbndldate} %% END OF MACRO DEFINITIONS FOR SOURCEXINT \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; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintkernelnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \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}. % % \changed[2020/01/11]{1.4} % \csbxint{Replicate}, \csbxint{Gobble}, \csbxint{LastOne}, \csbxint{FirstOne}. % % \changed{1.4l} % Fix the |1.4| added bug that |\XINTrestorecatcodes| forgot to restore % the catcode of |^||^A| which is set to |3| by |\XINTsetcatcodes|. % % \changed{1.4m} % Fix incompatibility under \eTeX{} with \ctanpackage{miniltx}, if latter was % loaded before \xintexprnameimp. The fix happens here because it relates to % matters of |\ProvidesPackage|. % % \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{lverb} % 1.4l replaces Info level user messages issued in case of problems % such as \numexpr not being available with Warning level messages (in the % LaTeX terminolgy). Should arguably be Error level in that case. % % xintkernel.sty was the only xint package emitting such an Info, now Warning % in case of being loaded twice (via \input in non-LaTeX). This was probably % a left-over from initial development stage of the loading architecture for % debugging. Starting with 1.4l, it will abort input silently in such case. % % Also at 1.4l I refactored a bit the loading code in the xint*sty files for % no real reason other than losing time. %\end{lverb} % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\space{ }\newlinechar10 \let\z\relax \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintkernel Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xintkernel}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \expandafter\ifx\csname XINTsetupcatcodes\endcsname\relax \else \def\z{\endgroup\endinput}% \fi \fi \ifx\z\relax\else\expandafter\z\fi% % \end{macrocode} % \subsubsection{\csh{XINTrestorecatcodes}, \csh{XINTsetcatcodes}, % \csh{XINTrestorecatcodesendinput}} % \changed{1.4e} %\begin{lverb} % Renamed \XINT{set,restore}catcodes % to be without underscores, to facilitate the reloading process % for xintlog.sty and xinttrig.sty in uncontrolled contexts. %\end{lverb} % \changed{1.4l} %\begin{lverb} % Fix the 1.4 bug of omission of \catcode1 restore. % % Reordered all catcodes assignements for easier maintenance and dropped most % disparate indications of which packages make use of which settings. % % The \XINTrestorecatcodes is somewhat misnamed as it is more a template % to be used in an \edef to help define actual catcode restoring macros. % % However \edef needs usually { and } so there is a potential difficulty with % telling people to do \edef\myrestore{\XINTrestorecatcodes}, and I almost % added at 1.4l some \XINTsettorestore$empty:#1->\edef#1{\XINTrestorecatcodes} but % well, this is not public interface anyhow. The reloading method of % xintlog.sty and xinttrig.sty does protect itself though against such irreal % usage possibility with non standard { or }. % % Removed at 1.4l the \XINT_setcatcodes and \XINT_restorecatcodes not used % anywhere now. Used by old version of xintsession.tex, but not anymore since % a while. %\end{lverb} % \begin{macrocode} \def\PrepareCatcodes {% \endgroup \def\XINTrestorecatcodes {% prepared for use in \edef \catcode0=\the\catcode0 % ^^@ \catcode1=\the\catcode1 % ^^A \catcode13=\the\catcode13 % ^^M \catcode32=\the\catcode32 % <space> \catcode33=\the\catcode33 % ! \catcode34=\the\catcode34 % " \catcode35=\the\catcode35 % # \catcode36=\the\catcode36 % $ \catcode38=\the\catcode38 % & \catcode39=\the\catcode39 % ' \catcode40=\the\catcode40 % ( \catcode41=\the\catcode41 % ) \catcode42=\the\catcode42 % * \catcode43=\the\catcode43 % + \catcode44=\the\catcode44 % , \catcode45=\the\catcode45 % - \catcode46=\the\catcode46 % . \catcode47=\the\catcode47 % / \catcode58=\the\catcode58 % : \catcode59=\the\catcode59 % ; \catcode60=\the\catcode60 % < \catcode61=\the\catcode61 % = \catcode62=\the\catcode62 % > \catcode63=\the\catcode63 % ? \catcode64=\the\catcode64 % @ \catcode91=\the\catcode91 % [ \catcode93=\the\catcode93 % ] \catcode94=\the\catcode94 % ^ \catcode95=\the\catcode95 % _ \catcode96=\the\catcode96 % ` \catcode123=\the\catcode123 % { \catcode124=\the\catcode124 % | \catcode125=\the\catcode125 % } \catcode126=\the\catcode126 % ~ \endlinechar=\the\endlinechar\relax }% % \end{macrocode} %\begin{lverb} % The \noexpand here is required. This feels to me a bit surprising, % but is a fact, and the source of this must be in the \edef implementation % but I have not checked it out at this time. %\end{lverb} % \begin{macrocode} \edef\XINTrestorecatcodesendinput {% \XINTrestorecatcodes\noexpand\endinput % }% \def\XINTsetcatcodes {% standard settings with a few xint*sty specific ones \catcode0=12 % for \romannumeral`&&@ \catcode1=3 % for safe separator &&A \catcode13=5 % ^^M \catcode32=10 % <space> \catcode33=12 % ! but used as LETTER inside xintexpr.sty \catcode34=12 % " \catcode35=6 % # \catcode36=3 % $ \catcode38=7 % & SUPERSCRIPT for && as replacement of ^^ \catcode39=12 % ' \catcode40=12 % ( \catcode41=12 % ) \catcode42=12 % * \catcode43=12 % + \catcode44=12 % , \catcode45=12 % - \catcode46=12 % . \catcode47=12 % / \catcode58=11 % : LETTER \catcode59=12 % ; \catcode60=12 % < \catcode61=12 % = \catcode62=12 % > \catcode63=11 % ? LETTER \catcode64=11 % @ LETTER \catcode91=12 % [ \catcode93=12 % ] \catcode94=11 % ^ LETTER \catcode95=11 % _ LETTER \catcode96=12 % ` \catcode123=1 % { \catcode124=12 % | \catcode125=2 % } \catcode126=3 % ~ MATH SHIFT \endlinechar=13 % }% \XINTsetcatcodes }% \PrepareCatcodes % \end{macrocode} % Other modules could possibly be loaded under a different catcode regime. % \begin{macrocode} \def\XINTsetupcatcodes {% for use by other modules \edef\XINTrestorecatcodesendinput {% \XINTrestorecatcodes\noexpand\endinput % }% \XINTsetcatcodes }% % \end{macrocode} % \subsection{Package identification} % % Inspired from \textsc{Heiko Oberdiek}'s packages.% % \changed{1.09b} % Re-usability 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. [nine years later I understood my mistake, see below]. % % \changed{1.09c} % Usage of \eTeX{} |\ifdefined|. % % \changed[2022/06/09]{1.4m} % Nine years too late, I understand that the |HO| \myenquote{extra % precautions} were there for some respectable reasons including % |etex+miniltx| and surely other things I can not imagine. So let's now make % sure |\ver@xintkernel.sty| and friends get defined on load, even if % |\ProvidesPackage| exists! However I remain careless in using |\ifdefined| % which could be fooled if some previous macro file ended up testing for % |\ProvidesPackage| in a way letting it to |\relax|. I do not test for that. % If I fixed that carelessness here I would have to fix it in other places % where I use similarly |\ifdefined\RequirePackage| or % |\ifdefined\PackageWarning| or whatever. % \begin{macrocode} \ifdefined\ProvidesPackage \def\XINT_providespackage\ProvidesPackage#1[#2]{% \ProvidesPackage{#1}[{#2}]% \expandafter\ifx\csname ver@#1.sty\endcsname\relax \expandafter\xdef\csname ver@#1.sty\endcsname{#2}% \fi }% \else \def\XINT_providespackage\ProvidesPackage#1[#2]{% \immediate\write-1{Package: #1 #2}% \expandafter\xdef\csname ver@#1.sty\endcsname{#2}% }% \fi \XINT_providespackage \ProvidesPackage {xintkernel}% [2022/06/10 v1.4m 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_xvii 17 \chardef\xint_c_xviii 18 \chardef\xint_c_xx 20 \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} % \added{1.2} % Check if \cs{empty} and \cs{space} have their standard meanings % and raise a warning if not. % \changed{1.3b} % Moved here |\xint_gobandstop_...| macros because this is handy for % \csbxint{RandomDigits}. % \changed{1.4} % Force \cs{empty} and \cs{space} to have their standard meanings, % rather than simply alerting user in the (theoretical) case they don't that % nothing will work. % If some \LaTeX{} user has \cs{renewcommand}ed them they will be long and % this will trigger xint redefinitions and warnings. % \begin{macrocode} \def\XINT_tmpa { }% \ifx\XINT_tmpa\space\else \immediate\write-1{Package xintkernel Warning:}% \immediate\write-1{\string\space\XINT_tmpa macro does not have its normal meaning from Plain or LaTeX, but:}% \immediate\write-1{\meaning\space}% \let\space\XINT_tmpa \immediate\write-1{\space\space\space\space % an exclam might let Emacs/AUCTeX think it is an error message, afair Forcing \string\space\space to be the usual one.}% \fi \def\XINT_tmpa {}% \ifx\XINT_tmpa\empty\else \immediate\write-1{Package xintkernel Warning:}% \immediate\write-1{\string\empty\space macro does not have its normal meaning from Plain or LaTeX, but:}% \immediate\write-1{\meaning\empty}% \let\empty\XINT_tmpa \immediate\write-1{\space\space\space\space Forcing \string\empty\space to be the usual one.}% \fi \let\XINT_tmpa\relax \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}% \long\def\xint_thirdofthree#1#2#3{#3}% 1.4d \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:{}% \long\def\xint_gob_til_^#1^{}% \def\xint_bracedstopper{\xint:}% \long\def\xint_gob_til_exclam #1!{}% This ! has catcode 12 \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} %^^A test de lverb %\begin{lverb} % \xint_Bye for \xintDSRr and \xintRound. Also \xint_stop_afterbye. %\end{lverb} % \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: %\begin{lverb} %( \if..\xint_dothis{..}\fi %: \if..\xint_dothis{..}\fi %: \if..\xint_dothis{..}\fi %: ...more such... %: \xint_orthat{...} %) %\end{lverb} % 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 (quite fragile in the normal sense i.e. non robust in the normal % sense of programming lingua) utility zaps leading, intermediate, trailing, % spaces in completely expanding context (|\edef|, |\csname...\endcsname|). % \centeredline{Usage: |\xint_zapspaces foo<space>\xint_gobble_i|} % % 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|. % % 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|. % % But for example |\foo{aa} {bb} {cc}| where |\foo| is a macro with three % non-delimited arguments breaks expansion, as expansion of |\foo| will happen % with |\xint_zapspaces| still around, and even if it wasn't it would have % stripped the braces around |{bb}|, certainly breaking other things. % % Despite such obvious shortcomings it is enough for our purposes. It is % currently used by \xintexprnameimp at various locations e.g. cleaning up % optional argument of |\xintiexpr| and |\xintfloatexpr|; maybe in future % internal usage will drop this in favour of a more robust utility. % % \changed{1.2e} |\xint_zapspaces_o|. % % \changed{1.2i} Made |\long|. % % ATTENTION THAT \xinttoolsnameimp HAS AN |\xintzapspaces| WHICH SHOULD NOT % GET CONFUSED WITH THIS ONE. % \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. Syntax with |\romannumeral0| adds some % slight (negligible) overhead; it is done to fit some general % principles of structure of the xint package macros but maybe % at some point I should drop it. And in fact it is often called % directly via the |\numexpr| access point. (bad coding...) % \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[2016/12/10]{1.2i} % One level % of braces removed in output. Output empty if input empty. Attention! % This means % that an empty input or an input ending with a {} empty brace pair % both give same output. % % The |\xint:| token must not be among items. |\xintFirstItem| added % at 1.4 for usage in xintexpr. It must contain neither |\xint:| % nor |\xint_bye| in its first item. % % \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{xintFirstItem}} %\begin{lverb} % 1.4. There must be neither \xint: % nor \xint_bye in its first item. %\end{lverb} % \begin{macrocode} \def\xintFirstItem {\romannumeral0\xintfirstitem }% \long\def\xintfirstitem #1{\XINT_firstitem #1{\xint:\XINT_firstitem_end}\xint_bye}% \long\def\XINT_firstitem #1#2\xint_bye{\xint_gob_til_xint: #1\xint:\space #1}% \def\XINT_firstitem_end\xint:{ }% % \end{macrocode} % \subsection{\csh{xintLastOne}} %\begin{lverb} % % As xintexpr 1.4 uses {c1}{c2}....{cN} storage when gathering comma separated % values we need to not handle identically an empty list and a list with an % empty item (as the above allows hierarchical structures). But \xintLastItem % removed one level of brace pair so it is anadequate for the last() function. % % By the way it is logical to interpret «item» as meaning {cj} inclusive of % the braces; but legacy xint user manual was not written in this spirit. And thus % \xintLastItem did brace stripping, thus we need another name for maintaining % backwards compatibility (although the cardinality of users is small). % % The \xint: token must not be found (visible) among the item contents. % %\end{lverb} % \begin{macrocode} \def\xintLastOne {\romannumeral0\xintlastone }% \long\def\xintlastone #1% {% \XINT_lastone_loop {}.#1% {\xint:\XINT_lastone_loop_enda}{\xint:\XINT_lastone_loop_endb}% {\xint:\XINT_lastone_loop_endc}{\xint:\XINT_lastone_loop_endd}% {\xint:\XINT_lastone_loop_ende}{\xint:\XINT_lastone_loop_endf}% {\xint:\XINT_lastone_loop_endg}{\xint:\XINT_lastone_loop_endh}\xint_bye }% \long\def\XINT_lastone_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_lastone_loop {{#9}}.% }% \long\def\XINT_lastone_loop_enda #1#2\xint_bye{{#1}}% \long\def\XINT_lastone_loop_endb #1#2#3\xint_bye{{#2}}% \long\def\XINT_lastone_loop_endc #1#2#3#4\xint_bye{{#3}}% \long\def\XINT_lastone_loop_endd #1#2#3#4#5\xint_bye{{#4}}% \long\def\XINT_lastone_loop_ende #1#2#3#4#5#6\xint_bye{{#5}}% \long\def\XINT_lastone_loop_endf #1#2#3#4#5#6#7\xint_bye{{#6}}% \long\def\XINT_lastone_loop_endg #1#2#3#4#5#6#7#8\xint_bye{{#7}}% \long\def\XINT_lastone_loop_endh #1#2#3#4#5#6#7#8#9\xint_bye{ #8}% % \end{macrocode} % \subsection{\csh{xintFirstOne}} %\begin{lverb} % For xintexpr 1.4 too. Jan 3, 2020. % % This is an experimental macro, don't use it. If input is nil (empty set) it % expands to nil, if not it fetches first item and braces it. Fetching will % have stripped one brace pair if item was braced to start with, which is % the case in non-symbolic xintexpr data objects. % % I have not given much thought to this (make it shorter, allow all tokens, % (we could first test if empty via combination with \detokenize), etc...) % as I need to get xint 1.4 out soon. So in particular attention that % the macro assumes the \xint: token is absent from first item of input. %\end{lverb} % \begin{macrocode} \def\xintFirstOne {\romannumeral0\xintfirstone }% \long\def\xintfirstone #1{\XINT_firstone #1{\xint:\XINT_firstone_empty}\xint:}% \long\def\XINT_firstone #1#2\xint:{\xint_gob_til_xint: #1\xint:{#1}}% \def\XINT_firstone_empty\xint:#1{ }% % \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}, \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|. % % \changed[2020/01/11]{1.4} % Added |\xintReplicate| ! The reason I did not before is that the prevailing % habits in xint source code was to trigger with |\romannumeral0| not % |\romannumeral| which is the lowercased named macros. Thus adding the % camelcase one creates a couple |\xintReplicate/\xintreplicate| not obeying % the general mold. % \begin{macrocode} \def\xintReplicate{\romannumeral\xintreplicate}% \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}, \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}...|} % % \changed[2020/01/11]{1.4} % Added |\xintGobble|. % \begin{macrocode} \def\xintGobble{\romannumeral\xintgobble}% \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{(xintkernel) No uniformdeviate primitive!}% 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}} % \changed{1.3c} % \begin{macrocode} \newif\ifxintglobaldefs \def\XINT_global{\ifxintglobaldefs\global\fi}% % \end{macrocode} % \subsection{(WIP) Expandable error message} % \changed[2017/07/26]{1.2l} But really belongs to next major release beyond |1.3|. % Basically copied over from l3kernel code. Using |\ ! /| control sequence, % which must be left undefined. |\xintError:| would be 6 letters more. % % \changed[2020/01/25]{1.4} Finally rather than |\ ! /| I use |\xint/|. % % \changed[2021/05/19]{1.4g} Rewrote to use not an undefined control % sequence but trigger "Use of |\xint/| doesn't match its definition." message. % % \changed[2021/05/20]{1.4g} Things evolve fast and I switch to a third % method which will exploit "Paragraph ended before |\foo| was complete" style % error. See % \centeredline{\url{https://github.com/latex3/latex3/issues/931#issuecomment-845367201}} % However I can not fully exploit this because xint may be used with % Plain etex which does not set |\newlinechar|. % I can only use a poorman version with no usage of |^^J|. Also % \ctanpackage{xintsession} could use the |^^J|, maybe I will integrate it % there. % % \def\xintsession{\ctanpackage{xintsession}} % %\begin{lverb} % I. Explanations on 2021/05/19 and 2021/05/20 before final change % % First I tried out things with undefined control sequence such as %(\ an error was reported by xint ... % %) % whose output produces a nice symmetrical display with no \, and with ... both % on left and right but this reduces drastically the available % space for the actual error context. No go. But see 2021/05/20 update below! % % Having replaced \xint/ by "\xint ", I next opted provisorily for "\Hit % RET at ?" control sequence, despite it being quite longer. And then I % thought about using "\ xint error", possibly with an included ^^J in the name, % or in the context. % % I experimented with ^^J in the context. But the context size is much % constrained, and when \errorcontextlines is at its default value of 5 for % etex, not -1 as done by LaTeX, having the info shifted to the right makes it % actually more visible. (however I have now updated $xintsession$ to 0.2b which % sets \errorcontextlines to 0) % % So I was finally back here to square one, apart from having replaced "\xint/" % by the more longish "\ xint error", hesitating with "\xinterrupt"... % % Then I had the idea to replace the undefined control sequence method by a % method with a macro \foo defined as \def\foo.{} but used as \foo<space> for % example. This gives something like this (the first line will be otherwise % if engine is run with -file-line-error): %( ! Use of \xint/ doesn't match its definition. %: <argument> \xint/ %: Ooops, looks like we are missing a ] (hit RET) %) % \xint/<space> (where the space is the unexpected token, the definition % expecting rather a full stop) makes for 7 characters % to compare to \ xint error which had 12, so I gained back 5. % % Back to ^^J: I had overlooked that TeX in the first part of the error % message will display \macro fully, so inserting ^^J in its name allows % arbitrarily long expandable error messages... as pointed out by BLF in % latex3/issues#931 as I read on the morning of 2021/05/20. This is very nice % but requires to predefine control sequences for each message, and also the % actual arguments #1, #2, ... values can appear only in the context. % % And the situation with ^^J is somewhat complicated: % % $xintsession$ sets the \newlinechar to 10, but this is not the case with bare % usage of xintexpr with etex. And this matters. To discuss ^^J we have to % separate two locations: %(- it appears in the control sequence name, %:- or in the context (which itself has two parts) %) % % 1) When in the context, what happens with ^^J is independent of the setting of % \newlinechar, and with TeXLive pdflatex the ^^J will induce a linebreak, but % with xelatex it must be used with option -8bit. % % $noindent2) When in the control sequence name the behaviour in log/terminal of ^^J is % influenced by the setting of \newlinechar. Although with pdflatex it will % always induce a linebreak, the actual count of characters where TeX will % forcefully break is influenced by whether ^^J is or not \newlinechar. And % with xelatex if it is \newlinechar, it does not depend then if -8bit or not, % but if not \newlinechar then it does and TeX forceful breaks also change % as for pdflatex. % % So, the control sequence name trick can be used to obtain arbitrarily % long messages, but the \newlinechar must be set. % % And in the context, we can try to insert some ^^J but this would need % with xetex the -8bit option, and anyhow the context size is limited, % and there is apparently no trick to get it larger. % % So, in view of all the above I decided not to use ^^J (rather $&$&J % here) at all, whether here in the control sequence or the context or % inserted in \XINT_signalcondition in the context! % % I also have a problem with usage from bnumexpr or polexpr for example, % they would need their own to avoid perhaps displaying \xint/ or analogous. % % II. Finally I modified again the method (completely, and no more need for % funny catcode 7 space as delimiter) as this allows a longer context message, % starting at start of line, and which obeys ^^J if \newlinechar is set to % it. It also allows to incorporate non-limited generic explanations as a % postfix, with linebreaks if \newlinechar is known. % % But as $xintexprnameimp can be used with Plain+etex which does not set the % \newlinechar, I can't use ^^J out of thee box. I can in $xintsession. % What I decided finally is to make a conditional definition here. % % In both cases I include the "hit RET" (how rather "hit <return>") in the % control sequence name serving to both provide extra information and trigger % the error from being defined short and finding a \par. % % The maximal size was increased from 48 characters (method with \xint/ being % badly delimited), to now 55 characters (using "! xint error:<^^J or space>" % as prefix to the message). Longer messages are truncated at 56 characters % with an appended "\ETC.". % % As it is late on this 2021/05/20, and in order to not have to change all % usages, I keep \XINT_signalcondition (in $xintcorenameimp) as a one argument % macro for time being, so will not include a more specific module name. % % The \par token has a special role here, and can't be (I)nserted without % damage, but who would want to insert it in an expandable computation % anyhow... and I don't need it in my custom error messages for sure. % % On 2021/05/21 I add a test about \newlinechar at time of package loading, % and make two distinct definitions: one using ^^J in the control sequence, % the other not using it. % % The -file-line-error toggle makes it impossible to control if the % line-break on first line will match next lines. In the ^^J branch I insert % "| " (no, finally "$ $ " with two spaces) at start of continuation lines. % Also I preferred to ensure a good-looking first line break for the case it % starts with a "! Paragraph ended ..." because a priori error messages will % be read if -file-line-error was emitted only a fortiori (this toggle % suggests some IDE launched TeX and probably -interaction=nonstopmode). % % I will perhaps make another definition in $xintsession$ (it currently loads % xintexpr prior to having set the \newlinechar, so the no ^^J definition will % be used, if nothing else is modified there). % % With some hesitation I do not insert a ^^J after "! xint error:", as % Emacs/AucTeX will display only the first line prominently and then the rest % (which is in file:line:error mode) in one block under "--- TeX said ---". I % use the ^^J only in the generic helper message embedded in the control % sequence. The cases with or without \newlinechar being 10 diverge a bit, as % in the latter case I had to ensure acceptable linebreaks at 79 chars, and I % did that first and then had spent enough time on the matter not to add more % to backport the latest ^^J style message. %\end{lverb} % \changed[2022/06/05]{1.4m} % Shorten the error message. I am always too verbose initially. % \begin{macrocode} \ifnum\newlinechar=10 \expandafter\def\csname xint<...> is done, but will resume:&&J \space hit <return> at the ? prompt to try fixing the error above&&J \space which has been encountered before expansion\endcsname #1\xint:{}% \def\XINT_expandableerror#1{% \def\XINT_expandableerror##1{% \expandafter \XINT_expandableerrorcontinue #1! xint error: ##1\par }}\expandafter\XINT_expandableerror\csname xint<...> is done, but will resume:&&J \space hit <return> at the ? prompt to try fixing the error above&&J \space which has been encountered before expansion\endcsname \else \expandafter\def\csname xint<...> is done, but will resume: hit <return> at \space the ? prompt to try fixing the error encountered before expansion\endcsname #1\xint:{}% \def\XINT_expandableerror#1{% \def\XINT_expandableerror##1{% \expandafter \XINT_expandableerrorcontinue #1! xint error: ##1\par }}\expandafter\XINT_expandableerror\csname xint<...> is done, but will resume: hit <return> at \space the ? prompt to try fixing the error encountered before expansion\endcsname \fi \def\XINT_expandableerrorcontinue#1\par{#1}% % \end{macrocode} % \subsection{The \csh{xintstrcmp} as alias of the engine primitive} % \added[2022/06/05]{1.4m} % For the \LuaTeX{} engine the code is copied over from |l3names.dtx|. I also % looked at Heiko Oberdiek's |pdftexcmds.sty| and |pdftexcmds.lua|, but I % removed |\luaescapestring| and used |token.scan_string()| as seen in % |l3names.dtx| (and I did try to inform myself about this in the \LuaTeX{} % manual, but only briefly). I am not sure about my syntax with the % |local|'s. And should I use |\directlua0|? Testing was minimal % Thus, we proceed at the user own risk. % \begin{macrocode} \ifdefined\strcmp\let\xintstrcmp\strcmp \else\ifdefined\pdfstrcmp\let\xintstrcmp\pdfstrcmp \else\ifdefined\directlua\directlua{% xintkernel = xintkernel or {} local minus_tok = token.new(string.byte'-', 12) local zero_tok = token.new(string.byte'0', 12) local one_tok = token.new(string.byte'1', 12) function xintkernel.strcmp() local A = token.scan_string() local B = token.scan_string() if A < B then tex.write(minus_tok, one_tok) else tex.write(A == B and zero_tok or one_tok) end end }\def\xintstrcmp{% \directlua{xintkernel.strcmp()}% }% \else \xintMessage{xintkernel}{Error}{Could not set-up \string\xintstrcmp.}% \errhelp{What kind of format are you using? Perhaps write the author? Bye now}% \errmessage{Sorry, could not find or define string comparison primitive}\fi\fi\fi \XINTrestorecatcodesendinput% % \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; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xinttoolsnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \xinttoolsnameimp implementation} % \RaisedLabel{sec:toolsimp} % % \localtableofcontents % % \added{1.09g} Splits off \xinttoolsnameimp from \xintnameimp. % \changed{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 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xinttools.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintkernel.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xinttools Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xinttools}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\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 \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 \def\z{\endgroup\endinput}% xinttools already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xinttools}% [2022/06/10 v1.4m Expandable and non-expandable utilities (JFB)]% % \end{macrocode} %\begin{lverb} % \XINT_toks is used in macros such as \xintFor. It is not used % elsewhere in the xint bundle. %\end{lverb} % \begin{macrocode} \newtoks\XINT_toks \xint_firstofone{\let\XINT_sptoken= } %<- space here! % \end{macrocode} % \subsection{\csh{xintgodef}, \csh{xintgoodef}, \csh{xintgfdef}} % \added{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}} % \added{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} %\begin{lverb} % 1.1c revisited this old code and improved upon the earlier endings. %\end{lverb} % \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}} % \added[2013/11/01]{1.09f} % \changed[2014/10/21]{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} %\begin{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: %\end{lverb} % \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}} % \added[2013/11/01]{1.09f} % \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} %\begin{lverb} % The \empty from \xintzaplastspaces is to prevent brace removal in the % #2 below. The \expandafter chain removes it. %\end{lverb} % \begin{macrocode} \xint_firstofone {\long\def\XINT_zapesp_a #1#2 } %<- second space here {\expandafter\XINT_zapesp_b\expandafter{#2}{#1}}% % \end{macrocode} %\begin{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 ?;-). %\end{lverb} % \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} %\begin{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. %\end{lverb} % \begin{macrocode} \long\def\XINT_zapesp_end? #1{\xint_bye #1\XINT_zapesp_end }% % \end{macrocode} %\begin{lverb} % We are done. The #1 here has accumulated all the previous material, % and is stripped of its ending spaces, if any. %\end{lverb} % \begin{macrocode} \long\def\XINT_zapesp_end\XINT_zapesp_e #1#2\xint:{ #1}% % \end{macrocode} %\begin{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. %\end{lverb} % \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}} % \added[2013/11/01]{1.09f} % \changed[2014/10/21]{1.1} It had 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}} % \added[2013/11/01]{1.09f} 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}} % \added{1.06} %\begin{lverb} \xintCSVtoList transforms a,b,..,z into {a}{b}...{z}. The comma % separated list may be a macro which is first f-expanded. Here, use of \Z % (and \R) perfectly safe. %\end{lverb} % \changed[2013/11/02]{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} %\begin{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). %\end{lverb} % \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}} % \added{1.04} %\begin{lverb} % \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. %\end{lverb} % \changed{1.2p} %\begin{lverb} % 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. %) %\end{lverb} % \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}} % \added{1.06} % \changed{1.2j} %\begin{lverb} % 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. %\end{lverb} % \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{xintNthOnePy}} % \added{1.4} % See relevant code comments in \xintexprnameimp. % \begin{macrocode} \def\xintNthOnePy {\romannumeral0\xintnthonepy }% \def\xintNthOnePyNoExpand {\romannumeral0\xintnthonepynoexpand }% \long\def\xintnthonepy #1#2{\expandafter\XINT_nthonepy_a\the\numexpr #1\expandafter.% \expandafter{\romannumeral`&&@#2}}% \def\xintnthonepynoexpand #1{\expandafter\XINT_nthonepy_a\the\numexpr #1.}% \def\XINT_nthonepy_a #1% {% \xint_UDsignfork #1\XINT_nthonepy_neg -{\XINT_nthonepy_nonneg #1}% \krof }% \long\def\XINT_nthonepy_neg #1.#2% {% \expandafter\XINT_nthonepy_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_nthonepy_neg_a #1% {% \xint_UDzerominusfork #1-\xint_stop_afterbye 0#1\xint_stop_afterbye 0-{}% \krof \expandafter\XINT_nthonepy_neg_b \romannumeral\expandafter\XINT_gobble\the\numexpr-\xint_c_i+#1% }% \long\def\XINT_nthonepy_neg_b #1#2\xint_bye{{#1}}% \long\def\XINT_nthonepy_nonneg #1.#2% {% \expandafter\XINT_nthonepy_nonneg_done \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_nthonepy_nonneg_done #1{% \long\def\XINT_nthonepy_nonneg_done ##1##2\xint_bye{% \xint_gob_til_xint:##1\expandafter#1\xint_gobble_ii\xint:{##1}}% }\XINT_nthonepy_nonneg_done{ }% % \end{macrocode} % \subsection{\csh{xintKeep}} % \added{1.09m} %\begin{lverb} % \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. %\end{lverb} % \changed{1.2i} %\begin{lverb} % 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. %\end{lverb} % \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}} % \added{1.2a} %\begin{lverb} % 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. %\end{lverb} % % \changed{1.2i} As |\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}} % \added{1.09m} %\begin{lverb} % \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. %\end{lverb} % \changed{1.2i} %\begin{lverb} % Speed improvements 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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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}} % \added{1.2a} % \changed{1.2i} As |\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}} % \added{1.04} %\begin{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. %\end{lverb} % \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{xintApply:x} (WIP, commented-out)} % \added[2020/01/27]{1.4} %\begin{lverb} % For usage in the NumPy-like slicing % routines. Well, actually, in the end I sticked with old-fashioned (quadratic % cost) \xintApply for 1.4 2020/01/31 release. See comments there. % % (Comments mainly from 2020/01/27, but on 2020/02/24 I comment out % the code and add an alternative) % % To expand in \expanded context, and does not need to % do any expansion of its second argument. % % This uses techniques I had developed for 1.2i/1.2j Keep, Trim, Length, % LastItem like macros, and I should revamp venerable \xintApply probably too. % But the latter f-expandability (if it does not have \expanded at disposal) % complicates significantly matters as it has to store material and release at % very end. % % Here it is simpler and I am doing it quickly as I really want to release % 1.4. The \xint: token should not be located in looped over items. I could % use something more exotic like the null char with catcode 3... % %( \long\def\xintApply:x #1#2$% %: {$% %: \XINT_apply:x_loop {#1}#2$% %: {\xint:\XINT_apply:x_loop_enda}{\xint:\XINT_apply:x_loop_endb}$% %: {\xint:\XINT_apply:x_loop_endc}{\xint:\XINT_apply:x_loop_endd}$% %: {\xint:\XINT_apply:x_loop_ende}{\xint:\XINT_apply:x_loop_endf}$% %: {\xint:\XINT_apply:x_loop_endg}{\xint:\XINT_apply:x_loop_endh}\xint_bye %: }$% %: \long\def\XINT_apply:x_loop #1#2#3#4#5#6#7#8#9$% %: {$% %: \xint_gob_til_xint: #9\xint: %: {#1{#2}}{#1{#3}}{#1{#4}}{#1{#5}}{#1{#6}}{#1{#7}}{#1{#8}}{#1{#9}}$% %: \XINT_apply:x_loop {#1}$% %: }$% %: \long\def\XINT_apply:x_loop_endh\xint: #1\xint_bye{}$% %: \long\def\XINT_apply:x_loop_endg\xint: #1#2\xint_bye{{#1}}$% %: \long\def\XINT_apply:x_loop_endf\xint: #1#2#3\xint_bye{{#1}{#2}}$% %: \long\def\XINT_apply:x_loop_ende\xint: #1#2#3#4\xint_bye{{#1}{#2}{#3}}$% %: \long\def\XINT_apply:x_loop_endd\xint: #1#2#3#4#5\xint_bye{{#1}{#2}{#3}{#4}}$% %: \long\def\XINT_apply:x_loop_endc\xint: #1#2#3#4#5#6\xint_bye{{#1}{#2}{#3}{#4}{#5}}$% %: \long\def\XINT_apply:x_loop_endb\xint: #1#2#3#4#5#6#7\xint_bye{{#1}{#2}{#3}{#4}{#5}{#6}}$% %: \long\def\XINT_apply:x_loop_enda\xint: #1#2#3#4#5#6#7#8\xint_bye{{#1}{#2}{#3}{#4}{#5}{#6}{#7}}$% %) % % For small number of items gain with respect to \xintApply is little if any % (might even be a loss). % % Picking one by one is possibly better for small number of items. Like % this for example, the natural simple minded thing: % %(\long\def\xintApply:x #1#2$% %: {$% %: \XINT_apply:x_loop {#1}#2\xint_bye\xint_bye %: }$% %: \long\def\XINT_apply:x_loop #1#2$% %: {$% %: \xint_bye #2\xint_bye {#1{#2}}$% %: \XINT_apply:x_loop {#1}$% %: }$% %) % % Some variant on 2020/02/24 % %( \long\def\xint_Bbye#1\xint_Bye{}$% %: \long\def\xintApply:x #1#2$% %: {$% %: \XINT_apply:x_loop {#1}#2$% %: {\xint_bye}{\xint_bye}{\xint_bye}{\xint_bye}$% %: {\xint_bye}{\xint_bye}{\xint_bye}{\xint_bye}\xint_bye %: }$% %: \long\def\XINT_apply:x_loop #1#2#3#4#5#6#7#8#9$% %: {$% %: \xint_Bye #2\xint_bye {#1{#2}}$% %: \xint_Bye #3\xint_bye {#1{#3}}$% %: \xint_Bye #4\xint_bye {#1{#4}}$% %: \xint_Bye #5\xint_bye {#1{#5}}$% %: \xint_Bye #6\xint_bye {#1{#6}}$% %: \xint_Bye #7\xint_bye {#1{#7}}$% %: \xint_Bye #8\xint_bye {#1{#8}}$% %: \xint_Bye #9\xint_bye {#1{#9}}$% %: \XINT_apply:x_loop {#1}$% %: }$% %) %\end{lverb} % \subsection{\csh{xintApplyUnbraced}} % \added{1.06b} %\begin{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. %\end{lverb} % \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{xintApplyUnbraced:x} (WIP, commented-out)} % \added[2020/01/27]{1.4} %\begin{lverb} % For usage in the NumPy-like slicing % routines. % % The items should not contain \xint: and the applied macro should not contain % \empty. % % Finally, xintexpr.sty 1.4 code did not use this macro but the f-expandable % one \xintApplyUnbraced. %\end{lverb} % \changed{1.4b} %\begin{lverb} % For 1.4b I prefer to keep the \xintApplyUnbraced:x code commented out, % and classify it as WIP. %( \long\def\xintApplyUnbraced:x #1#2$% %: {$% %: \XINT_applyunbraced:x_loop {#1}#2$% %: {\xint:\XINT_applyunbraced:x_loop_enda}{\xint:\XINT_applyunbraced:x_loop_endb}$% %: {\xint:\XINT_applyunbraced:x_loop_endc}{\xint:\XINT_applyunbraced:x_loop_endd}$% %: {\xint:\XINT_applyunbraced:x_loop_ende}{\xint:\XINT_applyunbraced:x_loop_endf}$% %: {\xint:\XINT_applyunbraced:x_loop_endg}{\xint:\XINT_applyunbraced:x_loop_endh}\xint_bye %: }$% %: \long\def\XINT_applyunbraced:x_loop #1#2#3#4#5#6#7#8#9$% %: {$% %: \xint_gob_til_xint: #9\xint: %: #1{#2}$% %: \empty#1{#3}$% %: \empty#1{#4}$% %: \empty#1{#5}$% %: \empty#1{#6}$% %: \empty#1{#7}$% %: \empty#1{#8}$% %: \empty#1{#9}$% %: \XINT_applyunbraced:x_loop {#1}$% %: }$% %: \long\def\XINT_applyunbraced:x_loop_endh\xint: #1\xint_bye{}$% %: \long\def\XINT_applyunbraced:x_loop_endg\xint: #1\empty#2\xint_bye{#1}$% %: \long\def\XINT_applyunbraced:x_loop_endf\xint: #1\empty %: #2\empty#3\xint_bye{#1#2}$% %: \long\def\XINT_applyunbraced:x_loop_ende\xint: #1\empty %: #2\empty %: #3\empty#4\xint_bye{#1#2#3}$% %: \long\def\XINT_applyunbraced:x_loop_endd\xint: #1\empty %: #2\empty %: #3\empty %: #4\empty#5\xint_bye{#1#2#3#4}$% %: \long\def\XINT_applyunbraced:x_loop_endc\xint: #1\empty %: #2\empty %: #3\empty %: #4\empty %: #5\empty#6\xint_bye{#1#2#3#4#5}$% %: \long\def\XINT_applyunbraced:x_loop_endb\xint: #1\empty %: #2\empty %: #3\empty %: #4\empty %: #5\empty %: #6\empty#7\xint_bye{#1#2#3#4#5#6}$% %: \long\def\XINT_applyunbraced:x_loop_enda\xint: #1\empty %: #2\empty %: #3\empty %: #4\empty %: #5\empty %: #6\empty %: #7\empty#8\xint_bye{#1#2#3#4#5#6#7}$% %) %\end{lverb} % \subsection{\csh{xintZip} (WIP, not public)} % \added[2020/02/25]{1.4b} %\begin{lverb} % Support for zip(). Requires \expanded. % % The implementation here thus considers the argument is already completely % expanded and is a sequence of nut-ples. I will come back at later date for % more generic macros. % % Consider even the name of the function zip() as WIP. % % As per what this does, it imitates the zip() function. See xint-manual.pdf. % % I use lame terminators. Will think again later on this. I have to be careful % with the used terminators, in particular with the NE context in mind. % % Generally speaking I will think another day about efficiency else I will % never start this. % % OK, done. More compact than I initially thought. Various things should be % commented upon here. Well, actually not so compact in the end as I basically % had to double the whole thing simply to avoid the overhead of having to grab % the final result delimited by some % \xint_bye\xint_bye\xint_bye\xint_bye\empty terminator. Now actually rather % \xint_bye\xint_bye\xint_bye\xint_bye\xint: %\end{lverb} % \begin{macrocode} \def\xintZip #1{\expanded\XINT_zip_A#1\xint_bye\xint_bye}% \def\XINT_zip_A#1% {% \xint_bye#1{\expandafter}\xint_bye \expanded{\unexpanded{\XINT_ziptwo_A #1\xint_bye\xint_bye\xint_bye\xint_bye\xint:}\expandafter}% \expanded\XINT_zip_a }% \def\XINT_zip_a#1% {% \xint_bye#1\XINT_zip_terminator\xint_bye \expanded{\unexpanded{\XINT_ziptwo_a #1\xint_bye\xint_bye\xint_bye\xint_bye\xint:}\expandafter}% \expanded\XINT_zip_a }% \def\XINT_zip_terminator\xint_bye#1\xint_bye{{}\empty\empty\empty\empty\xint:}% \def\XINT_ziptwo_a #1#2#3#4#5\xint:#6#7#8#9% {% \bgroup \xint_bye #1\XINT_ziptwo_e \xint_bye \xint_bye #6\XINT_ziptwo_e \xint_bye {{#1}#6}% \xint_bye #2\XINT_ziptwo_e \xint_bye \xint_bye #7\XINT_ziptwo_e \xint_bye {{#2}#7}% \xint_bye #3\XINT_ziptwo_e \xint_bye \xint_bye #8\XINT_ziptwo_e \xint_bye {{#3}#8}% \xint_bye #4\XINT_ziptwo_e \xint_bye \xint_bye #9\XINT_ziptwo_e \xint_bye {{#4}#9}% % \end{macrocode} %\begin{lverb} % Attention here that #6 can very well deliver no tokens at all. But % the \ifx will then do the expected thing. Only mentioning! % % By the way, the \xint_bye method means TeX needs to look into tokens % but skipping braced groups. A conditional based method lets TeX look only % at the start but then it has to find \else or \fi so here also it must looks % at tokens, and actually goes into braced groups. But (written 2020/02/26) I % never did serious testing comparing the two, and in xint I have usually % preferred \xint_bye/\xint_gob_til_foo types of methods (they proved superior % than \ifnum to check for 0000 in numerical core context for example, at the % early days when xint used blocks of 4 digits, not 8), or usage of \if/\ifx % only on single tokens, combined with some \xint_dothis/\xint_orthat syntax. %\end{lverb} % \begin{macrocode} \ifx \empty#6\expandafter\XINT_zipone_a\fi \XINT_ziptwo_b #5\xint: }% \def\XINT_zipone_a\XINT_ziptwo_b{\XINT_zipone_b}% \def\XINT_ziptwo_b #1#2#3#4#5\xint:#6#7#8#9% {% \xint_bye #1\XINT_ziptwo_e \xint_bye \xint_bye #6\XINT_ziptwo_e \xint_bye {{#1}#6}% \xint_bye #2\XINT_ziptwo_e \xint_bye \xint_bye #7\XINT_ziptwo_e \xint_bye {{#2}#7}% \xint_bye #3\XINT_ziptwo_e \xint_bye \xint_bye #8\XINT_ziptwo_e \xint_bye {{#3}#8}% \xint_bye #4\XINT_ziptwo_e \xint_bye \xint_bye #9\XINT_ziptwo_e \xint_bye {{#4}#9}% \XINT_ziptwo_b #5\xint: }% \def\XINT_ziptwo_e #1\XINT_ziptwo_b #2\xint:#3\xint: {\iffalse{\fi}\xint_bye\xint_bye\xint_bye\xint_bye\xint:}% \def\XINT_zipone_b #1#2#3#4% {% \xint_bye #1\XINT_zipone_e \xint_bye {{#1}}% \xint_bye #2\XINT_zipone_e \xint_bye {{#2}}% \xint_bye #3\XINT_zipone_e \xint_bye {{#3}}% \xint_bye #4\XINT_zipone_e \xint_bye {{#4}}% \XINT_zipone_b }% \def\XINT_zipone_e #1\XINT_zipone_b #2\xint: {\iffalse{\fi}\xint_bye\xint_bye\xint_bye\xint_bye\empty}% \def\XINT_ziptwo_A #1#2#3#4#5\xint:#6#7#8#9% {% \bgroup \xint_bye #1\XINT_ziptwo_end \xint_bye \xint_bye #6\XINT_ziptwo_end \xint_bye {{#1}#6}% \xint_bye #2\XINT_ziptwo_end \xint_bye \xint_bye #7\XINT_ziptwo_end \xint_bye {{#2}#7}% \xint_bye #3\XINT_ziptwo_end \xint_bye \xint_bye #8\XINT_ziptwo_end \xint_bye {{#3}#8}% \xint_bye #4\XINT_ziptwo_end \xint_bye \xint_bye #9\XINT_ziptwo_end \xint_bye {{#4}#9}% \ifx \empty#6\expandafter\XINT_zipone_A\fi \XINT_ziptwo_B #5\xint: }% \def\XINT_zipone_A\XINT_ziptwo_B{\XINT_zipone_B}% \def\XINT_ziptwo_B #1#2#3#4#5\xint:#6#7#8#9% {% \xint_bye #1\XINT_ziptwo_end \xint_bye \xint_bye #6\XINT_ziptwo_end \xint_bye {{#1}#6}% \xint_bye #2\XINT_ziptwo_end \xint_bye \xint_bye #7\XINT_ziptwo_end \xint_bye {{#2}#7}% \xint_bye #3\XINT_ziptwo_end \xint_bye \xint_bye #8\XINT_ziptwo_end \xint_bye {{#3}#8}% \xint_bye #4\XINT_ziptwo_end \xint_bye \xint_bye #9\XINT_ziptwo_end \xint_bye {{#4}#9}% \XINT_ziptwo_B #5\xint: }% \def\XINT_ziptwo_end #1\XINT_ziptwo_B #2\xint:#3\xint:{\iffalse{\fi}}% \def\XINT_zipone_B #1#2#3#4% {% \xint_bye #1\XINT_zipone_end \xint_bye {{#1}}% \xint_bye #2\XINT_zipone_end \xint_bye {{#2}}% \xint_bye #3\XINT_zipone_end \xint_bye {{#3}}% \xint_bye #4\XINT_zipone_end \xint_bye {{#4}}% \XINT_zipone_B }% \def\XINT_zipone_end #1\XINT_zipone_B #2\xint:#3\xint:{\iffalse{\fi}}% % \end{macrocode} % \subsection{\csh{xintSeq}} % \added{1.09c} % Without the optional argument puts stress on the input stack, % should not be used to generated thousands of terms then. % % \changed{1.4j} % This venerable macro had a brace removal bug in case it produced a single % number: |\xintSeq{10}{10}| expanded to |10| not |{10}|. When I looked at the % code the bug looked almost deliberate to me, but reading the documentation % (which I have not modified), the behaviour is really unexpected. And the % variant with step parameter |\xintSeq[1]{10}{10}| did produce |{10}|, so % yes, definitely it was a bug! % % I take this occasion to do some style (and perhaps efficiency) refactoring % in the coding. I feel there is room for improvement, no time this time. % And I don't touch the variant with step parameter. % % Memo: \xintexprnameimp has some variants, a priori on ultra quick look % they do not look like having similar bug as this one had. % \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 \the\numexpr#1\expandafter.\the\numexpr #2.% }% \def\XINT_seq #1.#2.% {% \ifnum #1=#2 \xint_dothis\XINT_seq_e\fi \ifnum #2>#1 \xint_dothis\XINT_seq_pa\fi \xint_orthat\XINT_seq_na #2.{#1}{#2}% }% \def\XINT_seq_e#1.#2{}% \def\XINT_seq_pa {\expandafter\XINT_seq_p\the\numexpr-\xint_c_i+}% \def\XINT_seq_na {\expandafter\XINT_seq_n\the\numexpr\xint_c_i+}% \def\XINT_seq_p #1.#2% {% \ifnum #1>#2 \expandafter\XINT_seq_p\the \else \expandafter\XINT_seq_e \fi \numexpr #1-\xint_c_i.{#2}{#1}% }% \def\XINT_seq_n #1.#2% {% \ifnum #1<#2 \expandafter\XINT_seq_n\the \else \expandafter\XINT_seq_e \fi \numexpr #1+\xint_c_i.{#2}{#1}% }% % \end{macrocode} % Note at time of the |1.4j| bug fix : I definitely should improve this branch % and diminish the number of expandafter's but no time this time. % \begin{macrocode} \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}} % \added[2013/11/22]{1.09g} % \changed{1.09h} Made |\long|. % \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}} % \added[2013/11/22]{1.09g} % \changed{1.09h} Made |\long|. % \added[2018/04/24]{1.3b} % \myenquote{braced} variants. % \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}} % \added[2013/10/29]{1.09e} % 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}} % \added{1.09a} %\begin{lverb} % \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. %\end{lverb} % \changed{1.09c} % Rewritten. 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}} % \added[2013/10/09]{1.09c} %\begin{lverb} % 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. %\end{lverb} % \changed{1.09e} %\begin{lverb} % Adds \XINT_forever with \xintintegers, \xintdimensions, \xintrationals % and \xintBreakFor, \xintBreakForAndDo, \xintifForFirst, \xintifForLast. On % this occasion \xint_firstoftwo and \xint_secondoftwo are made long. %\end{lverb} % \changed[2013/11/03]{1.09f} %\begin{lverb} % 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. % % Now allows all macro parameters % from #1 to #9 in \xintFor, \xintFor*, and \XINT_forever. %\end{lverb} % \changed{1.2i} %\begin{lverb} % Slightly more robust \xintifForFirst/Last in case of nesting. %\end{lverb} % \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}} % \added{1.09e} %\begin{lverb} % But this used inadvertently \xintiadd/\xintimul which % have the unnecessary \xintnum overhead. %\end{lverb} % \changed{1.09f} %\begin{lverb} % 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). %\end{lverb} % \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}} % \added{1.09c} % \changed[2013/11/02]{1.09f} %\begin{lverb} % \xintForpair delegate to \xintCSVtoList and its % \xintZapSpacesB the handling of spaces. Does not share code with \xintFor % anymore. % % \xintForpair extended to accept #1#2, #2#3 etc... up to % #8#9, \xintForthree, #1#2#3 up to #7#8#9, \xintForfour id. %\end{lverb} % \changed{1.2i} %\begin{lverb} % Slightly more robust \xintifForFirst/Last in case of nesting. %\end{lverb} % \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}} %\begin{lverb} % \xintAssign {a}{b}..{z}\to\A\B...\Z resp. \xintAssignArray % {a}{b}..{z}\to\U. % % \xintDigitsOf=\xintAssignArray. %\end{lverb} % \changed[2015/09/12]{1.1c} %\begin{lverb} % Belatedly corrects 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. %\end{lverb} % \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_assign_tmp {#1}% \ifx\XINT_assign_tmp\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_assign_tmp}% \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_assign_tmp {#1}% \ifx\XINT_assign_tmp\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_assign_tmp }% \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 is negative: ##1.} }% \else \xint_afterfi {% \ifnum ##1>#2 \xint_afterfi {\XINT_expandableerror{Array index is beyond range: ##1 > #2.} }% \else\xint_afterfi {\expandafter\expandafter\expandafter\space\csname #3##1\endcsname}% \fi}% \fi }% }% \let\xintDigitsOf\xintAssignArray % \end{macrocode} % \subsection{CSV (non user documented) variants of Length, Keep, Trim, NthElt, Reverse} % \changed{1.2j} % 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}} % \added{1.2g} % \changed{1.2j} % Contrarily to |\xintLength| from \xintkernelnameimp % 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} %\begin{lverb} % Must first check if empty list. %\end{lverb} % \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}} % \added{1.2j} %\begin{lverb} % \added{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. %\end{lverb} % \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} %\begin{lverb} % Must first recognize if empty list. If this is the case, return N. %\end{lverb} % \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}} % \added[2016/03/17]{1.2g} % \changed{1.2j} %\begin{lverb} % Redone 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. % %\end{lverb} % \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}} % \added[2016/03/17]{1.2g} % \changed[2016/12/20]{1.2j} % Redone 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}} %\begin{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. %\end{lverb} % \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} %\begin{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... %\end{lverb} % \begin{macrocode} \xint_firstofone{\long\def\XINT_nthelt:f:csv_pos_cleanup\xint:} % #1\xint:{ #1}% % \end{macrocode} % \subsubsection{\csh{xintReverse:f:csv}} % \added[2016/03/17]{1.2g} %\begin{lverb} % Contrarily to \xintReverseOrder from xintkernel.sty, this % one expands its argument. Handles empty list too. . %\end{lverb} % \changed{1.2j} Made |\long|. % \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}} % \added{1.2k} %\begin{lverb} % For use by first() in % \xintexpr-essions, and some amount of compatibility with \xintNewExpr. %\end{lverb} % \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}} % \added{1.2k} %\begin{lverb} % 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. %\end{lverb} % \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{\csh{xintKeep:x:csv}} % \added{1.2j} To \xintexprnameimp. Moved here at |1.4|. % Not part of % publicly supported macros, may be removed at any time. % \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{Public names for the undocumented csv macros: % \csh{xintCSVLength}, \csh{xintCSVKeep}, \csh{xintCSVKeepx}, \csh{xintCSVTrim}, % \csh{xintCSVNthEltPy}, \csh{xintCSVReverse}, % \csh{xintCSVFirstItem}, \csh{xintCSVLastItem}} % %\begin{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. %\end{lverb} % \begin{macrocode} \let\xintCSVLength \xintLength:f:csv \let\xintCSVKeep \xintKeep:f:csv \let\xintCSVKeepx \xintKeep:x: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 \XINTrestorecatcodesendinput% % \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; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintcorenameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \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 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintcore.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintkernel.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintcore Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xintcore}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\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 \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 \def\z{\endgroup\endinput}% xintkernel already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintcore}% [2022/06/10 v1.4m Expandable arithmetic on big integers (JFB)]% % \end{macrocode} % \subsection{(WIP!) Error conditions and exceptions} %\begin{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... %\end{lverb} %\odef\MakePrivateLetters{\MakePrivateLetters\catcode`- 11}^^A % \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 % \end{macrocode} % |#1|=signal, |#2|=condition, |#3|=explanation for user, % |#4|=context for error handlers, |#5|=used. % \begin{macrocode} \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 % \end{macrocode} % \let\MakePrivateLetters\xintMakePrivateLetters %\begin{lverb} % On 2021/05/19, 1.4g, I re-examined \XINT_expandableerror experimenting % at first with an added ^^J to shift to next line the actual message. % % Previously I was calling it thrice (condition #2, user context #3, next % tokens #5) here but it seems more reasonable to use it only once. As total % size is so limited, I decided to only display #3 (information for user) and % drop the #2 (condition, first argument of \XINT_signalcondition) and the % display of the #5 (next tokens, fourth argument of \XINT_signalcondition). % % Besides, why was I doing here \xint_stop_atfirstofone{#5}, which adds % limitations to usage? Now inserting #5 directly so callers will have to % insert a \romannumeral0 stopping space token if needed. I thus have to % update all usages across (mainly, I think) xintfrac. Done, but using here % \xint_firstofone{#5}. This looks silly, but allows some hypothetical future % usage by user of I\xintUse{stuff} usage where \xintUse would be % \xint_firstofthree. % % The problem is that this would have to be explained to user in the error % context but space there is so extremely limited... % % After having reviewed existing usage of \XINT_signalcondition, I noticed % there was free space in most cases and added here " (hit RET)" after #3. % % I experimented with ^^J here too (its effect in the "context" is % independent of the \newlinechar setting, but it depends on the engine: works % with TeXLive pdftex, requires -8bit with xetex) % % However, due to \errorcontextlines being 5 by default in etex (but % xintsession 0.2b sets it to 0), I finally decided to not insert a ^^J % ($&$&J) at all to separate the " (hit RET)" hint. % % On 2021/05/20 evening I found another completely different method for % \XINT_expandableerror, which has some advantages. In particular it allows me % to not use here "#3 (hit RET)" but simply "#3" as such information can be % integrated in a non size limited generic message. % % The maximal size of #3 here was increased from 48 characters (method % with \xint/ being badly delimited), to now 55 characters, longer % messages being truncated at 56 characters with an appended "\ETC.". %\end{lverb} % \begin{macrocode} \XINT_expandableerror{#3}% % not for X3.274 % \XINT_expandableerror{<RET>, or I\xintUse{...}<RET>, or I\xintCTRLC<RET>}% \xint_firstofone{#5}% }% }% %% \def\xintUse{\xint_firstofthree} % 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) % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`. 11 }% % \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} % \let\MakePrivateLetters\xintMakePrivateLetters % \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} %\begin{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. %\end{lverb} % % \subsection{\csh{XINT_cuz_small}} %\begin{lverb} % \XINT_cuz_small removes leading zeroes from the first eight digits. Expands % following \romannumeral0. At least one digit is produced. %\end{lverb} % \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{\cshnolabel{xintNum}, \csh{xintiNum}} %\begin{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. %\end{lverb} % \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 % \end{macrocode} % Attention |\xintnum| (hence |\xintNum|) gets redefined by % \xintfracnameimp. Click on names to see the redefinition there. % \begin{macrocode} \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} %\begin{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. %\end{lverb} % \begin{macrocode} \expandafter\XINT_num_loop \else % \end{macrocode} %\begin{lverb} % non terminated \numexpr (with nine tokens total) are % safe as after \fi, there is then \xint: %\end{lverb} % \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}} %\begin{lverb} % 1.2l made \xintiiSgn robust against non terminated input. % % 1.2o deprecates here \xintSgn (it requires xintfrac.sty). %\end{lverb} % \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}} %\begin{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". %\end{lverb} % \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}} %\begin{lverb} % Attention \xintiiAbs non robust against non terminated input. %\end{lverb} % \begin{macrocode} \def\xintiiAbs {\romannumeral0\xintiiabs }% \def\xintiiabs #1% {% \expandafter\XINT_abs \romannumeral`&&@#1% }% \def\XINT_abs #1% {% \xint_UDsignfork #1{ }% -{ #1}% \krof }% \def\XINT_Abs #1% {% \xint_UDsignfork #1{}% -{#1}% \krof }% % \end{macrocode} % \subsection{\csh{xintFDg}} %\begin{lverb} % FIRST DIGIT. % % 1.2l: \xintiiFDg made robust against non terminated input. % % 1.2o deprecates \xintiiFDg, gives to \xintFDg former meaning of \xintiiFDg. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{lverb} % Attention \xintDouble non robust against non terminated input. %\end{lverb} % \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}} %\begin{lverb} % Attention \xintHalf non robust against non terminated input. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % The lingua of release 1.2. %\end{lverb} % % \subsection{\csh{XINT_cuz}} %\begin{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. %\end{lverb} % \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}} %\begin{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 %\end{lverb} % \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}} % %\begin{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. %\end{lverb} % \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}} % %\begin{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. %\end{lverb} % \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}} % %\begin{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. %\end{lverb} % \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}} % %\begin{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. %\end{lverb} % \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}} % %\begin{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. %\end{lverb} % \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}} % %\begin{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. %\end{lverb} % \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}} % %\begin{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. %\end{lverb} % \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}} % %\begin{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. %\end{lverb} % \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}} %\begin{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). %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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). %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % % \subsection{\csh{xintiiAdd}} %\begin{lverb} % 1.2l: \xintiiAdd made robust against non terminated input. %\end{lverb} % \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_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 \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} %\begin{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 ? %\end{lverb} % \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} %\begin{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 algorithm this 1;! terminator can % thus conveniently be reused as part of input terminator (up to the length % problem). % %\end{lverb} % \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% }% \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} %\begin{lverb} % Here 2 stands for "carry", and 1 for "no carry" (we have been adding % 1 to 1<8digits>.) %\end{lverb} % \begin{macrocode} \def\XINT_add_o #1{\if #12\expandafter\XINT_add_l\else\expandafter\XINT_add_ke \fi}% % \end{macrocode} % \subsection{\csh{xintiiCmp}} % \changed[2022/06/05]{1.4m} % Now uses the |\xintstrcmp| engine primitive. % \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_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 {}{}}% % \end{macrocode} %\begin{lverb} % The \romannumeral0 trigger induces some complications here to terminate % nicely without grabbing too many tokens in the stream or deteriorating % expansion quality of the non-equal-length branches. % \expanded simplifies things. %\end{lverb} % \begin{macrocode} \def\XINT_cmp_plusplus #1#2#3\xint:#4\xint:{\expanded{ % \ifcase\expandafter\XINT_cntSgn\the\numexpr\xintLength{#1#4}-\xintLength{#2#3}\xint: \xintstrcmp{#1#4}{#2#3}\or1\else-1\fi }% }% % \end{macrocode} % Prior to |1.4m| the «strcmp» primitive was not used by \xintcorenameimp. % Here is the old implementation: %\begin{lverb} %( \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{lverb} % \subsection{\csh{xintiiSub}} %\begin{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 deciding 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. %\end{lverb} % \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_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 {}{}}% \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} %\begin{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. %\end{lverb} % \begin{macrocode} \def\XINT_sub_out {\XINT_unrevbyviii{}}% % \end{macrocode} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % %\end{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} %\begin{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 %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \begin{macrocode} \def\XINT_sub_comp_clean 1#1{+#1\relax}% % \end{macrocode} % \subsection{\csh{xintiiMul}} %\begin{lverb} % Completely rewritten for 1.2. % % 1.2l: \xintiiMul made robust against non terminated input. %\end{lverb} % \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} %\begin{lverb} % 1.2 I have changed the fork, and it complicates matters elsewhere. % % ATTENTION for example that 1.4 \xintiiPrd uses \XINT_mul_nfork now. %\end{lverb} % \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} %\begin{lverb} % Cooking recipe, 2015/10/05. %\end{lverb} % \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}% \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} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % Each of #1 and #2 brings its 1;! for \XINT_add_a. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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}% \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} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} %\begin{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|. %\end{lverb} % \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} %\begin{lverb} % On regarde les signes de A et de B. %\end{lverb} % \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 by zero: #1#4/#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} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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). %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % Le #2 poursuivra l'expansion par \XINT_div_dosmallsmall ou par % \XINT_smalldivx_a suivi de \XINT_sdiv_out. %\end{lverb} % \begin{macrocode} \def\XINT_div_small_b #1!#2{#2#1!}% % \end{macrocode} %\begin{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. %\end{lverb} % \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} %\begin{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}. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \begin{macrocode} \def\XINT_div_dosmalldiv {{\expandafter\XINT_sdiv_out\the\numexpr\XINT_smalldivx_a}}% % \end{macrocode} %\begin{lverb} % Ici B est au moins 10^8, on détermine combien de zéros lui adjoindre % pour qu'il soit de longueur 8N. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % L, K, A, x',y,x, B, «c»->K.A.x{LK{x'y}x}B«c» %\end{lverb} % \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} %\begin{lverb} % Ici ce sont routines de fin. Le reste déjà nettoyé. R.Q«c». %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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». %\end{lverb} % \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} %\begin{lverb} % Ceci est le point de retour de la boucle principale. a, x, alpha, B, % q0, L, K, {x'y}, x, alpha', B«c» %\end{lverb} % \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} %\begin{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». %\end{lverb} % \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} %\begin{lverb} % r.q.alpha, B, q0, L, K, {x'y}, x, alpha', B«c» %\end{lverb} % \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} %\begin{lverb} % attention très mauvaises notations avec _b et _db. %\end{lverb} % \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} %\begin{lverb} % La soustraction spéciale renvoie simplement - si le chiffre q est % trop grand. On invoque dans ce cas I_dP. %\end{lverb} % \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} %\begin{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» %\end{lverb} % \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} %\begin{lverb} % 1#1=nouveau q. nouvel alpha, L, K, {x'y},x,alpha', BQ«c» %\end{lverb} % \begin{macrocode} % \end{macrocode} %\begin{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» %\end{lverb} % \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} %\begin{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» %\end{lverb} % \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} %\begin{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» %\end{lverb} % \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} %\begin{lverb} % {x'y}alpha.B, {{x'y},x,K,L}, nouveau alpha',B,«c» %\end{lverb} % \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} %\begin{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» %\end{lverb} % \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} %\begin{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>. %\end{lverb} % \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} %\begin{lverb} % x'=10^8 and we return #1=1<8digits>. %\end{lverb} % \begin{macrocode} \def\XINT_div_xmini_c 0\XINT_div_mini 100000000\xint:50000000!#1!#2!{#1!}% % \end{macrocode} %\begin{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» %\end{lverb} % \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} %\begin{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>! %\end{lverb} % \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} %\begin{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» %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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» %\end{lverb} % \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} %\begin{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» %\end{lverb} % \begin{macrocode} \def\XINT_div_II_h 1#1\xint:#2#3#4% {% \XINT_div_II_k #4{#2}{#3}{#1}% }% % \end{macrocode} %\begin{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» %\end{lverb} % \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} %\begin{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» %\end{lverb} % \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} %\begin{lverb} % This multiplication is exactly like \XINT_smallmul -- apart from not % inserting an ending 1;! --, but keeps ever a vanishing ending carry. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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. % %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % On boucle vers \XINT_smalldiv_d. %\end{lverb} % \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} %\begin{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>. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \begin{macrocode} \def\xintiiDivRound {\romannumeral0\xintiidivround }% \def\xintiidivround #1{\expandafter\XINT_iidivround\romannumeral`&&@#1\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 by zero: #1#4/#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}} %\begin{lverb} % 1.2l: \xintiiDivTrunc made robust against non terminated input. %\end{lverb} % \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} %\begin{lverb} % Attention to not move DivRound code beyond that point. %\end{lverb} % \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}} %\begin{lverb} % Renamed from \xintiiMod to \xintiiModTrunc at 1.2p. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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 zero: #1#3/#2.}{}% {{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}} %\begin{lverb} % 1.2p. For bnumexpr actually, because \xintiiexpr could use % \xintDivFloor which also outputs an integer in strict format. %\end{lverb} % \begin{macrocode} \def\xintiiDivFloor {\romannumeral0\xintiidivfloor}% \def\xintiidivfloor {\expandafter\xint_stop_atfirstoftwo \romannumeral0\xintiidivmod}% % \end{macrocode} % \subsection{\csh{xintiiMod}} %\begin{lverb} % Associated with floored division at 1.2p. Formerly was associated with % truncated division. %\end{lverb} % \begin{macrocode} \def\xintiiMod {\romannumeral0\xintiimod}% \def\xintiimod {\expandafter\xint_stop_atsecondoftwo \romannumeral0\xintiidivmod}% % \end{macrocode} % \subsection{\csh{xintiiSqr}} %\begin{lverb} % 1.2l: \xintiiSqr made robust against non terminated input. %\end{lverb} % \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} %\begin{lverb} % 1.2c \XINT_mul_loop can now be called directly even with small % arguments, thus the following check is not anymore a necessity. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}{0 raised 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 is not an integer.}{}{ 0}}% \def\XINT_pow_BisZero #1\xint:{ 1}% % \end{macrocode} %\begin{lverb} % B = #1 > 0, A = #2 > 1. Earlier code checked if size of B did not % exceed a given limit (for example 131000). %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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}} %\begin{lverb} % Moved here from xint.sty with release 1.2 (to be usable by \bnumexpr). % % 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. % %\end{lverb} % \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 argument: #1.}{}{ 0}}% \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 argument is too large: #1 > 10^4.}{}{ 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}} %\begin{lverb} % 1.2o %\end{lverb} % \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}% {}% }% \XINTrestorecatcodesendinput% % \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; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \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. % % |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 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xint.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintcore.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xint Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xint}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\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 \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 \def\z{\endgroup\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}% [2022/06/10 v1.4m 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}} %\begin{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. %\end{lverb} % \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 \def\XINT_len_fork #1% {% \expandafter\XINT_length_loop\xint_UDsignfork#1{}-#1\krof }% % \end{macrocode} % \subsection{\csh{xintiiLogTen}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % le #2 a le bon pattern terminé par ; #1=0 est OK pour \XINT_rep. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}}% \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}% \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 }% \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}} %\begin{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. %\end{lverb} % \begin{macrocode} \def\xintDSHr {\romannumeral0\xintdshr }% \def\xintdshr #1#2% {% \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 {% \expandafter\xint_stop_atsecondoftwo\romannumeral0\XINT_dsx_xisPos }% % \end{macrocode} % \subsection{\csh{xintDSH}} % \begin{macrocode} \def\xintDSH {\romannumeral0\xintdsh }% \def\xintdsh #1#2% {% \expandafter\XINT_dsh_fork\the\numexpr#1\expandafter.\romannumeral`&&@#2;% }% \def\XINT_dsh_fork #1% {% \xint_UDzerominusfork #1-\XINT_dsh_xiszero 0#1\XINT_dsx_xisNeg_checkA 0-{\XINT_dsh_xisPos #1}% \krof }% \def\XINT_dsh_xiszero #1.#2;{ #2}% \def\XINT_dsh_xisPos {% \expandafter\xint_stop_atfirstoftwo\romannumeral0\XINT_dsx_xisPos }% % \end{macrocode} % \subsection{\csh{xintDSx}} %\begin{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. % %\end{lverb} % \begin{macrocode} \def\xintDSx {\romannumeral0\xintdsx }% \def\xintdsx #1#2% {% \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% \expandafter\XINT_dsx_append\romannumeral\XINT_rep #1\endcsname 0.#2% }% \def\XINT_dsx_xisNeg_Azero #1;{ 0}% \def\XINT_dsx_addzeros #1% {\expandafter\XINT_dsx_append\romannumeral\XINT_rep#1\endcsname0.}% \def\XINT_dsx_addzerosnofuss #1% {\expandafter\XINT_dsx_append\romannumeral\xintreplicate{#1}0.}% \def\XINT_dsx_append #1.#2;{ #2#1}% \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..% }% \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}% }% \def\XINT_dsx_AisPos #1.#2;% {% \expandafter\XINT_dsx_AisPos_finish \romannumeral0\XINT_split_xfork #1.#2\xint_bye2345678\xint_bye..% }% \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}} %\begin{lverb} % no \xintiieq. %\end{lverb} % \begin{macrocode} \def\xintiiEq #1#2{\romannumeral0\xintiiifeq{#1}{#2}{1}{0}}% % \end{macrocode} % \subsection{\csh{xintiiNotEq}} %\begin{lverb} % Pour xintexpr. Pas de version en lowercase. %\end{lverb} % \begin{macrocode} \def\xintiiNotEq #1#2{\romannumeral0\xintiiifeq {#1}{#2}{0}{1}}% % \end{macrocode} % \subsection{\csh{xintiiGeq}} %\begin{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. %\end{lverb} % \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: }% \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}} %\begin{lverb} % 1.09a. restyled in 1.09i. 1.1 adds \xintiiIsZero, etc... for % optimization in \xintexpr %\end{lverb} % \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}} %\begin{lverb} % 1.09a. restyled in 1.09i. 1.1 adds \xintiiIsZero, etc... for % optimization in \xintexpr %\end{lverb} % \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}} %\begin{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. % % % %\end{lverb} % \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}} %\begin{lverb} % \xintOdd is needed for the xintexpr-essions even() and odd() % functions (and also by \xintNewExpr). %\end{lverb} % \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}} %\begin{lverb} % MINUS ONE TO THE POWER N %\end{lverb} % \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}} %\begin{lverb} % MINUS ONE TO THE POWER N-1 %\end{lverb} % \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}} %\begin{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...). %\end{lverb} % \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}} %\begin{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) %\end{lverb} % \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}} %\begin{lverb} % 1.09e % \xintifCmp {n}{m}{if n<m}{if n=m}{if n>m}. 1.1a adds ii variant %\end{lverb} % \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}} %\begin{lverb} % 1.09a \xintifEq {n}{m}{YES if n=m}{NO if n<>m}. 1.1a adds ii variant %\end{lverb} % \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}} %\begin{lverb} % 1.09a \xintifGt {n}{m}{YES if n>m}{NO if n<=m}. 1.1a adds ii variant %\end{lverb} % \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}} %\begin{lverb} % 1.09a \xintifLt {n}{m}{YES if n<m}{NO if n>=m}. Restyled in 1.09i. % 1.1a adds ii variant %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{lverb} % added in 1.09i. 1.1a adds \xintiiifOne. %\end{lverb} % \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}} %\begin{lverb} % 1.09e. Restyled in 1.09i. 1.1a adds \xintiiifOdd. %\end{lverb} % \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}} %\begin{lverb} % 1.09i, with name changes at 1.2i. % % 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. %\end{lverb} % \begin{macrocode} \def\xintifTrueAelseB {\romannumeral0\xintiiifnotzero}% \def\xintifFalseAelseB{\romannumeral0\xintiiifzero}% % \end{macrocode} % \subsection{\csh{xintIsTrue}, \csh{xintIsFalse}} %\begin{lverb} % 1.09c. Suppressed at 1.2o. They seem not to have been documented, fortunately. %\end{lverb} % \begin{macrocode} %\let\xintIsTrue \xintIsNotZero %\let\xintIsFalse\xintIsZero % \end{macrocode} % \subsection{\csh{xintNOT}} %\begin{lverb} % 1.09c with name change at 1.2o. Besides, the macro is now defined as ii-type. %\end{lverb} % \begin{macrocode} \def\xintNOT{\romannumeral0\xintiiiszero}% % \end{macrocode} % \subsection{\csh{xintAND}, \csh{xintOR}, \csh{xintXOR}} %\begin{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. %\end{lverb} % \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}} %\begin{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. % % 1.4. This macro as well as ORof and XORof were formally not used by % xintexpr, which uses comma separated items, but at 1.4 xintexpr uses braced % items. And the macros here got slightly refactored and \XINT_ANDof added for % usage by xintexpr and the NewExpr hook. For some random reason I decided to % use ^ as delimiter this has to do that other macros in xintfrac in same % family (such as \xintGCDof, \xintSum) also use \xint: internally and % although not strictly needed having two separate ones clarifies. % %\end{lverb} % \begin{macrocode} \def\xintANDof {\romannumeral0\xintandof }% \def\xintandof #1{\expandafter\XINT_andof\romannumeral`&&@#1^}% \def\XINT_ANDof {\romannumeral0\XINT_andof}% \def\XINT_andof #1% {% \xint_gob_til_^ #1\XINT_andof_yes ^% \xintiiifNotZero{#1}\XINT_andof\XINT_andof_no }% \def\XINT_andof_no #1^{ 0}% \def\XINT_andof_yes ^#1\XINT_andof_no{ 1}% % \end{macrocode} % \subsection{\csh{xintORof}} %\begin{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. % % Refactored at 1.4. %\end{lverb} % \begin{macrocode} \def\xintORof {\romannumeral0\xintorof }% \def\xintorof #1{\expandafter\XINT_orof\romannumeral`&&@#1^}% \def\XINT_ORof {\romannumeral0\XINT_orof}% \def\XINT_orof #1% {% \xint_gob_til_^ #1\XINT_orof_no ^% \xintiiifNotZero{#1}\XINT_orof_yes\XINT_orof }% \def\XINT_orof_yes#1^{ 1}% \def\XINT_orof_no ^#1\XINT_orof{ 0}% % \end{macrocode} % \subsection{\csh{xintXORof}} %\begin{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. % % Refactored at 1.4 to use \numexpr (or an \ifnum). I have not tested if % more efficient or not or if one can do better without \the. % \XINT_XORof for xintexpr matters. %\end{lverb} % \begin{macrocode} \def\xintXORof {\romannumeral0\xintxorof }% \def\xintxorof #1{\expandafter\XINT_xorof\romannumeral`&&@#1^}% \def\XINT_XORof {\romannumeral0\XINT_xorof}% \def\XINT_xorof {\if1\the\numexpr\XINT_xorof_a}% \def\XINT_xorof_a #1% {% \xint_gob_til_^ #1\XINT_xorof_e ^% \xintiiifNotZero{#1}{-}{}\XINT_xorof_a }% \def\XINT_xorof_e ^#1\XINT_xorof_a {1\relax\xint_afterfi{ 0}\else\xint_afterfi{ 1}\fi}% % \end{macrocode} % \subsection{\csh{xintiiMax}} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % Refactored at 1.2m for avoiding grabbing arguments. Position of inputs % shared with iiCmp and iiGeq code. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \begin{macrocode} \def\XINT_max_minusminus --% {% \unless\if1\romannumeral0\XINT_geq_plusplus{}{}% }% % \end{macrocode} % \subsection{\csh{xintiiMin}} %\begin{lverb} % New with 1.09a. I add \xintiiMin in 1.1 and \xintMin is % an $xintfracnameimp macro. % % 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. %\end{lverb} % \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}} %\begin{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. % % 1.4 refactors code to allow empty argument. For usage by \xintiiexpr. % Slight deterioration, will come back. % %\end{lverb} % \begin{macrocode} \def\xintiiMaxof {\romannumeral0\xintiimaxof }% \def\xintiimaxof #1{\expandafter\XINT_iimaxof\romannumeral`&&@#1^}% \def\XINT_iiMaxof{\romannumeral0\XINT_iimaxof}% \def\XINT_iimaxof#1% {% \xint_gob_til_^ #1\XINT_iimaxof_empty ^% \expandafter\XINT_iimaxof_loop\romannumeral`&&@#1\xint: }% \def\XINT_iimaxof_empty ^#1\xint:{ 0}% \def\XINT_iimaxof_loop #1\xint:#2% {% \xint_gob_til_^ #2\XINT_iimaxof_e ^% \expandafter\XINT_iimaxof_loop\romannumeral0\xintiimax{#1}{#2}\xint: }% \def\XINT_iimaxof_e ^#1\xintiimax #2#3\xint:{ #2}% % \end{macrocode} % \subsection{\csh{xintiiMinof}} %\begin{lverb} % 1.09a. 1.2a adds \xintiiMinof which was lacking. % % 1.4 refactoring for \xintiiexpr matters. %\end{lverb} % \begin{macrocode} \def\xintiiMinof {\romannumeral0\xintiiminof }% \def\xintiiminof #1{\expandafter\XINT_iiminof\romannumeral`&&@#1^}% \def\XINT_iiMinof{\romannumeral0\XINT_iiminof}% \def\XINT_iiminof#1% {% \xint_gob_til_^ #1\XINT_iiminof_empty ^% \expandafter\XINT_iiminof_loop\romannumeral`&&@#1\xint: }% \def\XINT_iiminof_empty ^#1\xint:{ 0}% \def\XINT_iiminof_loop #1\xint:#2% {% \xint_gob_til_^ #2\XINT_iiminof_e ^% \expandafter\XINT_iiminof_loop\romannumeral0\xintiimin{#1}{#2}\xint: }% \def\XINT_iiminof_e ^#1\xintiimin #2#3\xint:{ #2}% % \end{macrocode} % \subsection{\csh{xintiiSum}} %\begin{lverb} % \xintiiSum {{a}{b}...{z}} % Refactored at 1.4 for matters initially related to xintexpr delimiter % choice. % % %\end{lverb} % \begin{macrocode} \def\xintiiSum {\romannumeral0\xintiisum }% \def\xintiisum #1{\expandafter\XINT_iisum\romannumeral`&&@#1^}% \def\XINT_iiSum{\romannumeral0\XINT_iisum}% \def\XINT_iisum #1% {% \expandafter\XINT_iisum_a\romannumeral`&&@#1\xint: }% \def\XINT_iisum_a #1% {% \xint_gob_til_^ #1\XINT_iisum_empty ^% \XINT_iisum_loop #1% }% \def\XINT_iisum_empty ^#1\xint:{ 0}% % \end{macrocode} %\begin{lverb} % bad coding as it depends on internal conventions of \XINT_add_nfork %\end{lverb} % \begin{macrocode} \def\XINT_iisum_loop #1#2\xint:#3% {% \expandafter\XINT_iisum_loop_a \expandafter#1\romannumeral`&&@#3\xint:#2\xint:\xint: }% \def\XINT_iisum_loop_a #1#2% {% \xint_gob_til_^ #2\XINT_iisum_loop_end ^% \expandafter\XINT_iisum_loop\romannumeral0\XINT_add_nfork #1#2% }% % \end{macrocode} %\begin{lverb} % see previous comment! %\end{lverb} % \begin{macrocode} \def\XINT_iisum_loop_end ^#1\XINT_add_nfork #2#3\xint:#4\xint:\xint:{ #2#4}% % \end{macrocode} % \subsection{\csh{xintiiPrd}} %\begin{lverb} % \xintiiPrd {{a}...{z}} % % % Macros renamed and refactored (slightly more macros here to supposedly bring % micro-gain) at 1.4 to match changes in xintfrac of delimiter, in sync with % some usage in xintexpr. % % Contrarily to the xintfrac version \xintPrd, this one aborts as soon as it % hits a zero value. % % %\end{lverb} % \begin{macrocode} \def\xintiiPrd {\romannumeral0\xintiiprd }% \def\xintiiprd #1{\expandafter\XINT_iiprd\romannumeral`&&@#1^}% \def\XINT_iiPrd{\romannumeral0\XINT_iiprd}% % \end{macrocode} %\begin{lverb} % The above romannumeral caused f-expansion of the list argument. % We f-expand below the first item and each successive items because % we do not use \xintiiMul but jump directly into \XINT_mul_nfork. % %\end{lverb} % \begin{macrocode} \def\XINT_iiprd #1% {% \expandafter\XINT_iiprd_a\romannumeral`&&@#1\xint: }% \def\XINT_iiprd_a #1% {% \xint_gob_til_^ #1\XINT_iiprd_empty ^% \xint_gob_til_zero #1\XINT_iiprd_zero 0% \XINT_iiprd_loop #1% }% \def\XINT_iiprd_empty ^#1\xint:{ 1}% \def\XINT_iiprd_zero 0#1^{ 0}% % \end{macrocode} %\begin{lverb} % bad coding as it depends on internal conventions of \XINT_mul_nfork %\end{lverb} % \begin{macrocode} \def\XINT_iiprd_loop #1#2\xint:#3% {% \expandafter\XINT_iiprd_loop_a \expandafter#1\romannumeral`&&@#3\xint:#2\xint:\xint: }% \def\XINT_iiprd_loop_a #1#2% {% \xint_gob_til_^ #2\XINT_iiprd_loop_end ^% \xint_gob_til_zero #2\XINT_iiprd_zero 0% \expandafter\XINT_iiprd_loop\romannumeral0\XINT_mul_nfork #1#2% }% % \end{macrocode} %\begin{lverb} % see previous comment! %\end{lverb} % \begin{macrocode} \def\XINT_iiprd_loop_end ^#1\XINT_mul_nfork #2#3\xint:#4\xint:\xint:{ #2#4}% % \end{macrocode} % \subsection{\csh{xintiiSquareRoot}} %\begin{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.) % %\end{lverb} % % \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.% }% \def\XINT_sqrt_bE #1.#2#3#4% {% \XINT_sqrt_c {#3#4}#2{#1}#3#4% }% \def\XINT_sqrt_bO #1.#2#3% {% \XINT_sqrt_c #3#2{#1}#3% }% \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 .% }% \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 .% }% \def\XINT_sqrt_small_e #1.#2.% {% \expandafter\XINT_sqrt_small_ea\the\numexpr #1*#1-#2.#1.% }% \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}}% \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.% }% \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.% }% \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.% }% \def\XINT_sqrt_small_g #1#2.% {% \if 0#1% \expandafter\XINT_sqrt_small_end \else \expandafter\XINT_sqrt_small_h \fi #1#2.% }% \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}}% \def\XINT_sqrt_big_d #1.#2% {% \ifodd #2 \xint_dothis{\expandafter\XINT_sqrt_big_eO}\fi \xint_orthat{\expandafter\XINT_sqrt_big_eE}% \the\numexpr (#2-\xint_c_i)/\xint_c_ii.#1;% }% \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}% }% \def\XINT_sqrt_big_eE_a #1.#2;#3% {% \expandafter\XINT_sqrt_bigormed_f \romannumeral0\XINT_sqrt_small_e #2000.#3.#1;% }% \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;% }% \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.}% \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.% }% \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.% }% \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}% }% \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} %\begin{lverb} % %\end{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.% }% \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;% }% \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}.% }% \def\XINT_sqrt_big_gd #1.#2.% {% \expandafter\XINT_sqrt_big_ge #2.#1.% }% \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.}% \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.% }% \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.% }% \def\XINT_sqrt_big_gi #1.% {% \expandafter\XINT_sqrt_big_gj\romannumeral\xintreplicate{#1}0.#1.% }% \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.% }% \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}.% }% \def\XINT_sqrt_big_gl #1.#2.% {% \expandafter\XINT_sqrt_big_gm #2.#1.% }% \def\XINT_sqrt_big_gm #1.#2.#3.#4.#5.% {% \expandafter\XINT_sqrt_big_gn \romannumeral0\XINT_split_fromleft\xint_c_ii*#3.#5\xint_bye2345678\xint_bye..% #1.#2.#3.#4.% }% \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.% }% \def\XINT_sqrt_big_ka #1.#2.#3.#4.% {% \expandafter\XINT_sqrt_big_kb \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.% }% \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}% }% \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}% }% \def\XINT_sqrt_big_ke #1% {% \if0\XINT_Sgn #1\xint: \expandafter \XINT_sqrt_big_end \else \expandafter \XINT_sqrt_big_kf \fi {#1}% }% \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.% }% \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} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \begin{macrocode} \def\XINT_binom_fork #1#2.#3#4.#5#6.% {% \if-#5\xint_dothis{\XINT_signalcondition{InvalidOperation}% {Binomial with negative first argument: #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: #5#6 >= 10^8.}{}{ 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} %\begin{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. %\end{lverb} % \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} %\begin{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). %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % Ici on prend trois par trois. %\end{lverb} % \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} %\begin{lverb} % Ici on prend deux par deux. %\end{lverb} % \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} %\begin{lverb} % Et finalement un par un. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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)!% }% \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} %\begin{lverb} % Vaguement envisagé d'éviter le 10^8+ mais bon. %\end{lverb} % \begin{macrocode} \def\XINT_binom_vsmallmuldiv #1!#2!1#3!{\xint_c_x^viii+#2*#3/#1!}% % \end{macrocode} %\begin{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. %\end{lverb} % \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!% }% \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} %\begin{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). %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % Code is a simplified version of the one for \xintiiBinomial, with no % attempt at implementing a "very small" branch. %\end{lverb} % \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 large argument: #2 >= 10^8.}{}{ 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}} %\begin{lverb} % 1.09c %\end{lverb} % \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{\csh{xintiiGCD}} % |1.3d|: |\xintiiGCD| code from \xintgcdnameimp is copied here to % support |gcd()| function in \csbxint{iiexpr}. % % |1.4|: removed from \xintgcdnameimp the original caode as now % \xintgcdnameimp loads \xintnameimp. % % \changed[2021/03/22]{1.4d} Damn'ed! Since |1.3d| (2019/01/06) the code was % broken if one of the arguments vanished due to a typo in macro names: % "AisZero" at one location and "Aiszero" at next, and same for B... % % How could this not be detected by my tests !?! % % This caused |\xintiiGCDof| hence the |gcd()| function in |\xintiiexpr| to % break as soon as one argument was zero. % \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{\csh{xintiiGCDof}} %\begin{lverb} % New with 1.09a (was located in xintgcd.sty). % % 1.2l adds protection against items being non-terminated \the\numexpr. % % 1.4 renames the macro into \xintiiGCDof and moves it here. % Terminator modified to ^ for direct call by \xintiiexpr function. % % 1.4d fixes breakage inherited since 1.3d rom \xintiiGCD, in case % any argument vanished. % % Currently does not support empty list of arguments. %\end{lverb} % \begin{macrocode} \def\xintiiGCDof {\romannumeral0\xintiigcdof }% \def\xintiigcdof #1{\expandafter\XINT_iigcdof_a\romannumeral`&&@#1^}% \def\XINT_iiGCDof {\romannumeral0\XINT_iigcdof_a}% \def\XINT_iigcdof_a #1{\expandafter\XINT_iigcdof_b\romannumeral`&&@#1!}% \def\XINT_iigcdof_b #1!#2{\expandafter\XINT_iigcdof_c\romannumeral`&&@#2!{#1}!}% \def\XINT_iigcdof_c #1{\xint_gob_til_^ #1\XINT_iigcdof_e ^\XINT_iigcdof_d #1}% \def\XINT_iigcdof_d #1!{\expandafter\XINT_iigcdof_b\romannumeral0\xintiigcd {#1}}% \def\XINT_iigcdof_e #1!#2!{ #2}% % \end{macrocode} % \subsection{\csh{xintiiLCM}} % Copied over |\xintiiLCM| code from \xintgcdnameimp at |1.3d| in order to % support |lcm()| function in \csbxint{iiexpr}. % % At |1.4| original code removed from \xintgcdnameimp as the latter now requires % \xintnameimp. % \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{\csh{xintiiLCMof}} %\begin{lverb} % See comments of \xintiiGCDof. %\end{lverb} % \begin{macrocode} \def\xintiiLCMof {\romannumeral0\xintiilcmof }% \def\xintiilcmof #1{\expandafter\XINT_iilcmof_a\romannumeral`&&@#1^}% \def\XINT_iiLCMof {\romannumeral0\XINT_iilcmof_a}% \def\XINT_iilcmof_a #1{\expandafter\XINT_iilcmof_b\romannumeral`&&@#1!}% \def\XINT_iilcmof_b #1!#2{\expandafter\XINT_iilcmof_c\romannumeral`&&@#2!{#1}!}% \def\XINT_iilcmof_c #1{\xint_gob_til_^ #1\XINT_iilcmof_e ^\XINT_iilcmof_d #1}% \def\XINT_iilcmof_d #1!{\expandafter\XINT_iilcmof_b\romannumeral0\xintiilcm {#1}}% \def\XINT_iilcmof_e #1!#2!{ #2}% % \end{macrocode} % \subsection{(WIP) \csh{xintRandomDigits}} %\begin{lverb} % 1.3b. See user manual. Whether this will be part of xintkernel, % xintcore, or xint is yet to be decided. %\end{lverb} % \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}, \csh{xintEightRandomDigits}} %\begin{lverb} % 1.3b. 1.4 adds some public alias... %\end{lverb} % \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% }% \let\xintEightRandomDigits\XINT_eightrandomdigits \def\xintRandBit{\xint_texuniformdeviate\xint_c_ii}% % \end{macrocode} % \subsection{(WIP) \csh{xintRandBit}} %\begin{lverb} % 1.4 And let's add also \xintRandBit while we are at it. %\end{lverb} % \begin{macrocode} \def\xintRandBit{\xint_texuniformdeviate\xint_c_ii}% % \end{macrocode} % \subsection{(WIP) \csh{xintXRandomDigits}} %\begin{lverb} % 1.3b. %\end{lverb} % \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}} %\begin{lverb} % 1.3b. Support for randrange() function. % % We 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. %\end{lverb} % \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}} %\begin{lverb} % 1.3b. Support for randrange(). %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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... %\end{lverb} % \begin{macrocode} \def\XINT_randrange_Z 0\xint:#1\xint:#2\xint: {% \xintinum{\xintRandomDigits{#1-\xint_c_viii}}% }% % \end{macrocode} %\begin{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. %\end{lverb} % \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{(WIP) Adjustments for engines without uniformdeviate primitive} %\begin{lverb} % 1.3b. %\end{lverb} % \begin{macrocode} \ifdefined\xint_texuniformdeviate \else \def\xintrandomdigits#1% {% \XINT_expandableerror {No uniformdeviate at engine level.} 0% }% \let\xintXRandomDigits\xintRandomDigits \def\XINT_randrange#1\xint: {% \XINT_expandableerror {No uniformdeviate at engine level.} 0% }% \fi \XINTrestorecatcodesendinput% % \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; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintbinhexnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \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 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintbinhex.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintkernel.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintbinhex Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xintbinhex}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\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 \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 \def\z{\endgroup\endinput}% xintbinhex already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintbinhex}% [2022/06/10 v1.4m Expandable binary and hexadecimal conversions (JFB)]% % \end{macrocode} % \subsection{Constants, etc...} %\begin{lverb} % 1.2n switches to \csname-governed expansion at various places. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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). %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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}} %\begin{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$empty: increased maximal size. % % An input without leading zeroes gives an output without leading zeroes. % % Most of the code canvas is shared with \xintDecToHex. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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.) %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}% \XINTrestorecatcodesendinput% % \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; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintgcdnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \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|. % % % 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|. % % From |1.1| to |1.3f| the package loaded only \xintcorenameimp. At |1.4| it % now automatically loads both of \xintnameimp and \xinttoolsnameimp (the % latter being in fact a requirement of \csbxint{TypesetEuclideAlgorithm} and % \csbxint{TypesetBezoutAlgorithm} since |1.09h|). % % \begin{framed} % At |1.4| \csbxint{GCD}, \csbxint{LCM}, \csbxint{GCDof}, and \csbxint{LCMof} % are \emph{removed} from the package:\IMPORTANTf they are provided only by % \xintfracnameimp and they handle general fractions, not only integers. % % The original\CHANGEDf{1.4} integer-only macros have been renamed into respectively % \csbxint{iiGCD}, \csbxint{iiLCM}, \csbxint{iiGCDof}, and \csbxint{iiLCMof} % and got relocated into \xintnameimp package. % \end{framed} % % \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 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintgcd.sty\endcsname \expandafter\let\expandafter\w\csname ver@xint.sty\endcsname \expandafter\let\expandafter\t\csname ver@xinttools.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintgcd Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xintgcd}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % plain-TeX, first loading of xintgcd.sty \ifx\w\relax % but xint.sty not yet loaded. \expandafter\def\expandafter\z\expandafter{\z\input xint.sty\relax}% \fi \ifx\t\relax % but xinttools.sty not yet loaded. \expandafter\def\expandafter\z\expandafter{\z\input xinttools.sty\relax}% \fi \else \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen \ifx\w\relax % xint.sty not yet loaded. \expandafter\def\expandafter\z\expandafter{\z\RequirePackage{xint}}% \fi \ifx\t\relax % xinttools.sty not yet loaded. \expandafter\def\expandafter\z\expandafter{\z\RequirePackage{xinttools}}% \fi \else \def\z{\endgroup\endinput}% xintgcd already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintgcd}% [2022/06/10 v1.4m Euclide algorithm with xint package (JFB)]% % \end{macrocode} % \subsection{\csh{xintBezout}} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % #3#4 = A, #1#2=B. Micro improvement for 1.2l. %\end{lverb} % \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} %\begin{lverb} % #4#2= A < 0, #3#1 = B < 0 %\end{lverb} % \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} %\begin{lverb} % minusplus #4#2= A > 0, B < 0 %\end{lverb} % \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} %\begin{lverb} % plusminus A < 0, B > 0 %\end{lverb} % \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} %\begin{lverb} % plusplus, B = #3#1 > 0, A = #4#2 > 0 %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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... %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % Ici #3#4=A, #1#2=B %\end{lverb} % \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} %\begin{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} %\end{lverb} % \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} %\begin{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 %\end{lverb} % \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} %\begin{lverb} % {n+1}{q(n+1)}{r(n+1)}{rn}{{qn}{rn}}... %\end{lverb} % \begin{macrocode} \def\XINT_euc_b #1.#2#3#4% {% \XINT_euc_c #3\Z {#1}{#3}{#4}{{#2}{#3}}% }% % \end{macrocode} %\begin{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. %\end{lverb} % \begin{macrocode} \def\XINT_euc_c #1#2\Z {% \xint_gob_til_zero #1\XINT_euc_end0\XINT_euc_a }% % \end{macrocode} %\begin{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} %\end{lverb} % \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}} %\begin{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 %\end{lverb} % \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} %\begin{lverb} % Ici #3#4=A, #1#2=B %\end{lverb} % \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} %\begin{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 %\end{lverb} % \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} %\begin{lverb} % {n+1}{q(n+1)}{r(n+1)}{r(n)}{alpha(n)}{beta(n)}{alpha(n-1)}{beta(n-1)}... %\end{lverb} % \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} %\begin{lverb} % {beta(n+1)}{alpha(n+1)}{n+1}{q(n+1)}{r(n+1)}{r(n)}{alpha(n)}{beta(n}} %\end{lverb} % \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} %\begin{lverb} % {alpha(n+1)}{n+1}{q(n+1)}{r(n+1)}{r(n)}{beta(n+1)} %\end{lverb} % \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} %\begin{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. %\end{lverb} % \begin{macrocode} \def\XINT_bezalg_e #1#2\Z {% \xint_gob_til_zero #1\XINT_bezalg_end0\XINT_bezalg_a }% % \end{macrocode} %\begin{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} %\end{lverb} % \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} %\begin{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} %\end{lverb} % \begin{macrocode} \def\XINT_bezalg_end_a #1#2#3#4{{#1}{#3}{0}{1}{#2}{#4}{1}{0}}% % \end{macrocode} % \subsection{\csh{xintTypesetEuclideAlgorithm}} %\begin{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 %\end{lverb} % \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}} %\begin{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 %\end{lverb} % \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 }% \XINTrestorecatcodesendinput% % \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: 72; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintfracnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \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 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintfrac.sty\endcsname \expandafter\let\expandafter\w\csname ver@xint.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintfrac Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xintfrac}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\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 \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 \def\z{\endgroup\endinput}% xintfrac already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintfrac}% [2022/06/10 v1.4m Expandable operations on fractions (JFB)]% % \end{macrocode} % \subsection{\csh{XINT_cntSgnFork}} %\begin{lverb} % 1.09i. Used internally, #1 must expand to \m@ne, \z@, or \@ne or % equivalent. \XINT_cntSgnFork does not insert a romannumeral stopper. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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% \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}} % \changed{1.06b} %\begin{lverb} % 1.06b version now outputs 0/1[0] and not 0[0] in case of zero. More generally % all macros have been checked in xintfrac, xintseries, xintcfrac, to make sure % the output format for fractions was always A/B[n]. (except \xintIrr, % \xintJrr, \xintRawWithZeros). % % 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. %\end{lverb} % \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[#3]% {% \XINT_signalcondition{DivisionByZero}{Division by zero: #1/#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}} % \added{1.03} %\begin{lverb} % Parses fraction, scientific notation, etc... and produces {n}{A}{B} % corresponding to A/B times 10^n. No reduction to smallest terms. %\end{lverb} % \changed{1.07} %\begin{lverb} % 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. %\end{lverb} % \changed[2015/10/09]{1.2} %\begin{lverb} % This venerable macro from the very early days % 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$empty: 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. %\end{lverb} % \changed{1.2l} %\begin{lverb} % 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. %\end{lverb} % \changed{1.4l} %\begin{lverb} % The venerable \XINT_inFrac is used nowhere, only \XINT_infrac is. % It is deprecated and I will remove it at next major release. % See \xintRawBraced. %\end{lverb} % \begin{macrocode} \def\XINT_inFrac {\XINT_expandableerror{\XINT_inFrac is deprecated, use \xintRawBraced}% \romannumeral0\XINT_infrac }% \def\XINT_infrac #1% this one is core xintfrac macro {% \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} %\begin{lverb} % Note that input exponent is here ignored and forced to be zero. %\end{lverb} % \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} %\begin{lverb} % An empty [] is not allowed. (this was authorized in 1.2, removed in % 1.2f). %\end{lverb} % \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}} % \changed{1.07} %\begin{lverb} % Extended at 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 %\end{lverb} % \changed{1.2} %\begin{lverb} % Completely rewritten. 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. %\end{lverb} % \changed{1.2f} %\begin{lverb} % 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. %\end{lverb} % \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} %\begin{lverb} % Note that #1 is only expanded so far up to decimal mark or "e". %\end{lverb} % \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% }% \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-% \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\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 by zero: #1/0.}{}{{#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}} %\begin{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! %\end{lverb} % \changed{1.3a} %\begin{lverb} % 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. %\end{lverb} % \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}}}} % %\begin{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. %\end{lverb} % \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}} % \added{1.07} %\begin{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. %\end{lverb} % \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{xintRawBraced}} % \added{1.4l} %\begin{lverb} % User level interface to core \romannumeral0\XINT_infrac. Replaces % \XINT_inFrac which was defined but nowhere used by the xint packages. %\end{lverb} % \begin{macrocode} \def\xintRawBraced {\romannumeral0\xintrawbraced }% \let\xintrawbraced \XINT_infrac % \end{macrocode} % \subsection{\csh{xintiLogTen}} % \added{1.3e} %\begin{lverb} % The exponent a, such that 10^a<= abs(x) < 10^(a+1). No rounding done on x, % handled as an exact fraction. %\end{lverb} % \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}} % \added{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{xintSPRaw}} %\begin{lverb} % This private macro was for internal usage by \xinttheexpr. % It got moved here % at 1.4 and is not used anymore by the package. % % It checks if input has a [N] part, if yes uses \xintPRaw, else % simply lets the input pass through as is. %\end{lverb} % \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}}% % \end{macrocode} % \subsection{\csh{xintFracToSci}} % \added{1.4l} %\begin{lverb} % The macro with this name which was added here at 1.4 then had % various changes and finally was moved to $xintexprnameimp at 1.4k % is now called there % \xint_FracToSci_x and is private. The present macro is public and % behaves like the other $xintfracnameimp macros: f-expandable and % accepts general input. Its output is exactly the same as % \xint_FracToSci_x for same inputs, with the exception of the empty % input which \xintFracToSci will output as 0 but \xint_FracToSci_x % as empty. But the latter is not used by \xinteval for an empty % leaf as it employs then \xintexprEmptyItem. %\end{lverb} % \begin{macrocode} \def\xintFracToSci{\romannumeral0\xintfractosci}% \def\xintfractosci#1{\expandafter\XINT_fractosci\romannumeral0\xintraw{#1}}% \def\XINT_fractosci#1#2/#3[#4]{\expanded{ % \ifnum#4=\xint_c_ #1#2\else \romannumeral0\expandafter\XINT_pfloat_a_fork\romannumeral0\xintrez{#1#2[#4]}% \fi \if\XINT_isOne{#3}1\else\if#10\else/#3\fi\fi}% }% % \end{macrocode} % \subsection{\csh{xintFracToDecimal}} % \added{1.4l} %\begin{lverb} % The macro with this name which was added at 1.4k to % $xintexprnameimp has been removed. The public variant here % behaves like the other % $xintfracnameimp macros: f-expandable and accepts general input. %\end{lverb} % \begin{macrocode} \def\xintFracToDecimal{\romannumeral0\xintfractodecimal}% \def\xintfractodecimal#1{\expandafter\XINT_fractodecimal\romannumeral0\xintraw{#1}}% \def\XINT_fractodecimal #1#2/#3[#4]{\expanded{ % \ifnum#4=\xint_c_ #1#2\else \romannumeral0\expandafter\XINT_dectostr\romannumeral0\xintrez{#1#2[#4]}% \fi \if\XINT_isOne{#3}1\else\if#10\else/#3\fi\fi}% }% % \end{macrocode} % \subsection{\csh{xintRawWithZeros}} %\begin{lverb} % This was called \xintRaw in versions earlier than 1.07 %\end{lverb} % \begin{macrocode} \def\xintRawWithZeros {\romannumeral0\xintrawwithzeros }% \def\xintrawwithzeros {% \expandafter\XINT_rawz_fork\romannumeral0\XINT_infrac }% \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}} % \added{1.3} %\begin{lverb} % This is a backport from polexpr 0.4. It is definitely not in % final form, consider it to be an unstable macro. %\end{lverb} % \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{xintDecToStringREZ}} % \added{1.4e} %\begin{lverb} % And I took this opportunity to improve documentation in manual. %\end{lverb} % \begin{macrocode} \def\xintDecToStringREZ{\romannumeral0\xintdectostringrez}% \def\xintdectostringrez#1{\expandafter\XINT_dectostr\romannumeral0\xintrez{#1}}% % \end{macrocode} % \subsection{\csh{xintFloor}, \csh{xintiFloor}} % \added{1.09a} %\begin{lverb} % 1.1 for \xintiFloor/\xintFloor. Not efficient if big negative % decimal exponent. Also sub-efficient if big positive decimal exponent. %\end{lverb} % \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}} % \added{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% {% \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{xintTeXFrac}} % \added{1.03} %\begin{lverb} % Useless typesetting macro. %\end{lverb} % \changed[2021/05/24]{1.4g} %\begin{lverb} % Renamed from \xintFrac. %\end{lverb} % \changed{1.4m} % The old name now raises an error, not a warning. % \begin{macrocode} \ifdefined\PackageWarning \def\xintfracTeXDeprecation#1#2{% \PackageWarning{xintfrac}{\string#1 is deprecated. Use \string#2\MessageBreak to suppress this warning}#2% }% \else \edef\xintfracTeXDeprecation#1#2{{\newlinechar10 \immediate\noexpand\write128{&&JPackage xintfrac Warning: \noexpand\string#1 is deprecated. Use \noexpand\string#2&&J% (xintfrac)\xintReplicate{16}{ }to suppress this warning on input line \noexpand\the\inputlineno.&&J}}#2% }% \fi \ifdefined\PackageError \def\xintfracTeXError#1#2{% \PackageError{xintfrac}{\string#1 has been removed.\MessageBreak Use \string#2 to suppress this error}% {I will fix it for now if you hit the `Return' key.}#2% }% \else \edef\xintfracTeXError#1#2{{\newlinechar10 \errhelp{I will fix it for now if you hit the `Return' key.}% \errmessage{Package xintfrac Error: \noexpand\string#1 has been removed.&&J% (xintfrac)\xintReplicate{16}{ }Use \noexpand\string#2 to suppress this error}}#2% }% \fi \def\xintFrac {\xintfracTeXError\xintFrac\xintTeXFrac}% \def\xintTeXFrac{\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{xintTeXsignedFrac}} % \changed[2021/05/24]{1.4g} %\begin{lverb} % Renamed from \xintSignedFrac. %\end{lverb} % \changed{1.4m} % The old name now raises an error, not a warning. % \begin{macrocode} \def\xintSignedFrac {\xintfracTeXError\xintSignedFrac\xintTeXsignedFrac}% \def\xintTeXsignedFrac{\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{xintTeXFromSci}} % \added{1.4g} %\begin{lverb} % The main problem is how to name this and related macros. % % I use \expanded here, as \xintFracToSci is not f-expandable. % % Some complications as I want this to be usable on output of \xintFracToSci % hence need to handle the case of a /B. After some hesitations I ended with % the following which looks reasonable: %(- if no scientific part, use \frac (or \over) for A/B %:- if scientific part, postfix /B as \cdot B^{-1} %) %\end{lverb} % \changed{1.4l} %\begin{lverb} % Suppress external \expanded. Keep internal one. % % Rename \xintTeXFromSci from \xintTeXfromSci. Keep deprecated old name % for the moment. % % Add \xintTeXFromScifracmacro. Make it \protected. % % Nota bene: catcode of ^ is normal one here (else nothing would work). %\end{lverb} % \begin{macrocode} \def\xintTeXfromSci{\xintfracTeXDeprecated\xintTeXfromSci\xintTeXFromSci}% \def\xintTeXFromSci#1% {% \expandafter\XINT_texfromsci\expanded{#1}/\relax/\xint: }% \def\XINT_texfromsci #1/#2#3/#4\xint: {% \XINT_texfromsci_a #1e\relax e\xint: {\ifx\relax#2\xint_dothis\xint_firstofone\fi \xint_orthat{\xintTeXFromScifracmacro{#2#3}}}% {\unless\ifx\relax#2\cdot{#2#3}^{-1}\fi}% }% \def\XINT_texfromsci_a #1e#2#3e#4\xint:#5#6% {% \ifx\relax#2#5{#1}\else#1\cdot10^{#2#3}#6\fi }% \ifdefined\frac \protected\def\xintTeXFromScifracmacro#1#2{\frac{#2}{#1}}% \else \protected\def\xintTeXFromScifracmacro#1#2{{#2\over#1}}% \fi % \end{macrocode} % \subsection{\csh{xintTeXOver}} % \changed[2021/05/24]{1.4g} %\begin{lverb} % Renamed from \xintFwOver. %\end{lverb} % \changed{1.4m} % The old name now raises an error, not a warning. % \begin{macrocode} \def\xintFwOver {\xintfracTeXError\xintFwOver\xintTeXOver}% \def\xintTeXOver{\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{xintTeXsignedOver}} % \changed[2021/05/24]{1.4g} %\begin{lverb} % Renamed from \xintSignedFwOver. %\end{lverb} % \changed{1.4m} % The old name now raises an error, not a warning. % \begin{macrocode} \def\xintSignedFwOver {\xintfracTeXError\xintSignedFwOver\xintTeXsignedOver}% \def\xintTeXsignedOver{\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}} %\begin{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. %\end{lverb} % \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}} % \added{1.07} %\begin{lverb} % The fraction is the first argument contrarily to \xintTrunc and % \xintRound. %\end{lverb} % \changed{1.1} %\begin{lverb} % 1.1 modifies and moves \xintiiE to xint.sty. %\end{lverb} % \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}} % \changed{1.04} %\begin{lverb} % fixes a buggy \xintIrr {0}. %\end{lverb} % \changed{1.05} %\begin{lverb} % modifies the initial parsing and post-processing to use \xintrawwithzeros % and to more quickly deal with an input denominator equal to 1. %\end{lverb} % \changed{1.08} %\begin{lverb} % this version does not remove a /1 denominator. %\end{lverb} % \changed{1.3} %\begin{lverb} % added \xintPIrr (partial Irr, which ignores the decimal part). %\end{lverb} % \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}{0/0 indeterminate fraction.}{}{ 0/1}% }% \def\XINT_irr_divisionbyzero #1#2#3#4#5% {% \XINT_signalcondition{DivisionByZero}{Division by zero: #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}} %\begin{lverb} % Added at 1.3d only, for isint() xintexpr function. %\end{lverb} % \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}{0/0 indeterminate fraction.}{}{ 0/1}% }% \def\XINT_jrr_divisionbyzero #1#2#3#4#5#6#7% {% \XINT_signalcondition{DivisionByZero}{Division by zero: #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}} % \added{1.09i} %\begin{lverb} % 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. %\end{lverb} % \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}} %\begin{lverb} % % This of course has a long history. Only showing here some comments. %\end{lverb} % \changed{1.2i} %\begin{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. %\end{lverb} % \changed[2020/02/18]{1.4a} %\begin{lverb} % % Adds handling of a negative first argument. % % Zero input still gives single digit 0 output as I did not want to complicate % the code. But if quantization gives 0, the exponent [D] will be there. Well % actually eD because of problem that sign of original is preserved in output % so we can have -0 and I can not use -0[D] notation as it is not legal for % strict format. So I will use -0eD hence eD generally even though this means % so slight suboptimality for trunc() function in \xintexpr. % % The idea to give a meaning to negative D (in the context of optional % argument to \xintiexpr) was suggested a long time ago by Kpym (October 20, % 2015). His suggestion was then to treat it as positive D but trim trailing % zeroes. But since then, there is \xintDecToString which can be combined with % \xintREZ, and I feel matters of formatting output require a whole module (or % rather use existing third-party tools), and I decided to opt rather for an % operation similar as the quantize() of Python Decimal module. I.e. we % truncate (or round) to an integer multiple of a given power of 10. % % Other reason to decide to do this is that it looks as if I don't even need % to understand the original code to hack into its ending via \XINT_trunc_G or % \XINT_itrunc_G. For the latter it looks as if logically I simply have to do % nothing. For the former I simply have to add some eD postfix. %\end{lverb} % \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}% \def\XINT_trunc_b {\expandafter\XINT_trunc_B\the\numexpr}% \def\XINT_trunc_sp_b {\expandafter\XINT_trunc_sp_B\the\numexpr}% \def\XINT_trunc_B #1% {% \xint_UDsignfork #1\XINT_trunc_C -\XINT_trunc_D \krof #1% }% \def\XINT_trunc_sp_B #1% {% \xint_UDsignfork #1\XINT_trunc_sp_C -\XINT_trunc_sp_D \krof #1% }% \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}}% \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 \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% }% \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#4.% {% \xint_gob_til_minus#3\XINT_trunc_Hc-% \expandafter\XINT_trunc_H \the\numexpr\romannumeral0\xintlength {#1}-#3#4.#3#4.{#1}#2% }% \def\XINT_trunc_Hc-\expandafter\XINT_trunc_H \the\numexpr\romannumeral0\xintlength #1.-#2.#3#4{#4#3e#2}% \def\XINT_trunc_H #1.#2.% {% \ifnum #1 > \xint_c_ \xint_dothis{\XINT_trunc_Ha {#2}}\fi \xint_orthat {\XINT_trunc_Hb {-#1}}% -0,--1,--2, .... }% \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.% \romannumeral\xintreplicate{#1}0#2% }% % \end{macrocode} % \subsection{\csh{xintTTrunc}} % \added{1.1} % \begin{macrocode} \def\xintTTrunc {\romannumeral0\xintttrunc }% \def\xintttrunc {\xintitrunc\xint_c_}% % \end{macrocode} % \subsection{\csh{xintNum}, \csh{xintnum}} % \begin{macrocode} \let\xintnum \xintttrunc % \end{macrocode} % \subsection{\csh{xintRound}, \csh{xintiRound}} %\begin{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. % % At 1.4a, first argument can be negative. This is handled at \XINT_trunc_G. % %\end{lverb} % \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}} % \added[2014/01/06]{1.09j} %\begin{lverb} % This is completely expandable but not f-expandable. %\end{lverb} % \changed[2016/12/04]{1.2i} %\begin{lverb} % Rewritten: % % - 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 %\end{lverb} % \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.% }% \def\XINT_xtrunc_b #1.#2{\XINT_xtrunc_c #2{#1}}% \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}% \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}% }% \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!}% }% \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 }% \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 }% \def\XINT_xtrunc_prepare_g #1;{\XINT_xtrunc_e {#1}}% \def\XINT_xtrunc_e #1#2% {% \ifnum #2<\xint_c_ \expandafter\XINT_xtrunc_I \else \expandafter\XINT_xtrunc_II \fi #2\xint:{#1}% }% \def\XINT_xtrunc_I -#1\xint:#2#3#4% {% \expandafter\XINT_xtrunc_I_a\romannumeral0#2{#4}{#2}{#1}{#3}% }% \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}% }% \def\XINT_xtrunc_I_b #1% {% \xint_UDsignfork #1\XINT_xtrunc_IA_c -\XINT_xtrunc_IB_c \krof #1% }% \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}% }% \def\XINT_xtrunc_IA_d #1% {% \xint_UDsignfork #1\XINT_xtrunc_IAA_e -\XINT_xtrunc_IAB_e \krof #1% }% \def\XINT_xtrunc_IAA_e -#1\xint:#2% {% \romannumeral0\XINT_split_fromleft #1.#2\xint_gobble_i\xint_bye2345678\xint_bye..% }% \def\XINT_xtrunc_IAB_e #1\xint:#2% {% 0.\romannumeral\XINT_rep#1\endcsname0#2% }% \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:% }% \def\XINT_xtrunc_IA_xe #1\xint:#2\xint:#3#4% {% \XINT_xtrunc_loop {#2}{#4}{#3}{#1}% }% \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}% }% \def\XINT_xtrunc_IB_d #1.#2.#3% {% \expandafter\XINT_xtrunc_IA_d\the\numexpr#3-\xintLength {#1}\xint:{#1}% }% \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:% }% \def\XINT_xtrunc_II_c #1\xint:#2\xint:#3#4#5% {% #3.\XINT_xtrunc_loop {#2}{#4}{#5}{#1}% }% \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}% }% \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% }% \def\XINT_xtrunc_sp_e #1% {% \ifnum #1<\xint_c_ \expandafter\XINT_xtrunc_sp_I \else \expandafter\XINT_xtrunc_sp_II \fi #1\xint:% }% \def\XINT_xtrunc_sp_I -#1\xint:#2#3% {% \expandafter\XINT_xtrunc_sp_I_a\the\numexpr #1-#3\xint:#1\xint:{#3}{#2}% }% \def\XINT_xtrunc_sp_I_a #1% {% \xint_UDsignfork #1\XINT_xtrunc_sp_IA_b -\XINT_xtrunc_sp_IB_b \krof #1% }% \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% }% \def\XINT_xtrunc_sp_IA_c #1% {% \xint_UDsignfork #1\XINT_xtrunc_sp_IAA -\XINT_xtrunc_sp_IAB \krof #1% }% \def\XINT_xtrunc_sp_IAA -#1\xint:#2% {% \romannumeral0\XINT_split_fromleft #1.#2\xint_gobble_i\xint_bye2345678\xint_bye..% }% \def\XINT_xtrunc_sp_IAB #1\xint:#2% {% 0.\romannumeral\XINT_rep#1\endcsname0#2% }% \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}% }% \def\XINT_xtrunc_sp_IB_c #1.#2.#3% {% \expandafter\XINT_xtrunc_sp_IA_c\the\numexpr#3-\xintLength {#1}\xint:{#1}% }% \def\XINT_xtrunc_sp_II #1\xint:#2#3% {% #2\romannumeral\XINT_rep#1\endcsname0.\romannumeral\XINT_rep#3\endcsname0% }% % \end{macrocode} % \subsection{\csh{xintAdd}} % \changed{1.3} %\begin{lverb} % Big change at 1.3: a/b+c/d uses lcm(b,d) as denominator. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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}} % \changed{1.3} %\begin{lverb} % Since 1.3 will use least common multiple of denominators. %\end{lverb} % \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}} %\begin{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 in the input are not accepted by this macro, but the input % may be empty. % % Refactored slightly at 1.4. \XINT_Sum used in xintexpr code. %\end{lverb} % \begin{macrocode} \def\xintSum {\romannumeral0\xintsum }% \def\xintsum #1{\expandafter\XINT_sum\romannumeral`&&@#1^}% \def\XINT_Sum{\romannumeral0\XINT_sum}% \def\XINT_sum#1% {% \xint_gob_til_^ #1\XINT_sum_empty ^% \expandafter\XINT_sum_loop\romannumeral0\xintraw{#1}\xint: }% \def\XINT_sum_empty ^#1\xint:{ 0/1[0]}% \def\XINT_sum_loop #1\xint:#2% {% \xint_gob_til_^ #2\XINT_sum_end ^% \expandafter\XINT_sum_loop \romannumeral0\xintadd{#1}{\romannumeral0\xintraw{#2}}\xint: }% \def\XINT_sum_end ^#1\xintadd #2#3\xint:{ #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}} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{lverb} % Factorial coefficients: variant which can be chained with other % xintfrac macros. %\end{lverb} % \begin{macrocode} \def\xintFac {\romannumeral0\xintfac}% \def\xintfac #1{\expandafter\XINT_fac_fork\the\numexpr\xintNum{#1}.[0]}% % \end{macrocode} % \subsection{\csh{xintBinomial}} % \added{1.2f} % \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}} % \added{1.2f} %\begin{lverb} % Partial factorial. For needs of xintexpr.sty. %\end{lverb} % \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}} %\begin{lverb} % Refactored at 1.4. After some hesitation the routine still does % not try to detect on the fly a zero item, to abort the loop. Indeed % this would add some overhead generally (as we need normalizing the item before % checking if it vanishes hence we must then grab things once more). %\end{lverb} % \begin{macrocode} \def\xintPrd {\romannumeral0\xintprd }% \def\xintprd #1{\expandafter\XINT_prd\romannumeral`&&@#1^}% \def\XINT_Prd{\romannumeral0\XINT_prd}% \def\XINT_prd#1% {% \xint_gob_til_^ #1\XINT_prd_empty ^% \expandafter\XINT_prd_loop\romannumeral0\xintraw{#1}\xint: }% \def\XINT_prd_empty ^#1\xint:{ 1/1[0]}% \def\XINT_prd_loop #1\xint:#2% {% \xint_gob_til_^ #2\XINT_prd_end ^% \expandafter\XINT_prd_loop \romannumeral0\xintmul{#1}{\romannumeral0\xintraw{#2}}\xint: }% \def\XINT_prd_end ^#1\xintmul #2#3\xint:{ #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}} % \added{1.1} %\begin{lverb} % Changed at 1.2p to not append /1[0] ending but rather output a % big integer in strict format, like \xintDivTrunc and \xintDivRound. %\end{lverb} % \begin{macrocode} \def\xintDivFloor {\romannumeral0\xintdivfloor }% \def\xintdivfloor #1#2{\xintifloor{\xintDiv {#1}{#2}}}% % \end{macrocode} % \subsection{\csh{xintDivTrunc}} % \added{1.1} % \begin{macrocode} \def\xintDivTrunc {\romannumeral0\xintdivtrunc }% \def\xintdivtrunc #1#2{\xintttrunc {\xintDiv {#1}{#2}}}% % \end{macrocode} % \subsection{\csh{xintDivRound}} %\begin{lverb} % 1.1 %\end{lverb} % \begin{macrocode} \def\xintDivRound {\romannumeral0\xintdivround }% \def\xintdivround #1#2{\xintiround 0{\xintDiv {#1}{#2}}}% % \end{macrocode} % \subsection{\csh{xintModTrunc}} % \added{1.1} %\begin{lverb} % \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. %\end{lverb} % \changed{1.3} %\begin{lverb} % At 1.3, uses least common multiple denominator, like \xintMod (next). %\end{lverb} % \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 zero: #1#4/(#2[#3]).}{}{ 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} %\begin{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). %\end{lverb} % \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}} % \added{1.2p} %\begin{lverb} % \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. %\end{lverb} % \changed{1.3} %\begin{lverb} % Modified (like \xintAdd and \xintSub) at 1.3 to use a l.c.m for final % denominator of the "mod" part. %\end{lverb} % \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 zero: #1#4/(#2[#3]).}{}% {{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}} % \added{1.2p} %\begin{lverb} % \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. %\end{lverb} % \changed{1.3} %\begin{lverb} % Modified (like \xintAdd and \xintSub) at 1.3 to use a l.c.m for final % denominator. %\end{lverb} % \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} %\begin{lverb} % Attention to not move ModTrunc code beyond that point. %\end{lverb} % \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}} % \added{1.09a} %\begin{lverb} % Could be more efficient. For fractions with big % powers of tens, it is better to use \xintCmp{f}{1}. Restyled in 1.09i. %\end{lverb} % \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 }% \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}} %\begin{lverb} % 1.2l protects \xintMaxof against items with non terminated % \the\numexpr expressions. % % 1.4 renders the macro compatible with an empty argument and it also defines % an accessor \XINT_Maxof suitable for xintexpr usage (formerly xintexpr % had its own macro handling comma separated values, but it changed % internal representation at 1.4). % %\end{lverb} % \begin{macrocode} \def\xintMaxof {\romannumeral0\xintmaxof }% \def\xintmaxof #1{\expandafter\XINT_maxof\romannumeral`&&@#1^}% \def\XINT_Maxof{\romannumeral0\XINT_maxof}% \def\XINT_maxof#1% {% \xint_gob_til_^ #1\XINT_maxof_empty ^% \expandafter\XINT_maxof_loop\romannumeral0\xintraw{#1}\xint: }% \def\XINT_maxof_empty ^#1\xint:{ 0/1[0]}% \def\XINT_maxof_loop #1\xint:#2% {% \xint_gob_til_^ #2\XINT_maxof_e ^% \expandafter\XINT_maxof_loop \romannumeral0\xintmax{#1}{\romannumeral0\xintraw{#2}}\xint: }% \def\XINT_maxof_e ^#1\xintmax #2#3\xint:{ #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}} %\begin{lverb} % 1.2l protects \xintMinof against items with non terminated % \the\numexpr expressions. % % 1.4 version is compatible with an empty input (empty items are handled as zero). %\end{lverb} % \begin{macrocode} \def\xintMinof {\romannumeral0\xintminof }% \def\xintminof #1{\expandafter\XINT_minof\romannumeral`&&@#1^}% \def\XINT_Minof{\romannumeral0\XINT_minof}% \def\XINT_minof#1% {% \xint_gob_til_^ #1\XINT_minof_empty ^% \expandafter\XINT_minof_loop\romannumeral0\xintraw{#1}\xint: }% \def\XINT_minof_empty ^#1\xint:{ 0/1[0]}% \def\XINT_minof_loop #1\xint:#2% {% \xint_gob_til_^ #2\XINT_minof_e ^% \expandafter\XINT_minof_loop\romannumeral0\xintmin{#1}{\romannumeral0\xintraw{#2}}\xint: }% \def\XINT_minof_e ^#1\xintmin #2#3\xint:{ #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 }% \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}{Inverse of zero: inv(#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{\csh{xintSignBit}} % \added{1.4l} % \begin{macrocode} \def\xintSignBit {\romannumeral0\xintsignbit }% \def\xintsignbit #1{\expandafter\XINT_signbit\romannumeral0\xintraw {#1}\xint:}% \def\XINT_signbit #1#2\xint: {% \xint_UDzerominusfork #1-{ 0}% 0#1{ 1}% 0-{ 0}% \krof }% % \end{macrocode} % \subsection{\csh{xintGCD}} % \changed{1.4} % They replace the former \xintgcdnameimp macros of the same names which % truncated to integers their arguments. Fraction-producing |gcd()| and % |lcm()| functions were available since |1.3d| \xintexprnameimp, with % non-public support macros handling comma separated values. % % \changed{1.4d} % Somewhat strangely \csh{xintGCD} was formerly \csh{xintGCDof} used with only two % arguments, as the latter directly implemented a fractionl gcd algorithm % using \csh{xintMod} repeatedly for two arguments. % % Now \csh{xintGCD} contains the pairwise gcd routine and \csh{xintGCDof} % is only a wrapper. And the pairwise gcd is reduced to integer-only % computations to hopefully reduce fraction overhead. % % Each input is filtered via |\xintPIrr| and |\xintREZ| to reduce size % of maniuplate integers in algebra. % % But hesitation about applying |\xintPIrr| to output, and/or |\xintREZ|. % (as it is applied on input). % % But as the code is now used for frational lcm's we actually need to do % some reduction of output else lcm's of integers will not be necessarily % printed by |\xinteval| as integers. % % Well finally I apply |\xintIrr| (but not |\xintREZ| to output). % Hesitations here (thinking of inputs with large [n] parts, the output % will have many zeros). So I do this only for the user macro but % the core routine as used by |\xintGCDof| will not do it. % % Also at |1.4d| the code uses |\expanded|. % \begin{macrocode} \def\xintGCD {\romannumeral0\xintgcd}% \def\xintgcd #1% {% \expandafter\XINT_fgcd_in \romannumeral0\xintrez{\xintPIrr{\xintAbs{#1}}}\xint: }% \def\XINT_fgcd_in #1#2\xint:#3% {% \expandafter\XINT_fgcd_out \romannumeral0\expandafter\XINT_fgcd_chkzeros\expandafter#1% \romannumeral0\xintrez{\xintPIrr{\xintAbs{#3}}}\xint:#1#2\xint: }% \def\XINT_fgcd_out#1[#2]{\xintirr{#1[#2]}[0]}% \def\XINT_fgcd_chkzeros #1#2% {% \xint_UDzerofork #1\XINT_fgcd_aiszero #2\XINT_fgcd_biszero 0\XINT_fgcd_main \krof #2% }% \def\XINT_fgcd_aiszero #1\xint:#2\xint:{ #1}% \def\XINT_fgcd_biszero #1\xint:#2\xint:{ #2}% \def\XINT_fgcd_main #1/#2[#3]\xint:#4/#5[#6]\xint: {% \expandafter\XINT_fgcd_a \romannumeral0\XINT_gcd_loop #2\xint:#5\xint:\xint: #2\xint:#5\xint:#1\xint:#4\xint:#3.#6.% }% \def\XINT_fgcd_a #1\xint:#2\xint: {% \expandafter\XINT_fgcd_b \romannumeral0\xintiiquo{#2}{#1}\xint:#1\xint:#2\xint: }% \def\XINT_fgcd_b #1\xint:#2\xint:#3\xint:#4\xint:#5\xint:#6\xint:#7.#8.% {% \expanded{% \xintiigcd{\xintiiE{\xintiiMul{#5}{\xintiiQuo{#4}{#2}}}{#7-#8}}% {\xintiiE{\xintiiMul{#6}{#1}}{#8-#7}}% /\xintiiMul{#1}{#4}% [\ifnum#7>#8 #8\else #7\fi]% }% }% % \end{macrocode} % \subsection{\csh{xintGCDof}} % \changed{1.4} % This inherits from former non public \xintexprnameimp macro called % |\xintGCDof:csv|, which handled comma separated items. % % It handles fractions presented as braced items and is the support macro % for the |gcd()| function in |\xintexpr| and |\xintfloatexpr|. The support % macro for the |gcd()| function in |\xintiiexpr| is \csbxint{iiGCDof}, from % \xintnameimp. % % An empty input is allowed but I have some hesitations on the return % value of 1. % % \changed{1.4d} % Sadly the |1.4| version had multiple problems: % \begin{itemize} % \item broken if first argument vanished, % \item broken if some argument was not in strict format, for example % had leading chains of signs or zeros (|\xintGCDof{2}{03}|). % This bug originates in the fact the original macro % was used only in \xintexprnameimp sanitized context. % \end{itemize} % % Also, output is now always an irreducible fraction (ending with |[0]|). % \begin{macrocode} \def\xintGCDof {\romannumeral0\xintgcdof}% \def\xintgcdof #1{\expandafter\XINT_fgcdof\romannumeral`&&@#1^}% \def\XINT_GCDof{\romannumeral0\XINT_fgcdof}% \def\XINT_fgcdof #1% {% \expandafter\XINT_fgcdof_chkempty\romannumeral`&&@#1\xint: }% \def\XINT_fgcdof_chkempty #1% {% \xint_gob_til_^#1\XINT_fgcdof_empty ^\XINT_fgcdof_in #1% }% \def\XINT_fgcdof_empty #1\xint:{ 1/1[0]}% hesitation, should it be infinity? O? \def\XINT_fgcdof_in #1\xint: {% \expandafter\XINT_fgcd_out \romannumeral0\expandafter\XINT_fgcdof_loop \romannumeral0\xintrez{\xintPIrr{\xintAbs{#1}}}\xint: }% \def\XINT_fgcdof_loop #1\xint:#2% {% \expandafter\XINT_fgcdof_chkend\romannumeral`&&@#2\xint:#1\xint:\xint: }% \def\XINT_fgcdof_chkend #1% {% \xint_gob_til_^#1\XINT_fgcdof_end ^\XINT_fgcdof_loop_pair #1% }% \def\XINT_fgcdof_end #1\xint:#2\xint:\xint:{ #2}% \def\XINT_fgcdof_loop_pair #1\xint:#2% {% \expandafter\XINT_fgcdof_loop \romannumeral0\expandafter\XINT_fgcd_chkzeros\expandafter#2% \romannumeral0\xintrez{\xintPIrr{\xintAbs{#1}}}\xint:#2% }% % \end{macrocode} % \subsection{\csh{xintLCM}} % Same comments as for \csh{xintGCD}. % Entirely redone for |1.4d|. % Well, actually we can express it in terms of fractional gcd. % \begin{macrocode} \def\xintLCM {\romannumeral0\xintlcm}% \def\xintlcm #1% {% \expandafter\XINT_flcm_in \romannumeral0\xintrez{\xintPIrr{\xintAbs{#1}}}\xint: }% \def\XINT_flcm_in #1#2\xint:#3% {% \expandafter\XINT_fgcd_out \romannumeral0\expandafter\XINT_flcm_chkzeros\expandafter#1% \romannumeral0\xintrez{\xintPIrr{\xintAbs{#3}}}\xint:#1#2\xint: }% \def\XINT_flcm_chkzeros #1#2% {% \xint_UDzerofork #1\XINT_flcm_zero #2\XINT_flcm_zero 0\XINT_flcm_main \krof #2% }% \def\XINT_flcm_zero #1\xint:#2\xint:{ 0/1[0]}% \def\XINT_flcm_main #1/#2[#3]\xint:#4/#5[#6]\xint: {% \xintinv {% \romannumeral0\XINT_fgcd_main #2/#1[-#3]\xint:#5/#4[-#6]\xint: }% }% % \end{macrocode} % \subsection{\csh{xintLCMof}} % See comments for |\xintGCDof|. \xintnameimp provides the integer only % \csbxint{iiLCMof}. % % \changed{1.4d}{} % Sadly, although a public \xintfracnameimp macro, it did not (since |1.4|) % sanitize its arguments like other \xintfracnameimp macros. % % \begin{macrocode} \def\xintLCMof {\romannumeral0\xintlcmof}% \def\xintlcmof #1{\expandafter\XINT_flcmof\romannumeral`&&@#1^}% \def\XINT_LCMof{\romannumeral0\XINT_flcmof}% \def\XINT_flcmof #1% {% \expandafter\XINT_flcmof_chkempty\romannumeral`&&@#1\xint: }% \def\XINT_flcmof_chkempty #1% {% \xint_gob_til_^#1\XINT_flcmof_empty ^\XINT_flcmof_in #1% }% \def\XINT_flcmof_empty #1\xint:{ 0/1[0]}% hesitation \def\XINT_flcmof_in #1\xint: {% \expandafter\XINT_fgcd_out \romannumeral0\expandafter\XINT_flcmof_loop \romannumeral0\xintrez{\xintPIrr{\xintAbs{#1}}}\xint: }% \def\XINT_flcmof_loop #1\xint:#2% {% \expandafter\XINT_flcmof_chkend\romannumeral`&&@#2\xint:#1\xint:\xint: }% \def\XINT_flcmof_chkend #1% {% \xint_gob_til_^#1\XINT_flcmof_end ^\XINT_flcmof_loop_pair #1% }% \def\XINT_flcmof_end #1\xint:#2\xint:\xint:{ #2}% \def\XINT_flcmof_loop_pair #1\xint:#2% {% \expandafter\XINT_flcmof_chkzero \romannumeral0\expandafter\XINT_flcm_chkzeros\expandafter#2% \romannumeral0\xintrez{\xintPIrr{\xintAbs{#1}}}\xint:#2% }% \def\XINT_flcmof_chkzero #1% {% \xint_gob_til_zero#1\XINT_flcmof_zero0\XINT_flcmof_loop#1% }% \def\XINT_flcmof_zero#1^{ 0/1[0]}% % \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} % %\begin{lverb} % Changes at 1.4e (done 2021/04/15; undone 2021/04/29) % % Macros named \XINTinFloat<name> are not public user-level but were designed % a long time ago for \xintfloatexpr context as a very preliminary step % towards attempting to preserve some internal format, here A[N] type. % % When <name> is lowercased it means it needs a \romannumeral0 trigger % (\XINTinfloatS keeps an uppercase S). % % Most were coded to check for an optional argument [D], and to use % D=\XINTdigits in its place if absent but it turned out only \XINTinfloatpow, % \XINTinfloatmul, \XINTinfloatadd were actually used with an optional % argument and this happened only in macros from the very old xintseries.sty, % so I changed all of them to not check for optional argument [D] anymore, % keeping only some private interface for the xintseries.sty use case. Some % required being used with [D], some still had names ending in "digits" % indicating they would use \XINTdigits always. % % Indeed basically all algebra is done "exactly" and the [D] governs rules of % float-rounding on input and output. % % During development of 1.4e we fleetingly experimented with letting the value % used in place of D be \XINTdigitsx to 1.4e, i.e. \XINTdigits with guard % digits, a situation which was motivated by the implementation of % trigonometrical functions at high level, i.e. using \xintdeffloatfunc which % had no mechanism to make intermediate calculations with guard digits. % % Simply doing everything "as is" but with 2 guard digits proved very good % (surprisingly efficient, even) to the trigonometrical functions. However % using them systematically raises many issues (for example, the correct % rounding at P digits is destroyed if we obtain it a D=P+2 then round from % P+2 to P digits so we definitely can not do this as default, so some % interface is needed to define intermediate functions only using such guard % digits and keeping them in their output). % % Finally, an approach limited to the xinttrig.sty scope was used and I % removed all \XINTdigitsx related matters from 1.4e. But this left some % modifications of the interfaces of the "float" macros here which this list % tries to document, mainly for the author's benefit. % %( Macros always using \XINTdigits and now not allowing [P] option %: \XINTinFloatAdd %: \XINTinFloatSub %: \XINTinFloatMul %: \XINTinFloatSqr %: \XINTinFloatInv %: \XINTinFloatDiv %: \XINTinFloatPow %: \XINTinFloatPower %: \XINTinFloatPFactorial %: \XINTinFloatBinomial %: %: Macros which already did not allow [P] option prior to 1.4e refactoring %: \XINTinFloatFrac (renamed from \XINTinFloatFracdigits) %: \XINTinFloatE %: \XINTinFloatMod %: \XINTinFloatDivFloor %: \XINTinFloatDivMod %: %: Macros requiring a [P]. Some of the "_wopt" named macros are& % renamings of macros formerly requiring [P]. %: \XINTinFloat %: \XINTinFloatS %: \XINTFloatiLogTen %: \XINTinRandomFloatS (this one has only the [P] mandatory argument) %: \XINTinFloatFac %: \XINTinFloatSqrt %: \XINTinFloatAdd_wopt, \XINTinfloatadd_wopt %: \XINTinFloatSub_wopt, \XINTinfloatsub_wopt %: \XINTinFloatMul_wopt, \XINTinfloatmul_wopt %: \XINTinFloatSqr_wopt %: \XINTinfloatpow_wopt (not FloatPow) %: \XINTinFloatDiv_wopt %: \XINTinFloatInv_wopt %: %: Specially named macros indicating usage of \XINTdigits %: \XINTinFloatdigits %: \XINTinFloatSdigits %: \XINTFloatiLogTendigits %: \XINTinRandomFloatSdigits %: \XINTinFloatFacdigits %: \XINTinFloatSqrtdigits %) %\end{lverb} % % \subsection{\csh{xintDigits}, \csh{xintSetDigits}} % \changed{1.3} %\begin{lverb} % 1.3f allows \xintDigits= in place of \xintDigits$empty:= syntax. % It defines \xintDigits*[:]= which reloads xinttrig.sty. Perhaps this should % be default, well. % % During 1.4e development I added an interface for guard digits, but I decided % to drop inclusion from 1.4e release because there were pending issues both % in documentation and functionalities for which I did not have time left. % % 1.4e fixes the issue that \xinttheDigits could not be used in the right hand % side of \xintDigits[*][:]=...; or inside the argument to \xintSetDigits. %\end{lverb} % \begin{macrocode} \mathchardef\XINTdigits 16 \chardef\XINTguarddigits 0 \def\xinttheDigits {\number\XINTdigits}% %\def\xinttheGuardDigits{\number\XINTguarddigits}% \def\xinttheGuardDigits{0}% in case used in some of my test files \def\xintDigits #1={\afterassignment\xintDigits_i\mathchardef\XINT_digits=}% \def\xintDigits_i#1% {% \let\XINTdigits\XINT_digits }% \def\xintSetDigits #1% {% \mathchardef\XINT_digits=\numexpr#1\relax \let\XINTdigits=\XINT_digits }% % \end{macrocode} % % \subsection{\csh{xintFloat}, \csh{xintFloatZero}} %\begin{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. %\end{lverb} % \begin{macrocode} \def\xintFloatZero{0.0e0}% 1.4k breaking change. Replaces hard-coded 0.e0 \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: {% \expandafter\XINT_float_opt_a\the\numexpr }% \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.{\expanded{ \xintFloatZero}}% \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{xintFloatBraced}} % \added{1.4l} %\begin{lverb} % Je ne le fais pas comme un wrapper au-dessus de \xintFloat % car c'est pénible avec argument optionnel donc finalemnt % on est obligé de rajouter overhead comme ici. % %( Hésitation si on obéit à \xintFloatZero ou pas. Finalement non. %: Hésitation si on renvoie avec séparateur décimal ou pas. %: Hésitation si on met l'exposant scientifique en premier. %: Hésitation si on sépare le signe pour le mettre en premier. %: Hésitation si on renvoie un exposant pour mantisse normalisée& % ou pas normalisée. %) % % Finalement je décide {signe}{exposant}{mantisse sans point décimal}. % Avec en fait 0 ou 1 pour signe (mais ce sign bit mais ça n'a pas grand % sens en décimal...). Non finalement mantisse avec point décimal. %\end{lverb} % \begin{macrocode} \def\xintFloatBraced{\romannumeral0\xintfloatbraced }% \def\xintfloatbraced#1{\XINT_floatbr_chkopt #1\xint:}% \def\XINT_floatbr_chkopt #1% {% \ifx [#1\expandafter\XINT_floatbr_opt \else\expandafter\XINT_floatbr_noopt \fi #1% }% \def\XINT_floatbr_noopt #1\xint:% {% \expandafter\XINT_floatbr_post \romannumeral0\XINTinfloat[\XINTdigits]{#1}\XINTdigits.% }% \def\XINT_floatbr_opt [\xint: {% \expandafter\XINT_floatbr_opt_a\the\numexpr }% \def\XINT_floatbr_opt_a #1]#2% {% \expandafter\XINT_floatbr_post \romannumeral0\XINTinfloat[#1]{#2}#1.% }% \def\XINT_floatbr_post #1% {% \xint_UDzerominusfork #1-\XINT_floatbr_zero 0#1\XINT_floatbr_neg 0-\XINT_floatbr_pos \krof #1% }% % \end{macrocode} %\begin{lverb} % Hésitation à faire %( \def\XINT_floatbr_zero #1]#2.{\expandafter\XINT_floatbr_zero_a\xintFloatZero e0e\relax}% %: \def\XINT_floatbr_zero_a#1e#2e#3\relax{{#1}{#2}}% %) % Finalement non. Et même je décide de renvoyer autant de zéros que P. % De plus depuis j'ai opté pour {sign bit}{exposant}{mantisse} % Hésitation si mantisse avec ou sans le séparateur décimal. % Est-ce que je devrais mettre plutôt -0+ au début? %\end{lverb} % \begin{macrocode} \def\XINT_floatbr_zero #1]#2.{\expanded{{0}{0}{0.\xintReplicate{#2-\xint_c_i}0}}}% \def\XINT_floatbr_neg-{\expandafter\XINT_floatbr_neg_a\romannumeral0\XINT_floatbr_pos}% \def\XINT_floatbr_neg_a#1{{1}}% \def\XINT_floatbr_pos #1#2[#3]#4.% {% \expanded{{0}{\the\numexpr#3+#4-\xint_c_i}}{#1.#2}% }% % \end{macrocode} % \subsection{\csh{XINTinFloat}, \csh{XINTinFloatS}} %\begin{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. % % (but the zero value must always be checked for, as it outputs 0[0]) % % 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. %\end{lverb} % \begin{macrocode} \def\XINTinFloat {\romannumeral0\XINTinfloat }% \def\XINTinfloat {\expandafter\XINT_infloat_clean\romannumeral0\XINT_infloat}% % \end{macrocode} %\begin{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). %\end{lverb} % \begin{macrocode} \def\XINT_infloat_clean #1% {\if #1!\xint_dothis\XINT_infloat_clean_a\fi\xint_orthat{ }#1}% % \end{macrocode} %\begin{lverb} % Ici on ajoute les zeros pour faire exactement avec P chiffres. % Car le #1 = P - L avec L la longueur de #2, (ou plutôt de abs(#2), % car ici le #2 peut avoir un signe) et L < P %\end{lverb} % \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} %\begin{lverb} % variant which allows output with shorter mantissas. %\end{lverb} % \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} %\begin{lverb} % début de la routine proprement dite, % l'argument optionnel est obligatoire. %\end{lverb} % \begin{macrocode} \def\XINT_infloat [#1]%#2% {% \expandafter\XINT_infloat_a\the\numexpr #1\expandafter.% \romannumeral0\XINT_infrac% {#2}% }% % \end{macrocode} %\begin{lverb} % #1=P, #2=n, #3=A, #4=B. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_a #1.#2#3#4% {% % \end{macrocode} %\begin{lverb} % micro boost au lieu d'utiliser \XINT_isOne{#4}, mais pas bon style. %\end{lverb} % \begin{macrocode} \if1\XINT_is_One#4XY% \expandafter\XINT_infloat_sp \else\expandafter\XINT_infloat_fork \fi #3.{#1}{#2}{#4}% }% % \end{macrocode} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % Attention surtout pas 0/1[0] ici. %\end{lverb} % \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} %\begin{lverb} % in: A.{P}{N}{1}$newline % out: P-L.A.P.N. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % Ici P=L. Le cas usuel dans \xintfloatexpr. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_sp_quick 0.#1.#2.#3.{ #1[#3]}% % \end{macrocode} %\begin{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. %\end{lverb} % \begin{macrocode} \def\XINT_infloat_sp_needzeros #1.#2.#3.#4.{!#1.#2[#4]}% % \end{macrocode} %\begin{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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % A.{P}{n}{B} avec B>1. %\end{lverb} % \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} %\begin{lverb} % |A|.P+4.{A}{P}{n}{B}. We check if A already has length % <= P+4. %\end{lverb} % \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} %\begin{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} %\end{lverb} % \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} %\begin{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} %\end{lverb} % \begin{macrocode} \def\XINT_infloat_Mb #1.#2.#3% {% \expandafter\XINT_infloat_MtoN\the\numexpr#2-#1.% #3..#2.#1.{#3}% }% % \end{macrocode} %\begin{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} %\end{lverb} % \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} %\begin{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} %\end{lverb} % \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} %\begin{lverb} % output v=P+4-|B|>=0.B''.junk.|B|.u.A''.P.|A|.n.{A}{B} %\end{lverb} % \begin{macrocode} \def\XINT_infloat_Ob #1.#2.#3% {% \expandafter\XINT_infloat_P\the\numexpr#2-#1.#3..#1.% }% % \end{macrocode} %\begin{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. %\end{lverb} % \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} %\begin{lverb} % «quick» branch. %\end{lverb} % \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} %\begin{lverb} % standard branch which will have to handle undecided rounding, if too % close to a mid-value. %\end{lverb} % \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} %\begin{lverb} % trailing digits.Q.P.|B|.|A|.n.{A}{B}$newline % #1=trailing digits (they may have leading zeros.) %\end{lverb} % \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} %\begin{lverb} % epsilon #2=Q.#3=P.#4=|B|.#5=|A|.#6=n.{A}{B}$newline % exposant final est n+|A|-|B|-P+epsilon %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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 %\end{lverb} % \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} %\begin{lverb} % check for rounding up to next power of ten. %\end{lverb} % \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} %\begin{lverb} % #1=1, #2=0. %\end{lverb} % \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{XINTFloatiLogTen}} % \added{1.3e} %\begin{lverb} % Le comportement pour un input nul est non % encore finalisé. Il changera lorsque NaN, +Inf, -Inf existeront. % % The optional argument [#1] is in fact mandatory and #1 is % not pre-expanded in a \numexpr. % % The return value here 2^31-2^15 is highly undecided. %\end{lverb} % \begin{macrocode} \def\XINTFloatiLogTen {\the\numexpr\XINTfloatilogten}% \def\XINTfloatilogten [#1]#2% {\expandafter\XINT_floatilogten\romannumeral0\XINT_infloat[#1]{#2}#1.}% \def\XINTFloatiLogTendigits{\the\numexpr\XINTfloatilogten[\XINTdigits]}% \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-\xint_c_i\relax}% \def\XINT_floatilogten_b #1[#2]#3.{#2+#3-\xint_c_i\relax}% % \end{macrocode} % \subsection{\csh{xintPFloat}} % \added{1.1} % \changed{1.4e} %\begin{lverb} % % xint has not yet incorporated a general formatter as it was % not a priority during development and external solutions exist % (I did not check for a while but I think LaTeX3 has implemented % a general formatter in the printf or Python ".format" spirit) % % But when one starts using really the package, especially in % an interactive way (xintsession 2021), one needs the default % output to be as nice as possible. % % The \xintPFloat macro was added at 1.1 as a "prettifying printer" % for floats, basically influenced by Maple. % %( The rules were: %: 0. The input is float-rounded to either Digits or the optional argument %: 1. zero is printed as "0." %: 2. x.yz...eK is printed "as is" if K>5 or K<-5. %: 3. if -5<=K<=5, fixed point decimal notation is used. %: 4. in cases 2. and 3., no trimming of trailing zeroes. %) % % 1.4b added \xintPFloatE to customize whether to use % e or E. % % % 1.4e, with some hesitation, decided to make a breaking change and to modify % the behaviour. % %( The new rules: %: 0. The input is float-rounded to either Digits or the optional argument %: 1. zero is printed as 0.0 %: 2. x.yz...eK is printed in decimal fixed point if -4<=K<=+5& % (notice the change, formerly K=-5 used fixed point notation in output)& % else it is printed in scientific notation %: 3. trailing zeros of the mantissa are trimmed always %: 4. in case of decimal fixed point for an integer, there& % is a trailing ".0" %: 5. in case of scientific notation with a one-digit trimmed mantissa& % there is an added ".0" too %) % % Further, \xintPFloatE can now also be redefined as a macro with a parameter % delimited by a full stop, with the full stop also in its ouput as % terminator. It would then grab the scientific exponent K as explicit digit % possibly prefixed by a minus sign. The macro must be f-expandable. % % The macro \xintPFloat_wopt is only there for a micro gain as the package % does % % \let\xintfloatexprPrintOne\xintPFloat_wopt % % as it knows it will % be used always with a [P] argument in the xintexpr.sty context. %\end{lverb} % \changed{1.4k} %\begin{lverb} % Addition of customization via \xintPFloatZero, \xintPFloatLengthOneSuffix, % \xintPFloatNoSciEmax, \xintPFloatNoSciEmin which replace formerly % hard-coded behaviour. % % Breaking change to not add ".0" suffix to integers (when scientific % notation dropped) or to one-digit mantissas. % % In my own practice I started being annoyed by the automatic trimming of % zeros added at 1.4e. % % This change had been influenced by using Python in interactive mode % which since 3.1 prints floats (in decimal conversion) choosing the % shortest string. In particular it trims trailing zeros, and it drops % the scientific notation in favor of decimal notation for something % like -4<= K <= 15, with K the scientific exponent. % % At 1.4e I was still influenced by my experience with Maple and % did for -4 <= K <= 5. Not very well thought anyhow (one may wish % to use decimal notation when sending things to PostScript, so perhaps % I should have kept with -5). % % But, the main problem is with trimming trailing zeros: although in % interactive sessions, this has its logic, as soon as one does tables % with numbers, dropping a trailing zero upsets alignments or creates % visual holes compared to other lines and this is in the end very % annoying. % % After much hesitation, I decided to slightly modifify only the former % behaviour: trimming only if that removes at least 4 zeros. I had also % experimented with another condition: trimmed mantissas should be at % most 6 digits (for example) wide, else use no trimming. % % Threshold customizable via \xintPFloatMinTrimmed. %\end{lverb} % \changed[2022/05/22]{1.4l} %\begin{lverb} % The 1.4k check for canceling the trimming of trailing zeros % took over priority over the later check for being an integer when % decimal fixed point notation was used (or being only with a one-digit % trimmed mantissa). In particular if user set \xintPFloatMinTrimmed to % the value of Digits (or P) to avoid trimming it also prevented % recognition of some integers (but not all). Fixed at 1.4l %\end{lverb} % \begin{macrocode} \def\xintPFloatE{e}% \def\xintPFloatNoSciEmax{\xint_c_v}% 1e6 uses sci.not. \def\xintPFloatNoSciEmin{-\xint_c_iv}% 1e-5 uses sci.not. \def\xintPFloatIntSuffix{}% \def\xintPFloatLengthOneSuffix{}% \def\xintPFloatZero{0}% \def\xintPFloatMinTrimmed{\xint_c_iv}% \def\xintPFloat {\romannumeral0\xintpfloat }% \def\xintpfloat #1{\XINT_pfloat_chkopt #1\xint:}% \def\xintPFloat_wopt[#1]#2% {% \romannumeral0\expandafter\XINT_pfloat \romannumeral0\XINTinfloatS[#1]{#2}#1.% }% \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\romannumeral0\XINTinfloatS[\XINTdigits]{#1}% \XINTdigits.% }% \def\XINT_pfloat_opt [\xint:{\expandafter\XINT_pfloat_opt_a\the\numexpr}% \def\XINT_pfloat_opt_a #1]#2% {% \expandafter\XINT_pfloat\romannumeral0\XINTinfloatS[#1]{#2}% #1.% }% \def\XINT_pfloat#1]% {% \expandafter\XINT_pfloat_fork\romannumeral0\xintrez{#1]}% }% \def\XINT_pfloat_fork#1% {% \xint_UDzerominusfork #1-\XINT_pfloat_zero 0#1\XINT_pfloat_neg 0-\XINT_pfloat_pos \krof #1% }% \def\XINT_pfloat_zero#1]#2.{\expanded{ \xintPFloatZero}}% \def\XINT_pfloat_neg-{\expandafter-\romannumeral0\XINT_pfloat_pos}% \def\XINT_pfloat_pos#1/1[#2]#3.% {% \expandafter\XINT_pfloat_aa\the\numexpr\xintLength{#1}.% #3.#2.#1.% }% % \end{macrocode} %\begin{lverb} %( #1 est la longueur de la mantisse trimmée %: #2 est Digits ou P %: Si #2-#1 < MinTrimmed, on se prépare à peut-être remettre les trailing zeros %) % % On teste pour #2=#1, car c'est le cas le plus fréquent (mais est-ce % une bonne idée) car on sait qu'alors il n'y a pas de trailing zéros % donc on va direct vers \XINT_pfloat_a. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_aa #1.#2.% {% \unless\ifnum\xintPFloatMinTrimmed>\numexpr#2-#1\relax \xint_dothis\XINT_pfloat_a\fi \ifnum#2>#1 \xint_dothis{\XINT_pfloat_i #2.}\fi \xint_orthat\XINT_pfloat_a #1.% }% % \end{macrocode} %\begin{lverb} % Needed for \xintFracToSci, which uses old pre 1.4k interface, % where the P parameter was not stored for counting how many zeros % were trimmed. \xintFracToSci trims always. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_a_fork#1% {% \xint_UDzerominusfork #1-\XINT_pfloat_a_zero 0#1\XINT_pfloat_a_neg 0-\XINT_pfloat_a_pos \krof #1% }% \def\XINT_pfloat_a_zero#1]{\expanded{ \xintPFloatZero}}% \def\XINT_pfloat_a_neg-{\expandafter-\romannumeral0\XINT_pfloat_a_pos}% \def\XINT_pfloat_a_pos#1/1[#2]% {% \expandafter\XINT_pfloat_a\the\numexpr\xintLength{#1}.#2.#1.% }% % \end{macrocode} %\begin{lverb} %( #1 est P > #2 mais peut être encore sous la forme \XINTdigits %: #2 est la longueur de la mantisse trimmée %: #3 est l'exposant non normalisé %: #4 est la mantisse %) % On reconstitue les trailing zéros à remettre éventuellement. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_i #1.#2.%#3.#4.% {% \expandafter\XINT_pfloat_j\romannumeral\xintreplicate{#1-#2}0.#2.% }% % \end{macrocode} %\begin{lverb} %( #1 est les trailing zeros à remettre peut-être %: #2 est la longueur de la mantisse trimmée %: #3#4 est l'exposant N pour mantisse trimmée entière %: #5 serait la mantisse trimmée %) % On calcule l'exposant scientifique. % % La façon bizarre de mettre #3 est liée aux versions anciennes % de la macro, héritage conservé pour minimiser effort d'adaptation. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_j #1.#2.#3#4.%#5. {% \expandafter\XINT_pfloat_b\the\numexpr#2+#3#4-\xint_c_i.% #3#2.#1.% }% % \end{macrocode} %\begin{lverb} %( #1 est la longueur de la mantisse trimmée %: #2#3 est l'exposant N pour mantisse trimmée %: #4 serait la mantisse %) % On calcule l'exposant scientifique. On est arrivé ici dans % une branche où on n'a pas besoin de remettre les zéros trimmés % donc on positionne un dernier argument vide pour \XINT_pfloat_b %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_a #1.#2#3.%#4. {% \expandafter\XINT_pfloat_b\the\numexpr#1+#2#3-\xint_c_i.% #2#1..% }% % \end{macrocode} %\begin{lverb} %( #1 est l'exposant scientifique K %: #2 est le signe ou premier chiffre de l'exposant N pour mantisse trimmée %: #3 serait la longueur de la mantisse trimmée %: #4 serait les trailing zéros %: #5 serait la mantisse trimmée %) % On va vers \XINT_float_P lorsque l'on n'utilise pas la notation % scientifique, mais qu'on a besoin de chiffres non nuls fractionnaires, % et vers \XINT_float_Ps si on n'en a pas besoin. % % On va vers \XINT_pfloat_N lorsque l'on n'utilise pas la notation % scientifique et que l'exposant scientifique était strictement négatif. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_b #1.#2%#3.#4.#5. {% \ifnum \xintPFloatNoSciEmax<#1 \xint_dothis\XINT_pfloat_sci\fi \ifnum \xintPFloatNoSciEmin>#1 \xint_dothis\XINT_pfloat_sci\fi \ifnum #1<\xint_c_ \xint_dothis\XINT_pfloat_N\fi \if-#2\xint_dothis\XINT_pfloat_P\fi \xint_orthat\XINT_pfloat_Ps #1.% }% % \end{macrocode} %\begin{lverb} % #1 is the scientific exponent, #2 is the length of the trimmed mantissa, % #3 are the trailing zeros, #4 is the trimmed integer mantissa % % \xintPFloatE can be replaced by any f-expandable macro with a dot-delimited % argument which produces a dot-delimited output. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_sci #1.#2.% {% \ifnum#2=\xint_c_i\expandafter\XINT_pfloat_sci_i\expandafter\fi \expandafter\XINT_pfloat_sci_a\romannumeral`&&@\xintPFloatE #1.% }% \def\XINT_pfloat_sci_a #1.#2.#3#4.{ #3.#4#2#1}% % \end{macrocode} %\begin{lverb} % #1#2=\fi\XINT_pfloat_sci_a % % 1-digit mantissa, hesitation between d.0eK or deK % Finally at 1.4k, \xintPFloatLengthOneSuffix for customization. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_sci_i #1#2#3.#4.#5.{\expanded{#1 #5\xintPFloatLengthOneSuffix}#3}% % \end{macrocode} %\begin{lverb} % #1=sci.exp. K, #2=mant. wd L, #3=trailing zéros, #4=trimmed mantissa % % For _N, #1 is at most -1, for _P, #1 is at least 0. For _P there % will be fractional digits, and #1+1 digits before the mark. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_N#1.#2.#3.#4.% {% \expandafter\XINT_pfloat_N_e\romannumeral\xintreplicate{-#1}{0}#4#3% }% \def\XINT_pfloat_N_e 0{ 0.}% % \end{macrocode} %\begin{lverb} % #1=sci.exp. K, #2=mant. wd L, #3=trailing zéros, #4=trimmed mantissa % % Abusive usage of internal \XINT_split_fromleft_a. % It means using x = -1 - #1 in \xintDecSplit from xint.sty. % We benefit also with the way \xintDecSplit is built upon % \XINT_split_fromleft with a final clean-up which here % we can shortcut via using terminator "\xint_bye." not "\xint_bye.." %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_P #1.#2.#3.#4.% {% \expandafter\XINT_split_fromleft_a \the\numexpr\xint_c_vii-#1.#4\xint_bye2345678\xint_bye.#3% }% % \end{macrocode} %\begin{lverb} % Here we have an integer so we only need to postfix the trimmed mantissa #4 % with #1+1-#2 zeros (#1=sci exp., #2=trimmed mantissa width). Less cumbersome % to do that with \expanded. And the trailing zeros #3 ignored here. %\end{lverb} % \begin{macrocode} \def\XINT_pfloat_Ps #1.#2.#3.#4.% {% \expanded{ #4% \romannumeral\xintreplicate{#1+\xint_c_i-#2}{0}\xintPFloatIntSuffix}% }% % \end{macrocode} % \subsection{\csh{xintFloatToDecimal}} % \added{1.4k} % \begin{macrocode} \def\xintFloatToDecimal {\romannumeral0\xintfloattodecimal }% \def\xintfloattodecimal #1{\XINT_floattodec_chkopt #1\xint:}% \def\XINT_floattodec_chkopt #1% {% \ifx [#1\expandafter\XINT_floattodec_opt \else\expandafter\XINT_floattodec_noopt \fi #1% }% \def\XINT_floattodec_noopt #1\xint:% {% \expandafter\XINT_floattodec\romannumeral0\XINTinfloatS[\XINTdigits]{#1}% }% \def\XINT_floattodec_opt [\xint:#1]% {% \expandafter\XINT_floattodec\romannumeral0\XINTinfloatS[#1]% }% % \end{macrocode} %\begin{lverb} % Temptation to try to use direct access to lower entry points % from \xintREZ, but it dates back from very early days and uses old \Z % delimiters (same remarks for the code jumping from \xintFracToSci % to \xintrez) %\end{lverb} % \begin{macrocode} \def\XINT_floattodec#1]% {% \expandafter\XINT_dectostr\romannumeral0\xintrez{#1]}% }% % \end{macrocode} % % \subsection{\csh{XINTinFloatFrac}} % \added{1.09i} % %\begin{lverb} % 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. %\end{lverb} % % \changed{1.1} %\begin{lverb} % 1.1 removes optional argument for which there was anyhow no interface, for % technical reasons having to do with \xintNewExpr. %\end{lverb} % % \changed{1.1a} %\begin{lverb} % 1.1a renames the macro as \XINTinFloatFracdigits (from \XINTinFloatFrac) to % be synchronous with the \XINTinFloatSqrt and \XINTinFloat habits related to % \xintNewExpr context and issues with macro names. %\end{lverb} % % \changed{1.4e} %\begin{lverb} % 1.4e renames it back to \XINTinFloatFrac because of all such similarly named % macros also using \XINTdigits forcedly. %\end{lverb} % \begin{macrocode} \def\XINTinFloatFrac {\romannumeral0\XINTinfloatfrac}% \def\XINTinfloatfrac #1% {% \expandafter\XINT_infloatfrac_a\expandafter {\romannumeral0\xinttfrac{#1}}% }% \def\XINT_infloatfrac_a {\XINTinfloat[\XINTdigits]}% % \end{macrocode} % \subsection{\csh{xintFloatAdd}, \csh{XINTinFloatAdd}} %\begin{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. % % See general introduction for important changes at 1.4e relative to % the \XINTinFloat<name> macros. % %\end{lverb} % \begin{macrocode} \def\xintFloatAdd {\romannumeral0\xintfloatadd}% \def\xintfloatadd #1{\XINT_fladd_chkopt \xintfloat #1\xint:}% \def\XINTinFloatAdd{\romannumeral0\XINTinfloatadd }% \def\XINTinfloatadd{\XINT_fladd_opt_a\XINTdigits.\XINTinfloatS}% \def\XINTinFloatAdd_wopt{\romannumeral0\XINTinfloatadd_wopt}% \def\XINTinfloatadd_wopt[#1]{\expandafter\XINT_fladd_opt_a\the\numexpr#1.\XINTinfloatS}% \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% }% \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]% }% \def\XINT_FL_add_c #1% {% \xint_gob_til_zero #1\XINT_FL_add_zero 0\XINT_FL_add_d #1% }% \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}} % \added{1.07} % \changed{1.2f} %\begin{lverb} % Starting with 1.2f the arguments undergo an intial rounding to the target % precision P not P+2. %\end{lverb} % % \begin{macrocode} \def\xintFloatSub {\romannumeral0\xintfloatsub}% \def\xintfloatsub #1{\XINT_flsub_chkopt \xintfloat #1\xint:}% \def\XINTinFloatSub{\romannumeral0\XINTinfloatsub}% \def\XINTinfloatsub{\XINT_flsub_opt_a\XINTdigits.\XINTinfloatS}% \def\XINTinFloatSub_wopt{\romannumeral0\XINTinfloatsub_wopt}% \def\XINTinfloatsub_wopt[#1]{\expandafter\XINT_flsub_opt_a\the\numexpr#1.\XINTinfloatS}% \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}} % \added{1.07} % \changed{1.2d} %\begin{lverb} % Starting with 1.2f the arguments are rounded to the target precision P not % P+2. %\end{lverb} % \changed{1.2g} %\begin{lverb} % 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. %\end{lverb} % \begin{macrocode} \def\xintFloatMul {\romannumeral0\xintfloatmul}% \def\xintfloatmul #1{\XINT_flmul_chkopt \xintfloat #1\xint:}% \def\XINTinFloatMul{\romannumeral0\XINTinfloatmul}% \def\XINTinfloatmul{\XINT_flmul_opt_a\XINTdigits.\XINTinfloatS}% \def\XINTinFloatMul_wopt{\romannumeral0\XINTinfloatmul_wopt}% \def\XINTinfloatmul_wopt[#1]{\expandafter\XINT_flmul_opt_a\the\numexpr#1.\XINTinfloatS}% \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]% }% \def\XINT_FL_mul_b #1[#2]#3[#4]{\xintiiMul{#3}{#1}/1[#4+#2]}% % \end{macrocode} % \subsection{\csh{xintFloatSqr}, \csh{XINTinFloatSqr}} % \added{1.4e} %\begin{lverb} % Strangely \xintFloatSqr had never been defined so far. % % An \XINTinFloatSqr{#1} was defined in xintexpr.sty directly as % \XINTinFloatMul[\XINTdigits]{#1}{#1}, to support the sqr() function. The % {#1}{#1} causes no problem as #1 in this context is always pre-expanded so % we don't need to worry about this, and the \xintdeffloatfunc mechanism % should hopefully take care to add the needed argument pre-expansion if need % be. % % Anyway let's do this finally properly here. %\end{lverb} % \begin{macrocode} \def\xintFloatSqr {\romannumeral0\xintfloatsqr}% \def\xintfloatsqr #1{\XINT_flsqr_chkopt \xintfloat #1\xint:}% \def\XINTinFloatSqr{\romannumeral0\XINTinfloatsqr}% \def\XINTinfloatsqr{\XINT_flsqr_opt_a\XINTdigits.\XINTinfloatS}% \def\XINT_flsqr_chkopt #1#2% {% \ifx [#2\expandafter\XINT_flsqr_opt \else\expandafter\XINT_flsqr_noopt \fi #1#2% }% \def\XINT_flsqr_noopt #1#2\xint: {% #1[\XINTdigits]% {\expandafter\XINT_FL_sqr_a\romannumeral0\XINTinfloatS[\XINTdigits]{#2}}% }% \def\XINT_flsqr_opt #1[\xint:#2]% {% \expandafter\XINT_flsqr_opt_a\the\numexpr #2.#1% }% \def\XINT_flsqr_opt_a #1.#2#3% {% #2[#1]{\expandafter\XINT_FL_sqr_a\romannumeral0\XINTinfloatS[#1]{#3}}% }% \def\XINT_FL_sqr_a #1[#2]{\xintiiSqr{#1}/1[#2+#2]}% \def\XINTinFloatSqr_wopt[#1]#2{\XINTinFloatS[#1]{\expandafter\XINT_FL_sqr_a\romannumeral0\XINTinfloatS[#1]{#2}}}% % \end{macrocode} % \subsection{\csh{XINTinFloatInv}} % \added{1.3e} %\begin{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. %\end{lverb} % \begin{macrocode} \def\XINTinFloatInv#1{\XINTinFloatS[\XINTdigits]{\xintInv{#1}}}% \def\XINTinFloatInv_wopt[#1]#2{\XINTinFloatS[#1]{\xintInv{#2}}}% % \end{macrocode} % \subsection{\csh{xintFloatDiv}, \csh{XINTinFloatDiv}} % \added{1.07} % \changed{1.2f} %\begin{lverb} % Starting with 1.2f the arguments are rounded to the target precision P not % P+2. %\end{lverb} % \changed{1.2g} %\begin{lverb} % 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). %\end{lverb} % \changed{1.2k} %\begin{lverb} % 1.2k does the same kind of improvement in \XINT_FL_div_b as for % multiplication: earlier code was unnecessarily high level. %\end{lverb} % \begin{macrocode} \def\xintFloatDiv {\romannumeral0\xintfloatdiv}% \def\xintfloatdiv #1{\XINT_fldiv_chkopt \xintfloat #1\xint:}% \def\XINTinFloatDiv{\romannumeral0\XINTinfloatdiv}% \def\XINTinfloatdiv{\XINT_fldiv_opt_a\XINTdigits.\XINTinfloatS}% \def\XINTinFloatDiv_wopt[#1]{\romannumeral0\XINT_fldiv_opt_a#1.\XINTinfloatS}% \def\XINT_fldiv_chkopt #1#2% {% \ifx [#2\expandafter\XINT_fldiv_opt \else\expandafter\XINT_fldiv_noopt \fi #1#2% }% % \end{macrocode} %\begin{lverb} % 1.4g adds here intercept of second argument being zero, % else a low level error will arise at later stage from the % the fall-back value returned by core iidivision being 0 % and not having expected number of digits at \XINT_infloat_Qq % and split from left returning some empty value breaking the % \ifnum test in \XINT_infloat_Rq. %\end{lverb} % \begin{macrocode} \def\XINT_fldiv_noopt #1#2\xint:#3% {% #1[\XINTdigits]% {\expandafter\XINT_FL_div_aa \romannumeral0\XINTinfloatS[\XINTdigits]{#3}\XINTdigits.{#2}}% }% \def\XINT_FL_div_aa #1% {% \xint_gob_til_zero#1\XINT_FL_div_Bzero0\XINT_FL_div_a #1% }% \def\XINT_FL_div_Bzero0\XINT_FL_div_a#1[#2]#3.#4% {% \XINT_signalcondition{DivisionByZero}{Division by zero (#1[#2]) of #4}{}{ 0[0]}% }% \def\XINT_fldiv_opt #1[\xint:#2]%#3#4% {% \expandafter\XINT_fldiv_opt_a\the\numexpr #2.#1% }% % \end{macrocode} %\begin{lverb} % Also here added early check at 1.4g if divisor is zero. %\end{lverb} % \begin{macrocode} \def\XINT_fldiv_opt_a #1.#2#3#4% {% #2[#1]{\expandafter\XINT_FL_div_aa\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% }% \def\XINT_FL_div_b #1[#2]{#1e#2}% % \end{macrocode} % \subsection{\csh{xintFloatPow}, \csh{XINTinFloatPow}} % \added{1.07} % %\begin{lverb} % 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. %\end{lverb} % % \changed{1.2f} %\begin{lverb} % 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). %\end{lverb} % \begin{macrocode} \def\xintFloatPow {\romannumeral0\xintfloatpow}% \def\xintfloatpow #1{\XINT_flpow_chkopt \xintfloat #1\xint:}% \def\XINTinFloatPow{\romannumeral0\XINTinfloatpow }% \def\XINTinfloatpow{\XINT_flpow_opt_a\XINTdigits.\XINTinfloatS}% \def\XINTinfloatpow_wopt[#1]{\expandafter\XINT_flpow_opt_a\the\numexpr#1.\XINTinfloatS}% \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]}}% \def\XINT_flpow_checkB_b #1#2.#3.% {% \expandafter\XINT_flpow_checkB_c \the\numexpr\xintLength{#2}+\xint_c_iii.#3.#2.{#1}% }% \def\XINT_flpow_checkB_c #1.#2.% {% \expandafter\XINT_flpow_checkB_d\the\numexpr#1+#2.#1.#2.% }% % \end{macrocode} %\begin{lverb} % % 1.2f rounds input to P digits, first. %\end{lverb} % \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}% }% \def\XINT_flpow_aa #1[#2]#3% {% \expandafter\XINT_flpow_ab\the\numexpr #2-#3\expandafter.% \romannumeral\XINT_rep #3\endcsname0.#1.% }% \def\XINT_flpow_ab #1.#2.#3.{\XINT_flpow_a #3#2[#1]}% \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 raised to power -#4.}{}{ 0[0]}}% }% }% \def\XINT_flpow_b #1#2[#3]#4#5% {% \XINT_flpow_loopI #5.#3.#2.#4.{#1\ifodd #5 \xint_c_i\fi\fi}% }% \def\XINT_flpow_truncate #1.#2.#3.% {% \expandafter\XINT_flpow_truncate_a \romannumeral0\XINT_split_fromleft #3.#2\xint_bye2345678\xint_bye..#1.#3.% }% \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.% }% \def\XINT_flpow_ItoIII\ifodd #1\fi #2.#3.#4.#5.#6% {% \expandafter\XINT_flpow_III\the\numexpr #6+\xint_c_.#3.#4.#5.% }% \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.% }% \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} %\begin{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). %\end{lverb} % \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% }% \def\XINT_flpow_IIIend #1#2#3% {#3{\if#21\xint_afterfi{\expandafter-\romannumeral`&&@}\fi#1}}% % \end{macrocode} % \subsection{\csh{xintFloatPower}, \csh{XINTinFloatPower}} % \added{1.07} %\begin{lverb} % 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. %\end{lverb} % \changed{1.2f} %\begin{lverb} % Same modifications as in \xintFloatPow for 1.2f. % % 1.2f \XINTinFloatPowerH (now moved to $xintlognameimp, and renamed). It % truncated the exponent to an integer of half-integer, and in the latter case % use Square-root extraction. At 1.2k this was improved as 1.2f stupidly % rounded to Digits before, not after the square root extraction, 1.2k kept 3 % guard digits for this last step. And the initial step was % changed to a rounding rather than truncating. %\end{lverb} % \changed{1.4e} %\begin{lverb} % Until 1.4e this \XINTinFloatPowerH was the macro for a^b in expressions, % but of course it behaved strangely for b not an integer or an half-integer! % At 1.4e, the non-integer, non-half-integer exponents will be handled via % log10() and pow10() support macros, see $xintlognameimp. The code % has now been relocated there. %\end{lverb} % \begin{macrocode} \def\xintFloatPower {\romannumeral0\xintfloatpower}% \def\xintfloatpower #1{\XINT_flpower_chkopt \xintfloat #1\xint:}% \def\XINTinFloatPower{\romannumeral0\XINTinfloatpower }% \def\XINTinfloatpower{\XINT_flpower_opt_a\XINTdigits.\XINTinfloatS}% % \end{macrocode} %\begin{lverb} % Start of macro. Check for optional argument. %\end{lverb} % \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}% }% \def\XINT_flpower_checkB_c #1.#2.% {% \expandafter\XINT_flpower_checkB_d\the\numexpr#1+#2.#1.#2.% }% \def\XINT_flpower_checkB_d #1.#2.#3.#4.#5#6% {% \expandafter \XINT_flpower_aa \romannumeral0\XINTinfloat [#3]{#6}{#2}{#1}{#4}{#5}% }% \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}% \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}% \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}} % \added{1.2} % \begin{macrocode} \def\xintFloatFac {\romannumeral0\xintfloatfac}% \def\xintfloatfac #1{\XINT_flfac_chkopt \xintfloat #1\xint:}% \def\XINTinFloatFac{\romannumeral0\XINTinfloatfac}% \def\XINTinfloatfac[#1]{\expandafter\XINT_flfac_opt_a\the\numexpr#1.\XINTinfloatS}% \def\XINTinFloatFacdigits{\romannumeral0\XINT_flfac_opt_a\XINTdigits.\XINTinfloatS}% \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} %\begin{lverb} % 1.2f XINT_FL_fac_isneg returns 0, earlier versions used 1 here. %\end{lverb} % \begin{macrocode} \def\XINT_FL_fac_isneg #1.#2#3#4#5% {% #5{\XINT_signalcondition{InvalidOperation} {Factorial argument is 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 argument is too large: #1>=10^8.}{}{ 0[0]}}% }% % \end{macrocode} %\begin{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$ttfamily % > 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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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} %\begin{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.) %\end{lverb} % \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}} % \added[2015/11/29]{1.2f} %\begin{lverb} % Partial factorial pfactorial(a,b)=(a+1)...b, % only for non-negative integers with a<=b<10^8. %\end{lverb} % \changed[2016/11/20]{1.2h} %\begin{lverb} % Now avoids raising \xintError:OutOfRangePFac if the % condition 0<=a<=b<10^8 is violated. Same as for \xintiiPFactorial. %\end{lverb} % \changed{1.4e} %\begin{lverb} % 1.4e extends the precision in floating point context adding some overhead % but well. %\end{lverb} % \begin{macrocode} \def\xintFloatPFactorial {\romannumeral0\xintfloatpfactorial}% \def\xintfloatpfactorial #1{\XINT_flpfac_chkopt \xintfloat #1\xint:}% \def\XINTinFloatPFactorial{\romannumeral0\XINTinfloatpfactorial }% \def\XINTinfloatpfactorial{\XINT_flpfac_opt_a\XINTdigits.\XINTinfloatS}% \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_a\the\numexpr #2.#1% }% \def\XINT_flpfac_opt_a #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 with too large argument: #2 >= 10^8.}{}{ 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} %\begin{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. %\end{lverb} % \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}} % \added[2015/12/01]{1.2f} %\begin{lverb} % 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). %\end{lverb} % \changed[2016/11/19]{1.2h} %\begin{lverb} % 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. % % 1.4e: same remarks as for factorial and partial factorial about added % overhead due to extra guard digits. %\end{lverb} % \begin{macrocode} \def\xintFloatBinomial {\romannumeral0\xintfloatbinomial}% \def\xintfloatbinomial #1{\XINT_flbinom_chkopt \xintfloat #1\xint:}% \def\XINTinFloatBinomial{\romannumeral0\XINTinfloatbinomial }% \def\XINTinfloatbinomial{\XINT_flbinom_opt\XINTinfloatS[\xint:\XINTdigits]}% \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 negative argument: #3.}{}{ 0[0]}}% }% \def\XINT_FL_binom_toobig #1.#2.#3.#4.#5% {% #5[#4]{\XINT_signalcondition{InvalidOperation} {Binomial with too large argument: #3 >= 10^8.}{}{ 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]}}% \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}} % \added{1.08} % \changed{1.2f} %\begin{lverb} % % 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. %\end{lverb} % \begin{macrocode} \def\xintFloatSqrt {\romannumeral0\xintfloatsqrt}% \def\xintfloatsqrt #1{\XINT_flsqrt_chkopt \xintfloat #1\xint:}% \def\XINTinFloatSqrt{\romannumeral0\XINTinfloatsqrt}% \def\XINTinfloatsqrt[#1]{\expandafter\XINT_flsqrt_opt_a\the\numexpr#1.\XINTinfloatS}% \def\XINTinFloatSqrtdigits{\romannumeral0\XINT_flsqrt_opt_a\XINTdigits.\XINTinfloatS}% \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]}}% }% \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.% }% \def\XINT_flsqrt #1.#2.% {% \expandafter\XINT_flsqrt_a \the\numexpr #2/\xint_c_ii-(#1-\xint_c_i)/\xint_c_ii.#1.% }% \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} % % \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}}.% }% \def\XINT_flsqrt_c #1.#2.% {% \expandafter\XINT_flsqrt_d \romannumeral0\XINT_split_fromleft#2.#1\xint_bye2345678\xint_bye..% }% \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.% }% \def\XINT_flsqrt_finish #1#2.#3.#4.#5.#6.#7.#8{#8[#6]{#3#1[#7]}}% \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.}}% \def\XINT_flsqrt_again #1.#2.% {% \expandafter\XINT_flsqrt_again_a\the\numexpr #2+\xint_c_viii.% }% \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}} % \added{1.07} %\begin{lverb} % The fraction is the first argument contrarily to \xintTrunc and % \xintRound. %\end{lverb} %\begin{lverb} % Attention to \XINTinFloatE$empty: it is for use by $xintexprnameimp. % With input 0 it produces on output an 0[N], not 0[0]. %\end{lverb} % \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}% \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}} % \added{1.1} %\begin{lverb} % Pour emploi dans xintexpr. Code shortened at 1.2p. %\end{lverb} % \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}} % \added{1.2p} %\begin{lverb} % Formerly // and /: in \xintfloatexpr used \xintDivFloor and % \xintMod, hence did not round their operands to float precision beforehand. %\end{lverb} % \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}} % \added{1.2p} %\begin{lverb} % 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. % % Breaking change at 1.4 as output format is not comma separated anymore. % Attention also that it uses \expanded. % % No time now at the time of completion of the big 1.4 rewrite of xintexpr % to test whether code efficiency here can be improved to expand the second % item of output. %\end{lverb} % \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{\expanded{{#1}{\XINTinFloat[#3]{#2}}}}% % \end{macrocode} % \subsection{\csh{xintifFloatInt}} % \added{1.3a} %\begin{lverb} % For ifint() function in \xintfloatexpr. %\end{lverb} % \begin{macrocode} \def\xintifFloatInt {\romannumeral0\xintiffloatint}% \def\xintiffloatint #1{\expandafter\XINT_iffloatint \romannumeral0\xintrez{\XINTinFloatS[\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}} % \added{1.3d} %\begin{lverb} % For isint() function in \xintfloatexpr. %\end{lverb} % \begin{macrocode} \def\xintFloatIsInt {\romannumeral0\xintfloatisint}% \def\xintfloatisint #1{\expandafter\XINT_iffloatint \romannumeral0\xintrez{\XINTinFloatS[\XINTdigits]{#1}}10}% % \end{macrocode} % \subsection{\csh{xintFloatIntType}} % \added{1.4e} %\begin{lverb} % For fractional powers. Expands to \xint_c_mone if argument is not an % integer, to \xint_c_ if it is an even integer and to \xint_c_i if it is an % odd integer. %\end{lverb} % \begin{macrocode} \def\xintFloatIntType {\romannumeral`&&@\xintfloatinttype}% \def\xintfloatinttype #1% {% \expandafter\XINT_floatinttype \romannumeral0\xintrez{\XINTinFloatS[\XINTdigits]{#1}}% }% \def\XINT_floatinttype #1#2/1[#3]% {% \if 0#1\xint_dothis\xint_c_\fi \ifnum#3<\xint_c_\xint_dothis\xint_c_mone\fi \ifnum#3>\xint_c_\xint_dothis\xint_c_\fi \ifodd\xintLDg{#1#2} \xint_dothis\xint_c_i\fi \xint_orthat\xint_c_ }% % \end{macrocode} % \subsection{\csh{XINTinFloatdigits}, \csh{XINTinFloatSdigits}} % \begin{macrocode} \def\XINTinFloatdigits {\XINTinFloat [\XINTdigits]}% \def\XINTinFloatSdigits{\XINTinFloatS[\XINTdigits]}% % \end{macrocode} % \subsection{(WIP) \csh{XINTinRandomFloatS}, \csh{XINTinRandomFloatSdigits}} % \added{1.3b} %\begin{lverb} % 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. %\end{lverb} % \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} %\begin{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. %\end{lverb} % \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}} % \added{1.3b} %\begin{lverb} % Support for qrand() function. %\end{lverb} % \begin{macrocode} \def\XINTinRandomFloatSixteen% {% \romannumeral0\expandafter\XINT_inrandomfloatS_a \romannumeral`&&@\expandafter\XINT_eightrandomdigits \romannumeral`&&@\XINT_eightrandomdigits[-16]% }% \let\XINTinFloatMaxof\XINT_Maxof \let\XINTinFloatMinof\XINT_Minof \let\XINTinFloatSum\XINT_Sum \let\XINTinFloatPrd\XINT_Prd \XINTrestorecatcodesendinput% % \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; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintseriesnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \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 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintseries.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintfrac.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintseries Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xintseries}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\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 \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 \def\z{\endgroup\endinput}% xintseries already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintseries}% [2022/06/10 v1.4m 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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{lverb} % 1.08a. I still have to re-visit \xintFxPtPowerSeries; temporarily I % just adapted the code to the case of floats. % % Usage of new names % \XINTinfloatpow_wopt \XINTinfloatmul_wopt, \XINTinfloatadd_wopt to track % xintfrac.sty changes at 1.4e. %\end{lverb} % \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_wopt[#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_wopt[#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_wopt[#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_wopt[#7]{#4}% {\XINTinfloatmul_wopt[#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_wopt[#7]{#6{#2}}{#1}}% }% % \end{macrocode} % \subsection{\csh{xintFloatPowerSeriesX}} %\begin{lverb} % 1.08a % % See \xintFloatPowerSeries for 1.4e comments. %\end{lverb} % \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_wopt[#5]{#1}{#2}}% {#2}{#1}{#3}{#4}{#5}% }% \XINTrestorecatcodesendinput% % \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; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintcfracnameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \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 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintcfrac.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintfrac.sty\endcsname \expandafter\ifx\csname numexpr\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintcfrac Warning:^^J% \space\space\space\space \numexpr not available, aborting input.^^J}% \else \PackageWarningNoLine{xintcfrac}{\numexpr not available, aborting input}% \fi \def\z{\endgroup\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 \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 \def\z{\endgroup\endinput}% xintcfrac already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% defined in xintkernel.sty % \end{macrocode} % \subsection{Package identification} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintcfrac}% [2022/06/10 v1.4m 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}} % Updated at |1.4g| to follow-up on renaming of |\xintFrac| into |\xintTeXFrac|. % \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{\xintTeXFrac{#4}}}% \def\XINT_gcfrac_U #1#2#3#4#5% {% \xint_gob_til_exclam #5\XINT_gcfrac_end!\XINT_gcfrac_U #1#2{\xintTeXFrac{#5}% \ifcase\xintSgn{#4} +\or+\else-\fi \cfrac{#1\xintTeXFrac{\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}} %\begin{lverb} % New with 1.09m %\end{lverb} % \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}} %\begin{lverb} % Modified in 1.09m: a space is added after the inserted commas. %\end{lverb} % \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}} %\begin{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 {} %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{lverb} % Still uses \xinticstocv \xintFtoCs rather than \xintctocv \xintFtoC. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}} %\begin{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. %\end{lverb} % \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}}% \XINTrestorecatcodesendinput% % \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; sentence-end-double-space: t; eval: (auto-fill-mode -1); ; fill-paragraph-function: nil; -*- % \clearpage\csname xintexprnameUp\endcsname % \let\MakePrivateLetters\xintexprMakePrivateLetters % \section{Package \xintexprnameimp implementation} % \RaisedLabel{sec:exprimp} % \etocarticlestylenomarks % \etocstandardlines % \etocsettocdepth {paragraph} % % This is release \expandafter|\xintbndlversion| of % \expandafter|\xintbndldate|. % % \localtableofcontents % % \etocsettocstyle{}{} % % \subsection{READ ME! Important warnings and explanations relative to the % status of the code source at the time of the 1.4 release} % \def\mybeginitemize{\begin{itemize}\catcode`\% 9 }^^A % \def\myenditemize{\end{itemize}}^^A %\begin{lverb} % At release 1.4 the csname encapsulation of intermediate evaluations during % parsing of expressions is dropped, and $xintexprnameimp requires the % \expanded primitive. This means that there is no more impact on the string % pool. And as internal storage now uses simply core \TeX{} syntax with braces % rather than comma separated items inside a csname dummy control sequence, % it became much easier to let the [...] syntax be associated to a true internal type of «tuple» % or «list». % % The output of \xintexpr (after \romannumeral0 or \romannumeral-`0 triggered % expansion or double expansion) is thus modified at 1.4. It now looks like % this: % % \XINTfstop \XINTexprprint .{{<number>}} in simplest case % % \XINTfstop \XINTexprprint .{{...}...{...}} in general case % % where ... stands for nested braces ultimately ending in {<num. rep.>} leaves. % The <num. rep.> stands for some internal representation of numeric data. It % may be empty, and currently as well as probably in future uses only catcode % 12 tokens (no spaces currently). % % {{}} corresponds (in input as in output) to []. The external TeX braces also % serve as set-theoretical braces. The comma is concatenation, so for example % [], [] will become {{}{}}, or rather {}{} if sub-unit of something else. % % The associated vocabulary is explained in the user manual and we avoid % too much duplication here. $xintfracnameimp numerical macros receiving an % empty argument usually handle it as being 0, but this is not the case of the % $xintcorenameimp macros supporting \xintiiexpr, they usually break if % exercised on some empty argument. % % The above expansion result \XINTfstop \XINTexprprint .{{<num1>}{<num2}...} % uses only normal catcodes: % the backslash, regular braces, and catcode 12 characters. Scientific % notation is internally converted to raw $xintfracnameimp representation % [N]. % % Additional data may be located before the dot; this is the case only for % \xintfloatexpr currently. As % xintexpr actually defines three parsers \xintexpr, \xintiiexpr and % \xintfloatexpr but tries to share as much code as possible, some overhead % is induced to fit all into the same mold. % % \XINTfstop stops \romannumeral-`0 (or 0) type spanned expansion, and is % invariant under \edef, but simply disappears in typesetting context. It is % thus now legal to use \xintexpr directly in typesetting flow. % % \XINTexprprint is \protected. % % The f-expansion of an \xintexpr <expression>\relax is a complete expansion, % i.e. one whose result remains invariant under \edef. But if exposed to % finitely many expansion steps (at least two) there is a «blinking» \noexpand % upfront depending on parity of number of steps. % % \xintthe\xintexpr <expression>\relax or \xinteval{<expression>} serve as % formerly to deliver the explicit digits, or more exactly some prettifying % view of the actual <internal number representation>. % % Nested contents like this % % {{1}{{2}{3}{{4}{5}{6}}}{9}} % % $noindent will get delivered using nested square brackets like that % % 1, [2, 3, [4, 5, 6]], 9 % % $noindent and as conversely \xintexpr 1, [2, 3, [4, 5, 6]], 9\relax expands to % % \XINTfstop \XINTexprprint .{{1}{{2}{3}{{4}{5}{6}}}{9}} % % $noindent we obtain the gratifying result that % % \xinteval{1, [2, 3, [4, 5, 6]], 9} % % $noindent expands to % % 1, [2, 3, [4, 5, 6]], 9 % % See user manual for explanations on the plasticity of \xintexpr syntax % regarding functions with multiple arguments, and the 1.4 «unpacking» % Python-like * prefix operator. % %\end{lverb} % % \begin{framed} % I have suppressed (from the public dtx) many big chunks of % comments. Some became obsolete and need to be updated, others are % currently of value only to the author as a historical record. % % ATTENTION! As the removal process itself took too much time, I ended up % leaving as is many comments which are obsoleted and wrong to various % degrees after the |1.4| release. Precedence levels of operators have all % been doubled to make room for new constructs % % Even comments added during 1.4 developement may now be obsolete because % the preparation of 1.4 took a few weeks and that's enough of duration to % provide the author many chances to contradict in the code what has been % already commented upon. % % Thus don't believe (fully) anything which is said here!\IMPORTANTf{} % \end{framed} % % %\begin{lverb} % Warning: in text below and also in left-over old comments I may refer % to «until» and «op» macros; due to the change of data storage at 1.4, I % needed to refactor a bit the way expansion is controlled, and the situation % now is mainly governed by «op», «exec», «check-» and «checkp» macros the % latter three replacing the two «until_a» and «until_b» of former code. This % allows to diminish the number of times an accumulated result will be grabbed % in order to propagate expansion to its right. Formerly this was not an issue % because such things were only a single token! I do not describe here how % this is all articulated but it is not hard to see it from the code (the % hardest thing in all such matter was in 2013 to actually write how the % expansion would be initially launched because to do that one basically has to % understand the mechanism in its whole and such things are not easy to % develop piecemeal). Another thing to keep in mind is that operators in truth % have a left precedence (i.e. the precedence they show to operators arising % earlier) and a right precedence (which determines how they react to % operators coming after them from the right). Only the first one is usually % encapsulated in a chardef, the second one is most of the times identical to % the first one and if not it is only virtual but implemented via \ifcase of % \ifnum branching. A final remark is that some things are achieved by special % «op» macros, which are a favorite tool to hack into the normal regular flow % of things, via injection of special syntax elements. I did not rename these % macros for avoiding too large git diffs, and besides the nice thing is that % the 1.4 refactoring minimally had to modify them, and all hacky things using % them kept on working with not a single modification. And a post-scriptum is % that advanced features crucially exploit injecting sub-\xintexpr-essions, as % all is expandable there is no real «context» (only a minimal one) which one % would have to perhaps store and restore and doing this sub-expression % injection is rather cheap and efficient operation. %\end{lverb} % % \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 % @ \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \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 % I don't think engine exists providing \expanded but not \numexpr \expandafter\ifx\csname expanded\endcsname\relax \expandafter\ifx\csname PackageWarningNoLine\endcsname\relax \immediate\write128{^^JPackage xintexpr Warning:^^J% \space\space\space\space \expanded not available, aborting input.^^J}% \else \PackageWarningNoLine{xintexpr}{\expanded not available, aborting input}% \fi \def\z{\endgroup\endinput}% \else \ifx\x\relax % plain-TeX (possibly with miniltx!), first loading of xintexpr.sty \ifx\w\relax % but xintfrac.sty not yet loaded (made miniltx robust 2022/06/09) \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 \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 \def\z{\endgroup\endinput}% xintexpr already loaded. \fi \fi \fi \z% \XINTsetupcatcodes% % \end{macrocode} % \subsection{Package identification} %\begin{lverb} % \XINT_Cmp alias for \xintiiCmp needed for some forgotten reason related to % \xintNewExpr (FIX THIS!) % %\end{lverb} % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintexpr}% [2022/06/10 v1.4m Expandable expression parser (JFB)]% \catcode`! 11 \let\XINT_Cmp \xintiiCmp \def\XINTfstop{\noexpand\XINTfstop}% % \end{macrocode} % \subsection{\csh{xintDigits*}, \csh{xintSetDigits*}, \csh{xintreloadscilibs}} %\begin{lverb} % 1.3f. 1.4e added some \xintGuardDigits and \XINTdigitsx mechanism but % it was finally removed, due to pending issues of user interface, % functionality, and documentation (the worst part) for whose resolution % no time was left. %\end{lverb} % \begin{macrocode} \def\xintreloadscilibs{\xintreloadxintlog\xintreloadxinttrig}% \def\xintDigits {\futurelet\XINT_token\xintDigits_i}% \def\xintDigits_i#1={\afterassignment\xintDigits_j\mathchardef\XINT_digits=}% \def\xintDigits_j#1% {% \let\XINTdigits=\XINT_digits \ifx*\XINT_token\expandafter\xintreloadscilibs\fi }% \let\xintfracSetDigits\xintSetDigits \def\xintSetDigits#1#{\if\relax\detokenize{#1}\relax\expandafter\xintfracSetDigits \else\expandafter\xintSetDigits_a\fi}% \def\xintSetDigits_a#1% {% \mathchardef\XINT_digits=\numexpr#1\relax \let\XINTdigits\XINT_digits \xintreloadscilibs }% % \end{macrocode} % \subsection{\csh{XINTdigitsormax}} %\begin{lverb} % 1.4f. To not let xintlog and xinttrig work with, and produce, % long mantissas exceeeding the supported range for accuracy of the math % functions. The official maximal value is 62, let's set the cut-off at 64. % % A priori, no need for \expandafter, always ends up expanded in \numexpr (I % saw also in an \edef in xinttrig as argument to \xintReplicate prior % to its \numexpr). %\end{lverb} % \begin{macrocode} \def\XINTdigitsormax{\ifnum\XINTdigits>\xint_c_ii^vi\xint_c_ii^vi\else\XINTdigits\fi}% % \end{macrocode} % \subsection{Support for output and transform of nested braced contents as % core data type} % New at 1.4, of course. The former |\csname.=...\endcsname| encapsulation % technique made very difficult implementation of nested structures. % \subsubsection{Bracketed list rendering with prettifying of leaves from nested % braced contents} % \added{1.4} % The braces in |\XINT:expr:toblistwith| are there because there is % an |\expanded| trigger. % \changed{1.4d} %\begin{lverb} % Add support for the polexpr 0.8 polynomial type. See \XINT:expr:toblist_a. %\end{lverb} % \changed{1.4l} %\begin{lverb} % Let \XINT:expr:toblist_b use #1{#2} with regular { and } in case % macro #1 is \protected and things are output to external file where former % #1<#2> would end up with catcode 12 < and >. %\end{lverb} % \begin{macrocode} \def\XINT:expr:toblistwith#1#2% {% {\expandafter\XINT:expr:toblist_checkempty \expanded{\noexpand#1!\expandafter}\detokenize{#2}^}% }% \def\XINT:expr:toblist_checkempty #1!#2% {% \if ^#2\expandafter\xint_gob_til_^\else\expandafter\XINT:expr:toblist_a\fi #1!#2% }% \catcode`< 1 \catcode`> 2 \catcode`{ 12 \catcode`} 12 \def\XINT:expr:toblist_a #1{#2% <% \if{#2\xint_dothis<[\XINT:expr:toblist_a>\fi \if P#2\xint_dothis<\XINT:expr:toblist_pol>\fi \xint_orthat\XINT:expr:toblist_b #1#2% >% \def\XINT:expr:toblist_pol #1!#2.{#3}}% <% pol([\XINT:expr:toblist_b #1!#3}^])\XINT:expr:toblist_c #1!}% >% \catcode`{ 1 \catcode`} 2 \def\XINT:expr:toblist_b #1{% \def\XINT:expr:toblist_b ##1!##2#1% {% \if\relax##2\relax\xintexprEmptyItem\else##1{##2}\fi\XINT:expr:toblist_c ##1!#1% }}\catcode`{ 12 \catcode`} 12 \XINT:expr:toblist_b<}>% \def\XINT:expr:toblist_c #1}#2% <% \if ^#2\xint_dothis<\xint_gob_til_^>\fi \if{#2\xint_dothis<, \XINT:expr:toblist_a>\fi \xint_orthat<]\XINT:expr:toblist_c>#1#2% >% \catcode`{ 1 \catcode`} 2 \catcode`< 12 \catcode`> 12 % \end{macrocode} % \subsubsection{Flattening nested % braced contents} %\begin{lverb} % 1.4b I hesitated whether using this technique or some variation of % the method of the ListSel macros. I chose this one which I downscaled from % toblistwith, I will revisit later. I only have a few minutes right now. % % Call form is \expanded\XINT:expr:flatten % % See \XINT_expr_func_flat. I hesitated with «flattened», but short names % are faster parsed. %\end{lverb} % \begin{macrocode} \def\XINT:expr:flatten#1% {% {{\expandafter\XINT:expr:flatten_checkempty\detokenize{#1}^}}% }% \def\XINT:expr:flatten_checkempty #1% {% \if ^#1\expandafter\xint_gobble_i\else\expandafter\XINT:expr:flatten_a\fi #1% }% \begingroup \catcode`[ 1 \catcode`] 2 \lccode`[`{ \lccode`]`} \catcode`< 1 \catcode`> 2 \catcode`{ 12 \catcode`} 12 \lowercase<\endgroup \def\XINT:expr:flatten_a {#1% <% \if{#1\xint_dothis<\XINT:expr:flatten_a>\fi \xint_orthat\XINT:expr:flatten_b #1% >% \def\XINT:expr:flatten_b #1}% <% [#1]\XINT:expr:flatten_c }% >% \def\XINT:expr:flatten_c }#1% <% \if ^#1\xint_dothis<\xint_gobble_i>\fi \if{#1\xint_dothis<\XINT:expr:flatten_a>\fi \xint_orthat<\XINT:expr:flatten_c>#1% >% >% back to normal catcodes % \end{macrocode} % \subsubsection{Braced contents rendering via a \TeX{} alignment with prettifying of leaves} %\begin{lverb} % 1.4. % % Breaking change at 1.4a as helper macros were renamed and their meanings % refactored: no more \xintexpraligntab nor \xintexpraligninnercomma or % \xintexpralignoutercomma but \xintexpraligninnersep, etc... % % At 1.4c I remove the \protected from \xintexpralignend. I had made note a % year ago that it served nothing. Let's trust myself on this one (risky one % year later!). %\end{lverb} % \begin{macrocode} \catcode`& 4 \protected\def\xintexpralignbegin {\halign\bgroup\tabskip2ex\hfil##&&##\hfil\cr}% \def\xintexpralignend {\crcr\egroup}% \protected\def\xintexpralignlinesep {,\cr}% \protected\def\xintexpralignleftbracket {[}% \protected\def\xintexpralignrightbracket{]}% \protected\def\xintexpralignleftsep {&}% \protected\def\xintexpralignrightsep {&}% \protected\def\xintexpraligninnersep {,&}% \catcode`& 7 \def\XINT:expr:toalignwith#1#2% {% {\expandafter\XINT:expr:toalign_checkempty \expanded{\noexpand#1!\expandafter}\detokenize{#2}^\expandafter}% \xintexpralignend }% \def\XINT:expr:toalign_checkempty #1!#2% {% \if ^#2\expandafter\xint_gob_til_^\else\expandafter\XINT:expr:toalign_a\fi #1!#2% }% \catcode`< 1 \catcode`> 2 \catcode`{ 12 \catcode`} 12 \def\XINT:expr:toalign_a #1{#2% <% \if{#2\xint_dothis<\xintexpralignleftbracket\XINT:expr:toalign_a>\fi \xint_orthat<\xintexpralignleftsep\XINT:expr:toalign_b>#1#2% >% \def\XINT:expr:toalign_b #1!#2}% <% \if\relax#2\relax\xintexprEmptyItem\else#1<#2>\fi\XINT:expr:toalign_c #1!}% >% \def\XINT:expr:toalign_c #1}#2% <% \if ^#2\xint_dothis<\xint_gob_til_^>\fi \if {#2\xint_dothis<\xintexpraligninnersep\XINT:expr:toalign_A>\fi \xint_orthat<\xintexpralignrightsep\xintexpralignrightbracket\XINT:expr:toalign_C>#1#2% >% \def\XINT:expr:toalign_A #1{#2% <% \if{#2\xint_dothis<\xintexpralignleftbracket\XINT:expr:toalign_A>\fi \xint_orthat\XINT:expr:toalign_b #1#2% >% \def\XINT:expr:toalign_C #1}#2% <% \if ^#2\xint_dothis<\xint_gob_til_^>\fi \if {#2\xint_dothis<\xintexpralignlinesep\XINT:expr:toalign_a>\fi \xint_orthat<\xintexpralignrightbracket\XINT:expr:toalign_C>#1#2% >% \catcode`{ 1 \catcode`} 2 \catcode`< 12 \catcode`> 12 % \end{macrocode} % \subsubsection{Transforming all leaves within nested % braced contents} % %\begin{lverb} % 1.4. Leaves must be of catcode 12... This is currently not a % constraint (or rather not a new constraint) for xintexpr because formerly % anyhow all data went through csname encapsulation and extraction via string. % % In order to share code with the functioning of universal functions, which % will be allowed to transform a number into an ople, the applied macro % is supposed to apply one level of bracing to its ouput. Thus to apply this % with an xintfrac macro such as \xintiRound{0} one needs first to define % a wrapper which will expand it inside an added brace pair: % % \def\foo#1{{\xintiRound{0}{#1}}} % % As the things will expand inside expanded, propagating expansion is not an % issue. % % This code is used by \xintiexpr and \xintfloatexpr in case of optional % argument and by the «Universal functions». % % Comment at 1.4l: this seems to be used only at private package level, else % I should modify \XINT:expr:mapwithin_b like I did with \XINT:expr:toblist_b % to use regular braces in case the applied macro is \protected and % things end up in external file. %\end{lverb} % % \begin{macrocode} \def\XINT:expr:mapwithin#1#2% {% {{\expandafter\XINT:expr:mapwithin_checkempty \expanded{\noexpand#1!\expandafter}\detokenize{#2}^}}% }% \def\XINT:expr:mapwithin_checkempty #1!#2% {% \if ^#2\expandafter\xint_gob_til_^\else\expandafter\XINT:expr:mapwithin_a\fi #1!#2% }% \begingroup \catcode`[ 1 \catcode`] 2 \lccode`[`{ \lccode`]`} \catcode`< 1 \catcode`> 2 \catcode`{ 12 \catcode`} 12 \lowercase<\endgroup \def\XINT:expr:mapwithin_a #1{#2% <% \if{#2\xint_dothis<[\iffalse]\fi\XINT:expr:mapwithin_a>\fi% \xint_orthat\XINT:expr:mapwithin_b #1#2% >% \def\XINT:expr:mapwithin_b #1!#2}% <% #1<#2>\XINT:expr:mapwithin_c #1!}% >% \def\XINT:expr:mapwithin_c #1}#2% <% \if ^#2\xint_dothis<\xint_gob_til_^>\fi \if{#2\xint_dothis<\XINT:expr:mapwithin_a>\fi% \xint_orthat<\iffalse[\fi]\XINT:expr:mapwithin_c>#1#2% >% >% back to normal catcodes % \end{macrocode} % \subsection{Top level user \TeX{} interface: \cshnolabel{xinteval}, % \cshnolabel{xintfloateval}, \cshnolabel{xintiieval}} % \localtableofcontents % \subsubsection{\csh{xintexpr}, \csh{xintiexpr}, \csh{xintfloatexpr}, % \csh{xintiiexpr}} %\begin{lverb} % % \xintiexpr and \xintfloatexpr have an optional argument since 1.1. % % ATTENTION! 1.3d renamed \xinteval to \xintexpro etc... % % % Usage of \xintiRound{0} for \xintiexpr without optional [D] means that % \xintiexpr ... \relax wrapper can be used to insert rounded-to-integers % values in \xintiiexpr context: no post-fix [0] which would break it. % % 1.4a add support for the optional argument [D] for \xintiexpr being negative % D, with same meaning as the 1.4a modified \xintRound from xintfrac.sty. % % \xintiexpr mechanism was refactored at 1.4e so that rounding due to [D] % optional argument uses raw format, not fixed point format on output, % delegating fixed point conversion to an \XINTiexprprint now separated from % \XINTexprprint. % % In case of negative [D], \xintiexpr [D]...\relax internally has the [0] % post-fix so it can not be inserted as sub-expression in \xintiiexpr without % a num() or \xintiexpr ...\relax (extra) wrapper. % %\end{lverb} % \begin{macrocode} \def\xintexpr {\romannumeral0\xintexpro }% \def\xintiexpr {\romannumeral0\xintiexpro }% \def\xintfloatexpr {\romannumeral0\xintfloatexpro }% \def\xintiiexpr {\romannumeral0\xintiiexpro }% \def\xintexpro {\expandafter\XINT_expr_wrap\romannumeral0\xintbareeval }% \def\xintiiexpro {\expandafter\XINT_iiexpr_wrap\romannumeral0\xintbareiieval }% \def\xintiexpro #1% {% \ifx [#1\expandafter\XINT_iexpr_withopt\else\expandafter\XINT_iexpr_noopt \fi #1% }% \def\XINT_iexpr_noopt {% \expandafter\XINT_iexpr_iiround\romannumeral0\xintbareeval }% \def\XINT_iexpr_iiround {% \expandafter\XINT_expr_wrap \expanded \XINT:NEhook:x:mapwithin\XINT:expr:mapwithin{\XINTiRoundzero_braced}% }% \def\XINTiRoundzero_braced#1{{\xintiRound{0}{#1}}}% \def\XINT_iexpr_withopt [#1]% {% \expandafter\XINT_iexpr_round \the\numexpr \xint_zapspaces #1 \xint_gobble_i\expandafter.% \romannumeral0\xintbareeval }% \def\XINT_iexpr_round #1.% {% \ifnum#1=\xint_c_\xint_dothis{\XINT_iexpr_iiround}\fi \xint_orthat{\XINT_iexpr_round_a #1.}% }% \def\XINT_iexpr_round_a #1.% {% \expandafter\XINT_iexpr_wrap \expanded \XINT:NEhook:x:mapwithin\XINT:expr:mapwithin{\XINTiRound_braced{#1}}% }% \def\XINTiRound_braced#1#2% {{\xintiRound{#1}{#2}[\the\numexpr\ifnum#1<\xint_c_i0\else-#1\fi]}}% \def\xintfloatexpro #1% {% \ifx [#1\expandafter\XINT_flexpr_withopt\else\expandafter\XINT_flexpr_noopt \fi #1% }% \def\XINT_flexpr_noopt {% \expandafter\XINT_flexpr_wrap\the\numexpr\XINTdigits\expandafter.% \romannumeral0\xintbarefloateval }% \def\XINT_flexpr_withopt [#1]% {% \expandafter\XINT_flexpr_withopt_a \the\numexpr\xint_zapspaces #1 \xint_gobble_i\expandafter.% \romannumeral0\xintbarefloateval }% \def\XINT_flexpr_withopt_a #1#2.% {% \expandafter\XINT_flexpr_withopt_b\the\numexpr\if#1-\XINTdigits\fi#1#2.% }% \def\XINT_flexpr_withopt_b #1.% {% \expandafter\XINT_flexpr_wrap \the\numexpr#1\expandafter.% \expanded \XINT:NEhook:x:mapwithin\XINT:expr:mapwithin{\XINTinFloat_braced[#1]}% }% \def\XINTinFloat_braced[#1]#2{{\XINTinFloat[#1]{#2}}}% % \end{macrocode} % \subsubsection{\csh{XINT_expr_wrap}, \csh{XINT_iiexpr_wrap}, \csh{XINT_flexpr_wrap}} %\begin{lverb} % 1.3e removes some leading space tokens which served nothing. There is % no \XINT_iexpr_wrap, because \XINT_expr_wrap is used directly. % % 1.4e has \XINT_iexpr_wrap separated from \XINT_expr_wrap, thus simplifying % internal matters as output printer for \xintexpr will not have to handle % fixed point input but only extended-raw type input (i.e. A, A/B, A[N] or A/B[N]). %\end{lverb} % \begin{macrocode} \def\XINT_expr_wrap {\XINTfstop\XINTexprprint.}% \def\XINT_iexpr_wrap {\XINTfstop\XINTiexprprint.}% \def\XINT_iiexpr_wrap {\XINTfstop\XINTiiexprprint.}% \def\XINT_flexpr_wrap {\XINTfstop\XINTflexprprint}% % \end{macrocode} % \subsubsection{\csh{XINTexprprint}, \csh{XINTiexprprint}, \csh{XINTiiexprprint}, \csh{XINTflexprprint}} % \label{\xintimplabelprefix xintexprPrintOne} % \label{\xintimplabelprefix xintiexprPrintOne} % \label{\xintimplabelprefix xintfloatexprPrintOne} % \label{\xintimplabelprefix xintiiexprprintone} % % \changed{1.4} % Requires |\expanded|. % % % \changed{1.4e} %\begin{lverb} % 1.4e has a breaking change of \XINTflexprprint and \xintfloatexprPrintOne % which now requires \xintfloatexprPrintOne[D]{x} syntax, with first argument % in brackets. % %\end{lverb} % \changed{1.4l} % The code does |\let\xintexprPrintOne\xint_FracToSci_x| but the latter is not yet % defined so this is delayed until |\xint_FracToSci_x| definition. % \changed[2022/06/05]{1.4m} % \csa{xintboolexprPrintOne} outputs |true| or |false|, not |True| or |False|. % By the way (undocumented) all four keywords |true|, |false|, |True|, % |False| are recognized as genuine variables since |1.4i|. % \begin{macrocode} \protected\def\XINTexprprint.% {\XINT:NEhook:x:toblist\XINT:expr:toblistwith\xintexprPrintOne}% \protected\def\XINTiexprprint.% {\XINT:NEhook:x:toblist\XINT:expr:toblistwith\xintiexprPrintOne}% \let\xintiexprPrintOne\xintDecToString \def\xintexprEmptyItem{[]}% \protected\def\XINTiiexprprint.% {\XINT:NEhook:x:toblist\XINT:expr:toblistwith\xintiiexprPrintOne}% \let\xintiiexprPrintOne\xint_firstofone \protected\def\XINTflexprprint #1.% {\XINT:NEhook:x:toblist\XINT:expr:toblistwith{\xintfloatexprPrintOne[#1]}}% \let\xintfloatexprPrintOne\xintPFloat_wopt \protected\def\XINTboolexprprint.% {\XINT:NEhook:x:toblist\XINT:expr:toblistwith\xintboolexprPrintOne}% \def\xintboolexprPrintOne#1{\xintiiifNotZero{#1}{true}{false}}% % \end{macrocode} % \subsubsection{\csh{xintthe}, \csh{xintthealign}, \csh{xinttheexpr}, \csh{xinttheiexpr}, \csh{xintthefloatexpr}, % \csh{xinttheiiexpr}} %\begin{lverb} % The reason why \xinttheiexpr et \xintthefloatexpr are handled % differently is that they admit an optional argument which acts via a custom % «printing» stage. % % We exploit here that \expanded expands forward until finding an implicit or % explicit brace, and that this expansion overrules \protected macros, forcing % them to expand, similarly as \romannumeral expands \protected macros, and % contrarily to what happens *within* the actual \expanded scope. I discovered % this fact by testing (with pdftex) and I don't know where this is documented % apart from the source code of the relevant engines. This is useful to us % because there are contexts where we will want to apply a complete expansion % before printing, but in purely numerical context this is not needed (if I % converted correctly after dropping at 1.4 the \csname governed expansions; % however I rely at various places on the fact that the xint macros are % f-expandable, so I have tried to not use zillions of expanded all over the % place), hence it is not needed to add the expansion overhead by default. But % the \expanded here will allow \xintNewExpr to create macro with suitable % modification or the printing step, via some hook rather than having to % duplicate all macros here with some new «NE» meaning (aliasing does not work % or causes big issues due to desire to support \xinteval also in «NE» context % as sub-constituent. The \XINT:NEhook:x:toblist is something else which % serves to achieve this support of *sub* \xinteval, it serves nothing for % the actual produced macros. For \xintdeffunc, things are simpler, but still % we support the [N] optional argument of \xintiexpr and \xintfloatexpr, which % required some work... % % The \expanded upfront ensures \xintthe mechanism does expand % completely in two steps. %\end{lverb} % \begin{macrocode} \def\xintthe #1{\expanded\expandafter\xint_gobble_i\romannumeral`&&@#1}% \def\xintthealign #1{\expandafter\xintexpralignbegin \expanded\expandafter\XINT:expr:toalignwith \romannumeral0\expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter\xint_gob_andstop_ii \expandafter\xint_gobble_i\romannumeral`&&@#1}% \def\xinttheexpr {\expanded\expandafter\XINTexprprint\expandafter.\romannumeral0\xintbareeval}% \def\xinttheiexpr {\expanded\expandafter\xint_gobble_i\romannumeral`&&@\xintiexpr}% \def\xintthefloatexpr {\expanded\expandafter\xint_gobble_i\romannumeral`&&@\xintfloatexpr}% \def\xinttheiiexpr {\expanded\expandafter\XINTiiexprprint\expandafter.\romannumeral0\xintbareiieval}% % \end{macrocode} % \subsubsection{\csh{xintbareeval}, \csh{xintbarefloateval}, \csh{xintbareiieval}} %\begin{lverb} % At 1.4 added one expansion step via _start macros. Triggering is expected to be % via either \romannumeral`^^@ or \romannumeral0 is also ok %\end{lverb} % \begin{macrocode} \def\xintbareeval {\XINT_expr_start }% \def\xintbarefloateval{\XINT_flexpr_start}% \def\xintbareiieval {\XINT_iiexpr_start}% % \end{macrocode} % \subsubsection{\csh{xintthebareeval}, \csh{xintthebarefloateval}, % \csh{xintthebareiieval}} %\begin{lverb} % For matters of \XINT_NewFunc %\end{lverb} % \begin{macrocode} \def\XINT_expr_unlock {\expandafter\xint_firstofone\romannumeral`&&@}% \def\xintthebareeval {\romannumeral0\expandafter\xint_stop_atfirstofone\romannumeral0\xintbareeval}% \def\xintthebareiieval {\romannumeral0\expandafter\xint_stop_atfirstofone\romannumeral0\xintbareiieval}% \def\xintthebarefloateval {\romannumeral0\expandafter\xint_stop_atfirstofone\romannumeral0\xintbarefloateval}% \def\xintthebareroundedfloateval {% \romannumeral0\expandafter\xintthebareroundedfloateval_a\romannumeral0\xintbarefloateval }% \def\xintthebareroundedfloateval_a {% \expandafter\xint_stop_atfirstofone \expanded\XINT:NEhook:x:mapwithin\XINT:expr:mapwithin{\XINTinFloatSdigits_braced}% }% \def\XINTinFloatSdigits_braced#1{{\XINTinFloatS[\XINTdigits]{#1}}}% % \end{macrocode} % \subsubsection{\csh{xinteval}, \csh{xintieval}, \csh{xintfloateval}, % \csh{xintiieval}} %\begin{lverb} % Refactored at 1.4. % % The \expanded upfront ensures \xinteval still expands % completely in two steps. No \romannumeral trigger here, in relation to the % fact that \XINTexprprint is no f-expandable, only e-expandable. % % (and attention that \xintexpr\relax is now legal, and an empty ople can be % produced in output also from \xintexpr [17][1]\relax for example) %\end{lverb} % \changed[2022/05/16]{1.4k} %\begin{lverb} % The \xintieval and \xintfloateval optional bracketed argument can now % be located outside the braces... took me years to finally make the step toward LaTeX % users expectations for a decent interface. %\end{lverb} % \begin{macrocode} \def\xinteval #1% {\expanded\expandafter\XINTexprprint\expandafter.\romannumeral0\xintbareeval#1\relax}% \def\xintieval {\expanded\expandafter\xint_ieval_chkopt\string}% \def\xint_ieval_chkopt #1% {% \ifx [#1\expandafter\xint_ieval_opt \else\expandafter\xint_ieval_noopt \fi #1% }% \def\xint_ieval_opt [#1]#2% {\expandafter\xint_gobble_i\romannumeral`&&@\xintiexpr[#1]#2\relax}% \def\xint_ieval_noopt #1{\expandafter\xint_ieval\expandafter{\iffalse}\fi}% \def\xint_ieval#1% {\expandafter\xint_gobble_i\romannumeral`&&@\xintiexpr#1\relax}% \def\xintfloateval {\expanded\expandafter\xint_floateval_chkopt\string}% \def\xint_floateval_chkopt #1% {% \ifx [#1\expandafter\xint_floateval_opt \else\expandafter\xint_floateval_noopt \fi #1% }% \def\xint_floateval_opt [#1]#2% {\expandafter\xint_gobble_i\romannumeral`&&@\xintfloatexpr[#1]#2\relax}% \def\xint_floateval_noopt #1{\expandafter\xint_floateval\expandafter{\iffalse}\fi}% \def\xint_floateval#1% {\expandafter\xint_gobble_i\romannumeral`&&@\xintfloatexpr#1\relax}% \def\xintiieval #1% {\expanded\expandafter\XINTiiexprprint \expandafter.\romannumeral0\xintbareiieval#1\relax}% % \end{macrocode} % \subsubsection{\csh{xintboolexpr}, \csh{XINT_boolexpr_print}, \csh{xinttheboolexpr}} %\begin{lverb} % ATTENTION! 1.3d renamed \xinteval to \xintexpro etc... % % Attention, the conversion to 1 or 0 is done only by the print macro. % Perhaps I should force it also inside raw result. %\end{lverb} % \begin{macrocode} \def\xintboolexpr {% \romannumeral0\expandafter\XINT_boolexpr_done\romannumeral0\xintexpro }% \def\XINT_boolexpr_done #1.{\XINTfstop\XINTboolexprprint.}% \def\xinttheboolexpr {% \expanded\expandafter\XINTboolexprprint\expandafter.\romannumeral0\xintbareeval }% % \end{macrocode} % \subsubsection{\csh{xintifboolexpr}, \csh{xintifboolfloatexpr}, \csh{xintifbooliiexpr}} %\begin{lverb} % They do not accept comma separated expressions input. %\end{lverb} % \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} % \subsubsection{\csh{xintifsgnexpr}, \csh{xintifsgnfloatexpr}, \csh{xintifsgniiexpr}} % \changed{1.3d} %\begin{lverb} % They do not accept comma separated expressions. %\end{lverb} % \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} % \subsubsection{\csh{xint_FracToSci_x}} % \added{1.4} % Under the name of |\xintFracToSci| and defined in \xintfracnameimp. % \changed{1.4e} %\begin{lverb} % Refactored and much simplified % % It only needs to be x-expandable, and indeed the implementation here is only % x-expandable. %\end{lverb} %\begin{lverb} % % Finally for 1.4e release I modify. This is breaking change for all % \xinteval output in case of scientific notation: it will not be with an % integer mantissa, but with regular scientific notation, using the same rules % as \xintPFloat. % % Of course no float rounding! Also, as [0] will always or almost always be % present from an \xinteval, we want then to use integer not scientific % notation. But expression contained decimal fixed point input, or uses % scientific functions, then probably the N will not be zero and this will % trigger usage of scientific notation in output. % % Implementing these changes sort of ruin our previous efforts to minimize % grabbing the argument, but well. So the rules now are % %( Input: A, A/B, A[N], A/B[N] %: Output: A, A/B, A if N=0, A/B if N=0 %: If N is not zero, scientific notation like \xintPFloat,& % i.e. behaviour like \xintfloateval apart from the rounding& % to significands of width Digits.& % At 1.4k, trimming of zeros from A is always done, i.e.& % the \xintPFloatMinTrimmed is ignored to keep behaviour.& % unchanged. Trailing zeros of B are kept as is. %: The zero gives 0, except in A[N] and A/B[N] cases, it may give& % 0.0 %) %\end{lverb} % \changed{1.4k} % Moved from \xintfracnameimp to \xintexprnameimp. % \changed{1.4l} %\begin{lverb} % Renamed to \xint_FracToSci_x to make it private and provide in % $xintfracnameimp another \xintFracToSci with same output but which behaves % like other macros there: f-expandable and accepting the whole range of % inputs accepted by the xintfrac public macros. % % The private x-expandable macro here will have an empty output for an empty % input but is never used for an empty input (see \xintexprEmptyItem). %\end{lverb} % \begin{macrocode} \def\xint_FracToSci_x #1{\expandafter\XINT_FracToSci_x\romannumeral`&&@#1/\W[\R}% \def\XINT_FracToSci_x #1/#2#3[#4% {% \xint_gob_til_W #2\XINT_FracToSci_x_noslash\W \xint_gob_til_R #4\XINT_FracToSci_x_slash_noN\R \XINT_FracToSci_x_slash_N #1/#2#3[#4% }% \def\XINT_FracToSci_x_noslash#1\XINT_FracToSci_x_slash_N #2[#3% {% \xint_gob_til_R #3\XINT_FracToSci_x_noslash_noN\R \XINT_FracToSci_x_noslash_N #2[#3% }% \def\XINT_FracToSci_x_noslash_noN\R\XINT_FracToSci_x_noslash_N #1/\W[\R{#1}% \def\XINT_FracToSci_x_noslash_N #1[#2]/\W[\R% {% \ifnum#2=\xint_c_ #1\else \romannumeral0\expandafter\XINT_pfloat_a_fork\romannumeral0\xintrez{#1[#2]}% \fi }% \def\XINT_FracToSci_x_slash_noN\R\XINT_FracToSci_x_slash_N #1#2/#3/\W[\R% {% #1\xint_gob_til_zero#1\expandafter\iffalse\xint_gobble_ii0\iftrue #2\if\XINT_isOne{#3}1\else/#3\fi\fi }% \def\XINT_FracToSci_x_slash_N #1#2/#3[#4]/\W[\R% {% \ifnum#4=\xint_c_ #1#2\else \romannumeral0\expandafter\XINT_pfloat_a_fork\romannumeral0\xintrez{#1#2[#4]}% \fi \if\XINT_isOne{#3}1\else\if#10\else/#3\fi\fi }% \let\xintexprPrintOne\xint_FracToSci_x % \end{macrocode} % \subsubsection{Small bits we have to put somewhere} %\begin{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...). %\end{lverb} % \begin{macrocode} \def\XINT_embrace#1{{#1}}% \def\xint_gob_til_! #1!{}% ! with catcode 11 \def\xintError:noopening {% \XINT_expandableerror{Extra ). This is serious and prospects are bleak.}% }% % \end{macrocode} % \paragraph{\csh{xintthecoords}} %\begin{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! %\end{lverb} % \begin{macrocode} \def\xintthecoords#1% {\romannumeral`&&@\expandafter\XINT_thecoords_a\romannumeral0#1}% \def\XINT_thecoords_a #1#2.#3% #2.=\XINTfloatprint<digits>. etc... {\expanded{\expandafter\XINT_thecoords_b\expanded#2.{#3},!,!,^}}% \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} % \paragraph{\csh{xintthespaceseparated}} %\begin{lverb} % 1.4a This is a utility macro which was distributed previously % separately for usage with PSTricks \listplot %\end{lverb} % \begin{macrocode} \def\xintthespaceseparated#1% {\expanded\expandafter\xintthespaceseparated_a\romannumeral0#1}% \def\xintthespaceseparated_a #1#2.#3% {{\expandafter\xintthespaceseparated_b\expanded#2.{#3},!,!,!,!,!,!,!,!,!,^}}% \def\xintthespaceseparated_b #1,#2,#3,#4,#5,#6,#7,#8,#9,% {\xint_gob_til_! #9\xintthespaceseparated_c !% #1#2#3#4#5#6#7#8#9% \xintthespaceseparated_b}% % \end{macrocode} %\begin{lverb} % 1.4c I add a space here to stop the \romannumeral`$&$&@ in case of % empty input. % But this space induces an extra un-needed space token after 9, 18, 27,... % items before the last group of less than 9 items. % % Fix (at 1.4h) is simple because I already use \expanded anyhow: I don't need % at all the \romannumeral`$&$&@ which was first in \xintthespaceseparated, % let's move the first \expanded which was in \xintthespaceseparated_a to % \xintthespaceseparated, and remove the extra space here in _c. % % (alternative would have been to put the space after #1 and accept a % systematic trailing space, at least it is more aesthetic). % % Again, I did have a test file, but it was not incorporated in my test suite, % so I discovered the problem accidentally by compiling all files in an archive. %\end{lverb} % \begin{macrocode} \def\xintthespaceseparated_c !#1!#2^{#1}% % \end{macrocode} % \subsection{Hooks into the numeric parser for usage by the % \cshnolabel{xintdeffunc} symbolic parser} %\begin{lverb} % This is new with 1.3 and considerably refactored at 1.4. See % «Mysterious stuff». %\end{lverb} % \begin{macrocode} \let\XINT:NEhook:f:one:from:one\expandafter \let\XINT:NEhook:f:one:from:one:direct\empty \let\XINT:NEhook:f:one:from:two\expandafter \let\XINT:NEhook:f:one:from:two:direct\empty \let\XINT:NEhook:x:one:from:two\empty \let\XINT:NEhook:f:one:and:opt:direct \empty \let\XINT:NEhook:f:tacitzeroifone:direct \empty \let\XINT:NEhook:f:iitacitzeroifone:direct \empty \let\XINT:NEhook:x:select:obey\empty \let\XINT:NEhook:x:listsel\empty \let\XINT:NEhook:f:reverse\empty % \end{macrocode} %\begin{lverb} % At 1.4 it was \def\XINT:NEhook:f:from:delim:u #1#2^{#1#2^} % which was trick to allow automatic unpacking of a nutple argument % to multi-arguments functions such as gcd() or max(). But this % sacrificied the usage with a single numeric argument. %\end{lverb} % \changed{1.4i} %\begin{lverb} % More sophisticated code to check if the argument ople % was actually a single number. Notice that this forces numeric % types to actually use catcode 12 tokens, and polexpr diverges % a bit using P, but actually always testing with \if not \ifx. % % This is used by gcd(), lcm(), max(), min(), `+`(), `*`(), all(), any(), % xor(). % % The nil and None will give the same result due to the initial brace % stripping done by \XINT:NEhook:f:from:delim:u (there was even a prior brace % stripping to provide the #2 which is empty here for the nil and {} for the % None). %\end{lverb} % \begin{macrocode} \def\XINT:NEhook:f:from:delim:u #1#2^% {% \expandafter\XINT_fooof_checkifnumber\expandafter#1\string#2^% }% \def\XINT_fooof_checkifnumber#1#2% {% \expandafter#1% \romannumeral0\expanded{\if ^#2^\else \if\bgroup#2\noexpand\XINT_fooof_no\else \noexpand\XINT_fooof_yes#2\fi\fi}% }% \def\XINT_fooof_yes#1^{{#1}^}% \def\XINT_fooof_no{\expandafter{\iffalse}\fi}% % \end{macrocode} % \changed{1.4i} %\begin{lverb} % Same changes as for the other multiple arguments functions, % making them again usable with a single numeric input. % % Was at 1.4 \def\XINT:NEhook:f:noeval:from:braced:u#1#2^{#1{#2}} which % is not compatible with a single numeric input. % % Used by len(), first(), last() but it is a potential implementation bug that % the three share this as the location where expansion takes places is one % level deeper for the support macro of len(). % % The None is here handled as nil, i.e. it is unpacked, which is fine % as the documentations says nutples are unpacked. % %\end{lverb} % \begin{macrocode} \def\XINT:NEhook:f:LFL #1{\expandafter#1\expandafter}% \def\XINT:NEhook:r:check #1^% {% \expandafter\XINT:NEhook:r:check_a\string#1^% }% \let\XINT:NEsaved:r:check \XINT:NEhook:r:check \def\XINT:NEhook:r:check_a #1% {% \if ^#1\xint_dothis\xint_c_\fi \if\bgroup#1\xint_dothis\XINT:NEhook:r:check_no\fi \xint_orthat{\XINT:NEhook:r:check_yes#1}% }% \def\XINT:NEhook:r:check_no {% \expandafter\XINT:NEhook:r:check_no_b \expandafter\xint_c_\expandafter{\iffalse}\fi }% \def\XINT:NEhook:r:check_no_b#1^{#1}% \def\XINT:NEhook:r:check_yes#1^{\xint_c_{#1}}% \let\XINT:NEhook:branch\expandafter \let\XINT:NEhook:seqx\empty \let\XINT:NEhook:iter\expandafter \let\XINT:NEhook:opx\empty \let\XINT:NEhook:rseq\expandafter \let\XINT:NEhook:iterr\expandafter \let\XINT:NEhook:rrseq\expandafter \let\XINT:NEhook:x:toblist\empty \let\XINT:NEhook:x:mapwithin\empty \let\XINT:NEhook:x:ndmapx\empty % \end{macrocode} % \subsection{\csh{XINT_expr_getnext}: fetch some value then an operator and % present them to last waiter with the found operator precedence, then % the operator, then the value} %\begin{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. % % Refactored at 1.4 to put expansion of \XINT_expr_getop after the fetched % number, thus avoiding it to have to fetch it (which could happen then % multiple times, it was not really important when it was only one token in % pre-1.4 xintexpr). % % Allow \xintexpr\relax at 1.4. % % Refactored at 1.4 the articulation % \XINT_expr_getnext/XINT_expr_func/XINT_expr_getop. For some legacy reason % the first token picked by getnext was soon turned to catcode 12 The next % ones after the first were not a priori stringified but the first token was, % and this made allowing things such as \xintexpr\relax, \xintexpr,,\relax, % [], 1+(), [:] etc... complicated and requiring each time specific measures. % % The \expandafter chain in \XINT_expr_put_op_first is an overhead related % to an 1.4 attempt, the "varvalue" mechanism. I.e.: expansion of % \XINT_expr_var_foo is {\XINT_expr_varvalue_foo } and then for example % \XINT_expr_varvalue_foo expands to {4/1[0]}. The mechanism was originally % conceived to have only one token with idea its makes things faster. But the % xintfrac macros break with syntax such as \xintMul\foo\bar and \foo % expansion giving braces. So at 1.4c I added here these \expandafter, but % this is REALLY not satisfactory because the \expandafter are needed it seems % only for this variable "varvalue" mechanism. % % See also the discussion of \XINT_expr_op__ which distinguishes variables from % functions. % % After a 1.4g refactoring it would be possible to drop here the % \expandafter if the \XINT_expr_var_foo macro was defined to f-expand to % {actual expanded value (as ople)} for example explicit {{3}}. I have to % balance the relative weights of doing always the \expandafter but they are % needed only for the case the value was encapsulated in a variable, and of % never doing the \expandafter and ensure f-expansion of the _var_foo gives % explicit value (now that the refactoring let it be f-expanded, and the case % of fake variables omit and abort in particular was safely separated instead % of being treated like other and imposing restrictions on general variable % handling), and then there is the overhead of possibly moving around many % digits in the #1 of \XINT_expr_put_op_first. % %\end{lverb} % \begin{macrocode} \def\XINT_expr_getnext #1% {% \expandafter\XINT_expr_put_op_first\romannumeral`&&@% \expandafter\XINT_expr_getnext_a\romannumeral`&&@#1% }% \def\XINT_expr_put_op_first #1#2#3{\expandafter#2\expandafter#3\expandafter{#1}}% \def\XINT_expr_getnext_a #1% {% \ifx\relax #1\xint_dothis\XINT_expr_foundprematureend\fi \ifx\XINTfstop#1\xint_dothis\XINT_expr_subexpr\fi \ifcat\relax#1\xint_dothis\XINT_expr_countetc\fi \xint_orthat{}\XINT_expr_getnextfork #1% }% \def\XINT_expr_foundprematureend\XINT_expr_getnextfork #1{{}\xint_c_\relax}% \def\XINT_expr_subexpr #1.#2% {% \expanded{\unexpanded{{#2}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} %\begin{lverb} % 1.2 adds \ht, \dp, \wd and the eTeX font things. 1.4 avoids big % nested \if's, simply for code readability. % % This "fetch as number" is dangerous as long as list is not complete... at % 1.4g I belatedly add \catcode %\end{lverb} % \begin{macrocode} \def\XINT_expr_countetc\XINT_expr_getnextfork#1% {% \if0\ifx\count#11\fi \ifx\numexpr#11\fi \ifx\catcode#11\fi \ifx\dimen#11\fi \ifx\dimexpr#11\fi \ifx\skip#11\fi \ifx\glueexpr#11\fi \ifx\fontdimen#11\fi \ifx\ht#11\fi \ifx\dp#11\fi \ifx\wd#11\fi \ifx\fontcharht#11\fi \ifx\fontcharwd#11\fi \ifx\fontchardp#11\fi \ifx\fontcharic#11\fi 0\expandafter\XINT_expr_fetch_as_number\fi \expandafter\XINT_expr_getnext_a\number #1% }% \def\XINT_expr_fetch_as_number \expandafter\XINT_expr_getnext_a\number #1% {% \expanded{{{\number#1}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} %\begin{lverb} % This is the key initial dispatch component. It has been refactored at % 1.4g to give priority to identifying letter and digit tokens first. It % thus combines former \XINT_expr_getnextfork, \XINT_expr_scan_nbr_or_func and % \XINT_expr_scanfunc. A branch of the latter having become % \XINT_expr_startfunc. The handling of non-catcode 11 underscore _ has % changed: it is now skipped completely like the +. Formerly it would cause an % infinite loop because it triggered first insertion of a nil variable, (being % confused with a possible operator at a location where one looks for a % value), then tacit multiplication (being now interpreted as starting some % name), and then it came back to getnextfork creating loop. The @ of catcode % 12 could have caused the same issue if it was not handled especially because % it is used in the syntax as special variable for recursion hence was % recognized even if of catcode 12. Anyway I could have handled the _ like the % @, to avoid this problem of infinite loop with a non-letter underscore used % as first character but decided finally to have it be ignored (it is already % ignored if among digits, but it can be a constituent of a function of % variable name). It is not ignored of course if of catcode 11. It may then % start a variable or function name, but only for use by the package (by % polexpr for example), not by users. % % Then the matter is handed over to specialized routines: gathering digits % of a number (inclusive of a decimal mark, an exponential part) or letters % of a function or variable. And we have to intercept some tokens to implement % various functionalities. % % In each dothis/orthat structure, the first encountered branches are usually % handled slower than the next, because \if..\fi test cost less than grabbing % tokens. The exception is in the first one where letters pass through % slightly faster than digits, presumably because the \ifnum test is more % costly. Prior to this 1.4g refactoring the case of a starting letter of % a variable or function name was handled last, it is now handled first. Now, % this is only first letter... % % Here are the various possibilities in order that they are appear below % (the indicative order of speed of treatment is given as a number). % %( -1 tokens of catcode letter start a variable or function name %: -2 digits (I apply \string for the test, but I will have to review,& % it seems natural anyhow to require digits to be of catcode 12 and& % this is in fact basically done by the package, \numexpr does not& % work if not the case.), %: -7 support for Python-like * "unpacking" unary operator (added at 1.4), %: -6 support for [ as opener for the [..] nutple constructor (1.4), %: -5 support for the minus as unary operator of variable precedence, %: -4 support for @ as first character of special variables even if not letter, %: -3 support for opening parentheses (possibly triggering tacit multiplication), %: -13 support for skipping over ignored + character, %: -12 support for numbers starting with a decimal point, %: -11 support for the `+`() and `*`() functions, %: -10 support for the !() function, %: -9 support for the ?() function, %: -8 support for " for input of hexadecimal numbers. But $xintbinhexnameimp& % must be loaded explicitly by user. %: -17 support for \xintdeffunc via special handling of # token, %: -16 support for ignoring _ if not of catcode 11 and at start of& % numbers or names (this 1.4g change fixes \xinteval{_4} creating& % infinite loop) %: -15 support for inserting "nil" in front of operators, as needed in particular& % for the Python slicing syntax. This covers the comma, the :, the ] and& % the ) and also the ; although I don't think using ; to delimit nil is licit. %: -14 support for inserting 0 as missing value if / or ^ are encountered& % directly. This 1.4g changes avoids \xinteval{/3} causing& % unrecoverable low level errors from \xintDiv receiving only one argument. % I did not see here other bad syntax to protect. %) % % The handling of "nil" insertion penalizes Python slicing but anyway time % differences in the 14-15-16-17 group are less than % 5$%. The alternative will be % to do some positive test for the targets (:, ], the comma and closing % parenthesis) and do this in the prior group but this then penalizes % others. Anyway. This is all negligible compared to actual computations... % % Note: the above may not be in sync with code as it is extremely % time-consuming to maintain correspondence in case of re-factoring. %\end{lverb} %\odef\MakePrivateLetters{\MakePrivateLetters\catcode`` 11 }^^A % \begin{macrocode} \def\XINT_expr_getnextfork #1% {% \ifcat a#1\xint_dothis\XINT_expr_startfunc\fi \ifnum \xint_c_ix<1\string#1 \xint_dothis\XINT_expr_startint\fi \xint_orthat\XINT_expr_getnextfork_a #1% }% \def\XINT_expr_getnextfork_a #1% {% \if#1*\xint_dothis {{}\xint_c_ii^v 0}\fi \if#1[\xint_dothis {{}\xint_c_ii^v \XINT_expr_itself_obracket}\fi \if#1-\xint_dothis {{}{}-}\fi \if#1@\xint_dothis{\XINT_expr_startfunc @}\fi \if#1(\xint_dothis {{}\xint_c_ii^v (}\fi \xint_orthat{\XINT_expr_getnextfork_b#1}% }% \catcode96 11 % ` \def\XINT_expr_getnextfork_b #1% {% \if#1+\xint_dothis \XINT_expr_getnext_a\fi \if#1.\xint_dothis \XINT_expr_startdec\fi \if#1`\xint_dothis {\XINT_expr_onliteral_`}\fi \if#1!\xint_dothis {\XINT_expr_startfunc !}\fi \if#1?\xint_dothis {\XINT_expr_startfunc ?}\fi \if#1"\xint_dothis \XINT_expr_starthex\fi \xint_orthat{\XINT_expr_getnextfork_c#1}% }% \def\XINT_tmpa #1{% \def\XINT_expr_getnextfork_c ##1% {% \if##1#1\xint_dothis \XINT_expr_getmacropar\fi \if##1_\xint_dothis \XINT_expr_getnext_a\fi \if0\if##1/1\fi\if##1^1\fi0\xint_dothis{\XINT_expr_insertnil##1}\fi \xint_orthat{\XINT_expr_missing_arg##1}% }% }\expandafter\XINT_tmpa\string#% % \end{macrocode} %\begin{lverb} % 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 require some expansion. %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_` #1#2({{#1}\xint_c_ii^v `}% \catcode96 12 % ` % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters %\begin{lverb} % Prior to 1.4g, I was using a \lowercase technique to insert the % catcode 12 #, but this is a bit risky when one does not ensure a priori control of all % lccodes. %\end{lverb} % \begin{macrocode} \def\XINT_tmpa #1{% \def\XINT_expr_getmacropar ##1% {% \expandafter{\expandafter{\expandafter#1\expandafter ##1\expandafter}\expandafter}\romannumeral`&&@\XINT_expr_getop }% }\expandafter\XINT_tmpa\string#% \def\XINT_expr_insertnil #1% {% \expandafter{\expandafter}\romannumeral`&&@\XINT_expr_getop_a#1% }% \def\XINT_expr_missing_arg#1% {% \expanded{\XINT_expandableerror {Expected a value, got nothing before `#1'. Inserting 0.}{{0}}\expandafter}% \romannumeral`&&@\XINT_expr_getop_a#1% }% % \end{macrocode} % \subsection{\csh{XINT_expr_startint}} % \localtableofcontents %\begin{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. % % Attention at this location #1 was of catcode 12 in all versions prior to % 1.4. % % We assume anyhow that catcodes of digits are 12... %\end{lverb} % \begin{macrocode} \def\XINT_expr_startint #1% {% \if #10\expandafter\XINT_expr_gobz_a\else\expandafter\XINT_expr_scanint_a\fi #1% }% \def\XINT_expr_scanint_a #1#2% {\expanded\bgroup{{\iffalse}}\fi #1% spare a \string \expandafter\XINT_expr_scanint_main\romannumeral`&&@#2}% \def\XINT_expr_gobz_a #1#2% {\expanded\bgroup{{\iffalse}}\fi \expandafter\XINT_expr_gobz_scanint_main\romannumeral`&&@#2}% \def\XINT_expr_startdec #1% {\expanded\bgroup{{\iffalse}}\fi \expandafter\XINT_expr_scandec_a\romannumeral`&&@#1}% % \end{macrocode} % \subsubsection{Integral part (skipping zeroes)} %\begin{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. % % (reference to \string is obsolete: it is only used in the test but the % tokens are not submitted to \string anymore) %\end{lverb} % \begin{macrocode} \def\XINT_expr_scanint_main #1% {% \ifcat \relax #1\expandafter\XINT_expr_scanint_hit_cs \fi \ifnum\xint_c_ix<1\string#1 \else\expandafter\XINT_expr_scanint_next\fi #1\XINT_expr_scanint_again }% \def\XINT_expr_scanint_again #1% {% \expandafter\XINT_expr_scanint_main\romannumeral`&&@#1% }% % \end{macrocode} % |1.4f| had |_getop| here, but let's jump directly to |_getop_a|. % \begin{macrocode} \def\XINT_expr_scanint_hit_cs \ifnum#1\fi#2\XINT_expr_scanint_again {% \iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop_a#2% }% % \end{macrocode} %\begin{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. %\end{lverb} % %\begin{lverb} % It is not obvious at 1.4 to support [] for three things: packing, % slicing, ... and raw xintfrac syntax A/B[N]. The only good way would be to % actually really separate completely \xintexpr, \xintfloatexpr and % \xintiiexpr code which would allow to handle both / and [] from A/B[N] as we % handle e and E. But triplicating the code is something I need to think % about. It is not possible as in pre 1.4 to consider [ only as an operator of % same precedence as multiplication and division which was the way we did % this, but we can use the technique of fake operators. Thus we intercept % hitting a [ here, which is not too much of a problem as anyhow we dropped % temporarily 3*[1,2,3]+5 syntax so we don't have to worry that 3[1,2,3] % should do tacit multiplication. I think only way in future will be to really % separate the code of the three parsers (or drop entirely support for A/B[N]; % as 1.4 has modified output of \xinteval to not use this notation this is not % too dramatic). % % Anyway we find a way to inject here the former handling of [N], which will % use a delimited macro to directly fetch until the closing]. We do still need % some fake operator because A/B[N] is (A/B) times 10^N and the /B is allowed % to be missing. We hack this using the $ which is not used currently as % operator elsewhere in the syntax and need to hook into \XINT_expr_getop_b. % No finally I use the null char. It must be of catcode 12. % % 1.4f had _getop here, but let's jump directly to _getop_a. %\end{lverb} % \begin{macrocode} \def\XINT_expr_scanint_next #1\XINT_expr_scanint_again {% \if [#1\xint_dothis\XINT_expr_rawxintfrac\fi \if _#1\xint_dothis\XINT_expr_scanint_again\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 {\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop_a#1}% }% \def\XINT_expr_rawxintfrac {% \iffalse{{{\fi}}\expandafter}\csname XINT_expr_precedence_&&@\endcsname&&@% }% \def\XINT_expr_gobz_scanint_main #1% {% \ifcat \relax #1\expandafter\XINT_expr_gobz_scanint_hit_cs\fi \ifnum\xint_c_x<1\string#1 \else\expandafter\XINT_expr_gobz_scanint_next\fi #1\XINT_expr_scanint_again }% \def\XINT_expr_gobz_scanint_again #1% {% \expandafter\XINT_expr_gobz_scanint_main\romannumeral`&&@#1% }% % \end{macrocode} % |1.4f| had |_getop| here, but let's jump directly to |_getop_a|. % \begin{macrocode} \def\XINT_expr_gobz_scanint_hit_cs\ifnum#1\fi#2\XINT_expr_scanint_again {% 0\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop_a#2% }% \def\XINT_expr_gobz_scanint_next #1\XINT_expr_scanint_again {% \if [#1\xint_dothis{\expandafter0\XINT_expr_rawxintfrac}\fi \if _#1\xint_dothis\XINT_expr_gobz_scanint_again\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_again\fi \xint_orthat {0\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop_a#1}% }% % \end{macrocode} % \subsubsection{Fractional part} %\begin{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 ? % % 1.4f had _getop here, but let's jump directly to _getop_a. %\end{lverb} % \begin{macrocode} \def\XINT_expr_startdec_a .#1% {% \expandafter\XINT_expr_scandec_a\romannumeral`&&@#1% }% \def\XINT_expr_scandec_a #1% {% \if .#1\xint_dothis{\iffalse{{{\fi}}\expandafter}% \romannumeral`&&@\XINT_expr_getop_a..}\fi \xint_orthat {\XINT_expr_scandec_main 0.#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\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop_a..}\fi \xint_orthat {\XINT_expr_gobz_scandec_main 0.#1}% }% \def\XINT_expr_scandec_main #1.#2% {% \ifcat \relax #2\expandafter\XINT_expr_scandec_hit_cs\fi \ifnum\xint_c_ix<1\string#2 \else\expandafter\XINT_expr_scandec_next\fi #2\expandafter\XINT_expr_scandec_again\the\numexpr #1-\xint_c_i.% }% \def\XINT_expr_scandec_again #1.#2% {% \expandafter\XINT_expr_scandec_main \the\numexpr #1\expandafter.\romannumeral`&&@#2% }% % \end{macrocode} % |1.4f| had |_getop| here, but let's jump directly to |_getop_a|. % \begin{macrocode} \def\XINT_expr_scandec_hit_cs\ifnum#1\fi #2\expandafter\XINT_expr_scandec_again\the\numexpr#3-\xint_c_i.% {% [#3]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop_a#2% }% \def\XINT_expr_scandec_next #1#2\the\numexpr#3-\xint_c_i.% {% \if _#1\xint_dothis{\XINT_expr_scandec_again#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]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop_a#1}% }% \def\XINT_expr_gobz_scandec_main #1.#2% {% \ifcat \relax #2\expandafter\XINT_expr_gobz_scandec_hit_cs\fi \ifnum\xint_c_ix<1\string#2 \else\expandafter\XINT_expr_gobz_scandec_next\fi \if0#2\expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi {\expandafter\XINT_expr_gobz_scandec_main}% {#2\expandafter\XINT_expr_scandec_again}\the\numexpr#1-\xint_c_i.% }% % \end{macrocode} % |1.4f| had |_getop| here, but let's jump directly to |_getop_a|. % \begin{macrocode} \def\XINT_expr_gobz_scandec_hit_cs \ifnum#1\fi\if0#2#3\xint_c_i.% {% 0[0]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop_a#2% }% \def\XINT_expr_gobz_scandec_next\if0#1#2\fi #3\numexpr#4-\xint_c_i.% {% \if _#1\xint_dothis{\XINT_expr_gobz_scandec_main #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]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop_a#1}% }% % \end{macrocode} % \subsubsection{Scientific notation} %\begin{lverb} % Some pluses and minuses are allowed at the start of the scientific % part, however not later, and no parenthesis. % % ATTENTION! 1e\numexpr2+3\relax or 1e\xintiexpr i\relax, i=1..5 % are not allowed and 1e1\numexpr2\relax does 1e1 * \numexpr2\relax. % Use \the\numexpr, \xinttheiexpr, etc... %\end{lverb} % \begin{macrocode} \def\XINT_expr_scanexp_a #1#2% {% #1\expandafter\XINT_expr_scanexp_main\romannumeral`&&@#2% }% \def\XINT_expr_scanexp_main #1% {% \ifcat \relax #1\expandafter\XINT_expr_scanexp_hit_cs\fi \ifnum\xint_c_ix<1\string#1 \else\expandafter\XINT_expr_scanexp_next\fi #1\XINT_expr_scanexp_again }% \def\XINT_expr_scanexp_again #1% {% \expandafter\XINT_expr_scanexp_main_b\romannumeral`&&@#1% }% % \end{macrocode} % |1.4f| had |_getop| here, but let's jump directly to |_getop_a|. % \begin{macrocode} \def\XINT_expr_scanexp_hit_cs\ifnum#1\fi#2\XINT_expr_scanexp_again {% ]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop_a#2% }% \def\XINT_expr_scanexp_next #1\XINT_expr_scanexp_again {% \if _#1\xint_dothis \XINT_expr_scanexp_again \fi \if +#1\xint_dothis {\XINT_expr_scanexp_a +}\fi \if -#1\xint_dothis {\XINT_expr_scanexp_a -}\fi \xint_orthat {]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop_a#1}% }% \def\XINT_expr_scanexp_main_b #1% {% \ifcat \relax #1\expandafter\XINT_expr_scanexp_hit_cs_b\fi \ifnum\xint_c_ix<1\string#1 \else\expandafter\XINT_expr_scanexp_next_b\fi #1\XINT_expr_scanexp_again_b }% % \end{macrocode} % |1.4f| had |_getop| here, but let's jump directly to |_getop_a|. % \begin{macrocode} \def\XINT_expr_scanexp_hit_cs_b\ifnum#1\fi#2\XINT_expr_scanexp_again_b {% ]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop_a#2% }% \def\XINT_expr_scanexp_again_b #1% {% \expandafter\XINT_expr_scanexp_main_b\romannumeral`&&@#1% }% \def\XINT_expr_scanexp_next_b #1\XINT_expr_scanexp_again_b {% \if _#1\xint_dothis\XINT_expr_scanexp_again\fi \xint_orthat {]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop_a#1}% }% % \end{macrocode} % \subsubsection{Hexadecimal numbers} %\begin{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. % % (some above remarks have been obsoleted for some long time, no more applied % \string since 1.4) % % Notice that internal representation adds a [N] part only in case input % used "DDD.dddd form, for compatibility with \xintiiexpr which is not % compatible with such internal representation. % % At 1.4g a very long-standing bug was fixed: input such as "\foo broke the % parser because (incredibly) the \foo token was picked up unexpanded and % ended up as is in an \ifcat ! % % Another long-standing bug was fixed at 1.4g: contrarily to the decimal case, % here in the hexadecimal input leading zeros were not trimmed. This was ok, % because formerly \xintHexToDec trimmed leading zeros, but at 1.2m 2017/07/31 % xintbinhex.sty was modified and this ceased being the case. But I forgot to % upgrade the parser here at that time. Leading zeros would in many % circumstances (presence of a fractional part, or \xintiiexpr context) lead % to wrong results. Leading zeros are now trimmed during input. % %\end{lverb} % \begin{macrocode} \def\XINT_expr_hex_in #1.#2#3;% {% \expanded{{{\if#2>% \xintHexToDec{#1}% \else \xintiiMul{\xintiiPow{625}{\xintLength{#3}}}{\xintHexToDec{#1#3}}% [\the\numexpr-4*\xintLength{#3}]% \fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} %\begin{lverb} % Let's not forget to grab-expand next token first as is normal rule % of operation. Formerly called \XINT_expr_scanhex_I and had " upfront. %\end{lverb} % \begin{macrocode} \def\XINT_expr_starthex #1% {% \expandafter\XINT_expr_hex_in\expanded\bgroup \expandafter\XINT_expr_scanhexIgobz_a\romannumeral`&&@#1% }% \def\XINT_expr_scanhexIgobz_a #1% {% \ifcat #1\relax 0.>;\iffalse{\fi\expandafter}\expandafter\xint_gobble_i\fi \XINT_expr_scanhexIgobz_aa #1% }% \def\XINT_expr_scanhexIgobz_aa #1% {% \if\ifnum`#1>`0 \ifnum`#1>`9 \ifnum`#1>`@ \ifnum`#1>`F 0\else1\fi\else0\fi\else1\fi\else0\fi 1% \xint_dothis\XINT_expr_scanhexI_b \fi \if 0#1\xint_dothis\XINT_expr_scanhexIgobz_bgob\fi \if _#1\xint_dothis\XINT_expr_scanhexIgobz_bgob\fi \if .#1\xint_dothis\XINT_expr_scanhexIgobz_toII\fi \xint_orthat {\XINT_expandableerror {Expected an hexadecimal digit but got `#1'. Using `0'.}% 0.>;\iffalse{\fi}}% #1% }% \def\XINT_expr_scanhexIgobz_bgob #1#2% {% \expandafter\XINT_expr_scanhexIgobz_a\romannumeral`&&@#2% }% \def\XINT_expr_scanhexIgobz_toII .#1% {% 0..\expandafter\XINT_expr_scanhexII_a\romannumeral`&&@#1% }% \def\XINT_expr_scanhexI_a #1% {% \ifcat #1\relax .>;\iffalse{\fi\expandafter}\expandafter\xint_gobble_i\fi \XINT_expr_scanhexI_aa #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_scanhexI_toII}\fi \xint_orthat {.>;\iffalse{\fi\expandafter}}% \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_scanhexI_toII .#1% {% ..\expandafter\XINT_expr_scanhexII_a\romannumeral`&&@#1% }% \def\XINT_expr_scanhexII_a #1% {% \ifcat #1\relax\xint_dothis{;\iffalse{\fi}#1}\fi \xint_orthat {\XINT_expr_scanhexII_aa #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{;\iffalse{\fi\expandafter}}% \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_startfunc}: collecting names of functions and % variables} % %\begin{lverb} % At 1.4 the first token left over has not been submitted to % \string. We also know it is not a control sequence. So we can test catcode % to identify if operator is found. And it is allowed to hit some operator % such as a closing parenthesis we will then insert the «nil» value (edited: which % however will cause certain breakage of the infix binary operators: I notice % I did not insert None {{}} but nil {}, perhaps by oversight). % % There was prior to 1.4 solely the dispatch in \XINT_expr_scanfunc_b % but now we do it immediately and issue \XINT_expr_func only in certain % cases. % % Comments here have been removed because 1.4g did a refactoring % and renamed \XINT_expr_scanfunc to \XINT_expr_startfunc, moving half of % it earlier inside the getnextfork macros. %\end{lverb} % \begin{macrocode} \def\XINT_expr_startfunc #1% {\expandafter\XINT_expr_func\expanded\bgroup#1\XINT_expr_scanfunc_a}% \def\XINT_expr_scanfunc_a #1% {% \expandafter\XINT_expr_scanfunc_b\romannumeral`&&@#1% }% % \end{macrocode} %\begin{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. %\end{lverb} % \begin{macrocode} \def\XINT_expr_scanfunc_b #1% {% \ifcat \relax#1\xint_dothis{\iffalse{\fi}(_#1}\fi \if (#1\xint_dothis{\iffalse{\fi}(`}\fi \if 1\ifcat a#10\fi \ifnum\xint_c_ix<1\string#1 0\fi \if @#10\fi \if _#10\fi 1% \xint_dothis{\iffalse{\fi}(_#1}\fi \xint_orthat {#1\XINT_expr_scanfunc_a}% }% % \end{macrocode} % \subsubsection{\csh{XINT_expr_func}: dispatch to variable replacement or to % function execution} %\begin{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_ii^v 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_ii^v #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_ii^v is there because _op_` must know in which parser % it works. Dispendious for _. Hence I modify for 1.2d. %\end{lverb} % \begin{macrocode} \def\XINT_expr_func #1(#2{\if _#2\xint_dothis{\XINT_expr_op__{#1}}\fi \xint_orthat{{#1}\xint_c_ii^v #2}}% % \end{macrocode} % \subsection{\csh{XINT_expr_op_`}: launch function or % pseudo-function, or evaluate variable and insert operator of multiplication % in front of parenthesized contents} % %\begin{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) and trigger here the use of the % suitable parser-dependant form. The former (pseudo functions and functions % handling dummy variables) first trigger a parser independent mechanism. % % With 1.2c "onliteral" is also used to disambiguate a variable followed % by an opening parenthesis from a function and then apply tacit multiplication. % 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. % This used to be decided much earlier at the time of % \XINT_expr_func. % % The advantage of 1.2c code is that the same name can be used for % a variable or a function. %\end{lverb} % % \changed[2021/06/11]{1.4i} %\begin{lverb} % The 1.2c abuse of «onliteral» for both tacit multiplication in front % of an opening parenthesis and «generic» functions or pseudo-functions meant % that the latter were vulnerable against user redefinition of a function name % as a variable name. This applied to subs, subsm, subsn, seq, add, mul, % ndseq, ndmap, ndfillraw, bool, togl, protect, qint, qfrac, qfloat, qraw, % random, qrand, rbit and the most susceptible in real life was probably "seq". % % Now variables have an associated «var*» named macro, not «onliteral». % % In passing I refactor here in a \romannumeral inspired way how \csname and % TeX booleans are intertwined, minimizing \expandafter usage. %\end{lverb} % % \begin{macrocode} \def\XINT_tmpa #1#2#3{% \def #1##1% {% \csname XINT_\ifcsname XINT_#3_func_##1\endcsname #3_func_##1\expandafter\endcsname\romannumeral`&&@\expandafter#2% \romannumeral\else \ifcsname XINT_expr_onliteral_##1\endcsname expr_onliteral_##1\expandafter\endcsname\romannumeral \else \ifcsname XINT_expr_var*_##1\endcsname expr_var*_##1\expandafter\endcsname\romannumeral \else #3_func_\XINT_expr_unknown_function {##1}% \expandafter\endcsname\romannumeral`&&@\expandafter#2% \romannumeral \fi\fi\fi\xint_c_ }% }% \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_unknown_function #1% {\XINT_expandableerror{`#1' is unknown, say `Isome_func' or I use 0.}}% \def\XINT_expr_func_ #1#2#3{#1#2{{0}}}% \let\XINT_flexpr_func_\XINT_expr_func_ \let\XINT_iiexpr_func_\XINT_expr_func_ % \end{macrocode} % % \subsection{\csh{XINT_expr_op__}: replace a variable by its value and % then fetch next operator} %\begin{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. % % At 1.4 \XINT_expr_getop is launched with accumulated result on its left. % But the omit and abort keywords are implemented via fake variables % which rely on possibility to modify incoming upfront tokens. If we did here % something such as % $centeredline$bgroup_var_#1\expandafter\endcsname\romannumeral`^^@\XINT_expr_getop$egroup % the premature expansion of getop would break the var_omit and % var_abort mechanism. Thus we revert % to former code which locates an \XINT_expr_getop (call it _legacy) % before the tokens from the variable expansion (in xintexpr < 1.4 the % normal variables expanded % to a single token so the overhead was not serious) so we can expand fake % variables first. % % Abusing variables to manipulate the incoming token stream is a bit bad, % usually I prefer functions for this (such as the break() function) but then % I have to define 3 macros for the 3 parsers. % % This trick of fake variables puts thus a general overhead at various % locations, and the situation here is REALLY not satisfactory. But 1.4 has % (had) to be released now. % % Even if I could put the \csname XINT_expr_var_foo\endcsname upfront, which % would then be f-expanded, this would still need \XINT_expr_put_op_first to % use its \expandafter's as long as \XINT_expr_var_foo expands to % {\XINT_expr_varvalue_foo} with a not-yet expanded \XINT_expr_var_value. % % I could let \XINT_expr_var_foo expand to % \expandafter{\XINT_expr_varvalue_foo} allowing then (if it gets f-expanded) % probably to drop the \expandafter in \XINT_expr_put_op_first. But I can not % consider this option in the form % $centeredline$bgroup_var_foo\expandafter\endcsname\romannumeral`^^@\XINT_expr_getop$egroup % until the issue with fake variables such as omit and % abort which must act before \XINT_expr_getop has some workaround. % This could be implemented here with some extra branch, i.e. there would not % be some \XINT_expr_var_omit but something else filtered out in the \else % branch here. % % The above comments mention only omit and abort, but the case of real dummy % variables also needs consideration. % % At 1.4g, I test first for existence of \XINT_expr_onliteral_foo. % % Updated for 1.4i: now rather existence of \XINT_expr_var*_foo is tested. % % This is % a trick which allows to distinguish actual or dummy variables from really % fake variables omit and abort (must check if there are others). For the real % or dummy variables we can trigger the expansion of the \XINT_expr_getop % before the one of the variable. I could test vor varvalue_foo but this % applies only to real variables not dummy variables. Actual and dummy % variables are thus handled slightly faster at 1.4g as there is less % induced moving around (the \expandafter chain in \XINT_expr_put_op_first % still applies at this stage, as I have not yet re-examined the var/varlue % mechanism). And the test for var_foo is moved directly inside the \csname % construct in the \else branch which now handles together % fake variables and non-existing variables. % % I only have to make sure dummy variables are really safe being handled this % way with the getop action having being done before they expand, but it looks % ok. Attention it is crucial that if \XINT_expr_getop finds a \relax it inserts % \xint_c_\relax so the \relax token is still there! % % With this refactoring the \XINT_expr_getop_legacy is applied only in case % of non-existent variables or fake variables omit/abort or things such as % nil, None, false, true, False, True. % % If user in interactive mode fixes the variable name, the \XINT_expr_var_foo % expanded once with deliver {\XINT_expr_varvalue_foo} (if not dummy), and the % braces are maintained by \XINT_expr_getop_legacy. % %\end{lverb} % \begin{macrocode} \def\XINT_expr_op__ #1% op__ with two _'s {% \ifcsname XINT_expr_var*_#1\endcsname \csname XINT_expr_var_#1\expandafter\endcsname \romannumeral`&&@\expandafter\XINT_expr_getop \else \expandafter\expandafter\expandafter\XINT_expr_getop_legacy \csname XINT_expr_var_% \ifcsname XINT_expr_var_#1\endcsname#1\else\XINT_expr_unknown_variable{#1}\fi \expandafter\endcsname \fi }% \def\XINT_expr_unknown_variable #1% {\XINT_expandableerror {`#1' unknown, say `Isome_var' or I use 0.}}% \def\XINT_expr_var_{{{0}}}% \let\XINT_flexpr_op__ \XINT_expr_op__ \let\XINT_iiexpr_op__ \XINT_expr_op__ \def\XINT_expr_getop_legacy #1% {% \expanded{\unexpanded{{#1}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} % \subsection{\csh{XINT_expr_getop}: fetch the next operator or closing % parenthesis or end of expression} %\begin{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. % % % 1.2q adds tacit multiplication in cases such as (1+1)3 or 5!7! % % 1.4 has simplified coding here as \XINT_expr_getop expansion happens % at a time when a fetched value has already being stored. % % Prior to 1.4g there was an \if _#1\xint_dothis\xint_secondofthree\fi % because the _ can be used to start names, for private use by package (for % example by polexpr). But this test was silly because these usages are only % with a _ of catcode 11. And allowing non-catcode 11 _ also to trigger tacit % multiplication caused an infinite loop in collaboration with % \XINT_expr_scanfunc, see explanations there (now removed after refactoring, % see \XINT_expr_startfunc). % % The situation with the @ is different because we must allow it even as % catcode 12 as a name, as it used in the syntax and must work the same if of % catcode 11 or 12. No infinite loop because it is filtered out by one of the % \XINT_expr_getnextfork macros. % % The check for : to send it to thirdofthree "getop" branch is needed, last % time I checked, because during some part of at least \xintdeffunc, some % scantokens are done which need to work with the : of catcode 11, and it % would be misconstrued to start a name if not filtered out. % %\end{lverb} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`* 11 }^^A % \begin{macrocode} \def\XINT_expr_getop #1% {% \expandafter\XINT_expr_getop_a\romannumeral`&&@#1% }% \catcode`* 11 \def\XINT_expr_getop_a #1% {% \ifx \relax #1\xint_dothis\xint_firstofthree\fi \ifcat \relax #1\xint_dothis\xint_secondofthree\fi \ifnum\xint_c_ix<1\string#1 \xint_dothis\xint_secondofthree\fi \if :#1\xint_dothis \xint_thirdofthree\fi \if @#1\xint_dothis \xint_secondofthree\fi \if (#1\xint_dothis \xint_secondofthree\fi %) \ifcat a#1\xint_dothis \xint_secondofthree\fi \xint_orthat \xint_thirdofthree % \end{macrocode} %\begin{lverb} % Formerly \XINT_expr_foundend as firstofthree but at 1.4g let's % simply insert \xint_c_ as the #1 is \relax (and anyhow a place-holder % according to remark in definition of \XINT_expr_foundend %\end{lverb} % \begin{macrocode} \xint_c_ % \end{macrocode} %\begin{lverb} % Tacit multiplication with higher precedence. Formerly % \XINT_expr_precedence_*** was used, renamed to \XINT_expr_prec_tacit at % 1.4g in case a backport is done of the \bnumdefinfix from bnumexpr. %\end{lverb} % \begin{macrocode} {\XINT_expr_prec_tacit *}% % \end{macrocode} %\begin{lverb} % This is only location which jumps to \XINT_expr_getop_b. At 1.4f and % perhaps for old legacy reasons this was \expandafter\XINT_expr_getop_b % \string#1 but I see no reason now for applying \string to #1. Removed at % 1.4g. And the #1 now moved out of the secondofthree and thirdofthree % branches. %\end{lverb} % \begin{macrocode} \XINT_expr_getop_b #1% }% \catcode`* 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters %\begin{lverb} % \relax is a place holder here. At 1.4g, we don't use % \XINT_expr_foundend anymore in \XINT_expr_getop_a which was slightly % refactored, but it is used elsewhere. % % Attention that keeping a \relax around if \XINT_expr_getop hits it is % crucial to good functioning of dummy variables after 1.4g refactoring of % \XINT_expr_op__, the \relax being used as delimiter by dummy variables, and % \XINT_expr_getop is now expanded before the variable itself does its thing. %\end{lverb} % \begin{macrocode} \def\XINT_expr_foundend {\xint_c_ \relax}% % \end{macrocode} %\begin{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. %\end{lverb} % %\begin{lverb} % null char is used as hack to implement A/B[N] raw input at 1.4. See % also \XINT_expr_scanint_c. %\end{lverb} % %\begin{lverb} % Memo: 1.4g, the token fetched by \XINT_expr_getop_b has not anymore % been previously submitted in \XINT_expr_getop_a to \string. %\end{lverb} % \begin{macrocode} \def\XINT_expr_getop_b#1{\def\XINT_expr_getop_b ##1% {% \if &&@##1\xint_dothis{#1&&@}\fi \if '##1\xint_dothis{\XINT_expr_binopwrd }\fi \if ?##1\xint_dothis{\XINT_expr_precedence_? ?}\fi \xint_orthat {\XINT_expr_scanop_a ##1}% }}\expandafter\XINT_expr_getop_b\csname XINT_expr_precedence_&&@\endcsname \def\XINT_expr_binopwrd #1'% {% \expandafter\XINT_expr_foundop_a \csname XINT_expr_itself_\xint_zapspaces #1 \xint_gobble_i\endcsname }% \def\XINT_expr_scanop_a #1#2% {% \expandafter\XINT_expr_scanop_b\expandafter#1\romannumeral`&&@#2% }% % \end{macrocode} %\begin{lverb} % Multi-character operators have an associated itself macro at each % stage of decomposition starting at two characters. Here, nothing imposes to % the operator characters not to be of catcode letter, this constraint applies % only on the first character and is done via \XINT_expr_getop_a, to handle in % particular tacit multiplication in front of variable or function names. % % But it would be dangerous to allow letters in operator characters, again due % to existence of variables and functions, and anyhow there is no user % interface to add such custom operators. However in bnumexpr, such a % constraint does not exist. % % I don't worry too much about efficiency here... and at 1.4g I have % re-written for code readability only. Once we see that #1#2 is not a % candidate to be or start an operator, we need to check if single-character % operator #1 is really an operator and this is done via the existence of the % precedence token. % % Unfortunately the 1.4g refactoring of the scanop macros had a bad bug: % \XINT_expr_scanop_c inserted \romannumeral`^^@ in stream but did not grab a % token first so a space would stop the \romannumeral and then the #2 in % \XINT_expr_scanop_d was not pre-expanded and ended up alone in \ifcat. It % is too distant in the past the time when I wrote the core of xintexpr in % 2013... older and dumber now. %\end{lverb} % \begin{macrocode} \def\XINT_expr_scanop_b #1#2% {% \unless\ifcat#2\relax \ifcsname XINT_expr_itself_#1#2\endcsname \XINT_expr_scanop_c \fi\fi \XINT_expr_foundop_a #1#2% }% \def\XINT_expr_scanop_c #1#2#3#4#5#6% #1#2=\fi\fi {% #1#2% \expandafter\XINT_expr_scanop_d\csname XINT_expr_itself_#4#5\expandafter\endcsname \romannumeral`&&@#6% }% \def\XINT_expr_scanop_d #1#2% {% \unless\ifcat#2\relax \ifcsname XINT_expr_itself_#1#2\endcsname \XINT_expr_scanop_c \fi\fi \XINT_expr_foundop #1#2% }% \def\XINT_expr_foundop_a #1% {% \ifcsname XINT_expr_precedence_#1\endcsname \csname XINT_expr_precedence_#1\expandafter\endcsname \expandafter #1% \else \expandafter\XINT_expr_getop\romannumeral`&&@% \xint_afterfi{\XINT_expandableerror {Expected an operator but got `#1'. Ignoring.}}% \fi }% \def\XINT_expr_foundop #1{\csname XINT_expr_precedence_#1\endcsname #1}% % \end{macrocode} % \subsection{Expansion spanning; opening and closing parentheses} %\begin{lverb} % % These comments apply to all definitions coming next relative % to execution of operations from parsing of syntax. % % Refactored (and unified) at 1.4. In particular % the 1.4 scheme uses op, exec, check-, and checkp. Formerly % it was until_a (check-) and until_b (now split into checkp and exec). % % This way neither check- nor checkp have to % grab the accumulated number so far (top of stack if you like) and besides % one never has to go back to check- from checkp (and neither from check-). % % % % Prior to 1.4, accumulated % intermediate results were stored as one token, but now we have to use % \expanded to propagate expansion beyond possibly arbitrary long braced % nested data. With the 1.4 refactoring we do this only once and only grab % a second time the data if we actually have to act upon it. % % 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. % % Exceptionally, the check- is here abbreviated to check. % %\end{lverb} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`) 11 }^^A % \begin{macrocode} \catcode`) 11 \def\XINT_tmpa #1#2#3#4#5#6% {% \def#1% start {% \expandafter#2\romannumeral`&&@\XINT_expr_getnext }% \def#2##1% check {% \xint_UDsignfork ##1{\expandafter#3\romannumeral`&&@#4}% -{#3##1}% \krof }% \def#3##1##2% checkp {% \ifcase ##1% \expandafter\XINT_expr_done \or\expandafter#5% \else \expandafter#3\romannumeral`&&@\csname XINT_#6_op_##2\expandafter\endcsname \fi }% \def#5% {% \XINT_expandableerror {Extra ) removed. Hit <return>, fingers crossed.}% \expandafter#2\romannumeral`&&@\expandafter\XINT_expr_put_op_first \romannumeral`&&@\XINT_expr_getop_legacy }% }% \let\XINT_expr_done\space \xintFor #1 in {expr,flexpr,iiexpr} \do {% \expandafter\XINT_tmpa \csname XINT_#1_start\expandafter\endcsname \csname XINT_#1_check\expandafter\endcsname \csname XINT_#1_checkp\expandafter\endcsname \csname XINT_#1_op_-xii\expandafter\endcsname \csname XINT_#1_extra_)\endcsname {#1}% }% % \end{macrocode} %\begin{lverb} % Here also we take some shortcuts relative to general philosophy and have no explicit % exec macro. %\end{lverb} % \begin{macrocode} \def\XINT_tmpa #1#2#3#4#5#6#7% {% \def #1##1% op_( {% \expandafter #4\romannumeral`&&@\XINT_expr_getnext }% \def #2##1% op_) {% \expanded{\unexpanded{\XINT_expr_put_op_first{##1}}\expandafter}% \romannumeral`&&@\XINT_expr_getop }% \def #3% oparen {% \expandafter #4\romannumeral`&&@\XINT_expr_getnext }% \def #4##1% check- {% \xint_UDsignfork ##1{\expandafter#5\romannumeral`&&@#6}% -{#5##1}% \krof }% \def #5##1##2% checkp {% \ifcase ##1\expandafter\XINT_expr_missing_) \or \csname XINT_#7_op_##2\expandafter\endcsname \else \expandafter #5\romannumeral`&&@\csname XINT_#7_op_##2\expandafter\endcsname \fi }% }% \def\XINT_expr_missing_) {\XINT_expandableerror{End of expression found, but some ) was missing there.}% \xint_c_ \XINT_expr_done }% \xintFor #1 in {expr,flexpr,iiexpr} \do {% \expandafter\XINT_tmpa \csname XINT_#1_op_(\expandafter\endcsname \csname XINT_#1_op_)\expandafter\endcsname \csname XINT_#1_oparen\expandafter\endcsname \csname XINT_#1_check-_)\expandafter\endcsname \csname XINT_#1_checkp_)\expandafter\endcsname \csname XINT_#1_op_-xii\endcsname {#1}% }% \let\XINT_expr_precedence_)\xint_c_i \catcode`) 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters % \subsection{The comma as binary operator} %\begin{lverb} % New with 1.09a. Refactored at 1.4. %\end{lverb} % \begin{macrocode} \def\XINT_tmpa #1#2#3#4#5#6% {% \def #1##1% \XINT_expr_op_, {% \expanded{\unexpanded{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3##4{##2##3{##1##4}}% \XINT_expr_exec_, \def #3##1% \XINT_expr_check-_, {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_, {% \ifnum ##1>\xint_c_iii \expandafter#4% \romannumeral`&&@\csname XINT_#6_op_##2\expandafter\endcsname \else \expandafter##1\expandafter##2% \fi }% }% \xintFor #1 in {expr,flexpr,iiexpr} \do {% \expandafter\XINT_tmpa \csname XINT_#1_op_,\expandafter\endcsname \csname XINT_#1_exec_,\expandafter\endcsname \csname XINT_#1_check-_,\expandafter\endcsname \csname XINT_#1_checkp_,\expandafter\endcsname \csname XINT_#1_op_-xii\endcsname {#1}% }% \expandafter\let\csname XINT_expr_precedence_,\endcsname\xint_c_iii % \end{macrocode} % \subsection{The minus as prefix operator of variable precedence level} %\begin{lverb} % Inherits the precedence level of the previous infix operator, if the % latter has at least the precedence level of binary + and -, i.e. currently % 12. % % Refactored at 1.4. % % At 1.4g I belatedly observe that I have been defining architecture for % op_-xvi but such operator can never be created, because there are no infix % operators of precedence level 16. Perhaps in the past this was really % needed? But now such 16 is precedence level of tacit multiplication which % is implemented simply by the \XINT_expr_prec_tacit token, there is no macro % check-_*** which would need an op_-xvi. % % For the record: at least one scenario exists % which creates tacit multiplication in front of a unary -, it is 2\count0 % which first generates tacit multiplication then applies \number to \count0, % but the operator % is still *, so this triggers only \XINT_expr_op_-xiv, not -xvi. % % At 1.4g we need 17 and not 18 anymore as the precedence of unary minus % following power operators ^ and **. The needed \xint_c_xvii creation was % added to xintkernel.sty. %\end{lverb} % \begin{macrocode} \def\XINT_tmpb #1#2#3#4#5#6#7% {% \def #1% \XINT_expr_op_-<level> {% \expandafter #2\romannumeral`&&@\expandafter#3% \romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3% \XINT_expr_exec_-<level> {% \expandafter ##1\expandafter ##2\expandafter {% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@#7##3}% }% }% \def #3##1% \XINT_expr_check-_-<level> {% \xint_UDsignfork ##1{\expandafter #4\romannumeral`&&@#1}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_-<level> {% \ifnum ##1>#5% \expandafter #4% \romannumeral`&&@\csname XINT_#6_op_##2\expandafter\endcsname \else \expandafter ##1\expandafter ##2% \fi }% }% \def\XINT_tmpa #1#2#3% {% \expandafter\XINT_tmpb \csname XINT_#1_op_-#3\expandafter\endcsname \csname XINT_#1_exec_-#3\expandafter\endcsname \csname XINT_#1_check-_-#3\expandafter\endcsname \csname XINT_#1_checkp_-#3\expandafter\endcsname \csname xint_c_#3\endcsname {#1}#2% }% \xintApplyInline{\XINT_tmpa {expr}\xintOpp}{{xii}{xiv}{xvii}}% \xintApplyInline{\XINT_tmpa {flexpr}\xintOpp}{{xii}{xiv}{xvii}}% \xintApplyInline{\XINT_tmpa {iiexpr}\xintiiOpp}{{xii}{xiv}{xvii}}% % \end{macrocode} % \subsection{The \texorpdfstring{\protect\lowast}{*}{} as Python-like «unpacking» prefix operator} % %\begin{lverb} % New with 1.4. Prior to 1.4 the internal data structure was % the one of \csname encapsulated comma separated numbers. No hierarchical % structure was (easily) possible. At 1.4, we can use TeX braces because there % is no detokenization to catcode 12. %\end{lverb} % % % \begin{macrocode} \def\XINT_tmpa#1#2#3% {% \def#1##1{\expandafter#2\romannumeral`&&@\XINT_expr_getnext}% \def#2##1##2% {% \ifnum ##1>\xint_c_xx \expandafter #2% \romannumeral`&&@\csname XINT_#3_op_##2\expandafter\endcsname \else \expandafter##1\expandafter##2\romannumeral0\expandafter\XINT:NEhook:unpack \fi }% }% \def\XINT:NEhook:unpack{\xint_stop_atfirstofone}% \xintFor* #1 in {{expr}{flexpr}{iiexpr}}: {\expandafter\XINT_tmpa\csname XINT_#1_op_0\expandafter\endcsname \csname XINT_#1_until_unpack\endcsname {#1}}% % \end{macrocode} % \subsection{Infix operators} % % \localtableofcontents % %\begin{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. % % At 1.4b we must make sure that the ! in expansion of \XINT_expr_itself_!= is % of catcode 12 and not of catcode 11. This is because implementation of % chaining of comparison operators proceeds via inserting the itself macro % directly into upcoming token stream, whereas formerly such itself macros % would be expanded only in a \csname...\endcsname context. %\end{lverb} % \begin{macrocode} \catcode`& 12 \catcode`! 12 \xintFor* #1 in {{==}{!=}{<=}{>=}{&&}{||}{//}{/:}{..}{..[}{].}{]..}}% \do {\expandafter\def\csname XINT_expr_itself_#1\endcsname {#1}}% \catcode`& 7 \catcode`! 11 % \end{macrocode} % \subsubsection{\&\&, \textbar\textbar, //, /:, +, % \textendash, \texorpdfstring{\protect\lowast}{*}, /, \textasciicircum, % \texorpdfstring{\protect\lowast\protect\lowast}{**}{}, \textquotesingle and\textquotesingle, \textquotesingle % or\textquotesingle, \textquotesingle xor\textquotesingle, and % \textquotesingle mod\textquotesingle} % %\begin{lverb} % At 1.4g I finally decide to enact the switch to right % associativity for the power operators ^ and **. % % This goes via inserting into the checkp macros not anymore the precedence % chardef token (which now only serves as left precedence, inserted in the % token stream) but in its place an \xint_c_<roman> token holding the right % precedence. Which is also transmitted to spanned unary minus operators. % % Here only levels 12, 14, and 17 are created as right precedences. % % #6 and #7 got permuted and the new #7 is directly a control sequence. % Also #3 and #4 are now integers which need \romannumeral. The change in % \XINT_expr_defbin_c does not propagate as it is re-defined shortly thereafter. %\end{lverb} % \begin{macrocode} \def\XINT_expr_defbin_c #1#2#3#4#5#6#7#8% {% \def #1##1% \XINT_expr_op_<op> {% \expanded{\unexpanded{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3##4% \XINT_expr_exec_<op> {% \expandafter##2\expandafter##3\expandafter {\romannumeral`&&@\XINT:NEhook:f:one:from:two{\romannumeral`&&@#7##1##4}}% }% \def #3##1% \XINT_expr_check-_<op> {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_<op> {% \ifnum ##1>#6% \expandafter#4% \romannumeral`&&@\csname XINT_#8_op_##2\expandafter\endcsname \else \expandafter ##1\expandafter ##2% \fi }% }% \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_exec_#2\expandafter\endcsname \csname XINT_#1_check-_#2\expandafter\endcsname \csname XINT_#1_checkp_#2\expandafter\endcsname \csname XINT_#1_op_-\romannumeral\ifnum#4>12 #4\else12\fi\expandafter\endcsname \csname xint_c_\romannumeral#4\endcsname #5% {#1}% \expandafter % done 3 times but well \let\csname XINT_expr_precedence_#2\expandafter\endcsname \csname xint_c_\romannumeral#3\endcsname }% \XINT_expr_defbin_b {expr} {||} {6} {6} \xintOR \XINT_expr_defbin_b {flexpr}{||} {6} {6} \xintOR \XINT_expr_defbin_b {iiexpr}{||} {6} {6} \xintOR \catcode`& 12 \XINT_expr_defbin_b {expr} {&&} {8} {8} \xintAND \XINT_expr_defbin_b {flexpr}{&&} {8} {8} \xintAND \XINT_expr_defbin_b {iiexpr}{&&} {8} {8} \xintAND \catcode`& 7 \XINT_expr_defbin_b {expr} {xor}{6} {6} \xintXOR \XINT_expr_defbin_b {flexpr}{xor}{6} {6} \xintXOR \XINT_expr_defbin_b {iiexpr}{xor}{6} {6} \xintXOR \XINT_expr_defbin_b {expr} {//} {14}{14}\xintDivFloor \XINT_expr_defbin_b {flexpr}{//} {14}{14}\XINTinFloatDivFloor \XINT_expr_defbin_b {iiexpr}{//} {14}{14}\xintiiDivFloor \XINT_expr_defbin_b {expr} {/:} {14}{14}\xintMod \XINT_expr_defbin_b {flexpr}{/:} {14}{14}\XINTinFloatMod \XINT_expr_defbin_b {iiexpr}{/:} {14}{14}\xintiiMod \XINT_expr_defbin_b {expr} + {12}{12}\xintAdd \XINT_expr_defbin_b {flexpr} + {12}{12}\XINTinFloatAdd \XINT_expr_defbin_b {iiexpr} + {12}{12}\xintiiAdd \XINT_expr_defbin_b {expr} - {12}{12}\xintSub \XINT_expr_defbin_b {flexpr} - {12}{12}\XINTinFloatSub \XINT_expr_defbin_b {iiexpr} - {12}{12}\xintiiSub \XINT_expr_defbin_b {expr} * {14}{14}\xintMul \XINT_expr_defbin_b {flexpr} * {14}{14}\XINTinFloatMul \XINT_expr_defbin_b {iiexpr} * {14}{14}\xintiiMul \let\XINT_expr_prec_tacit \xint_c_xvi \XINT_expr_defbin_b {expr} / {14}{14}\xintDiv \XINT_expr_defbin_b {flexpr} / {14}{14}\XINTinFloatDiv \XINT_expr_defbin_b {iiexpr} / {14}{14}\xintiiDivRound % \end{macrocode} %\begin{lverb} % At 1.4g, right associativity is implemented via % a lowered right precedence here. %\end{lverb} % \begin{macrocode} \XINT_expr_defbin_b {expr} ^ {18}{17}\xintPow \XINT_expr_defbin_b {flexpr} ^ {18}{17}\XINTinFloatSciPow \XINT_expr_defbin_b {iiexpr} ^ {18}{17}\xintiiPow % \end{macrocode} %\begin{lverb} % 1.4g This is a trick (which was in old version of bnumexpr, I % wonder why I did not have it here) but it will make error messages in case % of **<token> confusing. The ^ here is of catcode 11 but it does not matter. %\end{lverb} % \begin{macrocode} \expandafter\def\csname XINT_expr_itself_**\endcsname{^}% \catcode`& 12 % \end{macrocode} %\begin{lverb} % For this which contributes to implementing 'and', 'or', etc... see % \XINT_expr_binopwrd. %\end{lverb} % \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 }% \catcode`& 7 % \end{macrocode} % \subsubsection{.., ..[, and ].. for a..b and a..[b]..c syntax} %\begin{lverb} % The 1.4 exec_..[ macros (which do no further expansion!) had silly % \expandafter doing nothing for the sole reason of sharing a common % \XINT_expr_defbin_c as used previously for the +, - etc... operators. At % 1.4b we take the time to set things straight and do other similar % simplifications. %\end{lverb} % \begin{macrocode} \def\XINT_expr_defbin_c #1#2#3#4#5#6#7% {% \def #1##1% \XINT_expr_op_..[ {% \expanded{\unexpanded{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3##4% \XINT_expr_exec_..[ {% ##2##3{{##1##4}}% }% \def #3##1% \XINT_expr_check-_..[ {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_..[ {% \ifnum ##1>#6% \expandafter#4% \romannumeral`&&@\csname XINT_#7_op_##2\expandafter\endcsname \else \expandafter ##1\expandafter ##2% \fi }% }% \def\XINT_expr_defbin_b #1% {% \expandafter\XINT_expr_defbin_c \csname XINT_#1_op_..[\expandafter\endcsname \csname XINT_#1_exec_..[\expandafter\endcsname \csname XINT_#1_check-_..[\expandafter\endcsname \csname XINT_#1_checkp_..[\expandafter\endcsname \csname XINT_#1_op_-xii\expandafter\endcsname \csname XINT_expr_precedence_..[\endcsname {#1}% }% \XINT_expr_defbin_b {expr}% \XINT_expr_defbin_b {flexpr}% \XINT_expr_defbin_b {iiexpr}% \expandafter\let\csname XINT_expr_precedence_..[\endcsname\xint_c_vi \def\XINT_expr_defbin_c #1#2#3#4#5#6#7#8% {% \def #1##1% \XINT_expr_op_<op> {% \expanded{\unexpanded{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3##4% \XINT_expr_exec_<op> {% \expandafter##2\expandafter##3\expanded {{\XINT:NEhook:x:one:from:two#8##1##4}}% }% \def #3##1% \XINT_expr_check-_<op> {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_<op> {% \ifnum ##1>#6% \expandafter#4% \romannumeral`&&@\csname XINT_#7_op_##2\expandafter\endcsname \else \expandafter ##1\expandafter ##2% \fi }% }% \def\XINT_expr_defbin_b #1#2#3% {% \expandafter\XINT_expr_defbin_c \csname XINT_#1_op_#2\expandafter\endcsname \csname XINT_#1_exec_#2\expandafter\endcsname \csname XINT_#1_check-_#2\expandafter\endcsname \csname XINT_#1_checkp_#2\expandafter\endcsname \csname XINT_#1_op_-xii\expandafter\endcsname \csname XINT_expr_precedence_#2\endcsname {#1}#3% \expandafter\let \csname XINT_expr_precedence_#2\expandafter\endcsname\xint_c_vi }% \XINT_expr_defbin_b {expr} {..}\xintSeq:tl:x \XINT_expr_defbin_b {flexpr} {..}\xintSeq:tl:x \XINT_expr_defbin_b {iiexpr} {..}\xintiiSeq:tl:x \XINT_expr_defbin_b {expr} {]..}\xintSeqB:tl:x \XINT_expr_defbin_b {flexpr}{]..}\xintSeqB:tl:x \XINT_expr_defbin_b {iiexpr}{]..}\xintiiSeqB:tl:x % \end{macrocode} % \subsubsection{<, >, ==, <=, >=, != with Python-like chaining} %\begin{lverb} % 1.4b % This is preliminary implementation of chaining of comparison % operators like Python and (I think) l3fp do. I am not too happy % with how many times the (second) operand (already evaluated) is fetched. % %\end{lverb} % \begin{macrocode} \def\XINT_expr_defbin_d #1#2% {% \def #1##1##2##3##4% \XINT_expr_exec_<op> {% \expandafter##2\expandafter##3\expandafter {\romannumeral`&&@\XINT:NEhook:f:one:from:two{\romannumeral`&&@#2##1##4}}% }% }% \def\XINT_expr_defbin_c #1#2#3#4#5#6#7#8#9% {% \def #1##1% \XINT_expr_op_<op> {% \expanded{\unexpanded{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#7% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #3##1% \XINT_expr_check-_<op> {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_<op> {% \ifnum ##1>#6% \expandafter#4% \romannumeral`&&@\csname XINT_#9_op_##2\expandafter\endcsname \else \expandafter ##1\expandafter ##2% \fi }% \let #6\xint_c_x \def #7##1% \XINT_expr_checkc_<op> {% \ifnum ##1=\xint_c_x\expandafter#8\fi ##1% }% \edef #8##1##2##3% \XINT_expr_execc_<op> {% \csname XINT_#9_precedence_\string&\string&\endcsname \expandafter\noexpand\csname XINT_#9_itself_\string&\string&\endcsname {##3}% \XINTfstop.{##3}##2% }% \XINT_expr_defbin_d #2% \XINT_expr_exec_<op> }% \def\XINT_expr_defbin_b #1#2%#3% {% \expandafter\XINT_expr_defbin_c \csname XINT_#1_op_#2\expandafter\endcsname \csname XINT_#1_exec_#2\expandafter\endcsname \csname XINT_#1_check-_#2\expandafter\endcsname \csname XINT_#1_checkp_#2\expandafter\endcsname \csname XINT_#1_op_-xii\expandafter\endcsname \csname XINT_expr_precedence_#2\expandafter\endcsname \csname XINT_#1_checkc_#2\expandafter\endcsname \csname XINT_#1_execc_#2\endcsname {#1}%#3% }% % \end{macrocode} %\begin{lverb} % Attention that third token here is left in stream by defbin_b, then % also by defbin_c and is picked up as #2 of defbin_d. Had to work around TeX % accepting only 9 arguments. Why did it not start counting at #0 like all % decent mathematicians do? %\end{lverb} % \begin{macrocode} \XINT_expr_defbin_b {expr} <\xintLt \XINT_expr_defbin_b {flexpr}<\xintLt \XINT_expr_defbin_b {iiexpr}<\xintiiLt \XINT_expr_defbin_b {expr} >\xintGt \XINT_expr_defbin_b {flexpr}>\xintGt \XINT_expr_defbin_b {iiexpr}>\xintiiGt \XINT_expr_defbin_b {expr} {==}\xintEq \XINT_expr_defbin_b {flexpr}{==}\xintEq \XINT_expr_defbin_b {iiexpr}{==}\xintiiEq \XINT_expr_defbin_b {expr} {<=}\xintLtorEq \XINT_expr_defbin_b {flexpr}{<=}\xintLtorEq \XINT_expr_defbin_b {iiexpr}{<=}\xintiiLtorEq \XINT_expr_defbin_b {expr} {>=}\xintGtorEq \XINT_expr_defbin_b {flexpr}{>=}\xintGtorEq \XINT_expr_defbin_b {iiexpr}{>=}\xintiiGtorEq \XINT_expr_defbin_b {expr} {!=}\xintNotEq \XINT_expr_defbin_b {flexpr}{!=}\xintNotEq \XINT_expr_defbin_b {iiexpr}{!=}\xintiiNotEq % \end{macrocode} % \subsubsection{Support macros for .., ..[ and ]..} % \localtableofcontents % % \paragraph{\csh{xintSeq:tl:x}} %\begin{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. %\end{lverb} % \begin{macrocode} \def\xintSeq:tl:x #1#2% {% \expandafter\XINT_Seq:tl:x \the\numexpr \xintiCeil{#1}\expandafter.\the\numexpr \xintiFloor{#2}.% }% \def\XINT_Seq:tl:x #1.#2.% {% \ifnum #2=#1 \xint_dothis\XINT_Seq:tl:x_z\fi \ifnum #2<#1 \xint_dothis\XINT_Seq:tl:x_n\fi \xint_orthat\XINT_Seq:tl:x_p #1.#2.% }% \def\XINT_Seq:tl:x_z #1.#2.{{#1/1[0]}}% \def\XINT_Seq:tl:x_p #1.#2.% {% {#1/1[0]}\ifnum #1=#2 \XINT_Seq:tl:x_e\fi \expandafter\XINT_Seq:tl:x_p \the\numexpr #1+\xint_c_i.#2.% }% \def\XINT_Seq:tl:x_n #1.#2.% {% {#1/1[0]}\ifnum #1=#2 \XINT_Seq:tl:x_e\fi \expandafter\XINT_Seq:tl:x_n \the\numexpr #1-\xint_c_i.#2.% }% \def\XINT_Seq:tl:x_e#1#2.#3.{#1}% % \end{macrocode} % \paragraph{\csh{xintiiSeq:tl:x}} % \begin{macrocode} \def\xintiiSeq:tl:x #1#2% {% \expandafter\XINT_iiSeq:tl:x \the\numexpr \xintiCeil{#1}\expandafter.\the\numexpr \xintiFloor{#2}.% }% \def\XINT_iiSeq:tl:x #1.#2.% {% \ifnum #2=#1 \xint_dothis\XINT_iiSeq:tl:x_z\fi \ifnum #2<#1 \xint_dothis\XINT_iiSeq:tl:x_n\fi \xint_orthat\XINT_iiSeq:tl:x_p #1.#2.% }% \def\XINT_iiSeq:tl:x_z #1.#2.{{#1}}% \def\XINT_iiSeq:tl:x_p #1.#2.% {% {#1}\ifnum #1=#2 \XINT_Seq:tl:x_e\fi \expandafter\XINT_iiSeq:tl:x_p \the\numexpr #1+\xint_c_i.#2.% }% \def\XINT_iiSeq:tl:x_n #1.#2.% {% {#1}\ifnum #1=#2 \XINT_Seq:tl:x_e\fi \expandafter\XINT_iiSeq:tl:x_n \the\numexpr #1-\xint_c_i.#2.% }% % \end{macrocode} %\begin{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. %\end{lverb} % % \paragraph{\csh{xintSeqA}, \csh{xintiiSeqA}} % % \begin{macrocode} \def\xintSeqA {\expandafter\XINT_SeqA\romannumeral0\xintraw}% \def\xintiiSeqA #1{\expandafter\XINT_iiSeqA\romannumeral`&&@#1;}% \def\XINT_SeqA #1]#2{\expandafter\XINT_SeqA_a\romannumeral0\xintraw {#2}#1]}% \def\XINT_iiSeqA#1;#2{\expandafter\XINT_SeqA_a\romannumeral`&&@#2;#1;}% \def\XINT_SeqA_a #1{\xint_UDzerominusfork #1-{z}% 0#1{n}% 0-{p}% \krof #1}% % \end{macrocode} % \paragraph{\csh{xintSeqB:tl:x}} %\begin{lverb} % At 1.4, delayed expansion of start and step done here and not before, % for matters of \xintdeffunc and «NEhooks». % % The float variant at 1.4 is made identical to the exact variant. I.e. % stepping is exact and comparison to the range limit too. But recall that a/b % input will be converted to a float. To handle 1/3 step for example still % better to use \xintexpr 1..1/3..10\relax for example inside the \xintfloateval. % %\end{lverb} % \begin{macrocode} \def\xintSeqB:tl:x #1{\expandafter\XINT_SeqB:tl:x\romannumeral`&&@\xintSeqA#1}% \def\XINT_SeqB:tl:x #1{\csname XINT_SeqB#1:tl:x\endcsname}% \def\XINT_SeqBz:tl:x #1]#2]#3{{#2]}}% \def\XINT_SeqBp:tl:x #1]#2]#3% {\expandafter\XINT_SeqBp:tl:x_a\romannumeral0\xintraw{#3}#2]#1]}% \def\XINT_SeqBp:tl:x_a #1]#2]#3]% {% \xintifCmp{#1]}{#2]}% {}{{#2]}}{{#2]}\expandafter\XINT_SeqBp:tl:x_b\romannumeral0\xintadd{#3]}{#2]}#1]#3]}% }% \def\XINT_SeqBp:tl:x_b #1]#2]#3]% {% \xintifCmp{#1]}{#2]}% {{#1]}\expandafter\XINT_SeqBp:tl:x_b\romannumeral0\xintadd{#3]}{#1]}#2]#3]}{{#1]}}{}% }% \def\XINT_SeqBn:tl:x #1]#2]#3% {\expandafter\XINT_SeqBn:tl:x_a\romannumeral0\xintraw{#3}#2]#1]}% \def\XINT_SeqBn:tl:x_a #1]#2]#3]% {% \xintifCmp{#1]}{#2]}% {{#2]}\expandafter\XINT_SeqBn:tl:x_b\romannumeral0\xintadd{#3]}{#2]}#1]#3]}{{#2]}}{}% }% \def\XINT_SeqBn:tl:x_b #1]#2]#3]% {% \xintifCmp{#1]}{#2]}% {}{{#1]}}{{#1]}\expandafter\XINT_SeqBn:tl:x_b\romannumeral0\xintadd{#3]}{#1]}#2]#3]}% }% % \end{macrocode} % \paragraph{\csh{xintiiSeqB:tl:x}} % \begin{macrocode} \def\xintiiSeqB:tl:x #1{\expandafter\XINT_iiSeqB:tl:x\romannumeral`&&@\xintiiSeqA#1}% \def\XINT_iiSeqB:tl:x #1{\csname XINT_iiSeqB#1:tl:x\endcsname}% \def\XINT_iiSeqBz:tl:x #1;#2;#3{{#2}}% \def\XINT_iiSeqBp:tl:x #1;#2;#3{\expandafter\XINT_iiSeqBp:tl:x_a\romannumeral`&&@#3;#2;#1;}% \def\XINT_iiSeqBp:tl:x_a #1;#2;#3;% {% \xintiiifCmp{#1}{#2}% {}{{#2}}{{#2}\expandafter\XINT_iiSeqBp:tl:x_b\romannumeral0\xintiiadd{#3}{#2};#1;#3;}% }% \def\XINT_iiSeqBp:tl:x_b #1;#2;#3;% {% \xintiiifCmp{#1}{#2}% {{#1}\expandafter\XINT_iiSeqBp:tl:x_b\romannumeral0\xintiiadd{#3}{#1};#2;#3;}{{#1}}{}% }% \def\XINT_iiSeqBn:tl:x #1;#2;#3{\expandafter\XINT_iiSeqBn:tl:x_a\romannumeral`&&@#3;#2;#1;}% \def\XINT_iiSeqBn:tl:x_a #1;#2;#3;% {% \xintiiifCmp{#1}{#2}% {{#2}\expandafter\XINT_iiSeqBn:tl:x_b\romannumeral0\xintiiadd{#3}{#2};#1;#3;}{{#2}}{}% }% \def\XINT_iiSeqBn:tl:x_b #1;#2;#3;% {% \xintiiifCmp{#1}{#2}% {}{{#1}}{{#1}\expandafter\XINT_iiSeqBn:tl:x_b\romannumeral0\xintiiadd{#3}{#1};#2;#3;}% }% % \end{macrocode} % \subsection{Square brackets [\texorpdfstring{\,}{ }] both as a container and a Python slicer} % Refactored at |1.4| % %\begin{lverb} % The architecture allows to implement separately a «left» and a «right» % precedence and this is crucial. %\end{lverb} % \localtableofcontents % % % \subsubsection{[...] as «oneple» constructor} % %\begin{lverb} % In the definition of \XINT_expr_op_obracket the parameter % is trash {}. The [ is intercepted by the getnextfork and handled % via the \xint_c_ii^v highest precedence trick to get op_obracket % executed. %\end{lverb} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`[ 11 \catcode`] 11 }^^A % \begin{macrocode} \def\XINT_expr_itself_obracket{obracket}% \catcode`] 11 \catcode`[ 11 \def\XINT_expr_defbin_c #1#2#3#4#5#6% {% \def #1##1% {% \expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1% op_] {% \expanded{\unexpanded{\XINT_expr_put_op_first{{##1}}}\expandafter}% \romannumeral`&&@\XINT_expr_getop }% \def #3##1% until_cbracket_a {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% #5 = op_-xii -{#4##1}% \krof }% \def #4##1##2% until_cbracket_b {% \ifcase ##1\expandafter\XINT_expr_missing_] \or \expandafter\XINT_expr_missing_] \or \expandafter#2% \else \expandafter #4% \romannumeral`&&@\csname XINT_#6_op_##2\expandafter\endcsname \fi }% }% \def\XINT_expr_defbin_b #1% {% \expandafter\XINT_expr_defbin_c \csname XINT_#1_op_obracket\expandafter\endcsname \csname XINT_#1_op_]\expandafter\endcsname \csname XINT_#1_until_cbracket_a\expandafter\endcsname \csname XINT_#1_until_cbracket_b\expandafter\endcsname \csname XINT_#1_op_-xii\endcsname {#1}% }% \XINT_expr_defbin_b {expr}% \XINT_expr_defbin_b {flexpr}% \XINT_expr_defbin_b {iiexpr}% \def\XINT_expr_missing_] {\XINT_expandableerror{Ooops, looks like we are missing a ]. Aborting!}% \xint_c_ \XINT_expr_done}% \let\XINT_expr_precedence_]\xint_c_ii % \end{macrocode} % \subsubsection{[...] brackets and : operator for NumPy-like slicing and item % indexing syntax} %\begin{lverb} % The opening bracket [ for the nutple constructor is filtered out by % \XINT_expr_getnextfork and becomes «obracket» which behaves with % precedence level 2. For the [..] Python slicer on the other hand, a real % operator [ is defined with precedence level 4 (it must be higher than % precedence level of commas) on its right and maximal precedence on its left. % % Important: although slicing and indexing shares many rules with Python/NumPy % there are some significant differences: in particular there can not be any % out-of-range error generated, slicing applies also to «oples» and not only % to «nutple», and nested lists do not have to have their leaves at a constant % depth. See the user manual. % % Currently, NumPy-like nested (basic) slicing is implemented, i.e [a:b, c:d, % N, e:f, M] type syntax with Python rules regarding negative integers. This % is parsed as an expression and can arise from expansion or contain % calculations. % % Currently stepping, Ellipsis, and simultaneous multi-index extracting are % not yet implemented. % % There are some subtle things here with possibility of variables been passed % by reference. %\end{lverb} % \begin{macrocode} \def\XINT_expr_defbin_c #1#2#3#4#5#6% {% \def #1##1% \XINT_expr_op_[ {% \expanded{\unexpanded{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3##4% \XINT_expr_exec_] {% \expandafter\XINT_expr_put_op_first \expanded {% {\XINT:NEhook:x:listsel\XINT_ListSel_top ##1__##4&({##1}\expandafter}% \expandafter }% \romannumeral`&&@\XINT_expr_getop }% \def #3##1% \XINT_expr_check-_] {% \xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_] {% \ifcase ##1\XINT_expr_missing_] \or \XINT_expr_missing_] \or \expandafter##1\expandafter##2% \else \expandafter#4% \romannumeral`&&@\csname XINT_#6_op_##2\expandafter\endcsname \fi }% }% \let\XINT_expr_precedence_[ \xint_c_xx \def\XINT_expr_defbin_b #1% {% \expandafter\XINT_expr_defbin_c \csname XINT_#1_op_[\expandafter\endcsname \csname XINT_#1_exec_]\expandafter\endcsname \csname XINT_#1_check-_]\expandafter\endcsname \csname XINT_#1_checkp_]\expandafter\endcsname \csname XINT_#1_op_-xii\endcsname {#1}% }% \XINT_expr_defbin_b {expr}% \XINT_expr_defbin_b {flexpr}% \XINT_expr_defbin_b {iiexpr}% \catcode`] 12 \catcode`[ 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters %\begin{lverb} % At 1.4 the getnext, scanint, scanfunc, getop chain got revisited to % trigger automatic insertion of the nil variable if needed, without having in % situations like here to define operators to support «[:» or «:]». And as we % want to implement nested slicing à la NumPy, we would have had to handle % also «:,» for example. Thus here we simply have to define the sole operator % «:» and it will be some sort of inert joiner preparing a slicing spec. %\end{lverb} % \begin{macrocode} \def\XINT_expr_defbin_c #1#2#3#4#5#6% {% \def #1##1% \XINT_expr_op_: {% \expanded{\unexpanded{#2{##1}}\expandafter}% \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% \def #2##1##2##3##4% \XINT_expr_exec_: {% ##2##3{:##1{0};##4:_}% }% \def #3##1% \XINT_expr_check-_: {\xint_UDsignfork ##1{\expandafter#4\romannumeral`&&@#5}% -{#4##1}% \krof }% \def #4##1##2% \XINT_expr_checkp_: {% \ifnum ##1>\XINT_expr_precedence_: \expandafter #4\romannumeral`&&@% \csname XINT_#6_op_##2\expandafter\endcsname \else \expandafter##1\expandafter##2% \fi }% }% \let\XINT_expr_precedence_: \xint_c_vi \def\XINT_expr_defbin_b #1% {% \expandafter\XINT_expr_defbin_c \csname XINT_#1_op_:\expandafter\endcsname \csname XINT_#1_exec_:\expandafter\endcsname \csname XINT_#1_check-_:\expandafter\endcsname \csname XINT_#1_checkp_:\expandafter\endcsname \csname XINT_#1_op_-xii\endcsname {#1}% }% \XINT_expr_defbin_b {expr}% \XINT_expr_defbin_b {flexpr}% \XINT_expr_defbin_b {iiexpr}% % \end{macrocode} % \subsubsection{Macro layer implementing indexing and slicing} %\begin{lverb} % xintexpr applies slicing not only to «objects» (which can be passed % as arguments to functions) but also to «oples». % % Our «nlists» are not necessarily regular N-dimensional arrays à la NumPy. % Leaves can be at arbitrary depths. If we were handling regular «ndarrays», % we could proceed a bit differently. % % For the related % explanations, refer to the user manual. % % Notice that currently the code uses f-expandable (and not using \expanded) % macros \xintApply, \xintApplyUnbraced, \xintKeep, \xintTrim, \xintNthOne from % $xinttoolsnameimp. % % But the whole expansion happens inside an \expanded context, so possibly % some gain could be achieved with x-expandable variants (xintexpr < 1.4 % had an \xintKeep:x:csv). % % I coded \xintApply:x and \xintApplyUnbraced:x in $xinttoolsnameimp, Brief % testing indicated they were perhaps a bit better for 5x5x5x5 and 15x15x15x15 % arrays of 8 digits numbers and for 30x30x15 with 16 digits numbers: say % 1$% gain... this seems to raise to between 4$% and % 5$% for 400x400 array of 1 digit... % % Currently sticking with old macros. %\end{lverb} % \begin{macrocode} \def\XINT_ListSel_deeper #1% {% \if :#1\xint_dothis\XINT_ListSel_slice_next\fi \xint_orthat {\XINT_ListSel_extract_next {#1}}% }% \def\XINT_ListSel_slice_next #1(% {% \xintApply{\XINT_ListSel_recurse{:#1}}% }% \def\XINT_ListSel_extract_next #1(% {% \xintApplyUnbraced{\XINT_ListSel_recurse{#1}}% }% \def\XINT_ListSel_recurse #1#2% {% \XINT_ListSel_check #2__#1({#2}\expandafter\empty\empty }% \def\XINT_ListSel_check{\expandafter\XINT_ListSel_check_a \string}% \def\XINT_ListSel_check_a #1% {% \if #1\bgroup\xint_dothis\XINT_ListSel_check_is_ok\fi \xint_orthat\XINT_ListSel_check_leaf }% \def\XINT_ListSel_check_leaf #1\expandafter{\expandafter}% \def\XINT_ListSel_check_is_ok {% \expandafter\XINT_ListSel_check_is_ok_a\expandafter{\string}% }% \def\XINT_ListSel_check_is_ok_a #1__#2% {% \if :#2\xint_dothis{\XINT_ListSel_slice}\fi \xint_orthat {\XINT_ListSel_nthone {#2}}% }% \def\XINT_ListSel_top #1#2% {% \if _\noexpand#2% \expandafter\XINT_ListSel_top_one_or_none\string#1.\else \expandafter\XINT_ListSel_top_at_least_two\fi }% \def\XINT_ListSel_top_at_least_two #1__{\XINT_ListSel_top_ople}% \def\XINT_ListSel_top_one_or_none #1% {% \if #1_\xint_dothis\XINT_ListSel_top_nil\fi \if #1.\xint_dothis\XINT_ListSel_top_nutple_a\fi \if #1\bgroup\xint_dothis\XINT_ListSel_top_nutple\fi \xint_orthat\XINT_ListSel_top_number }% \def\XINT_ListSel_top_nil #1\expandafter#2\expandafter{\fi\expandafter}% \def\XINT_ListSel_top_nutple {% \expandafter\XINT_ListSel_top_nutple_a\expandafter{\string}% }% \def\XINT_ListSel_top_nutple_a #1_#2#3(#4% {% \fi\if :#2\xint_dothis{{\XINT_ListSel_slice #3(#4}}\fi \xint_orthat {\XINT_ListSel_nthone {#2}#3(#4}% }% \def\XINT_ListSel_top_number #1_{\fi\XINT_ListSel_top_ople}% \def\XINT_ListSel_top_ople #1% {% \if :#1\xint_dothis\XINT_ListSel_slice\fi \xint_orthat {\XINT_ListSel_nthone {#1}}% }% \def\XINT_ListSel_slice #1% {% \expandafter\XINT_ListSel_slice_a \expandafter{\romannumeral0\xintnum{#1}}% }% \def\XINT_ListSel_slice_a #1#2;#3#4% {% \if _#4\expandafter\XINT_ListSel_s_b \else\expandafter\XINT_ListSel_slice_b\fi #1;#3% }% \def\XINT_ListSel_s_b #1#2;#3#4% {% \if \expandafter\XINT_ListSel_s_last\fi \XINT_ListSel_s_c #1{#1#2}{#4}% }% \def\XINT_ListSel_s_last\XINT_ListSel_s_c #1#2#3(#4% {% \if-#1\expandafter\xintKeep\else\expandafter\xintTrim\fi {#2}{#4}% }% \def\XINT_ListSel_s_c #1#2#3(#4% {% \expandafter\XINT_ListSel_deeper \expanded{\unexpanded{#3}(\expandafter}\expandafter{% \romannumeral0% \if-#1\expandafter\xintkeep\else\expandafter\xinttrim\fi {#2}{#4}}% }% % \end{macrocode} %\begin{lverb} % % \xintNthElt from xinttools (knowingly) strips one level of % braces when fetching kth «item» from {v1}...{vN}. If we expand % {\xintNthElt{k}{{v1}...{vN}}} (notice external braces): % %( if k is out of range we end up with {} %: if k is in range and the kth braced item was {} we end up with {} %: if k is in range and the kth braced item was {17} we end up with {17} %) % % Problem is that individual numbers such as 17 are stored {{17}}. So % we must have one more brace pair and in the first two cases we end up % with {{}}. But in the first case we should end up with the empty ople % {}, not the empty bracketed ople {{}}. % % I have thus added \xintNthOne to $xinttoolsnameimp which does not % strip brace pair from an extracted item. % % Attention: \XINT_nthonepy_a does no expansion on second argument. % But here arguments are either numerical or already expanded. % Normally. % %\end{lverb} % \begin{macrocode} \def\XINT_ListSel_nthone #1#2% {% \if \expandafter\XINT_ListSel_nthone_last\fi \XINT_ListSel_nthone_a {#1}{#2}% }% \def\XINT_ListSel_nthone_a #1#2(#3% {% \expandafter\XINT_ListSel_deeper \expanded{\unexpanded{#2}(\expandafter}\expandafter{% \romannumeral0\expandafter\XINT_nthonepy_a\the\numexpr\xintNum{#1}.{#3}}% }% \def\XINT_ListSel_nthone_last\XINT_ListSel_nthone_a #1#2(%#3% {% \romannumeral0\expandafter\XINT_nthonepy_a\the\numexpr\xintNum{#1}.%{#3} }% % \end{macrocode} %\begin{lverb} % The macros here are basically f-expandable and use the % f-expandable \xintKeep and \xintTrim. Prior to xint 1.4, there was % here an x-expandable \xintKeep:x:csv dealing with comma separated % items, for time being we make do with our f-expandable toolkit. %\end{lverb} % \begin{macrocode} \def\XINT_ListSel_slice_b #1;#2_#3% {% \if \expandafter\XINT_ListSel_slice_last\fi \expandafter\XINT_ListSel_slice_c \expandafter{\romannumeral0\xintnum{#2}};#1;{#3}% }% \def\XINT_ListSel_slice_last\expandafter\XINT_ListSel_slice_c #1;#2;#3(%#4 {% \expandafter\XINT_ListSel_slice_last_c #1;#2;%{#4} }% \def\XINT_ListSel_slice_last_c #1;#2;#3% {% \romannumeral0\XINT_ListSel_slice_d #2;#1;{#3}% }% \def\XINT_ListSel_slice_c #1;#2;#3(#4% {% \expandafter\XINT_ListSel_deeper \expanded{\unexpanded{#3}(\expandafter}\expandafter{% \romannumeral0\XINT_ListSel_slice_d #2;#1;{#4}}% }% \def\XINT_ListSel_slice_d #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 \expandafter\xint_gob_andstop_iii\fi \xintkeep{#2-#1}{\xintTrim{#1}{#3}}% }% \def\XINT_ListSel_N:N #1;#2;#3% {% \expandafter\XINT_ListSel_N:N_a \the\numexpr #2-#1\expandafter;\the\numexpr#1+\xintLength{#3};{#3}% }% \def\XINT_ListSel_N:N_a #1;#2;#3% {% \unless\ifnum #1>\xint_c_ \expandafter\xint_gob_andstop_iii\fi \xintkeep{#1}{\xintTrim{\ifnum#2<\xint_c_\xint_c_\else#2\fi}{#3}}% }% \def\XINT_ListSel_N:P #1;#2;#3% {% \expandafter\XINT_ListSel_N:P_a \the\numexpr #1+\xintLength{#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{#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} % \subsection{Support for raw A/B[N]} %\begin{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. % % At 1.4, [ is already overloaded and it is not easy to support this. We do % this by a kludge maintaining more or less former (very not efficient) way % but using $$ sign which is free for time being. No, finally I use the null % character, should be safe enough! (I hesitated about using R with catcode % 12). % % As for ? operator we needed % to hack into \XINT_expr_getop_b for intercepting that pseudo operator. See % also \XINT_expr_scanint_c (\XINT_expr_rawxintfrac). %\end{lverb} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`& 11 }^^A % \begin{macrocode} \catcode0 11 \let\XINT_expr_precedence_&&@ \xint_c_xiv \def\XINT_expr_op_&&@ #1#2]% {% \expandafter\XINT_expr_put_op_first \expanded{{{\xintE#1{\xint_zapspaces #2 \xint_gobble_i}}}% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT_iiexpr_op_&&@ #1#2]% {% \expandafter\XINT_expr_put_op_first \expanded{{{\xintiiE#1{\xint_zapspaces #2 \xint_gobble_i}}}% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT_flexpr_op_&&@ #1#2]% {% \expandafter\XINT_expr_put_op_first \expanded{{{\XINTinFloatE#1{\xint_zapspaces #2 \xint_gobble_i}}}% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \catcode0 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters % \subsection{? as two-way and ?? as three-way «short-circuit» conditionals} %\begin{lverb} % Comments undergoing reconstruction. %\end{lverb} % % \begin{macrocode} \let\XINT_expr_precedence_? \xint_c_xx \catcode`- 11 % \end{macrocode} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`- 11 }\FixInterMacrocodeVspace % \begin{macrocode} \def\XINT_expr_op_? {\XINT_expr_op__? \XINT_expr_op_-xii}% \def\XINT_flexpr_op_?{\XINT_expr_op__? \XINT_flexpr_op_-xii}% \def\XINT_iiexpr_op_?{\XINT_expr_op__? \XINT_iiexpr_op_-xii}% \catcode`- 12 \def\XINT_expr_op__? #1#2#3% {\XINT_expr_op__?_a #3!\xint_bye\XINT_expr_exec_? {#1}{#2}{#3}}% \def\XINT_expr_op__?_a #1{\expandafter\XINT_expr_op__?_b\detokenize{#1}}% \def\XINT_expr_op__?_b #1% {\if ?#1\expandafter\XINT_expr_op__?_c\else\expandafter\xint_bye\fi }% \def\XINT_expr_op__?_c #1{\xint_gob_til_! #1\XINT_expr_op_?? !\xint_bye}% \def\XINT_expr_op_?? !\xint_bye\xint_bye\XINT_expr_exec_?{\XINT_expr_exec_??}% \catcode`- 11 \def\XINT_expr_exec_? #1#2% {% \expandafter\XINT_expr_check-_after?\expandafter#1% \romannumeral`&&@\expandafter\XINT_expr_getnext\romannumeral0\xintiiifnotzero#2% }% \def\XINT_expr_exec_?? #1#2#3% {% \expandafter\XINT_expr_check-_after?\expandafter#1% \romannumeral`&&@\expandafter\XINT_expr_getnext\romannumeral0\xintiiifsgn#2% }% \def\XINT_expr_check-_after? #1{% \def\XINT_expr_check-_after? ##1##2% {% \xint_UDsignfork ##2{##1}% #1{##2}% \krof }}\expandafter\XINT_expr_check-_after?\string -% \catcode`- 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters % \subsection{! as postfix factorial operator} % \begin{macrocode} \let\XINT_expr_precedence_! \xint_c_xx \def\XINT_expr_op_! #1% {% \expandafter\XINT_expr_put_op_first \expanded{{\romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintFac#1}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT_flexpr_op_! #1% {% \expandafter\XINT_expr_put_op_first \expanded{{\romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINTinFloatFacdigits#1}}\expandafter}% \romannumeral`&&@\XINT_expr_getop }% \def\XINT_iiexpr_op_! #1% {% \expandafter\XINT_expr_put_op_first \expanded{{\romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiFac#1}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} %\begin{lverb} % At 1.4g, fix for input "x! == y" via a fake operator !==. The ! % is of catcode 11 but this does not matter here. The definition of % \XINT_expr_itself_!== is required by the functioning of the scanop macros. % % We don't have to worry about "x! = y" as the single-character Boolean % comparison = operator has been removed from syntax. Fixing it would have % required obeying space tokens when parsing operators. For "x! == y" case, % obeying space tokens would not solve "x!==y" input case anyhow. %\end{lverb} % \begin{macrocode} \expandafter \def\csname XINT_expr_precedence_!==\expandafter\endcsname \csname XINT_expr_itself_!==\endcsname {\XINT_expr_precedence_! !==}% \expandafter\def\csname XINT_expr_itself_!==\endcsname{!==}% % \end{macrocode} % \subsection{User defined variables} % \localtableofcontents % % \subsubsection{\csh{xintdefvar}, \csh{xintdefiivar}, % \csh{xintdeffloatvar}} % \changed{1.1} % \changed[2017/12/01]{1.2p} Extends |\xintdefvar| et al.\@ to accept % simultaneous assignments to multiple variables. % \changed[2018/06/17]{1.3c} % 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} % %\begin{lverb} % Note that the optional argument [P] as usable with % \xintfloatexpr is **not** % supported by \xintdeffloatvar. One must do \xintdeffloatvar % foo = \xintfloatexpr[16] blabla \relax; to achieve the effect. %\end{lverb} % % \changed[2020/01/27]{1.4} % The expression will be fetched up to final semi-colon in a manner % allowing inner semi-colons as used in the iter(), rseq(), subsm(), % subsn() etc... syntax. They don't need to be hidden within a % braced pair anymore. % % \changed{1.4} % Automatic unpacking in case of simultaneous assignments if the expression % evaluates to a nutple. % % Notes (added much later on 2021/06/10 during preparation of |1.4i|): % \begin{enumerate} % \item the code did not try to intercept illicit syntax such as % |\xintdefvar a,b,c:=<number>;|. It blindly «unpacked» the number handling it as if % it was a nutple. The extended functionality added at |1.4i| requires to % check for such a situation, as the syntax is not illicit anymore. % \item the code was broken in case the expression to evaluate was an ople of % length 10 or more, due to a silly mistake at some point during |1.4| % development which replaced some |\ifnum| by an |\if|, perhaps due to % mental confusion with the fact that functions can have at most 9 % arguments, but here the code is about defining variables. Anyway this got % fixed as corollary to the |1.4i| extension. % \end{enumerate} % % % \changed[2021/02/20]{1.4c} One year later I realized I had broken tacit % multiplication for situations such as |variable(1+2)|. As hinted at in % comments above before |1.4| release I had been doing some deep refactoring % here, which I cancelled almost completely in the end... but not quite, and % as a result there was a problem that some macro holding braced contents was % expanded to late, once it was in old core routines of xintfrac not expecting % other things than digits. I do an emergency bugfix here with some % |\expandafter|'s but I don't have the code in my brain at this time, and % don't have the luxury now to invest into it. Let's hope this does not induce % breakage elsewhere, and that the February 2020 |1.4| did not break something % else. % % \changed[2021/04/17]{1.4e} %\begin{lverb} % Modifies \xintdeffloatvar to round to the prevailing % precision (formerly, any operation would induce rounding, but in case of % things such as \xintdeffloatvar foo:=\xintexpr 1/100!\relax; there was no % automatic rounding. One could use 0+ syntax to trigger it, and for oples, % some trick like \xintfloatexpr[\XINTdigits]...\relax extra wrapper. %\end{lverb} % \changed[2021/05/22]{1.4g} %\begin{lverb} % The \expandafter\expandafter\expandafter et al. chain % which was kept by \XINT_expr_defvar_one_b for expanding only at time of use % the \XINT_expr_var_foo in \XINT_expr_onliteral_foo were senseless overhead % added at 1.4c. This is used only for real variables, not dummy variables or % fake variables and it is simpler to have the \XINT_expr_var_foo % pre-expanded. So let's use some \edef here. % % The \XINT_expr_onliteral_foo is expanded as result of action of \XINT_expr_op_` % (or \XINT_flexpr_op_`, \XINT_iiexpr_op_`) which itself was triggered consuming % already an \XINT_expr_put_op_first, so its expansion has to produce tokens % as expected after \XINT_expr_put_op_first$empty: % <precedence token><op token>{expanded value}. %\end{lverb} % % \changed[2021/06/10]{1.4i} % Implement extended notion of simultaneous assignments: if there are more % variables than values, define the extra variables to be nil. If there are % less variables than values let the last variable % be defined as the ople concatenating all non reclaimed values. % % If there are at least two variables, the right hand side, if it turns out to % be a nutple, is (as since |1.4|) automatically unpacked, then the above % rules apply. % % \changed[2021/06/11]{1.4i} %\begin{lverb} % Fix the long-standing «seq renaming bug» via a change here of the % name of auxiliary macro. Previously «onliteral_<varname>» now % «var*_<varname>». I hesitated with using «var_varname*» rather. % % Hesitated adding \XINT_expr_letvar_one (motivation: case of simultaneous % assignments leading to defining «nil» variables). Finally, no. %\end{lverb} % % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`* 11 }^^A % \begin{macrocode} \catcode`* 11 \def\XINT_expr_defvar_one #1#2% {% \XINT_global \expandafter\edef\csname XINT_expr_varvalue_#1\endcsname {#2}% \XINT_expr_defvar_one_b {#1}% }% \def\XINT_expr_defvar_one_b #1% {% \XINT_global \expandafter\edef\csname XINT_expr_var_#1\endcsname {{\expandafter\noexpand\csname XINT_expr_varvalue_#1\endcsname}}% \XINT_global \expandafter\edef\csname XINT_expr_var*_#1\endcsname {\XINT_expr_prec_tacit *\csname XINT_expr_var_#1\endcsname(}% \ifxintverbose\xintMessage{xintexpr}{Info} {Variable #1 \ifxintglobaldefs globally \fi defined with value \csname XINT_expr_varvalue_#1\endcsname.}% \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% {% \def\XINT_defvar_tmpa{#2}% \expandafter\XINT_expr_defvar_a\expanded{\unexpanded{{#1}}\expandafter}% \romannumeral\XINT_expr_fetch_to_semicolon }% \def\XINT_expr_defvar_a #1#2% {% \xintexprRestoreCatcodes % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters %\begin{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..). % % The \XINT_expr_defvar_getname closes the group opened here. %\end{lverb} % \begin{macrocode} \begingroup\lccode`~`: \lowercase{\let~}\empty \edef\XINT_defvar_tmpa{\XINT_defvar_tmpa}% \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}{Error} {Aborting: not allowed to declare variable with empty name.}% \or \XINT_global \expandafter \edef\csname XINT_expr_varvalue_\XINT_defvar_tmpa\endcsname{#1#2\relax}% \XINT_expr_defvar_one_b\XINT_defvar_tmpa \else \edef\XINT_defvar_tmpb{#1#2\relax}% \edef\XINT_defvar_tmpd{\expandafter\xintLength\expandafter{\XINT_defvar_tmpb}}% \ifnum\XINT_defvar_tmpd=\xint_c_i \oodef\XINT_defvar_tmpb{\expandafter\xint_firstofone\XINT_defvar_tmpb}% \if0\expandafter\expandafter\expandafter\XINT_defvar_checkifnutple \expandafter\string\XINT_defvar_tmpb _\xint_bye \odef\XINT_defvar_tmpb{\expandafter{\XINT_defvar_tmpb}}% \else \edef\XINT_defvar_tmpd{\expandafter\xintLength\expandafter{\XINT_defvar_tmpb}}% \fi \fi \xintAssignArray\xintCSVtoList\XINT_defvar_tmpa\to\XINT_defvar_tmpvar \def\XINT_defvar_tmpe{1}% \expandafter\XINT_expr_defvar_multiple\XINT_defvar_tmpb\relax \fi }% \def\XINT_defvar_checkifnutple#1% {% \if#1_1\fi \if#1\bgroup1\fi 0\xint_bye }% \def\XINT_expr_defvar_multiple {% \ifnum\XINT_defvar_tmpe<\XINT_defvar_tmpc\space \expandafter\XINT_expr_defvar_multiple_one \else \expandafter\XINT_expr_defvar_multiple_last\expandafter\empty \fi }% \def\XINT_expr_defvar_multiple_one {% \ifnum\XINT_defvar_tmpe>\XINT_defvar_tmpd\space \expandafter\XINT_expr_defvar_one \csname XINT_defvar_tmpvar\XINT_defvar_tmpe\endcsname{}% \edef\XINT_defvar_tmpe{\the\numexpr\XINT_defvar_tmpe+1}% \expandafter\XINT_expr_defvar_multiple \else \expandafter\XINT_expr_defvar_multiple_one_a \fi }% \def\XINT_expr_defvar_multiple_one_a #1% {% \expandafter\XINT_expr_defvar_one \csname XINT_defvar_tmpvar\XINT_defvar_tmpe\endcsname{{#1}}% \edef\XINT_defvar_tmpe{\the\numexpr\XINT_defvar_tmpe+1}% \XINT_expr_defvar_multiple }% \def\XINT_expr_defvar_multiple_last #1\relax {% \expandafter\XINT_expr_defvar_one \csname XINT_defvar_tmpvar\XINT_defvar_tmpe\endcsname{#1}% \xintRelaxArray\XINT_defvar_tmpvar \let\XINT_defvar_tmpa\empty \let\XINT_defvar_tmpb\empty \let\XINT_defvar_tmpc\empty \let\XINT_defvar_tmpd\empty \let\XINT_defvar_tmpe\empty }% \catcode`~ 3 \catcode`: 11 % \end{macrocode} %\begin{lverb} % This SafeCatcodes is mainly in the hope that semi-colon ending the % expression can still be sanitized. % % Pre 1.4e definition: %(\def\xintdeffloatvar {\xintexprSafeCatcodes\xintdeffloatvar_a}% %:\def\xintdeffloatvar_a #1={\XINT_expr_defvar\xintthebarefloateval{#1}}% %) % This would keep the value (or values) with extra digits, now. % If this is actually wanted one can use % \xintdefvar foo:=\xintfloatexpr...\relax; % syntax, but recalling that only operations trigger the rounding inside % \xintfloatexpr. Some tricks are needed for no operations case if multiple or % nested values. But for a single one, one can use simply the float() % function. % %\end{lverb} % \begin{macrocode} \def\xintdefvar {\xintexprSafeCatcodes\xintdefvar_a}% \def\xintdefvar_a#1={\XINT_expr_defvar\xintthebareeval{#1}}% \def\xintdefiivar {\xintexprSafeCatcodes\xintdefiivar_a}% \def\xintdefiivar_a#1={\XINT_expr_defvar\xintthebareiieval{#1}}% \def\xintdeffloatvar {\xintexprSafeCatcodes\xintdeffloatvar_a}% \def\xintdeffloatvar_a #1={\XINT_expr_defvar\xintthebareroundedfloateval{#1}}% % \end{macrocode} % \subsubsection{\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_`}. % % \changed{1.4i} % Track |s/onliteral/var*/| change in macro names. % \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_varvalue_\XINT_unvar_tmpa\endcsname\xint_undefined \XINT_global\expandafter \let\csname XINT_expr_var_\XINT_unvar_tmpa\endcsname\xint_undefined \XINT_global\expandafter \let\csname XINT_expr_var*_\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{Support for dummy variables} % \localtableofcontents % \subsubsection{\csh{xintnewdummy}} %\begin{lverb} % Comments under reconstruction. % % 1.4 adds multi-letter names as usable dummy variables! %\end{lverb} % \changed[2021/06/11]{1.4i} %\begin{lverb} % s/onliteral/var*/ to fix the «seq renaming bug». %\end{lverb} % \begin{macrocode} \catcode`* 11 \def\XINT_expr_makedummy #1% {% \edef\XINT_tmpa{\xint_zapspaces #1 \xint_gobble_i}% \ifcsname XINT_expr_var_\XINT_tmpa\endcsname \XINT_global \expandafter\let\csname XINT_expr_var_\XINT_tmpa/old\expandafter\endcsname \csname XINT_expr_var_\XINT_tmpa\expandafter\endcsname \fi \ifcsname XINT_expr_var*_\XINT_tmpa\endcsname \XINT_global \expandafter\let\csname XINT_expr_var*_\XINT_tmpa/old\expandafter\endcsname \csname XINT_expr_var*_\XINT_tmpa\expandafter\endcsname \fi \expandafter\XINT_global \expanded {\edef\expandafter\noexpand \csname XINT_expr_var_\XINT_tmpa\endcsname ##1\relax !\XINT_tmpa##2}% {{##2}##1\relax !\XINT_tmpa{##2}}% \expandafter\XINT_global \expanded {\edef\expandafter\noexpand \csname XINT_expr_var*_\XINT_tmpa\endcsname ##1\relax !\XINT_tmpa##2}% {\XINT_expr_prec_tacit *{##2}(##1\relax !\XINT_tmpa{##2}}%) }% \xintApplyUnbraced \XINT_expr_makedummy {abcdefghijklmnopqrstuvwxyz}% \xintApplyUnbraced \XINT_expr_makedummy {ABCDEFGHIJKLMNOPQRSTUVWXYZ}% \def\xintnewdummy #1{% \XINT_expr_makedummy{#1}% \ifxintverbose\xintMessage {xintexpr}{Info}% {\XINT_tmpa\space now \ifxintglobaldefs globally \fi usable as dummy variable.}% \fi }% \catcode`* 12 % \end{macrocode} % The |nil| variable was need in |xint < 1.4| (with some other meaning) % in places the syntax could not allow emptiness, such as |,,|, and % other things, but at |1.4| meaning as changed. % % The other variables are new with |1.4|. % Don't use the |None|, it is tentative, and may be input as |[]|. % % Refactored at |1.4i| to define them as really genuine variables, % i.e. also with associated |var*| macros involved in tacit multiplication % (even though it will be broken with |nil|, and with |None| in |\xintiiexpr|). % No real reason, because |\XINT_expr_op__| managed them fine even in absence % of |var*| macros. % \begin{macrocode} \XINT_expr_defvar_one{nil}{}% \XINT_expr_defvar_one{None}{{}}% ? tentative \XINT_expr_defvar_one{false}{{0}}% Maple, TeX \XINT_expr_defvar_one{true}{{1}}% \XINT_expr_defvar_one{False}{{0}}% Python \XINT_expr_defvar_one{True}{{1}}% % \end{macrocode} % \subsubsection{\csh{xintensuredummy}, \csh{xintrestorevariable}} %\begin{lverb} % 1.3e \xintensuredummy differs from \xintnewdummy only in the informational message... % Attention that this is not meant to be nested. % % 1.4 fixes that the message mentioned non-existent \xintrestoredummy (real % name was \xintrestorelettervar and renames the latter to % \xintrestorevariable as it applies also to multi-letter names. %\end{lverb} % \begin{macrocode} \def\xintensuredummy #1{% \XINT_expr_makedummy{#1}% \ifxintverbose\xintMessage {xintexpr}{Info}% {\XINT_tmpa\space now \ifxintglobaldefs globally \fi usable as dummy variable.&&J Issue \string\xintrestorevariable{\XINT_tmpa} to restore former meaning.}% \fi }% \def\xintrestorevariablesilently #1{% \edef\XINT_tmpa{\xint_zapspaces #1 \xint_gobble_i}% \ifcsname XINT_expr_var_\XINT_tmpa/old\endcsname \XINT_global \expandafter\let\csname XINT_expr_var_\XINT_tmpa\expandafter\endcsname \csname XINT_expr_var_\XINT_tmpa/old\expandafter\endcsname \fi \ifcsname XINT_expr_var*_\XINT_tmpa/old\endcsname \XINT_global \expandafter\let\csname XINT_expr_var*_\XINT_tmpa\expandafter\endcsname \csname XINT_expr_var*_\XINT_tmpa/old\expandafter\endcsname \fi }% \def\xintrestorevariable #1{% \xintrestorevariablesilently {#1}% \ifxintverbose\xintMessage {xintexpr}{Info}% {\XINT_tmpa\space \ifxintglobaldefs globally \fi restored to its earlier status, if any.}% \fi }% % \end{macrocode} % \subsubsection{Checking (without expansion) that a symbolic expression % contains correctly nested parentheses} % %\begin{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. Call it as: % % \XINT_isbalanced_a \relax #1(\xint_bye)\xint_bye % % This is legacy f-expandable code not using \expanded even at 1.4. %\end{lverb} % \begin{macrocode} \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} %\begin{lverb} % if #2 is not \xint_bye, a ) was found, but there was no (. Hence error -> -1 %\end{lverb} % \begin{macrocode} \def\XINT_isbalanced_error #1)\xint_bye {\xint_c_mone}% % \end{macrocode} %\begin{lverb} % #2 was \xint_bye, was there a ) in original #1? %\end{lverb} % \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} %\begin{lverb} % #1 is \xint_bye, there was never ( nor ) in original #1, hence OK. %\end{lverb} % \begin{macrocode} \def\XINT_isbalanced_yes\xint_bye\XINT_isbalanced_d\xint_bye )\xint_bye {\xint_c_ }% % \end{macrocode} %\begin{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. %\end{lverb} % \begin{macrocode} \def\XINT_isbalanced_d #1)#2% {\xint_bye #2\XINT_isbalanced_no\xint_bye\XINT_isbalanced_a #1#2}% % \end{macrocode} %\begin{lverb} % #2 was \xint_bye, we did not find a closing ) in original #1. Error. %\end{lverb} % \begin{macrocode} \def\XINT_isbalanced_no\xint_bye #1\xint_bye\xint_bye {\xint_c_i }% % \end{macrocode} % \subsubsection{Fetching balanced expressions E1, E2 and a variable name Name from E1, Name=E2)} % % Multi-letter dummy variables added at |1.4|. % \begin{macrocode} \def\XINT_expr_fetch_E_comma_V_equal_E_a #1#2,% {% \ifcase\XINT_isbalanced_a \relax #1#2(\xint_bye)\xint_bye \expandafter\XINT_expr_fetch_E_comma_V_equal_E_c \or\expandafter\XINT_expr_fetch_E_comma_V_equal_E_b \else\expandafter\xintError:noopening \fi {#1#2},% }% \def\XINT_expr_fetch_E_comma_V_equal_E_b #1,% {\XINT_expr_fetch_E_comma_V_equal_E_a {#1,}}% \def\XINT_expr_fetch_E_comma_V_equal_E_c #1,#2#3=% {% \expandafter\XINT_expr_fetch_E_comma_V_equal_E_d\expandafter {\expanded{{\xint_zapspaces #2#3 \xint_gobble_i}}{#1}}{}% }% \def\XINT_expr_fetch_E_comma_V_equal_E_d #1#2#3)% {% \ifcase\XINT_isbalanced_a \relax #2#3(\xint_bye)\xint_bye \or\expandafter\XINT_expr_fetch_E_comma_V_equal_E_e \else\expandafter\xintError:noopening \fi {#1}{#2#3}% }% \def\XINT_expr_fetch_E_comma_V_equal_E_e #1#2% {\XINT_expr_fetch_E_comma_V_equal_E_d {#1}{#2)}}% % \end{macrocode} % \subsubsection{Fetching a balanced expression delimited by a semi-colon} % %\begin{lverb} % 1.4. For subsn() leaner syntax of nested substitutions. % % Will also serve to \xintdeffunc, to not have to hide inner semi-colons in % for example an iter() from \xintdeffunc. % % Adding brace removal protection for no serious reason, anyhow the xintexpr % parsers always removes braces when moving forward, but well. % % Trigger by \romannumeral\XINT_expr_fetch_to_semicolon upfront. %\end{lverb} % % \begin{macrocode} \def\XINT_expr_fetch_to_semicolon {\XINT_expr_fetch_to_semicolon_a {}\empty}% \def\XINT_expr_fetch_to_semicolon_a #1#2;% {% \ifcase\XINT_isbalanced_a \relax #1#2(\xint_bye)\xint_bye \xint_dothis{\expandafter\XINT_expr_fetch_to_semicolon_c}% \or\xint_dothis{\expandafter\XINT_expr_fetch_to_semicolon_b}% \else\expandafter\xintError:noopening \fi\xint_orthat{}\expandafter{#2}{#1}% }% \def\XINT_expr_fetch_to_semicolon_b #1#2{\XINT_expr_fetch_to_semicolon_a {#2#1;}\empty}% \def\XINT_expr_fetch_to_semicolon_c #1#2{\xint_c_{#2#1}}% % \end{macrocode} % \subsubsection{Low-level support for omit and abort keywords, the break() % function, the n++ construct and the semi-colon as used in the syntax of % seq(), add(), mul(), iter(), rseq(), iterr(), rrseq(), subsm(), subsn(), ndseq(), % ndmap()} %\begin{lverb} % There is some clever play simply based on setting suitable precedence % levels combined with special meanings given to op macros. % % The special !? internal operator is a helper for omit and abort keywords in % list generators. % % Prior to 1.4 support for +[, *[, ..., ]+, ]*, had some elements here. %\end{lverb} % \paragraph{The n++ construct} %\begin{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. %\end{lverb} % \begin{macrocode} \expandafter\def\csname XINT_expr_itself_++\endcsname {++}% \expandafter\def\csname XINT_expr_itself_++)\endcsname {++)}% \expandafter\let\csname XINT_expr_precedence_++)\endcsname \xint_c_i \xintFor #1 in {expr,flexpr,iiexpr} \do {% \expandafter\def\csname XINT_#1_op_++)\endcsname ##1##2\relax {\expandafter\XINT_expr_foundend \expanded{{+{\XINT:NEhook:f:one:from:one:direct\xintiCeil##1}}}% }% }% % \end{macrocode} % \paragraph{The \cshn{break()} function} %\begin{lverb} % break is a true function, the parsing via expansion of the enclosed % material proceeds via _oparen macros as with any other function. %\end{lverb} % \begin{macrocode} \catcode`? 3 \def\XINT_expr_func_break #1#2#3{#1#2{?#3}}% \catcode`? 11 \let\XINT_flexpr_func_break \XINT_expr_func_break \let\XINT_iiexpr_func_break \XINT_expr_func_break % \end{macrocode} % \paragraph{The \cshn{omit} and \cshn{abort} keywords} %\begin{lverb} % Comments are currently undergoing reconstruction. % % The mechanism is somewhat complex. The operator !? will fetch a dummy value % ! or ^ which is then recognized int the loops implementing the various seq % etc... construct using dummy variables and implement omit and abort. % % In May 2021 I realized that the January 2020 1.4 had broken omit and abort % if used inside a subs(). The definition %(\edef\XINT_expr_var_omit #1\relax !{1\string !?!\relax !}% %) % conflicted with the 1.4 refactoring of «subs» and similar things % which had replaced formerly clean-up macros (of ! and what's next, as in % now defunct % \def\XINT_expr_subx:_end #1!#2#3{#1} which was involved in subs mechanism, % and by the way would be incompatible with multi-letter dummy variables) by usage % of an \iffalse as in "\relax\iffalse\relax !" to delimite a sub-expression, which was % supposed to be clever (the "\relax !" being delimiter for dummy variables). % % This \iffalse from subs mechanism ended up being gobbled by omit/abort thus % inducing breakage. % % Grabbing \relax #2! would be a fix but looks a bit dangerous, as there can % be a subexpression after the omit or abort bringing its own \relax, although % this is very very unlikely. % % I considered to modify the dummy variables delimiter from \relax ! to % \xint_Bye ! for example but got afraid from the ramifications, as all % structures handling dummy variables would have needed refactoring. % % So finally things here remain unchanged and the refactoring to fix this % breakage was done in \XINT_allexpr_subsx (and also subsm). % Done at 1.4h. See \XINT_allexpr_subsx for comments. %\end{lverb} % % \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_itself_!? {!?}% \def\XINT_expr_op_!? #1#2\relax{\XINT_expr_foundend{#2}}% \let\XINT_iiexpr_op_!? \XINT_expr_op_!? \let\XINT_flexpr_op_!? \XINT_expr_op_!? \let\XINT_expr_precedence_!? \xint_c_iv % \end{macrocode} % \paragraph{The semi-colon} % %\begin{lverb} % Obsolete comments undergoing re-construction %\end{lverb} % % \begin{macrocode} \xintFor #1 in {expr,flexpr,iiexpr} \do {% \expandafter\def\csname XINT_#1_op_;\endcsname {\xint_c_i ;}% }% \expandafter\let\csname XINT_expr_precedence_;\endcsname\xint_c_i \expandafter\def\csname XINT_expr_itself_;)\endcsname {)}% \expandafter\let\csname XINT_expr_precedence_;)\endcsname\xint_c_i % \end{macrocode} % \subsubsection{Reserved dummy variables @, @1, @2, @3, @4, @@, @@(1), \dots, @@@, % @@@(1), \dots{} for recursions} %\begin{lverb} % Comments currently under reconstruction. % % 1.4 breaking change: @ and @1 behave differently and one can not use @ in % place of @1 in iterr() and rrseq(). Formerly @ and @1 had the same % definition. % % Brace stripping in \XINT_expr_func_@@ % is prevented by some ending 0 or other token see iterr() and rrseq() code. % % For the record, the ~ and ? have catcode 3 in this code. % %\end{lverb} % % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`* 11 }^^A % \begin{macrocode} \catcode`* 11 \def\XINT_expr_var_@ #1~#2{{#2}#1~{#2}}% \def\XINT_expr_var*_@ #1~#2{\XINT_expr_prec_tacit *{#2}(#1~{#2}}% \expandafter \def\csname XINT_expr_var_@1\endcsname #1~#2{{{#2}}#1~{#2}}% \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}}% \expandafter\def\csname XINT_expr_var*_@1\endcsname #1~#2% {\XINT_expr_prec_tacit *{{#2}}(#1~{#2}}% \expandafter\def\csname XINT_expr_var*_@2\endcsname #1~#2#3% {\XINT_expr_prec_tacit *{{#3}}(#1~{#2}{#3}}% \expandafter\def\csname XINT_expr_var*_@3\endcsname #1~#2#3#4% {\XINT_expr_prec_tacit *{{#4}}(#1~{#2}{#3}{#4}}% \expandafter\def\csname XINT_expr_var*_@4\endcsname #1~#2#3#4#5% {\XINT_expr_prec_tacit *{{#5}}(#1~{#2}{#3}{#4}{#5}}% \catcode`* 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters\FixInterMacrocodeVspace % \begin{macrocode} \catcode`? 3 \def\XINT_expr_func_@@ #1#2#3#4~#5?% {% \expandafter#1\expandafter#2\expandafter{\expandafter{% \romannumeral0\xintntheltnoexpand{\xintNum#3}{#5}}}#4~#5?% }% \def\XINT_expr_func_@@@ #1#2#3#4~#5~#6?% {% \expandafter#1\expandafter#2\expandafter{\expandafter{% \romannumeral0\xintntheltnoexpand{\xintNum#3}{#6}}}#4~#5~#6?% }% \def\XINT_expr_func_@@@@ #1#2#3#4~#5~#6~#7?% {% \expandafter#1\expandafter#2\expandafter{\expandafter{% \romannumeral0\xintntheltnoexpand{\xintNum#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\expandafter{\expandafter{% \romannumeral0\xintntheltnoexpand{\xint_firstofone#3}{#5}}}#4~#5?% }% \def\XINT_iiexpr_func_@@@ #1#2#3#4~#5~#6?% {% \expandafter#1\expandafter#2\expandafter{\expandafter{% \romannumeral0\xintntheltnoexpand{\xint_firstofone#3}{#6}}}#4~#5~#6?% }% \def\XINT_iiexpr_func_@@@@ #1#2#3#4~#5~#6~#7?% {% \expandafter#1\expandafter#2\expandafter{\expandafter{% \romannumeral0\xintntheltnoexpand{\xint_firstofone#3}{#7}}}#4~#5~#6~#7?% }% \catcode`? 11 % \end{macrocode} % \subsection{Pseudo-functions involving dummy variables and generating scalars or sequences} % \localtableofcontents % % \subsubsection{Comments} %\begin{lverb} % Comments added 2020/01/16. % % The mechanism for «seq» is the following. When the parser encounters «seq», % which means it parsed these letters and encountered (from expansion) an % opening parenthesis, the \XINT_expr_func mechanism triggers the «`» operator % which realizes that «seq» is a pseudo-function (there is no _func_seq) and % thus spans the \XINT_expr_onliteral_seq macro (currently this means however % that the knowledge of which parser we are in is lost, see comments of % \XINT_expr_op_` code). The latter will use delimited macros and parenthesis % check to fetch (without any expansion), the symbolic expression ExprSeq to % evaluate, the Name (now possibly multi-letter) of the variable and the % expression ExprValues to evaluate which will give the values to assign to % the dummy variable Name. It then positions upstream ExprValues suitably % terminated (see next) and after it {{Name}{ExprSeq}}. Then it inserts a % second call to the «`» operator with now «seqx» as argument hence % the appropriate «{,fl,ii}expr_func_seqx» macros gets executed. The general % way function macros work is that first all their arguments are evaluated via % a call not to \xintbare{,float,ii}eval but to the suitable % \XINT_{expr,flexpr,iiexpr}_oparen core macro which does almost same excepts % it expects a final closing parenthesis (of course allowing nested % parenthesis in-between) and stops there. Here, this closing parenthesis got positioned % deliberately with a \relax after it, so the parser, which always after % having gathered a value looks ahead to find the next operator, thinks it has % hit the end of the expression and as result inserts a \xint_c_ (i.e. \z@) % token for precedence level and a dummy \relax token (place-holder for a % non-existing operator). Generally speaking «func_foo» macros expect to % be executed with three parameters #1#2#3, #1 = precedence, #2 = operator, #3 % = values (call it «args») i.e. the fully evaluated list of all its % arguments. The special «func_seqx» and cousins know that the first two % tokens are trash and they now proceed forward, having thus lying before them % upstream the values to loop over, now fully evaluated, and % {{Name}{ExprSeq}}. It then positions appropriately ExprSeq inside a % sub-expression and after it, following suitable delimiter, Name and the % evaluated values to assign to Name. % % Dummy variables are essentially simply delimited macros where the delimiter % is the variable name preceded by a \relax token and a catcode 11 exclamation % point. Thus the various «subsx», «seqx», «iterx» position the tokens % appropriately and launch suitable loops. % % All of this nests well, inner «seq»'s (or more often in practice «subs»'s) % being allowed to refer to the dummy variables used by outer «seq»'s because % the outer «seq»'s have the values to assign to their variables evaluated % first and their ExprSeq evaluated last. For inner dummy variables to be able % to refer to outer dummy variables the author must be careful of course to % not use in the implementation braces { and } which would break dummy % variables to fetch values beyond the closing brace. % % The above «seq» mechanism was done around June 15-25th 2014 at the time of % the transition from 1.09n to 1.1 but already in October 2014 I made a note % that I had a hard time to understand it again: % % « [START OF YEAR 2014 COMMENTS] % % 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_fetch_E_comma_V_equal_E_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_ii^v 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. % % [END OF YEAR 2014 OLD COMMENTS]» % % On Jeudi 16 janvier 2020 à 15:13:32 I finally did the documentation as % above. % % The case of «iter», «rseq», «iterr», «rrseq» differs slightly because the % initial values need evaluation. This is done by genuine functions % \XINT_<parser>_func_iter etc... (there was no \XINT_<parser>_func_seq). The % trick is via the semi-colon ; which is a genuine operator having the % precedence of a closing parenthesis and whose action is only to stop % expansion. Thus this first step of gathering the initial values is done as % part of the reguler expansion job of the parser not using delimited macros % and the ; can be hidden in braces {;} because the three parsers when moving % forward remove one level of braces always. Thus % \XINT_<parser>_func_seq simply hand over to \XINT_allexpr_iter which will % then trigger the fetching without expansion of ExprIter, Name=ExprValues as % described previously for «seq». % % With 1.4, multi-letter names for dummy variables are allowed. % % Also there is the additional 1.4 ambition to make the whole thing parsable % by \xintNewExpr/\xintdeffunc. This is done by checking if all is numerical, % because the omit, abort and break() mechanisms have no translation into % macros, and the only solution for symbolic material is to simply keep it as % is, so that expansion will again activate the xintexpr parsers. At 1.4 this % approach is fine although the initial goals of \xintNewExpr/\xintdeffunc was % to completely replace the parsers (whose storage method hit the string pool % formerly) by macros. Now that 1.4 does not impact the string pool we can % make \xintdeffunc much more powerful but it will not be a construct using % only xintfrac macros, it will still be partially the \xintexpr etc... % parsers in such cases. %\end{lverb} % %\begin{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. % % Refactored at 1.4 using \expanded rather than \csname. % % And support for multi-letter variables, which means function declarations % can now use multi-letter variables ! %\end{lverb} % \subsubsection{\cshn{subs()}: substitution of one variable} % \begin{macrocode} \def\XINT_expr_onliteral_subs {% \expandafter\XINT_allexpr_subs_f \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_allexpr_subs_f #1#2{\xint_c_ii^v `{subsx}#2)\relax #1}% \def\XINT_expr_func_subsx #1#2{\XINT_allexpr_subsx \xintbareeval }% \def\XINT_flexpr_func_subsx #1#2{\XINT_allexpr_subsx \xintbarefloateval}% \def\XINT_iiexpr_func_subsx #1#2{\XINT_allexpr_subsx \xintbareiieval }% % \end{macrocode} %\begin{lverb} % #2 is the value to assign to the dummy variable % #3 is the dummy variable name (possibly multi-letter), #4 is the expression % to evaluate % % 1.4 was doing something clever to get rid of the ! and tokens following it, % via an \iffalse...\fi which erased them and propagated the expansion to % trigger the getopt: % %(\expanded\bgroup\romannumeral0#1#4\relax \iffalse\relax !#3{#2}{\fi\expandafter} %) % % But sadly, with a delay of more than one year later (right after having % released 1.4g) I realized that this had broken omit and abort if inside a % subs. As omit and abort would clean all up to \relax !, this meant here % swallowing in particular the above \iffalse, leaving a dangling \fi. I had % the files which show this bug already at time of 1.4 release but did not % compile them, and they were not included in my test suite. % % I hesitated with modifying the delimiter from "\relax !<varname>" (catcode % 11 !) to "\relax \xint_Bye<varname>" for the dummy variables which would % have allowed some trickery using \xint_Bye...\xint_bye clean-up but got % afraid from the breakage potential of such refactoring with many induced % changes. % % A variant like this: %( \def\XINT_allexpr_subsx #1#2#3#4% %: {% %: \expandafter\XINT_expr_clean_and_put_op_first %: \expanded %: {\romannumeral0#1#4\relax !#3{#2}\xint:\expandafter}\romannumeral`$&$&\XINT_expr_getop %: }% %: \def\XINT_expr_clean_and_put_op_first #1#2\xint:#3#4{#3#4{#1}}% %) % breaks nesting: the braces make variables encountered in #4 unable to % match their definition. This would work: % %( \def\XINT_allexpr_subsx #1#2#3#4% %: {% %: \expandafter\XINT_allexpr_subsx_clean\romannumeral0#1#4\relax !#3{#2}\xint: %: }% %: \def\XINT_allexpr_subsx_clean #1#2\xint: %: {% %: \expandafter\XINT_expr_put_op_first %: \expanded{\unexpanded{{#1}}\expandafter}\romannumeral`$&$&@\XINT_expr_getop %: }% %) % (not tested). % % But in the end I decided to simply fix the first envisioned code above. % This accepts expansion of supposedly inert #3{#2}. There is again the % \iffalse but it is moved to the right. This change limits possibly hacky % future developments. Done at 1.4h (2021/01/27). % % No need for the \expandafter's from \XINT_expr_put_op_first in % \XINT_expr_clean_and_put_op_first. %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_subsx #1#2#3#4% {% \expandafter\XINT_expr_clean_and_put_op_first \expanded \bgroup\romannumeral0#1#4\relax !#3{#2}\xint:\iffalse{\fi\expandafter}% \romannumeral`&&@\XINT_expr_getop }% \def\XINT_expr_clean_and_put_op_first #1#2\xint:#3#4{#3#4{#1}}% % \end{macrocode} % \subsubsection{\cshn{subsm()}: simultaneous independent substitutions} %\begin{lverb} % New with 1.4. Globally the var1=expr1; var2=expr2; var2=expr3;... % part can arise from expansion, except that once a semi-colon has been found % (from expansion) the varK= thing following it must be there. And as for % subs() the final parenthesis must be there from the start. % %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_subsm {% \expandafter\XINT_allexpr_subsm_f \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_allexpr_subsm_f #1#2{\xint_c_ii^v `{subsmx}#2)\relax #1}% \def\XINT_expr_func_subsmx {% \expandafter\XINT_allexpr_subsmx\expandafter\xintbareeval \expanded\bgroup{\iffalse}\fi\XINT_allexpr_subsm_A\XINT_expr_oparen }% \def\XINT_flexpr_func_subsmx {% \expandafter\XINT_allexpr_subsmx\expandafter\xintbarefloateval \expanded\bgroup{\iffalse}\fi\XINT_allexpr_subsm_A\XINT_flexpr_oparen }% \def\XINT_iiexpr_func_subsmx {% \expandafter\XINT_allexpr_subsmx\expandafter\xintbareiieval \expanded\bgroup{\iffalse}\fi\XINT_allexpr_subsm_A\XINT_iiexpr_oparen }% \def\XINT_allexpr_subsm_A #1#2#3% {% \ifx#2\xint_c_ \expandafter\XINT_allexpr_subsm_done \else \expandafter\XINT_allexpr_subsm_B \fi #1% }% \def\XINT_allexpr_subsm_B #1#2#3#4=% {% {#2}\relax !\xint_zapspaces#3#4 \xint_gobble_i \expandafter\XINT_allexpr_subsm_A\expandafter#1\romannumeral`&&@#1% }% % \end{macrocode} %\begin{lverb} %( #1 = \xintbareeval, or \xintbarefloateval or \xintbareiieval %: #2 = evaluation of last variable assignment %) %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_subsm_done #1#2{{#2}\iffalse{{\fi}}}% % \end{macrocode} %\begin{lverb} %( #1 = \xintbareeval or \xintbarefloateval or \xintbareiieval %: #2 = {value1}\relax !var2{value2}....\relax !varN{valueN} (value's may be oples) %: #3 = {var1} %: #4 = the expression to evaluate %) % Refactored at 1.4h as for \XINT_allexpr_subsx, see comments there related % to the omit/abort conundrum. %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_subsmx #1#2#3#4% {% \expandafter\XINT_expr_clean_and_put_op_first \expanded \bgroup\romannumeral0#1#4\relax !#3#2\xint:\iffalse{\fi\expandafter}% \romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} % \subsubsection{\cshn{subsn()}: leaner syntax for nesting (possibly dependent) substitutions} %\begin{lverb} % New with 1.4. 2020/01/24 % %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_subsn {% \expandafter\XINT_allexpr_subsn_f \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_allexpr_subsn_f #1{\XINT_allexpr_subsn_g #1}% % \end{macrocode} %\begin{lverb} %( #1 = Name1 %: #2 = Expression in all variables which is to evaluate %: #3 = all the stuff after Name1 = and up to final parenthesis %) % % This one needed no reactoring at 1.4h to fix the omit/abort problem, as % there was no \iffalse..\fi clean-up: the clean-up is done directly via % \XINT_allexpr_subsnx_J. % % I only added usage of \XINT_expr_put_op_first_noexpand. There may be other % locations where it could be used, but I can't afford now reviewing % usage. For next release after 1.4h bugfix. %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_subsn_g #1#2#3% {% \expandafter\XINT_allexpr_subsn_h \expanded\bgroup{\iffalse}\fi\expandafter\XINT_allexpr_subsn_B \romannumeral\XINT_expr_fetch_to_semicolon #1=#3;\hbox=;;^{#2}% }% \def\XINT_allexpr_subsn_B #1{\XINT_allexpr_subsn_C #1\vbox}% \def\XINT_allexpr_subsn_C #1#2=#3\vbox {% \ifx\hbox#1\iffalse{{\fi}\expandafter}\else {{\xint_zapspaces #1#2 \xint_gobble_i}};\unexpanded{{{#3}}}% \expandafter\XINT_allexpr_subsn_B \romannumeral\expandafter\XINT_expr_fetch_to_semicolon\fi }% \def\XINT_allexpr_subsn_h {% \xint_c_ii^v `{subsnx}\romannumeral0\xintreverseorder }% \def\XINT_expr_func_subsnx #1#2#3#4#5;#6% {% \xint_gob_til_^ #6\XINT_allexpr_subsnx_H ^% \expandafter\XINT_allexpr_subsnx\expandafter \xintbareeval\romannumeral0\xintbareeval #5\relax !#4{#3}\xintundefined {\relax !#4{#3}\relax !#6}% }% \def\XINT_iiexpr_func_subsnx #1#2#3#4#5;#6% {% \xint_gob_til_^ #6\XINT_allexpr_subsnx_H ^% \expandafter\XINT_allexpr_subsnx\expandafter \xintbareiieval\romannumeral0\xintbareiieval #5\relax !#4{#3}\xintundefined {\relax !#4{#3}\relax !#6}% }% \def\XINT_flexpr_func_subsnx #1#2#3#4#5;#6% {% \xint_gob_til_^ #6\XINT_allexpr_subsnx_H ^% \expandafter\XINT_allexpr_subsnx\expandafter \xintbarefloateval\romannumeral0\xintbarefloateval #5\relax !#4{#3}\xintundefined {\relax !#4{#3}\relax !#6}% }% \def\XINT_allexpr_subsnx #1#2!#3\xintundefined#4#5;#6% {% \xint_gob_til_^ #6\XINT_allexpr_subsnx_I ^% \expandafter\XINT_allexpr_subsnx\expandafter #1\romannumeral0#1#5\relax !#4{#2}\xintundefined {\relax !#4{#2}\relax !#6}% }% \def\XINT_allexpr_subsnx_H ^#1\romannumeral0#2#3!#4\xintundefined #5#6% {% \expandafter\XINT_allexpr_subsnx_J\romannumeral0#2#6#5% }% \def\XINT_allexpr_subsnx_I ^#1\romannumeral0#2#3\xintundefined #4#5% {% \expandafter\XINT_allexpr_subsnx_J\romannumeral0#2#5#4% }% \def\XINT_allexpr_subsnx_J #1#2^% {% \expandafter\XINT_expr_put_op_first_noexpand \expanded{\unexpanded{{#1}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT_expr_put_op_first_noexpand#1#2#3{#2#3{#1}}% % \end{macrocode} % \subsubsection{\cshn{seq()}: sequences from assigning values to a % dummy variable} %\begin{lverb} % In seq_f, the #2 is the ExprValues expression which needs evaluation to % provide the values to the dummy variable and #1 is {Name}{ExprSeq} % where Name is the name of dummy variable and {ExprSeq} the expression % which will have to be evaluated. %\end{lverb} % % % \begin{macrocode} \def\XINT_allexpr_seq_f #1#2{\xint_c_ii^v `{seqx}#2)\relax #1}% \def\XINT_expr_onliteral_seq {\expandafter\XINT_allexpr_seq_f\romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}}% \def\XINT_expr_func_seqx #1#2{\XINT:NEhook:seqx\XINT_allexpr_seqx\xintbareeval }% \def\XINT_flexpr_func_seqx #1#2{\XINT:NEhook:seqx\XINT_allexpr_seqx\xintbarefloateval}% \def\XINT_iiexpr_func_seqx #1#2{\XINT:NEhook:seqx\XINT_allexpr_seqx\xintbareiieval }% \def\XINT_allexpr_seqx #1#2#3#4% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup {\iffalse}\fi\XINT_expr_seq:_b {#1#4\relax !#3}#2^% \XINT_expr_cb_and_getop }% \def\XINT_expr_cb_and_getop{\iffalse{\fi\expandafter}\romannumeral`&&@\XINT_expr_getop}% % \end{macrocode} % %\begin{lverb} % Comments undergoing reconstruction. %\end{lverb} % \begin{macrocode} \catcode`? 3 \def\XINT_expr_seq:_b #1#2% {% \ifx +#2\xint_dothis\XINT_expr_seq:_Ca\fi \ifx !#2!\xint_dothis\XINT_expr_seq:_noop\fi \ifx ^#2\xint_dothis\XINT_expr_seq:_end\fi \xint_orthat{\XINT_expr_seq:_c}{#2}{#1}% }% \def\XINT_expr_seq:_noop #1{\XINT_expr_seq:_b }% \def\XINT_expr_seq:_end #1#2{\iffalse{\fi}}% \def\XINT_expr_seq:_c #1#2{\expandafter\XINT_expr_seq:_d\romannumeral0#2{{#1}}{#2}}% \def\XINT_expr_seq:_d #1{\ifx ^#1\xint_dothis\XINT_expr_seq:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_seq:_break\fi \ifx !#1\xint_dothis\XINT_expr_seq:_omit\fi \xint_orthat{\XINT_expr_seq:_goon {#1}}}% \def\XINT_expr_seq:_abort #1!#2^{\iffalse{\fi}}% \def\XINT_expr_seq:_break #1!#2^{#1\iffalse{\fi}}% \def\XINT_expr_seq:_omit #1!#2#{\expandafter\XINT_expr_seq:_b\xint_gobble_i}% \def\XINT_expr_seq:_goon #1!#2#{#1\expandafter\XINT_expr_seq:_b\xint_gobble_i}% \def\XINT_expr_seq:_Ca #1#2#3{\XINT_expr_seq:_Cc#3.{#2}}% \def\XINT_expr_seq:_Cb #1{\expandafter\XINT_expr_seq:_Cc\the\numexpr#1+\xint_c_i.}% \def\XINT_expr_seq:_Cc #1.#2{\expandafter\XINT_expr_seq:_D\romannumeral0#2{{#1}}{#1}{#2}}% \def\XINT_expr_seq:_D #1{\ifx ^#1\xint_dothis\XINT_expr_seq:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_seq:_break\fi \ifx !#1\xint_dothis\XINT_expr_seq:_Omit\fi \xint_orthat{\XINT_expr_seq:_Goon {#1}}}% \def\XINT_expr_seq:_Omit #1!#2#{\expandafter\XINT_expr_seq:_Cb\xint_gobble_i}% \def\XINT_expr_seq:_Goon #1!#2#{#1\expandafter\XINT_expr_seq:_Cb\xint_gobble_i}% % \end{macrocode} % \subsubsection{\cshn{iter()}} % %\begin{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. % % To understand the tokens which are presented to \XINT_allexpr_iter it is % needed to check elsewhere in the source code how the ; hack is done. % % The #2 in \XINT_allexpr_iter is \xint_c_i from the ; hack. Formerly (xint < % 1.4) there was no such token. The change is motivated to using ; also in % subsm() syntax. % %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_iter {\XINT_allexpr_iter \xintbareeval }% \def\XINT_flexpr_func_iter {\XINT_allexpr_iter \xintbarefloateval }% \def\XINT_iiexpr_func_iter {\XINT_allexpr_iter \xintbareiieval }% \def\XINT_allexpr_iter #1#2#3#4% {% \expandafter\XINT_expr_iterx \expandafter#1\expanded{\unexpanded{{#4}}\expandafter}% \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_expr_iterx #1#2#3#4% {% \XINT:NEhook:iter\XINT_expr_itery\romannumeral0#1(#4)\relax {#2}#3#1% }% \def\XINT_expr_itery #1#2#3#4#5% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup {\iffalse}\fi \XINT_expr_iter:_b {#5#4\relax !#3}#1^~{#2}\XINT_expr_cb_and_getop }% \def\XINT_expr_iter:_b #1#2% {% \ifx +#2\xint_dothis\XINT_expr_iter:_Ca\fi \ifx !#2!\xint_dothis\XINT_expr_iter:_noop\fi \ifx ^#2\xint_dothis\XINT_expr_iter:_end\fi \xint_orthat{\XINT_expr_iter:_c}{#2}{#1}% }% \def\XINT_expr_iter:_noop #1{\XINT_expr_iter:_b }% \def\XINT_expr_iter:_end #1#2~#3{#3\iffalse{\fi}}% \def\XINT_expr_iter:_c #1#2{\expandafter\XINT_expr_iter:_d\romannumeral0#2{{#1}}{#2}}% \def\XINT_expr_iter:_d #1{\ifx ^#1\xint_dothis\XINT_expr_iter:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_iter:_break\fi \ifx !#1\xint_dothis\XINT_expr_iter:_omit\fi \xint_orthat{\XINT_expr_iter:_goon {#1}}}% \def\XINT_expr_iter:_abort #1!#2^~#3{#3\iffalse{\fi}}% \def\XINT_expr_iter:_break #1!#2^~#3{#1\iffalse{\fi}}% \def\XINT_expr_iter:_omit #1!#2#{\expandafter\XINT_expr_iter:_b\xint_gobble_i}% \def\XINT_expr_iter:_goon #1!#2#{\XINT_expr_iter:_goon_a {#1}}% \def\XINT_expr_iter:_goon_a #1#2#3~#4{\XINT_expr_iter:_b #3~{#1}}% \def\XINT_expr_iter:_Ca #1#2#3{\XINT_expr_iter:_Cc#3.{#2}}% \def\XINT_expr_iter:_Cb #1{\expandafter\XINT_expr_iter:_Cc\the\numexpr#1+\xint_c_i.}% \def\XINT_expr_iter:_Cc #1.#2{\expandafter\XINT_expr_iter:_D\romannumeral0#2{{#1}}{#1}{#2}}% \def\XINT_expr_iter:_D #1{\ifx ^#1\xint_dothis\XINT_expr_iter:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_iter:_break\fi \ifx !#1\xint_dothis\XINT_expr_iter:_Omit\fi \xint_orthat{\XINT_expr_iter:_Goon {#1}}}% \def\XINT_expr_iter:_Omit #1!#2#{\expandafter\XINT_expr_iter:_Cb\xint_gobble_i}% \def\XINT_expr_iter:_Goon #1!#2#{\XINT_expr_iter:_Goon_a {#1}}% \def\XINT_expr_iter:_Goon_a #1#2#3~#4{\XINT_expr_iter:_Cb #3~{#1}}% % \end{macrocode} % \subsubsection{\cshn{add()}, \cshn{mul()}} %\begin{lverb} % Comments under reconstruction. % % These were a bit anomalous as they did not implement omit and abort keyword % and the break() function (and per force then neither the n++ syntax). % % At 1.4 they are simply mapped to using adequately % iter(). Thus, there is small loss in efficiency, but supporting omit, abort % and break is important. Using dedicated macros here would have caused also % slight efficiency drop. Simpler to remove the old approach. %\end{lverb} % % \begin{macrocode} \def\XINT_expr_onliteral_add {\expandafter\XINT_allexpr_add_f\romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}}% \def\XINT_allexpr_add_f #1#2{\xint_c_ii^v `{opx}#2)\relax #1{+}{0}}% \def\XINT_expr_onliteral_mul {\expandafter\XINT_allexpr_mul_f\romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}}% \def\XINT_allexpr_mul_f #1#2{\xint_c_ii^v `{opx}#2)\relax #1{*}{1}}% \def\XINT_expr_func_opx {\XINT:NEhook:opx \XINT_allexpr_opx \xintbareeval }% \def\XINT_flexpr_func_opx {\XINT:NEhook:opx \XINT_allexpr_opx \xintbarefloateval}% \def\XINT_iiexpr_func_opx {\XINT:NEhook:opx \XINT_allexpr_opx \xintbareiieval }% % \end{macrocode} %\begin{lverb} % 1.4a In case of usage of omit (did I not test it? obviously % I didn't as neither omit nor abort could work; and break neither), % 1.4 code using (#6) syntax caused a % (somewhat misleading) «missing )» error message which originated in the % #6. This is non-obvious problem (perhaps explained why prior to 1.4 I had % not added support for omit and break() to add() and mul()... % % Allowing () is not enough as it would have to be 0 or 1 depending on % whether we are using add() or mul(). Hence the somewhat complicated % detour (relying on precise way var_omit and var_abort work) via % \XINT_allexpr_opx_ifnotomitted. % % \break() has special meaning here as it is used as last operand, not as last % value. The code is very unsatisfactory and inefficient but this is hotfix % for 1.4a. %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_opx #1#2#3#4#5#6#7#8% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup {\iffalse}\fi \XINT_expr_iter:_b {#1% \expandafter\XINT_allexpr_opx_ifnotomitted \romannumeral0#1#6\relax#7@\relax !#5}#4^~{{#8}}\XINT_expr_cb_and_getop }% \def\XINT_allexpr_opx_ifnotomitted #1% {% \ifx !#1\xint_dothis{@\relax}\fi \ifx ^#1\xint_dothis{\XINTfstop. ^\relax}\fi \if ?\xintFirstItem{#1}\xint_dothis{\XINT_allexpr_opx_break{#1}}\fi \xint_orthat{\XINTfstop.{#1}}% }% \def\XINT_allexpr_opx_break #1#2\relax {% break(\expandafter\XINTfstop\expandafter.\expandafter{\xint_gobble_i#1}#2)\relax }% % \end{macrocode} % \subsubsection{\cshn{rseq()}} % %\begin{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 (and leaving a \xint_c_i left-over token since 1.4). 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. %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_rseq {\XINT_allexpr_rseq \xintbareeval }% \def\XINT_flexpr_func_rseq {\XINT_allexpr_rseq \xintbarefloateval }% \def\XINT_iiexpr_func_rseq {\XINT_allexpr_rseq \xintbareiieval }% \def\XINT_allexpr_rseq #1#2#3#4% {% \expandafter\XINT_expr_rseqx \expandafter #1\expanded{\unexpanded{{#4}}\expandafter}% \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_expr_rseqx #1#2#3#4% {% \XINT:NEhook:rseq \XINT_expr_rseqy\romannumeral0#1(#4)\relax {#2}#3#1% }% \def\XINT_expr_rseqy #1#2#3#4#5% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup {\iffalse}\fi #2% \XINT_expr_rseq:_b {#5#4\relax !#3}#1^~{#2}\XINT_expr_cb_and_getop }% \def\XINT_expr_rseq:_b #1#2% {% \ifx +#2\xint_dothis\XINT_expr_rseq:_Ca\fi \ifx !#2!\xint_dothis\XINT_expr_rseq:_noop\fi \ifx ^#2\xint_dothis\XINT_expr_rseq:_end\fi \xint_orthat{\XINT_expr_rseq:_c}{#2}{#1}% }% \def\XINT_expr_rseq:_noop #1{\XINT_expr_rseq:_b }% \def\XINT_expr_rseq:_end #1#2~#3{\iffalse{\fi}}% \def\XINT_expr_rseq:_c #1#2{\expandafter\XINT_expr_rseq:_d\romannumeral0#2{{#1}}{#2}}% \def\XINT_expr_rseq:_d #1{\ifx ^#1\xint_dothis\XINT_expr_rseq:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_rseq:_break\fi \ifx !#1\xint_dothis\XINT_expr_rseq:_omit\fi \xint_orthat{\XINT_expr_rseq:_goon {#1}}}% \def\XINT_expr_rseq:_abort #1!#2^~#3{\iffalse{\fi}}% \def\XINT_expr_rseq:_break #1!#2^~#3{#1\iffalse{\fi}}% \def\XINT_expr_rseq:_omit #1!#2#{\expandafter\XINT_expr_rseq:_b\xint_gobble_i}% \def\XINT_expr_rseq:_goon #1!#2#{\XINT_expr_rseq:_goon_a {#1}}% \def\XINT_expr_rseq:_goon_a #1#2#3~#4{#1\XINT_expr_rseq:_b #3~{#1}}% \def\XINT_expr_rseq:_Ca #1#2#3{\XINT_expr_rseq:_Cc#3.{#2}}% \def\XINT_expr_rseq:_Cb #1{\expandafter\XINT_expr_rseq:_Cc\the\numexpr#1+\xint_c_i.}% \def\XINT_expr_rseq:_Cc #1.#2{\expandafter\XINT_expr_rseq:_D\romannumeral0#2{{#1}}{#1}{#2}}% \def\XINT_expr_rseq:_D #1{\ifx ^#1\xint_dothis\XINT_expr_rseq:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_rseq:_break\fi \ifx !#1\xint_dothis\XINT_expr_rseq:_Omit\fi \xint_orthat{\XINT_expr_rseq:_Goon {#1}}}% \def\XINT_expr_rseq:_Omit #1!#2#{\expandafter\XINT_expr_rseq:_Cb\xint_gobble_i}% \def\XINT_expr_rseq:_Goon #1!#2#{\XINT_expr_rseq:_Goon_a {#1}}% \def\XINT_expr_rseq:_Goon_a #1#2#3~#4{#1\XINT_expr_rseq:_Cb #3~{#1}}% % \end{macrocode} % \subsubsection{\cshn{iterr()}} %\begin{lverb} % ATTENTION! at 1.4 the @ and @1 are not synonymous anymore. One *must* use % @1 in iterr() context. %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_iterr {\XINT_allexpr_iterr \xintbareeval }% \def\XINT_flexpr_func_iterr {\XINT_allexpr_iterr \xintbarefloateval }% \def\XINT_iiexpr_func_iterr {\XINT_allexpr_iterr \xintbareiieval }% \def\XINT_allexpr_iterr #1#2#3#4% {% \expandafter\XINT_expr_iterrx \expandafter #1\expanded{{\xintRevWithBraces{#4}}\expandafter}% \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_expr_iterrx #1#2#3#4% {% \XINT:NEhook:iterr\XINT_expr_iterry\romannumeral0#1(#4)\relax {#2}#3#1% }% \def\XINT_expr_iterry #1#2#3#4#5% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup {\iffalse}\fi \XINT_expr_iterr:_b {#5#4\relax !#3}#1^~#20?\XINT_expr_cb_and_getop }% \def\XINT_expr_iterr:_b #1#2% {% \ifx +#2\xint_dothis\XINT_expr_iterr:_Ca\fi \ifx !#2!\xint_dothis\XINT_expr_iterr:_noop\fi \ifx ^#2\xint_dothis\XINT_expr_iterr:_end\fi \xint_orthat{\XINT_expr_iterr:_c}{#2}{#1}% }% \def\XINT_expr_iterr:_noop #1{\XINT_expr_iterr:_b }% \def\XINT_expr_iterr:_end #1#2~#3#4?{{#3}\iffalse{\fi}}% \def\XINT_expr_iterr:_c #1#2{\expandafter\XINT_expr_iterr:_d\romannumeral0#2{{#1}}{#2}}% \def\XINT_expr_iterr:_d #1{\ifx ^#1\xint_dothis\XINT_expr_iterr:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_iterr:_break\fi \ifx !#1\xint_dothis\XINT_expr_iterr:_omit\fi \xint_orthat{\XINT_expr_iterr:_goon {#1}}}% \def\XINT_expr_iterr:_abort #1!#2^~#3?{\iffalse{\fi}}% \def\XINT_expr_iterr:_break #1!#2^~#3?{#1\iffalse{\fi}}% \def\XINT_expr_iterr:_omit #1!#2#{\expandafter\XINT_expr_iterr:_b\xint_gobble_i}% \def\XINT_expr_iterr:_goon #1!#2#{\XINT_expr_iterr:_goon_a{#1}}% \def\XINT_expr_iterr:_goon_a #1#2#3~#4?% {% \expandafter\XINT_expr_iterr:_b \expanded{\unexpanded{#3~}\xintTrim{-2}{#1#4}}0?% }% \def\XINT_expr_iterr:_Ca #1#2#3{\XINT_expr_iterr:_Cc#3.{#2}}% \def\XINT_expr_iterr:_Cb #1{\expandafter\XINT_expr_iterr:_Cc\the\numexpr#1+\xint_c_i.}% \def\XINT_expr_iterr:_Cc #1.#2% {\expandafter\XINT_expr_iterr:_D\romannumeral0#2{{#1}}{#1}{#2}}% \def\XINT_expr_iterr:_D #1{\ifx ^#1\xint_dothis\XINT_expr_iterr:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_iterr:_break\fi \ifx !#1\xint_dothis\XINT_expr_iterr:_Omit\fi \xint_orthat{\XINT_expr_iterr:_Goon {#1}}}% \def\XINT_expr_iterr:_Omit #1!#2#{\expandafter\XINT_expr_iterr:_Cb\xint_gooble_i}% \def\XINT_expr_iterr:_Goon #1!#2#{\XINT_expr_iterr:_Goon_a{#1}}% \def\XINT_expr_iterr:_Goon_a #1#2#3~#4?% {% \expandafter\XINT_expr_iterr:_Cb \expanded{\unexpanded{#3~}\xintTrim{-2}{#1#4}}0?% }% % \end{macrocode} % \subsubsection{\cshn{rrseq()}} % %\begin{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. #2 = \xint_c_i and #3 are left-over trash. %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_rrseq {\XINT_allexpr_rrseq \xintbareeval }% \def\XINT_flexpr_func_rrseq {\XINT_allexpr_rrseq \xintbarefloateval }% \def\XINT_iiexpr_func_rrseq {\XINT_allexpr_rrseq \xintbareiieval }% \def\XINT_allexpr_rrseq #1#2#3#4% {% \expandafter\XINT_expr_rrseqx\expandafter#1\expanded {\unexpanded{{#4}}{\xintRevWithBraces{#4}}\expandafter}% \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_expr_rrseqx #1#2#3#4#5% {% \XINT:NEhook:rrseq\XINT_expr_rrseqy\romannumeral0#1(#5)\relax {#2}{#3}#4#1% }% \def\XINT_expr_rrseqy #1#2#3#4#5#6% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup {\iffalse}\fi #2\XINT_expr_rrseq:_b {#6#5\relax !#4}#1^~#30?\XINT_expr_cb_and_getop }% \def\XINT_expr_rrseq:_b #1#2% {% \ifx +#2\xint_dothis\XINT_expr_rrseq:_Ca\fi \ifx !#2!\xint_dothis\XINT_expr_rrseq:_noop\fi \ifx ^#2\xint_dothis\XINT_expr_rrseq:_end\fi \xint_orthat{\XINT_expr_rrseq:_c}{#2}{#1}% }% \def\XINT_expr_rrseq:_noop #1{\XINT_expr_rrseq:_b }% \def\XINT_expr_rrseq:_end #1#2~#3?{\iffalse{\fi}}% \def\XINT_expr_rrseq:_c #1#2{\expandafter\XINT_expr_rrseq:_d\romannumeral0#2{{#1}}{#2}}% \def\XINT_expr_rrseq:_d #1{\ifx ^#1\xint_dothis\XINT_expr_rrseq:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_rrseq:_break\fi \ifx !#1\xint_dothis\XINT_expr_rrseq:_omit\fi \xint_orthat{\XINT_expr_rrseq:_goon {#1}}}% \def\XINT_expr_rrseq:_abort #1!#2^~#3?{\iffalse{\fi}}% \def\XINT_expr_rrseq:_break #1!#2^~#3?{#1\iffalse{\fi}}% \def\XINT_expr_rrseq:_omit #1!#2#{\expandafter\XINT_expr_rrseq:_b\xint_gobble_i}% \def\XINT_expr_rrseq:_goon #1!#2#{\XINT_expr_rrseq:_goon_a {#1}}% \def\XINT_expr_rrseq:_goon_a #1#2#3~#4?% {% #1\expandafter\XINT_expr_rrseq:_b\expanded{\unexpanded{#3~}\xintTrim{-2}{#1#4}}0?% }% \def\XINT_expr_rrseq:_Ca #1#2#3{\XINT_expr_rrseq:_Cc#3.{#2}}% \def\XINT_expr_rrseq:_Cb #1{\expandafter\XINT_expr_rrseq:_Cc\the\numexpr#1+\xint_c_i.}% \def\XINT_expr_rrseq:_Cc #1.#2% {\expandafter\XINT_expr_rrseq:_D\romannumeral0#2{{#1}}{#1}{#2}}% \def\XINT_expr_rrseq:_D #1{\ifx ^#1\xint_dothis\XINT_expr_rrseq:_abort\fi \ifx ?#1\xint_dothis\XINT_expr_rrseq:_break\fi \ifx !#1\xint_dothis\XINT_expr_rrseq:_Omit\fi \xint_orthat{\XINT_expr_rrseq:_Goon {#1}}}% \def\XINT_expr_rrseq:_Omit #1!#2#{\expandafter\XINT_expr_rrseq:_Cb\xint_gobble_i}% \def\XINT_expr_rrseq:_Goon #1!#2#{\XINT_expr_rrseq:_Goon_a {#1}}% \def\XINT_expr_rrseq:_Goon_a #1#2#3~#4?% {% #1\expandafter\XINT_expr_rrseq:_Cb\expanded{\unexpanded{#3~}\xintTrim{-2}{#1#4}}0?% }% \catcode`? 11 % \end{macrocode} % \subsection{Pseudo-functions related to N-dimensional hypercubic lists} % \subsubsection{\cshn{ndseq()}} %\begin{lverb} % New with 1.4. 2020/01/23. It is derived from subsm() but instead of % evaluating one expression according to one value per variable, it constructs % a nested bracketed seq... this means the expression is parsed each time ! % Anyway, proof of concept. Nota Bene : omit, abort, break() work ! %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_ndseq {% \expandafter\XINT_allexpr_ndseq_f \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% \def\XINT_allexpr_ndseq_f #1#2{\xint_c_ii^v `{ndseqx}#2)\relax #1}% \def\XINT_expr_func_ndseqx {% \expandafter\XINT_allexpr_ndseqx\expandafter\xintbareeval \expandafter{\romannumeral0\expandafter\xint_gobble_i\string}% \expandafter\xintrevwithbraces \expanded\bgroup{\iffalse}\fi\XINT_allexpr_ndseq_A\XINT_expr_oparen }% \def\XINT_flexpr_func_ndseqx {% \expandafter\XINT_allexpr_ndseqx\expandafter\xintbarefloateval \expandafter{\romannumeral0\expandafter\xint_gobble_i\string}% \expandafter\xintrevwithbraces \expanded\bgroup{\iffalse}\fi\XINT_allexpr_ndseq_A\XINT_flexpr_oparen }% \def\XINT_iiexpr_func_ndseqx {% \expandafter\XINT_allexpr_ndseqx\expandafter\xintbareiieval \expandafter{\romannumeral0\expandafter\xint_gobble_i\string}% \expandafter\xintrevwithbraces \expanded\bgroup{\iffalse}\fi\XINT_allexpr_ndseq_A\XINT_iiexpr_oparen }% \def\XINT_allexpr_ndseq_A #1#2#3% {% \ifx#2\xint_c_ \expandafter\XINT_allexpr_ndseq_C \else \expandafter\XINT_allexpr_ndseq_B \fi #1% }% \def\XINT_allexpr_ndseq_B #1#2#3#4=% {% {#2}{\xint_zapspaces#3#4 \xint_gobble_i}% \expandafter\XINT_allexpr_ndseq_A\expandafter#1\romannumeral`&&@#1% }% % \end{macrocode} %\begin{lverb} % #1 = \xintbareeval, or \xintbarefloateval or \xintbareiieval % #2 = values for last coordinate %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_ndseq_C #1#2{{#2}\iffalse{{{\fi}}}}% % \end{macrocode} %\begin{lverb} % #1 = \xintbareeval or \xintbarefloateval or \xintbareiieval % #2 = {valuesN}...{values2}{var2}{values1} % #3 = {var1} % #4 = the expression to evaluate %\end{lverb} % \begin{macrocode} \def\XINT_allexpr_ndseqx #1#2#3#4% {% \expandafter\XINT_expr_put_op_first \expanded \bgroup \romannumeral0#1\empty \expanded{\xintReplicate{\xintLength{{#3}#2}/2}{[seq(}% \unexpanded{#4}% \XINT_allexpr_ndseqx_a #2{#3}^^% }% \relax \iffalse{\fi\expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT_allexpr_ndseqx_a #1#2% {% \xint_gob_til_^ #1\XINT_allexpr_ndseqx_e ^% \unexpanded{,#2=\XINTfstop.{#1})]}\XINT_allexpr_ndseqx_a }% \def\XINT_allexpr_ndseqx_e ^#1\XINT_allexpr_ndseqx_a{}% % \end{macrocode} % \subsubsection{\cshn{ndmap()}} %\begin{lverb} % New with 1.4. 2020/01/24. %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_ndmap #1,{\xint_c_ii^v `{ndmapx}\XINTfstop.{#1};}% \def\XINT_expr_func_ndmapx #1#2#3% {% \expandafter\XINT_allexpr_ndmapx \csname XINT_expr_func_\xint_zapspaces #3 \xint_gobble_i\endcsname \XINT_expr_oparen }% \def\XINT_flexpr_func_ndmapx #1#2#3% {% \expandafter\XINT_allexpr_ndmapx \csname XINT_flexpr_func_\xint_zapspaces #3 \xint_gobble_i\endcsname \XINT_flexpr_oparen }% \def\XINT_iiexpr_func_ndmapx #1#2#3% {% \expandafter\XINT_allexpr_ndmapx \csname XINT_iiexpr_func_\xint_zapspaces #3 \xint_gobble_i\endcsname \XINT_iiexpr_oparen }% \def\XINT_allexpr_ndmapx #1#2% {% \expandafter\XINT_expr_put_op_first \expanded\bgroup{\iffalse}\fi \expanded {\noexpand\XINT:NEhook:x:ndmapx \noexpand\XINT_allexpr_ndmapx_a \noexpand#1{}\expandafter}% \expanded\bgroup\expandafter\XINT_allexpr_ndmap_A \expandafter#2\romannumeral`&&@#2% }% \def\XINT_allexpr_ndmap_A #1#2#3% {% \ifx#3;% \expandafter\XINT_allexpr_ndmap_B \else \xint_afterfi{\XINT_allexpr_ndmap_C#2#3}% \fi #1% }% \def\XINT_allexpr_ndmap_B #1#2% {% {#2}\expandafter\XINT_allexpr_ndmap_A\expandafter#1\romannumeral`&&@#1% }% \def\XINT_allexpr_ndmap_C #1#2#3#4% {% {#4}^\relax\iffalse{{{\fi}}}#1#2% }% \def\XINT_allexpr_ndmapx_a #1#2#3% {% \xint_gob_til_^ #3\XINT_allexpr_ndmapx_l ^% \XINT_allexpr_ndmapx_b #1{#2}{#3}% }% \def\XINT_allexpr_ndmapx_l ^#1\XINT_allexpr_ndmapx_b #2#3#4\relax {% #2\empty\xint_firstofone{#3}% }% \def\XINT_allexpr_ndmapx_b #1#2#3#4\relax {% {\iffalse}\fi\XINT_allexpr_ndmapx_c {#4\relax}#1{#2}#3^% }% \def\XINT_allexpr_ndmapx_c #1#2#3#4% {% \xint_gob_til_^ #4\XINT_allexpr_ndmapx_e ^% \XINT_allexpr_ndmapx_a #2{#3{#4}}#1% \XINT_allexpr_ndmapx_c {#1}#2{#3}% }% \def\XINT_allexpr_ndmapx_e ^#1\XINT_allexpr_ndmapx_c {\iffalse{\fi}\xint_gobble_iii}% % \end{macrocode} % \subsubsection{\cshn{ndfillraw()}} %\begin{lverb} % New with 1.4. 2020/01/24. J'hésite à autoriser un #1 quelconque, % ou plutôt à le wrapper dans un \xintbareval. Mais il faut alors distinguer % les trois. De toute façon les variables ne marcheraient pas donc j'hésite % à mettre un wrapper automatique. Mais ce n'est pas bien d'autoriser l'injection % de choses quelconques. % % Pour des choses comme ndfillraw(\xintRandomBit,[10,10]). % % Je n'aime pas le nom !. Le changer. ndconst? Surtout je n'aime pas % que dans le premier argument il faut rajouter explicitement si nécessaire % \xintiiexpr wrap. %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_ndfillraw #1,{\xint_c_ii^v `{ndfillrawx}\XINTfstop.{{#1}},}% \def\XINT_expr_func_ndfillrawx #1#2#3% {% \expandafter#1\expandafter#2\expanded{{{\XINT_allexpr_ndfillrawx_a #3}}}% }% \let\XINT_iiexpr_func_ndfillrawx\XINT_expr_func_ndfillrawx \let\XINT_flexpr_func_ndfillrawx\XINT_expr_func_ndfillrawx \def\XINT_allexpr_ndfillrawx_a #1#2% {% \expandafter\XINT_allexpr_ndfillrawx_b \romannumeral0\xintApply{\xintNum}{#2}^\relax {#1}% }% \def\XINT_allexpr_ndfillrawx_b #1#2\relax#3% {% \xint_gob_til_^ #1\XINT_allexpr_ndfillrawx_c ^% \xintReplicate{#1}{{\XINT_allexpr_ndfillrawx_b #2\relax {#3}}}% }% \def\XINT_allexpr_ndfillrawx_c ^\xintReplicate #1#2% {% \expandafter\XINT_allexpr_ndfillrawx_d\xint_firstofone #2% }% \def\XINT_allexpr_ndfillrawx_d\XINT_allexpr_ndfillrawx_b \relax #1{#1}% % \end{macrocode} % \subsection{Other pseudo-functions: \cshn{bool()}, \cshn{togl()}, \cshn{protect()}, % \cshn{qraw()}, \cshn{qint()}, \cshn{qfrac()}, \cshn{qfloat()}, \cshn{qrand()}, % \cshn{random()}, \cshn{rbit()}} % %\begin{lverb} % bool, togl and protect use delimited macros. They are not true % functions, they turn off the parser to gather their "variable". %\end{lverb} % % \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. % %\begin{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. %\end{lverb} % %\begin{lverb} % 1.3b. random(), qrand() % Function-like syntax but with no argument currently, so let's % use fast parsing which requires though the closing parenthesis to be % explicit. %\end{lverb} % %\begin{lverb} % Attention that qraw() % which pre-supposes knowledge of internal storage model is fragile % and may break at any release. % % 1.4 adds rbit(). Short for random bit. %\end{lverb} % \begin{macrocode} \def\XINT_expr_onliteral_bool #1)% {\expandafter\XINT_expr_put_op_first\expanded{{{\xintBool{#1}}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_togl #1)% {\expandafter\XINT_expr_put_op_first\expanded{{{\xintToggle{#1}}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_protect #1)% {\expandafter\XINT_expr_put_op_first\expanded{{{\detokenize{#1}}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_qint #1)% {\expandafter\XINT_expr_put_op_first\expanded{{{\xintiNum{#1}}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_qfrac #1)% {\expandafter\XINT_expr_put_op_first\expanded{{{\xintRaw{#1}}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_qfloat #1)% {\expandafter\XINT_expr_put_op_first\expanded{{{\XINTinFloatSdigits{#1}}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_qraw #1)% {\expandafter\XINT_expr_put_op_first\expanded{{#1}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_random #1)% {\expandafter\XINT_expr_put_op_first\expanded{{{\XINTinRandomFloatSdigits}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_qrand #1)% {\expandafter\XINT_expr_put_op_first\expanded{{{\XINTinRandomFloatSixteen}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% \def\XINT_expr_onliteral_rbit #1)% {\expandafter\XINT_expr_put_op_first\expanded{{{\xintRandBit}}\expandafter }\romannumeral`&&@\XINT_expr_getop}% % \end{macrocode} % \def\auxiliarymacro#1{ \noexpand\cshn{#1()}} % \edef\zzz{Regular built-in functions: \xintListWithSep{, }{\xintApply\auxiliarymacro % {{num}{reduce}{preduce} % {abs}{sgn}{frac}{floor}{ceil}{sqr} % {?}{!}{not}{odd}{even}{isint}{isone} % {factorial}{sqrt}{sqrtr} % {inv}{round}{trunc} % {float}{sfloat}{ilog10} % {divmod}{mod}{binomial}{pfactorial} % {randrange} % {iquo}{irem}{gcd}{lcm}{max}{min} % {`+`}{`*`} % {all}{any}{xor} % {len}{first}{last}{reversed} % {if}{ifint}{ifone}{ifsgn} % {nuple}{unpack}{flat}}} % and \noexpand\cshn{zip()}} % \expandafter\subsection\expandafter{\zzz} % \begin{macrocode} \def\XINT:expr:f: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:f:tacitzeroifone #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:expr:f:iitacitzeroifone #1#2#3!#4% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {#4{0}}{#4{#2}}{#1}% }% \def\XINT_expr_func_num #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintNum#3}}% }% \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\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintIrr#3}}% }% \let\XINT_flexpr_func_reduce\XINT_expr_func_reduce \def\XINT_expr_func_preduce #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintPIrr#3}}% }% \let\XINT_flexpr_func_preduce\XINT_expr_func_preduce \def\XINT_expr_func_abs #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintAbs#3}}% }% \let\XINT_flexpr_func_abs\XINT_expr_func_abs \def\XINT_iiexpr_func_abs #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiAbs#3}}% }% \def\XINT_expr_func_sgn #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintSgn#3}}% }% \let\XINT_flexpr_func_sgn\XINT_expr_func_sgn \def\XINT_iiexpr_func_sgn #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiSgn#3}}% }% \def\XINT_expr_func_frac #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintTFrac#3}}% }% \def\XINT_flexpr_func_frac #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINTinFloatFrac#3}}% }% % \end{macrocode} %\begin{lverb} % no \XINT_iiexpr_func_frac %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_floor #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintFloor#3}}% }% \let\XINT_flexpr_func_floor\XINT_expr_func_floor % \end{macrocode} %\begin{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. %\end{lverb} % \begin{macrocode} \def\XINT_iiexpr_func_floor #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiFloor#3}}% }% \def\XINT_expr_func_ceil #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintCeil#3}}% }% \let\XINT_flexpr_func_ceil\XINT_expr_func_ceil \def\XINT_iiexpr_func_ceil #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiCeil#3}}% }% \def\XINT_expr_func_sqr #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintSqr#3}}% }% \def\XINT_flexpr_func_sqr #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINTinFloatSqr#3}}% }% \def\XINT_iiexpr_func_sqr #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiSqr#3}}% }% \def\XINT_expr_func_? #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiIsNotZero#3}}% }% \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\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiIsZero#3}}% }% \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\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiIsZero#3}}% }% \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\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintOdd#3}}% }% \let\XINT_flexpr_func_odd\XINT_expr_func_odd \def\XINT_iiexpr_func_odd #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiOdd#3}}% }% \def\XINT_expr_func_even #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintEven#3}}% }% \let\XINT_flexpr_func_even\XINT_expr_func_even \def\XINT_iiexpr_func_even #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiEven#3}}% }% \def\XINT_expr_func_isint #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintIsInt#3}}% }% \def\XINT_flexpr_func_isint #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintFloatIsInt#3}}% }% \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\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintIsOne#3}}% }% \let\XINT_flexpr_func_isone\XINT_expr_func_isone \def\XINT_iiexpr_func_isone #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiIsOne#3}}% }% \def\XINT_expr_func_factorial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt #3,!\xintFac\XINTinFloatFac }}% }% \def\XINT_flexpr_func_factorial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt#3,!\XINTinFloatFacdigits\XINTinFloatFac }}% }% \def\XINT_iiexpr_func_factorial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiFac#3}}% }% \def\XINT_expr_func_sqrt #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt #3,!\XINTinFloatSqrtdigits\XINTinFloatSqrt }}% }% \let\XINT_flexpr_func_sqrt\XINT_expr_func_sqrt \def\XINT_iiexpr_func_sqrt #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiSqrt#3}}% }% \def\XINT_iiexpr_func_sqrtr #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiSqrtR#3}}% }% \def\XINT_expr_func_inv #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintInv#3}}% }% \def\XINT_flexpr_func_inv #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINTinFloatInv#3}}% }% \def\XINT_expr_func_round #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:tacitzeroifone:direct \XINT:expr:f:tacitzeroifone #3,!\xintiRound\xintRound }}% }% \let\XINT_flexpr_func_round\XINT_expr_func_round \def\XINT_iiexpr_func_round #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:iitacitzeroifone:direct \XINT:expr:f:iitacitzeroifone #3,!\xintiRound }}% }% \def\XINT_expr_func_trunc #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:tacitzeroifone:direct \XINT:expr:f:tacitzeroifone #3,!\xintiTrunc\xintTrunc }}% }% \let\XINT_flexpr_func_trunc\XINT_expr_func_trunc \def\XINT_iiexpr_func_trunc #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:iitacitzeroifone:direct \XINT:expr:f:iitacitzeroifone #3,!\xintiTrunc }}% }% % \end{macrocode} %\begin{lverb} % Hesitation at 1.3e about using \XINTinFloatSdigits and \XINTinFloatS. % Finally I add a sfloat() function. It helps for xinttrig.sty. %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_float #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt #3,!\XINTinFloatdigits\XINTinFloat }}% }% \let\XINT_flexpr_func_float\XINT_expr_func_float % \end{macrocode} %\begin{lverb} % float_() was added at 1.4, as a shortcut alias to float() skipping the check % for an optional second argument. This is useful to transfer function % definitions between \xintexpr and \xintfloatexpr contexts. % % % No need for a similar shortcut for sfloat() as currently used in % xinttrig.sty to go from float to expr: as it is used there as sfloat(x) with % dummy x, it sees there is no optional argument, contrarily to for example % float(\xintexpr...\relax) which has to allow for the inner expression to % expand to an ople with two items, so does not know in which branch it is at % time of definiion. % % % After some hesitation at 1.4e regarding guard digits mechanism the float_() % got renamed to float_dgt(), but then renamed back to float_() to avoid a % breaking change and having to document it. % % Nevertheless the documentation of 1.4e mentioned float_dgt()... but it was still % float_()... now changed into float_dgt() for real at 1.4f. % % 1.4f also adds private float_dgtormax and sfloat_dgtormax for matters of xinttrig. % %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_float_dgt #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINTinFloatdigits#3}}% }% \let\XINT_flexpr_func_float_dgt\XINT_expr_func_float_dgt % no \XINT_iiexpr_func_float_dgt \def\XINT_expr_func_float_dgtormax #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINTinFloatdigitsormax#3}}% }% \let\XINT_flexpr_func_float_dgtormax\XINT_expr_func_float_dgtormax \def\XINT_expr_func_sfloat #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt #3,!\XINTinFloatSdigits\XINTinFloatS }}% }% \let\XINT_flexpr_func_sfloat\XINT_expr_func_sfloat % no \XINT_iiexpr_func_sfloat \def\XINT_expr_func_sfloat_dgtormax #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINTinFloatSdigitsormax#3}}% }% \let\XINT_flexpr_func_sfloat_dgtormax\XINT_expr_func_sfloat_dgtormax \expandafter\def\csname XINT_expr_func_ilog10\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt #3,!\xintiLogTen\XINTFloatiLogTen }}% }% \expandafter\def\csname XINT_flexpr_func_ilog10\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:and:opt:direct \XINT:expr:f:one:and:opt #3,!\XINTFloatiLogTendigits\XINTFloatiLogTen }}% }% \expandafter\def\csname XINT_iiexpr_func_ilog10\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\xintiiLogTen#3}}% }% \def\XINT_expr_func_divmod #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintDivMod #3}}% }% \def\XINT_flexpr_func_divmod #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\XINTinFloatDivMod #3}}% }% \def\XINT_iiexpr_func_divmod #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintiiDivMod #3}}% }% \def\XINT_expr_func_mod #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintMod#3}}% }% \def\XINT_flexpr_func_mod #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\XINTinFloatMod#3}}% }% \def\XINT_iiexpr_func_mod #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintiiMod#3}}% }% \def\XINT_expr_func_binomial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintBinomial #3}}% }% \def\XINT_flexpr_func_binomial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\XINTinFloatBinomial #3}}% }% \def\XINT_iiexpr_func_binomial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintiiBinomial #3}}% }% \def\XINT_expr_func_pfactorial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintPFactorial #3}}% }% \def\XINT_flexpr_func_pfactorial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\XINTinFloatPFactorial #3}}% }% \def\XINT_iiexpr_func_pfactorial #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintiiPFactorial #3}}% }% \def\XINT_expr_func_randrange #1#2#3% {% \expandafter #1\expandafter #2\expanded{{{% \XINT:expr:randrange #3,!% }}}% }% \let\XINT_flexpr_func_randrange\XINT_expr_func_randrange \def\XINT_iiexpr_func_randrange #1#2#3% {% \expandafter #1\expandafter #2\expanded{{{% \XINT:iiexpr:randrange #3,!% }}}% }% \def\XINT:expr:randrange #1#2#3!% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {\xintiiRandRange{\XINT:NEhook:f:one:from:one:direct\xintNum{#1}}}% {\xintiiRandRangeAtoB{\XINT:NEhook:f:one:from:one:direct\xintNum{#1}}% {\XINT:NEhook:f:one:from:one:direct\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_iiexpr_func_iquo #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintiiQuo #3}}% }% \def\XINT_iiexpr_func_irem #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% \XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintiiRem #3}}% }% \def\XINT_expr_func_gcd #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_GCDof#3^}}% }% \let\XINT_flexpr_func_gcd\XINT_expr_func_gcd \def\XINT_iiexpr_func_gcd #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_iiGCDof#3^}}% }% \def\XINT_expr_func_lcm #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_LCMof#3^}}% }% \let\XINT_flexpr_func_lcm\XINT_expr_func_lcm \def\XINT_iiexpr_func_lcm #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_iiLCMof#3^}}% }% \def\XINT_expr_func_max #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_Maxof#3^}}% }% \def\XINT_iiexpr_func_max #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_iiMaxof#3^}}% }% \def\XINT_flexpr_func_max #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINTinFloatMaxof#3^}}% }% \def\XINT_expr_func_min #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_Minof#3^}}% }% \def\XINT_iiexpr_func_min #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_iiMinof#3^}}% }% \def\XINT_flexpr_func_min #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINTinFloatMinof#3^}}% }% \expandafter \def\csname XINT_expr_func_+\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_Sum#3^}}% }% \expandafter \def\csname XINT_flexpr_func_+\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINTinFloatSum#3^}}% }% \expandafter \def\csname XINT_iiexpr_func_+\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_iiSum#3^}}% }% \expandafter \def\csname XINT_expr_func_*\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_Prd#3^}}% }% \expandafter \def\csname XINT_flexpr_func_*\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINTinFloatPrd#3^}}% }% \expandafter \def\csname XINT_iiexpr_func_*\endcsname #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_iiPrd#3^}}% }% \def\XINT_expr_func_all #1#2#3% {% \expandafter #1\expandafter #2\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_ANDof#3^}}% }% \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\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_ORof#3^}}% }% \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\expandafter{\expandafter {\romannumeral`&&@\XINT:NEhook:f:from:delim:u\XINT_XORof#3^}}% }% \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\expandafter{\expandafter{% \romannumeral`&&@\XINT:NEhook:f:LFL\xintLength {\romannumeral\XINT:NEhook:r:check#3^}% }}% }% \let\XINT_flexpr_func_len \XINT_expr_func_len \let\XINT_iiexpr_func_len \XINT_expr_func_len \def\XINT_expr_func_first #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:LFL\xintFirstOne {\romannumeral\XINT:NEhook:r:check#3^}% }% }% \let\XINT_flexpr_func_first\XINT_expr_func_first \let\XINT_iiexpr_func_first\XINT_expr_func_first \def\XINT_expr_func_last #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:LFL\xintLastOne {\romannumeral\XINT:NEhook:r:check#3^}% }% }% \let\XINT_flexpr_func_last\XINT_expr_func_last \let\XINT_iiexpr_func_last\XINT_expr_func_last \def\XINT_expr_func_reversed #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:reverse\XINT_expr_reverse #3^^#3\xint:\xint:\xint:\xint: \xint:\xint:\xint:\xint:\xint_bye }% }% \def\XINT_expr_reverse #1#2% {% \if ^\noexpand#2% \expandafter\XINT_expr_reverse:_one_or_none\string#1.% \else \expandafter\XINT_expr_reverse:_at_least_two \fi }% \def\XINT_expr_reverse:_at_least_two #1^^{\XINT_revwbr_loop {}}% \def\XINT_expr_reverse:_one_or_none #1% {% \if #1\bgroup\xint_dothis\XINT_expr_reverse:_nutple\fi \if #1^\xint_dothis\XINT_expr_reverse:_nil\fi \xint_orthat\XINT_expr_reverse:_leaf }% \edef\XINT_expr_reverse:_nil #1\xint_bye{\noexpand\fi\space}% \def\XINT_expr_reverse:_leaf#1\fi #2\xint:#3\xint_bye{\fi\xint_gob_andstop_i#2}% \def\XINT_expr_reverse:_nutple% {% \expandafter\XINT_expr_reverse:_nutple_a\expandafter{\string}% }% \def\XINT_expr_reverse:_nutple_a #1^#2\xint:#3\xint_bye {% \fi\expandafter {\romannumeral0\XINT_revwbr_loop{}#2\xint:#3\xint_bye}% }% \let\XINT_flexpr_func_reversed\XINT_expr_func_reversed \let\XINT_iiexpr_func_reversed\XINT_expr_func_reversed \def\XINT_expr_func_if #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\xintiiifNotZero #3}}% }% \let\XINT_flexpr_func_if\XINT_expr_func_if \let\XINT_iiexpr_func_if\XINT_expr_func_if \def\XINT_expr_func_ifint #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\xintifInt #3}}% }% \let\XINT_iiexpr_func_ifint\XINT_expr_func_ifint \def\XINT_flexpr_func_ifint #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\xintifFloatInt #3}}% }% \def\XINT_expr_func_ifone #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\xintifOne #3}}% }% \let\XINT_flexpr_func_ifone\XINT_expr_func_ifone \def\XINT_iiexpr_func_ifone #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\xintiiifOne #3}}% }% \def\XINT_expr_func_ifsgn #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\xintiiifSgn #3}}% }% \let\XINT_flexpr_func_ifsgn\XINT_expr_func_ifsgn \let\XINT_iiexpr_func_ifsgn\XINT_expr_func_ifsgn \def\XINT_expr_func_nuple #1#2#3{#1#2{{#3}}}% \let\XINT_flexpr_func_nuple\XINT_expr_func_nuple \let\XINT_iiexpr_func_nuple\XINT_expr_func_nuple \def\XINT_expr_func_unpack #1#2%#3% {\expandafter#1\expandafter#2\romannumeral0\XINT:NEhook:unpack}% \let\XINT_flexpr_func_unpack\XINT_expr_func_unpack \let\XINT_iiexpr_func_unpack\XINT_expr_func_unpack \def\XINT_expr_func_flat #1#2%#3% {% \expandafter#1\expandafter#2\expanded \XINT:NEhook:x:flatten\XINT:expr:flatten }% \let\XINT_flexpr_func_flat\XINT_expr_func_flat \let\XINT_iiexpr_func_flat\XINT_expr_func_flat \let\XINT:NEhook:x:flatten\empty \def\XINT_expr_func_zip #1#2%#3% {% \expandafter#1\expandafter#2\romannumeral`&&@% \XINT:NEhook:x:zip\XINT:expr:zip }% \let\XINT_flexpr_func_zip\XINT_expr_func_zip \let\XINT_iiexpr_func_zip\XINT_expr_func_zip \let\XINT:NEhook:x:zip\empty \def\XINT:expr:zip#1{\expandafter{\expanded\XINT_zip_A#1\xint_bye\xint_bye}}% % \end{macrocode} % \subsection{User declared functions} %\begin{lverb} % It is possible that % the author actually does understand at this time the % \xintNewExpr/\xintdeffunc refactored code and mechanisms for the first time % since 2014: past evolutions such as the 2018 1.3 refactoring were done a bit % in the fog (although they did accomplish a crucial step). % % The 1.4 version of function and macro definitions is much more powerful than % 1.3 one. But the mechanisms such as «omit», «abort» and «break()» in iter() % et al. can't be translated into much else than their actual code when they % potentially have to apply to non-numeric only context. The 1.4 \xintdeffunc % is thus apparently able to digest them but its pre-parsing benefits are % limited compared to simply assigning such parts of an expression to a % mock-function created by \xintNewFunction (which creates simply a TeX macro % from its substitution expression in macro parameters and add % syntactic sugar to let it appear to \xintexpr as a genuine «function» % although nothing of the syntax has really been pre-parsed.) % % At 1.4 fetching the expression up to final semi-colon is done using % \XINT_expr_fetch_to_semicolon, hence semi-colons arising in the syntax do % not need to be hidden inside braces. %\end{lverb} % % \localtableofcontents % % \subsubsection{\csh{xintdeffunc}, \csh{xintdefiifunc}, % \csh{xintdeffloatfunc}} % % \changed[2015/11/12]{1.2c} %\begin{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. %\end{lverb} % % \changed[2015/11/13]{1.2c} %\begin{lverb} % Function names first expanded then detokenized and cleaned of spaces. %\end{lverb} % % \changed[2015/11/21]{1.2e} %\begin{lverb} % No \detokenize anymore on the function % names. And #1(#2)#3=#4 parameter pattern to avoid to have to worry if a : is % there and it is active. %\end{lverb} % % \changed[2016/02/22]{1.2f} %\begin{lverb} % La macro associée à la fonction ne débute % plus par un \romannumeral, car de toute façon elle est pour emploi dans % \csname..\endcsname. %\end{lverb} % % \changed[2016/03/08]{1.2f} %\begin{lverb} % Comma separated expressions allowed (formerly this required using % parenthesis \xintdeffunc foo(x,..):=(.., .., ..); %\end{lverb} % % \changed[2018/06/17]{1.3c} %\begin{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. %\end{lverb} % % \changed{1.3e} %\begin{lverb} % \xintdefefunc variant added for functions which will expand % completely if used with numeric arguments in other function definitions. % They can't be used for recursive definitions. % % Their functionality was merged into \xintdeffunc et al. at 1.4. The % original macros were removed at 1.4m. %\end{lverb} % % \changed[2020/01/10]{1.4} %\begin{lverb} % Multi-letter variables can be used (with no prior declaration) %\end{lverb} % % \changed[2020/01/11]{1.4} %\begin{lverb} % The new internal data model has caused many worries initially (such % as whether to allow functions with «ople» outputs in contrast to «numbers» % or «nutples») but in the end all is simpler again and the refactoring of ? % and ?? in function definitions allows to fuse inert functions (allowing % recursive definitions) and expanding functions (expanding completely if with % numeric arguments) into a single entity. % % A special situation is with % functions of no variables. In that case it will be handled as an inert % entity, else they would not be different from variables. % %\end{lverb} % % \changed[2020/01/19]{1.4} %\begin{lverb} % Addition de la syntaxe déclarative \xintdeffunc foo(a,b,...,*z) = ...; % %\end{lverb} % % \changed[2022/06/05]{1.4m} %\begin{lverb} % Removal of the \xintdefefunc et al.$@ macros deprecated at 1.4. %\end{lverb} % \begin{macrocode} \def\XINT_tmpa #1#2#3#4#5% {% \def #1##1(##2)##3={% \edef\XINT_deffunc_tmpa {##1}% \edef\XINT_deffunc_tmpa {\xint_zapspaces_o \XINT_deffunc_tmpa}% \def\XINT_deffunc_tmpb {0}% \edef\XINT_deffunc_tmpd {##2}% \edef\XINT_deffunc_tmpd {\xint_zapspaces_o\XINT_deffunc_tmpd}% \def\XINT_deffunc_tmpe {0}% \expandafter#5\romannumeral\XINT_expr_fetch_to_semicolon }% end of \xintdeffunc_a definition \def#5##1{% \def\XINT_deffunc_tmpc{(##1)}% \ifnum\xintLength:f:csv{\XINT_deffunc_tmpd}>\xint_c_ \xintFor ####1 in {\XINT_deffunc_tmpd}\do {% \xintifForFirst{\let\XINT_deffunc_tmpd\empty}{}% \def\XINT_deffunc_tmpf{####1}% \if*\xintFirstItem{####1}% \xintifForLast {% \def\XINT_deffunc_tmpe{1}% \edef\XINT_deffunc_tmpf{\xintTrim{1}{####1}}% }% {% \edef\XINT_deffunc_tmpf{\xintTrim{1}{####1}}% \xintMessage{xintexpr}{Error} {Only the last positional argument can be variadic. Trimmed ####1 to \XINT_deffunc_tmpf}% }% \fi \XINT_expr_makedummy{\XINT_deffunc_tmpf}% \edef\XINT_deffunc_tmpd{\XINT_deffunc_tmpd{\XINT_deffunc_tmpf}}% \edef\XINT_deffunc_tmpb {\the\numexpr\XINT_deffunc_tmpb+\xint_c_i}% \edef\XINT_deffunc_tmpc {subs(\unexpanded\expandafter{\XINT_deffunc_tmpc},% \XINT_deffunc_tmpf=################\XINT_deffunc_tmpb)}% }% \fi % \end{macrocode} % Place holder for comments. Logic at 1.4 is simplified here compared to % earlier releases. % % \begin{macrocode} \ifcase\XINT_deffunc_tmpb\space \expandafter\XINT_expr_defuserfunc_none\csname \else \expandafter\XINT_expr_defuserfunc\csname \fi XINT_#2_func_\XINT_deffunc_tmpa\expandafter\endcsname \csname XINT_#2_userfunc_\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 \xintFor* ####1 in {\XINT_deffunc_tmpd}:{\xintrestorevariablesilently{####1}}% \xintexprRestoreCatcodes }% end of \xintdeffunc_b definition }% \def\xintdeffunc {\xintexprSafeCatcodes\xintdeffunc_a}% \def\xintdefiifunc {\xintexprSafeCatcodes\xintdefiifunc_a}% \def\xintdeffloatfunc {\xintexprSafeCatcodes\xintdeffloatfunc_a}% \XINT_tmpa\xintdeffunc_a {expr} \XINT_NewFunc {expr}\xintdeffunc_b \XINT_tmpa\xintdefiifunc_a {iiexpr}\XINT_NewIIFunc {iiexpr}\xintdefiifunc_b \XINT_tmpa\xintdeffloatfunc_a{flexpr}\XINT_NewFloatFunc{floatexpr}\xintdeffloatfunc_b \def\XINT_expr_defuserfunc_none #1#2#3#4% {% \XINT_global \def #1##1##2##3% {% \expandafter##1\expandafter##2\expanded{% {\XINT:NEhook:usernoargfunc\csname XINT_#4_userfunc_#3\endcsname}% }% }% }% \let\XINT:NEhook:usernoargfunc \empty \def\XINT_expr_defuserfunc #1#2#3#4% {% \if0\XINT_deffunc_tmpe \XINT_global \def #1##1##2%##3% {% \expandafter ##1\expandafter##2\expanded\bgroup{\iffalse}\fi \XINT:NEhook:userfunc{XINT_#4_userfunc_#3}#2%##3% }% \else % \end{macrocode} %\begin{lverb} % Last argument in the call signature is variadic (was prefixed by *). %\end{lverb} % \begin{macrocode} \def #1##1{% \XINT_global\def #1####1####2%####3% {% \expandafter ####1\expandafter####2\expanded\bgroup{\iffalse}\fi \XINT:NEhook:userfunc:argv{##1}{XINT_#4_userfunc_#3}#2%####3% }}\expandafter#1\expandafter{\the\numexpr\XINT_deffunc_tmpb-1}% \fi }% % \end{macrocode} %\begin{lverb} % Deliberate brace stripping of #3 to reveal the elements of the ople, % which may be atoms i.e. numeric data such as {1}, or again oples, which % means that the corresponding item was a nutple, for example it came from % input syntax such as foo(1, 2, [1, 2], 3), so (up to details of raw % encoding) {1}{2}{{1}{2}}{3}, which gives 4 braced arguments to macro #2. %\end{lverb} % \begin{macrocode} \def\XINT:NEhook:userfunc #1#2#3{#2#3\iffalse{{\fi}}}% % \end{macrocode} %\begin{lverb} % Here #1 indicates the number k-1 of standard positional arguments of % the call signature, the kth and last one having been declared of variadic % type. The braces around \xintTrim{#1}{#4} have the effect to gather all % these remaining elements to provide a single one to the TeX macro. % % For example input was foo(1,2,3,4,5) and call signature was foo(a,b,*z). % Then #4 will fetch {{1}{2}{3}{4}{5}}, with one level of brace removal. % We will have \xintKeep{2}{{1}{2}{3}{4}{5}} which produces {1}{2}. % Then {\xintTrim{2}{{1}{2}{3}{4}{5}}} which produces {{3}{4}{5}}. % So the macro will be used as \macro{1}{2}{{3}{4}{5}} having been % declared as a macro with 3 arguments. % % The above comments were added in June 2021 but the code was done on January % 19, 2020 for 1.4. % % Note on June 10, 2021: at core level \XINT_NewFunc is used which is derived % from \XINT_NewExpr which has always prepared TeX macros with non-delimited % parameters. A refactoring could add a final delimiter, for example \relax. % The macro with 3 arguments would be defined as \def\macro#1#2#3\relax{...} % for example. Then we could transfer to TeX core processing what is achieved % here via \xintKeep/\xintTrim, of course adding efficiency, via insertion of % the delimiter. In the case of foo(1,2,3,4,5) we would have the #3 of % delimited \macro fetch {3}{4}{5}, no brace removal, which is equivalent to % current situation fetching {{3}{4}{5}} with brace removal. But let's see in % case of foo(1,2,3) then. This would lead to delimited \macro{1}{2}{3}\relax % and #3 will fetch {3}, removing one brace pair. Whereas current % non-delimited \macro is used as \macro{1}{2}{{3}} from the Keep/Trim, then % #3 fetches {{3}}, removing one brace pair. Not the same thing. So it seems % there is a stumbling-block here to adopt such an alternative method, in % relation with brace removal. Rather relieved in fact, as my head starts % spinning in ople world. Seems better to stop thinking about doing something % like that, and what it would imply as consequences for user declarative % interface also. Oples are dangerous to mental health, let's stick with % one-ples: « named arguments in function body declaration must stand for % one-ples », even the last one, although a priori it could be envisioned if % foo has been declared with call signature (x,y,z) and is used with more % items that z is mapped to the ople of extra elements beyond the first % two ones. For my sanity I stick with my January 2020 concept of (x,y,*z) % which makes z stand for a nutple always and having to be used as such in the % function body (possibly unpacked there using *z). %\end{lverb} % \begin{macrocode} \def\XINT:NEhook:userfunc:argv #1#2#3#4% {\expandafter#3\expanded{\xintKeep{#1}{#4}{\xintTrim{#1}{#4}}}\iffalse{{\fi}}}% % \end{macrocode} % \subsubsection{\csh{xintdefufunc}, \csh{xintdefiiufunc}, % \csh{xintdeffloatufunc}} % %\begin{lverb} % Added at 1.4 %\end{lverb} % \changed[2022/05/15]{1.4k} %\begin{lverb} % The \xintexprSafeCatcodes was not paired correctly with % \xintexprRestoreCatcodes which was in only one branch of \xint_defufunc_b, % and as a result sanitization of catcodes was never reverted. That the % bug remained unseen and in particular did not break compilation of % user manual (where the | must be active), was a sort of unhappy miracle % due to the | ending up recovering its active catcode from some ulterior % \xintdefiifunc whose Safe/Restore behaved as described in the user manual, % i.e. it did a restore to the state before the first unpaired Safe, and this % miraculous recovery happened before breakage had happened, by sheer luck, % or rather lack of luck, else I would have seen and solved % the problem two years ago... %\end{lverb} % \begin{macrocode} \def\XINT_tmpa #1#2#3#4#5#6% {% \def #1##1(##2)##3={% \edef\XINT_defufunc_tmpa {##1}% \edef\XINT_defufunc_tmpa {\xint_zapspaces_o \XINT_defufunc_tmpa}% \edef\XINT_defufunc_tmpd {##2}% \edef\XINT_defufunc_tmpd {\xint_zapspaces_o\XINT_defufunc_tmpd}% \expandafter#5\romannumeral\XINT_expr_fetch_to_semicolon }% end of \xint_defufunc_a \def#5##1{% \def\XINT_defufunc_tmpc{(##1)}% \ifnum\xintLength:f:csv{\XINT_defufunc_tmpd}=\xint_c_i \expandafter#6% \else \xintMessage {xintexpr}{ERROR} {Universal functions must be functions of one argument only, but the declaration of \XINT_defufunc_tmpa\space has \xintLength:f:csv{\XINT_defufunc_tmpd} of them. Canceled.}% \xintexprRestoreCatcodes \fi }% end of \xint_defufunc_b \def #6{% \XINT_expr_makedummy{\XINT_defufunc_tmpd}% \edef\XINT_defufunc_tmpc {subs(\unexpanded\expandafter{\XINT_defufunc_tmpc},% \XINT_defufunc_tmpd=########1)}% \expandafter\XINT_expr_defuserufunc \csname XINT_#2_func_\XINT_defufunc_tmpa\expandafter\endcsname \csname XINT_#2_userufunc_\XINT_defufunc_tmpa\expandafter\endcsname \expandafter{\XINT_defufunc_tmpa}{#2}% \expandafter#3\csname XINT_#2_userufunc_\XINT_defufunc_tmpa\endcsname [1]{\XINT_defufunc_tmpc}% \ifxintverbose\xintMessage {xintexpr}{Info} {Universal function \XINT_defufunc_tmpa\space for \string\xint #4 parser associated to \string\XINT_#2_userufunc_\XINT_defufunc_tmpa\space with \ifxintglobaldefs global \fi meaning \expandafter\meaning \csname XINT_#2_userufunc_\XINT_defufunc_tmpa\endcsname}% \fi \xintexprRestoreCatcodes }% end of \xint_defufunc_c }% \def\xintdefufunc {\xintexprSafeCatcodes\xintdefufunc_a}% \def\xintdefiiufunc {\xintexprSafeCatcodes\xintdefiiufunc_a}% \def\xintdeffloatufunc {\xintexprSafeCatcodes\xintdeffloatufunc_a}% \XINT_tmpa\xintdefufunc_a {expr} \XINT_NewFunc {expr}% \xintdefufunc_b\xintdefufunc_c \XINT_tmpa\xintdefiiufunc_a {iiexpr}\XINT_NewIIFunc {iiexpr}% \xintdefiiufunc_b\xintdefiiufunc_c \XINT_tmpa\xintdeffloatufunc_a{flexpr}\XINT_NewFloatFunc{floatexpr}% \xintdeffloatufunc_b\xintdeffloatufunc_c \def\XINT_expr_defuserufunc #1#2#3#4% {% \XINT_global \def #1##1##2%##3% {% \expandafter ##1\expandafter##2\expanded \XINT:NEhook:userufunc{XINT_#4_userufunc_#3}#2%##3% }% }% \def\XINT:NEhook:userufunc #1{\XINT:expr:mapwithin}% % \end{macrocode} % % \subsubsection{\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_userufunc_\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} % \subsubsection{\csh{xintNewFunction}} %\begin{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. % % As the letters used for variables in \xintdeffunc, #1, #2, etc... can not % stand for non numeric «oples», because at time of function call f(a, b, c, % ...) how to decide if #1 stands for a or a, b etc... ? Or course «a» can be % packed and thus the macro function can handle #1 as a «nutple» and for this % be defined with the * unpacking operator being applied to it. %\end{lverb} % \begin{macrocode} \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 {\XINTfstop.{{##1}}}{\XINTfstop.{{##2}}}{\XINTfstop.{{##3}}}% {\XINTfstop.{{##4}}}{\XINTfstop.{{##5}}}{\XINTfstop.{{##6}}}% {\XINTfstop.{{##7}}}{\XINTfstop.{{##8}}}{\XINTfstop.{{##9}}}}% \expandafter\XINT_expr_newfunction \csname XINT_expr_func_\XINT_newfunc_tmpa\expandafter\endcsname \expandafter{\XINT_newfunc_tmpa}\xintbareeval \expandafter\XINT_expr_newfunction \csname XINT_iiexpr_func_\XINT_newfunc_tmpa\expandafter\endcsname \expandafter{\XINT_newfunc_tmpa}\xintbareiieval \expandafter\XINT_expr_newfunction \csname XINT_flexpr_func_\XINT_newfunc_tmpa\expandafter\endcsname \expandafter{\XINT_newfunc_tmpa}\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% {% \XINT_global \def#1##1##2##3% {\expandafter ##1\expandafter ##2% \romannumeral0\XINT:NEhook:macrofunc #3{\csname XINT_expr_macrofunc_#2\endcsname##3}\relax }% }% \let\XINT:NEhook:macrofunc\empty % \end{macrocode} % \subsubsection{Mysterious stuff} % % 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. % % It is always too soon to try to comment and explain. In brief, this attempts % to hack into the \emph{purely numeric} |\xintexpr| parsers to transform them % into \emph{symbolic} parsers, allowing to do once and for all the parsing % job and inherit a gigantic nested macro. Originally only f-expandable % nesting. The initial motivation was that the |\csname| encapsulation impacted % the string pool memory. Later this work proved to be the basis to provide % support for implementing % user-defined functions and it is now its main purpose. % % Deep refactorings happened at 1.3 and 1.4. % % At 1.3 the crucial idea of the «hook» macros was introduced, reducing % considerably the preparatory work done by |\xintNewExpr|. % % At 1.4 further considerable simplifications happened, and it is possible % that the author currently does at long last understand the code! % % The 1.3 code had serious complications with trying % to identify would-be «list» arguments, distinguishing them from «single» % arguments (things like parsing |#2+[[#1..[#3]..#4][#5:#6]]*#7| and convert % it to a single nested f-exandable macro...) % % The conversion at 1.4 is both more powerful and simpler, due in part to the % new storage model which from |\csname| encapsulated comma separated values % up to 1.3f became simply a braced list of braced values, and also crucially % due to the possibilities opened up by usage of |\expanded| primitive. % % \begin{macrocode} \catcode`~ 12 \def\XINT:NE:hastilde#1~#2#3\relax{\unless\if !#21\fi}% \def\XINT:NE:hashash#1{% \def\XINT:NE:hashash##1#1##2##3\relax{\unless\if !##21\fi}% }\expandafter\XINT:NE:hashash\string#% \def\XINT:NE:unpack #1{% \def\XINT:NE:unpack ##1% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0\else \expandafter\XINT:NE:unpack:p\fi \xint_stop_atfirstofone{##1}% }}\expandafter\XINT:NE:unpack\string#% \def\XINT:NE:unpack:p#1#2% {{~romannumeral0~expandafter~xint_stop_atfirstofone~expanded{#2}}}% \def\XINT:NE:f:one:from:one #1{% \def\XINT:NE:f:one:from:one ##1% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0\else \xint_dothis\XINT:NE:f:one:from:one_a\fi \xint_orthat\XINT:NE:f:one:from:one_b ##1&&A% }}\expandafter\XINT:NE:f:one:from:one\string#% \def\XINT:NE:f:one:from:one_a\romannumeral`&&@#1#2&&A% {% \expandafter{\detokenize{\expandafter#1}#2}% }% \def\XINT:NE:f:one:from:one_b#1{% \def\XINT:NE:f:one:from:one_b\romannumeral`&&@##1##2&&A% {% \expandafter{\romannumeral`&&@% \if0\XINT:NE:hastilde ##2~!\relax \XINT:NE:hashash ##2#1!\relax 0\else \expandafter\string\fi ##1{##2}}% }}\expandafter\XINT:NE:f:one:from:one_b\string#% \def\XINT:NE:f:one:from:one:direct #1#2{\XINT:NE:f:one:from:one:direct_a #2&&A{#1}}% \def\XINT:NE:f:one:from:one:direct_a #1#2&&A#3% {% \if ###1\xint_dothis {\detokenize{#3}}\fi \if ~#1\xint_dothis {\detokenize{#3}}\fi \xint_orthat {#3}{#1#2}% }% \def\XINT:NE:f:one:from:two #1{% \def\XINT:NE:f:one:from:two ##1% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0\else \xint_dothis\XINT:NE:f:one:from:two_a\fi \xint_orthat\XINT:NE:f:one:from:two_b ##1&&A% }}\expandafter\XINT:NE:f:one:from:two\string#% \def\XINT:NE:f:one:from:two_a\romannumeral`&&@#1#2&&A% {% \expandafter{\detokenize{\expandafter#1\expanded}{#2}}% }% \def\XINT:NE:f:one:from:two_b#1{% \def\XINT:NE:f:one:from:two_b\romannumeral`&&@##1##2##3&&A% {% \expandafter{\romannumeral`&&@% \if0\XINT:NE:hastilde ##2##3~!\relax \XINT:NE:hashash ##2##3#1!\relax 0\else \expandafter\string\fi ##1{##2}{##3}}% }}\expandafter\XINT:NE:f:one:from:two_b\string#% \def\XINT:NE:f:one:from:two:direct #1#2#3{\XINT:NE:two_fork #2&&A#3&&A#1{#2}{#3}}% \def\XINT:NE:two_fork #1#2&&A#3#4&&A{\XINT:NE:two_fork_nn#1#3}% \def\XINT:NE:two_fork_nn #1#2% {% \if #1##\xint_dothis\string\fi \if #1~\xint_dothis\string\fi \if #2##\xint_dothis\string\fi \if #2~\xint_dothis\string\fi \xint_orthat{}% }% \def\XINT:NE:f:one:and:opt:direct#1{% \def\XINT:NE:f:one:and:opt:direct##1!% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0\else \xint_dothis\XINT:NE:f:one:and:opt_a\fi \xint_orthat\XINT:NE:f:one:and:opt_b ##1&&A% }}\expandafter\XINT:NE:f:one:and:opt:direct\string#% \def\XINT:NE:f:one:and:opt_a #1#2&&A#3#4% {% \detokenize{\romannumeral-`0\expandafter#1\expanded{#2}$XINT_expr_exclam#3#4}%$ }% \def\XINT:NE:f:one:and:opt_b\XINT:expr:f:one:and:opt #1#2#3&&A#4#5% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {\XINT:NE:f:one:from:one:direct#4}% {\expandafter\XINT:NE:f:onewithopttoone\expandafter#5% \expanded{{\XINT:NE:f:one:from:one:direct\xintNum{#2}}}}% {#1}% }% \def\XINT:NE:f:onewithopttoone#1#2#3{\XINT:NE:two_fork #2&&A#3&&A#1[#2]{#3}}% \def\XINT:NE:f:tacitzeroifone:direct#1{% \def\XINT:NE:f:tacitzeroifone:direct##1!% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0\else \xint_dothis\XINT:NE:f:one:and:opt_a\fi \xint_orthat\XINT:NE:f:tacitzeroifone_b ##1&&A% }}\expandafter\XINT:NE:f:tacitzeroifone:direct\string#% \def\XINT:NE:f:tacitzeroifone_b\XINT:expr:f:tacitzeroifone #1#2#3&&A#4#5% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {\XINT:NE:f:one:from:two:direct#4{0}}% {\expandafter\XINT:NE:f:one:from:two:direct\expandafter#5% \expanded{{\XINT:NE:f:one:from:one:direct\xintNum{#2}}}}% {#1}% }% \def\XINT:NE:f:iitacitzeroifone:direct#1{% \def\XINT:NE:f:iitacitzeroifone:direct##1!% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0\else \xint_dothis\XINT:NE:f:iitacitzeroifone_a\fi \xint_orthat\XINT:NE:f:iitacitzeroifone_b ##1&&A% }}\expandafter\XINT:NE:f:iitacitzeroifone:direct\string#% \def\XINT:NE:f:iitacitzeroifone_a #1#2&&A#3% {% \detokenize {\romannumeral`$XINT_expr_null\expandafter#1\expanded{#2}$XINT_expr_exclam#3}% }% \def\XINT:NE:f:iitacitzeroifone_b\XINT:expr:f:iitacitzeroifone #1#2#3&&A#4% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi {\XINT:NE:f:one:from:two:direct#4{0}}% {\XINT:NE:f:one:from:two:direct#4{#2}}% {#1}% }% \def\XINT:NE:x:one:from:two #1#2#3{\XINT:NE:x:one:from:two_fork #2&&A#3&&A#1{#2}{#3}}% \def\XINT:NE:x:one:from:two_fork #1{% \def\XINT:NE:x:one:from:two_fork ##1##2&&A##3##4&&A% {% \if0\XINT:NE:hastilde ##1##3~!\relax\XINT:NE:hashash ##1##3#1!\relax 0% \else \expandafter\XINT:NE:x:one:from:two:p \fi }}\expandafter\XINT:NE:x:one:from:two_fork\string#% \def\XINT:NE:x:one:from:two:p #1#2#3% {~expanded{\detokenize{\expandafter#1}~expanded{{#2}{#3}}}}% \def\XINT:NE:x:listsel #1{% \def\XINT:NE:x:listsel ##1##2&% {% \if0\expandafter\XINT:NE:hastilde\detokenize{##2}~!\relax \expandafter\XINT:NE:hashash\detokenize{##2}#1!\relax 0% \else \expandafter\XINT:NE:x:listsel:p \fi ##1##2&% }}\expandafter\XINT:NE:x:listsel\string#% \def\XINT:NE:x:listsel:p #1#2_#3&(#4% {% \detokenize{\expanded\XINT:expr:ListSel{{#3}{#4}}}% }% \def\XINT:expr:ListSel{\expandafter\XINT:expr:ListSel_i\expanded}% \def\XINT:expr:ListSel_i #1#2{{\XINT_ListSel_top #2_#1&({#2}}}% \def\XINT:NE:f:reverse #1{% \def\XINT:NE:f:reverse ##1^% {% \if0\expandafter\XINT:NE:hastilde\detokenize\expandafter{\xint_gobble_i##1}~!\relax \expandafter\XINT:NE:hashash\detokenize{##1}#1!\relax 0% \else \expandafter\XINT:NE:f:reverse:p \fi ##1^% }}\expandafter\XINT:NE:f:reverse\string#% \def\XINT:NE:f:reverse:p #1^#2\xint_bye {% \expandafter\XINT:NE:f:reverse:p_i\expandafter{\xint_gobble_i#1}% }% \def\XINT:NE:f:reverse:p_i #1% {% \detokenize{\romannumeral0\XINT:expr:f:reverse{{#1}}}% }% \def\XINT:expr:f:reverse{\expandafter\XINT:expr:f:reverse_i\expanded}% \def\XINT:expr:f:reverse_i #1% {% \XINT_expr_reverse #1^^#1\xint:\xint:\xint:\xint: \xint:\xint:\xint:\xint:\xint_bye }% \def\XINT:NE:f:from:delim:u #1{% \def\XINT:NE:f:from:delim:u ##1##2^% {% \if0\expandafter\XINT:NE:hastilde\detokenize{##2}~!\relax \expandafter\XINT:NE:hashash\detokenize{##2}#1!\relax 0% \xint_afterfi{\expandafter\XINT_fooof_checkifnumber\expandafter##1\string}% \else \xint_afterfi{\XINT:NE:f:from:delim:u:p##1\empty}% \fi ##2^% }}\expandafter\XINT:NE:f:from:delim:u\string#% \def\XINT:NE:f:from:delim:u:p #1#2^% {% \detokenize {\expandafter\XINT:fooof:checkifnumber\expandafter#1}~expanded{#2}$XINT_expr_caret%$ }% \def\XINT:fooof:checkifnumber#1{\expandafter\XINT_fooof_checkifnumber\expandafter#1\string}% \def\XINT:NE:f:LFL#1#2{\expandafter\XINT:NE:f:LFL_a\expandafter#1#2\XINT:NE:f:LFL_a}% \def\XINT:NE:f:LFL_a#1#2% {% \if#2i\else\expandafter\XINT:NE:f:LFL_p \fi #1% }% \def\XINT:NE:r:check#1{% \def\XINT:NE:r:check##1\XINT:NE:f:LFL_a {% \if0\expandafter\XINT:NE:hastilde\detokenize{##1}~!\relax% \expandafter\XINT:NE:hashash\detokenize{##1}#1!\relax 0% \else \expandafter\XINT:NE:r:check:p \fi 1\expandafter{\romannumeral\XINT:NEsaved:r:check##1}% }}\expandafter\XINT:NE:r:check\string#% \def\XINT:NE:r:check:p 1\expandafter#1{\XINT:NE:r:check:p_i#1}% \def\XINT:NE:r:check:p_i\romannumeral\XINT:NEsaved:r:check{\XINT:NE:r:check:p_ii\empty}% \def\XINT:NE:r:check:p_ii#1^% {% 5~expanded{{~romannumeral~XINT:NEsaved:r:check#1$XINT_expr_caret}}%$ }% \def\XINT:NE:f:LFL_p#1% {% \detokenize{\romannumeral`$XINT_expr_null\expandafter#1}%$ }% \catcode`- 11 \def\XINT:NE:exec_? #1#2% {% \XINT:NE:exec_?_b #2&&A#1{#2}% }% % \end{macrocode} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`- 11 }\FixInterMacrocodeVspace % \begin{macrocode} \def\XINT:NE:exec_?_b #1{% \def\XINT:NE:exec_?_b ##1&&A% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0% \xint_dothis\XINT:NE:exec_?:x\fi \xint_orthat\XINT:NE:exec_?:p }}\expandafter\XINT:NE:exec_?_b\string#% \def\XINT:NE:exec_?:x #1#2#3% {% \expandafter\XINT_expr_check-_after?\expandafter#1% \romannumeral`&&@\expandafter\XINT_expr_getnext\romannumeral0\xintiiifnotzero#3% }% \def\XINT:NE:exec_?:p #1#2#3#4#5% {% \csname XINT_expr_func_*If\expandafter\endcsname \romannumeral`&&@#2\XINTfstop.{#3},[#4],[#5])% }% \expandafter\def\csname XINT_expr_func_*If\endcsname #1#2#3% {% #1#2{~expanded{~xintiiifNotZero#3}}% }% \def\XINT:NE:exec_?? #1#2#3% {% \XINT:NE:exec_??_b #2&&A#1{#2}% }% \def\XINT:NE:exec_??_b #1{% \def\XINT:NE:exec_??_b ##1&&A% {% \if0\XINT:NE:hastilde ##1~!\relax \XINT:NE:hashash ##1#1!\relax 0% \xint_dothis\XINT:NE:exec_??:x\fi \xint_orthat\XINT:NE:exec_??:p }}\expandafter\XINT:NE:exec_??_b\string#% \def\XINT:NE:exec_??:x #1#2#3% {% \expandafter\XINT_expr_check-_after?\expandafter#1% \romannumeral`&&@\expandafter\XINT_expr_getnext\romannumeral0\xintiiifsgn#3% }% \def\XINT:NE:exec_??:p #1#2#3#4#5#6% {% \csname XINT_expr_func_*IfSgn\expandafter\endcsname \romannumeral`&&@#2\XINTfstop.{#3},[#4],[#5],[#6])% }% \expandafter\def\csname XINT_expr_func_*IfSgn\endcsname #1#2#3% {% #1#2{~expanded{~xintiiifSgn#3}}% }% \catcode`- 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters\FixInterMacrocodeVspace % \begin{macrocode} \def\XINT:NE:branch #1% {% \if0\XINT:NE:hastilde #1~!\relax 0\else \xint_dothis\XINT:NE:branch_a\fi \xint_orthat\XINT:NE:branch_b #1&&A% }% \def\XINT:NE:branch_a\romannumeral`&&@#1#2&&A% {% \expandafter{\detokenize{\expandafter#1\expanded}{#2}}% }% \def\XINT:NE:branch_b#1{% \def\XINT:NE:branch_b\romannumeral`&&@##1##2##3&&A% {% \expandafter{\romannumeral`&&@% \if0\XINT:NE:hastilde ##2~!\relax \XINT:NE:hashash ##2#1!\relax 0\else \expandafter\string\fi ##1{##2}##3}% }}\expandafter\XINT:NE:branch_b\string#% \def\XINT:NE:seqx#1{% \def\XINT:NE:seqx\XINT_allexpr_seqx##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##2}#1!\relax 0% \else \expandafter\XINT:NE:seqx:p \fi \XINT_allexpr_seqx{##1}{##2}% }}\expandafter\XINT:NE:seqx\string#% \def\XINT:NE:seqx:p\XINT_allexpr_seqx #1#2#3#4% {% \expandafter\XINT_expr_put_op_first \expanded {% {% \detokenize {% \expanded\bgroup \expanded {\unexpanded{\XINT_expr_seq:_b{#1#4\relax $XINT_expr_exclam #3}}% #2$XINT_expr_caret}% }% }% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT:NE:opx#1{% \def\XINT:NE:opx\XINT_allexpr_opx ##1##2##3##4%##5##6##7##8% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##4}~!\relax \expandafter\XINT:NE:hashash \detokenize{##4}#1!\relax 0% \else \expandafter\XINT:NE:opx:p \fi \XINT_allexpr_opx ##1{##2}{##3}{##4}% en fait ##2 = \xint_c_, ##3 = \relax }}\expandafter\XINT:NE:opx\string#% \def\XINT:NE:opx:p\XINT_allexpr_opx #1#2#3#4#5#6#7#8% {% \expandafter\XINT_expr_put_op_first \expanded {% {% \detokenize {% \expanded\bgroup \expanded{\unexpanded{\XINT_expr_iter:_b {#1\expandafter\XINT_allexpr_opx_ifnotomitted \romannumeral0#1#6\relax#7@\relax $XINT_expr_exclam #5}}% #4$XINT_expr_caret$XINT_expr_tilde{{#8}}}%$ }% }% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT:NE:iter{\expandafter\XINT:NE:itery\expandafter}% \def\XINT:NE:itery#1{% \def\XINT:NE:itery\XINT_expr_itery##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##1##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##1##2}#1!\relax 0% \else \expandafter\XINT:NE:itery:p \fi \XINT_expr_itery{##1}{##2}% }}\expandafter\XINT:NE:itery\string#% \def\XINT:NE:itery:p\XINT_expr_itery #1#2#3#4#5% {% \expandafter\XINT_expr_put_op_first \expanded {% {% \detokenize {% \expanded\bgroup \expanded{\unexpanded{\XINT_expr_iter:_b {#5#4\relax $XINT_expr_exclam #3}}% #1$XINT_expr_caret$XINT_expr_tilde{#2}}%$ }% }% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT:NE:rseq{\expandafter\XINT:NE:rseqy\expandafter}% \def\XINT:NE:rseqy#1{% \def\XINT:NE:rseqy\XINT_expr_rseqy##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##1##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##1##2}#1!\relax 0% \else \expandafter\XINT:NE:rseqy:p \fi \XINT_expr_rseqy{##1}{##2}% }}\expandafter\XINT:NE:rseqy\string#% \def\XINT:NE:rseqy:p\XINT_expr_rseqy #1#2#3#4#5% {% \expandafter\XINT_expr_put_op_first \expanded {% {% \detokenize {% \expanded\bgroup \expanded{#2\unexpanded{\XINT_expr_rseq:_b {#5#4\relax $XINT_expr_exclam #3}}% #1$XINT_expr_caret$XINT_expr_tilde{#2}}%$ }% }% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT:NE:iterr{\expandafter\XINT:NE:iterry\expandafter}% \def\XINT:NE:iterry#1{% \def\XINT:NE:iterry\XINT_expr_iterry##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##1##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##1##2}#1!\relax 0% \else \expandafter\XINT:NE:iterry:p \fi \XINT_expr_iterry{##1}{##2}% }}\expandafter\XINT:NE:iterry\string#% \def\XINT:NE:iterry:p\XINT_expr_iterry #1#2#3#4#5% {% \expandafter\XINT_expr_put_op_first \expanded {% {% \detokenize {% \expanded\bgroup \expanded{\unexpanded{\XINT_expr_iterr:_b {#5#4\relax $XINT_expr_exclam #3}}% #1$XINT_expr_caret$XINT_expr_tilde #20$XINT_expr_qmark}% }% }% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT:NE:rrseq{\expandafter\XINT:NE:rrseqy\expandafter}% \def\XINT:NE:rrseqy#1{% \def\XINT:NE:rrseqy\XINT_expr_rrseqy##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##1##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##1##2}#1!\relax 0% \else \expandafter\XINT:NE:rrseqy:p \fi \XINT_expr_rrseqy{##1}{##2}% }}\expandafter\XINT:NE:rrseqy\string#% \def\XINT:NE:rrseqy:p\XINT_expr_rrseqy #1#2#3#4#5#6% {% \expandafter\XINT_expr_put_op_first \expanded {% {% \detokenize {% \expanded\bgroup \expanded{#2\unexpanded{\XINT_expr_rrseq:_b {#6#5\relax $XINT_expr_exclam #4}}% #1$XINT_expr_caret$XINT_expr_tilde #30$XINT_expr_qmark}% }% }% \expandafter}\romannumeral`&&@\XINT_expr_getop }% \def\XINT:NE:x:toblist#1{% \def\XINT:NE:x:toblist\XINT:expr:toblistwith##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##2}#1!\relax 0% \else \expandafter\XINT:NE:x:toblist:p \fi \XINT:expr:toblistwith{##1}{##2}% }}\expandafter\XINT:NE:x:toblist\string#% \def\XINT:NE:x:toblist:p\XINT:expr:toblistwith #1#2{{\XINTfstop.{#2}}}% \def\XINT:NE:x:flatten#1{% \def\XINT:NE:x:flatten\XINT:expr:flatten##1% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##1}~!\relax \expandafter\XINT:NE:hashash \detokenize{##1}#1!\relax 0% \else \expandafter\XINT:NE:x:flatten:p \fi \XINT:expr:flatten{##1}% }}\expandafter\XINT:NE:x:flatten\string#% \def\XINT:NE:x:flatten:p\XINT:expr:flatten #1% {% {{% \detokenize {% \expandafter\XINT:expr:flatten_checkempty \detokenize\expandafter{\expanded{#1}}$XINT_expr_caret%$ }% }}% }% \def\XINT:NE:x:zip#1{% \def\XINT:NE:x:zip\XINT:expr:zip##1% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##1}~!\relax \expandafter\XINT:NE:hashash \detokenize{##1}#1!\relax 0% \else \expandafter\XINT:NE:x:zip:p \fi \XINT:expr:zip{##1}% }}\expandafter\XINT:NE:x:zip\string#% \def\XINT:NE:x:zip:p\XINT:expr:zip #1% {% \expandafter{% \detokenize {% \expanded\expandafter\XINT_zip_A\expanded{#1}\xint_bye\xint_bye }% }% }% \def\XINT:NE:x:mapwithin#1{% \def\XINT:NE:x:mapwithin\XINT:expr:mapwithin ##1##2% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##2}#1!\relax 0% \else \expandafter\XINT:NE:x:mapwithin:p \fi \XINT:expr:mapwithin {##1}{##2}% }}\expandafter\XINT:NE:x:mapwithin\string#% \def\XINT:NE:x:mapwithin:p \XINT:expr:mapwithin #1#2% {% {{% \detokenize {% % \end{macrocode} % Attention (2022/06/10) I do not remember why I left these two commented % lines which docstrip will not remove, I hope this is not a forgotten % left=over from some debugging session. % \begin{macrocode} %% \expanded %% {% \expandafter\XINT:expr:mapwithin_checkempty \expanded{\noexpand#1$XINT_expr_exclam\expandafter}%$ \detokenize\expandafter{\expanded{#2}}$XINT_expr_caret%$ % \end{macrocode} % This is is the matching one. % \begin{macrocode} %% }% }% }}% }% \def\XINT:NE:x:ndmapx#1{% \def\XINT:NE:x:ndmapx\XINT_allexpr_ndmapx_a ##1##2^% {% \if 0\expandafter\XINT:NE:hastilde\detokenize{##2}~!\relax \expandafter\XINT:NE:hashash \detokenize{##2}#1!\relax 0% \else \expandafter\XINT:NE:x:ndmapx:p \fi \XINT_allexpr_ndmapx_a ##1##2^% }}\expandafter\XINT:NE:x:ndmapx\string#% \def\XINT:NE:x:ndmapx:p #1#2#3^\relax {% \detokenize {% \expanded{% \expandafter#1\expandafter#2\expanded{#3}$XINT_expr_caret\relax %$ }% }% }% % \end{macrocode} %\begin{lverb} % Attention here that user function % names may contain digits, so we don't use a \detokenize or ~ approach. % % This syntax means that a function defined by \xintdeffunc never expands % when used in another definition, so it can implement recursive definitions. % % \XINT:NE:userefunc et al. added at 1.3e. % % I added at \xintdefefunc, \xintdefiiefunc, \xintdeffloatefunc at 1.3e to on % the contrary expand if possible (i.e. if used only with numeric arguments) % in another definition. % % The \XINTusefunc % uses \expanded. Its ancestor \xintExpandArgs (xinttools 1.3) % had some more primitive f-expansion technique. %\end{lverb} % \begin{macrocode} \def\XINTusenoargfunc #1% {% 0\csname #1\endcsname }% \def\XINT:NE:usernoargfunc\csname #1\endcsname {% ~romannumeral~XINTusenoargfunc{#1}% }% \def\XINTusefunc #1% {% 0\csname #1\expandafter\endcsname\expanded }% \def\XINT:NE:usefunc #1#2#3% {% ~romannumeral~XINTusefunc{#1}{#3}\iffalse{{\fi}}% }% \def\XINTuseufunc #1% {% \expanded\expandafter\XINT:expr:mapwithin\csname #1\expandafter\endcsname\expanded }% \def\XINT:NE:useufunc #1#2#3% {% {{~expanded~XINTuseufunc{#1}{#3}}}% }% \def\XINT:NE:userfunc #1{% \def\XINT:NE:userfunc ##1##2##3% {% \if0\expandafter\XINT:NE:hastilde\detokenize{##3}~!\relax \expandafter\XINT:NE:hashash\detokenize{##3}#1!\relax 0% \expandafter\XINT:NE:userfunc_x \else \expandafter\XINT:NE:usefunc \fi {##1}{##2}{##3}% }}\expandafter\XINT:NE:userfunc\string#% \def\XINT:NE:userfunc_x #1#2#3{#2#3\iffalse{{\fi}}}% \def\XINT:NE:userufunc #1{% \def\XINT:NE:userufunc ##1##2##3% {% \if0\expandafter\XINT:NE:hastilde\detokenize{##3}~!\relax \expandafter\XINT:NE:hashash\detokenize{##3}#1!\relax 0% \expandafter\XINT:NE:userufunc_x \else \expandafter\XINT:NE:useufunc \fi {##1}{##2}{##3}% }}\expandafter\XINT:NE:userufunc\string#% \def\XINT:NE:userufunc_x #1{\XINT:expr:mapwithin}% \def\XINT:NE:macrofunc #1#2% {\expandafter\XINT:NE:macrofunc:a\string#1#2\empty&}% \def\XINT:NE:macrofunc:a#1\csname #2\endcsname#3&% {{~XINTusemacrofunc{#1}{#2}{#3}}}% \def\XINTusemacrofunc #1#2#3% {% \romannumeral0\expandafter\xint_stop_atfirstofone \romannumeral0#1\csname #2\endcsname#3\relax }% % \end{macrocode} % \subsubsection{\csh{XINT_expr_redefinemacros}} %\begin{lverb} % Completely refactored at 1.3. % % Again refactored at 1.4. The availability of \expanded allows more powerful % mechanisms and more importantly I better thought out the root problems % caused by the handling of list operations in this context and this helped % simplify considerably the code. %\end{lverb} % \odef\MakePrivateLetters{\MakePrivateLetters\catcode`- 11 }^^A % \begin{macrocode} \catcode`- 11 \def\XINT_expr_redefinemacros {% \let\XINT:NEhook:unpack \XINT:NE:unpack \let\XINT:NEhook:f:one:from:one \XINT:NE:f:one:from:one \let\XINT:NEhook:f:one:from:one:direct \XINT:NE:f:one:from:one:direct \let\XINT:NEhook:f:one:from:two \XINT:NE:f:one:from:two \let\XINT:NEhook:f:one:from:two:direct \XINT:NE:f:one:from:two:direct \let\XINT:NEhook:x:one:from:two \XINT:NE:x:one:from:two \let\XINT:NEhook:f:one:and:opt:direct \XINT:NE:f:one:and:opt:direct \let\XINT:NEhook:f:tacitzeroifone:direct \XINT:NE:f:tacitzeroifone:direct \let\XINT:NEhook:f:iitacitzeroifone:direct \XINT:NE:f:iitacitzeroifone:direct \let\XINT:NEhook:x:listsel \XINT:NE:x:listsel \let\XINT:NEhook:f:reverse \XINT:NE:f:reverse \let\XINT:NEhook:f:from:delim:u \XINT:NE:f:from:delim:u \let\XINT:NEhook:f:LFL \XINT:NE:f:LFL \let\XINT:NEhook:r:check \XINT:NE:r:check \let\XINT:NEhook:branch \XINT:NE:branch \let\XINT:NEhook:seqx \XINT:NE:seqx \let\XINT:NEhook:opx \XINT:NE:opx \let\XINT:NEhook:rseq \XINT:NE:rseq \let\XINT:NEhook:iter \XINT:NE:iter \let\XINT:NEhook:rrseq \XINT:NE:rrseq \let\XINT:NEhook:iterr \XINT:NE:iterr \let\XINT:NEhook:x:toblist \XINT:NE:x:toblist \let\XINT:NEhook:x:flatten \XINT:NE:x:flatten \let\XINT:NEhook:x:zip \XINT:NE:x:zip \let\XINT:NEhook:x:mapwithin \XINT:NE:x:mapwithin \let\XINT:NEhook:x:ndmapx \XINT:NE:x:ndmapx \let\XINT:NEhook:userfunc \XINT:NE:userfunc \let\XINT:NEhook:userufunc \XINT:NE:userufunc \let\XINT:NEhook:usernoargfunc \XINT:NE:usernoargfunc \let\XINT:NEhook:macrofunc \XINT:NE:macrofunc \def\XINTinRandomFloatSdigits{~XINTinRandomFloatSdigits }% \def\XINTinRandomFloatSixteen{~XINTinRandomFloatSixteen }% \def\xintiiRandRange{~xintiiRandRange }% \def\xintiiRandRangeAtoB{~xintiiRandRangeAtoB }% \def\xintRandBit{~xintRandBit }% \let\XINT_expr_exec_? \XINT:NE:exec_? \let\XINT_expr_exec_?? \XINT:NE:exec_?? \def\XINT_expr_op_? {\XINT_expr_op__?{\XINT_expr_op_-xii\XINT_expr_oparen}}% \def\XINT_flexpr_op_?{\XINT_expr_op__?{\XINT_flexpr_op_-xii\XINT_flexpr_oparen}}% \def\XINT_iiexpr_op_?{\XINT_expr_op__?{\XINT_iiexpr_op_-xii\XINT_iiexpr_oparen}}% }% \catcode`- 12 % \end{macrocode} % \let\MakePrivateLetters\xintexprMakePrivateLetters % \subsubsection{\csh{xintNewExpr}, \csh{xintNewIExpr}, \csh{xintNewFloatExpr}, % \csh{xintNewIIExpr}} %\begin{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. % % As \XINT_NewExpr always execute \XINT_expr_redefineprints since 1.3e whether % with \xintNewExpr or \XINT_NewFunc, it has been moved from argument to % hardcoded in replacement text. % % NO MORE \XINT_expr_redefineprints at 1.4 ! This allows better support for % \xinteval, \xinttheexpr as sub-entities inside an \xintNewExpr. And the % «cleaning» will remove the new \XINTfstop (detokenized from \meaning % output), to maintain backwards compatibility with former behaviour % that created macros expand to explicit digits and not an encapsulated % result. % % The #2#3 in clean stands for \noexpand\XINTfstop (where the actual % scantoken-ized input uses $$ originally with catcode letter as the escape % character). %\end{lverb} % \begin{macrocode} \def\xintNewExpr {\XINT_NewExpr\xint_firstofone\xintexpr \XINT_newexpr_clean}% \def\xintNewFloatExpr{\XINT_NewExpr\xint_firstofone\xintfloatexpr\XINT_newexpr_clean}% \def\xintNewIExpr {\XINT_NewExpr\xint_firstofone\xintiexpr \XINT_newexpr_clean}% \def\xintNewIIExpr {\XINT_NewExpr\xint_firstofone\xintiiexpr \XINT_newexpr_clean}% \def\xintNewBoolExpr {\XINT_NewExpr\xint_firstofone\xintboolexpr \XINT_newexpr_clean}% \def\XINT_newexpr_clean #1>#2#3{\noexpand\expanded\noexpand\xintNEprinthook}% \def\xintNEprinthook#1.#2{\expanded{\unexpanded{#1.}{#2}}}% % \end{macrocode} %\begin{lverb} % 1.2c for \xintdeffunc, \xintdefiifunc, \xintdeffloatfunc. % % At 1.3, NewFunc does not use anymore a comma delimited pattern for the % arguments to the macro being defined. % % At 1.4 we use \xintthebareeval, whose meaning now does not mean unlock % from csname but firstofone to remove a level of braces % This is involved in functioning of expr:userfunc and expr:userefunc %\end{lverb} % \begin{macrocode} \def\XINT_NewFunc {\XINT_NewExpr\xint_gobble_i\xintthebareeval\XINT_newfunc_clean}% \def\XINT_NewFloatFunc{\XINT_NewExpr\xint_gobble_i\xintthebarefloateval\XINT_newfunc_clean}% \def\XINT_NewIIFunc {\XINT_NewExpr\xint_gobble_i\xintthebareiieval\XINT_newfunc_clean}% \def\XINT_newfunc_clean #1>{}% % \end{macrocode} %\begin{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. % % The \xintexprSafeCatcodes inserted here by \xintNewExpr % is not paired with an \xintexprRestoreCatcodes, % but this happens within a scope limiting group so does not matter. % At 1.3c, \XINT_NewFunc et al. do not even execute the % \xintexprSafeCatcodes, as it gets already done by \xintdeffunc prior % to arriving here. % %\end{lverb} % \begin{macrocode} \def\XINT_NewExpr #1#2#3#4#5[#6]% {% \begingroup \ifcase #6\relax \toks0 {\endgroup\XINT_global\def#4}% \or \toks0 {\endgroup\XINT_global\def#4##1}% \or \toks0 {\endgroup\XINT_global\def#4##1##2}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3##4}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3##4##5}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3##4##5##6}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3##4##5##6##7}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3##4##5##6##7##8}% \or \toks0 {\endgroup\XINT_global\def#4##1##2##3##4##5##6##7##8##9}% \fi #1\xintexprSafeCatcodes \XINT_expr_redefinemacros \XINT_NewExpr_a #1#2#3#4% }% % \end{macrocode} %\begin{lverb} % $catcode38 12 % % 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. % % Attention that at 1.4, there might be entire sub-xintexpressions embedded in % detokenized form. They are re-tokenized and the main thing is that the % parser should not mis-interpret catcode 11 characters as starting variable % names. As some macros use : in their names, the retokenization must be done % with : having catcode 11. To not break embedded non-evaluated % sub-expressions, the \XINT_expr_getop was extended to intercept the : % (alternative would have been to never inject any macro with : in its name... % too late now). On the other hand the ! is not used in the macro names % potentially kept as is non expanded by the \xintNewExpr/\xintdeffunc % process; it can thus be retokenized with catcode 12. But the «hooks» of % seq(), iter(), etc... if deciding they can't evaluate immediately will % inject a full sub-expression (possibly arbitrarily complicated) and append % to it for its delayed expansion a catcode 11 ! character (as well as % possibly catcode 3 ~ and ? and catcode 11 caret ^ and even catcode 7 $&). % The macros \XINT_expr_tilde etc... below serve for this injection (there are % *two* successive \scantokens using different catcode regimes and these % macros remain detokenized during the first pass!) and as consequence the % final meaning may have characters such as ! or & present with both standard % and special catcodes depending on where they are located. It may thus not be % possible to (easily) retokenize the meaning as printed in the log file if % \xintverbosetrue was issued. % % If a defined function is used in another expression it would thus break % things if its meaning was included pre-expanded ; a mechanism exists which % keeps only the name of the macro associated to the function (this name may % contain digits by the way), when the macro can not be immediately fully % expanded. Thus its meaning (with its possibly funny catcodes) is not % exposed. And this gives opportunity to pre-expand its arguments before % actually expanding the macro. %\end{lverb} % \begin{macrocode} \catcode`~ 3 \catcode`? 3 \def\XINT_expr_tilde{~}\def\XINT_expr_qmark{?}% catcode 3 \def\XINT_expr_caret{^}\def\XINT_expr_exclam{!}% catcode 11 \def\XINT_expr_tab{&}% catcode 7 \def\XINT_expr_null{&&@}% \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~{$noexpand$}@ \catcode`: 11 \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 @ $ \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 \XINTsetcatcodes % clean up to avoid surprises if something changes % \end{macrocode} % \subsubsection{\csh{xintexprSafeCatcodes}, \csh{xintexprRestoreCatcodes}} % \changed[2018/06/17]{1.3c} %\begin{lverb} % Added \ifxintexprsafecatcodes to allow nesting %\end{lverb} % \changed[2022/05/15]{1.4k} %\begin{lverb} % The "allow nesting" from the 2018 comment was strange, because % the behaviour, as correctly documented in user manual, was that % in case of a series of \xintexprSafeCatcodes, the \xintexprRestoreCatcodes % would set catcodes to what they were before the *first* sanitization. % But as \xintdefvar and \xintdeffunc used such a pair this meant % that they would incomprehensibly for user reset catcodes to what % they were before a possible user \xintexprSafeCatcodes located before... % very lame situation. Anyway. I finally % fix at 1.4k that by removing the silly \ifxintexprsafecatcodes thing % and replace it by some stack-like method, avoiding extra macros % thanks to the help of \unexpanded. %\end{lverb} % \changed{1.4m} Use |\protected| rather than |\unexpanded| mechanism, % for lisibility. % \begin{macrocode} \protected\def\xintexprRestoreCatcodes{}% \def\xintexprSafeCatcodes {% \protected\edef\xintexprRestoreCatcodes{% \endlinechar=\the\endlinechar \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 \protected\odef\xintexprRestoreCatcodes{\xintexprRestoreCatcodes}% }% \endlinechar=13 % \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 \let\XINT_tmpd\undefined \let\XINT_tmpe\undefined % \end{macrocode} %\begin{lverb} % 1.4l makes \usepackage{xintlog} with no prior \usepackage{xintexpr} % not abort but attempt to do the right thing. We have to work-around the % fact that LaTeX will ignore a \usepackage here. Simpler for non-LaTeX. % % In all cases, notice that the input of xintlog.sty and xinttrig.sty is done % with xintexpr catcodes in place. And xintlog will sanitize catcodes at time % of loading poormanlog. Attention also to not mix-up things at time of % restoring catcodes. This is reason why xintlog.sty and xinttrig.sty have % their own endinput wrappers. And that the rescue attempt of loading % xintexpr (which will load xintlog) from xintlog itself is done carefully. % %\end{lverb} % \begin{macrocode} \ifdefined\RequirePackage \ifcsname ver@xinttrig.sty\endcsname % \end{macrocode} % We end up here since |1.4l| with \LaTeX{} if the user has issued % |\usepackage{xinttrig}| or |\RequirePackage{xinttrig}| with no prior loading % of \xintexprnameimp. In such (not officially supported) case, the loading % of |xintexpr| was launched from this first instance of \xinttrignameimp. % This first \xinttrignameimp will abort itself, once this input conludes. % But before that a second instance of \xinttrignameimp is |\input| and will % do all its macro definitions. We can not do |\RequirePackage{xinttrig}| or % |\usepackage{xinttrig}| as it has occurred already under the user % responsability, so we use |\@@input|. % \begin{macrocode} \@@input xinttrig.sty\relax \else % \end{macrocode} % Here this is either the normal case with \LaTeX{} (or other formats % providing |\RequirePackage|) and \xintexprnameimp requested by user % directly, or some more exotic possibility such as \eTeX{} with the % \ctanpackage{miniltx} loaded and then |\input xintexpr.sty\relax| was done. % As |\RequirePackage| appears to be defined we use it. % \begin{macrocode} \RequirePackage{xinttrig}% \fi % \end{macrocode} % Same situation with \xintlognameimp. % \begin{macrocode} \ifcsname ver@xintlog.sty\endcsname \@@input xintlog.sty\relax \else \RequirePackage{xintlog}% \fi \else % \end{macrocode} % Here we are not with \LaTeX{} and not with \ctanpackage{miniltx} either. % Let's just use |\input|. Perhaps there was an |\input xinttrig.sty| earlier % which triggered |\input xintexpr.sty| after a warning to the user. The % second |\input xinttrig.sty| issued here will execute the macro definitions, % and the former one will abort its own input after that. % \begin{macrocode} \input xinttrig.sty \input xintlog.sty \fi \XINTrestorecatcodesendinput% % \end{macrocode} % \setcounter{xintMacroCnt}{\the\numexpr452+\value{xintMacroCnt}\relax} % \StoreCodelineNo {xintexpr} % \etocsettocdepth{subsubsection} % \cleardoublepage\let\xintexprnameUp\undefined %\gardesactifs %\let</xintexpr>\relax %\let<*xinttrig>\gardesinactifs %</xintexpr>^^A-------------------------------------------------- %<*xinttrig>^^A--------------------------------------------------- %^^A -*- coding: utf-8; mode: doctex; fill-column: 78; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xinttrignameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \xinttrignameimp implementation} % \RaisedLabel{sec:trigimp} % \etocarticlestylenomarks % \etocsetnexttocdepth {subsubsection} % % \localtableofcontents % % A preliminary implementation was done only late in the development of % \xintexprnameimp, as an example of the high level user interface, in January % 2019. In March and April 2019 I improved the algorithm for the inverse % trigonometrical functions and included the whole as a new \csbxint{expr} % module. But, as the high level interface provided no way to have % intermediate steps executed with guard digits, the whole scheme could only % target say P-2 digits where P is the prevailing precision, and only with a % moderate requirement on what it means to have P-2 digits about correct. % % Finally in April 2021, after having at long last added exponential and % logarithm up to 62 digits and at a rather strong precision requirement % (something like, say with inputs in normal ranges: targeting at most 0.505ulp % distance to exact result), I revisited the code here. % % We keep most of the high level usage of \csbxint{deffloatfunc}, but hack % into its process in order to let it map the 4 operations and some functions % such as square-root to macros using 4 extra digits. This hack is enough to % support the used syntax here, but is not usable generally. All functions and % their auxiliaries defined during the time the hack applies are named with % |@| as first letter. % % Later the public functions, without the |@|, are defined as wrappers of the % |@|-named ones, which float-round to P digits on output. % % Apart from that the sine and cosine series were implemented at macro level, % bypassing the \csbxint{deffloatfunc} interface. This is done mainly for % handling Digits at high value (24 or more) as it then becomes beneficial to % float-round the variable to less and less digits, the deeper one goes into % the series. % % And regarding the arcsine I modified a bit my original idea in order to % execute the first step in a single \cs{numexpr}. It turns out that that for % 16 digits the algorithm then ``only'' needs one sine and one cosine % evaluation (and a square-root), and there is no need for an arcsine series % auxiliary then. I am aware this is by far not the ``best'' approach but the % problem is that I am a bit enamored into the idea of the algorithm even % though it is at least twice as costly than a sine evaluation! Actually, for % many digits, it turns out the arcsine is less costly than two random sine % evaluations, probably because the latter have the overhead of range % reduction. % % Speaking of this, the range reduction is rather naive and not extremely % ambitious. I wrote it initially having only |sind()| and |cosd()| in mind, % and in 2019 reduced degrees to radians in the most naive way possible. I % have only slighly improved this for this |1.4e| 2021 release, the announced % precision for inputs less than say |1e6|, but at |1e8| and higher, one will % start feeling the gradual loss of precision compared to the task of % computing the exact mathematical result correctly rounded. Also, I do not % worry here about what happens when the input is very near a big multiple of % $\pi$, and one computes a sine for example. Maybe I will improve in future % this aspect but I decided I was seriously running out of steam for the % |1.4e| release. % % As commented in \xintlognameimp regarding exponential and logarithms, even % though we have instilled here some dose of lower level coding, the whole % suffers from \xintfracnameimp not yet having made floating point numbers a % native type. Thus inefficiencies accumulate... % % At 8 digits, the gain was only about 40\% compared to 16 digits. So at the % last minute, on the day I was going to do the release I decided to implement % a poorman way for sine and cosine, for "speed". I transferred the idea from % the arcsine numexpr to sine and cosine. Indeed there is an interesting speed % again of about 4X compared to applying the same approach as for higher % values of Digits. Correct rounding during random testing is still obtained % reasonably often (at any rate more than 95\% of cases near 45 degrees and % always faithful rounding), although at less than the 99\% reached for the % main branch handling Digits up to 62. But the precision is more than enough % for usage in plots for example. I am keeping the guard digits, as removing % then would add a further speed gain of about 20\% to 40\% but the precision % then would drop dramatically, and this is not acceptable at the time of our % 2021 standards (not a period of enlightenment generally speaking, though). % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % \changed{1.4l} %\begin{lverb} % Silly paranoid modification of \z in case { and } do not have their % normal catcodes when xinttrig.sty is reloaded (initial loading via % xintexpr.sty does not need this), to define \XINTtrigendinput there and not % after the \endgroup from \z has already restored possibly bad catcodes. % % 1.4l handles much better the situation with \usepackage{xinttrig} without % previous loading of xintexpr (or same with \input and etex). cf comments in % xintlog.sty. % %\end{lverb} % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode35=6 % # \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xinttrig.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintexpr.sty\endcsname \expandafter \ifx\csname PackageWarningNoLine\endcsname\relax \def\y#1#2{\immediate\write128{^^JPackage #1 Warning:^^J% \space\space\space\space#2.^^J}}% \else \def\y#1#2{\PackageWarningNoLine{#1}{#2}}% \fi \expandafter \ifx\csname numexpr\endcsname\relax \y{xinttrig}{\numexpr not available, aborting input}% \def\z{\endgroup\endinput}% \else \ifx\w\relax % xintexpr.sty not yet loaded. \edef\MsgBrk{^^J\space\space\space\space}% \y{xinttrig}% {\ifx\x\empty xinttrig should not be loaded directly\MessageBreak The correct way is \string\usepackage{xintexpr}.\MessageBreak Will try that now% \else First loading of xinttrig.sty should be via \string\input\space xintexpr.sty\relax\MsgBrk Will try that now% \fi }% \ifx\x\empty \def\z{\endgroup\RequirePackage{xintexpr}\endinput}% \else \def\z{\endgroup\input xintexpr.sty\relax\endinput}% \fi \else \def\z{\endgroup\edef\XINTtrigendinput{\XINTrestorecatcodes\noexpand\endinput}}% \fi \fi \z% \XINTsetcatcodes% \catcode`? 12 % \end{macrocode} % \subsection{Library identification} % If the file has already been loaded, let's skip the |\ProvidesPackage|. % Else let's do it and set a flag to indicate loading happened at least once % already. % \changed{1.4l} % Message also to Terminal not only log file. % \begin{macrocode} \ifcsname xintlibver@trig\endcsname \expandafter\xint_firstoftwo \else \expandafter\xint_secondoftwo \fi {\immediate\write128{Reloading xinttrig library using Digits=\xinttheDigits.}}% {\expandafter\gdef\csname xintlibver@trig\endcsname{2022/06/10 v1.4m}% \XINT_providespackage \ProvidesPackage{xinttrig}% [2022/06/10 v1.4m 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{lverb} % Much simplified at 1.4e, from a modified catcode regime management. %\end{lverb} % \begin{macrocode} \def\xintreloadxinttrig{\input xinttrig.sty }% % \end{macrocode} % \subsection{Auxiliary variables} %\begin{lverb} % The variables with private names have extra digits. Whether private or % public, the variables can all be redefined without impacting the defined % functions, whose meanings will contain already the variable values. % % Formerly variables holding the 1/n! were defined, but this got removed at 1.4e. %\end{lverb} % \subsubsection{\cshn{@twoPi}, \cshn{@threePiover2}, \cshn{@Pi}, \cshn{@Piover2}} %\begin{lverb} % At 1.4e we need more digits, also \xintdeffloatvar changed and always rounds % to P=Digits precision so we use another path to store values with extra digits. %\end{lverb} % \begin{macrocode} \xintdefvar @twoPi := float( 6.2831853071795864769252867665590057683943387987502116419498891846156328125724180 ,\XINTdigitsormax+4);% \xintdefvar @threePiover2 := float( 4.7123889803846898576939650749192543262957540990626587314624168884617246094293135 ,\XINTdigitsormax+4);% \xintdefvar @Pi := float( 3.1415926535897932384626433832795028841971693993751058209749445923078164062862090 ,\XINTdigitsormax+4);% \xintdefvar @Piover2 := float( 1.5707963267948966192313216916397514420985846996875529104874722961539082031431045 ,\XINTdigitsormax+4);% % \end{macrocode} % \subsubsection{\cshn{@oneDegree}, \cshn{@oneRadian}} %\begin{lverb} % Those are needed for range reduction, particularly @oneRadian. We define % it with 12 extra digits. But the whole process of range reduction in radians % is very naive one. %\end{lverb} % \begin{macrocode} \xintdefvar @oneDegree := float( 0.017453292519943295769236907684886127134428718885417254560971914401710091146034494 ,\XINTdigitsormax+4);% \xintdefvar @oneRadian := float( 57.295779513082320876798154814105170332405472466564321549160243861202847148321553 ,\XINTdigitsormax+12);% % \end{macrocode} % \subsection{Hack \cs{xintdeffloatfunc} for inserting usage of guard digits} %\begin{lverb} % 1.4e. This is not a general approach, but it sufficient for the % limited use case done here of \xintdeffloatfunc. What it does is to let % \xintdeffloatfunc hardcode usage of macros which will execute computations % with an elevated number of digits. But for example if 5/3 is encountered in % a float expression it will remain unevaluated so one would have to use % alternate input syntax for efficiency (\xintexpr % float(5/3,\xinttheDigits+4)\relax as a subexpression, for example). %\end{lverb} % \begin{macrocode} \catcode`~ 12 \def\XINT_tmpa#1#2#3.#4.% {% \let #1#2% \def #2##1##2##3##4% {##2##3{{~expanded{~unexpanded{#4[#3]}~expandafter}~expanded{##1##4}}}}% }% \expandafter\XINT_tmpa \csname XINT_flexpr_exec_+_\expandafter\endcsname \csname XINT_flexpr_exec_+\expandafter\endcsname \the\numexpr\XINTdigitsormax+4.~XINTinFloatAdd_wopt.% \expandafter\XINT_tmpa \csname XINT_flexpr_exec_-_\expandafter\endcsname \csname XINT_flexpr_exec_-\expandafter\endcsname \the\numexpr\XINTdigitsormax+4.~XINTinFloatSub_wopt.% \expandafter\XINT_tmpa \csname XINT_flexpr_exec_*_\expandafter\endcsname \csname XINT_flexpr_exec_*\expandafter\endcsname \the\numexpr\XINTdigitsormax+4.~XINTinFloatMul_wopt.% \expandafter\XINT_tmpa \csname XINT_flexpr_exec_/_\expandafter\endcsname \csname XINT_flexpr_exec_/\expandafter\endcsname \the\numexpr\XINTdigitsormax+4.~XINTinFloatDiv_wopt.% \def\XINT_tmpa#1#2#3.#4.% {% \let #1#2% \def #2##1##2##3{##1##2{{~expanded{~unexpanded{#4[#3]}~expandafter}##3}}}% }% \expandafter\XINT_tmpa \csname XINT_flexpr_sqrfunc\expandafter\endcsname \csname XINT_flexpr_func_sqr\expandafter\endcsname \the\numexpr\XINTdigitsormax+4.~XINTinFloatSqr_wopt.% \expandafter\XINT_tmpa \csname XINT_flexpr_sqrtfunc\expandafter\endcsname \csname XINT_flexpr_func_sqrt\expandafter\endcsname \the\numexpr\XINTdigitsormax+4.~XINTinFloatSqrt.% \expandafter\XINT_tmpa \csname XINT_flexpr_invfunc\expandafter\endcsname \csname XINT_flexpr_func_inv\expandafter\endcsname \the\numexpr\XINTdigitsormax+4.~XINTinFloatInv_wopt.% \catcode`~ 3 % \end{macrocode} % \subsection{The sine and cosine series} %\begin{lverb} % Old pending question: 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. % % Update at last minute: this is actually exactly what I do if Digits is at % most 8. % % Small values of the variable are very badly handled here because a much % shorter truncation of the series should be used. % % At 1.4e the original \xintdeffloatfunc was converted into macros, whose % principle can be seen also at work in xintlog.sty. We prepare the input % variables with shorter and shorter mantissas for usage deep in the series. % % This divided by about 3 the execution cost of the series for P about 60. % % Originally, the thresholds were computed a priori with 0.79 as upper bound % of the variable, but then for 1.4e I developped enough test files to try to % adjust heuristically with a target of say % 99,5$% of correct rounding, and always at most % 1ulp error. The numerical analysis is not easy due to the complications of % the implementation... % % Also, random testing never explores the weak spots... % % The 0.79 (a bit more than Pi/4) upper bound induces a costly check of % variable on input, if Digits is big. Much faster would be to check if input % is less than 10 degrees or 1 radian as done in xfp. But using enough % coefficients for allowing up to 1 radian, which is without pain for % Digits=16 starts being annoying for higher values such as Digits=48. % % But the main reason I don't do it now is that I spend too much time % fine-tuning the table of thresholds... maybe in next release. %\end{lverb} % \subsubsection{Support macros for the sine and cosine series} % %\begin{lverb} % Computing the 1/n! from n! then inverting would require % costly divisions and significantly increase the loading time. % % So a method is employed to simply divide by 2k(2k-1) or (2k+1)(2k) % step by step, with what we hope are enough 8 security digits, and % reducing the sizes of the mantissas at each step. % % This whole section is conditional on Digits being at least nine. %\end{lverb} % % \begin{macrocode} \ifnum\XINTdigits>8 \edef\XINT_tmpG % 1/3! {1\xintReplicate{\XINTdigitsormax+2}{6}7[\the\numexpr-\XINTdigitsormax-4]}% \edef\XINT_tmpH % 1/5! {8\xintReplicate{\XINTdigitsormax+1}{3}[\the\numexpr-\XINTdigitsormax-4]}% \edef\XINT_tmpd % 1/5! {8\xintReplicate{\XINTdigitsormax+9}{3}[\the\numexpr-\XINTdigitsormax-12]}% \def\XINT_tmpe#1.#2.#3.#4.#5#6#7% {% \def#5##1\xint: {% \expandafter#6\romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def#6##1\xint: {% \expandafter#7\romannumeral0\xintsub{#4}{\XINTinFloat[#2]{\xintMul{#3}{##1}}}\xint: }% \def#7##1\xint:##2\xint: {% \xintSub{1/1[0]}{\XINTinFloat[#1]{\xintMul{##1}{##2}}}% }% }% \expandafter\XINT_tmpe \the\numexpr\XINTdigitsormax+4\expandafter.% \the\numexpr\XINTdigitsormax+2\expandafter.\expanded{% \XINT_tmpH.% 1/5! \XINT_tmpG.% 1/3! \expandafter}% \csname XINT_SinAux_series_a_iii\expandafter\endcsname \csname XINT_SinAux_series_b\expandafter\endcsname \csname XINT_SinAux_series_c_i\endcsname \def\XINT_tmpa #1 #2 #3 #4 #5 #6 #7 #8 % {% \def\XINT_tmpb ##1##2##3##4##5% {% \def\XINT_tmpc####1.####2.####3.####4.####5.% {% \def##1########1\xint: {% \expandafter##2% \romannumeral0\XINTinfloatS[####1]{########1}\xint:########1\xint: }% \def##2########1\xint: {% \expandafter##3% \romannumeral0\XINTinfloatS[####2]{########1}\xint:########1\xint: }% \def##3########1\xint: {% \expandafter##4% \romannumeral0\xintsub{####4}{\XINTinFloat[####2]{\xintMul{####3}{########1}}}\xint: }% \def##4########1\xint:########2\xint: {% \expandafter##5% \romannumeral0\xintsub{####5}% {\XINTinFloat[####1]{\xintMul{########1}{########2}}}\xint: }% }% }% \expandafter\XINT_tmpb \csname XINT_#8Aux_series_a_\romannumeral\numexpr#1-1\expandafter\endcsname \csname XINT_#8Aux_series_a_\romannumeral\numexpr#1\expandafter\endcsname \csname XINT_#8Aux_series_b\expandafter\endcsname \csname XINT_#8Aux_series_c_\romannumeral\numexpr#1-2\expandafter\endcsname \csname XINT_#8Aux_series_c_\romannumeral\numexpr#1-3\endcsname \edef\XINT_tmpd {\XINTinFloat[\XINTdigitsormax-#2+8]{\xintDiv{\XINT_tmpd}{\the\numexpr#5*(#5-1)\relax}}}% \let\XINT_tmpF\XINT_tmpG \let\XINT_tmpG\XINT_tmpH \edef\XINT_tmpH{\XINTinFloat[\XINTdigitsormax-#2]{\XINT_tmpd}}% \expandafter\XINT_tmpc \the\numexpr\XINTdigitsormax-#3\expandafter.% \the\numexpr\XINTdigitsormax-#2\expandafter.\expanded{% \XINT_tmpH.% \XINT_tmpG.% \XINT_tmpF.% }% }% \XINT_tmpa 4 -1 -2 -4 7 5 3 Sin % \ifnum\XINTdigits>3 \XINT_tmpa 5 1 -1 -2 9 7 5 Sin \fi \ifnum\XINTdigits>5 \XINT_tmpa 6 3 1 -1 11 9 7 Sin \fi \ifnum\XINTdigits>8 \XINT_tmpa 7 6 3 1 13 11 9 Sin \fi \ifnum\XINTdigits>11 \XINT_tmpa 8 9 6 3 15 13 11 Sin \fi \ifnum\XINTdigits>14 \XINT_tmpa 9 12 9 6 17 15 13 Sin \fi \ifnum\XINTdigits>16 \XINT_tmpa 10 14 12 9 19 17 15 Sin \fi \ifnum\XINTdigits>19 \XINT_tmpa 11 17 14 12 21 19 17 Sin \fi \ifnum\XINTdigits>22 \XINT_tmpa 12 20 17 14 23 21 19 Sin \fi \ifnum\XINTdigits>25 \XINT_tmpa 13 23 20 17 25 23 21 Sin \fi \ifnum\XINTdigits>28 \XINT_tmpa 14 26 23 20 27 25 23 Sin \fi \ifnum\XINTdigits>31 \XINT_tmpa 15 29 26 23 29 27 25 Sin \fi \ifnum\XINTdigits>34 \XINT_tmpa 16 32 29 26 31 29 27 Sin \fi \ifnum\XINTdigits>37 \XINT_tmpa 17 35 32 29 33 31 29 Sin \fi \ifnum\XINTdigits>40 \XINT_tmpa 18 38 35 32 35 33 31 Sin \fi \ifnum\XINTdigits>44 \XINT_tmpa 19 42 38 35 37 35 33 Sin \fi \ifnum\XINTdigits>47 \XINT_tmpa 20 45 42 38 39 37 35 Sin \fi \ifnum\XINTdigits>51 \XINT_tmpa 21 49 45 42 41 39 37 Sin \fi \ifnum\XINTdigits>55 \XINT_tmpa 22 53 49 45 43 41 39 Sin \fi \ifnum\XINTdigits>58 \XINT_tmpa 23 56 53 49 45 43 41 Sin \fi \edef\XINT_tmpd % 1/4! {41\xintReplicate{\XINTdigitsormax+8}{6}7[\the\numexpr-\XINTdigitsormax-12]}% \edef\XINT_tmpH % 1/4! {41\xintReplicate{\XINTdigitsormax}{6}7[\the\numexpr-\XINTdigitsormax-4]}% \def\XINT_tmpG{5[-1]}% 1/2! \expandafter\XINT_tmpe \the\numexpr\XINTdigitsormax+4\expandafter.% \the\numexpr\XINTdigitsormax+3\expandafter.\expanded{% \XINT_tmpH.% \XINT_tmpG.% \expandafter}% \csname XINT_CosAux_series_a_iii\expandafter\endcsname \csname XINT_CosAux_series_b\expandafter\endcsname \csname XINT_CosAux_series_c_i\endcsname \XINT_tmpa 4 -2 -3 -4 6 4 2 Cos % \ifnum\XINTdigits>2 \XINT_tmpa 5 0 -2 -3 8 6 4 Cos \fi \ifnum\XINTdigits>4 \XINT_tmpa 6 2 0 -2 10 8 6 Cos \fi \ifnum\XINTdigits>7 \XINT_tmpa 7 5 2 0 12 10 8 Cos \fi \ifnum\XINTdigits>9 \XINT_tmpa 8 7 5 2 14 12 10 Cos \fi \ifnum\XINTdigits>12 \XINT_tmpa 9 10 7 5 16 14 12 Cos \fi \ifnum\XINTdigits>15 \XINT_tmpa 10 13 10 7 18 16 14 Cos \fi \ifnum\XINTdigits>18 \XINT_tmpa 11 16 13 10 20 18 16 Cos \fi \ifnum\XINTdigits>20 \XINT_tmpa 12 18 16 13 22 20 18 Cos \fi \ifnum\XINTdigits>24 \XINT_tmpa 13 22 18 16 24 22 20 Cos \fi \ifnum\XINTdigits>27 \XINT_tmpa 14 25 22 18 26 24 22 Cos \fi \ifnum\XINTdigits>30 \XINT_tmpa 15 28 25 22 28 26 24 Cos \fi \ifnum\XINTdigits>33 \XINT_tmpa 16 31 28 25 30 28 26 Cos \fi \ifnum\XINTdigits>36 \XINT_tmpa 17 34 31 28 32 30 28 Cos \fi \ifnum\XINTdigits>39 \XINT_tmpa 18 37 34 31 34 32 30 Cos \fi \ifnum\XINTdigits>42 \XINT_tmpa 19 40 37 34 36 34 32 Cos \fi \ifnum\XINTdigits>45 \XINT_tmpa 20 43 40 37 38 36 34 Cos \fi \ifnum\XINTdigits>49 \XINT_tmpa 21 47 43 40 40 38 36 Cos \fi \ifnum\XINTdigits>53 \XINT_tmpa 22 51 47 43 42 40 38 Cos \fi \ifnum\XINTdigits>57 \XINT_tmpa 23 55 51 47 44 42 40 Cos \fi \ifnum\XINTdigits>60 \XINT_tmpa 24 58 55 51 46 44 42 Cos \fi \let\XINT_tmpH\xint_undefined\let\XINT_tmpG\xint_undefined\let\XINT_tmpF\xint_undefined \let\XINT_tmpd\xint_undefined\let\XINT_tmpe\xint_undefined \def\XINT_SinAux_series#1% {% \expandafter\XINT_SinAux_series_a_iii \romannumeral0\XINTinfloatS[\XINTdigitsormax+4]{#1}\xint: }% \def\XINT_CosAux_series#1% {% \expandafter\XINT_CosAux_series_a_iii \romannumeral0\XINTinfloatS[\XINTdigitsormax+4]{#1}\xint: }% \fi % end of \XINTdigits>8 % \end{macrocode} % \subsubsection{The poor man approximate but speedier approach for Digits at most 8} % \begin{macrocode} \ifnum\XINTdigits<9 \def\XINT_SinAux_series#1% {% \the\numexpr\expandafter\XINT_SinAux_b\romannumeral0\xintiround9{#1}.[-9]% }% \def\XINT_SinAux_b#1.% {% ((((((((((((%(\xint_c_x^ix/-210) -4761905*#1/\xint_c_x^ix+\xint_c_x^ix)/% -156)*#1/\xint_c_x^ix+\xint_c_x^ix)/% -110)*#1/\xint_c_x^ix+\xint_c_x^ix)/% -72)*#1/\xint_c_x^ix+\xint_c_x^ix)/% -42)*#1/\xint_c_x^ix+\xint_c_x^ix)/% -20)*#1/\xint_c_x^ix+\xint_c_x^ix)/% -6)*#1/\xint_c_x^ix+\xint_c_x^ix }% \def\XINT_CosAux_series#1% {% \the\numexpr\expandafter\XINT_CosAux_b\romannumeral0\xintiround9{#1}.[-9]% }% \def\XINT_CosAux_b#1.% {% ((((((((((((((%(\xint_c_x^ix/-240) -4166667*#1/\xint_c_x^ix+\xint_c_x^ix)/% -182)*#1/\xint_c_x^ix+\xint_c_x^ix)/% -132)*#1/\xint_c_x^ix+\xint_c_x^ix)/% -90)*#1/\xint_c_x^ix+\xint_c_x^ix)/% -56)*#1/\xint_c_x^ix+\xint_c_x^ix)/% -30)*#1/\xint_c_x^ix+\xint_c_x^ix)/% -12)*#1/\xint_c_x^ix+\xint_c_x^ix)/% -2)*#1/\xint_c_x^ix+\xint_c_x^ix }% \fi % \end{macrocode} % \subsubsection{Declarations of the \cshn{@sin_aux()} and \cshn{@cos_aux()} functions} % \begin{macrocode} \def\XINT_flexpr_func_@sin_aux#1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINT_SinAux_series#3}}% }% \def\XINT_flexpr_func_@cos_aux#1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINT_CosAux_series#3}}% }% % \end{macrocode} % \subsubsection{\cshn{@sin_series()}, \cshn{@cos_series()}} % \begin{macrocode} \xintdeffloatfunc @sin_series(x) := x * @sin_aux(sqr(x));% \xintdeffloatfunc @cos_series(x) := @cos_aux(sqr(x));% % \end{macrocode} % \subsection{Range reduction for sine and cosine using degrees} % %\begin{lverb} % As commented in the package introduction, Range reduction is a demanding % domain and we handle it semi-satisfactorily. The main problem is that in % January 2019 I had done only support for degrees, and when I added radians I % used the most naive approach. But one can find worse: in 2019 I was % surprised to observe important divergences with Maple's results 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 even though the approach here is still naive, it % behaves much better. % % The @sind_rr() and @cosd_rr() sine and cosine "doing range reduction" are % coded directly at macro level via \xintSind and \xintCosd which will % dispatch to usage of the sine or cosine series, depending on case. % % Old note from 2019: attention that \xintSind and \xintCosd must be used % with a positive argument. % % We start with an auxiliary macro to reduce modulo 360 quickly. %\end{lverb} % \subsubsection{Low level modulo 360 helper macro \csh{XINT_mod_ccclx_i}} %\begin{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 that 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. %\end{lverb} % \begin{macrocode} \def\XINT_mod_ccclx_i #1.% {% \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.% {% (\XINT_mod_ccclx_ja {++}#2#1\XINT_mod_ccclx_jb 0000000\relax }% \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} %\begin{lverb} % Attention that \XINT_cclcx_e wants non negative input because \numexpr % division is not periodical ... %\end{lverb} % \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_rr()} function and its support macro \csh{xintSind}} % \begin{macrocode} \def\XINT_flexpr_func_@sind_rr #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one{\romannumeral`&&@\xintSind#3}}% }% % \end{macrocode} %\begin{lverb} % old comment: Must be f-expandable for nesting macros from \xintNewExpr % % This is where the prize of using the same macros for two distinct use cases % has serious disadvantages. The reason of Digits+12 is only to support an % input which contains a multiplication by @oneRadian with its extended % digits. % % Then we do a somewhat strange truncation to a fixed point of fractional % digits, which is ok in the "Degrees" case, but causes issues of its own in % the "Radians" case. Please consider this whole thing as marked for future % improvement, when times allows. % % ATTENTION \xintSind ONLY FOR POSITIVE ARGUMENTS %\end{lverb} % \begin{macrocode} \def\XINT_tmpa #1.{% \def\xintSind##1% {% \romannumeral`&&@\expandafter\xintsind\romannumeral0\XINTinfloatS[#1]{##1}}% }\expandafter\XINT_tmpa\the\numexpr\XINTdigitsormax+12.% \def\xintsind #1[#2#3]% {% \xint_UDsignfork #2\XINT_sind -\XINT_sind_int \krof#2#3.#1..% }% \def\XINT_tmpa #1.{% \def\XINT_sind ##1.##2.% {% \expandafter\XINT_sind_a \romannumeral0\xinttrunc{#1}{##2[##1]}% }% }\expandafter\XINT_tmpa\the\numexpr\XINTdigitsormax+5.% \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.% {% \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.% }% \def\XINT_tmpa #1.#2.{% \def\XINT_sind_A##1.##2.% {% \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@sin_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{##1.##2}#2}}% }% \def\XINT_sind_B_n-##1.##2.% {% \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@cos_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{\xintSub{##1[0]}{.##2}}#2}}% }% \def\XINT_sind_B_p##1.##2.% {% \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@cos_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{##1.##2}#2}}% }% \def\XINT_sind_C_n-##1.##2.% {% \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@sin_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{\xintSub{##1[0]}{.##2}}#2}}% }% \def\XINT_sind_C_p##1.##2.% {% \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@sin_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{##1.##2}#2}}% }% \def\XINT_sind_D_n-##1.##2.% {% \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@cos_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{\xintSub{##1[0]}{.##2}}#2}}% }% \def\XINT_sind_D_p##1.##2.% {% \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@cos_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{##1.##2}#2}}% }% \def\XINT_sind_E-##1.##2.% {% \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@sin_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{\xintSub{##1[0]}{.##2}}#2}}% }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax+4\expandafter.% \romannumeral`&&@\xintbarefloateval @oneDegree\relax.% \def\XINT_sind_B#1{\xint_UDsignfork#1\XINT_sind_B_n-\XINT_sind_B_p\krof #1}% \def\XINT_sind_C#1{\xint_UDsignfork#1\XINT_sind_C_n-\XINT_sind_C_p\krof #1}% \def\XINT_sind_D#1{\xint_UDsignfork#1\XINT_sind_D_n-\XINT_sind_D_p\krof #1}% % \end{macrocode} % \subsubsection{\cshn{@cosd_rr()} function and its support macro \csh{xintCosd}} % \begin{macrocode} \def\XINT_flexpr_func_@cosd_rr #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one{\romannumeral`&&@\xintCosd#3}}% }% % \end{macrocode} %\begin{lverb} % ATTENTION ONLY FOR POSITIVE ARGUMENTS %\end{lverb} % \begin{macrocode} \def\XINT_tmpa #1.{% \def\xintCosd##1% {% \romannumeral`&&@\expandafter\xintcosd\romannumeral0\XINTinfloatS[#1]{##1}}% }\expandafter\XINT_tmpa\the\numexpr\XINTdigitsormax+12.% \def\xintcosd #1[#2#3]% {% \xint_UDsignfork #2\XINT_cosd -\XINT_cosd_int \krof#2#3.#1..% }% \def\XINT_tmpa #1.{% \def\XINT_cosd ##1.##2.% {% \expandafter\XINT_cosd_a \romannumeral0\xinttrunc{#1}{##2[##1]}% }% }\expandafter\XINT_tmpa\the\numexpr\XINTdigitsormax+5.% \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} %\begin{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. %\end{lverb} % \begin{macrocode} \def\XINT_tmpa#1.#2.{% \def\XINT_cosd_A##1.##2.% {% \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@cos_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{##1.##2}#2}}% }% \def\XINT_cosd_B_n-##1.##2.% {% \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@sin_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{\xintSub{##1[0]}{.##2}}#2}}% }% \def\XINT_cosd_B_p##1.##2.% {% \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@sin_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{##1.##2}#2}}% }% \def\XINT_cosd_C_n-##1.##2.% {% \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@cos_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{\xintSub{##1[0]}{.##2}}#2}}% }% \def\XINT_cosd_C_p##1.##2.% {% \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@cos_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{##1.##2}#2}}% }% \def\XINT_cosd_D_n-##1.##2.% {% \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@sin_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{\xintSub{##1[0]}{.##2}}#2}}% }% \def\XINT_cosd_D_p##1.##2.% {% \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@sin_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{##1.##2}#2}}% }% \def\XINT_cosd_E-##1.##2.% {% \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_@cos_series\expandafter {\romannumeral0\XINTinfloat[#1]{\xintMul{\xintSub{##1[0]}{.##2}}#2}}% }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax+4\expandafter.% \romannumeral`&&@\xintbarefloateval @oneDegree\relax.% \def\XINT_cosd_B#1{\xint_UDsignfork#1\XINT_cosd_B_n-\XINT_cosd_B_p\krof #1}% \def\XINT_cosd_C#1{\xint_UDsignfork#1\XINT_cosd_C_n-\XINT_cosd_C_p\krof #1}% \def\XINT_cosd_D#1{\xint_UDsignfork#1\XINT_cosd_D_n-\XINT_cosd_D_p\krof #1}% % \end{macrocode} % \subsection{\cshn{@sind()}, \cshn{@cosd()}} %\begin{lverb} % The -45 is stored internally as -45/1[0] from the action of the unary minus % operator, which float macros then parse faster. The 45e0 is to let it become % 45[0] and not simply 45. % % Here and below the \ifnum\XINTdigits>8 45\else60\fi will all be resolved % at time of definition. This is the charm and power of expandable parsers! %\end{lverb} % \begin{macrocode} \xintdeffloatfunc @sind(x) := (x)?? {(x>=-\ifnum\XINTdigits>8 45\else60\fi)? {@sin_series(x*@oneDegree)} {-@sind_rr(-x)} } {0e0} {(x<=\ifnum\XINTdigits>8 45\else60\fi e0)? {@sin_series(x*@oneDegree)} {@sind_rr(x)} } ;% \xintdeffloatfunc @cosd(x) := (x)?? {(x>=-\ifnum\XINTdigits>8 45\else60\fi)? {@cos_series(x*@oneDegree)} {@cosd_rr(-x)} } {1e0} {(x<=\ifnum\XINTdigits>8 45\else60\fi e0)? {@cos_series(x*@oneDegree)} {@cosd_rr(x)} } ;% % \end{macrocode} % \subsection{\cshn{@sin()}, \cshn{@cos()}} %\begin{lverb} % For some reason I did not define sin() and cos() in January 2019 ?? % % The sub \xintexpr x*@oneRadian\relax means that the multiplication will be % done exactly @oneRadian having its 12 extra digits (and x its 4 extra % digits), before being rounded in entrance of \xintSind, respectively % \xintCosd, to P+12 mantissa. % % The strange 79e-2 could be 0.79 which would give 79[-2] internally too. %\end{lverb} % \begin{macrocode} \xintdeffloatfunc @sin(x):= (abs(x)<\ifnum\XINTdigits>8 79e-2\else1e0\fi)? {@sin_series(x)} {(x)?? {-@sind_rr(-\xintexpr x*@oneRadian\relax)} {0} {@sind_rr(\xintexpr x*@oneRadian\relax)} } ;% \xintdeffloatfunc @cos(x):= (abs(x)<\ifnum\XINTdigits>8 79e-2\else1e0\fi)? {@cos_series(x)} {@cosd_rr(abs(\xintexpr x*@oneRadian\relax))} ;% % \end{macrocode} % \subsection{\cshn{@sinc()}} %\begin{lverb} % Should I also consider adding (1-cos(x))/(x^2/2) ? it is sinc^2(x/2) but % avoids a square. %\end{lverb} % \begin{macrocode} \xintdeffloatfunc @sinc(x):= (abs(x)<\ifnum\XINTdigits>8 79e-2\else1e0\fi) ? {@sin_aux(sqr(x))} {@sind_rr(\xintexpr abs(x)*@oneRadian\relax)/abs(x)} ;% % \end{macrocode} % \subsection{\cshn{@tan()}, \cshn{@tand()}, \cshn{@cot()}, \cshn{@cotd()}} %\begin{lverb} % The 0 in cot(x) is a dummy place holder. We don't have a notion of % Inf yet. %\end{lverb} % \begin{macrocode} \xintdeffloatfunc @tand(x):= @sind(x)/@cosd(x);% \xintdeffloatfunc @cotd(x):= @cosd(x)/@sind(x);% \xintdeffloatfunc @tan(x) := (x)?? {(x>-\ifnum\XINTdigits>8 79e-2\else1e0\fi)? {@sin(x)/@cos(x)} {-@cotd(\xintexpr9e1+x*@oneRadian\relax) } } {0e0} {(x<\ifnum\XINTdigits>8 79e-2\else1e0\fi)? {@sin(x)/@cos(x)} {@cotd(\xintexpr9e1-x*@oneRadian\relax)} } ;% \xintdeffloatfunc @cot(x) := (abs(x)<\ifnum\XINTdigits>8 79e-2\else1e0\fi)? {@cos(x)/@sin(x)} {(x)?? {-@tand(\xintexpr9e1+x*@oneRadian\relax)} {0} {@tand(\xintexpr9e1-x*@oneRadian\relax)} };% % \end{macrocode} % \subsection{\cshn{@sec()}, \cshn{@secd()}, \cshn{@csc()}, \cshn{@cscd()}} % \begin{macrocode} \xintdeffloatfunc @sec(x) := inv(@cos(x));% \xintdeffloatfunc @csc(x) := inv(@sin(x));% \xintdeffloatfunc @secd(x):= inv(@cosd(x));% \xintdeffloatfunc @cscd(x):= inv(@sind(x));% % \end{macrocode} % \subsection{Core routine for inverse trigonometry} % %\begin{lverb} % I always liked very much the general algorithm whose idea I found % in 2019. But it costs a square root plus a sine plus a cosine all % at target precision. For the arctangent the square root will be % avoided by a trick. (memo: it is replaced by a division and I am not so sure % now this is advantageous in fact) % % And now I like it even more as I have re-done the first step entirely % in a single \numexpr... Thus the inverse trigonometry got a serious % improvement at 1.4e... % % Here is the idea. We have 0<t<sqrt(2)/2 and we want a = Arcsin t. % % Imagine we have some very good approximation b = a - h. We know b, % and don't know yet h. No problem h is a-b so sin(h)=sin(a)cos(b)- % cos(a)sin(b). And we know everything here: sin(a) is t, cos(a) is % u = sqrt(1-t^2), and we can compute cos(b) and sin(b). % % I said h was small so the computation of sin(a)cos(b)-cos(a)sin(b) will % involve a lot of cancellation, no problem with xint, as it knows how to % compute exactly... and if we wanted to go very low level we could do % cos(a)sin(b) paying attention only on least significant digits. % % Ok, so we have sin(h), but h is small, so the series of Arcsine can be used % with few terms! % % In fact h will be at most of the order of 1e-9, so it is no problem to % simply replace sin(h) with h if the target precision is 16 ! % % Ok, so how do we obtain b, the good approximation to Arcsin t ? Simply by % using its Taylor series, embedded in a single \numexpr working with nine % digits numbers... I like this one! Notice that it reminisces with my % questioning about how to best do Horner like for sine and cosine. Here in % \numexpr we can only manipulate whole integers and simply can't do things % such as ...)*x + 5/112)*x + 3/40)*x + 1/6)*x +1 .... But I found another % way, see the code, which uses extensively the "scaling" operations in % \numexpr. % % I have not proven rigorously that b-a is always less or equal in absolute % value than 1e-9, but it is possible for example in Python to program it and % go through all possible (less than) 1e9 inputs and check what happens. % % Very small inputs will give b=0 (first step is a fixed point rounding of t to % nine fractional digits, so this rounding gives zero for input <0.5e-9, % others will give b=t, because the arcsine numexpr will end up with % 1000000000 (last time I checked that was for t a bit less than 5e-5, % the latter gives 1000000001). % All seems to work perfectly fine, in practice... % % %\end{lverb} % %\begin{lverb} % First we let the @sin_aux() and @cos_aux() functions be usable in exact % \xintexpr context. % % The @asin_II() function will be used only for Digits>16. %\end{lverb} % \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 \ifnum\XINTdigits>16 \def\XINT_flexpr_func_@asin_II#1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINT_Arcsin_II_a#3}}% }% \def\XINT_tmpc#1.% {% \def\XINT_Arcsin_II_a##1% {% \expandafter\XINT_Arcsin_II_c_i\romannumeral0\XINTinfloatS[#1]{##1}% }% \def\XINT_Arcsin_II_c_i##1[##2]% {% \xintAdd{1/1[0]}{##1/6[##2]}% }% }% \expandafter\XINT_tmpc\the\numexpr\XINTdigitsormax-14.% \fi \ifnum\XINTdigits>34 \def\XINT_tmpc#1.#2.#3.#4.% {% \def\XINT_Arcsin_II_a##1% {% \expandafter\XINT_Arcsin_II_a_iii\romannumeral0\XINTinfloatS[#1]{##1}\xint: }% \def\XINT_Arcsin_II_a_iii##1\xint: {% \expandafter\XINT_Arcsin_II_b\romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_Arcsin_II_b##1\xint: {% \expandafter\XINT_Arcsin_II_c_i \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{#3}{##1}}}\xint: }% \def\XINT_Arcsin_II_c_i##1\xint:##2\xint: {% \xintAdd{1/1[0]}{\XINTinFloat[#1]{\xintMul{##1}{##2}}}% }% }% \expandafter\XINT_tmpc \the\numexpr\XINTdigitsormax-14\expandafter.% \the\numexpr\XINTdigitsormax-32\expandafter.\expanded{% \XINTinFloat[\XINTdigitsormax-32]{3/40[0]}.% \XINTinFloat[\XINTdigitsormax-14]{1/6[0]}.% }% \fi \ifnum\XINTdigits>52 \def\XINT_tmpc#1.#2.#3.#4.#5.% {% \def\XINT_Arcsin_II_a_iii##1\xint: {% \expandafter\XINT_Arcsin_II_a_iv\romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_Arcsin_II_a_iv##1\xint: {% \expandafter\XINT_Arcsin_II_b\romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_Arcsin_II_b##1\xint: {% \expandafter\XINT_Arcsin_II_c_ii \romannumeral0\xintadd{#4}{\XINTinfloat[#2]{\xintMul{#3}{##1}}}\xint: }% \def\XINT_Arcsin_II_c_ii##1\xint:##2\xint: {% \expandafter\XINT_Arcsin_II_c_i \romannumeral0\xintadd{#5}{\XINTinFloat[#1]{\xintMul{##1}{##2}}}\xint: }% }% \expandafter\XINT_tmpc \the\numexpr\XINTdigitsormax-32\expandafter.% \the\numexpr\XINTdigitsormax-50\expandafter.\expanded{% \XINTinFloat[\XINTdigitsormax-50]{5/112[0]}.% \XINTinFloat[\XINTdigitsormax-32]{3/40[0]}.% \XINTinFloat[\XINTdigitsormax-14]{1/6[0]}.% }% \fi \def\XINT_flexpr_func_@asin_I#1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINT_Arcsin_I#3}}% }% \def\XINT_Arcsin_I#1% {% \the\numexpr\expandafter\XINT_Arcsin_Ia\romannumeral0\xintiround9{#1}.% }% \def\XINT_Arcsin_Ia#1.% {% (\expandafter\XINT_Arcsin_Ib\the\numexpr#1*#1/\xint_c_x^ix.)*% #1/\xint_c_x^ix[-9]% }% \def\XINT_Arcsin_Ib#1.% {%(((((((((((((((( % 3481/3660)*#1/\xint_c_x^ix+\xint_c_x^ix)*% % 3249/3422)*#1/\xint_c_x^ix+\xint_c_x^ix)*% % 3025/3192)*#1/\xint_c_x^ix+\xint_c_x^ix)*% % 2809/2970)*#1/\xint_c_x^ix+\xint_c_x^ix)*% % 2601/2756)*#1/\xint_c_x^ix+\xint_c_x^ix)*% % 2401/2550)*#1/\xint_c_x^ix+\xint_c_x^ix)*% % 2209/2352)*#1/\xint_c_x^ix+\xint_c_x^ix)*% % 2025/2162)*#1/\xint_c_x^ix+\xint_c_x^ix)*% ((((((((((((((((((((((((((((((((((((((((((% %(\xint_c_x^ix*1849/1980)*% 933838384*#1/\xint_c_x^ix+\xint_c_x^ix)*% 1681/1806)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 1521/1640)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 1369/1482)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 1225/1332)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 1089/1190)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 961/1056)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 841/930)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 729/812)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 625/702)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 529/600)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 441/506)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 361/420)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 289/342)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 225/272)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 169/210)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 121/156)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 81/110)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 49/72)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 25/42)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 9/20)*#1/\xint_c_x^ix+\xint_c_x^ix)*% 1/6)*#1/\xint_c_x^ix+\xint_c_x^ix }% \ifnum\XINTdigits>16 \xintdeffloatfunc @asin_o(D, T) := T + D*@asin_II(sqr(D));% \xintdeffloatfunc @asin_n(V, T, t, u) :=% @asin_o(\xintexpr t*@cos_aux(V) - u*T*@sin_aux(V)\relax, T);% \else \xintdeffloatfunc @asin_n(V, T, t, u) :=% \xintexpr t*@cos_aux(V) - u*T*@sin_aux(V)\relax + T;% \fi \xintdeffloatfunc @asin_m(T, t, u) := @asin_n(sqr(T), T, t, u);% \xintdeffloatfunc @asin_l(t, u) := @asin_m(@asin_I(t), t, u);% % \end{macrocode} % \subsection{\cshn{@asin()}, \cshn{@asind()}} %\begin{lverb} % Only non-negative arguments t and u for asin_a(t,u), and asind_a(t,u). %\end{lverb} % \begin{macrocode} \xintdeffloatfunc @asin_a(t, u) := (t<u)? {@asin_l(t, u)} {@Piover2 - @asin_l(u, t)} ;% \xintdeffloatfunc @asind_a(t, u):= (t<u)? {@asin_l(t, u) * @oneRadian} {9e1 - @asin_l(u, t) * @oneRadian} ;% \xintdeffloatfunc @asin(t) := (t)?? {-@asin_a(-t, sqrt(1e0-sqr(t)))} {0e0} {@asin_a(t, sqrt(1e0-sqr(t)))} ;% \xintdeffloatfunc @asind(t) := (t)?? {-@asind_a(-t, sqrt(1e0-sqr(t)))} {0e0} {@asind_a(t, sqrt(1e0-sqr(t)))} ;% % \end{macrocode} % \subsection{\cshn{@acos()}, \cshn{@acosd()}} % \begin{macrocode} \xintdeffloatfunc @acos(t) := @Piover2 - @asin(t);% \xintdeffloatfunc @acosd(t):= 9e1 - @asind(t);% % \end{macrocode} % \subsection{\cshn{@atan()}, \cshn{@atand()}} %\begin{lverb} % Uses same core routine asin_l() as for asin(), but avoiding a square-root % extraction in preparing its arguments (to the cost of computing an inverse, % rather). % % radians %\end{lverb} % \begin{macrocode} \xintdeffloatfunc @atan_b(t, w, z):= 5e-1 * (w< 0)? {@Pi - @asin_a(2e0*z * t, -w*z)} {@asin_a(2e0*z * t, w*z)} ;% \xintdeffloatfunc @atan_a(t, T) := @atan_b(t, 1e0-T, inv(1e0+T));% \xintdeffloatfunc @atan(t):= (t)?? {-@atan_a(-t, sqr(t))} {0} {@atan_a(t, sqr(t))} ;% % \end{macrocode} %\begin{lverb} % degrees %\end{lverb} % \begin{macrocode} \xintdeffloatfunc @atand_b(t, w, z) := 5e-1 * (w< 0)? {18e1 - @asind_a(2e0*z * t, -w*z)} {@asind_a(2e0*z * t, w*z)} ;% \xintdeffloatfunc @atand_a(t, T) := @atand_b(t, 1e0-T, inv(1e0+T));% \xintdeffloatfunc @atand(t) := (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()}} %\begin{lverb} % Arg(x,y) function from -π (excluded) to +π (included) %\end{lverb} % \begin{macrocode} \xintdeffloatfunc @Arg(x, y):= (y>x)? {(y>-x)? {@Piover2 - @atan(x/y)} {(y<0)? {-@Pi + @atan(y/x)} {@Pi + @atan(y/x)} } } {(y>-x)? {@atan(y/x)} {-@Piover2 + @atan(x/-y)} } ;% % \end{macrocode} %\begin{lverb} % atan2(y,x) = Arg(x,y) ... (some people have atan2 with arguments reversed % but the convention here seems the most often encountered) %\end{lverb} % \begin{macrocode} \xintdeffloatfunc @atan2(y,x) := @Arg(x, y);% % \end{macrocode} %\begin{lverb} % Argd(x,y) function from -180 (excluded) to +180 (included) %\end{lverb} % \begin{macrocode} \xintdeffloatfunc @Argd(x, y):= (y>x)? {(y>-x)? {9e1 - @atand(x/y)} {(y<0)? {-18e1 + @atand(y/x)} {18e1 + @atand(y/x)} } } {(y>-x)? {@atand(y/x)} {-9e1 + @atand(x/-y)} } ;% % \end{macrocode} %\begin{lverb} % atan2d(y,x) = Argd(x,y) %\end{lverb} % \begin{macrocode} \xintdeffloatfunc @atan2d(y,x) := @Argd(x, y);% % \end{macrocode} %\begin{lverb} % pArg(x,y) function from 0 (included) to 2π (excluded) % I hesitated between pArg, Argpos, and Argplus. Opting for pArg in the end. %\end{lverb} % \begin{macrocode} \xintdeffloatfunc @pArg(x, y):= (y>x)? {(y>-x)? {@Piover2 - @atan(x/y)} {@Pi + @atan(y/x)} } {(y>-x)? {(y<0)? {@twoPi + @atan(y/x)} {@atan(y/x)} } {@threePiover2 + @atan(x/-y)} } ;% % \end{macrocode} %\begin{lverb} % pArgd(x,y) function from 0 (included) to 360 (excluded) %\end{lverb} % \begin{macrocode} \xintdeffloatfunc @pArgd(x, y):=(y>x)? {(y>-x)? {9e1 - @atan(x/y)*@oneRadian} {18e1 + @atan(y/x)*@oneRadian} } {(y>-x)? {(y<0e0)? {36e1 + @atan(y/x)*@oneRadian} {@atan(y/x)*@oneRadian} } {27e1 + @atan(x/-y)*@oneRadian} } ;% % \end{macrocode} % \subsection{Restore \cs{xintdeffloatfunc} to its normal state, with no extra digits} % \begin{macrocode} \expandafter\let \csname XINT_flexpr_exec_+\expandafter\endcsname \csname XINT_flexpr_exec_+_\endcsname \expandafter\let \csname XINT_flexpr_exec_-\expandafter\endcsname \csname XINT_flexpr_exec_-_\endcsname \expandafter\let \csname XINT_flexpr_exec_*\expandafter\endcsname \csname XINT_flexpr_exec_*_\endcsname \expandafter\let \csname XINT_flexpr_exec_/\expandafter\endcsname \csname XINT_flexpr_exec_/_\endcsname \expandafter\let \csname XINT_flexpr_func_sqr\expandafter\endcsname \csname XINT_flexpr_sqrfunc\endcsname \expandafter\let \csname XINT_flexpr_func_sqrt\expandafter\endcsname \csname XINT_flexpr_sqrtfunc\endcsname \expandafter\let \csname XINT_flexpr_func_inv\expandafter\endcsname \csname XINT_flexpr_invfunc\endcsname % \end{macrocode} % \subsection{Let the functions be known to the \cshnolabel{xintexpr} parser} %\begin{lverb} % We use here float_dgtormax which uses the smaller of Digits and 64. %\end{lverb} % \begin{macrocode} \edef\XINTinFloatdigitsormax{\noexpand\XINTinFloat[\the\numexpr\XINTdigitsormax]}% \edef\XINTinFloatSdigitsormax{\noexpand\XINTinFloatS[\the\numexpr\XINTdigitsormax]}% \xintFor #1 in {sin, cos, tan, sec, csc, cot, asin, acos, atan}\do {% \xintdeffloatfunc #1(x) := float_dgtormax(@#1(x));% \xintdeffloatfunc #1d(x) := float_dgtormax(@#1d(x));% \xintdeffunc #1(x) := float_dgtormax(\xintfloatexpr @#1(sfloat_dgtormax(x))\relax);% \xintdeffunc #1d(x):= float_dgtormax(\xintfloatexpr @#1d(sfloat_dgtormax(x))\relax);% }% \xintFor #1 in {Arg, pArg, atan2}\do {% \xintdeffloatfunc #1(x, y) := float_dgtormax(@#1(x, y));% \xintdeffloatfunc #1d(x, y) := float_dgtormax(@#1d(x, y));% \xintdeffunc #1(x, y) := float_dgtormax(\xintfloatexpr @#1(sfloat_dgtormax(x), sfloat_dgtormax(y))\relax);% \xintdeffunc #1d(x, y):= float_dgtormax(\xintfloatexpr @#1d(sfloat_dgtormax(x), sfloat_dgtormax(y))\relax);% }% \xintdeffloatfunc sinc(x):= float_dgtormax(@sinc(x));% \xintdeffunc sinc(x):= float_dgtormax(\xintfloatexpr @sinc(sfloat_dgtormax(x))\relax);% % \end{macrocode} % \subsection{Synonyms: \cshn{@tg()}, \cshn{@cotg()}} %\begin{lverb} % These are my childhood notations and I am attached to them. In % radians only, and for \xintfloateval only. We skip some overhead here by using a \let at core level. %\end{lverb} % \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{Final clean-up} %\begin{lverb} % Restore used dummy variables to their status prior to the package reloading. % On first loading this is not needed, but I have not added a way to check % here whether this a first loading or a re-loading. %\end{lverb} % \begin{macrocode} \xintdefvar twoPi := float_dgtormax(@twoPi);% \xintdefvar threePiover2 := float_dgtormax(@threePiover2);% \xintdefvar Pi := float_dgtormax(@Pi);% \xintdefvar Piover2 := float_dgtormax(@Piover2);% \xintdefvar oneDegree := float_dgtormax(@oneDegree);% \xintdefvar oneRadian := float_dgtormax(@oneRadian);% \xintunassignvar{@twoPi}\xintunassignvar{@threePiover2}% \xintunassignvar{@Pi}\xintunassignvar{@Piover2}% \xintunassignvar{@oneRadian}\xintunassignvar{@oneDegree}% \xintFor* #1 in {iDTVtuwxyzX}\do{\xintrestorevariable{#1}}% \XINTtrigendinput% % \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; sentence-end-double-space: t; eval: (auto-fill-mode -1); fill-paragraph-function: nil; -*- % \clearpage\csname xintlognameUp\endcsname % \let\MakePrivateLetters\xintMakePrivateLetters % \section{Package \xintlognameimp implementation} % \RaisedLabel{sec:logimp} % \etocarticlestylenomarks % \etocsetnexttocdepth {subsubsection} % % \localtableofcontents % % \etocsettocstyle{}{} % % In 2019, at 1.3e release I almost included extended precision for log() and % exp() but the time I could devote to xint expired. Finally, at long last, % (and I had procrastinated far more than the two years since 2019) the 1.4e % release in April 2021 brings log10(), pow10(), log(), pow() to P=Digits % precision: up to 62 digits with at least (said roughly) 99\% chances of % correct rounding (the design is targeting less than about 0.005ulp distance % to mathematical value, before rounding). % % Implementation is EXPERIMENTAL. % % For up to Digits=8, it is simply based upon the poormanlog package. The % probability of correct rounding will be less than for Digits>8, especially % in the cases of Digits=8 and to a lesser extent Digits=7. And, for all % Digits<=8, there is a systematic loss of rounding precision in the floating % point sense in the case of log10(x) for inputs close to 1: % %\begin{lverb} % % Summary of limitations of log10() and pow10() in the case of Digits<=8: %( - For log10(x) with x near 1, the precision of output as floating point& % will be mechanically reduced from the fact that this is based on a fixed& % point result, for example log10(1.0011871) is produced as 5.15245e-4,& % which stands for 0.000515145 having indeed 9 correct fractional digits,& % but only 6 correct digits in the floating point sense.& % % This feature affects the entire range Digits<=8. %: - Even if limiting to inputs x with 1.26<x<10 (1.26 is a bit more than& % 10^0.1 hence its choice as lower bound), the poormanlog documentation& % mentions an absolute error possibly up to about 1e-9. In practice a& % test of 10000 random inputs 1.26<x<10 revealed 9490 correctly rounded& % log10(x) at 8 digits (and the 510 non-correctly rounded ones with an error& % of 1 in last digit compared to correct rounding). So correct rounding& % achieved only in about 95$% of cases here.& % % At 7 digits the same 10000 random& % inputs are correctly rounded in 99.4$% of cases, and at 6 digits it is& % 99.94$% of cases.& % % Again with Digits=8, the log10(i) for i in 1..1000 are all correctly& % rounded to 8 digits with two exceptions: log10(3) and log10(297) with a& % 1ulp error. And the log(i) in the same range are correctly rounded to 8& % digits with the 15 exceptions i= 99, 105, 130, 178, 224, 329, 446, 464,& % 564, 751, 772, 777, 886, 907, 962, whose natural logarithms& % are obtained with a 1ulp error. %: - Regarding the computation of 10^x, I obtained for -1<x<1 the following& % with 10000 random inputs: 518/10000 errors at 1ulp, 60/10000, and 8/10000,& % at respectively Digits = 8, 7, 6 so chances of correct rounding are& % respectively about 95$%, 99.4$% and more than 99.9$%. %) %\end{lverb} % % Despite its limitations the poormanlog based approach used for Digits up to % 8 has the advantage of speed (at least 8X compared to working with 16 % digits) and is largely precise enough for plots. % % For 9 digits or more, the observed precision in some random tests appears to % be at least of 99.9\% chances of correct rounding, and the log10(x) with x % near 1 are correctly (if not really efficiently) handled in the floating % point sense for the output. The poormanlog approximate log10() is still used % to boot-strap the process, generally. The pow10() at Digits=9 or more is % done independently of poormanlog. % % All of this is done on top of my 2013 structures for floating point % computations which have always been marked as provisory and rudimentary and % instills intrinsic non-efficiency: % %\begin{lverb} %( - no internal data format for a ``floating point number at P digits'', %: - mantissa lengths are again and again computed, %: - digits are not pre-organized say in blocks of 4 by 4 or 8 by 8, %: - floating point multiplication is done via an *exact* multiplication, then& % rounding to P digits! %) %\end{lverb} % % This is legacy of the fact that the project was initially devoted to big % integers only, but in the weeks that followed its inception in March 2013 I % added more and more functionalities without a well laid out preliminary % plan. % % Anyway, for years I have felt a better foundation would help achieve at % least something such as 2X gain (perhaps the last item by itself, if % improved upon, would bring most of such 2X gain?) % % I did not try to optimize for the default 16 digits, the goal being more of % having a general scalable structure in place and there is no difficulty to % go up to 100 digits precision if one stores extended pre-computed constants % and increases the length of the ``series'' support. % % Apart from log(10) and its inverse, no other logarithms are stored or % pre-computed: the rest of the stored data is the same for pow10() and % log10() and consists of the fractional powers 10\string^±0.i, % 10\string^±0.0i, ..., 10\string^±0.00000i at P+5 and also at P+10 digits. % % In order to reduce the loading time of the package the inverses are not % computed internally (as this would require costly divisions) but simply % hard-coded with enough digits to cover the allowed Digits range. % % % \subsection{Catcodes, \protect\eTeX{} and reload detection} % \changed{1.4l} %\begin{lverb} % Silly paranoid modification of \z in case { and } do not have their % normal catcodes when xintlog.sty is reloaded (initial loading via % xintexpr.sty does not need this), to define \XINTlogendinput there and not % after the \endgroup from \z has already restored possibly bad catcodes. % % % 1.4l handles much better the situation with \usepackage{xintlog} without % previous loading of xintexpr (or same with \input and etex). Instead of % aborting with a message (which actually was wrong with LaTeX since 1.4e, % mentioning \input in place of \usepackage), it will initiate loading % xintexpr itself. This required an adaptation at end of xintexpr and some % care to not leave bad catcodes. % %\end{lverb} % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% \catcode13=5 % ^^M \endlinechar=13 % \catcode123=1 % { \catcode125=2 % } \catcode64=11 % @ \catcode35=6 % # \catcode44=12 % , \catcode46=12 % . \catcode58=12 % : \catcode94=7 % ^ \def\empty{}\def\space{ }\newlinechar10 \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintlog.sty\endcsname \expandafter\let\expandafter\w\csname ver@xintexpr.sty\endcsname \expandafter \ifx\csname PackageWarningNoLine\endcsname\relax \def\y#1#2{\immediate\write128{^^JPackage #1 Warning:^^J% \space\space\space\space#2.^^J}}% \else \def\y#1#2{\PackageWarningNoLine{#1}{#2}}% \fi \expandafter \ifx\csname numexpr\endcsname\relax \y{xintlog}{\numexpr not available, aborting input}% \def\z{\endgroup\endinput}% \else \ifx\w\relax % xintexpr.sty not yet loaded. \edef\MsgBrk{^^J\space\space\space\space}% \y{xintlog}% {\ifx\x\empty xintlog should not be loaded directly\MessageBreak The correct way is \string\usepackage{xintexpr}.\MessageBreak Will try that now% \else First loading of xintlog.sty should be via \string\input\space xintexpr.sty\relax\MsgBrk Will try that now% \fi }% \ifx\x\empty \def\z{\endgroup\RequirePackage{xintexpr}\endinput}% \else \def\z{\endgroup\input xintexpr.sty\relax\endinput}% \fi \else \def\z{\endgroup\edef\XINTlogendinput{\XINTrestorecatcodes\noexpand\endinput}}% \fi \fi \z% % \end{macrocode} %\begin{lverb} % Here we set catcodes to the package values, the current settings % having been saved in the \XINTlogendinput macro. We arrive here only if % xintlog is either loaded from xintexpr or is being reloaded via an \input % from \xintreloadxintlog. Else we aborted right before via \endinput and do % not modify catcodes. As xintexpr inputs xintlog.sty at a time the catcode % configuration is already the package one we pay attention to not use % \XINTsetupcatcodes which would badly redefine \XINTrestorecatcodesendinput % as executed at end of xintexpr.sty. There is slight inefficiency here to % execute \XINTsetcatcodes when xintexpr initiated the xintlog loading, but % let's live with it. %\end{lverb} % \begin{macrocode} \XINTsetcatcodes% % \end{macrocode} % \subsection{Library identification} % If the file has already been loaded, let's skip the |\ProvidesPackage|. % Else let's do it and set a flag to indicate loading happened at least once % already. % \changed{1.4l} % Message also to Terminal not only log file. % \begin{macrocode} \ifcsname xintlibver@log\endcsname \expandafter\xint_firstoftwo \else \expandafter\xint_secondoftwo \fi {\immediate\write128{Reloading xintlog library using Digits=\xinttheDigits.}}% {\expandafter\gdef\csname xintlibver@log\endcsname{2022/06/10 v1.4m}% \XINT_providespackage \ProvidesPackage{xintlog}% [2022/06/10 v1.4m Logarithms and exponentials for xintexpr (JFB)]% }% % \end{macrocode} % \subsection{\csh{xintreloadxintlog}} %\begin{lverb} % Now needed at 1.4e. % %\end{lverb} % \begin{macrocode} \def\xintreloadxintlog{\input xintlog.sty }% % \end{macrocode} % \subsection{Loading the \cshn{poormanlog} package} %\begin{lverb} % Attention to the catcode regime when loading poormanlog. % % % Also, for xintlog.sty to be multiple-times loadable, we need to avoid using % LaTeX's \RequirePackage twice. % %\end{lverb} % \begin{macrocode} \xintexprSafeCatcodes \unless\ifdefined\XINTinFloatPowTen \ifdefined\RequirePackage \RequirePackage{poormanlog}% \else \input poormanlog.tex \fi\fi \xintexprRestoreCatcodes % \end{macrocode} % \subsection{Macro layer on top of the poormanlog package} %\begin{lverb} % This was moved here with some macro renames from xintfrac on occasion % of 1.4e release. % % Breaking changes at 1.4e: % %( - \poormanloghack now a no-op (removed at 1.4m), %: - \xintLog was used for \xinteval and differed slightly from its& % counterpart used for \xintfloateval, the latter float-rounded& % to P = Digits, the former did not and kept completly meaning-less& % digits in output. Both macros now replaced by a \PoorManLog& % which will always float round the output to P = Digits. Because xint& % does not really implement a fixed point interface anyhow. %: - \xintExp (used in \xinteval) and another macro (used in \xintfloateval)& % did not use a sufficiently long approximation to 1/log(10) to& % support precisely enough exp(x) if output of the order of 10^10000 for& % example, (last two digits wrong then)& % and situation became worse for very high values such as exp(1e8)& % which had only 4 digits correct. % The new \PoorManExp which replaces them is more careful... and for& % example exp(12345678) obtains correct rounding (Digits=8). %: - \XINTinFloatxintLog and \XINTinFloatxintExp were removed; they were& % used for log() and exp() in \xintfloateval, and differed from \xintLog& % and \xintExp a bit, now renamed to \PoorManLog and \PoorManExp. %: - \PoorManPower has simply disappeared, see \XINTinFloatSciPow and \xintPow. %) % % See the general xintlog introduction for some comments on the achieved % precision and probabilities of correct rounding. % %\end{lverb} % % \subsubsection{\csh{PoorManLogBaseTen}, \csh{PoorManLog}} %\begin{lverb} % 1.3f. Code originally in poormanlog v0.04 got transferred here. It % produces the logarithm in base 10 with an error (believed to be at most) of % the order of 1 unit in the 9th (i.e. last, fixed point) fractional % digit. Testing seems to indicate the error is never exceeding 2 units in the % 9th place, in worst cases. % % These macros will still be the support macros for \xintfloatexpr log10(), % pow10(), etc... up to Digits=8 and the poormanlog logarithm is used as % starting point for higher precision if Digits is at least 9. % % Notice that \PML@999999999. expands (in \numexpr) to 1000000000 (ten % digits), which is the only case with the output having ten digits. But there % is no need here to treat this case especially, it works fine in % \PML@logbaseten. % % Breaking change at 1.4e: for consistency with various considerations % on floats, the output will be float rounded to P=Digits. % % One could envision the \xinteval variant to keep 9 fractional digits % (it is known the last one may very well be off by 1 unit). But this % creates complications of principles. % % All of this is very strange because the logarithm clearly shows the % deficiencies of the whole idea of floating point arithmetic, logarithm goes % from floating point to fixed point, and coercing it into pure floating point % has moral costs. Anyway, I shall obide. % %\end{lverb} % \begin{macrocode} \def\PoorManLogBaseTen{\romannumeral0\poormanlogbaseten}% \def\poormanlogbaseten #1% {% \XINTinfloat[\XINTdigits]% {\romannumeral0\expandafter\PML@logbaseten\romannumeral0\XINTinfloat[9]{#1}}% }% \def\PoorManLogBaseTen_raw%#1 {% \romannumeral0\expandafter\PML@logbaseten\romannumeral0\XINTinfloat[9]%{#1}% }% \def\PML@logbaseten#1[#2]% {% \xintiiadd{\xintDSx{-9}{\the\numexpr#2+8\relax}}{\the\numexpr\PML@#1.}[-9]% }% \def\PoorManLog#1% {% \XINTinFloat[\XINTdigits]{\xintMul{\PoorManLogBaseTen_raw{#1}}{23025850923[-10]}}% }% % \end{macrocode} % \subsubsection{\csh{PoorManPowerOfTen}, \csh{PoorManExp}} %\begin{lverb} % Originally in poormanlog v0.04, got transferred into xintfrac.sty at % 1.3f, then here into xintlog.sty at 1.4e. % % Produces 10^x with 9 digits of float precision, with an error (believed to % be) at most 2 units in the last place, when 0<x<1. Of course for this the % input must be precise enough to have 9 fractional digits of **fixed point** % precision. % % Breaking change at 1.4e: output always float-rounded at P=Digits. % % The 1.3f definition for \xintExp (now \PoorManExp) was not careful enough % (see comments above) for very large exponents. This has been corrected at % 1.4e. Formerly exp(12345678) produced shameful 6.3095734e5361659 where only % the first digit (and exponent...) is correct! Now, with \xintDigits*:=8;, % exp(12345678) will produce 6.7725836e5361659 which is correct rounding to 8 % digits. Sorry if your rover expedition to Mars ended in failure due to using % my software. I was not expecting anyone to use it so I did back then in 2019 % a bit too expeditively the \xintExp thing on top of 10^x. % % The 1.4e \PoorManExp replaces and amends deceased \xintExp. % % Before using \xintRound we screen out the case of zero as \xintRound in this % case outputs no fractional digits. %\end{lverb} % \begin{macrocode} \def\PoorManPowerOfTen{\romannumeral0\poormanpoweroften}% \def\poormanpoweroften #1% {% \expandafter\PML@powoften@out \the\numexpr\expandafter\PML@powoften\romannumeral0\xintraw{#1}% }% \def\PML@powoften@out#1[#2]{\XINTinfloat[\XINTdigits]{#1[#2]}}% \def\PML@powoften#1% {% \xint_UDzerominusfork #1-\PML@powoften@zero 0#1\PML@powoften@neg 0-\PML@powoften@pos \krof #1% }% \def\PML@powoften@zero 0/1[0]{1\relax/1[0]}% \def\PML@powoften@pos#1[#2]% {% \expandafter\PML@powoften@pos@a\romannumeral0\xintround{9}{#1[#2]}.% }% \def\PML@powoften@pos@a#1.#2.{\PML@Pa#2.\expandafter[\the\numexpr-8+#1]}% \def\PML@powoften@neg#1[#2]% {% \expandafter\PML@powoften@neg@a\romannumeral0\xintround{9}{#1[#2]}.% }% \def\PML@powoften@neg@a#1.#2.% {% \ifnum#2=\xint_c_ \xint_afterfi{1\relax/1[#1]}\else \expandafter\expandafter\expandafter \PML@Pa\expandafter\xint_gobble_i\the\numexpr2000000000-#2.% \expandafter[\the\numexpr-9+#1\expandafter]\fi }% \def\PoorManExp#1{\PoorManPowerOfTen{\xintMul{#1}{43429448190325182765[-20]}}}% % \end{macrocode} % \subsubsection{Removed: \csh{PoorManPower}, see \cshnolabel{XINTinFloatSciPow}} %\begin{lverb} % Removed at 1.4e. See \XINTinFloatSciPow. %\end{lverb} % \subsection{Macro support for powers} % % \subsubsection{\csh{XINTinFloatSciPow}} % % %\begin{lverb} % % This is the new name and extension of \XINTinFloatPowerH which was % a non user-documented macro used for a^b previously, and previously % was located in $xintfracnameimp. % % A check is done whether the exponent is integer or half-integer, and if % positive, the legacy \xintFloatPower/\xintFloatSqrt macros are used. The % rationale is that: % %( - they give faster evaluations for integer exponent b < 10000 (and beyond) %: - they operate at any value of Digits %: - they keep accuracy even with gigantic exponents, whereas the pow10()/log10()& % path starts losing accuracy for b about 1e8. In fact at 1.4e it was even& % for b about 1000, as log10(A) was not computed with enough fractional& % digits, except for 0.8<A<1.26 (roughly), for this usage. At the 1.4f& % bugfix we compute log10(A) with enough accuracy for A^b to be safe with& % b as large as 1e7, and show visible degradation only for b about 1e9. %) % % The user documentation of \xintFloatPower mentions a 0.52 ulp(Z) error where % Z is the computed result, which seems not as good as the kind of accuracy we % target for pow10() (for -1<x<1) and log10() (for 1<x<10) which is more like % about 0.505ulp. Perhaps in future I will examine if I need to increase a % bit the theoretical accuracy of \xintFloatPower but at time of 1.4e/1.4f % release I have left it standing as is. % % The check whether exponent is integer or half-integer is not on the value % but on the representation. Even in \xintfloatexpr, input such % 10^\xintexpr4/2\relax is possible, and 4/2 will not be recognized as integer % to avoid costly overhead. 3/2 will not be recognized as half-integer. % But 2.0 will be recognized as integer, 25e-1 as half-integer. % % In the computation of A^b, A will be float-rounded to Digits, but the % exponent b will be handled "as is" until last minute. Recall that the % \xintfloatexpr parser does not automatically float round isolated inputs, % this happens only once involved in computations. % % In the Digits<=8 branch we do the same as for Digits>8 since 1.4f. At 1.4e I % had strangely chosen (for "speed", but that was anyhow questionable for % integer exponents less than 10 for example) to always use log10()/pow10()... % But with only 9 fractional digits for the logarithms, exponents such as 1000 % naturally led to last 2 or 3 digits being wrong and let's not even mention % when the exponent was of the order or 1e6... now A^1000 and A^1000.5 are % accurately computed and one can handle a^1000.1 as a^1000*a^0.1 % % I wrote the code during 1.4e to 1.4f transition for doing this split of % exponent automatically, but it induced a very significant time penalty down % the line for fractional exponents, whereas currently a^b is computed at % Digits=8 with perfectly acceptable accuracy for fractional abs(b)<10, and at % high speed, and accuracy for big exponents can be obtained by manually % splitting as above (although the above has no user interface for keeping % each contribution with its extra digits; a single one for a^h, -1<h<1). %\end{lverb} % \begin{macrocode} \def\XINTinFloatSciPow{\romannumeral0\XINTinfloatscipow}% \def\XINTinfloatscipow#1#2% {% \expandafter\XINT_scipow_a\romannumeral0\xintrez{#2}\XINT_scipow_int{#1}% }% \def\XINT_scipow_a #1% {% \xint_gob_til_zero#1\XINT_scipow_Biszero0\XINT_scipow_b#1% }% \def\XINT_scipow_Biszero#1]#2#3{ 1[0]}% \def\XINT_scipow_b #1#2/#3[#4]#5% {% \unless\if1\XINT_is_One#3XY\xint_dothis\XINT_scipow_c\fi \ifnum#4<\xint_c_mone\xint_dothis\XINT_scipow_c\fi \ifnum#4=\xint_c_mone \if5\xintLDg{#1#2} % \xint_afterfi{\xint_dothis\XINT_scipow_halfint}\else \xint_afterfi{\xint_dothis\XINT_scipow_c}% \fi \fi \xint_orthat#5#1#2/#3[#4]% }% \def\XINT_scipow_int #1/1[#2]#3% {% \expandafter\XINT_flpower_checkB_a \romannumeral0\XINT_dsx_addzeros{#2}#1;.\XINTdigits.{#3}{\XINTinfloatS[\XINTdigits]}% }% % \end{macrocode} %\begin{lverb} % The \XINT_flpowerh_finish is the sole remnant of \XINTinFloatPowerH % which was formerly stitched to \xintFloatPower and checked for half-integer % exponent. %\end{lverb} % \begin{macrocode} \def\XINT_scipow_halfint#1/1[#2]#3% {% \expandafter\XINT_flpower_checkB_a \romannumeral0\xintdsr{\xintDouble{#1}}.\XINTdigits.{#3}\XINT_flpowerh_finish }% \def\XINT_flpowerh_finish #1% {% \XINTinfloatS[\XINTdigits]{\XINTinFloatSqrt[\XINTdigits+\xint_c_iii]{#1}}% }% \def\XINT_tmpa#1.{% \def\XINT_scipow_c ##1[##2]##3% {% \expandafter\XINT_scipow_d\romannumeral0\XINTinfloatS[#1]{##3}\xint:##1[##2]\xint: }% }\expandafter\XINT_tmpa\the\numexpr\XINTdigits.% \def\XINT_scipow_d #1% {% \xint_UDzerominusfork #1-\XINT_scipow_Aiszero 0#1\XINT_scipow_Aisneg 0-\XINT_scipow_Aispos \krof #1% }% \def\XINT_scipow_Aiszero #1\xint:#2#3\xint: {% % \end{macrocode} %\begin{lverb} % Missing NaN and Infinity causes problems. Inserting something % like 1["7FFF8000] is risky as certain macros convert [N] into N zeros... % so the run can appear to stall and will crash possibly badly if we do that. % There is some usage in relation to ilog10 in xint.sty and xintfrac.sty % of "7FFF8000 but here I will stay prudent and insert the usual 0 value % (changed at 1.4g) %\end{lverb} % \begin{macrocode} \if-#2\xint_dothis {\XINT_signalcondition{InvalidOperation}{0 raised to power #2#3.}{}{ 0[0]}}\fi \xint_orthat{ 0[0]}% }% \def\XINT_scipow_Aispos #1\xint:#2\xint: {% \XINTinfloatpowten{\xintMul{#2}{\XINTinFloatLogTen_xdgout#1}}% }% % \end{macrocode} %\begin{lverb} % If a^b with a<0, we arrive here only if b was not considered to be % an integer exponent. So let's raise an error. %\end{lverb} % \begin{macrocode} \def\XINT_scipow_Aisneg #1#2\xint:#3\xint: {% \XINT_signalcondition{InvalidOperation}% {Fractional power #3 of negative #1#2.}{}{ 0[0]}% }% \ifnum\XINTdigits<9 % \end{macrocode} %\begin{lverb} % At 1.4f we only need for Digits up to 8 to insert usage of poormanlog % for non integer, non half-integer exponents. At 1.4e the code was more % complicated because I had strangely opted for using always the log10() % path. However we have to be careful to use \PML@logbaseten with 9 digits % always. % % As the legacy macros used for integer and half-integer exponents float-round % the input to Digits digits, we must do the same here for coherence. Which % induces some small complications here. %\end{lverb} % \begin{macrocode} \def\XINT_tmpa#1.#2.#3.{% \def\XINT_scipow_c ##1[##2]##3% {% \expandafter\XINT_scipow_d \romannumeral0\expandafter\XINT_scipow_c_i \romannumeral0\XINTinfloat[#1]{##3}\xint:##1[##2]\xint: }% \def\XINT_scipow_c_i##1[##2]{ ##1#3[##2-#2]}% }\expandafter\XINT_tmpa\the\numexpr\XINTdigits\expandafter.% \the\numexpr9-\XINTdigits\expandafter.% \romannumeral\xintreplicate{9-\XINTdigits}0.% \def\XINT_scipow_Aispos #1\xint:#2\xint: {% \poormanpoweroften{\xintMul{#2}{\romannumeral0\expandafter\PML@logbaseten#1}}% }% \fi % \end{macrocode} % \subsubsection{\cshnolabel{xintPow}} %\begin{lverb} % % Support macro for a^b in \xinteval. This overloads the original % $xintfracnameimp macro, keeping its original meaning only for integer % exponents, which are not too big: for exact evaluation of A^b, we want the % output to not have more than about 10000 digits (separately for numerator % and denominator). For this we limit b depending on the length of A, simply % we want b to be smaller than the rounded value of 10000 divided by the % length of A. For one-digit A, this would give 10000 as maximal exponent but % due to organization of code related to avoir arithmetic overflow (we can't % immediately operate in \numexpr with b as it is authorized to be beyond TeX % bound), the maximal exponent is 9999. % % The criterion, which guarantees output (numerator and % denominator separately) does not exceed by much 10000 digits if at all is % that the exponent should be less than the (rounded in the sense of \numexpr) % quotient of 10000 by the number of digits of a (considering separately % numerator and denominator). % % The decision whether to compute A^b exactly depends on the length of % internal representation of A. So 9^9999 is evaluated exactly (in \xinteval) % but for 9.0 it is 9.0^5000 the maximal power. This may change in future. % % 1.4e had the following bug (for Digits>8): big integer exponents used the % log10()/pow10() based approach rather than the legacy macro path which goes % via \xintFloatPower, as done by \xintfloateval! As a result powers with very % large integer exponents were more precise in \xintfloateval than in \xinteval! % % 1.4f fixes this. Also, it handles Digits<=8 as Digits>8, bringing much % simplification here. %\end{lverb} % \begin{macrocode} \def\xintPow{\romannumeral0\xintpow}% \def\xintpow#1#2% {% \expandafter\XINT_scipow_a\romannumeral0\xintrez{#2}\XINT_pow_int{#1}% }% % \end{macrocode} %\begin{lverb} % In case of half-integer exponent the \XINT_scipow_a will have % triggered usage of the (new incarnation) of \XINTinFloatPowerH which combines % \xintFloatPower and square root extraction. So we only have to handle here % the case of integer exponents which will trigger execution of this % \XINT_pow_int macro passed as parameter to \xintpow. %\end{lverb} % \begin{macrocode} \def\XINT_pow_int #1/1[#2]% {% \expandafter\XINT_pow_int_a\romannumeral0\XINT_dsx_addzeros{#2}#1;.% }% % \end{macrocode} %\begin{lverb} % 1.4e had a bug here for integer exponents >= 10000: they triggered % going back to the floating point routine but at a late location where % the log10()/pow10() approach is used. %\end{lverb} % \begin{macrocode} \def\XINT_pow_int_a #1#2.% {% \ifnum\if-#1\xintLength{#2}\else\xintLength{#1#2}\fi>\xint_c_iv \expandafter\XINT_pow_bigint \else\expandafter\XINT_pow_int_b \fi #1#2.% }% % \end{macrocode} %\begin{lverb} % At 1.4f we correctly jump to the appropriate entry point into the % \xintFloatPower routine of $xintfracnameimp, in case of a big integer % exponent. %\end{lverb} % \begin{macrocode} \def\XINT_pow_bigint #1.#2% {% \XINT_flpower_checkB_a#1.\XINTdigits.{#2}{\XINTinfloatS[\XINTdigits]}% }% \def\XINT_pow_int_b #1.#2% {% % \end{macrocode} %\begin{lverb} % We now check if the output will not be too bulky. We use here (on the % a of a^b) \xintraw, not \xintrez, on purpose so that for example 9.0^9999 % is computed in floating point sense but 9^9999 is computed exactly. However % 9.0^5000 will be computed exactly. And if I used \xintrez here \xinteval{100^2} % would print 10000.0 and \xinteval{100^3} would print 1.0e6. Thus situation % is complex. % % By the way I am happy to see that 9.0*9.0 in % \xinteval does print 81.0 but the truth is that internally it does have the % more bulky 8100/1[-2] maybe I should make some revision of this, i.e. use % rather systematically \xintREZ on input rather than \xintRaw (note taken on % 2021/05/08 at time of doing 1.4f bugfix release). %\end{lverb} % \begin{macrocode} \expandafter\XINT_pow_int_c\romannumeral0\xintraw{#2}\xint:#1\xint: }% % \end{macrocode} %\begin{lverb} % The \XINT_fpow_fork is (quasi top level) entry point we have found % into the legacy \xintPow routine of $xintfracnameimp. Its interface is a bit % weird, but let's not worry about this now. % %\end{lverb} % \begin{macrocode} \def\XINT_pow_int_c#1#2/#3[#4]\xint:#5\xint: {% \if0\ifnum\numexpr\xint_c_x^iv/% (\xintLength{#1#2}\if-#1-\xint_c_i\fi)<\XINT_Abs#5 % 1\else \ifnum\numexpr\xint_c_x^iv/\xintLength{#3}<\XINT_Abs#5 % 1\else 0\fi\fi \expandafter\XINT_fpow_fork\else\expandafter\XINT_pow_bigint_i \fi #5\Z{#4}{#1#2}{#3}% }% % \end{macrocode} %\begin{lverb} % \XINT_pow_bigint_i is like \XINT_pow_bigint but has its parameters % organized differently. %\end{lverb} % \begin{macrocode} \def\XINT_pow_bigint_i#1\Z#2#3#4% {% \XINT_flpower_checkB_a#1.\XINTdigits.{#3/#4[#2]}{\XINTinfloatS[\XINTdigits]}% }% % \end{macrocode} % \subsection{Macro support for \cshnolabel{xintexpr} and \cshnolabel{xintfloatexpr} syntax} % \subsubsection{The \cshn{log10()} and \cshn{pow10()} functions} %\begin{lverb} % Up to 8 digits included we use the poormanlog based ones. %\end{lverb} % \begin{macrocode} \ifnum\XINTdigits<9 \expandafter\def\csname XINT_expr_func_log10\endcsname#1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\PoorManLogBaseTen#3}}% }% \expandafter\def\csname XINT_expr_func_pow10\endcsname#1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\PoorManPowerOfTen#3}}% }% \else \expandafter\def\csname XINT_expr_func_log10\endcsname#1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINTinFloatLogTen#3}}% }% \expandafter\def\csname XINT_expr_func_pow10\endcsname#1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINTinFloatPowTen#3}}% }% \fi \expandafter\let\csname XINT_flexpr_func_log10\expandafter\endcsname \csname XINT_expr_func_log10\endcsname \expandafter\let\csname XINT_flexpr_func_pow10\expandafter\endcsname \csname XINT_expr_func_pow10\endcsname % \end{macrocode} % \subsubsection{The \cshn{log()}, \cshn{exp()} functions} % \begin{macrocode} \ifnum\XINTdigits<9 \def\XINT_expr_func_log #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\PoorManLog#3}}% }% \def\XINT_expr_func_exp #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\PoorManExp#3}}% }% \let\XINT_flexpr_func_log\XINT_expr_func_log \let\XINT_flexpr_func_exp\XINT_expr_func_exp \else \def\XINT_expr_func_log #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINTinFloatLog#3}}% }% \def\XINT_expr_func_exp #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:one {\romannumeral`&&@\XINTinFloatExp#3}}% }% \let\XINT_flexpr_func_log\XINT_expr_func_log \let\XINT_flexpr_func_exp\XINT_expr_func_exp \fi % \end{macrocode} % \subsubsection{The \cshn{pow()} function} %\begin{lverb} % The mapping of ** and ^ to \XINTinFloatSciPow (in \xintfloatexpr % context) and \xintPow (in \xintexpr context), % is done in $xintexprnameimp. %\end{lverb} % \begin{macrocode} \def\XINT_expr_func_pow #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:two {\romannumeral`&&@\xintPow#3}}% }% \def\XINT_flexpr_func_pow #1#2#3% {% \expandafter #1\expandafter #2\expandafter{% \romannumeral`&&@\XINT:NEhook:f:one:from:two {\romannumeral`&&@\XINTinFloatSciPow#3}}% }% % \end{macrocode} % \subsection{End of package loading for low Digits} % \begin{macrocode} \ifnum\XINTdigits<9 \expandafter\XINTlogendinput\fi% % \end{macrocode} % \subsection{Stored constants} %\begin{lverb} % The constants were obtained from Maple at 80 digits: fractional power % of 10, but only one logarithm log(10). % % Currently the code whether for exponential or logarihm will not screen out 0 % digits and even will do silly multiplication by 10^0 = 1 in that case, and % we need to store such silly values. % % We add the data for the 10^-0.i etc... because pre-computing them on the fly % significantly adds overhead to the package loading. % % The fractional powers of ten with D+5 digits are used to compute pow10() % function, those with D+10 digits are used to compute log10() function. This % is done with % an elevated precision for two reasons: %( - handling of inputs near 1, %: - in order for a^b = pow10(b*log10(a)) to keep accuracy& % even with large exponents, say in absolute value up to 1e7,& % degradation beginning to show-up at 1e8. %) %\end{lverb} % \def\macro@font{\ttfamily \hfuzz 30pt } % \begin{macrocode} \def\XINT_tmpa{1[0]}% \expandafter\let\csname XINT_c_1_0\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_2_0\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_3_0\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_4_0\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_5_0\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_6_0\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_1_0_x\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_2_0_x\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_3_0_x\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_4_0_x\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_5_0_x\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_6_0_x\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_1_0_inv\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_2_0_inv\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_3_0_inv\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_4_0_inv\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_5_0_inv\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_6_0_inv\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_1_0_inv_x\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_2_0_inv_x\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_3_0_inv_x\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_4_0_inv_x\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_5_0_inv_x\endcsname\XINT_tmpa \expandafter\let\csname XINT_c_6_0_inv_x\endcsname\XINT_tmpa \def\XINT_tmpa#1#2#3#4;% {\expandafter\edef\csname XINT_c_#1_#2\endcsname {\XINTinFloat[\XINTdigitsormax+5]{#3#4[-79]}}% \expandafter\edef\csname XINT_c_#1_#2_x\endcsname {\XINTinFloat[\XINTdigitsormax+10]{#3#4[-79]}}% }% % 10^0.i \XINT_tmpa 1 1 12589254117941672104239541063958006060936174094669310691079230195266476157825020;% \XINT_tmpa 1 2 15848931924611134852021013733915070132694421338250390683162968123166568636684540;% \XINT_tmpa 1 3 19952623149688796013524553967395355579862743154053460992299136670049309106980490;% \XINT_tmpa 1 4 25118864315095801110850320677993273941585181007824754286798884209082432477235613;% \XINT_tmpa 1 5 31622776601683793319988935444327185337195551393252168268575048527925944386392382;% \XINT_tmpa 1 6 39810717055349725077025230508775204348767703729738044686528414806022485386945804;% \XINT_tmpa 1 7 50118723362727228500155418688494576806047198983281926392969745588901125568883069;% \XINT_tmpa 1 8 63095734448019324943436013662234386467294525718822872452772952883349494329768681;% \XINT_tmpa 1 9 79432823472428150206591828283638793258896063175548433209232392931695569719148754;% % 10^0.0i \XINT_tmpa 2 1 10232929922807541309662751748198778273411640572379813085994255856738296458625172;% \XINT_tmpa 2 2 10471285480508995334645020315281400790567914715039292120056525299012577641023719;% \XINT_tmpa 2 3 10715193052376064174083022246945087339158659633422172707894501914136771607653870;% \XINT_tmpa 2 4 10964781961431850131437136061411270464271158762483023169080841607885740984711300;% \XINT_tmpa 2 5 11220184543019634355910389464779057367223085073605529624450744481701033026862244;% \XINT_tmpa 2 6 11481536214968827515462246116628360182562102373996119340874991068894793593040890;% \XINT_tmpa 2 7 11748975549395295417220677651268442278134317971793124791953875805007912852226246;% \XINT_tmpa 2 8 12022644346174129058326127151935204486942664354881189151104892745683155052368222;% \XINT_tmpa 2 9 12302687708123815342415404364750907389955639574572144413097319170011637639124482;% % 10^0.00i \XINT_tmpa 3 1 10023052380778996719154048893281105540536684535421606464116348523047431367720401;% \XINT_tmpa 3 2 10046157902783951424046519858132787392010166060319618489538315083825599423438638;% \XINT_tmpa 3 3 10069316688518041699296607872661381368099438247964820601930206419324524707606686;% \XINT_tmpa 3 4 10092528860766844119155277641202580844111492027373621434478800545314309618714957;% \XINT_tmpa 3 5 10115794542598985244409323144543146957419235215102899054703546688078254946034250;% \XINT_tmpa 3 6 10139113857366794119988279023017296985954042032867436525450889437280417044987125;% \XINT_tmpa 3 7 10162486928706956276733661150135543062420167220622552197768982666050994284378619;% \XINT_tmpa 3 8 10185913880541169240797988673338257820431768224957171297560936579346433061037662;% \XINT_tmpa 3 9 10209394837076799554149033101487543990018213667630072574873723356334069913329713;% % 10^0.000i \XINT_tmpa 4 1 10002302850208247526835942556719413318678216124626534526963475845228205382579041;% \XINT_tmpa 4 2 10004606230728403216239656646745503559081482371024284871882409614422496765669196;% \XINT_tmpa 4 3 10006910141682589957025973521996241909035914023642264228577379693841345823180462;% \XINT_tmpa 4 4 10009214583192958761081718336761022426385537997384755843291864010938378093197023;% \XINT_tmpa 4 5 10011519555381688769842032367472488618040778885656970999331288116685029387850446;% \XINT_tmpa 4 6 10013825058370987260768186632475607982636715641432550952229573271596547716373358;% \XINT_tmpa 4 7 10016131092283089653826887255241073941084503769368844606021481400409002185558343;% \XINT_tmpa 4 8 10018437657240259517971072914549205297136779497498835020699531587537662833033174;% \XINT_tmpa 4 9 10020744753364788577622204725249622301332888222801030351604197113557132455165040;% % 10^0.0000i \XINT_tmpa 5 1 10000230261160268806710649793464495797824846841503180050673957122443571394978721;% \XINT_tmpa 5 2 10000460527622557806255008596155855743730116854295068547616656160734125748005947;% \XINT_tmpa 5 3 10000690799386989083565213461287219981856579552059660369243804541364501659468630;% \XINT_tmpa 5 4 10000921076453684726384543254593368743049141124080210677706489564626675960578367;% \XINT_tmpa 5 5 10001151358822766825267483384008265483772370538793312970508590203623535763866465;% \XINT_tmpa 5 6 10001381646494357473579790530833073090516914490540536234536867917078761046656260;% \XINT_tmpa 5 7 10001611939468578767498557382394677469502542123237272447312733350028467607076918;% \XINT_tmpa 5 8 10001842237745552806012277366194752842273812293689190856411757410911882303011468;% \XINT_tmpa 5 9 10002072541325401690920909385549403068574626162727745910217443397959031898734024;% % 10^0.00000i \XINT_tmpa 6 1 10000023025877439451356029805459000097926504781151663770980171880313737943886754;% \XINT_tmpa 6 2 10000046051807898005897723104514851394069452605882077809669546315010724085277647;% \XINT_tmpa 6 3 10000069077791375785706217087438809625967243923218032821061587553353589726808164;% \XINT_tmpa 6 4 10000092103827872912862930047032391734439796534302560512742030066798473305401477;% \XINT_tmpa 6 5 10000115129917389509449561379274639104559958866285946533811801963402821672829477;% \XINT_tmpa 6 6 10000138156059925697548091583969382297005329013199894805417325991907389143667949;% \XINT_tmpa 6 7 10000161182255481599240782265392507269793911275470978276390154932321984777772469;% \XINT_tmpa 6 8 10000184208504057336610176132939223090407041937631374389422968832433217547184883;% \XINT_tmpa 6 9 10000207234805653031739097001771331138303016031686764989867510425362339583809842;% \def\XINT_tmpa#1#2#3#4;% {\expandafter\edef \csname XINT_c_#1_#2_inv\endcsname{\XINTinFloat[\XINTdigitsormax+5]{#3#4[-80]}}% \expandafter\edef \csname XINT_c_#1_#2_inv_x\endcsname{\XINTinFloat[\XINTdigitsormax+10]{#3#4[-80]}}% }% % 10^-0.i \XINT_tmpa 1 1 79432823472428150206591828283638793258896063175548433209232392931695569719148754;% \XINT_tmpa 1 2 63095734448019324943436013662234386467294525718822872452772952883349494329768681;% \XINT_tmpa 1 3 50118723362727228500155418688494576806047198983281926392969745588901125568883069;% \XINT_tmpa 1 4 39810717055349725077025230508775204348767703729738044686528414806022485386945804;% \XINT_tmpa 1 5 31622776601683793319988935444327185337195551393252168268575048527925944386392382;% \XINT_tmpa 1 6 25118864315095801110850320677993273941585181007824754286798884209082432477235613;% \XINT_tmpa 1 7 19952623149688796013524553967395355579862743154053460992299136670049309106980490;% \XINT_tmpa 1 8 15848931924611134852021013733915070132694421338250390683162968123166568636684540;% \XINT_tmpa 1 9 12589254117941672104239541063958006060936174094669310691079230195266476157825020;% % 10^-0.0i \XINT_tmpa 2 1 97723722095581068269707600696156123863427170069897801526639004097175507042084888;% \XINT_tmpa 2 2 95499258602143594972395937950148401513087269708053320302465127242741421479104601;% \XINT_tmpa 2 3 93325430079699104353209661168364840720225485199736026149257155811788093771138272;% \XINT_tmpa 2 4 91201083935590974212095940791872333509323858755696109214760361851771695487999100;% \XINT_tmpa 2 5 89125093813374552995310868107829696398587478293004836994794349506746891059190135;% \XINT_tmpa 2 6 87096358995608063751082742520877054774747128501284704090761796673224328569285177;% \XINT_tmpa 2 7 85113803820237646781712631859248682794521725442067093899553745086385146367436049;% \XINT_tmpa 2 8 83176377110267100616669140273840405263880767161887438462740286611379995442629360;% \XINT_tmpa 2 9 81283051616409924654127879773132980187568851100062454636602325121954484722491710;% % 10^-0.00i \XINT_tmpa 3 1 99770006382255331719442194285376231055211861394573154624878230890945476532432225;% \XINT_tmpa 3 2 99540541735152696244806147089510943107144177264574823668081299845609359857038344;% \XINT_tmpa 3 3 99311604842093377157642607688515474663519162181123336122073822476734517364853150;% \XINT_tmpa 3 4 99083194489276757440828314388392035249938006860819409201135652190410238171119287;% \XINT_tmpa 3 5 98855309465693884028524792978202683686410726723055209558576898759166522286083202;% \XINT_tmpa 3 6 98627948563121047157261523093421290951784086730437722805070296627452491731402556;% \XINT_tmpa 3 7 98401110576113374484101831088824192144756194053451911515003663381199842081528019;% \XINT_tmpa 3 8 98174794301998439937928161622872240632362817134775142288598128693131032909278350;% \XINT_tmpa 3 9 97948998540869887269961493687844910565420716785032030061251916654655049965062649;% % 10^-0.000i \XINT_tmpa 4 1 99976976799815658635141604638981297541396466984477711459083930684685186989697929;% \XINT_tmpa 4 2 99953958900308784552845777251512089759003230012954649234748668826546533498169555;% \XINT_tmpa 4 3 99930946300258992168693777702512591351888960684418033717545524043693899420866954;% \XINT_tmpa 4 4 99907938998446176870082987427724649318531547584410414997787083472394558389284098;% \XINT_tmpa 4 5 99884936993650514951538205746462968844845952521633937925370747725933629958238429;% \XINT_tmpa 4 6 99861940284652463550037839584112909891259691850983307437097305856727153967481065;% \XINT_tmpa 4 7 99838948870232760580354983175435314251655958968480344701699631967048474751069525;% \XINT_tmpa 4 8 99815962749172424670413384320528274471550942114263604264788586703624513163664479;% \XINT_tmpa 4 9 99792981920252755096658293766085025870392854106037465990011216356523334125368417;% % 10^-0.0000i \XINT_tmpa 5 1 99997697441416293040019992468837639003787989306240470048763511538639048400765328;% \XINT_tmpa 5 2 99995394935850346394065999228750187791584034668237852053859761641089829514536011;% \XINT_tmpa 5 3 99993092483300939297147020491645017932348508508297743745039515152378182676736684;% \XINT_tmpa 5 4 99990790083766851012380885556584619169980753943113396677545915245611923361705686;% \XINT_tmpa 5 5 99988487737246860830993605587529673614422529030613405900998412734419982883669223;% \XINT_tmpa 5 6 99986185443739748072318726405984801565268578044798475766025647187221659622450651;% \XINT_tmpa 5 7 99983883203244292083796681298546635825139453823571398432959235283529730820181019;% \XINT_tmpa 5 8 99981581015759272240974143839353881367972777961073357987943600347058023396510672;% \XINT_tmpa 5 9 99979278881283467947503380727439017235290006415950636109257677645557027950744160;% % 10^-0.00000i \XINT_tmpa 6 1 99999769741755795297487775997495948154386159348543852707438213487494386559762090;% \XINT_tmpa 6 2 99999539484041779185217876175552674518572114763104546143049036309870762496098218;% \XINT_tmpa 6 3 99999309226857950442387361668529812394860404492721699528707852590634886516924591;% \XINT_tmpa 6 4 99999078970204307848196104610199226516866442484686906173860803560254163287393673;% \XINT_tmpa 6 5 99998848714080850181846788127272455158309917012010320554498356105168896062430977;% \XINT_tmpa 6 6 99998618458487576222544906332928167145404344730731751204389698696345970645201375;% \XINT_tmpa 6 7 99998388203424484749498764320339633772810463403640242228131015918494067456365331;% \XINT_tmpa 6 8 99998157948891574541919478156202215623119146605983303201215215949834619332550929;% \XINT_tmpa 6 9 99997927694888844379020974874260864289829523807763942234420930258187873904191138;% % log(10) \edef\XINT_c_logten {\XINTinFloat[\XINTdigitsormax+4] {23025850929940456840179914546843642076011014886287729760333279009675726096773525[-79]}}% \edef\XINT_c_oneoverlogten {\XINTinFloat[\XINTdigitsormax+4] {43429448190325182765112891891660508229439700580366656611445378316586464920887077[-80]}}% \edef\XINT_c_oneoverlogten_xx {\XINTinFloat[\XINTdigitsormax+14] {43429448190325182765112891891660508229439700580366656611445378316586464920887077[-80]}}% % \end{macrocode} % \def\macro@font{\ttfamily} % \subsection{April 2021: at last, \csh{XINTinFloatPowTen}, \csh{XINTinFloatExp}} %\begin{lverb} % Done April 2021. I have procrastinated (or did not have time to % devote to this) at least 5 years, even more. % % Speed improvements will have to wait to long delayed refactoring of core % floating point support which is still in the 2013 primitive state ! % % I did not try to optimize for say 16 digits, as I was more focused on % reaching 60 digits in a reasonably efficient manner (trigonometric functions % achieved this since 2019) in the same coding framework. Finally, up to 62 digits. % % The stored constants are log(10) at P+4 digits and the powers 10^0.d, % 10^0.0d, etc, up to 10^0.00000d for d=1..9, as well as their inverses, at % P+5 and P+10 digits. The constants were obtained from Maple at 80 digits. % % Initially I constructed the exponential series exp(h) as one big unique nested % macro. It contained pre-rounded values of the 1/i! but would float-round h % to various numbers of digits, with always the full initial h as input. % % After having experimented with the logarithm, I redid exp(h) = 1 + h(1 + % h(1/2 + ...)) with many macros in order to have more readable code, and to % dynamically cut-off more and more digits from h the deeper it is used. See % the logarithm code for (perhaps) more comments. % % The thresholds have been obtained from considerations including an hmax % (a bit more than 0.5 log(10) 10^-6). Here is the table: % %( - maximal value of P: 8, 15, 21, 28, 35, 42, 48, 55, 62 %: - last included term: /1, /2, /6, /4!, /5!, /6!, /7!, /8!, /9! %) % % Computations are done morally targeting P+4 fractional fixed point digits, % with a stopping criteria at say about 5e(-P-4), which was used for the table % above using only the worst case. As the used macros are a mix of exact % operations and floating point reductions this is in practice a bit % different. The h will be initially float rounded to P-1 digits. It is % cut-off more and more, the deeper nested it is used. % % The code for this evaluation of 10^x is very poor with x very near zero: it % does silly multiplication by 1, and uses more terms of exponential series % than would then be necessary. % % For the computation of exp(x) as 10^(c*x) with c=log(10)^-1, we need more % precise c the larger abs(x) is. For abs(x)<1 (or 2), the c with P+4 % fractional digits is sufficient. But decimal exponents are more or less % allowed to be near the TeX maximum 2^31-1, which means that abs(x) could be % as big as 0.5e10, and we then need c with P+14 digits to cover that range. % % I am hesitating whether to first examine integral part of abs(x) and for % example to use c with either P+4, P+9 or P+14 digits, and also take this % opportunity to inject an error message if x is too big before TeX arithmetic % overflow happens later on. For time being I will use overhead of % oneoverlogten having ample enough digits... % % The exponent received as input is float rounded to P + 14 digits. In % practice the input will be already a P-digits float. The motivation here is % for low Digits situation: but this done so that for example with Digits=4, % we want exp(12345) not to be evaluated as exp(12350) which would have no % meaning at all. The +14 is because we have prepared 1/log(10) with that many % significant digits. This conundrum is due to the inadequation of the world % of floating point numbers with exp() and log(): clearly exp() goes from % fixed point to floating point and log() goes from floating point to fixed % point, and coercing them to work inside the sole floating point domain is % not mathematically natural. Although admittedly it does create interesting % mathematical questions! A similar situation applies to functions such as % cos() and sin(), what sense is there in the expression cos(exp(50)) for % example with 16 digits precision? My opinion is that it does not make ANY % sense. Anyway, I shall obide. % % As \XINTinFloatS will not add unnecessarily trailing zeros, the % \XINTdigits+14 is not really an enormous overhead for integer exponents, % such as in the example above the 12345, or more realistically small integer % exponents, and if the input is already float rounded to P digits, the % overhead is also not enormous (float-rounding is costly when the input is a % fraction). % % \XINTinfloatpowten will receive an input with at least P+14 and up to 2P+28 % digits... fortunaltely with no fraction part and will start rounding it in % the fixed point sense of its input to P+4 digits after decimal point, which % is not enormously costly. % % Of course all these things pile up... %\end{lverb} % \begin{macrocode} \def\XINTinFloatExp{\romannumeral0\XINTinfloatexp}% \def\XINT_tmpa#1.{% \def\XINTinfloatexp##1% {% \XINTinfloatpowten {\xintMul{\XINT_c_oneoverlogten_xx}{\XINTinFloatS[#1]{##1}}}% }% }\expandafter\XINT_tmpa\the\numexpr\XINTdigitsormax+14.% % \end{macrocode} %\begin{lverb} % Here is how the reduction to computations of an exp(h) via series is done. % % Starting from x, after initial argument normalization, it is fixed-point % rounded to 6 fractional digits giving x'' = ±n.d_1...d_6 (which may be 0). % % I have to resist temptation using very low level routines here and wisely % will employ the available user-level stuff. One computes then the % difference x-x'' which gives some eta, and the h will be log(10).eta. The % subtraction and multiplication are done exactly then float rounded to P-1 % digits to obtain the h. % % Then exp(h) is computed. And to finish it is multiplied with the stored % 10^±0.d_1, 10^±0.0d_2, etc...., constants and its decimal exponent is % increased by ±n. These operations are done at P+5 floating point digits. The % final result is then float-rounded to the target P digits. % % Currently I may use nested macros for some operations but will perhaps % revise in future (it makes tracing very complicated if one does not have % intermediate macros). The exponential series itself was initially only one % single macro, but as commented above I have now modified it. %\end{lverb} % \begin{macrocode} \def\XINTinFloatPowTen{\romannumeral0\XINTinfloatpowten}% \def\XINT_tmpa#1.{% \def\XINTinfloatpowten##1% {% \expandafter\XINT_powten_fork \romannumeral0\xintiround{#1}{##1}[-#1]% }% }\expandafter\XINT_tmpa\the\numexpr\XINTdigitsormax+4.% \def\XINT_powten_fork#1% {% \xint_UDzerominusfork #1-\XINT_powten_zero 0#1\XINT_powten_neg 0-\XINT_powten_pos \krof #1% }% \def\XINT_powten_zero #1[#2]{ 1[0]}% % \end{macrocode} %\begin{lverb} % This rounding may produce 0.000000 but will always have 6 exactly % fractional digits, because the special case of a zero input was filtered out % preventively. %\end{lverb} % \begin{macrocode} \def\XINT_powten_pos#1[#2]% {% \expandafter\XINT_powten_pos_a\romannumeral0\xintround{6}{#1[#2]}#1[#2]% }% \def\XINT_tmpa #1.#2.#3.{% \def\XINT_powten_pos_a ##1.##2##3##4##5##6##7##8[##9]% {% \expandafter\XINT_infloate \romannumeral0\XINTinfloat[#3]{% \xintMul{\csname XINT_c_1_##2\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_2_##3\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_3_##4\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_4_##5\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_5_##6\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_6_##7\endcsname}{% \xintAdd{1[0]}{% \expandafter\XINT_Exp_series_a_ii \romannumeral0\XINTinfloat[#2]{% \xintMul{\XINT_c_logten}% {\xintAdd{-##1.##2##3##4##5##6##7}{##8[##9]}}% }% \xint: }% }}}}}}}}}}}}{##1}% }}\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax+5\expandafter.% \the\numexpr\XINTdigitsormax-1\expandafter.% \the\numexpr\XINTdigitsormax.% % \end{macrocode} %\begin{lverb} % This rounding may produce -0.000000 but will always have 6 exactly % fractional digits and a leading minus sign. %\end{lverb} % \begin{macrocode} \def\XINT_powten_neg#1[#2]% {% \expandafter\XINT_powten_neg_a\romannumeral0\xintround{6}{#1[#2]}#1[#2]% }% \def\XINT_tmpa #1.#2.#3.{% \def\XINT_powten_neg_a -##1.##2##3##4##5##6##7##8[##9]% {% \expandafter\XINT_infloate \romannumeral0\XINTinfloat[#3]{% \xintMul{\csname XINT_c_1_##2_inv\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_2_##3_inv\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_3_##4_inv\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_4_##5_inv\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_5_##6_inv\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_6_##7_inv\endcsname}{% \xintAdd{1[0]}{% \expandafter\XINT_Exp_series_a_ii \romannumeral0\XINTinfloat[#2]{% \xintMul{\XINT_c_logten}% {\xintAdd{##1.##2##3##4##5##6##7}{##8[##9]}}% }% \xint: }% }}}}}}}}}}}}{-##1}% }}\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax+5\expandafter.% \the\numexpr\XINTdigitsormax-1\expandafter.% \the\numexpr\XINTdigitsormax.% % \end{macrocode} % \subsubsection{Exponential series} %\begin{lverb} % Or rather here h(1 + h(1/2 + h (1/6 + ....))). Upto at most h^9/9! % term. % % The used initial h has been float rounded to P-1 digits. %\end{lverb} % \begin{macrocode} \def\XINT_tmpa#1.#2.{% \def\XINT_Exp_series_a_ii##1\xint: {% \expandafter\XINT_Exp_series_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_Exp_series_b##1[##2]\xint: {% \expandafter\XINT_Exp_series_c_ \romannumeral0\xintadd{1}{\xintHalf{##10}[##2-1]}\xint: }% \def\XINT_Exp_series_c_##1\xint:##2\xint: {% \XINTinFloat[#2]{\xintMul{##1}{##2}}% }% }% \expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-6\expandafter.% \the\numexpr\XINTdigitsormax-1.% \ifnum\XINTdigits>15 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_Exp_series_a_ii##1\xint: {% \expandafter\XINT_Exp_series_a_iii \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_Exp_series_a_iii##1\xint: {% \expandafter\XINT_Exp_series_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_Exp_series_b##1[##2]\xint: {% \expandafter\XINT_Exp_series_c_i \romannumeral0\xintadd{#3}{##1/6[##2]}\xint: }% \def\XINT_Exp_series_c_i##1\xint:##2\xint: {% \expandafter\XINT_Exp_series_c_ \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-13\expandafter.% \the\numexpr\XINTdigitsormax-6.% {5[-1]}.% {1[0]}.% \fi \ifnum\XINTdigits>21 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_Exp_series_a_iii##1\xint: {% \expandafter\XINT_Exp_series_a_iv \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_Exp_series_a_iv##1\xint: {% \expandafter\XINT_Exp_series_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_Exp_series_b##1[##2]\xint: {% \expandafter\XINT_Exp_series_c_ii \romannumeral0\xintadd{#3}{##1/24[##2]}\xint: }% \def\XINT_Exp_series_c_ii##1\xint:##2\xint: {% \expandafter\XINT_Exp_series_c_i \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-19\expandafter.% \the\numexpr\XINTdigitsormax-13\expandafter.% \romannumeral0\XINTinfloat[\XINTdigitsormax-13]{1/6[0]}.% {5[-1]}.% \fi \ifnum\XINTdigits>28 \def\XINT_tmpa #1 #2 #3 #4 #5 #6 #7 % {% \def\XINT_tmpb ##1##2##3##4% {% \def\XINT_tmpc####1.####2.####3.####4.% {% \def##2########1\xint: {% \expandafter##1% \romannumeral0\XINTinfloatS[####2]{########1}\xint:########1\xint: }% \def##1########1\xint: {% \expandafter\XINT_Exp_series_b \romannumeral0\XINTinfloatS[####1]{########1}\xint:########1\xint: }% \def\XINT_Exp_series_b########1[########2]\xint: {% \expandafter##3% \romannumeral0\xintadd{####3}{########1/#5[########2]}\xint: }% \def##3########1\xint:########2\xint: {% \expandafter##4% \romannumeral0\xintadd{####4}% {\XINTinFloat[####2]{\xintMul{########1}{########2}}}\xint: }% }% }% \expandafter\XINT_tmpb \csname XINT_Exp_series_a_\romannumeral\numexpr#1\expandafter\endcsname \csname XINT_Exp_series_a_\romannumeral\numexpr#1-1\expandafter\endcsname \csname XINT_Exp_series_c_\romannumeral\numexpr#1-2\expandafter\endcsname \csname XINT_Exp_series_c_\romannumeral\numexpr#1-3\endcsname \expandafter\XINT_tmpc \the\numexpr\XINTdigitsormax-#2\expandafter.% \the\numexpr\XINTdigitsormax-#3\expandafter.\expanded{% \XINTinFloat[\XINTdigitsormax-#3]{1/#6[0]}.% \XINTinFloat[\XINTdigitsormax-#4]{1/#7[0]}.% }% }% \XINT_tmpa 5 26 19 13 120 24 6 %<-- keep space \ifnum\XINTdigits>35 \XINT_tmpa 6 33 26 19 720 120 24 \fi \ifnum\XINTdigits>42 \XINT_tmpa 7 40 33 26 5040 720 120 \fi \ifnum\XINTdigits>48 \XINT_tmpa 8 46 40 33 40320 5040 720 \fi \ifnum\XINTdigits>55 \XINT_tmpa 9 53 46 40 362880 40320 5040 \fi \fi % \end{macrocode} % \subsection{April 2021: at last \csh{XINTinFloagLogTen}, \csh{XINTinFloatLog}} %\begin{lverb} % Attention that this is not supposed to be used with \XINTdigits at % 8 or less, it will crash if that is the case. The log10() and log() % functions in case \XINTdigits is at most 8 are mapped to \PoormanLogBaseTen % respectively \PoormanLog macros. % % In the explications here I use the function names rather than the macro % names. % % Both log(x) and log10(x) are on top of an underlying macro which will % produce z and h such that x is about 10^z e^h (with h being small is % obtained via a log series). Then log(x) computes log(10)z+h whereas log10(x) % computes as z+h/log(10). % % There will be three branches [NO FINALLY ONLY TWO BRANCHES SINCE 1.4f] % according to situation of x relative to 1. Let y be the math value log10(x) % that we want to approximate to target precision P digits. P is assumed at % least 9. % % I will describe the algorithm roughly, but skip its underlying support % analysis; at some point I mention "fixed point calculations", but in % practice it is not done exactly that way, but describing it would be % complicated so look at the code which is very readable (by the author, at % the present time). % % First we compute z = ±n.d_1d_2...d_6 as the rounded to 6 fractional digits % approximation of y=log10(x) obtained by first using the poormanlog macros on x % (float rounded to 9 digits) then rounding as above. % % Warning: this description is not in sync with the code, now the case where % d_1d_2...d_6 is 000000 is filtered out and one jumps directly either to case % I if n≠0 or to case III if n=0. The case when rounding produces a z equal % to zero is also handled especially. % % WARNING: at 1.4f, the CASE I was REMOVED. Everything is handled as CASE II % or exceptionally case III. Indeed this removal was observed to simply cost % about 10$% extra time at D=16 digits, which was deemed an acceptable cost. % The cost is certainly higher at D=9 but also relatively lower at high % D's. It means that logarithms are always computed with 9, not 4, safety % **fractional** digits, and this allows to compute powers accurately with % exponents say up to 1e7, degradation starting to show at 1e8 and for sure at % 1e9. However for integer and half-integer exponents the old routine % \xintFloatPower will still be used, and perhaps it will need some increased % precision update as the documented 0.52ulp error bound is higher than our % more stringent standards of 2021. % % CASE I: [removed at 1.4f!] % either n is NOT zero or d_1d_2....d_6 is at least 100001. Then we % compute X = 10^(-z)*x which is near 1, by using the table of powers of % 10, using P+5 digits significands. Then we compute (exactly) eta = X-1, % (which is in absolute value less than 0.0000012) % and obtain % y as z + log(10)^(-1) times log(1+eta) % where log(1+eta) = eta - eta^2/2 + eta^3/3- ... is "computed with % P+4 fractional fixed point digits" [1]_ according to the following table: % %( - maximal value of P: 9, 15, 21, 27, 33, 39, 45, 51, 57, 63 %: - last included term: /1, /2, /3, /4, /5, /6, /7, /8, /9, /10 %) % % .. [1] this "P+4" includes leading fractional zeroes so in practice it will % rather be done as eta(1 - eta(1/2 + eta(1/3-...))), and the inner sums will % be done in various precisions, the top level (external) eta probably at P-1 % digits, the first inner eta at P-7 digits, the next at P-13, something in % this style. The heuristics is simple: at P=9 we don't need the first inner % eta, so let's use there P-9 or rather P-7 digits by security. Similarly at % P=3 we would not need at all the eta, so let's use the top level one rounded % at P-3+2 = P-1 digits. And there is a shift by 6 less digits at each inner % level. RÉFLÉCHIR SI C'EST PAS PLUTÔT P-2 ICI, suffisant au regard de la % précision par ailleurs pour la réduction près de 1. % % The sequence of maximal P's is simply an arithmetic progression. % % The addition of z will trigger the final rounding to P digits. % The inverse of log(10) is precomputed with P+4 digits. % % This case I essentially handles x such as max(x,1/x)>10^0.1=1.2589... % % CASE II: n is zero and d_1d_2....d_6 is not zero. We operate as in CASE I, % up to the following differences: %( - the table of fractional powers of 10 is used with P+10 significands. %: - the X is also computed with P+10 digits, i.e. eta = X-1 (which obeys& % the given estimate) is estimated with P+9 [2]_ fractional fixed points digits& % and the log series will be evaluated in this sense. %: - the constant log(10)^(-1) is still used with only P+4 digits %) % % The log series is terminated according to the following table: %( - maximal value of P: 4, 10, 16, 22, 28, 34, 40, 46, 52, 58, 64 %: - last included term: /1, /2, /3, /4, /5, /6, /7, /8, /9, /10 %) % % Again the P's are in arithmetic progression, the same as before shifted by % 5. % % .. [2] same remark as above. The top level eta in eta(1 - eta(1/2 - % eta(...))) will use P+4 significant digits, but the first inner eta will be % used with only P-2 digits, the next inner one with P-8 digits etc... % % This case II handles the x which are near 1, but not as close as 10^±0.000001. % % CASE III: z=0. In this case X = x = 1+eta and we use the log series in % this sense : log(10)^(-1)*eta*(1 - eta/2 + eta^2/3-....) % where again log(10)^(-1) has been precomputed with P+4 digits % and morally the series uses P+4 fractional digits (P+3 would probably % be enough for the precision I want, need to check my notes) % and the thresholds table is: %( - maximal value of P: 3, 9, 15, 21, 27, 33, 39, 45, 51, 57, 63 %: - last included term: /1, /2, /3, /4, /5, /6, /7, /8, /9, /10, /11 %) % % This is same progression but shifted by one. % % To summarize some relevant aspects: %( - this algorithm uses only log(10)^(-1) as precomputed logarithm %: - in particular the logarithms of small integers 2, 3, 5,... are& % not pre-computed. Added note: I have now tested at 16, 32, 48 and 62& % digits that all of the log10(n), for n = 1..1000, are computed with& % correct rounding. In fact, generally speaking, random testing of a& % about 20000 inputs has failed to reveal a single non-correct& % rounding. Naturally, randomly testing is not the way to corner& % the software into its weak points... %: - it uses two tables of fractional powers of ten: one with P+5 digits and& % another one with extended precision at P+10 digits. %: - it needs three distinct implementations of the log series. %: - it does not use the well-known trick reducing to using only odd powers& % in the log series (somehow I have come to dread divisions, even though& % here as is well-known it could be replaced with some product, my& % impression was that what is gained on one side is lost on the other,& % for the range of P I am targeting, i.e. P up to about 60.) %: - all of this is experimental (in particular the previous item was not& % done perhaps out of sheer laziness) %) % % Absolutely no error check is done whether the input x is really positive. % As seen above the maximal target precision is 63 (not 64). % % Update for 1.4f: when the logarithm is computed via case I, i.e. basically % always except roughly for 0.8<a<1.26, its fractional part has only about 4 % safety digits. This is barely enough for a^b with b near 1000 and certainly % not enough for a^b with b of the order 10000. % % I hesitated with the option to always handle b as N+h with N integer for % which we can use old \xintFloatPower (which perhaps I will have to update to % ensure better than the 0.52ulp it mentions in its documentation). But in % the end, I decided to simply add a variant where case I is handled as case % II, i.e. with 9 not 4 safety fractional digits for the logarithm. This % variant will be the one used by the power function for fractional exponents % (non integer, non half-integer). % %\end{lverb} % \begin{macrocode} \def\XINT_tmpa#1.{% \def\XINTinFloatLog{\romannumeral0\XINTinfloatlog}% \def\XINTinfloatlog {% \expandafter\XINT_log_out \romannumeral0\expandafter\XINT_logtenxdg_a \romannumeral0\XINTinfloat[#1]%{##1} }% \def\XINT_log_out ##1\xint:##2\xint: {% \XINTinfloat[#1]% {\xintAdd{\xintMul{\XINT_c_logten}{##1}}{##2}}% }% \def\XINTinFloatLogTen{\romannumeral0\XINTinfloatlogten}% \def\XINTinfloatlogten {% \expandafter\XINT_logten_out \romannumeral0\expandafter\XINT_logtenxdg_a \romannumeral0\XINTinfloat[#1]%{##1} }% \def\XINT_logten_out ##1\xint:##2\xint: {% \XINTinfloat[#1]% {\xintAdd{##1}{\xintMul{\XINT_c_oneoverlogten}{##2}}}% }% }\expandafter\XINT_tmpa\the\numexpr\XINTdigitsormax.% \def\XINTinFloatLogTen_xdgout%#1[#2] {% \romannumeral0\expandafter\XINT_logten_xdgout\romannumeral0\XINT_logtenxdg_a }% \def\XINT_logten_xdgout #1\xint:#2\xint: {% \xintadd{#1}{\xintMul{\XINT_c_oneoverlogten_xx}{#2}}% }% % \end{macrocode} %\begin{lverb} % No check is done whether input is negative or vanishes. We apply % \XINTinfloat[9] which if input is not zero always produces 9 digits (and % perhaps a minus sign) the first digit is non-zero. This is the expected % input to \numexpr\PML@<digits><dot>.\relax % % The variants xdg_a, xdg_b, xdg_c, xdg_d were added at 1.4f to always go via % II or III, ensuring more fractional digits to the logarithm for accuracy of % fractional powers with big exponents. "Old" 1.4e routines were removed. %\end{lverb} % \begin{macrocode} \def\XINT_logtenxdg_a#1[#2]% {% \expandafter\XINT_logtenxdg_b \romannumeral0\XINTinfloat[9]{#1[#2]}#1[#2]% }% \def\XINT_logtenxdg_b#1[#2]% {% \expandafter\XINT_logtenxdg_c \romannumeral0\xintround{6}% {\xintiiAdd{\xintDSx{-9}{\the\numexpr#2+8\relax}}% {\the\numexpr\PML@#1.\relax}% [-9]}% \xint: }% % \end{macrocode} %\begin{lverb} % If we were either in 100000000[0] or 999999999[-1] for the #1[#2] % \XINT_logten_b input, and only in those cases, the \xintRound{6} produced % "0". We are very near 1 and will treat this as case III, but this is % sub-optimal. %\end{lverb} % \begin{macrocode} \def\XINT_logtenxdg_c #1#2% {% \xint_gob_til_xint:#2\XINT_logten_IV\xint: \XINT_logtenxdg_d #1#2% }% \def\XINT_logten_IV\xint:\XINT_logtenxdg_d0{\XINT_logten_f_III}% % \end{macrocode} %\begin{lverb} % Here we are certain that \xintRound{6} produced a decimal point and % 6 fractional digit tokens #2, but they can be zeros and also -0.000000 is possible. % % If #1 vanishes and #2>100000 we are in case I. % % If #1 vanishes and 100000>=#2>0 we are in case II. % % If #1 and #2 vanish we are in case III. % % If #1 does not vanish we are in case I with a direct quicker access if #2 vanishes. % % Attention to the sign of #1, it is checked later on. % % At 1.4f, we handle the case I with as many digits as case II (and exceptionnally case III). % %\end{lverb} % \begin{macrocode} \def\XINT_logtenxdg_d #1.#2\xint: {% \ifcase \ifnum#1=\xint_c_ \ifnum #2=\xint_c_ \xint_c_iii\else \xint_c_ii\fi \else \ifnum#2>\xint_c_ \xint_c_ii\else \xint_c_\fi \fi \expandafter\XINT_logten_f_Isp \or% never \or\expandafter\XINT_logten_f_IorII \else\expandafter\XINT_logten_f_III \fi #1.#2\xint: }% \def\XINT_logten_f_IorII#1% {% \xint_UDsignfork #1\XINT_logten_f_IorII_neg -\XINT_logten_f_IorII_pos \krof #1% }% % \end{macrocode} %\begin{lverb} % We are here only with a non-zero ##1, so no risk of a -0[0] which % would be illegal usage of A[N] raw format. A negative ##1 is no trouble in ##3-##1. %\end{lverb} % \begin{macrocode} \def\XINT_tmpa#1.{% \def\XINT_logten_f_Isp##1.000000\xint:##2[##3]% {% {##1[0]}\xint: {\expandafter\XINT_LogTen_serII_a_ii \romannumeral0\XINTinfloatS[#1]{\xintAdd{##2[##3-##1]}{-1[0]}}% \xint: }\xint: }% }\expandafter\XINT_tmpa\the\numexpr\XINTdigitsormax.% \def\XINT_tmpa#1.{% \def\XINT_logten_f_III##1\xint:##2[##3]% {% {0[0]}\xint: {\expandafter\XINT_LogTen_serIII_a_ii \romannumeral0\XINTinfloatS[#1]{\xintAdd{##2[##3]}{-1[0]}}% \xint: }\xint: }}\expandafter\XINT_tmpa\the\numexpr\XINTdigitsormax+4.% \def\XINT_tmpa#1.#2.{% \def\XINT_logten_f_IorII_pos##1.##2##3##4##5##6##7\xint:##8[##9]% {% {\the\numexpr##1##2##3##4##5##6##7[-6]}\xint: {\expandafter\XINT_LogTen_serII_a_ii \romannumeral0\XINTinfloat[#2]% {\xintAdd{-1[0]}% {\xintMul{\csname XINT_c_1_##2_inv_x\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_2_##3_inv_x\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_3_##4_inv_x\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_4_##5_inv_x\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_5_##6_inv_x\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_6_##7_inv_x\endcsname} {##8[##9-##1]}% }}}}}}}}}}% }% }\xint: }\xint: }% \def\XINT_logten_f_IorII_neg##1.##2##3##4##5##6##7\xint:##8[##9]% {% {\the\numexpr##1##2##3##4##5##6##7[-6]}\xint: {\expandafter\XINT_LogTen_serII_a_ii \romannumeral0\XINTinfloat[#2]% {\xintAdd{-1[0]}% {\xintMul{\csname XINT_c_1_##2_x\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_2_##3_x\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_3_##4_x\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_4_##5_x\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_5_##6_x\endcsname}{% \XINTinFloat[#1]{% \xintMul{\csname XINT_c_6_##7_x\endcsname} {##8[##9-##1]}% }}}}}}}}}}% }% }\xint: }\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax+10\expandafter.\the\numexpr\XINTdigitsormax+4.% % \end{macrocode} %\begin{lverb} % Initially all of this was done in a single big nested macro but the % float-rounding of argument to less digits worked again each time from % initial long input; the advantage on the other hand was that the 1/i % constants were all pre-computed and rounded. % % Pre-coding the successive rounding to six digits less at each stage could be % done via a single loop which would then walk back up inserting coeffs like % 1/#1 having no special optimizing tricks. Pre-computing the 1/#1 too is % possible but then one would have to copy the full set of such constants % (which would be pre-computed depending on P), and this will add grabbing % overhead in the loop expansion. Or one defines macros to hold the % pre-rounded constants. % % Finally I do define macros, not only to hold the constants but to hold the % whole build-up. Sacrificing brevity of code to benefit of expansion "speed". % % Firts one prepares eta, with P+4 digits for mantissa, and then hands it over % to the log series. This will proceed via first preparing eta\xint: eta\xint: % .... eta\xint:, the leftmost ones being more and more reduced in number of % digits. Finally one goes back up to the right, the hard-coded number of % steps depending on value of P=\XINTdigits at time of reloading of % package. This number of steps is hard-coded in the number of macros which % get defined. % % Descending (leftwards) chain: _a, Turning point: _b, Ascending: _c. % % As it is very easy to make silly typing mistakes in the numerous macros I % have refactored a number of times the set-up to make manual verification % straightforward. Automatization is possible but the _b macros complicate % things, each one is its own special case. In the end the set-up will define % then redefine some _a and the (finally unique) _b macro, this allows easier % to read code, with no nesting of conditionals or else branches. % % Actually series III and series II differ by only a shift by and we could use % always the slightly more costly series III in place of series II. But that % would add one un-needed term and a bit overhead to the default P which is % 16... % % (1.4f: hesitation on 2021/05/09 after removal or case I log series should % I not follow the simplifying logic and use always the slightly more costly III?) %\end{lverb} % % \subsubsection{Log series, case II} % \begin{macrocode} \def\XINT_tmpa#1.#2.{% \def\XINT_LogTen_serII_a_ii##1\xint: {% \expandafter\XINT_LogTen_serII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_b#1[#2]\xint: {% \expandafter\XINT_LogTen_serII_c_ \romannumeral0\xintadd{1}{\xintiiOpp\xintHalf{#10}[#2-1]}\xint: }% \def\XINT_LogTen_serII_c_##1\xint:##2\xint: {% \XINTinFloat[#2]{\xintMul{##1}{##2}}% }% }% \expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-2\expandafter.% \the\numexpr\XINTdigitsormax+4.% \ifnum\XINTdigits>10 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serII_a_ii##1\xint: {% \expandafter\XINT_LogTen_serII_a_iii \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_a_iii##1\xint: {% \expandafter\XINT_LogTen_serII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serII_c_i \romannumeral0\xintadd{#3}{##1/3[##2]}\xint: }% \def\XINT_LogTen_serII_c_i##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serII_c_ \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-8\expandafter.% \the\numexpr\XINTdigitsormax-2.% {-5[-1]}.% {1[0]}.% \fi \ifnum\XINTdigits>16 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serII_a_iii##1\xint: {% \expandafter\XINT_LogTen_serII_a_iv \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_a_iv##1\xint: {% \expandafter\XINT_LogTen_serII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serII_c_ii \romannumeral0\xintadd{#3}{\xintiiMul{-25}{##1}[##2-2]}\xint: }% \def\XINT_LogTen_serII_c_ii##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serII_c_i \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-14\expandafter.% \the\numexpr\XINTdigitsormax-8\expandafter.% \romannumeral0\XINTinfloat[\XINTdigitsormax-8]{1/3[0]}.% {-5[-1]}.% \fi \ifnum\XINTdigits>22 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serII_a_iv##1\xint: {% \expandafter\XINT_LogTen_serII_a_v \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_a_v##1\xint: {% \expandafter\XINT_LogTen_serII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serII_c_iii \romannumeral0\xintadd{#3}{\xintDouble{##1}[##2-1]}\xint: }% \def\XINT_LogTen_serII_c_iii##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serII_c_ii \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-20\expandafter.% \the\numexpr\XINTdigitsormax-14\expandafter.\expanded{% {-25[-2]}.% \XINTinFloat[\XINTdigitsormax-8]{1/3[0]}.% }% \fi \ifnum\XINTdigits>28 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serII_a_v##1\xint: {% \expandafter\XINT_LogTen_serII_a_vi \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_a_vi##1\xint: {% \expandafter\XINT_LogTen_serII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serII_c_iv \romannumeral0\xintadd{#3}{\xintiiOpp##1/6[##2]}\xint: }% \def\XINT_LogTen_serII_c_iv##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serII_c_iii \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-26\expandafter.% \the\numexpr\XINTdigitsormax-20.% {2[-1]}.% {-25[-2]}.% \fi \ifnum\XINTdigits>34 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serII_a_vi##1\xint: {% \expandafter\XINT_LogTen_serII_a_vii \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_a_vii##1\xint: {% \expandafter\XINT_LogTen_serII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serII_c_v \romannumeral0\xintadd{#3}{##1/7[##2]}\xint: }% \def\XINT_LogTen_serII_c_v##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serII_c_iv \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-32\expandafter.% \the\numexpr\XINTdigitsormax-26\expandafter.% \romannumeral0\XINTinfloatS[\XINTdigitsormax-26]{-1/6[0]}.% {2[-1]}.% \fi \ifnum\XINTdigits>40 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serII_a_vii##1\xint: {% \expandafter\XINT_LogTen_serII_a_viii \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_a_viii##1\xint: {% \expandafter\XINT_LogTen_serII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serII_c_vi \romannumeral0\xintadd{#3}{\xintiiMul{-125}{##1}[##2-3]}\xint: }% \def\XINT_LogTen_serII_c_vi##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serII_c_v \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-38\expandafter.% \the\numexpr\XINTdigitsormax-32\expandafter.\expanded{% \XINTinFloat[\XINTdigitsormax-32]{1/7[0]}.% \XINTinFloat[\XINTdigitsormax-26]{-1/6[0]}.% }% \fi \ifnum\XINTdigits>46 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serII_a_viii##1\xint: {% \expandafter\XINT_LogTen_serII_a_ix \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_a_ix##1\xint: {% \expandafter\XINT_LogTen_serII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serII_c_vii \romannumeral0\xintadd{#3}{##1/9[##2]}\xint: }% \def\XINT_LogTen_serII_c_vii##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serII_c_vi \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-44\expandafter.% \the\numexpr\XINTdigitsormax-38\expandafter.\expanded{% {-125[-3]}.% \XINTinFloat[\XINTdigitsormax-32]{1/7[0]}.% }% \fi \ifnum\XINTdigits>52 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serII_a_ix##1\xint: {% \expandafter\XINT_LogTen_serII_a_x \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_a_x##1\xint: {% \expandafter\XINT_LogTen_serII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serII_c_viii \romannumeral0\xintadd{#3}{\xintiiOpp##1[##2-1]}\xint: }% \def\XINT_LogTen_serII_c_viii##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serII_c_vii \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-50\expandafter.% \the\numexpr\XINTdigitsormax-44\expandafter.% \romannumeral0\XINTinfloat[\XINTdigitsormax-44]{1/9[0]}.% {-125[-3]}.% \fi \ifnum\XINTdigits>58 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serII_a_x##1\xint: {% \expandafter\XINT_LogTen_serII_a_xi \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_a_xi##1\xint: {% \expandafter\XINT_LogTen_serII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serII_c_ix \romannumeral0\xintadd{#3}{##1/11[##2]}\xint: }% \def\XINT_LogTen_serII_c_ix##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serII_c_viii \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-56\expandafter.% \the\numexpr\XINTdigitsormax-50\expandafter.\expanded{% {-1[-1]}.% \XINTinFloat[\XINTdigitsormax-44]{1/9[0]}.% }% \fi % \end{macrocode} % \subsubsection{Log series, case III} % \begin{macrocode} \def\XINT_tmpa#1.#2.{% \def\XINT_LogTen_serIII_a_ii##1\xint: {% \expandafter\XINT_LogTen_serIII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_b#1[#2]\xint: {% \expandafter\XINT_LogTen_serIII_c_ \romannumeral0\xintadd{1}{\xintiiOpp\xintHalf{#10}[#2-1]}\xint: }% \def\XINT_LogTen_serIII_c_##1\xint:##2\xint: {% \XINTinFloat[#2]{\xintMul{##1}{##2}}% }% }% \expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-1\expandafter.% \the\numexpr\XINTdigitsormax+4.% \ifnum\XINTdigits>9 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serIII_a_ii##1\xint: {% \expandafter\XINT_LogTen_serIII_a_iii \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_a_iii##1\xint: {% \expandafter\XINT_LogTen_serIII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serIII_c_i \romannumeral0\xintadd{#3}{##1/3[##2]}\xint: }% \def\XINT_LogTen_serIII_c_i##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serIII_c_ \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-7\expandafter.% \the\numexpr\XINTdigitsormax-1.% {-5[-1]}.% {1[0]}.% \fi \ifnum\XINTdigits>15 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serIII_a_iii##1\xint: {% \expandafter\XINT_LogTen_serIII_a_iv \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_a_iv##1\xint: {% \expandafter\XINT_LogTen_serIII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serIII_c_ii \romannumeral0\xintadd{#3}{\xintiiMul{-25}{##1}[##2-2]}\xint: }% \def\XINT_LogTen_serIII_c_ii##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serIII_c_i \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-13\expandafter.% \the\numexpr\XINTdigitsormax-7\expandafter.% \romannumeral0\XINTinfloat[\XINTdigitsormax-7]{1/3[0]}.% {-5[-1]}.% \fi \ifnum\XINTdigits>21 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serIII_a_iv##1\xint: {% \expandafter\XINT_LogTen_serIII_a_v \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_a_v##1\xint: {% \expandafter\XINT_LogTen_serIII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serIII_c_iii \romannumeral0\xintadd{#3}{\xintDouble{##1}[##2-1]}\xint: }% \def\XINT_LogTen_serIII_c_iii##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serIII_c_ii \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-19\expandafter.% \the\numexpr\XINTdigitsormax-13\expandafter.\expanded{% {-25[-2]}.% \XINTinFloat[\XINTdigitsormax-7]{1/3[0]}.% }% \fi \ifnum\XINTdigits>27 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serIII_a_v##1\xint: {% \expandafter\XINT_LogTen_serIII_a_vi \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_a_vi##1\xint: {% \expandafter\XINT_LogTen_serIII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serIII_c_iv \romannumeral0\xintadd{#3}{\xintiiOpp##1/6[##2]}\xint: }% \def\XINT_LogTen_serIII_c_iv##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serIII_c_iii \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-25\expandafter.% \the\numexpr\XINTdigitsormax-19.% {2[-1]}.% {-25[-2]}.% \fi \ifnum\XINTdigits>33 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serIII_a_vi##1\xint: {% \expandafter\XINT_LogTen_serIII_a_vii \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_a_vii##1\xint: {% \expandafter\XINT_LogTen_serIII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serIII_c_v \romannumeral0\xintadd{#3}{##1/7[##2]}\xint: }% \def\XINT_LogTen_serIII_c_v##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serIII_c_iv \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-31\expandafter.% \the\numexpr\XINTdigitsormax-25\expandafter.% \romannumeral0\XINTinfloatS[\XINTdigitsormax-25]{-1/6[0]}.% {2[-1]}.% \fi \ifnum\XINTdigits>39 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serIII_a_vii##1\xint: {% \expandafter\XINT_LogTen_serIII_a_viii \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_a_viii##1\xint: {% \expandafter\XINT_LogTen_serIII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serIII_c_vi \romannumeral0\xintadd{#3}{\xintiiMul{-125}{##1}[##2-3]}\xint: }% \def\XINT_LogTen_serIII_c_vi##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serIII_c_v \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-37\expandafter.% \the\numexpr\XINTdigitsormax-31\expandafter.\expanded{% \XINTinFloat[\XINTdigitsormax-31]{1/7[0]}.% \XINTinFloat[\XINTdigitsormax-25]{-1/6[0]}.% }% \fi \ifnum\XINTdigits>45 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serIII_a_viii##1\xint: {% \expandafter\XINT_LogTen_serIII_a_ix \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_a_ix##1\xint: {% \expandafter\XINT_LogTen_serIII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serIII_c_vii \romannumeral0\xintadd{#3}{##1/9[##2]}\xint: }% \def\XINT_LogTen_serIII_c_vii##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serIII_c_vi \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-43\expandafter.% \the\numexpr\XINTdigitsormax-37\expandafter.\expanded{% {-125[-3]}.% \XINTinFloat[\XINTdigitsormax-31]{1/7[0]}.% }% \fi \ifnum\XINTdigits>51 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serIII_a_ix##1\xint: {% \expandafter\XINT_LogTen_serIII_a_x \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_a_x##1\xint: {% \expandafter\XINT_LogTen_serIII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serIII_c_viii \romannumeral0\xintadd{#3}{\xintiiOpp##1[##2-1]}\xint: }% \def\XINT_LogTen_serIII_c_viii##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serIII_c_vii \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-49\expandafter.% \the\numexpr\XINTdigitsormax-43\expandafter.% \romannumeral0\XINTinfloat[\XINTdigitsormax-43]{1/9[0]}.% {-125[-3]}.% \fi \ifnum\XINTdigits>57 \def\XINT_tmpa#1.#2.#3.#4.{% \def\XINT_LogTen_serIII_a_x##1\xint: {% \expandafter\XINT_LogTen_serIII_a_xi \romannumeral0\XINTinfloatS[#2]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_a_xi##1\xint: {% \expandafter\XINT_LogTen_serIII_b \romannumeral0\XINTinfloatS[#1]{##1}\xint:##1\xint: }% \def\XINT_LogTen_serIII_b##1[##2]\xint: {% \expandafter\XINT_LogTen_serIII_c_ix \romannumeral0\xintadd{#3}{##1/11[##2]}\xint: }% \def\XINT_LogTen_serIII_c_ix##1\xint:##2\xint: {% \expandafter\XINT_LogTen_serIII_c_viii \romannumeral0\xintadd{#4}{\XINTinFloat[#2]{\xintMul{##1}{##2}}}\xint: }% }\expandafter\XINT_tmpa \the\numexpr\XINTdigitsormax-55\expandafter.% \the\numexpr\XINTdigitsormax-49\expandafter.\expanded{% {-1[-1]}.% \XINTinFloat[\XINTdigitsormax-43]{1/9[0]}.% }% \fi \XINTlogendinput% % \end{macrocode} % \StoreCodelineNo {xintlog} % \cleardoublepage\let\xintlognameUp\undefined % \MakePercentComment %</xintlog>------------------------------------------------------ %<*dtx>----------------------------------------------------------- \iffalse % grep -c -e "^{%" xint*sty xint.sty:205 xintbinhex.sty:53 xintcfrac.sty:183 xintcore.sty:267 xintexpr.sty:461 xintfrac.sty:522 xintgcd.sty:41 xintkernel.sty:17 xintlog.sty:149 xintseries.sty:48 xinttools.sty:157 xinttrig.sty:66 \fi % grep -o "^{%" xint*sty | wc -l \def\totala{ 2169} \iffalse % grep -c -e "^}%" xint*sty xint.sty:204 xintbinhex.sty:52 xintcfrac.sty:183 xintcore.sty:265 xintexpr.sty:442 xintfrac.sty:530 xintgcd.sty:43 xintkernel.sty:18 xintlog.sty:150 xintseries.sty:48 xinttools.sty:156 xinttrig.sty:65 \fi % grep -o "^}%" xint*sty | wc -l \def\totalb{ 2156} \cleardoublepage \section{Cumulative line and macro count} % le 6 juin 2022 j'ajoute le décompte des macros \def\mymacro #1{\mymacroaux #1} \def\mymacroaux #1#2#3{\strut \csname #1nameimp\endcsname&\dtt{#2}&(\dtt{#3})\tabularnewline } \indent \begin{tabular}[t]{rrr} module&lines¯os\tabularnewline \xintApplyInline\mymacro\storedlinecounts \end{tabular} \hfil \begin{minipage}[t]{10cm} \def\mymacroaux #1#2#3{#2}% 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. \bigskip \def\mymacroaux #1#2#3{#3}% Total number of def'ed (or let'ed) macros: \dtt{\the\numexpr \xintListWithSep+{\xintApply\mymacro\storedlinecounts}\relax }. This is an approximation as some macros are def'ed in a way escaping the automated detection, in particular this applies to \xintexprnameimp macros associated to infix operators and syntax elements, whose construction uses |\csname|-based definitions with a template and auxiliary macros. Their number has been evaluated manually at being at least about \dtt{452} (this is incorporated into the \xintexprnameimp count shown left, and the total above.) \bigskip Version {\xintbndlversion} of {\xintbndldate}.\par \end{minipage} \CheckSum {38900}% 1.4m % 39032 pour 1.4l % 38925 pour 1.4k, 38590 pour 1.4j, 38591 pour 1.4i, 38427 pour 1.4h % 38423 pour 1.4g, 38212 pour 1.4f, 38813 pour 1.4e, 35184 pour 1.4d % 35109 pour 1.4c, 35103 pour 1.4b, 34648 pour 1.4a, 34575 pour 1.4 % 33497 pour 1.3f, 33274 pour 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