diff options
author | Norbert Preining <norbert@preining.info> | 2020-02-02 03:02:06 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2020-02-02 03:02:06 +0000 |
commit | e05dc0bb38b16bfb9ba35591285e40af0adaadc4 (patch) | |
tree | 564fc3b7389c845780f5685d16fe13ae29372fb4 /macros/generic/xint | |
parent | 5bcf334281674db82263ea71485108bd44a05a5d (diff) |
CTAN sync 202002020302
Diffstat (limited to 'macros/generic/xint')
-rw-r--r-- | macros/generic/xint/CHANGES.html | 313 | ||||
-rw-r--r-- | macros/generic/xint/CHANGES.pdf | bin | 105478 -> 0 bytes | |||
-rw-r--r-- | macros/generic/xint/Makefile | 14 | ||||
-rw-r--r-- | macros/generic/xint/README | 205 | ||||
-rw-r--r-- | macros/generic/xint/README.html | 133 | ||||
-rw-r--r-- | macros/generic/xint/README.md | 116 | ||||
-rw-r--r-- | macros/generic/xint/README.pdf | bin | 32975 -> 0 bytes | |||
-rw-r--r-- | macros/generic/xint/sourcexint.pdf | bin | 929151 -> 981183 bytes | |||
-rw-r--r-- | macros/generic/xint/xint.dtx | 19223 | ||||
-rw-r--r-- | macros/generic/xint/xint.pdf | bin | 993327 -> 944806 bytes |
10 files changed, 10432 insertions, 9572 deletions
diff --git a/macros/generic/xint/CHANGES.html b/macros/generic/xint/CHANGES.html index cf755b8ddb..f6b53aa447 100644 --- a/macros/generic/xint/CHANGES.html +++ b/macros/generic/xint/CHANGES.html @@ -4,7 +4,7 @@ <meta charset="utf-8" /> <meta name="generator" content="pandoc" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> - <meta name="author" content="xint 1.3f" /> + <meta name="author" content="xint 1.4" /> <title>CHANGE LOG</title> <style type="text/css"> code{white-space: pre-wrap;} @@ -25,128 +25,134 @@ <body> <header> <h1 class="title">CHANGE LOG</h1> -<p class="author">xint 1.3f</p> -<p class="date">2019/09/10</p> +<p class="author">xint 1.4</p> +<p class="date">2020/01/31</p> </header> <nav id="TOC"> <ul> -<li><a href="#f-20190910"><code>1.3f (2019/09/10)</code></a><ul> +<li><a href="#section"><code>1.4 (2020/01/31)</code></a><ul> +<li><a href="#breaking-changes">Breaking changes</a></li> <li><a href="#improvements-and-new-features">Improvements and new features</a></li> <li><a href="#bug-fixes">Bug fixes</a></li> +<li><a href="#todo">TODO</a></li> </ul></li> -<li><a href="#e-20190405"><code>1.3e (2019/04/05)</code></a><ul> -<li><a href="#incompatible-changes">Incompatible changes</a></li> +<li><a href="#f-20190910"><code>1.3f (2019/09/10)</code></a><ul> <li><a href="#improvements-and-new-features-1">Improvements and new features</a></li> <li><a href="#bug-fixes-1">Bug fixes</a></li> </ul></li> -<li><a href="#d-20190106"><code>1.3d (2019/01/06)</code></a><ul> -<li><a href="#incompatible-changes-1">Incompatible changes</a></li> +<li><a href="#e-20190405"><code>1.3e (2019/04/05)</code></a><ul> +<li><a href="#breaking-changes-1">Breaking changes</a></li> <li><a href="#improvements-and-new-features-2">Improvements and new features</a></li> <li><a href="#bug-fixes-2">Bug fixes</a></li> </ul></li> -<li><a href="#c-20180617"><code>1.3c (2018/06/17)</code></a><ul> +<li><a href="#d-20190106"><code>1.3d (2019/01/06)</code></a><ul> +<li><a href="#breaking-changes-2">Breaking changes</a></li> <li><a href="#improvements-and-new-features-3">Improvements and new features</a></li> <li><a href="#bug-fixes-3">Bug fixes</a></li> </ul></li> -<li><a href="#b-20180518"><code>1.3b (2018/05/18)</code></a><ul> +<li><a href="#c-20180617"><code>1.3c (2018/06/17)</code></a><ul> <li><a href="#improvements-and-new-features-4">Improvements and new features</a></li> +<li><a href="#bug-fixes-4">Bug fixes</a></li> </ul></li> -<li><a href="#a-20180307"><code>1.3a (2018/03/07)</code></a><ul> -<li><a href="#removed">Removed</a></li> +<li><a href="#b-20180518"><code>1.3b (2018/05/18)</code></a><ul> <li><a href="#improvements-and-new-features-5">Improvements and new features</a></li> -<li><a href="#bug-fixes-4">Bug fixes</a></li> </ul></li> -<li><a href="#section"><code>1.3 (2018/03/01)</code></a><ul> -<li><a href="#incompatible-changes-2">Incompatible changes</a></li> +<li><a href="#a-20180307"><code>1.3a (2018/03/07)</code></a><ul> +<li><a href="#removed">Removed</a></li> <li><a href="#improvements-and-new-features-6">Improvements and new features</a></li> +<li><a href="#bug-fixes-5">Bug fixes</a></li> </ul></li> -<li><a href="#q-20180206"><code>1.2q (2018/02/06)</code></a><ul> +<li><a href="#section-1"><code>1.3 (2018/03/01)</code></a><ul> +<li><a href="#breaking-changes-3">Breaking changes</a></li> <li><a href="#improvements-and-new-features-7">Improvements and new features</a></li> -<li><a href="#bug-fixes-5">Bug fixes</a></li> </ul></li> -<li><a href="#p-20171205"><code>1.2p (2017/12/05)</code></a><ul> -<li><a href="#incompatible-changes-3">Incompatible changes</a></li> +<li><a href="#q-20180206"><code>1.2q (2018/02/06)</code></a><ul> <li><a href="#improvements-and-new-features-8">Improvements and new features</a></li> <li><a href="#bug-fixes-6">Bug fixes</a></li> </ul></li> +<li><a href="#p-20171205"><code>1.2p (2017/12/05)</code></a><ul> +<li><a href="#breaking-changes-4">Breaking changes</a></li> +<li><a href="#improvements-and-new-features-9">Improvements and new features</a></li> +<li><a href="#bug-fixes-7">Bug fixes</a></li> +</ul></li> <li><a href="#o-20170829"><code>1.2o (2017/08/29)</code></a><ul> -<li><a href="#incompatible-changes-4">Incompatible changes</a></li> +<li><a href="#breaking-changes-5">Breaking changes</a></li> <li><a href="#deprecated">Deprecated</a></li> </ul></li> <li><a href="#n-20170806"><code>1.2n (2017/08/06)</code></a><ul> -<li><a href="#incompatible-changes-5">Incompatible changes</a></li> -<li><a href="#improvements-and-new-features-9">Improvements and new features</a></li> -</ul></li> -<li><a href="#m-20170731"><code>1.2m (2017/07/31)</code></a><ul> -<li><a href="#incompatible-changes-6">Incompatible changes</a></li> +<li><a href="#breaking-changes-6">Breaking changes</a></li> <li><a href="#improvements-and-new-features-10">Improvements and new features</a></li> -<li><a href="#bug-fixes-7">Bug fixes</a></li> </ul></li> -<li><a href="#l-20170726"><code>1.2l (2017/07/26)</code></a><ul> -<li><a href="#removed-1">Removed</a></li> +<li><a href="#m-20170731"><code>1.2m (2017/07/31)</code></a><ul> +<li><a href="#breaking-changes-7">Breaking changes</a></li> <li><a href="#improvements-and-new-features-11">Improvements and new features</a></li> <li><a href="#bug-fixes-8">Bug fixes</a></li> </ul></li> -<li><a href="#k-20170106"><code>1.2k (2017/01/06)</code></a><ul> -<li><a href="#incompatible-changes-7">Incompatible changes</a></li> +<li><a href="#l-20170726"><code>1.2l (2017/07/26)</code></a><ul> +<li><a href="#removed-1">Removed</a></li> <li><a href="#improvements-and-new-features-12">Improvements and new features</a></li> <li><a href="#bug-fixes-9">Bug fixes</a></li> </ul></li> -<li><a href="#j-20161222"><code>1.2j (2016/12/22)</code></a><ul> +<li><a href="#k-20170106"><code>1.2k (2017/01/06)</code></a><ul> +<li><a href="#breaking-changes-8">Breaking changes</a></li> <li><a href="#improvements-and-new-features-13">Improvements and new features</a></li> <li><a href="#bug-fixes-10">Bug fixes</a></li> </ul></li> -<li><a href="#i-20161213"><code>1.2i (2016/12/13)</code></a><ul> -<li><a href="#incompatible-changes-8">Incompatible changes</a></li> -<li><a href="#removed-2">Removed</a></li> +<li><a href="#j-20161222"><code>1.2j (2016/12/22)</code></a><ul> <li><a href="#improvements-and-new-features-14">Improvements and new features</a></li> <li><a href="#bug-fixes-11">Bug fixes</a></li> </ul></li> -<li><a href="#h-20161120"><code>1.2h (2016/11/20)</code></a><ul> +<li><a href="#i-20161213"><code>1.2i (2016/12/13)</code></a><ul> +<li><a href="#breaking-changes-9">Breaking changes</a></li> +<li><a href="#removed-2">Removed</a></li> <li><a href="#improvements-and-new-features-15">Improvements and new features</a></li> <li><a href="#bug-fixes-12">Bug fixes</a></li> </ul></li> -<li><a href="#g-20160319"><code>1.2g (2016/03/19)</code></a><ul> -<li><a href="#incompatible-changes-9">Incompatible changes</a></li> +<li><a href="#h-20161120"><code>1.2h (2016/11/20)</code></a><ul> <li><a href="#improvements-and-new-features-16">Improvements and new features</a></li> +<li><a href="#bug-fixes-13">Bug fixes</a></li> </ul></li> -<li><a href="#f-20160312"><code>1.2f (2016/03/12)</code></a><ul> -<li><a href="#incompatible-changes-10">Incompatible changes</a></li> +<li><a href="#g-20160319"><code>1.2g (2016/03/19)</code></a><ul> +<li><a href="#breaking-changes-10">Breaking changes</a></li> <li><a href="#improvements-and-new-features-17">Improvements and new features</a></li> -<li><a href="#bug-fixes-13">Bug fixes</a></li> </ul></li> -<li><a href="#e-20151122"><code>1.2e (2015/11/22)</code></a><ul> +<li><a href="#f-20160312"><code>1.2f (2016/03/12)</code></a><ul> +<li><a href="#breaking-changes-11">Breaking changes</a></li> <li><a href="#improvements-and-new-features-18">Improvements and new features</a></li> <li><a href="#bug-fixes-14">Bug fixes</a></li> </ul></li> -<li><a href="#d-20151118"><code>1.2d (2015/11/18)</code></a><ul> +<li><a href="#e-20151122"><code>1.2e (2015/11/22)</code></a><ul> <li><a href="#improvements-and-new-features-19">Improvements and new features</a></li> <li><a href="#bug-fixes-15">Bug fixes</a></li> </ul></li> -<li><a href="#c-20151116"><code>1.2c (2015/11/16)</code></a><ul> +<li><a href="#d-20151118"><code>1.2d (2015/11/18)</code></a><ul> <li><a href="#improvements-and-new-features-20">Improvements and new features</a></li> <li><a href="#bug-fixes-16">Bug fixes</a></li> </ul></li> -<li><a href="#b-20151029"><code>1.2b (2015/10/29)</code></a><ul> +<li><a href="#c-20151116"><code>1.2c (2015/11/16)</code></a><ul> +<li><a href="#improvements-and-new-features-21">Improvements and new features</a></li> <li><a href="#bug-fixes-17">Bug fixes</a></li> </ul></li> -<li><a href="#a-20151019"><code>1.2a (2015/10/19)</code></a><ul> -<li><a href="#improvements-and-new-features-21">Improvements and new features</a></li> +<li><a href="#b-20151029"><code>1.2b (2015/10/29)</code></a><ul> <li><a href="#bug-fixes-18">Bug fixes</a></li> </ul></li> -<li><a href="#section-1"><code>1.2 (2015/10/10)</code></a><ul> -<li><a href="#removed-3">Removed</a></li> +<li><a href="#a-20151019"><code>1.2a (2015/10/19)</code></a><ul> <li><a href="#improvements-and-new-features-22">Improvements and new features</a></li> +<li><a href="#bug-fixes-19">Bug fixes</a></li> +</ul></li> +<li><a href="#section-2"><code>1.2 (2015/10/10)</code></a><ul> +<li><a href="#removed-3">Removed</a></li> +<li><a href="#improvements-and-new-features-23">Improvements and new features</a></li> </ul></li> <li><a href="#c-20150912"><code>1.1c (2015/09/12)</code></a></li> <li><a href="#b-20150831"><code>1.1b (2015/08/31)</code></a></li> <li><a href="#a-20141107"><code>1.1a (2014/11/07)</code></a></li> -<li><a href="#section-2"><code>1.1 (2014/10/28)</code></a><ul> -<li><a href="#incompatible-changes-11">Incompatible changes</a></li> +<li><a href="#section-3"><code>1.1 (2014/10/28)</code></a><ul> +<li><a href="#breaking-changes-12">Breaking changes</a></li> <li><a href="#removed-4">Removed</a></li> <li><a href="#deprecated-1">Deprecated</a></li> -<li><a href="#improvements-and-new-features-23">Improvements and new features</a></li> -<li><a href="#bug-fixes-19">Bug fixes</a></li> +<li><a href="#improvements-and-new-features-24">Improvements and new features</a></li> +<li><a href="#bug-fixes-20">Bug fixes</a></li> </ul></li> <li><a href="#n-20140401"><code>1.09n (2014/04/01)</code></a></li> <li><a href="#m-20140226"><code>1.09m (2014/02/26)</code></a></li> @@ -164,22 +170,75 @@ <li><a href="#a-20130924"><code>1.09a (2013/09/24)</code></a></li> <li><a href="#b-20130614"><code>1.08b (2013/06/14)</code></a></li> <li><a href="#a-20130611"><code>1.08a (2013/06/11)</code></a></li> -<li><a href="#section-3"><code>1.08 (2013/06/07)</code></a></li> -<li><a href="#section-4"><code>1.07 (2013/05/25)</code></a></li> +<li><a href="#section-4"><code>1.08 (2013/06/07)</code></a></li> +<li><a href="#section-5"><code>1.07 (2013/05/25)</code></a></li> <li><a href="#b-20130514"><code>1.06b (2013/05/14)</code></a></li> -<li><a href="#section-5"><code>1.06 (2013/05/07)</code></a></li> -<li><a href="#section-6"><code>1.05 (2013/05/01)</code></a></li> -<li><a href="#section-7"><code>1.04 (2013/04/25)</code></a></li> -<li><a href="#section-8"><code>1.03 (2013/04/14)</code></a></li> -<li><a href="#section-9"><code>1.0 (2013/03/28)</code></a></li> +<li><a href="#section-6"><code>1.06 (2013/05/07)</code></a></li> +<li><a href="#section-7"><code>1.05 (2013/05/01)</code></a></li> +<li><a href="#section-8"><code>1.04 (2013/04/25)</code></a></li> +<li><a href="#section-9"><code>1.03 (2013/04/14)</code></a></li> +<li><a href="#section-10"><code>1.0 (2013/03/28)</code></a></li> </ul> </nav> -<pre><code>Source: xint.dtx 1.3f 2019/09/10 (doc 2019/09/10) +<pre><code>Source: xint.dtx 1.4 2020/01/31 (doc 2020/01/31) Author: Jean-Francois Burnol Info: Expandable operations on big integers, decimals, fractions -License: LPPL 1.3f</code></pre> -<h2 id="f-20190910"><code>1.3f (2019/09/10)</code></h2> +License: LPPL 1.3c</code></pre> +<h2 id="section"><code>1.4 (2020/01/31)</code></h2> +<h3 id="breaking-changes">Breaking changes</h3> +<p>Please note that this list is currently incomplete. If not otherly specified all items regard the <strong>xintexpr</strong> module.</p> +<ul> +<li><p>The <code>\expanded</code> primitive (TeXLive 2019) is <strong>required</strong>. This does not affect the macro layer <strong>xintcore</strong>, <strong>xint</strong>, <strong>xintfrac</strong>, <strong>xinttools</strong> (yet).</p></li> +<li><p>The “broadcasting” (as it turned out, ^<sup>c3</sup>^a0 la <code>NumPy</code>) of scalar operations on one-dimensional “lists”, e.g <code>3*[1,3,5,7]+10</code> acting itemwise is <strong>dropped</strong>. 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) <code>[13,19,25,31]</code> which will be the output in future.</p></li> +<li><p>Formerly square brackets <code>[...]</code> were, on their own, not different from parentheses, but they are now a genuine constructor of nested lists. For example <code>\xinteval{1, [2, [3, 4]], 5}</code> produces <code>1, [2, [3, 4]], 5</code> (recall this is free bloatware).</p></li> +<li><p>The <code>divmod()</code> function now produces on output such a bracketed pair, but simultaneous assignment such as <code>\xintdefvar xq, xr = divmod(a,b);</code> will work transparently.</p></li> +<li><p>The syntax for using conditionals in function declarations has changed. Now, one <em>must</em> use the <code>?</code> and <code>??</code> short-circuit boolean branching operators whereas in the past it was explained that the syntax had to use the <code>if()</code> and <code>ifsgn()</code> functions.</p></li> +<li><p>The output of <code>\xinteval</code> has changed (besides containing brackets). It does not use anymore the so-called <em>raw</em> <strong>xintfrac</strong> format, i.e. things such as <code>A/B[N]</code> (which can still be used in input but are discouraged in <strong>xintexpr</strong> context), but scientific notation <code>AeN/B</code>. As formerly, the denominator is printed only if <code>B>1</code> and the scientific part is dropped if the exponent vanishes. In this way the output of <code>\xinteval</code> can be pasted to alternative software.</p> +<p>The output format of <code>\xinthe\xintboolexpr</code> has changed. It uses <code>True</code> and <code>False</code> (which are accepted on input), and this can easily be configured otherwise (also <code>true</code> and <code>false</code> are accepted on input).</p></li> +</ul> <h3 id="improvements-and-new-features">Improvements and new features</h3> +<p>Please note that this list is currently incomplete. For more information look at the user manual and the documented source code <code>sourcexint.pdf</code>.</p> +<p>Unless otherwise specified all changes commented upon here regard <strong>xintexpr</strong>. 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…).</p> +<ul> +<li><p>The <code>\csname</code> encapsulation technique used since <strong>xintexpr</strong> initial release (<code>1.07 2013/05/25</code>) to move around possibly large data during expansion-only operations is replaced with methods based on the <code>\expanded</code> engine primitive. The latter is available in all major engines since TeXLive 2019.</p> +<p>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.</p> +<p>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.</p></li> +<li><p>The package supports input and output of arbitrarily <em>nested lists</em>, a.k.a. <em>oples</em> or <em>nlists</em>, with <code>[...]</code> as the constructor of <em>bracketed lists</em>, a.k.a <em>nut-ples</em>. Operations on these objects (as briefly surveyed in later items) are inspired from syntax and functionalities of <code>NumPy</code>’s <em>ndarrays</em>. Our <em>oples</em> (hence also their packaged form <em>nut-ples</em>) may have <em>leaves</em> at varying depths rather than obeying an N-dimensional hyperrectangular shape. But the syntax does provide specific constructors for <em>ndlists</em> (i.e. hyperrectangular <em>oples</em> or <em>nut-ples</em>).</p> +<p>In a (distant?) future, perhaps <strong>xintexpr</strong> itself or a third-party package will provide an interface, say <code>\xintstorearray</code>, <code>\xintgetarray</code>, to store (which can not be expandable) and retrieve (which can be expandable and thus be embedded inside expressions parsed by <code>\xintexpr</code>, <code>\xintiiexpr</code> or <code>\xintfloatexpr</code>) such <em>ndlists</em> from TeX memory. This is why the package does not use the word <em>ndarray</em> and reserves it for such memory stored objects.</p></li> +<li><p>The <code>*</code> serves as <em>unpacking</em> operator on <em>nut-ples</em>, i.e. reversing the <code>[]</code> bracketing of an <em>ople</em>.</p></li> +<li><p><em>oples</em> have no exact equivalent in <code>Python</code>. For example <strong>xintexpr</strong> allows <code>foo(Var1, x)</code> if <code>foo</code> is a function of 4 variables and <code>Var1</code> is a variable producing a length 3 <em>ople</em>, or <code>foo(Var2)</code> if <code>Var2</code> is a variable producing a length 4 <em>ople</em>. Python would require here to use explicitly the <code>*</code>-unpacking notation on some “packed” objects.</p> +<p>Variable and function values may be <em>oples</em> (even <em>nil</em>), but in function declarations variables must stand for <em>one-ples</em>, i.e. either <em>numbers</em> or <em>nut-ples</em> (as there is no non-ambiguous way to split e.g. 5 arguments into two separate <em>oples</em>).</p></li> +<li><p>Simultaneous assignment to at least two variables via <code>\xintdefvar</code> et al. automatically unpacks the assigned value if it is a <em>one-ple</em>. If this value was in fact a <em>number</em>, low-level errors will result shortly afterwards as no check is done if the unpacking was illicit. (Such checks exist in the codebase, but have not yet been integrated into <code>\xintdefvar</code> by laziness).</p></li> +<li><p>The <code>NumPy</code> concept and syntax for nested slicing and item selection are implemented. Currently <em>stepping</em> and the <em>Ellipsis object</em> are not yet available. Only so-called basic slicing is currently supported. (The author has not yet read the section of <code>NumPy</code> documentation on so-called <em>advanced indexing</em>).</p></li> +<li><p>The <em>broadcasting</em> of scalar operations, such as itemwise addition or multiplication of <em>nut-ples</em> of the same shape is <strong>not yet implemented</strong>.</p></li> +<li><p>Slicing and indexing apply also at top level to the <em>oples</em> with behaviour conforming to intuitive expectations (see user manual); if it turns out the <em>ople</em> is in fact a <em>nut-ple</em>, the top-level slicing/indexing switches to the <code>Python/NumPy</code> conventions, i.e. it operates inside the brackets for slicing and removes brackets if indexing.</p></li> +<li><p>The syntax <code>ndseq(expression in x, y, ..., x = values; y = values; ...)</code> constructs a (bracketed) <em>ndlist</em> by evaluation the expression on all possible Cartesian n-uples, where the first variable indexes the first axis, the second the next, etc…</p></li> +<li><p>The <code>ndmap(foo, values1; values2; ...; valuesN)</code> syntax constructs a (bracketed) <em>ndlist</em> by evaluating the function <code>foo</code> on all elements of the cartesian product of the given (one-dimensional) value lists.</p></li> +<li><p>The two concepts of <code>\xintdeffunc</code> (for recursive definitions) and <code>\xintdefefunc</code> (for functions which expand immediately in other function declarations) have been merged. The <code>\xintdefefunc</code> et al. are deprecated and kept as aliases for <code>\xintdeffunc</code> et al.</p></li> +<li><p><code>\xintdefufunc</code> allows to define so-called <em>universal functions</em>, i.e. functions <code>foo</code> such that <code>foo(myople)</code> will apply itemwise at arbitrary depth in the nested structure. The function <code>foo</code> is allowed to produce from a scalar an <em>ople</em>…</p></li> +<li><p>The variables in function declarations can now be multi-letter words.</p></li> +<li><p>The last positional variable in a function declaration can be prefixed with a <code>*</code> meaning exactly as in Python (<em>variadic</em> function argument) that it stands for a one-dimensional <em>nut-ple</em> 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.</p></li> +<li><p>Dummy variables used in constructors can also be multi-letter words, if they have been declared as such.</p></li> +<li><p>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.</p></li> +<li><p><code>subsm(expression, var1 = value1; var2 = value2; ...)</code> provides a leaner syntax for multiple substitutions; they must be independent, though.</p></li> +<li><p><code>subsn(expression, var1 = value1; var2 = value2; ...)</code> provides a leaner syntax for nested substitutions, i.e., each <code>valueJ</code> may be an expression using the dummy variables <code>varK</code> with <code>K>J</code>. And finally of course the evaluated expression can refer to all variables.</p></li> +<li><p><code>\xintthealign\xintexpr...\relax</code> (or with <code>\xintfloatexpr</code> or <code>\xintiiexpr</code> or <code>\xintboolexpr</code>…) will use a TeX alignment to display <em>oples</em>. The output (for regular N-dimensional lists) looks very similar to what <code>Python/NumPy</code> produces in interactive session. This is entirely configurable and can also be set-up to be used for writing into external files.</p> +<p>Attention that <code>\xintthealign</code> only works if followed by <code>\xintexpr</code> et al., not by <code>\xinteval{}</code>.</p></li> +<li><p>It is now possible to use <code>\xintexpr...\relax</code> directly for typesetting. The syntax <code>\xinteval{...}</code> or <code>\xintthe\xintexpr...\relax</code> is needed only if one wants the expansion to give the explicit digits, but <code>\xintexpr...\relax</code> 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 <code>\edef</code>.)</p> +<p>As formerly, <code>\xintexpr...\relax</code> is the preferred way to include an expression into another one. Using <code>\xinteval</code> is a waste because it forces the outer parser to re-digest all the digits (or now also the square brackets).</p></li> +<li><p>The output format of <code>\xintfloateval</code> with scientific notation has not changed (apart from possible presence of bracketed lists), but the author hesitates because the <em>prettifying</em> it does by default is not really adapted to display of arrays (see <code>\xintthealign</code>). Anyway, this is configurable by the user. It is possible to specify whether to use <code>e</code> or <code>E</code>.</p></li> +<li><p>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.</p></li> +<li><p>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…</p></li> +</ul> +<h3 id="bug-fixes">Bug fixes</h3> +<p>Bugs? Those identified in <code>1.3f</code> were almost features. As per <code>1.4</code> the code base of <strong>xintexpr</strong> 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.</p> +<h3 id="todo">TODO</h3> +<ul> +<li><p>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 <code>1.07 2013/05/25</code> (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).</p></li> +<li><p>Prior to integrating all of <code>NumPy</code>, it is envisioned to start with matrix algebra first.</p></li> +</ul> +<h2 id="f-20190910"><code>1.3f (2019/09/10)</code></h2> +<h3 id="improvements-and-new-features-1">Improvements and new features</h3> <ul> <li><p><strong>xintfrac</strong>: <code>\xintDigits = P;</code> syntax (i.e. without a colon) is now accepted in addition to <code>\xintDigits := P;</code>.</p> <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. <code>\xintDigits := 32\relax</code>.</p> @@ -187,17 +246,17 @@ License: LPPL 1.3f</code></pre> <li><p><strong>xintexpr</strong>: add starred variants <code>\xintDigits*</code> and <code>\xintSetDigits*</code> which execute <code>\xintreloadxinttrig</code>.</p> <p>Revert 1.3e ban on usage of <code>\xinteval</code> et al. inside expressions by <code>\xintdeffunc</code>. And make them usable also inside macro definitions via <code>\xintNewExpr</code>.</p></li> </ul> -<h3 id="bug-fixes">Bug fixes</h3> +<h3 id="bug-fixes-1">Bug fixes</h3> <ul> <li><p><strong>xintexpr</strong>: fix bug preventing usage of <code>\xintdefefunc</code> to define a function without variables.</p> <p>Fix some issue with <code>\xintfloatexpr[D]..\relax</code> if used inside an expression parsed by <code>\xintdeffunc</code> et al.</p></li> </ul> <h2 id="e-20190405"><code>1.3e (2019/04/05)</code></h2> -<h3 id="incompatible-changes">Incompatible changes</h3> +<h3 id="breaking-changes-1">Breaking changes</h3> <ul> <li>(<em>reverted at 1.3f</em>) When defining functions, sub-expressions can only use the <code>\xint(float)expr...\relax</code> syntax. One can not use there the <code>\xint(float)eval</code> wrappers.</li> </ul> -<h3 id="improvements-and-new-features-1">Improvements and new features</h3> +<h3 id="improvements-and-new-features-2">Improvements and new features</h3> <ul> <li><p>The <strong>xinttrig</strong> library is automatically loaded by <strong>xintexpr</strong>. 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).</p></li> <li><p>The <strong>xintlog</strong> library is automatically loaded by <strong>xintexpr</strong>. It uses <a href="http://ctan.org/pkg/poormanlog">poormanlog</a> to provide logarithms and exponentials with almost 9 digits of precision. Extended precision is for a future release.</p></li> @@ -207,17 +266,17 @@ License: LPPL 1.3f</code></pre> <li><p><strong>xintexpr</strong>: <code>\xintensuredummy</code>, <code>\xintrestorelettervar</code>.</p></li> <li><p>The optional argument of <code>\xintfloatexpr</code> or <code>\xintfloateval</code> (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.</p></li> </ul> -<h3 id="bug-fixes-1">Bug fixes</h3> +<h3 id="bug-fixes-2">Bug fixes</h3> <ul> <li>Some bugfixes related to user functions with no variables at all; they were dysfunctional.</li> </ul> <h2 id="d-20190106"><code>1.3d (2019/01/06)</code></h2> -<h3 id="incompatible-changes-1">Incompatible changes</h3> +<h3 id="breaking-changes-2">Breaking changes</h3> <ul> <li><p><strong>xintexpr</strong>: the <code>gcd()</code> and <code>lcm()</code> functions formerly converted their arguments to integers via <code>\xintNum</code>. They now handle general input with no such modification.</p></li> <li><p><strong>xintexpr</strong>: former <code>\xinteval</code>, <code>\xintieval</code>, <code>\xintiieval</code>, and <code>\xintfloateval</code> renamed to <code>\xintexpro</code>, <code>\xintiexpro</code>, <code>\xintiiexpro</code>, and <code>\xintfloatexpro</code>.</p></li> </ul> -<h3 id="improvements-and-new-features-2">Improvements and new features</h3> +<h3 id="improvements-and-new-features-3">Improvements and new features</h3> <ul> <li><p><strong>xintexpr</strong>: the <code>gcd()</code> and <code>lcm()</code> multi-arguments functions have been refactored to handle general fractions. The dependency on <strong>xintgcd</strong> is removed.</p></li> <li><p><strong>xintexpr</strong>: three-way branching <code>\xintifsgnexpr</code>, <code>\xintifsgnfloatexpr</code>, <code>\xintifsgniiexpr</code> conditional macros.</p></li> @@ -226,12 +285,12 @@ License: LPPL 1.3f</code></pre> <li><p><strong>xintexpr</strong>: functions <code>isone()</code> and <code>isint()</code>.</p></li> <li><p><strong>xintexpr</strong>: <code>\xinteval</code>, <code>\xintieval</code>, <code>\xintiieval</code>, and <code>\xintfloateval</code> as synonyms to <code>\xinttheexpr...\relax</code> etc…, but with the (comma-separated) expression as a usual braced macro argument.</p></li> </ul> -<h3 id="bug-fixes-2">Bug fixes</h3> +<h3 id="bug-fixes-3">Bug fixes</h3> <ul> <li><strong>xintcore</strong>, <strong>xintexpr</strong> : division in <code>\xintiiexpr</code> was broken for a zero dividend and a one-digit divisor (e.g. <code>0//7</code>) since <code>1.2p</code> due to a bug in <code>\xintiiDivMod</code> for such arguments. The bug was signaled (thanks to Kpym for report) and fixed shortly after <code>1.3c</code> release but I then completely forgot to upload a bugfix release to CTAN at that time, apologies for that.</li> </ul> <h2 id="c-20180617"><code>1.3c (2018/06/17)</code></h2> -<h3 id="improvements-and-new-features-3">Improvements and new features</h3> +<h3 id="improvements-and-new-features-4">Improvements and new features</h3> <ul> <li><p><strong>xintexpr</strong>: with <code>\xintglobaldefstrue</code>, <code>\xintdefvar</code>, <code>\xintdeffunc</code>, <code>\xintNewExpr</code> et al. make definitions with global scope.</p></li> <li><p><strong>xintexpr</strong>: <code>qraw()</code> for fast input of (very many) comma separated numbers (in suitable raw format).</p></li> @@ -239,12 +298,12 @@ License: LPPL 1.3f</code></pre> <li><p><strong>xintexpr</strong>: <code>\xintdefvar</code>, <code>\xintdeffunc</code> 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.</p></li> <li><p><code>\xintUniformDeviate</code> is better documented and <code>sourcexint.pdf</code> is better hyperlinked and includes indices for the macros defined by each package.</p></li> </ul> -<h3 id="bug-fixes-3">Bug fixes</h3> +<h3 id="bug-fixes-4">Bug fixes</h3> <ul> <li><strong>xintfrac</strong>: since <code>1.3</code> release, it loaded <strong>xintgcd</strong> in contradiction to what the documentation says (hence also <strong>xintexpr</strong> loaded <strong>xintgcd</strong> automatically). There is no actual dependency so the loading is removed for now.</li> </ul> <h2 id="b-20180518"><code>1.3b (2018/05/18)</code></h2> -<h3 id="improvements-and-new-features-4">Improvements and new features</h3> +<h3 id="improvements-and-new-features-5">Improvements and new features</h3> <p>All additions related to randomness are marked as work-in-progress. They require an engine providing the <code>\(pdf)uniformdeviate</code> primitive.</p> <ul> <li><p><strong>xintkernel</strong>: <code>\xintUniformDeviate</code>.</p></li> @@ -259,41 +318,41 @@ License: LPPL 1.3f</code></pre> <ul> <li><strong>xintcore</strong>, <strong>xint</strong>, <strong>xintfrac</strong>: removal of the internal macros which were used at <code>1.2o</code> to add a deprecation mechanism; all deprecated macros have been removed at <code>1.3</code> so there was no reason to keep the code used for deprecating them.</li> </ul> -<h3 id="improvements-and-new-features-5">Improvements and new features</h3> +<h3 id="improvements-and-new-features-6">Improvements and new features</h3> <ul> <li><p><strong>xintexpr</strong>: new conditionals <code>ifone()</code> and <code>ifint()</code>.</p></li> <li><p><strong>xintfrac</strong>: <code>\xintREZ</code> is faster on inputs having one hundred digits or more.</p></li> <li><p>Added to the user manual mention of macros such as <code>\xintDivFloor</code>, <code>\xintMod</code>, <code>\xintModTrunc</code>, which had been left out so far.</p></li> </ul> -<h3 id="bug-fixes-4">Bug fixes</h3> +<h3 id="bug-fixes-5">Bug fixes</h3> <ul> <li><strong>xintexpr</strong>: the mechanism for adjunction to the expression parsers of user defined functions was refactored and improved at previous release <code>1.3</code>: in particular recursive definitions became possible. But an oversight made these recursive functions quite inefficient (to remain polite.) This release fixes the problem.</li> </ul> -<h2 id="section"><code>1.3 (2018/03/01)</code></h2> -<h3 id="incompatible-changes-2">Incompatible changes</h3> +<h2 id="section-1"><code>1.3 (2018/03/01)</code></h2> +<h3 id="breaking-changes-3">Breaking changes</h3> <ul> <li><p><strong>xintcore</strong>, <strong>xint</strong>, <strong>xintfrac</strong>: all macros deprecated at <code>1.2o</code> got removed.</p></li> <li><p><strong>xintfrac</strong>: addition and subtraction of <code>a/b</code> and <code>c/d</code> now use the l.c.m. of the denominators. Similarly the macro supporting the modulo operator <code>/:</code> uses a l.c.m. for the denominator of the result.</p></li> <li><p><strong>xintexpr</strong>: the addition, subtraction, modulo <code>/:</code>, and the <code>mod()</code> and <code>divmod()</code> functions produce generally smaller denominators (see previous item).</p></li> <li><p><strong>xintexpr</strong>: 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 <code>\xintverbosetrue</code>).</p></li> </ul> -<h3 id="improvements-and-new-features-6">Improvements and new features</h3> +<h3 id="improvements-and-new-features-7">Improvements and new features</h3> <ul> <li><p><strong>xintexpr</strong>: user-defined functions may now be of a recursive nature. This was made possible by a refactoring of the <code>\xintNewExpr</code> mechanism. It became both leaner and more extensive than formerly.</p></li> <li><p><strong>xintfrac</strong>: new macros <code>\xintPIrr</code> and <code>\xintDecToString</code>. The latter is a backport of a <code>polexpr 0.4</code> utility, and it is to be considered unstable.</p></li> <li><p><strong>xintexpr</strong>: new function <code>preduce()</code> associated with <code>\xintPIrr</code>.</p></li> </ul> <h2 id="q-20180206"><code>1.2q (2018/02/06)</code></h2> -<h3 id="improvements-and-new-features-7">Improvements and new features</h3> +<h3 id="improvements-and-new-features-8">Improvements and new features</h3> <ul> <li><strong>xintexpr</strong>: tacit multiplication extended to cases such as <code>3!4!5!</code> or <code>(1+2)3</code>.</li> </ul> -<h3 id="bug-fixes-5">Bug fixes</h3> +<h3 id="bug-fixes-6">Bug fixes</h3> <ul> <li><strong>xintcore</strong>: sadly, refactoring at <code>1.2l</code> of subtraction left an extra character in an inner macro causing breakage in some rare circumstances. This should not have escaped our test suite!</li> </ul> <h2 id="p-20171205"><code>1.2p (2017/12/05)</code></h2> -<h3 id="incompatible-changes-3">Incompatible changes</h3> +<h3 id="breaking-changes-4">Breaking changes</h3> <ul> <li><p><strong>xintgcd</strong>: <code>\xintBezout{a}{b}</code>’s output consists of <code>{u}{v}{d}</code> with <code>u*a+v*b==d</code>, with <code>d</code> the GCD. Formerly it was <code>{a}{b}{u}{v}{d}</code>, and with <code>u*a-v*b==d</code>.</p></li> <li><p><strong>xintgcd</strong>: <code>\xintBezout{0}{0}</code> expands to <code>{0}{0}{0}</code>. Formerly (since <code>1.2l</code>) it raised <code>InvalidOperation</code>.</p></li> @@ -301,13 +360,13 @@ License: LPPL 1.3f</code></pre> <li><p><strong>xintfrac</strong>: <code>\xintMod</code> is now associated with floored division. The former meaning is available as <code>\xintModTrunc</code>.</p></li> <li><p><strong>xintexpr</strong>: the <code>//</code> operator and its associated modulo <code>'mod'</code> (or <code>/:</code>) now correspond to floored division, like the Python language <code>//</code>, <code>%</code>, and <code>divmod(x, y)</code>. Formerly they had been associated to truncated division. This is breaking change for operands of opposite signs.</p></li> </ul> -<h3 id="improvements-and-new-features-8">Improvements and new features</h3> +<h3 id="improvements-and-new-features-9">Improvements and new features</h3> <ul> <li><p><strong>xinttools</strong>: <code>\xintListWithSep</code>, which had remained unchanged since its introduction at <code>1.04 (2013/04/25)</code>, was rewritten for increased speed.</p></li> <li><p><strong>xintexpr</strong>: <code>\xintdefvar</code>’s syntax is extended to allow simultaneous assignments. Examples: <code>\xintdefvar x1, x2, x3 := 1, 3**10, 3**20;</code> or <code>\xintdefiivar A, B := B, A 'mod' B;</code> for already defined variables <code>A</code> and <code>B</code>.</p></li> <li><p><strong>xintexpr</strong>: added <code>divmod()</code> to the built-in functions. It is associated with floored division, like the Python language <code>divmod()</code>. Related support macros added to <strong>xintcore</strong>, and <strong>xintfrac</strong>.</p></li> </ul> -<h3 id="bug-fixes-6">Bug fixes</h3> +<h3 id="bug-fixes-7">Bug fixes</h3> <ul> <li><p><strong>xintgcd</strong>: <code>\xintBezout{6}{3}</code> (for example) expanded to <code>{6}{3}{-0}{-1}{3}</code>, but the <code>-0</code> should have been <code>0</code>.</p></li> <li><p><strong>xintgcd</strong>: it still used macro <code>\xintiAbs</code> although the latter had been deprecated from <strong>xintcore</strong>.</p></li> @@ -315,7 +374,7 @@ License: LPPL 1.3f</code></pre> <li><p>various documentation fixes; in particular, the partial dependency of <strong>xintcfrac</strong> on <strong>xinttools</strong> had not been mentioned.</p></li> </ul> <h2 id="o-20170829"><code>1.2o (2017/08/29)</code></h2> -<h3 id="incompatible-changes-4">Incompatible changes</h3> +<h3 id="breaking-changes-5">Breaking changes</h3> <ul> <li><strong>xint</strong>: <code>\xintAND</code>, <code>\xintOR</code>, … and similar Boolean logic macros do not apply anymore <code>\xintNum</code> (or <code>\xintRaw</code> if <strong>xintfrac</strong> is loaded), to their arguments (often, from internal usage of <code>\xintSgn</code>), but only f-expand them (using e.g. <code>\xintiiSgn</code>). This is kept un-modified even if loading <strong>xintfrac</strong>.</li> </ul> @@ -331,26 +390,26 @@ License: LPPL 1.3f</code></pre> <li><p><strong>xint</strong>: <code>\xintNot</code> was renamed to <code>\xintNOT</code>, former denomination is deprecated. See also item about Boolean logic macros in the <em>Incompatible Changes</em> section.</p></li> </ul> <h2 id="n-20170806"><code>1.2n (2017/08/06)</code></h2> -<h3 id="incompatible-changes-5">Incompatible changes</h3> +<h3 id="breaking-changes-6">Breaking changes</h3> <ul> <li><strong>xintbinhex</strong> does not load package <strong>xintcore</strong> anymore, but only <strong>xintkernel</strong>.</li> </ul> -<h3 id="improvements-and-new-features-9">Improvements and new features</h3> +<h3 id="improvements-and-new-features-10">Improvements and new features</h3> <ul> <li><p><strong>xintbinhex</strong> has only <strong>xintkernel</strong> as dependency.</p></li> <li><p>Macros of <strong>xintbinhex</strong> have been improved for speed and increased maximal sizes of allowable inputs.</p></li> </ul> <h2 id="m-20170731"><code>1.2m (2017/07/31)</code></h2> -<h3 id="incompatible-changes-6">Incompatible changes</h3> +<h3 id="breaking-changes-7">Breaking changes</h3> <ul> <li><p><strong>xintbinhex</strong>: the length of the input is now limited. The maximum size depends on the macro and ranges from about <code>4000</code> to about <code>19900</code> digits.</p></li> <li><p><strong>xintbinhex</strong>: <code>\xintCHexToBin</code> is now the variant of <code>\xintHexToBin</code> which does not remove leading binary zeroes: <code>N</code> hex-digits give on output exactly <code>4N</code> binary digits.</p></li> </ul> -<h3 id="improvements-and-new-features-10">Improvements and new features</h3> +<h3 id="improvements-and-new-features-11">Improvements and new features</h3> <ul> <li><strong>xintbinhex</strong>: all macros have been rewritten using techniques from the 1.2 release (they had remained unmodified since <code>1.08</code> of <code>2013/06/07</code>.) The new macros are faster but limited to a few thousand digits. The <code>1.08</code> routines could handle tens of thousands of digits, but not in a reasonable time.</li> </ul> -<h3 id="bug-fixes-7">Bug fixes</h3> +<h3 id="bug-fixes-8">Bug fixes</h3> <ul> <li><p>user manual: the <code>Changes</code> section wrongly stated at <code>1.2l</code> that the macros of <strong>xintbinhex</strong> had been made robust against non terminated input such as <code>\number\mathcode`\-</code>. Unfortunately the author fell into the trap of believing his own documentation and he forgot to actually implement the change. Now done.</p></li> <li><p>user manual: the PDF bookmarks were messed up.</p></li> @@ -362,7 +421,7 @@ License: LPPL 1.3f</code></pre> <li><p><code>\xintiiSumExpr</code>, <code>\xintiiPrdExpr</code> (<strong>xint</strong>) and <code>\xintSumExpr</code>, <code>\xintPrdExpr</code> (<strong>xintfrac</strong>). They had not been formally deprecated, but had been left un-documented since <code>1.09d (2013/10/22)</code>.</p></li> <li><p>internal macro <code>\xint_gob_til_xint_relax</code> removed.</p></li> </ul> -<h3 id="improvements-and-new-features-11">Improvements and new features</h3> +<h3 id="improvements-and-new-features-12">Improvements and new features</h3> <ul> <li><p>the underscore character <code>_</code> is accepted by the <strong>xintexpr</strong> parsers as a digit separator (the space character already could be used for improved readability of big numbers). It is not allowed as <em>first</em> character of a number, as it would then be mis-interpreted as the start of a possible variable name.</p></li> <li><p>some refactoring in <strong>xintcore</strong> auxiliary routines and in <code>\xintiiSub</code> and <code>\xintiiCmp</code> for some small efficiency gains.</p></li> @@ -371,33 +430,33 @@ License: LPPL 1.3f</code></pre> <p>The situation with expressions is unchanged: syntax such as <code>\xintexpr \numexpr1+2\relax</code> is illegal as the ending <code>\relax</code> token will get swallowed by the <code>\numexpr</code>; but it is needed by the <code>xintexpr</code>-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 <code>}</code> for example can not terminate an <code>xintexpr</code>-ession, the parser must find a <code>\relax</code> token at some point). Thus there must be in this example a second <code>\relax</code>.</p></li> <li><p>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.</p></li> </ul> -<h3 id="bug-fixes-8">Bug fixes</h3> +<h3 id="bug-fixes-9">Bug fixes</h3> <ul> <li><p><strong>xintbinhex</strong>: since <code>1.2 (2015/10/10)</code>, <code>\xintHexToDec</code> was broken due to an undefined macro (it was in <code>xint.sty</code>, but the module by itself is supposedly dependent only upon <code>xintcore.sty</code>).</p></li> <li><p><strong>xintgcd</strong>: macro <code>\xintBezout</code> produced partially wrong output if one of its two arguments was zero.</p></li> <li><p><strong>xintfrac</strong>: the manual said one could use directly <code>\numexpr</code> compatible expressions in arithmetic macros (without even a <code>\numexpr</code> 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 <code>\the\numexpr</code> prefix and not to worry about the token count… The ending <code>\relax</code> is now un-needed.</p></li> </ul> <h2 id="k-20170106"><code>1.2k (2017/01/06)</code></h2> -<h3 id="incompatible-changes-7">Incompatible changes</h3> +<h3 id="breaking-changes-8">Breaking changes</h3> <ul> <li><p>macro <code>\xintFloat</code> which rounds its input to a floating point number does <em>not</em> print anymore <code>10.0...0eN</code> 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.</p></li> <li><p>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.</p></li> </ul> -<h3 id="improvements-and-new-features-12">Improvements and new features</h3> +<h3 id="improvements-and-new-features-13">Improvements and new features</h3> <ul> <li><p>the initial rounding to the target precision <code>P</code> which is applied by the floating point macros from <strong>xintfrac</strong> to their arguments achieves the <em>exact (aka correct) rounding</em> even for inputs which are fractions with more than <code>P+2</code> digits in their numerators and denominators (<code>>1</code>.) Hence the computed values depend only on the arguments as rational numbers and not upon their representatives. This is not relevant to <em>expressions</em> (<strong>xintexpr</strong>), because the <code>\xintfloatexpr</code> parser sees there <code>/</code> as an operator and does not (apart from special constructs) get to manipulate fractions as such.</p></li> <li><p><code>\xintnewdummy</code> is public interface to a <code>1.2e</code> macro which serves to declare any given catcode 11 character as a dummy variable for expressions (<strong>xintexpr</strong>). This is useful for Unicode engines (the Latin letters being already all pre-declared as dummy variables.)</p></li> <li><p>added <code>\xintiSqrtR</code>, there was only <code>\xintiiSqrtR</code> alongside <code>\xintiSqrt</code> and <code>\xintiiSqrt</code> (<strong>xint</strong>).</p></li> <li><p>added non public <code>\xintLastItem:f:csv</code> to <strong>xinttools</strong> for faster <code>last()</code> function, and improved <code>\xintNewExpr</code> compatibility. Also <code>\xintFirstItem:f:csv</code>.</p></li> </ul> -<h3 id="bug-fixes-9">Bug fixes</h3> +<h3 id="bug-fixes-10">Bug fixes</h3> <ul> <li><p>the <code>1.2f</code> half-integer powers computed within <code>\xintfloatexpr</code> had a silly rounding to the target precision just <em>before</em> the final square-root extraction, thus possibly losing some precision. The <code>1.2k</code> 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 <code>0.52 ulp</code> (for inputs having at most <code>\xinttheDigits</code> digits.)</p></li> <li><p>more regressions from <code>1.2i</code> were fixed: <code>\xintLen</code> (<strong>xint</strong>, <strong>xintfrac</strong>) and <code>\xintDouble</code> (<strong>xintcore</strong>) 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.</p></li> <li><p><code>\xintiiSquareRoot{0}</code> now produces <code>{1}{1}</code>, which fits better the general documented behaviour of this macro than <code>11</code>.</p></li> </ul> <h2 id="j-20161222"><code>1.2j (2016/12/22)</code></h2> -<h3 id="improvements-and-new-features-13">Improvements and new features</h3> +<h3 id="improvements-and-new-features-14">Improvements and new features</h3> <ul> <li><p><strong>xinttools</strong> and <strong>xintexpr</strong>:</p> <ol type="1"> @@ -406,12 +465,12 @@ License: LPPL 1.3f</code></pre> </ol></li> <li><p>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 <strong>xintexpr</strong> syntax to a kind of awe-inspiring perfection… except that implementation of some math functions is still lacking.</p></li> </ul> -<h3 id="bug-fixes-10">Bug fixes</h3> +<h3 id="bug-fixes-11">Bug fixes</h3> <ul> <li>fix two <code>1.2i</code> regressions caused by undefined macros (<code>\xintNthElt</code> in certain branches and <code>[list][N]</code> item extraction in certain cases.) The test files existed but were not executed prior to release. Automation in progress.</li> </ul> <h2 id="i-20161213"><code>1.2i (2016/12/13)</code></h2> -<h3 id="incompatible-changes-8">Incompatible changes</h3> +<h3 id="breaking-changes-9">Breaking changes</h3> <ul> <li><code>\xintDecSplit</code> second argument must have no sign (former code replaced it with its absolute value, a sign now may cause an error.)</li> </ul> @@ -419,7 +478,7 @@ License: LPPL 1.3f</code></pre> <ul> <li>deprecated macros <code>\xintifTrue</code>, <code>\xintifTrueFalse</code>, <code>\xintQuo</code>, <code>\xintRem</code>, <code>\xintquo</code>, <code>\xintrem</code>.</li> </ul> -<h3 id="improvements-and-new-features-14">Improvements and new features</h3> +<h3 id="improvements-and-new-features-15">Improvements and new features</h3> <ul> <li><p><strong>xintkernel</strong>: <code>\xintLength</code> is faster. New macros:</p> <ul> @@ -438,17 +497,17 @@ License: LPPL 1.3f</code></pre> <li><p>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 <code>\xintNewFunction</code> for recursive definitions.</p></li> <li><p>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 <strong>xint</strong> is about expansion of macros (plus the use of <code>\numexpr</code>).</p></li> </ul> -<h3 id="bug-fixes-11">Bug fixes</h3> +<h3 id="bug-fixes-12">Bug fixes</h3> <ul> <li><code>\xintDecSplitL</code> and <code>\xintDecSplitR</code> from <strong>xint</strong> produced their output in a spurious brace pair (bug introduced in <code>1.2f</code>).</li> </ul> <h2 id="h-20161120"><code>1.2h (2016/11/20)</code></h2> -<h3 id="improvements-and-new-features-15">Improvements and new features</h3> +<h3 id="improvements-and-new-features-16">Improvements and new features</h3> <ul> <li><p>new macro <code>\xintNewFunction</code> in <strong>xintexpr</strong> which allows to extend the parser syntax with functions in situations where <code>\xintdeffunc</code> is not usable (typically, because dummy variables are used over a not yet determined range of values because it depends on the variables).</p></li> <li><p>after three years of strict obedience to <code>xint</code> prefix, now <code>\thexintexpr</code>, <code>\thexintiexpr</code>, <code>\thexintfloatexpr</code>, and <code>\thexintiiexpr</code> are provided as synonyms to <code>\xinttheexpr</code>, etc…</p></li> </ul> -<h3 id="bug-fixes-12">Bug fixes</h3> +<h3 id="bug-fixes-13">Bug fixes</h3> <ul> <li><p>the <code>(cond)?{foo}{bar}</code> operator from <strong>xintexpr</strong> mis-behaved in certain circumstances (such as an empty <code>foo</code>).</p></li> <li><p>the <strong>xintexpr</strong> <code>1.2f</code> <code>binomial</code> function (which uses <code>\xintiiBinomial</code> from <strong>xint.sty</strong> or <code>\xintFloatBinomial</code> from <strong>xintfrac.sty</strong>) deliberately raised an error for <code>binomial(x,y)</code> with <code>y<0</code> or <code>x<y</code>. This was unfortunate, and it now simply evaluates to zero in such cases.</p></li> @@ -456,12 +515,12 @@ License: LPPL 1.3f</code></pre> <li><p>the <code>add</code> and <code>mul</code> from <strong>xintexpr</strong>, which work with dummy variables since <code>1.1</code>, raised an error since <code>1.2c 2015/11/16</code> when the dummy variable was given an empty range (or list) of values, rather than producing respectively <code>0</code> and <code>1</code> as formerly.</p></li> </ul> <h2 id="g-20160319"><code>1.2g (2016/03/19)</code></h2> -<h3 id="incompatible-changes-9">Incompatible changes</h3> +<h3 id="breaking-changes-10">Breaking changes</h3> <ul> <li><p>inside expressions, list item selector <code>[L][n]</code> counts starting at zero, not at one. This is more coherent with <code>[L][a:b]</code> which was already exactly like in Python since its introduction. A function len(L) replaces earlier <code>[L][0]</code>.</p></li> <li><p>former <code>iter</code> keyword now called <code>iterr</code>. Indeed it matched with <code>rrseq</code>, the new <code>iter</code> (which was somehow missing from <code>1.1</code>) is the one matching <code>rseq</code>. Allows to iterate more easily with a “list” variable.</p></li> </ul> -<h3 id="improvements-and-new-features-16">Improvements and new features</h3> +<h3 id="improvements-and-new-features-17">Improvements and new features</h3> <ul> <li><p>in <strong>xintexpr.sty</strong>: list selectors <code>[L][n]</code> and <code>[L][a:b]</code> are more efficient: the earlier <code>1.1</code> routines did back and forth conversions from comma separated values to braced tokens, the <code>1.2g</code> routines use macros from <strong>xinttools.sty</strong> handling directly the encountered lists of comma separated values.</p></li> <li><p>in <strong>xinttools.sty</strong>: slight improvements in the efficiency of the <code>\xintNthElt</code>, <code>\xintKeep</code>, <code>\xintTrim</code> routines and new routines handling directly comma separated values. The latter are not included in the user manual (they are not <code>\long</code>, 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).</p></li> @@ -470,11 +529,11 @@ License: LPPL 1.3f</code></pre> <li><p>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 <code>iter</code> in a float expression.</p></li> </ul> <h2 id="f-20160312"><code>1.2f (2016/03/12)</code></h2> -<h3 id="incompatible-changes-10">Incompatible changes</h3> +<h3 id="breaking-changes-11">Breaking changes</h3> <ul> <li>no more <code>\xintFac</code> macro but <code>\xintiFac/\xintiiFac/\xintFloatFac</code>.</li> </ul> -<h3 id="improvements-and-new-features-17">Improvements and new features</h3> +<h3 id="improvements-and-new-features-18">Improvements and new features</h3> <ul> <li><p>functions <code>binomial</code>, <code>pfactorial</code> and <code>factorial</code> in both integer and float versions.</p></li> <li><p>macros <code>\xintiiBinomial</code>, <code>\xintiiPFactorial</code> (<strong>xint.sty</strong>) and <code>\xintFloatBinomial</code>, <code>\xintFloatPFactorial</code> (<strong>xintfrac.sty</strong>). Improvements to <code>\xintFloatFac</code>.</p></li> @@ -488,69 +547,69 @@ License: LPPL 1.3f</code></pre> <li><p>(TeXperts only) the macros defined (internally) from <code>\xintdeffunc</code> et al. constructs do not incorporate an initial <code>\romannumeral</code> anymore.</p></li> <li><p>renewed desperate efforts at improving the documentation by random shuffling of sections and well thought additions; cuts were considered and even performed.</p></li> </ul> -<h3 id="bug-fixes-13">Bug fixes</h3> +<h3 id="bug-fixes-14">Bug fixes</h3> <ul> <li><p>squaring macro <code>\xintSqr</code> from <strong>xintfrac.sty</strong> was broken due to a misspelled sub-macro name. Dates back to <code>1.1</code> release of <code>2014/10/28</code> <code>:-((</code>.</p></li> <li><p><code>1.2c</code>’s fix to the subtraction bug from <code>1.2</code> 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 <code>\xintiiSquareRoot</code>.</p></li> <li><p>the comparison operators were not recognized by <code>\xintNewIIExpr</code> and <code>\xintdefiifunc</code> constructs.</p></li> </ul> <h2 id="e-20151122"><code>1.2e (2015/11/22)</code></h2> -<h3 id="improvements-and-new-features-18">Improvements and new features</h3> +<h3 id="improvements-and-new-features-19">Improvements and new features</h3> <ul> <li><p>macro <code>\xintunassignvar</code>.</p></li> <li><p>slight modifications of the logged messages in case of <code>\xintverbosetrue</code>.</p></li> <li><p>a space in <code>\xintdeffunc f(x)<space>:= expression ;</code> is now accepted.</p></li> <li><p>documentation enhancements: the <em>Quick Sort</em> section with its included code samples has been entirely re-written; the <em>Commands of the xintexpr package</em> section has been extended and reviewed entirely.</p></li> </ul> -<h3 id="bug-fixes-14">Bug fixes</h3> +<h3 id="bug-fixes-15">Bug fixes</h3> <ul> <li><p>in <strong>xintfrac</strong>: the <code>\xintFloatFac</code> from release <code>1.2</code> parsed its argument only through <code>\numexpr</code> but it should have used <code>\xintNum</code>.</p></li> <li><p>in <strong>xintexpr</strong>: release <code>1.2d</code> had broken the recognition of sub-expressions immediately after variable names (with tacit multiplication).</p></li> <li><p>in <strong>xintexpr</strong>: contrarily to what <code>1.2d</code> documentation said, tacit multiplication was not yet always done with enhanced precedence. Now yes.</p></li> </ul> <h2 id="d-20151118"><code>1.2d (2015/11/18)</code></h2> -<h3 id="improvements-and-new-features-19">Improvements and new features</h3> +<h3 id="improvements-and-new-features-20">Improvements and new features</h3> <ul> <li><p>the function definitions done by <code>\xintdeffunc</code> et al., as well as the macro declarations by <code>\xintNewExpr</code> et al. now have only local scope.</p></li> <li><p>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).</p></li> <li><p>some documentation enhancements, particularly in the chapter on xintexpr.sty, and also in the code source comments.</p></li> </ul> -<h3 id="bug-fixes-15">Bug fixes</h3> +<h3 id="bug-fixes-16">Bug fixes</h3> <ul> <li>in <strong>xintcore</strong>: release <code>1.2c</code> had inadvertently broken the <code>\xintiiDivRound</code> macro.</li> </ul> <h2 id="c-20151116"><code>1.2c (2015/11/16)</code></h2> -<h3 id="improvements-and-new-features-20">Improvements and new features</h3> +<h3 id="improvements-and-new-features-21">Improvements and new features</h3> <ul> <li><p>macros <code>\xintdeffunc</code>, <code>\xintdefiifunc</code>, <code>\xintdeffloatfunc</code> and boolean <code>\ifxintverbose</code>.</p></li> <li><p>on-going code improvements and documentation enhancements, but stopped in order to issue this bugfix release.</p></li> </ul> -<h3 id="bug-fixes-16">Bug fixes</h3> +<h3 id="bug-fixes-17">Bug fixes</h3> <ul> <li>in <strong>xintcore</strong>: recent release <code>1.2</code> introduced a bug in the subtraction (happened when 00000001 was found under certain circumstances at certain mod 8 locations).</li> </ul> <h2 id="b-20151029"><code>1.2b (2015/10/29)</code></h2> -<h3 id="bug-fixes-17">Bug fixes</h3> +<h3 id="bug-fixes-18">Bug fixes</h3> <ul> <li>in <strong>xintcore</strong>: recent release <code>1.2</code> 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).</li> </ul> <h2 id="a-20151019"><code>1.2a (2015/10/19)</code></h2> -<h3 id="improvements-and-new-features-21">Improvements and new features</h3> +<h3 id="improvements-and-new-features-22">Improvements and new features</h3> <ul> <li><p>added <code>\xintKeepUnbraced</code>, <code>\xintTrimUnbraced</code> (<strong>xinttools</strong>) and fixed documentation of <code>\xintKeep</code> and <code>\xintTrim</code> regarding brace stripping.</p></li> <li><p>added <code>\xintiiMaxof/\xintiiMinof</code> (<strong>xint</strong>).</p></li> <li><p>TeX hackers only: replaced all code uses of <code>\romannumeral-`0</code> by the quicker <code>\romannumeral`&&@</code> (<code>^</code> being used as letter, had to find another character usable with catcode 7).</p></li> </ul> -<h3 id="bug-fixes-18">Bug fixes</h3> +<h3 id="bug-fixes-19">Bug fixes</h3> <ul> <li>in <strong>xintexpr</strong>: recent release <code>1.2</code> introduced a bad bug in the parsing of decimal numbers and as a result <code>\xinttheexpr 0.01\relax</code> expanded to <code>0</code> ! (sigh…)</li> </ul> -<h2 id="section-1"><code>1.2 (2015/10/10)</code></h2> +<h2 id="section-2"><code>1.2 (2015/10/10)</code></h2> <h3 id="removed-3">Removed</h3> <ul> <li>the macros <code>\xintAdd</code>, <code>\xintSub</code>, <code>\xintMul</code>, <code>\xintMax</code>, <code>\xintMin</code>, <code>\xintMaxof</code>, <code>\xintMinof</code> are removed from package <strong>xint</strong>, and only exist in the versions from <strong>xintfrac</strong>. With only <strong>xintcore</strong> or <strong>xint</strong> loaded, one <em>must</em> use <code>\xintiiAdd</code>, <code>\xintiiSub</code>, …, or <code>\xintiAdd</code>, <code>\xintiSub</code>, etc…</li> </ul> -<h3 id="improvements-and-new-features-22">Improvements and new features</h3> +<h3 id="improvements-and-new-features-23">Improvements and new features</h3> <ul> <li><p>the basic arithmetic implemented in <strong>xintcore</strong> has been entirely rewritten. The mathematics remains the elementary school one, but the <code>TeX</code> 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.</p></li> <li><p>the inputs must have less than 19959 digits. But computations with thousands of digits take time.</p></li> @@ -583,8 +642,8 @@ License: LPPL 1.3f</code></pre> <li><p>added the previously mentioned <code>ii</code> macros, and some others from <code>1.1</code>, to the user manual. But their main usage is internal to <code>\xintiiexpr</code>, to skip unnecessary overheads.</p></li> <li><p>various typographical fixes throughout the documentation, and a bit of clean up of the code comments. Improved <code>\Factors</code> example of nested <code>subs</code>, <code>rseq</code>, <code>iter</code> in <code>\xintiiexpr</code>.</p></li> </ul> -<h2 id="section-2"><code>1.1 (2014/10/28)</code></h2> -<h3 id="incompatible-changes-11">Incompatible changes</h3> +<h2 id="section-3"><code>1.1 (2014/10/28)</code></h2> +<h3 id="breaking-changes-12">Breaking changes</h3> <ul> <li><p>in <code>\xintiiexpr</code>, <code>/</code> does <em>rounded</em> division, rather than the Euclidean division (for positive arguments, this is truncated division). The <code>//</code> operator does truncated division,</p></li> <li><p>the <code>:</code> operator for three-way branching is gone, replaced with <code>??</code>,</p></li> @@ -604,7 +663,7 @@ License: LPPL 1.3f</code></pre> <li><p><code>\xintMax</code>, <code>\xintMin</code>, <code>\xintAdd</code>, <code>\xintSub</code>, <code>\xintMul</code> (<strong>xint</strong>): their usage without <strong>xintfrac</strong> is deprecated; use <code>\xintiMax</code>, <code>\xintiMin</code>, <code>\xintiAdd</code>, <code>\xintiSub</code>, <code>\xintiMul</code>.</p></li> <li><p>the <code>&</code> and <code>|</code> as Boolean operators in <code>xintexpr</code>-essions are deprecated in favour of <code>&&</code> and <code>||</code>. The single letter operators might be assigned some other meaning in some later release (bitwise operations, perhaps). Do not use them.</p></li> </ul> -<h3 id="improvements-and-new-features-23">Improvements and new features</h3> +<h3 id="improvements-and-new-features-24">Improvements and new features</h3> <ul> <li><p>new package <strong>xintcore</strong> has been split off <strong>xint</strong>. It contains the core arithmetic macros (it is loaded by LaTeX package <strong>bnumexpr</strong>),</p></li> <li><p>neither <strong>xint</strong> nor <strong>xintfrac</strong> load <strong>xinttools</strong>. Only <strong>xintexpr</strong> does,</p></li> @@ -642,7 +701,7 @@ License: LPPL 1.3f</code></pre> <li><p><code>\xintthecoords</code> converts a comma separated list of an even number of items to the format expected by the <code>TikZ</code> <code>coordinates</code> syntax,</p></li> <li><p>completely new version <code>\xintNewExpr</code>, <code>protect</code> function to handle external macros. The dollar sign <code>$</code> for place holders is not accepted anymore, only the standard macro parameter <code>#</code>. Not all constructs are compatible with <code>\xintNewExpr</code>.</p></li> </ul> -<h3 id="bug-fixes-19">Bug fixes</h3> +<h3 id="bug-fixes-20">Bug fixes</h3> <ul> <li><p><code>\xintZapFirstSpaces</code> hence also <code>\xintZapSpaces</code> from package <strong>xinttools</strong> were buggy when used with an argument either empty or containing only space tokens.</p></li> <li><p><code>\xintiiexpr</code> did not strip leading zeroes, hence <code>\xinttheiiexpr 001+1\relax</code> did not obtain the expected result …</p></li> @@ -785,12 +844,12 @@ License: LPPL 1.3f</code></pre> <li><p>Better management by <code>\xintCmp</code>, <code>\xintMax</code>, <code>\xintMin</code> and <code>\xintGeq</code> of inputs having big powers of ten in them.</p></li> <li><p>Macros for floating point numbers added to the <strong>xintseries</strong> package.</p></li> </ul> -<h2 id="section-3"><code>1.08 (2013/06/07)</code></h2> +<h2 id="section-4"><code>1.08 (2013/06/07)</code></h2> <ul> <li><p>(<strong>xint</strong> and <strong>xintfrac</strong>) Macros for extraction of square roots, for floating point numbers (<code>\xintFloatSqrt</code>), and integers (<code>\xintiSqrt</code>).</p></li> <li><p>new package <strong>xintbinhex</strong> providing <em>conversion routines</em> to and from binary and hexadecimal bases.</p></li> </ul> -<h2 id="section-4"><code>1.07 (2013/05/25)</code></h2> +<h2 id="section-5"><code>1.07 (2013/05/25)</code></h2> <ul> <li><p>The <strong>xintexpr</strong> package is a new core constituent (which loads automatically <strong>xintfrac</strong> and <strong>xint</strong>) and implements the expandable expanding parser</p> <pre><code>\xintexpr . . . \relax,</code></pre> @@ -805,16 +864,16 @@ License: LPPL 1.3f</code></pre> <ul> <li>Minor code and documentation improvements. Everywhere in the source code, a more modern underscore has replaced the @ sign.</li> </ul> -<h2 id="section-5"><code>1.06 (2013/05/07)</code></h2> +<h2 id="section-6"><code>1.06 (2013/05/07)</code></h2> <ul> <li><p>Some code improvements, particularly for macros of <strong>xint</strong> doing loops.</p></li> <li><p>New utilities in <strong>xint</strong> for expandable manipulations of lists:</p> <pre><code>\xintNthElt, \xintCSVtoList, \xintRevWithBraces</code></pre></li> <li><p>The macros did only a double expansion of their arguments. They now fully expand them (using <code>\romannumeral-`0</code>). Furthermore, in the case of arguments constrained to obey the TeX bounds they will be inserted inside a <code>\numexpr..\relax</code>, hence completely expanded, one may use count registers, even infix arithmetic operations, etc…</p></li> </ul> -<h2 id="section-6"><code>1.05 (2013/05/01)</code></h2> +<h2 id="section-7"><code>1.05 (2013/05/01)</code></h2> <p>Minor changes and additions to <strong>xintfrac</strong> and <strong>xintcfrac</strong>.</p> -<h2 id="section-7"><code>1.04 (2013/04/25)</code></h2> +<h2 id="section-8"><code>1.04 (2013/04/25)</code></h2> <ul> <li><p>New component <strong>xintcfrac</strong> devoted to continued fractions.</p></li> <li><p><strong>xint</strong>: faster division.</p></li> @@ -824,13 +883,13 @@ License: LPPL 1.3f</code></pre> <li><p><code>tex xint.dtx</code> extracts style files (no need for a <code>xint.ins</code>).</p></li> <li><p>Bug fix (<strong>xintfrac</strong>): <code>\xintIrr {0}</code> crashed.</p></li> </ul> -<h2 id="section-8"><code>1.03 (2013/04/14)</code></h2> +<h2 id="section-9"><code>1.03 (2013/04/14)</code></h2> <ul> <li><p>New modules <strong>xintfrac</strong> (expandable operations on fractions) and <strong>xintseries</strong> (expandable partial sums with xint package).</p></li> <li><p>Slightly improved division and faster multiplication (the best ordering of the arguments is chosen automatically).</p></li> <li><p>Added illustration of Machin algorithm to the documentation.</p></li> </ul> -<h2 id="section-9"><code>1.0 (2013/03/28)</code></h2> +<h2 id="section-10"><code>1.0 (2013/03/28)</code></h2> <p>Initial announcement:</p> <blockquote> <p>The <strong>xint</strong> 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.</p> diff --git a/macros/generic/xint/CHANGES.pdf b/macros/generic/xint/CHANGES.pdf Binary files differdeleted file mode 100644 index d449cb63c8..0000000000 --- a/macros/generic/xint/CHANGES.pdf +++ /dev/null diff --git a/macros/generic/xint/Makefile b/macros/generic/xint/Makefile index df8fd9a051..c8bdeb9bf2 100644 --- a/macros/generic/xint/Makefile +++ b/macros/generic/xint/Makefile @@ -1,20 +1,16 @@ -# Makefile for compilation of the complete xint -# documentation, packages, and installation. -# (C) 2014-2015 Jean-Francois Burnol -# distributed under LPPL 1.3c or later at your convenience. - -# with this file Makefile and xint.dtx in a working -# repertory run 'make' and then get further instructions. +# Makefile for building and installing xint +# (C) 2014-2019 Jean-Francois Burnol +# distributed under LPPL 1.3c. # Tested with GNU Make 3.81 on Mac OS X Mavericks, # with TeXLive 2014 and Pandoc 1.13.1, xint.dtx v1.1 +Makefile.mk: xint.dtx ; etex xint.dtx + # For some reason I would like Makefile.mk to be always # recreated if xint.dtx is newer, *before* being included # here via include, but my brief attempt (2015/09/16) did # not succeed. -Makefile.mk: xint.dtx ; etex xint.dtx - include Makefile.mk diff --git a/macros/generic/xint/README b/macros/generic/xint/README deleted file mode 100644 index 580b1e8965..0000000000 --- a/macros/generic/xint/README +++ /dev/null @@ -1,205 +0,0 @@ - Source: xint.dtx 1.3f 2019/09/10 (doc 2019/09/10) - Author: Jean-Francois Burnol - Info: Expandable operations on big integers, decimals, fractions - License: LPPL 1.3f - -This README is also available as README.pdf and README.html. - -Change log is to be found in CHANGES.pdf or CHANGES.html. - -The user manual is xint.pdf, and the commented source code is available -as sourcexint.pdf. - - - -AIM - - -The basic aim is provide _expandable_ computations on integers, -fractions, and floating point numbers. For example - - \xinttheexpr reduce(37189719/183618963+11390170/17310720)^17\relax - -will evaluate exactly the fraction; the result has 462 characters -(including the fraction slash.) One can also work with dummy variables: - - \xinttheexpr mul(add(x(x+1)(x+2), x=y..y+15), y=171286,98762,9296)\relax - -evaluates to 15979066346135829902328007959448563667099190784. - -Float computations are possible at an adjustable precision (default 16). - - \xintDigits:=48;\xintthefloatexpr 123_456_789^1_000.5\relax - ->3.63692761822782679930738270515740797370813691938e8095 - -(as this example shows the underscore character can be used to separate -visually digits, one can also use the space character for that purpose). - -Square-root and the four operations achieve correct rounding in the -given arbitrary precision. - -Trigonometric functions (direct and inverse) are available with a -maximal precision of 60 digits. - -Logarithms and exponentials are available using the poormanlog package -which provides only 8 or 9 digits of precision. This will be increased -in future. - - - -USAGE - - -It is possible to use the package both with Plain (\input xintexpr.sty) -or with LaTeX (\usepackage{xintexpr}). - - -With LaTeX - - \usepackage{xint} % expandable arithmetic with big integers - \usepackage{xintfrac} % decimal numbers, fractions, floats - \usepackage{xinttools} % expandable and non expandable loops - \usepackage{xintexpr} % expressions with infix operators - -The xinttrig and xintlog packages are loaded automatically by xintexpr -and will refuse to be loaded directly. - -Further packages: xintbinhex, xintgcd, xintseries and xintcfrac. - -Main dependencies are handled automatically. For example xintexpr -automatically loads xinttools and xintfrac (which itself loads xint). -Hexadecimal input requires explicit loading of xintbinhex. - -Package xintcore is the subset of xint providing only the five -operations on big integers: \xintiiAdd, \xintiiMul, … - -The LaTeX package bnumexpr defines a more light-weight parser of -arithmetical expressions using big integers, which supports only the -four operations, the modulo operation, the power operation, and the -factorial. By default it uses the macros from xintcore but this can be -customized. - -The LaTeX package polexpr is based upon xintexpr and allows formal -algebra with polynomials, and finding all real roots with arbitrary -precision. - - -With TeX - -One does for example: - - \input xintexpr.sty - -This will automatically load xintfrac.sty, xinttrig.sty, xintlog.sty and -xinttools.sty. The packages may be loaded in any catcode context such -that letters, digits, \ and % have their standard catcodes. - -xintcore.sty and xinttools.sty both import xintkernel.sty which has the -catcode handler and package identifier and defines a few utilities such -as \oodef/\fdef, \xint_dothis/\xint_orthat, or \xintLength. - -Since 1.3b, xintkernel.sty also provides \xintUniformDeviate which is a -wrapper of the engine \pdfuniformdeviate or \uniformdeviate done to -guarantee more uniformity of the pseudo-random integers. - - - -INSTALLATION - - -Method A: using the package manager of your TeX distribution - -xint is included in TeXLive (hence also MacTeX) and MikTeX. - -There can be a few days of delay between apparition of a new version on -CTAN and availability via the distribution package manager. - - -Method B: manual installation using xint.tds.zip and unzip - -Assumes a GNU/Linux-like system (or Mac OS X). - -1. obtain xint.tds.zip from CTAN: - http://mirror.ctan.org/install/macros/generic/xint.tds.zip - -2. cd to the download repertory and issue: - - unzip xint.tds.zip -d <TEXMF> - - where <TEXMF> is a suitable TDS-compliant destination repertory. For - example, with TeXLive: - - - Linux, standard access rights, hence sudo is needed, - installation into the “local” tree: - - sudo unzip xint.tds.zip -d /usr/local/texlive/texmf-local - sudo texhash /usr/local/texlive/texmf-local - - - Mac OS X, installation into user home folder (no sudo needed, - and it is recommended to not have a ls-R file there, hence no - texhash): - - unzip xint.tds.zip -d ~/Library/texmf - - -Method C: manual installation using Makefile and xint.dtx - -The Makefile automatizes rebuilding from xint.dtx all documentation -files as well as xint.tds.zip. It is for GNU/Linux-like (inc. Mac OS X) -systems, with a teTeX like installation such as TeXLive. The Latexmk and -Pandoc softwares are required to build all the documentation. - -1. obtain xint.dtx and Makefile from - http://mirror.ctan.org/macros/generic/xint. - -2. put them in an otherwise empty working repertory, run make or - equivalently make help for further instructions. - - -Method D: installation starting with only xint.dtx - -Run etex xint.dtx to extract from xint.dtx all macro files as well as -auxiliary files needed for building the documentation. Among them there -is Makefile.mk. If you are on a GNU/Linux-type system, rename the file -to Makefile and execute make on command line for further help. If you -can’t use make read the contents of the Makefile for instructions. - -Finishing the installation in a TDS hierarchy: - -- move the style files to TDS:tex/generic/xint/ - -- xint.dtx goes to TDS:source/generic/xint/ - -- The documentation (xint.pdf, README.md,…) goes to - TDS:doc/generic/xint/ - -Depending on the destination, it may then be necessary to refresh a -filename database. - - - -LICENSE - - -Copyright (C) 2013-2019 by Jean-Francois Burnol - -This Work may be distributed and/or modified under the conditions of the -LaTeX Project Public License version 1.3c. This version of this license -is in - - http://www.latex-project.org/lppl/lppl-1-3c.txt - -and version 1.3 or later is part of all distributions of LaTeX version -2005/12/01 or later. - -This Work has the LPPL maintenance status author-maintained. - -The Author of this Work is Jean-Francois Burnol. - -This Work consists of the source file xint.dtx and of its derived files: -xintkernel.sty, xintcore.sty, xint.sty, xintfrac.sty, xintexpr.sty, -xinttrig.sty, xintlog.sty, xintbinhex.sty, xintgcd.sty, xintseries.sty, -xintcfrac.sty, xinttools.sty, xint.ins, xint.tex, README, README.md, -README.html, README.pdf, CHANGES.md, CHANGES.html, CHANGES.pdf, -pandoctpl.latex, doHTMLs.sh, doPDFs.sh, xint.dvi, xint.pdf, and -Makefile.mk. diff --git a/macros/generic/xint/README.html b/macros/generic/xint/README.html deleted file mode 100644 index cee77f4af2..0000000000 --- a/macros/generic/xint/README.html +++ /dev/null @@ -1,133 +0,0 @@ -<!DOCTYPE html> -<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang=""> -<head> - <meta charset="utf-8" /> - <meta name="generator" content="pandoc" /> - <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> - <meta name="author" content="xint 1.3f" /> - <title>README</title> - <style type="text/css"> - code{white-space: pre-wrap;} - span.smallcaps{font-variant: small-caps;} - span.underline{text-decoration: underline;} - div.column{display: inline-block; vertical-align: top; width: 50%;} - </style> - <style type="text/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;} - </style> - <!--[if lt IE 9]> - <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script> - <![endif]--> -</head> -<body> -<header> -<h1 class="title">README</h1> -<p class="author">xint 1.3f</p> -<p class="date">2019/09/10</p> -</header> -<nav id="TOC"> -<ul> -<li><a href="#aim">Aim</a></li> -<li><a href="#usage">Usage</a><ul> -<li><a href="#with-latex">With LaTeX</a></li> -<li><a href="#with-tex">With TeX</a></li> -</ul></li> -<li><a href="#installation">Installation</a><ul> -<li><a href="#method-a-using-the-package-manager-of-your-tex-distribution">Method A: using the package manager of your TeX distribution</a></li> -<li><a href="#method-b-manual-installation-using-xint.tds.zip-and-unzip">Method B: manual installation using <code>xint.tds.zip</code> and <code>unzip</code></a></li> -<li><a href="#method-c-manual-installation-using-makefile-and-xint.dtx">Method C: manual installation using <code>Makefile</code> and <code>xint.dtx</code></a></li> -<li><a href="#method-d-installation-starting-with-only-xint.dtx">Method D: installation starting with only <code>xint.dtx</code></a></li> -</ul></li> -<li><a href="#license">License</a></li> -</ul> -</nav> -<pre><code>Source: xint.dtx 1.3f 2019/09/10 (doc 2019/09/10) -Author: Jean-Francois Burnol -Info: Expandable operations on big integers, decimals, fractions -License: LPPL 1.3f</code></pre> -<p>This <code>README</code> is also available as <code>README.pdf</code> and <code>README.html</code>.</p> -<p>Change log is to be found in <code>CHANGES.pdf</code> or <code>CHANGES.html</code>.</p> -<p>The user manual is <code>xint.pdf</code>, and the commented source code is available as <code>sourcexint.pdf</code>.</p> -<h1 id="aim">Aim</h1> -<p>The basic aim is provide <em>expandable</em> computations on integers, fractions, and floating point numbers. For example</p> -<pre><code>\xinttheexpr reduce(37189719/183618963+11390170/17310720)^17\relax</code></pre> -<p>will evaluate exactly the fraction; the result has 462 characters (including the fraction slash.) One can also work with dummy variables:</p> -<pre><code>\xinttheexpr mul(add(x(x+1)(x+2), x=y..y+15), y=171286,98762,9296)\relax</code></pre> -<p>evaluates to <code>15979066346135829902328007959448563667099190784</code>.</p> -<p>Float computations are possible at an adjustable precision (default 16).</p> -<pre><code>\xintDigits:=48;\xintthefloatexpr 123_456_789^1_000.5\relax -->3.63692761822782679930738270515740797370813691938e8095</code></pre> -<p>(as this example shows the underscore character can be used to separate visually digits, one can also use the space character for that purpose).</p> -<p>Square-root and the four operations achieve correct rounding in the given arbitrary precision.</p> -<p>Trigonometric functions (direct and inverse) are available with a maximal precision of 60 digits.</p> -<p>Logarithms and exponentials are available using the <a href="http://www.ctan.org/pkg/poormanlog">poormanlog</a> package which provides only 8 or 9 digits of precision. This will be increased in future.</p> -<h1 id="usage">Usage</h1> -<p>It is possible to use the package both with Plain (<code>\input xintexpr.sty</code>) or with LaTeX (<code>\usepackage{xintexpr}</code>).</p> -<h2 id="with-latex">With LaTeX</h2> -<pre><code>\usepackage{xint} % expandable arithmetic with big integers -\usepackage{xintfrac} % decimal numbers, fractions, floats -\usepackage{xinttools} % expandable and non expandable loops -\usepackage{xintexpr} % expressions with infix operators</code></pre> -<p>The <code>xinttrig</code> and <code>xintlog</code> packages are loaded automatically by <code>xintexpr</code> and will refuse to be loaded directly.</p> -<p>Further packages: <code>xintbinhex</code>, <code>xintgcd</code>, <code>xintseries</code> and <code>xintcfrac</code>.</p> -<p>Main dependencies are handled automatically. For example <code>xintexpr</code> automatically loads <code>xinttools</code> and <code>xintfrac</code> (which itself loads <code>xint</code>). Hexadecimal input requires explicit loading of <code>xintbinhex</code>.</p> -<p>Package <code>xintcore</code> is the subset of <code>xint</code> providing only the five operations on big integers: <code>\xintiiAdd</code>, <code>\xintiiMul</code>, …</p> -<p>The LaTeX package <a href="http://www.ctan.org/pkg/bnumexpr">bnumexpr</a> defines a more light-weight parser of arithmetical expressions using big integers, which supports only the four operations, the modulo operation, the power operation, and the factorial. By default it uses the macros from <code>xintcore</code> but this can be customized.</p> -<p>The LaTeX package <a href="http://www.ctan.org/pkg/polexpr">polexpr</a> is based upon <code>xintexpr</code> and allows formal algebra with polynomials, and finding all real roots with arbitrary precision.</p> -<h2 id="with-tex">With TeX</h2> -<p>One does for example:</p> -<pre><code>\input xintexpr.sty</code></pre> -<p>This will automatically load <code>xintfrac.sty</code>, <code>xinttrig.sty</code>, <code>xintlog.sty</code> and <code>xinttools.sty</code>. The packages may be loaded in any catcode context such that letters, digits, <code>\</code> and <code>%</code> have their standard catcodes.</p> -<p><code>xintcore.sty</code> and <code>xinttools.sty</code> both import <code>xintkernel.sty</code> which has the catcode handler and package identifier and defines a few utilities such as <code>\oodef/\fdef</code>, <code>\xint_dothis/\xint_orthat</code>, or <code>\xintLength</code>.</p> -<p>Since <code>1.3b</code>, <code>xintkernel.sty</code> also provides <code>\xintUniformDeviate</code> which is a wrapper of the engine <code>\pdfuniformdeviate</code> or <code>\uniformdeviate</code> done to guarantee more uniformity of the pseudo-random integers.</p> -<h1 id="installation">Installation</h1> -<h2 id="method-a-using-the-package-manager-of-your-tex-distribution">Method A: using the package manager of your TeX distribution</h2> -<p><code>xint</code> is included in <a href="http://tug.org/texlive/">TeXLive</a> (hence also <a href="http://tug.org/mactex/">MacTeX</a>) and <a href="http://www.miktex.org/">MikTeX</a>.</p> -<p>There can be a few days of delay between apparition of a new version on <a href="http://www.ctan.org/pkg/xint">CTAN</a> and availability via the distribution package manager.</p> -<h2 id="method-b-manual-installation-using-xint.tds.zip-and-unzip">Method B: manual installation using <code>xint.tds.zip</code> and <code>unzip</code></h2> -<p>Assumes a GNU/Linux-like system (or Mac OS X).</p> -<ol type="1"> -<li><p>obtain <code>xint.tds.zip</code> from CTAN: <a href="http://mirror.ctan.org/install/macros/generic/xint.tds.zip" class="uri">http://mirror.ctan.org/install/macros/generic/xint.tds.zip</a></p></li> -<li><p>cd to the download repertory and issue:</p> -<pre><code> unzip xint.tds.zip -d <TEXMF></code></pre> -<p>where <code><TEXMF></code> is a suitable TDS-compliant destination repertory. For example, with TeXLive:</p> -<ul> -<li><p>Linux, standard access rights, hence sudo is needed, installation into the “local” tree:</p> -<pre><code> sudo unzip xint.tds.zip -d /usr/local/texlive/texmf-local - sudo texhash /usr/local/texlive/texmf-local</code></pre></li> -<li><p>Mac OS X, installation into user home folder (no sudo needed, and it is recommended to not have a ls-R file there, hence no texhash):</p> -<pre><code> unzip xint.tds.zip -d ~/Library/texmf</code></pre></li> -</ul></li> -</ol> -<h2 id="method-c-manual-installation-using-makefile-and-xint.dtx">Method C: manual installation using <code>Makefile</code> and <code>xint.dtx</code></h2> -<p>The Makefile automatizes rebuilding from <code>xint.dtx</code> all documentation files as well as <code>xint.tds.zip</code>. It is for GNU/Linux-like (inc. Mac OS X) systems, with a teTeX like installation such as TeXLive. The <a href="http://personal.psu.edu/jcc8/software/latexmk/">Latexmk</a> and <a href="http://johnmacfarlane.net/pandoc/">Pandoc</a> softwares are required to build all the documentation.</p> -<ol type="1"> -<li><p>obtain <code>xint.dtx</code> and <code>Makefile</code> from <a href="http://mirror.ctan.org/macros/generic/xint" class="uri">http://mirror.ctan.org/macros/generic/xint</a>.</p></li> -<li><p>put them in an otherwise empty working repertory, run <code>make</code> or equivalently <code>make help</code> for further instructions.</p></li> -</ol> -<h2 id="method-d-installation-starting-with-only-xint.dtx">Method D: installation starting with only <code>xint.dtx</code></h2> -<p>Run <code>etex xint.dtx</code> to extract from <code>xint.dtx</code> all macro files as well as auxiliary files needed for building the documentation. Among them there is <code>Makefile.mk</code>. If you are on a GNU/Linux-type system, rename the file to <code>Makefile</code> and execute <code>make</code> on command line for further help. If you can’t use <code>make</code> read the contents of the <code>Makefile</code> for instructions.</p> -<p>Finishing the installation in a TDS hierarchy:</p> -<ul> -<li><p>move the style files to <code>TDS:tex/generic/xint/</code></p></li> -<li><p><code>xint.dtx</code> goes to <code>TDS:source/generic/xint/</code></p></li> -<li><p>The documentation (xint.pdf, README.md,…) goes to <code>TDS:doc/generic/xint/</code></p></li> -</ul> -<p>Depending on the destination, it may then be necessary to refresh a filename database.</p> -<h1 id="license">License</h1> -<div class="mono"> -<p>Copyright (C) 2013-2019 by Jean-Francois Burnol</p> -<p>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</p> -<blockquote> -<p><a href="http://www.latex-project.org/lppl/lppl-1-3c.txt" class="uri">http://www.latex-project.org/lppl/lppl-1-3c.txt</a></p> -</blockquote> -<p>and version 1.3 or later is part of all distributions of LaTeX version 2005/12/01 or later.</p> -<p>This Work has the LPPL maintenance status <code>author-maintained</code>.</p> -<p>The Author of this Work is Jean-Francois Burnol.</p> -This Work consists of the source file xint.dtx and of its derived files: xintkernel.sty, xintcore.sty, xint.sty, xintfrac.sty, xintexpr.sty, xinttrig.sty, xintlog.sty, xintbinhex.sty, xintgcd.sty, xintseries.sty, xintcfrac.sty, xinttools.sty, xint.ins, xint.tex, README, README.md, README.html, README.pdf, CHANGES.md, CHANGES.html, CHANGES.pdf, pandoctpl.latex, doHTMLs.sh, doPDFs.sh, xint.dvi, xint.pdf, and Makefile.mk. -</div> -</body> -</html> diff --git a/macros/generic/xint/README.md b/macros/generic/xint/README.md new file mode 100644 index 0000000000..06aa3d216a --- /dev/null +++ b/macros/generic/xint/README.md @@ -0,0 +1,116 @@ +% README +% xint 1.4 +% 2020/01/31 + + Source: xint.dtx 1.4 2020/01/31 (doc 2020/01/31) + Author: Jean-Francois Burnol + Info: Expandable operations on big integers, decimals, fractions + License: LPPL 1.3c + +Aim and usage +============= + +The basic aim is provide *expandable* computations on integers, +fractions, and floating point numbers. For example, with fractions: + + \xinteval{reduce(37189719/183618963+11390170/17310720)^17} + +The result has `462` characters (forward slash included.) +One can also work with dummy variables: + + \xinteval{mul(add(x(x+1)(x+2), x=y..y+15), y=171286,98762,9296)} + +and do computations with floating point numbers at an adjustable +precision (default `16`). + + \xintDigits:=48;\xintfloateval{123_456_789^10_000.5} + expands to 1.56866129625858270633170234772583710433908855336e80919 + +Release `1.4` adds support for nested structures: + + \xintthealign\xintexpr ndseq(1/(i+j), i=1..5; j=1..5)\relax + +will print on the page + + [[ 1/2, 1/3, 1/4, 1/5, 1/6 ], + [ 1/3, 1/4, 1/5, 1/6, 1/7 ], + [ 1/4, 1/5, 1/6, 1/7, 1/8 ], + [ 1/5, 1/6, 1/7, 1/8, 1/9 ], + [ 1/6, 1/7, 1/8, 1/9, 1/10 ]] + +The four operations and the square-root extraction achieve so-called +*correct rounding* in the given arbitrary precision. + +Trigonometric functions (direct and inverse) are available up to a +maximal precision of about `58` digits. Logarithms and exponentials are +currently evaluated only with `8` or `9` digits precision. + +It is possible to use the package both with Plain (`\input xintexpr.sty`) +or with the LaTeX macro format (`\usepackage{xintexpr}`). + +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. + +Alternatives: + +- download + [`xint.tds.zip`](http://mirror.ctan.org/install/macros/generic/xint.tds.zip) + and install in a suitable TDS-compliant repertory via `unzip`. "admin" + privilges might be needed, as well as a file database rebuild (`texhash`). + For example, on macos x, installation into user home folder (no `sudo`, + and no `texhash` as it is recommended to not have a ls-R file there) + + unzip xint.tds.zip -d ~/Library/texmf + +- all files can be extracted using `etex xint.dtx`, or `make` if the + `Makefile` included in the CTAN upload is present; see the file `INSTALL`, + if present, else read the help in extracted file `Makefile.mk`. + +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`) + +Requirements +============ + +Attention, release `1.4` requires the `\expanded` primitive available +in all major TeX engines since TeXLive 2019. + +License +======= + +Copyright (C) 2013-2020 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 `Makefile`, `INSTALL`, and `xint.dtx` +and its extracted and derived files inclusive of the documentation +files `xint.pdf`, `sourcexint.pdf` and `CHANGES.html`. + +See `xint.pdf` for contact information. + diff --git a/macros/generic/xint/README.pdf b/macros/generic/xint/README.pdf Binary files differdeleted file mode 100644 index 9fa9fe6008..0000000000 --- a/macros/generic/xint/README.pdf +++ /dev/null diff --git a/macros/generic/xint/sourcexint.pdf b/macros/generic/xint/sourcexint.pdf Binary files differindex 7a2465e316..3cf21147b9 100644 --- a/macros/generic/xint/sourcexint.pdf +++ b/macros/generic/xint/sourcexint.pdf diff --git a/macros/generic/xint/xint.dtx b/macros/generic/xint/xint.dtx index a0620b17be..0962cf0553 100644 --- a/macros/generic/xint/xint.dtx +++ b/macros/generic/xint/xint.dtx @@ -3,28 +3,28 @@ % Extract all files via "etex xint.dtx" and do "make help" % or follow instructions from extracted README.md. %<*dtx> -\def\xintdtxtimestamp {Time-stamp: <10-09-2019 at 22:59:27 CEST>} +\def\xintdtxtimestamp {Time-stamp: <31-01-2020 at 16:51:45 CET>} %</dtx> %<*drv> %% --------------------------------------------------------------- -\def\xintdocdate {2019/09/10} -\def\xintbndldate{2019/09/10} -\def\xintbndlversion {1.3f} +\def\xintdocdate {2020/01/31} +\def\xintbndldate{2020/01/31} +\def\xintbndlversion {1.4} %</drv> %<readme>% README %<changes>% CHANGE LOG -%<readme|changes>% xint 1.3f -%<readme|changes>% 2019/09/10 +%<readme|changes>% xint 1.4 +%<readme|changes>% 2020/01/31 %<readme|changes> -%<readme|changes> Source: xint.dtx 1.3f 2019/09/10 (doc 2019/09/10) +%<readme|changes> Source: xint.dtx 1.4 2020/01/31 (doc 2020/01/31) %<readme|changes> Author: Jean-Francois Burnol %<readme|changes> Info: Expandable operations on big integers, decimals, fractions -%<readme|changes> License: LPPL 1.3f +%<readme|changes> License: LPPL 1.3c %<readme|changes> -%<*!readme&!changes&!dohtmlsh&!dopdfsh&!makefile> +%<*!readme&!changes&!dohtmlsh&!makefile> %% --------------------------------------------------------------- -%% The xint bundle 1.3f 2019/09/10 -%% Copyright (C) 2013-2019 by Jean-Francois Burnol +%% The xint bundle 1.4 2020/01/31 +%% Copyright (C) 2013-2020 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 @@ -38,207 +38,359 @@ %<xinttrig>%% xinttrig: Trigonometry for the xintexpr package %<xintlog>%% xintlog: Logarithms and exponentials for xintexpr %% --------------------------------------------------------------- -%</!readme&!changes&!dohtmlsh&!dopdfsh&!makefile> +%</!readme&!changes&!dohtmlsh&!makefile> %<*dtx> \bgroup\catcode2 0 \catcode`\\ 12 ^^Biffalse %</dtx> %<*readme>-------------------------------------------------------- -This `README` is also available as `README.pdf` and `README.html`. - -Change log is to be found in `CHANGES.pdf` or `CHANGES.html`. - -The user manual is `xint.pdf`, and the commented source code is -available as `sourcexint.pdf`. - -Aim -=== +Aim and usage +============= The basic aim is provide *expandable* computations on integers, -fractions, and floating point numbers. For example - - \xinttheexpr reduce(37189719/183618963+11390170/17310720)^17\relax +fractions, and floating point numbers. For example, with fractions: -will evaluate exactly the fraction; the result has 462 characters -(including the fraction slash.) One can also work with dummy variables: + \xinteval{reduce(37189719/183618963+11390170/17310720)^17} - \xinttheexpr mul(add(x(x+1)(x+2), x=y..y+15), y=171286,98762,9296)\relax +The result has `462` characters (forward slash included.) +One can also work with dummy variables: -evaluates to `15979066346135829902328007959448563667099190784`. + \xinteval{mul(add(x(x+1)(x+2), x=y..y+15), y=171286,98762,9296)} -Float computations are possible at an adjustable precision (default 16). +and do computations with floating point numbers at an adjustable +precision (default `16`). - \xintDigits:=48;\xintthefloatexpr 123_456_789^1_000.5\relax - ->3.63692761822782679930738270515740797370813691938e8095 + \xintDigits:=48;\xintfloateval{123_456_789^10_000.5} + expands to 1.56866129625858270633170234772583710433908855336e80919 -(as this example shows the underscore character can be used to separate -visually digits, one can also use the space character for that purpose). +Release `1.4` adds support for nested structures: -Square-root and the four operations achieve correct rounding in the -given arbitrary precision. + \xintthealign\xintexpr ndseq(1/(i+j), i=1..5; j=1..5)\relax -Trigonometric functions (direct and inverse) are available with a -maximal precision of 60 digits. +will print on the page -Logarithms and exponentials are available using the -[poormanlog](http://www.ctan.org/pkg/poormanlog) package which provides -only 8 or 9 digits of precision. This will be increased in future. + [[ 1/2, 1/3, 1/4, 1/5, 1/6 ], + [ 1/3, 1/4, 1/5, 1/6, 1/7 ], + [ 1/4, 1/5, 1/6, 1/7, 1/8 ], + [ 1/5, 1/6, 1/7, 1/8, 1/9 ], + [ 1/6, 1/7, 1/8, 1/9, 1/10 ]] -Usage -===== +The four operations and the square-root extraction achieve so-called +*correct rounding* in the given arbitrary precision. -It is possible to use the package both with Plain -(`\input xintexpr.sty`) or with LaTeX (`\usepackage{xintexpr}`). +Trigonometric functions (direct and inverse) are available up to a +maximal precision of about `58` digits. Logarithms and exponentials are +currently evaluated only with `8` or `9` digits precision. -## With LaTeX +It is possible to use the package both with Plain (`\input xintexpr.sty`) +or with the LaTeX macro format (`\usepackage{xintexpr}`). - \usepackage{xint} % expandable arithmetic with big integers - \usepackage{xintfrac} % decimal numbers, fractions, floats - \usepackage{xinttools} % expandable and non expandable loops - \usepackage{xintexpr} % expressions with infix operators - -The `xinttrig` and `xintlog` packages are loaded automatically by -`xintexpr` and will refuse to be loaded directly. - -Further packages: `xintbinhex`, `xintgcd`, `xintseries` and `xintcfrac`. +Installation +============ -Main dependencies are handled automatically. For example `xintexpr` -automatically loads `xinttools` and `xintfrac` (which itself loads -`xint`). Hexadecimal input requires explicit loading of `xintbinhex`. +`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. -Package `xintcore` is the subset of `xint` providing only the five -operations on big integers: `\xintiiAdd`, `\xintiiMul`, ... +Alternatives: -The LaTeX package [bnumexpr](http://www.ctan.org/pkg/bnumexpr) defines a -more light-weight parser of arithmetical expressions using big integers, -which supports only the four operations, the modulo operation, the power -operation, and the factorial. By default it uses the macros from -`xintcore` but this can be customized. +- download + [`xint.tds.zip`](http://mirror.ctan.org/install/macros/generic/xint.tds.zip) + and install in a suitable TDS-compliant repertory via `unzip`. "admin" + privilges might be needed, as well as a file database rebuild (`texhash`). + For example, on macos x, installation into user home folder (no `sudo`, + and no `texhash` as it is recommended to not have a ls-R file there) -The LaTeX package [polexpr](http://www.ctan.org/pkg/polexpr) is based -upon `xintexpr` and allows formal algebra with polynomials, and finding -all real roots with arbitrary precision. + unzip xint.tds.zip -d ~/Library/texmf -## With TeX +- all files can be extracted using `etex xint.dtx`, or `make` if the + `Makefile` included in the CTAN upload is present; see the file `INSTALL`, + if present, else read the help in extracted file `Makefile.mk`. -One does for example: +Documentation +============= - \input xintexpr.sty +`README.md`: this file -This will automatically load `xintfrac.sty`, `xinttrig.sty`, -`xintlog.sty` and `xinttools.sty`. The packages may be loaded in any -catcode context such that letters, digits, `\` and `%` have their -standard catcodes. +`CHANGES.html`: change log as relevant to end users + (`texdoc --list xint`) -`xintcore.sty` and `xinttools.sty` both import `xintkernel.sty` -which has the catcode handler and package identifier and defines a -few utilities such as `\oodef/\fdef`, `\xint_dothis/\xint_orthat`, -or `\xintLength`. +`xint.pdf`: user manual -Since `1.3b`, `xintkernel.sty` also provides `\xintUniformDeviate` which -is a wrapper of the engine `\pdfuniformdeviate` or `\uniformdeviate` -done to guarantee more uniformity of the pseudo-random integers. +`sourcexint.pdf`: commented source code + (`texdoc --list xint` or `texdoc sourcexint`) -Installation +Requirements ============ -## Method A: using the package manager of your TeX distribution - -`xint` is included in [TeXLive](http://tug.org/texlive/) (hence also -[MacTeX](http://tug.org/mactex/)) and [MikTeX](http://www.miktex.org/). - -There can be a few days of delay between apparition of a new version on -[CTAN](http://www.ctan.org/pkg/xint) and availability via the distribution -package manager. - -## Method B: manual installation using `xint.tds.zip` and `unzip` +Attention, release `1.4` requires the `\expanded` primitive available +in all major TeX engines since TeXLive 2019. -Assumes a GNU/Linux-like system (or Mac OS X). - -1. obtain `xint.tds.zip` from CTAN: - <http://mirror.ctan.org/install/macros/generic/xint.tds.zip> - -2. cd to the download repertory and issue: +License +======= - unzip xint.tds.zip -d <TEXMF> +Copyright (C) 2013-2020 by Jean-Francois Burnol - where `<TEXMF>` is a suitable TDS-compliant destination repertory. - For example, with TeXLive: +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 - - Linux, standard access rights, hence sudo is needed, installation - into the "local" tree: +> <http://www.latex-project.org/lppl/lppl-1-3c.txt> - sudo unzip xint.tds.zip -d /usr/local/texlive/texmf-local - sudo texhash /usr/local/texlive/texmf-local +and version 1.3 or later is part of all distributions of +LaTeX version 2005/12/01 or later. - - Mac OS X, installation into user home folder (no sudo needed, - and it is recommended to not have a ls-R file there, hence no texhash): +This Work has the LPPL maintenance status `author-maintained`. - unzip xint.tds.zip -d ~/Library/texmf +The Author of this Work is `Jean-Francois Burnol`. -## Method C: manual installation using `Makefile` and `xint.dtx` +This Work consists of the files `Makefile`, `INSTALL`, and `xint.dtx` +and its extracted and derived files inclusive of the documentation +files `xint.pdf`, `sourcexint.pdf` and `CHANGES.html`. -The Makefile automatizes rebuilding from `xint.dtx` all documentation -files as well as `xint.tds.zip`. It is for GNU/Linux-like (inc. Mac OS -X) systems, with a teTeX like installation such as TeXLive. The -[Latexmk](http://personal.psu.edu/jcc8/software/latexmk/) -and [Pandoc](http://johnmacfarlane.net/pandoc/) softwares -are required to build all the documentation. +See `xint.pdf` for contact information. -1. obtain `xint.dtx` and `Makefile` from - <http://mirror.ctan.org/macros/generic/xint>. +%</readme>-------------------------------------------------------- +%<*changes>------------------------------------------------------- -2. put them in an otherwise empty working repertory, run `make` or - equivalently `make help` for further instructions. +`1.4 (2020/01/31)` +---- -## Method D: installation starting with only `xint.dtx` +### Breaking changes -Run `etex xint.dtx` to extract from `xint.dtx` all macro files as well -as auxiliary files needed for building the documentation. Among them -there is `Makefile.mk`. If you are on a GNU/Linux-type system, rename -the file to `Makefile` and execute `make` on command line for further -help. If you can't use `make` read the contents of the `Makefile` for -instructions. +Please note that this list is currently incomplete. If not otherly +specified all items regard the **xintexpr** module. -Finishing the installation in a TDS hierarchy: + - The `\expanded` primitive (TeXLive 2019) is **required**. This does + not affect the macro layer **xintcore**, **xint**, **xintfrac**, + **xinttools** (yet). -- move the style files to `TDS:tex/generic/xint/` + - 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. -- `xint.dtx` goes to `TDS:source/generic/xint/` + - Formerly square brackets `[...]` were, on their own, not different + from parentheses, 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 documentation (xint.pdf, README.md,...) goes to `TDS:doc/generic/xint/` + - 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. + + - 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` 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). -Depending on the destination, it may then be necessary to refresh a -filename database. +### Improvements and new features -License -======= +Please note that this list is currently incomplete. For more +information look at the user manual and the documented source code +`sourcexint.pdf`. -<div class="mono"> -Copyright (C) 2013-2019 by Jean-Francois Burnol +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. + (Such checks exist in the codebase, but have not yet been integrated + into `\xintdefvar` by laziness). + + - 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... -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 +### Bug fixes -> <http://www.latex-project.org/lppl/lppl-1-3c.txt> +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. -and version 1.3 or later is part of all distributions of -LaTeX version 2005/12/01 or later. +### TODO -This Work has the LPPL maintenance status `author-maintained`. + - 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). -The Author of this Work is Jean-Francois Burnol. + - Prior to integrating all of `NumPy`, it is envisioned to start with + matrix algebra first. -This Work consists of the source file xint.dtx and of its derived -files: xintkernel.sty, xintcore.sty, xint.sty, xintfrac.sty, -xintexpr.sty, xinttrig.sty, xintlog.sty, xintbinhex.sty, -xintgcd.sty, xintseries.sty, -xintcfrac.sty, xinttools.sty, xint.ins, xint.tex, README, README.md, -README.html, README.pdf, CHANGES.md, CHANGES.html, CHANGES.pdf, -pandoctpl.latex, doHTMLs.sh, doPDFs.sh, xint.dvi, xint.pdf, -and Makefile.mk.</div> -%</readme>-------------------------------------------------------- -%<*changes>------------------------------------------------------- `1.3f (2019/09/10)` ---- @@ -273,7 +425,7 @@ and Makefile.mk.</div> `1.3e (2019/04/05)` ---- -### Incompatible changes +### 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 @@ -320,7 +472,7 @@ and Makefile.mk.</div> `1.3d (2019/01/06)` ---- -### Incompatible changes +### Breaking changes - **xintexpr**: the `gcd()` and `lcm()` functions formerly converted their arguments to integers via `\xintNum`. They now handle general @@ -448,7 +600,7 @@ require an engine providing the `\(pdf)uniformdeviate` primitive. `1.3 (2018/03/01)` ---- -### Incompatible changes +### Breaking changes - **xintcore**, **xint**, **xintfrac**: all macros deprecated at `1.2o` got removed. @@ -498,7 +650,7 @@ require an engine providing the `\(pdf)uniformdeviate` primitive. `1.2p (2017/12/05)` ---- -### Incompatible changes +### 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 @@ -557,7 +709,7 @@ require an engine providing the `\(pdf)uniformdeviate` primitive. `1.2o (2017/08/29)` ---- -### Incompatible changes +### Breaking changes - **xint**: `\xintAND`, `\xintOR`, ... and similar Boolean logic macros do not apply anymore `\xintNum` (or `\xintRaw` if **xintfrac** is loaded), to @@ -607,7 +759,7 @@ releases. They will all get removed at some future release. `1.2n (2017/08/06)` ---- -### Incompatible changes +### Breaking changes - **xintbinhex** does not load package **xintcore** anymore, but only **xintkernel**. @@ -623,7 +775,7 @@ releases. They will all get removed at some future release. `1.2m (2017/07/31)` ---- -### Incompatible changes +### 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 @@ -730,7 +882,7 @@ releases. They will all get removed at some future release. `1.2k (2017/01/06)` ---- -### Incompatible changes +### 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 @@ -816,7 +968,7 @@ releases. They will all get removed at some future release. `1.2i (2016/12/13)` ---- -### Incompatible changes +### Breaking changes - `\xintDecSplit` second argument must have no sign (former code replaced it with its absolute value, a sign now may cause an error.) @@ -916,7 +1068,7 @@ releases. They will all get removed at some future release. `1.2g (2016/03/19)` ---- -### Incompatible changes +### 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 @@ -958,7 +1110,7 @@ releases. They will all get removed at some future release. `1.2f (2016/03/12)` ---- -### Incompatible changes +### Breaking changes - no more `\xintFac` macro but `\xintiFac/\xintiiFac/\xintFloatFac`. @@ -1236,7 +1388,7 @@ releases. They will all get removed at some future release. `1.1 (2014/10/28)` ---- -### Incompatible changes +### Breaking changes - in `\xintiiexpr`, `/` does _rounded_ division, rather than the Euclidean division (for positive arguments, this is truncated division). @@ -1956,15 +2108,11 @@ Initial announcement: %</changes>------------------------------------------------------ %<*makefile>------------------------------------------------------ # This file: Makefile.mk (generated from xint.dtx) -# Rename the file as Makefile, or keep is named as Makefile.mk -# and download master Makefile from -# http://mirror.ctan.org/macros/generic/xint -# then run "make help" +# "make --file=Makefile.mk help" -# Starting with xint 1.3c, uses Latexmk for easier compilation of -# sourcexint.pdf as it includes indices. These indices for -# source code were actually removed at 1.3e but usage of Latexmk -# is maintained for the build (despite it being simpler now). +# 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. @@ -1985,57 +2133,41 @@ newline := $(newline) define helptext ==== INSTRUCTIONS -The Makefile is to automatize the extraction and compilation from -xint.dtx of package files and documentation files, and for producing -xint.tds.zip. It is for GNU/Linux like systems, with a teTeX like -installation such as TeXLive. Tested on Mac OS X Mavericks with TL2014. - -For compiling the PDF files, packages newtx, newtxtt, etoc,... are used -and should be up-to-date (as of 2014/10). Conversion to plain, html and -pdf format of README.md and CHANGES.md (make PanPDF, make PanHTML) -require Pandoc software. (tested with Pandoc 1.13.1). - -It is recommended to work with xint.dtx and Makefile in an otherwise -initially empty temporary repertory. +It is recommended to work with xint.dtx and Makefile moved to some +otherwise empty temporary repertory. make help - prints this help (using more). It will also have already extracted - all files from xint.dtx. + prints this help using more. And it will extract all files + inclusive of README.md, CHANGES.md, and TeX macro files. make helpless - prints this help (using less). - -make xint.pdf - extracts files and produces xint.pdf, using latex and dvipdfmx. - Uses Latexmk. No Pandoc needed. To get xint.pdf to include - the source code and indices, refer to instructions in xint.tex. - -make sourcexint.pdf - extracts files and produces sourcexint.pdf, using latex, makeindex - and dvipdfmx. Uses Latexmk. No Pandoc needed. - -make PanPDF - produces README.pdf and CHANGES.pdf, requires Pandoc. - -make PanHTML - produces README.html and CHANGES.html, requires Pandoc. + prints this help using less. make doc - produces all documentation. + produces all documentation, requires Latexmk and Pandoc. make all - produces all documentation, and creates xint.tds.zip. + 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, using latex and dvipdfmx. + Requires Latexmk. + +make sourcexint.pdf + extracts files and produces sourcexint.pdf, using latex, makeindex + 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). If no - Makefile, use "etex xint.dtx" to regenerate Makefile.mk, rename - it as Makefile and run "make help". + removes all files, leaving only xint.dtx (and Makefile). ==== INSTALLING @@ -2043,27 +2175,28 @@ The following has been tested on a TeXLive installation: make installhome creates xint.tds.zip, and unzips it in <TEXMFHOME> - (it assumes there is no ls-R file there) make installlocal - creates xint.tds.zip, and unzips it in <TEXMFLOCAL> - (and then does texhash <TEXMFLOCAL>) - IT MIGHT BE NEEDED TO RUN IT AS "sudo make installlocal" - This depends on how the access rights are configured. - In case of doubt run first "make doc" and then "make - installlocal". If the latter fails, "sudo make installlocal". + 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>) - IT MIGHT BE NEEDED TO RUN IT AS "sudo make uninstalllocal" + and then does texhash <TEXMFLOCAL> + + Might need "sudo". endef -.PHONY: help helpless all extract doc PanPDF PanHTML clean cleanall\ +.PHONY: help helpless all doc clean cleanall\ installhome uninstallhome installlocal uninstalllocal # for printf with subst and \n, got it from @@ -2090,17 +2223,12 @@ packages = xintkernel.sty xintcore.sty xint.sty xintfrac.sty xintexpr.sty\ # docstrip, as .tex is always appended if a filename with no extension is # specified. If "make -f Makefile.mk" is run, Makefile.mk will not be # overwritten because tex xint.dtx does not extract it (etex xint.dtx does). -extracted = $(packages) xint.tex xint.ins README.md CHANGES.md\ - doHTMLs.sh doPDFs.sh pandoctpl.latex -doc_pdf = README.pdf CHANGES.pdf -doc_html = README.html CHANGES.html +extracted = $(packages) xint.tex xint.ins README.md CHANGES.md doHTMLs.sh filesfortex = $(packages) filesforsource = xint.dtx Makefile -filesfordoc = xint.pdf sourcexint.pdf README $(doc_pdf) $(doc_html) +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\ - README.dvi README.aux README.toc README.out README.log\ - CHANGES.dvi CHANGES.aux CHANGES.toc CHANGES.out CHANGES.log + sourcexint.dvi sourcexint.aux sourcexint.toc sourcexint.log xint_cmd = latexmk xint sourcexint_cmd = latexmk -jobname=sourcexint\ -latex='latex %O "\chardef\dosourcexint=1 \input{%S}"' xint.tex @@ -2108,12 +2236,10 @@ sourcexint_cmd = latexmk -jobname=sourcexint\ all: $(extracted) doc xint.tds.zip @echo 'make all done.' -extract: $(extracted) - $(extracted): xint.dtx tex xint.dtx -doc: xint.pdf sourcexint.pdf README PanPDF PanHTML +doc: xint.pdf sourcexint.pdf CHANGES.html @echo 'make doc done.' xint.pdf: xint.dtx xint.tex @@ -2124,17 +2250,7 @@ sourcexint.pdf: xint.dtx xint.tex $(sourcexint_cmd) dvipdfmx sourcexint.dvi -README: README.md - pandoc -t plain -o README README.md - -PanPDF: $(doc_pdf) - -$(doc_pdf): doPDFs.sh - chmod u+x doPDFs.sh && ./doPDFs.sh - -PanHTML: $(doc_html) - -$(doc_html): doHTMLs.sh +CHANGES.html: CHANGES.md doHTMLs.sh chmod u+x doHTMLs.sh && ./doHTMLs.sh xint.tds.zip: $(filesfordoc) $(filesforsource) $(filesfortex) @@ -2191,125 +2307,18 @@ clean: xint.fls xint.fdb_latexmk cleanall: clean - rm -f $(extracted) $(doc_pdf) $(doc_html)\ - README README.tex CHANGES.tex\ + rm -f $(extracted) CHANGES.html \ xint.pdf sourcexint.pdf xint.tds.zip xint.zip Makefile.mk %</makefile>$----------------------------------------------------- -%<*pandoctpl>----------------------------------------------------- -\newcommand{\tightlist}{% - \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}} -$if(dvipdfmx)$ -{\csname @for\endcsname\x:=hyperref,graphicx,color,xcolor\do - {\PassOptionsToPackage{dvipdfmx}\x}} - \PassOptionsToPackage{dvipdfmx-outline-open}{hyperref} - \PassOptionsToPackage{dvipdfm}{geometry} -$endif$ -\documentclass[$papersize$,fontsize=$fontsize$]{scrartcl} -\usepackage[T1]{fontenc} -\usepackage[utf8]{inputenc} -\usepackage[english]{babel} - -\usepackage{newtxtext} -\usepackage{newtxtt} -\usepackage{newtxmath} - -\usepackage{upquote} - -% pour les \texttt venant de la conversion par pandoc des `...`: -\begingroup\makeatletter - \catcode`\'\active - \catcode`\*\active - \catcode`\`\active -\@firstofone {\endgroup - \def\dostraightquotesandstar{% textcomp package is loaded by newtxtext - \let`\textasciigrave - \let'\textquotesingle - \edef*{\noexpand\raisebox{-.25\noexpand\height}{\string*}}% - \catcode39\active % ' - \catcode96\active % ` - \catcode42\active }% * -}% for \texttt, let's just forget about math and italic correction things -\DeclareRobustCommand\texttt {\bgroup - \dostraightquotesandstar\afterassignment\ttfamily\let\next=} - -$if(geometry)$ -\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry} -$endif$ -$if(tables)$ -\usepackage{longtable,booktabs} -$endif$ -\usepackage[unicode=true,bookmarks]{hyperref} -\hypersetup{breaklinks=true,% - pdfauthor={Jean-Fran\c cois Burnol},% - pdftitle={$title$ $author$ $date$},% - colorlinks=true,% - citecolor=$if(citecolor)$$citecolor$$else$blue$endif$,% - urlcolor=$if(urlcolor)$$urlcolor$$else$blue$endif$,% - linkcolor=$if(linkcolor)$$linkcolor$$else$magenta$endif$,% - pdfborder={0 0 0},% - pdfstartview=FitH,% - pdfpagemode=UseOutlines} -%%\urlstyle{same} % don't use monospace font for urls - -\setlength{\parindent}{0pt} -\setlength{\emergencystretch}{3em} % prevent overfull lines -\usepackage{enumitem} -%% reduce LaTeX's insane vertical spacing around verbatim blocks -\setlength{\parskip}{\medskipamount} -\setlist[trivlist]{topsep=0pt,partopsep=0pt,itemsep=0pt,parsep=0pt} - -$if(numbersections)$ -\setcounter{secnumdepth}{5} -$else$ -\setcounter{secnumdepth}{0} -$endif$ - -$if(etoc)$\usepackage{etoc}$endif$ - -\title{$title$} -\author{$author$} -\date{$date$} - -$for(header-includes)$ -$header-includes$ -$endfor$ - -\begin{document} -$if(title)$ -\maketitle -$endif$ - -$for(include-before)$ -$include-before$ - -$endfor$ - -$if(toc)$ -\setcounter{tocdepth}{$toc-depth$} -$if(etoc)$ -\etocdefaultlines -\etocmulticolstyle[$etoc$]{} -$endif$ -\tableofcontents -$endif$ - -$body$ - -$for(include-after)$ -$include-after$ - -$endfor$ -\end{document} -%</pandoctpl>----------------------------------------------------- %<*dohtmlsh>------------------------------------------------------ #! /bin/sh -# produces README.html and CHANGES.html from README.md and CHANGES.md +# <s>README.html and</s> CHANGES.html from <s>README.md and </s>CHANGES.md # tested with pandoc 1.13.1 -pandoc -o README.html -s --toc -V highlighting-css=' body{margin-left : 10%; margin-right : 15%; margin-top: 4ex; font-size: 12pt;} - pre {white-space: pre-wrap; } - code {white-space: pre-wrap; } - .mono {font-family: monospace;}' README.md +# pandoc -o README.html -s --toc -V highlighting-css=' body{margin-left : 10%; margin-right : 15%; margin-top: 4ex; font-size: 12pt;} +# pre {white-space: pre-wrap; } +# code {white-space: pre-wrap; } +# .mono {font-family: monospace;}' README.md pandoc -o CHANGES.html -s --toc -V highlighting-css=' body{margin-left : 10%; margin-right : 15%; margin-top: 4ex; font-size: 12pt;} pre {white-space: pre-wrap;} @@ -2317,25 +2326,6 @@ pandoc -o CHANGES.html -s --toc -V highlighting-css=' body{margin-left : 10%; #TOC {float: right; position: relative; top: 100px; margin-bottom: 100px;}' CHANGES.md %</dohtmlsh>------------------------------------------------------ -%<*dopdfsh>------------------------------------------------------- -#! /bin/sh -# produces README.pdf and CHANGES.pdf from README.md and CHANGES.md -# via latex+dvipdfmx and custom pandoc latex template - -pandoc -o README.tex --template=pandoctpl --toc -V papersize=a4paper -V fontsize=11pt -V dvipdfmx --variable=geometry:footskip=1cm,left=2.5cm,right=2.5cm,top=2cm,bottom=3cm -V etoc=1 README.md -rm -f README.aux README.toc README.out -latex -interaction=nonstopmode README -latex -interaction=nonstopmode README -latex -interaction=nonstopmode README -dvipdfmx README.dvi - -pandoc -o CHANGES.tex --template=pandoctpl --toc -V 'toc-depth'=2 -V papersize=a4paper -V fontsize=11pt -V dvipdfmx --variable=geometry:footskip=1cm,left=2.5cm,right=2.5cm,top=2cm,bottom=3cm -V etoc=2 CHANGES.md -rm -f CHANGES.aux CHANGES.toc CHANGES.out -latex -interaction=nonstopmode CHANGES -latex -interaction=nonstopmode CHANGES -latex -interaction=nonstopmode CHANGES -dvipdfmx CHANGES.dvi -%</dopdfsh>------------------------------------------------------- %<*drv>----------------------------------------------------------- %% %% To produce manually xint.pdf from xint.tex: @@ -2343,15 +2333,12 @@ dvipdfmx CHANGES.dvi %% - or xelatex/pdflatex thrice. %% %% To produce manually sourcexint.pdf from xint.tex: +%% (latexmk argument quoting may need shell-dependant changes) %% latexmk -jobname=sourcexint\ %% -latex="latex %O \\\\chardef\\\\dosourcexint=1 \\\\input{%S}"\ %% xint.tex -%% (quoting may differ, depending on the shell) %% dvipdfmx sourcexint.dvi %% -%% It is naturally possible to replace latexmk by suitable latex -%% and makeindex calls, but details are left out here. -%% %% To get xint.pdf to include the source code and indices: %% - etex xint.dtx (this will regenerate this file), %% - replace 1 by 0 in \chardef line below, @@ -2369,73 +2356,6 @@ dvipdfmx CHANGES.dvi %%% TeX-PDF-from-DVI: "Dvipdfmx" %%% End: %</drv>----------------------------------------------------------- -%<*ins>----------------------------------------------------------- -%% -%% `tex xint.ins' extracts all package files from xint.dtx, as well as -%% xint.tex, README.md, CHANGES.md, doPDFs.sh, doHTMLs.sh, .latexmkrc -%% and xint-gind.ist -%% -%% `etex xint.ins' additionally extracts Makefile.mk, which is needed -%% for building documentation using `make'. -%% -\input docstrip.tex -\askforoverwritefalse -\generate{\nopreamble\nopostamble -\file{README.md}{\from{xint.dtx}{readme}} -\file{CHANGES.md}{\from{xint.dtx}{changes}} -\file{doHTMLs.sh}{\from{xint.dtx}{dohtmlsh}} -\file{doPDFs.sh}{\from{xint.dtx}{dopdfsh}} -\ifx\numexpr\undefined\else\catcode9 11 - \file{Makefile.mk}{\from{xint.dtx}{makefile}}\fi -\usepreamble\defaultpreamble -\usepostamble\defaultpostamble -\file{pandoctpl.latex}{\from{xint.dtx}{pandoctpl}} -\file{xint.tex}{\from{xint.dtx}{drv}} -\file{xintkernel.sty}{\from{xint.dtx}{xintkernel}} -\file{xinttools.sty}{\from{xint.dtx}{xinttools}} -\file{xintcore.sty}{\from{xint.dtx}{xintcore}} -\file{xint.sty}{\from{xint.dtx}{xint}} -\file{xintbinhex.sty}{\from{xint.dtx}{xintbinhex}} -\file{xintgcd.sty}{\from{xint.dtx}{xintgcd}} -\file{xintfrac.sty}{\from{xint.dtx}{xintfrac}} -\file{xintseries.sty}{\from{xint.dtx}{xintseries}} -\file{xintcfrac.sty}{\from{xint.dtx}{xintcfrac}} -\file{xintexpr.sty}{\from{xint.dtx}{xintexpr}} -\file{xinttrig.sty}{\from{xint.dtx}{xinttrig}} -\file{xintlog.sty}{\from{xint.dtx}{xintlog}}} -\catcode32=13\relax% active space -\let =\space% -\Msg{********************************************************************} -\Msg{*} -\Msg{* To finish the installation you have to move the following} -\Msg{* files into a directory searched by TeX:} -\Msg{*} -\Msg{* xintkernel.sty} -\Msg{* xintcore.sty} -\Msg{* xint.sty} -\Msg{* xintbinhex.sty} -\Msg{* xintgcd.sty} -\Msg{* xintfrac.sty} -\Msg{* xintseries.sty} -\Msg{* xintcfrac.sty} -\Msg{* xintexpr.sty} -\Msg{* xinttrig.sty} -\Msg{* xintlog.sty} -\Msg{* xinttools.sty} -\Msg{*} -\Msg{* To produce the user manual run latex thrice on xint.tex} -\Msg{* then dvipdfmx on xint.dvi, or if your system allows,} -\Msg{* execute `make xint.pdf' (this requires Latexmk).} -\Msg{*} -\Msg{* The commented source code is generated from executing} -\Msg{* `make sourcexint.pdf' (this requires Latexmk; if not} -\Msg{* available check the details in Makefile.mk and .latexmkrc)} -\Msg{*} -\Msg{* Happy TeXing!} -\Msg{*} -\Msg{********************************************************************} -\endbatchfile -%</ins>----------------------------------------------------------- %<*dtx>----------------------------------------------------------- ^^Bfi^^Begroup \chardef\noetex 0 @@ -2481,13 +2401,16 @@ dvipdfmx CHANGES.dvi \Msg{* \space\space\space\space xinttrig.sty^^J}% \Msg{* \space\space\space\space xintlog.sty^^J}% \Msg{*^^J}% -\Msg{* To produce the user manual run latex thrice on xint.tex^^J}% -\Msg{* then dvipdfmx on xint.dvi, or if your system allows,^^J}% -\Msg{* execute `make xint.pdf' (this requires Latexmk).^^J}% +\Msg{* Rename Makefile.mk to Makefile if the latter is absent^^J}% +\Msg{* (or use --file=Makefile.mk option to "make") then "make help"^^J}% +\Msg{* provides information on targets. In particular:^^J}% +\Msg{* - the "doc" target builds all documentation,^^J}% +\Msg{* - the "xint.tds.zip" target additionally prepares a TDS-compliant^^J}% +\Msg{*\space\space\space archive.^^J}% +\Msg{* This requires Latexmk (for xint.pdf and sourcexint.pdf) and Pandoc^^J}% +\Msg{* (for CHANGES.html).^^J}% \Msg{*^^J}% -\Msg{* The commented source code is generated from executing^^J}% -\Msg{* `make sourcexint.pdf' (this requires Latexmk; if not^^J}% -\Msg{* available check the details in Makefile.mk and .latexmkrc)^^J}% +\Msg{* Or check instructions in xint.tex for manual compilation.^^J}% \Msg{*^^J}% \Msg{* Happy TeXing!^^J}% \Msg{*^^J}% @@ -2505,11 +2428,8 @@ dvipdfmx CHANGES.dvi \ifnum\noetex=1 \else\ifx\XeTeXinterchartoks\undefined \file{Makefile.mk}{\from{xint.dtx}{makefile}}\fi\fi \file{doHTMLs.sh}{\from{xint.dtx}{dohtmlsh}} - \file{doPDFs.sh}{\from{xint.dtx}{dopdfsh}} \usepreamble\defaultpreamble \usepostamble\defaultpostamble - \file{pandoctpl.latex}{\from{xint.dtx}{pandoctpl}} - \file{xint.ins}{\from{xint.dtx}{ins}} \file{xint.tex}{\from{xint.dtx}{drv}} \file{xintkernel.sty}{\from{xint.dtx}{xintkernel}} \file{xinttools.sty}{\from{xint.dtx}{xinttools}} @@ -2559,11 +2479,6 @@ dvipdfmx CHANGES.dvi \else \documentclass {scrdoc} \fi -% Revert change to \smash and other macros at LaTeX 2018/12/01 -% https://github.com/latex3/latex2e/issues/108 -\makeatletter -\let\leavevmode@ifvmode\empty % for \smash in \NewWith etc... -\makeatother % Remove from sectioning commands insertion of marks, because we % will do it ourself. @@ -2575,8 +2490,16 @@ dvipdfmx CHANGES.dvi \patchcmd{\@sect}% {\expandafter\csname#1mark\expandafter\endcsname\expandafter{\@currentheadentry}}% {}{}{} +% 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{}% \makeatother - + + +\makeatletter + \PassOptionsToPackage{bookmarks=true}{hyperref} \ifnum\NoSourceCode=1 @@ -2615,8 +2538,8 @@ dvipdfmx CHANGES.dvi \usepackage{xintcfrac} \usepackage{amsmath}% for \cfrac usage \DeclareMathOperator{\sinc}{sinc} -\usepackage{pifont}% for \ding{73} (hollow star) \fi +\usepackage{pifont}% for \ding{73} (hollow star) \usepackage{xinttools} @@ -2676,15 +2599,16 @@ colorlinks=true,% urlcolor=niceone,% linkcolor=blue,% pdfauthor={Jean-Fran\c cois Burnol},% -pdftitle={The xint bundle},% +pdftitle={The xintexpr and allied packages},% pdfsubject={Arithmetic with TeX},% pdfkeywords={Expansion, arithmetic, TeX},% pdfstartview=FitH,% -pdfpagemode=UseOutlines} +pdfpagemode=UseNone,% +} \usepackage{hypcap} \ifnum\dosourcexint=1 -\hypersetup{pdftitle={The xint bundle source code}} +\hypersetup{pdftitle={The xint packages source code}} \fi \usepackage{bookmark} @@ -2908,10 +2832,12 @@ pdfpagemode=UseOutlines} % \fixmeaning \makeatletter -\def\fixmeaning {\expandafter\fix@meaning\meaning} -\expandafter\edef\expandafter\fix@meaning - \expandafter #\expandafter1\string\romannumeral#2#3% - {#1\string\romannumeral`\string^\string^@} +% \def\fixmeaning {\expandafter\fix@meaning\meaning} +% \expandafter\edef\expandafter\fix@meaning +% \expandafter #\expandafter1\string\romannumeral#2#3% +% {#1\string\romannumeral`\string^\string^@} +% Pour 1.4 +\let\fixmeaning\meaning \makeatother % Margin Notes @@ -2920,19 +2846,21 @@ pdfpagemode=UseOutlines} \makeatletter \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 - \smash{\hbox to 0pt + \hbox{\smash{\hbox to 0pt {\color[named]{PineGreen}\normalfont\small \hsize 1.6cm\rightskip.5cm minus.5cm - \hss\vtop{#2}\ $\to$#1\ }}% + \hss\vtop{#2}\ $\to$#1\ }}}% \vskip\dp\strutbox }\strut\@esphack} \def\MyMarginNoteWithBrace #1#2{\@bsphack \vadjust{\vskip-\dp\strutbox - \smash{\hbox to 0pt + \hbox{\smash{\hbox to 0pt {\color[named]{PineGreen}%\normalfont\small - \hss #1\ $\bigg\{$#2}}% + \hss #1\ $\bigg\{$#2}}}% \vskip\dp\strutbox }\strut\@esphack} \def\IMPORTANT {\MyMarginNoteWithBrace @@ -2942,19 +2870,19 @@ pdfpagemode=UseOutlines} {\kern\dimexpr\FrameSep+\FrameRule\relax\ }} \def\etype #1{\@bsphack \vadjust{\vskip-\dp\strutbox - \smash{\hbox to 0pt {\hss\color[named]{PineGreen}% - \itshape \xintListWithSep{\,}{#1}\ $\star$\quad }}% + \hbox{\smash{\hbox to 0pt {\hss\color[named]{PineGreen}% + \itshape \xintListWithSep{\,}{#1}\ $\star$\quad }}}% \vskip\dp\strutbox }\strut\@esphack} \def\retype #1{\@bsphack \vadjust{\vskip-\dp\strutbox - \smash{\hbox to 0pt {\hss\color[named]{PineGreen}% - \itshape \xintListWithSep{\,}{#1}\ \ding{73}\quad }}% + \hbox{\smash{\hbox to 0pt {\hss\color[named]{PineGreen}% + \itshape \xintListWithSep{\,}{#1}\ \ding{73}\quad }}}% \vskip\dp\strutbox }\strut\@esphack} \def\ntype #1{\@bsphack \vadjust{\vskip-\dp\strutbox - \smash{\hbox to 0pt {\hss\color[named]{PineGreen}% - \itshape \xintListWithSep{\,}{#1}\quad }}% + \hbox{\smash{\hbox to 0pt {\hss\color[named]{PineGreen}% + \itshape \xintListWithSep{\,}{#1}\quad }}}% \vskip\dp\strutbox }\strut\@esphack} % \def\Numf {{\vbox{\halign{\hfil##\hfil\cr \footnotesize @@ -2972,44 +2900,44 @@ pdfpagemode=UseOutlines} % \def\NewWith #1{\@bsphack \vadjust{\vskip-\dp\strutbox - \smash{\hbox to 0pt {\hss\color[named]{PineGreen}% + \hbox{\smash{\hbox to 0pt {\hss\color[named]{PineGreen}% \normalfont\small\bfseries \hsize 1.5cm\rightskip.5cm minus.5cm - \vtop{\noindent New with #1}\ }}% + \vtop{\noindent New with #1}\ }}}% \vskip\dp\strutbox }\strut\@esphack} % \def\CHANGED #1{\@bsphack \vadjust{\vskip-\dp\strutbox - \smash{\hbox to 0pt {\hss\color[named]{Red}% + \hbox{\smash{\hbox to 0pt {\hss\color[named]{Red}% \normalfont\small\bfseries \hsize 1.5cm\rightskip.5cm minus.5cm - \vtop{\noindent Changed at #1!}\ }}% + \vtop{\noindent Changed at #1!}\ }}}% \vskip\dp\strutbox }\strut\@esphack} \def\DEPRECATED #1{\@bsphack \vadjust{\vskip-\dp\strutbox - \smash{\hbox to 0pt {\hss\color[named]{PineGreen}% + \hbox{\smash{\hbox to 0pt {\hss\color[named]{PineGreen}% \normalfont\small\bfseries \hsize 2cm\rightskip.5cm minus.5cm - \vtop{\noindent Deprecated! (#1)}\ }}% + \vtop{\noindent Deprecated! (#1)}\ }}}% \vskip\dp\strutbox }\strut\@esphack} % \def\CHANGEDf #1{\@bsphack \vadjust{\vskip-\dp\strutbox - \smash{\hbox to 0pt {\hss\color[named]{Red}% + \hbox{\smash{\hbox to 0pt {\hss\color[named]{Red}% \normalfont\small\bfseries \hsize 1.5cm\rightskip.5cm minus.5cm \vtop{\noindent Changed at #1!}\ - \kern\dimexpr\FrameSep+\FrameRule\relax}}% + \kern\dimexpr\FrameSep+\FrameRule\relax}}}% \vskip\dp\strutbox }\strut\@esphack} % \def\NewWithf #1{\@bsphack \vadjust{\vskip-\dp\strutbox - \smash{\hbox to 0pt {\hss\color[named]{PineGreen}% + \hbox{\smash{\hbox to 0pt {\hss\color[named]{PineGreen}% \normalfont\small\bfseries \hsize 1.5cm\rightskip.5cm minus.5cm \vtop{\noindent New with #1}\ - \kern\dimexpr\FrameSep+\FrameRule\relax}}% + \kern\dimexpr\FrameSep+\FrameRule\relax}}}% \vskip\dp\strutbox }\strut\@esphack} \makeatother @@ -3018,35 +2946,18 @@ pdfpagemode=UseOutlines} % ======================================================= % 7 mars 2013 -% -% This macro allows to conveniently center a line inside a paragraph and still -% allow use therein of \verb or other macros changing catcodes. -% A proposito, the \LaTeX \centerline uses \hsize and not \linewidth ! -% (which in my humble opinion is bad) - -% Actually my \centeredline works nicely in list environments. - -% \ignorespaces added June 9, 2013 - -% Note: \centeredline creates a group - -\makeatletter -\newcommand*\centeredline {% - \ifhmode \\\relax - \def\centeredline@{\hss\egroup\hskip\z@skip\ignorespaces }% - \else - \def\centeredline@{\hss\egroup }% - \fi - \afterassignment\@centeredline - \let\next=} -\def\@centeredline - {\hbox to \linewidth \bgroup \hss \bgroup \aftergroup\centeredline@ } +% 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. + +\makeatletter \newif\ifinlefted \newcommand*\leftedline {% @@ -3447,7 +3358,8 @@ pdfpagemode=UseOutlines} \xintForpair #1#2 in -{(xintkernel,kernel), +{(xintbundle,bundle), + (xintkernel,kernel), (xinttools,tools), (xintcore,core),(xint,xint),(xintbinhex,binhex),(xintgcd,gcd),% (xintfrac,frac),(xintseries,series),(xintcfrac,cfrac),(xintexpr,expr),% @@ -3480,8 +3392,14 @@ pdfpagemode=UseOutlines} \expandafter\@firstoftwo\else \expandafter\@secondoftwo \fi - {\fbox{\textup{#1}}}{#1}} +% \ifinheader 2020/01/30 + {\ifinheader\fbox{\textup{#1}}\else#1\fi}% + {#1}% +} \makeatother +\newif\ifinheader +% doit être protégé +\protected\def\inheadertrue{\let\ifinheader\iftrue} % \RaisedLabel % ============ @@ -3505,19 +3423,21 @@ pdfpagemode=UseOutlines} \begin{document}\thispagestyle{empty} \pdfbookmark[1]{Title page}{TOP} +\def\partname{Part} +\addto\captionsenglish{\def\partname{Part}} {% \normalfont\Large\parindent0pt \parfillskip 0pt\relax \leftskip 2cm plus 1fil \rightskip 2cm plus 1fil \ifnum\dosourcexint=1 - The \xintnameimp source code\par + The \xintnameimp packages source code\par \gdef\DOCxintfrontpage {\texorpdfstring {\hyperref[frontpage]{\relax{\color{blue}TOC}}}% {TOC}% \xspace }% \else - The \xintname bundle\par + The \xintexprname and allied packages\par \fi \RaisedLabel{frontpage} } @@ -3532,22 +3452,40 @@ pdfpagemode=UseOutlines} } \medskip + +% 31 janvier 2020 + + \def\DOCuserguide + {\texorpdfstring + {\hyperref[sec:xintexprsyntax]{\relax{\color{joli}\MakeNameUp{Syntax reference}}}}% + {Syntax reference}% + \xspace }% + + \def\DOCxintexprmacros + {\texorpdfstring + {\hyperref[sec:oldxintexpr]{\relax{\color{joli}\MakeNameUp{Older macros and doc}}}}% + {Older macros and doc}% + \xspace }% + + \def\DOCexamples + {\texorpdfstring + {\hyperref[sec:examples]{\relax{\color{joli}\MakeNameUp{Old examples}}}}% + {Old examples}% + \xspace }% + % Vendredi 15 juin 2018 % Someone makes the comma active (not me! not sure if doc.sty or KOMA) and % this derails xspace.sty, in the headers, as it uses \scantokens on a list of % tokens, so it fails to recognize the commas which of course are of catcode12 -\def\xintRunningHeader{{\catcode`,12\relax +\def\xintRunningHeader{{\inheadertrue\catcode`,12\relax \DOCxintfrontpage, - \xintkernelname, - \xintcorename, - \xintname, - \xintfracname, - \xintexprname, \xinttrigname, \xintlogname, - \xintbinhexname, - \xintgcdname, - \xintseriesname, - \xintcfracname, - \xinttoolsname}} + \xintexprname, + \DOCuserguide, + \DOCxintexprmacros, + \xinttrigname, + \xintlogname, + \DOCexamples, + \xintbundlename}} \markboth{\makebox[0pt]{\xintRunningHeader}}{\makebox[0pt]{\xintRunningHeader}} % Skips safely. @@ -3570,12 +3508,14 @@ pdfpagemode=UseOutlines} \renewcommand*{\etocinnertopsep}{0pt} \renewcommand*{\etoctoclineleaders} {\hbox{\normalfont\normalsize\hbox to 1ex {\hss.\hss}}} -\etocmulticolstyle [1]{% - \phantomsection\section* {Contents} - \etoctoccontentsline*{toctobookmark}{Contents}{1}% -} - -\etocsettagdepth {description}{subsection} +% \etocmulticolstyle [1]{% +% \phantomsection\section* {Contents} +% \etoctoccontentsline*{toctobookmark}{Contents}{1}% +% } + +\etocsettocstyle{}{} +\etocsettagdepth {part1A}{subsection} +\etocsettagdepth {part1B}{section} \etocsettagdepth {macros}{none} \etocsettagdepth {implementation}{none} @@ -3584,12 +3524,13 @@ pdfpagemode=UseOutlines} \renewcommand*\etocabovetocskip{\bigskipamount} \makeatletter -\etocmulticolstyle [2]{\parskip\z@skip\raggedcolumns +\etocmulticolstyle [2]{\parskip\z@skip%\raggedcolumns \setlength{\columnsep}{\leftmarginii}% \setlength{\columnseprule}{0pt}% }% \makeatother - \etocsettagdepth {description}{none} + \etocsettagdepth {part1A}{none} + \etocsettagdepth {part1B}{none} \etocsettagdepth {macros} {section} \ifnum\NoSourceCode=1 \etocsettagdepth {implementation}{none} @@ -3597,6 +3538,7 @@ pdfpagemode=UseOutlines} \etocsettagdepth {implementation}{section} \fi +\vspace*{2\baselineskip} \tableofcontents @@ -3711,7 +3653,7 @@ pdfpagemode=UseOutlines} \node [block, below left of=A] (tools) {\xinttoolsname}; \node [block, right of=core, xshift=1cm] (bnumexpr) {\href{https://ctan.org/pkg/bnumexpr}{bnumexpr}}; \node [block, below of=core] (xint) {\xintname}; - \node [block, left of=xint, xshift=-.5cm] (gcd) {\xintgcdname}; + \node [block, left of=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}; @@ -3725,10 +3667,11 @@ pdfpagemode=UseOutlines} \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]}] (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); @@ -3740,7 +3683,8 @@ pdfpagemode=UseOutlines} \path [line,dashed,-{Stealth[length=5mm]}] (binhex.south) -- (expr); % at 1.3d gcd() and lcm() needs no support from xintgcd % \path [line,dashed,-{Stealth[length=5mm]}] (gcd.south) -- (expr); - \path [line,dashed,-{Stealth[length=5mm]}] (tools) to [out=0, in=90] +% 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 @@ -3778,270 +3722,132 @@ pdfpagemode=UseOutlines} \clearpage -\etocdepthtag.toc {description} - -\section{Read this first}\RaisedLabel{sec:quickintro} - -This section provides recommended reading on first discovering the package. - -This is release \expandafter|\xintbndlversion|. -\begin{enumerate} -\item \func{log}, \func{exp}, \func{log10}, \func{pow10}, \func{pow} are implemented via - \href{http://ctan.org/pkg/poormanlog}{poormanlog}: this achieves only \dtt{8} or \dtt{9} - digits of precision.... This situation is provisory, I simply was lacking - the time. See \xintlogname. -\item \func{sin}, \func{cos}, ..., \func{asin}, ... are implemented (using - high level user interface), up to about \dtt{60} digits of - precision, see \xinttrigname. -\item |NaN|, |+Infty|, |-Infty|, etc... and a proper internal data structure - for storing floating point numbers are \emph{yet to be implemented}. -\item \xintname can handle numbers with thousands of digits, but execution - times (and - \hyperref[ssec:memory]{memory considerations}) limit the practical range to - perhaps up to a few hundreds digits. -\item Attention that exact operations with fractions do not reduce to lowest - terms (additions and subtractions use |l.c.m.| of denominators), see - \func{reduce}. -\end{enumerate} +\etocdepthtag.toc {part1A} +\csname xintexprnameUp\endcsname +\part{The \xintexprname package} +\RaisedLabel[12]{sec:expr} +\etocsetnexttocdepth{section} +\localtableofcontents +\section {Release \texttt{\xintbndlversion } of \texttt{\xintbndldate}} -\begin{addmargin}{1cm} -\makeatletter -\renewenvironment{description} - {\list{}{\topsep\baselineskip\partopsep\z@skip - \parsep\z@ \labelwidth\z@ \itemindent-\leftmargin - \let\makelabel\descriptionlabel}} - {\endlist} -\makeatother +\subsection{Start here} -%\noindent\null\par\kern-\baselineskip -\leavevmode +To use with |etex|, |pdftex|, ..., i.e. with \TeX{} engines activating the +e\TeX{} extensions: +\begin{everbatim} +\input xintexpr.sty +\end{everbatim} +To use with the \LaTeX{} macro layer (|latex|, |pdflatex|, ...): +\begin{everbatim} +\usepackage{xintexpr} +\end{everbatim} -\begin{description} -\item[\xinttoolsname] provides utilities of independent interest such as - expandable and non-expandable loops. \xintgcdname and \xintcfracname have a - partial dependency on it but it must be required by user explicitely. - \xintexprname loads it automatically. - -\item[\xintcorename] provides expandable macros implementing addition, - subtraction, multiplication, division, and power with arbitrarily long - numbers. It is loaded automatically by \xintname, and also by \LaTeX\ - package \href{http://ctan.org/pkg/bnumexpr}{bnumexpr} in its default - configuration. - -\item[\xintname] extends \xintcorename with additional operations on big - integers. It loads automatically \xintcorename. - -\item[\xintfracname] extends the scope of \xintname to decimal numbers, to - numbers in scientific notation and also to fractions with arbitrarily - long such numerators and denominators separated by a forward slash. It loads - automatically \xintname. - -\item[\xintexprname] extends \xintfracname with expandable parsers doing - algebra (either exact, float, or limited to big integers) on comma separated - expressions using the standard infix notations and parentheses (or sub - \xintexprname-essions). It implements tacit multiplication, functions with - one or multiple arguments, Python-like slicing of lists, user-definable - variables and user-definable functions, boolean two way or three way - branching. Dummy variables can be used for summing or multiplying an - expression over a range, or for more complicated iterative evaluations - allowing \keyword{omit}, \keyword{abort}, - and \keyword{break} keywords. It loads automatically - \xintfracname (hence \xintname and \xintcorename) and \xinttoolsname. - And \xinttrigname and \xintlogname since |1.3e|. - -\item[\xinttrigname] trigonometrical functions for \xintexprname, - automatically loaded\NewWith{1.3e} by it, can not be used separately. - -\item[\xintlogname] logarithm, exponential, power functions for \xintexprname, - automatically loaded\NewWith{1.3e} by it, can not be used separately. -\end{description} +\medskip +|1.4| is a major release with new features and breaking changes. They are +summarized at top of |CHANGES.html| file (|texdoc --list xint|) and it is +recommended to read it as it may contain information which will not be +duplicated here. -Further modules: +\medskip -\begin{description} -\item[\xintbinhexname] is for conversions to and from binary and - hexadecimal bases. Support in \xintexprname of the \TeX\ |"| prefix for - hexadecimal inputs requires this module to be loaded by user. - -\item[\xintgcdname] implements the Euclidean algorithm and its typesetting. - The macro \csbxint{Irr} (hence the \xintexprname function \func{reduce}) is - provided independently in \xintfracname. Also the \xintexprname functions - \func{gcd} and \func{lcm} are implemented directly so loading this - module is not needed for them (since |1.3d|). - -\item[\xintseriesname] provides some basic functionality for computing in an - expandable manner partial sums of series and power series with fractional - coefficients. - -\item[\xintcfracname] is provided to help with the computation and display of - continued fractions. -\end{description} -\end{addmargin} +The formatted source code is available in file |sourcexint.pdf| +(|texdoc sourcexint|). \begin{framed} -All macros from the \xintname packages doing computations are -\emph{expandable}, and naturally also the parsers provided by \xintexprname. - - The reasonable range of use of the package arithmetics is with numbers of - \emph{up to a few hundred digits.} - Although numbers up to about \dtt{19950} digits are acceptable - inputs, the package is not at his peak efficiency when confronted with such - really big numbers having thousands of digits.\footnotemark + The main breaking change is that \xintexprname |1.4| requires the + |\expanded| primitive, available with all major \TeX{} engines since \TeX + Live 2019. But the supporting macro packages \xintcorename, \xintname, + \xintfracname, \xinttoolsname do not (yet). \end{framed} -\footnotetext{The maximal handled size for inputs to multiplication is - \dtt{19959} digits. This limit is observed with the current default values - of some parameters of the tex executable (input stack size at 5000, - maximal expansion depth at 10000). Nesting of macros will reduce it and it - is best to restrain numbers to at most \dtt{19900} digits. The output, as - naturally is the case with multiplication, may exceed the bound.} - - - -\subsection{First examples} - -With |\usepackage{xintexpr}| if using \LaTeX, or |\input xintexpr.sty\relax| -for other formats, you can do computations such as the following. -\begin{description} -\item[with floats:]\leavevmode\par -\begin{everbatim*} -\xintfloateval{3.25^100/3.2^100, 2^1000000, sqrt(1000!)}\newline -\xintfloateval{[-1] sind(37), cosd(37)}\newline % trim off last digit (via rounding) -\xintfloateval{[8] log10(12345678), pow10(0.1234)}\newline % only 8 or 9 digits! -\xintfloateval{[8] pow(2,1/3)}\newline % only 8 or 9 digits! -\xintfloateval{[8] log(10), exp(1)}\par % only 8 or 9 digits! -\end{everbatim*} - The \csbxint{floateval} macro using braces was introduced at |1.3d|. - Formerly, one did: -\begin{everbatim} -\thexintfloatexpr 10^-3.5\relax\ or rather \xintthefloatexpr 10^-3.5\relax -\end{everbatim} -Most of the manual is couched using the \csbxint{theexpr}|...\relax| -which is the original one from first release of \xintexprname. +\xintexprname is a package to do expandable computations, either exactly or in +the sense of floating point numbers at an arbitrary (reasonable% +% +\footnote{Trigonometrical functions are currently supported only up to about + \dtt{58} decimal digits, and generally speaking expansion starts taking + really too much time at about \dtt{500} digits. It looks as if \dtt{100} + digits is a reasonable upper limit for floating point (this is already a lot + to fit on one single line of text) and future development of the package + will not attempt to support floating point calculations efficiently beyond + that limit.}% +) precision. It supports user definition of variables and functions. Its +interface allows multiple comma separated expressions. - For powers with fractional exponents, see \hyperref[ssec:poormanloghack]{poormanloghack}. -\item[with fractions:]\leavevmode\par -Here is an example using a dummy a variable: -\begin{everbatim*} -$\sum_{i=1}^{25} (-1)^{i-1}\frac{1}{i^2} = - \xintFrac{\xinteval{reduce(add((-1)^(i-1)/i**2, i=1..25))}}$ -\end{everbatim*} -\item[with integers:]\leavevmode\par -\begin{everbatim*} -\xintiieval{3^159+2^234}\newline -\xintiieval{lcm(seq(n, n=100..110))}\par -\end{everbatim*} -\end{description} +\medskip -Float computations are done by default with \dtt{16} digits of precision. -This can be changed via an assignment to |\xintDigits|: +Iterated commas are like only one. The parentheses serve only to disambiguate +operator precedences or to hand-over variables to functions. One can add 100 +paired parentheses to |1, 2, 3| and it will not change anything. On the +other hand brackets |[|, |]| allow to define nested \emph{lists}, for example \begin{everbatim*} -% use braces (or a LaTeX environment) to limit the scope of the \xintDigits assignment -{\xintDigits := 88\relax \xintfloateval{3.25^100-3.2^100}}\par +\xinteval{1, 2, [3, [4, 5]], 6} \end{everbatim*} -Trigonometrical function need a reload after modifying the float precision, -this is done by \csbxint{reloadxinttrig}. +is a pretty impressive feast. -We can even try daring things:\footnote{The \cs{printnumber} is not part of - the package, see \autoref{ssec:printnumber}.} -\begin{everbatim*} -{\xintDigits:=500\relax \printnumber{\xintfloateval{sqrt(2)}}} -\end{everbatim*} +\medskip -All operations executed by the parsers are based on underlying macros from -packages \xintfracname and \xintname which are loaded automatically by -\xintexprname. With \xintbinhexname loaded the -parsers can handle hexadecimal notation on (even fractional) input. +Warning: I don't have the time to maintain perfectly such large documentation. +In preparing the |1.4| release I may have missed updating some bits +which got randomly shuffled to new places (at least I did delete large +sections, which was a hard decision to take, almost breaking the palimpsest +quality of the document). Reports welcome.% +% +\footnote{Thanks to Jürgen Gilg for keeping the author motivated and + helping proof-reading the documentation.} -All macros doing computations ultimately rely on (and reduce to) the -|\numexpr| primitive from \eTeX{}. These \eTeX{} extensions date back to 1999 -and are by default incorporated into the |pdftex| etc... executables from -major modern \TeX{} installations since more than ten years now. Only the -|tex| binary does not benefit from them, as it has to remain the original -\textsc{D.~Knuth}'s software, but one can then use |etex| on the command line. -PDF\TeX\ (in pdf or dvi output mode), Lua\TeX, Xe\TeX\ all include the \eTeX\ -extensions. - -\subsection{Quick overview (expressions with \xintexprname)} - -This section gives a first few examples of using the expression parsers which -are provided by package \xintexprname. See \autoref{sec:xintexprsyntax} for -a more detailed description, and perhaps read \autoref{ssec:threeparsers} -before coming back here. - -Loading \xintexprname automatically also -loads packages \xinttoolsname and \xintfracname. The latter loads \xintname -which loads \xintcorename. All three provide the macros which ultimately do the -computations associated in expressions with the various symbols like |+, *, ^, -!| and functions such as |max, sqrt, gcd|. The package -\xinttoolsname does not handle computations but provides some useful utilities. +\subsection{License and installation instructions} -\begin{framed} - Release |1.2h| defines |\thexintexpr| as synonym to |\xinttheexpr|, - |\thexintfloatexpr| as synonym of |\xintthefloatexpr|, etc... -\end{framed} +\label{ssec:install} -\begin{framed} - Release |1.3d| defines \csbxint{eval}, \csbxint{ieval}, \csbxint{iieval}, - \NewWithf{1.3d} - and \csbxint{floateval} which use braces to delimit their arguments, which - will be more familiar to \LaTeX\ users than the \csbxint{theexpr}|...\relax| - syntax. For example: -\begin{everbatim*} -\xinteval{1+2+3}, \xintfloateval{111/123}, \xintfloateval{[3] 111/123} -\end{everbatim*} +\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. - This documentation however uses systematically |\xinttheexpr...\relax| or - |\thexintexpr...\relax| syntax for legacy reasons. In this input syntax the - |\relax| does not have to be physically present it may arise from pure - expansion (see \autoref{sec:expr}). +On \TeX\ distributions with a |"texdoc"| or similar utility, +\centeredline{|texdoc --list xint|} +will offer to display one of those files: +\begin{itemize}[nosep] +\item |xint.pdf| (this file), +\item |sourcexint.pdf| (source code), +\item |README.md|, +\item |CHANGES.html|. +\end{itemize} - Notice that for the \csbxint{theiexpr} and \csbxint{thefloatexpr} parsers - which admit an optional argument, this optional argument will have to be - located \emph{inside} the braces when using |\xintieval| or |\xintfloateval| - input syntax, as examplified above. - The main reason is that it is sometimes useful to hide the square brackets, for - example when using the |\num| macro from package - \href{http://ctan.org/pkg/siunitx}{siunitx}. -\end{framed} -\begin{framed} - The square root extraction \func{sqrt} is allowed in |\xintexpr..\relax| but - naturally can't return an \emph{exact} value, it computes as if it was in - |\xintfloatexpr..\relax|. - - The synonymous power operators |^| and |**| allow only integral exponents - (non-negative in the integer only parser \csbxint{iiexpr}) in \csbxint{expr} - and half-integral exponents in \csbxint{floatexpr}. Since |1.3e| fractional - powers via the \func{pow} function are available, see - \xintlogname.\NewWithf{1.3e} But they achieve currently only about \dtt{8} - digits of precision. -\end{framed} +\subsection{Quick overview of syntax elements} -Here is a (partial) list of the recognized symbols: +Here is a (partial) list of the recognized syntax elements: \begin{itemize} \item the comma (to separate distinct computations or arguments to a function), \item parentheses, +\item square brackets,\NewWith{1.4} \item \hyperref[tab:precedences]{operators}: \begin{itemize}[nosep] \item |+|, |-|, |*|, |/|, -\item powers via |^| or equivalently |**|, see \xintlogname for allowing with - them fractional exponents, -\item |//| for floored division and |/:| its associated modulo, +\item powers via |^| or equivalently |**|, see \xintlogname for allowing usage of + them with fractional exponents (half-integer exponents are allowed by + default by \csbxint{floateval}), +\item |//| for floored division (attention that |-3//2| is computed as + |-(3//2)|) and |/:| its associated modulo, \item branching via |(x)?{x non zero}{x zero}| and |(x)??{x<0}{x=0}{x>0}| syntax, -\item boolean logic |!|, |&&| or |'and'|, \verb+||+ or |'or'|, -\item comparison operators |=| (or |==|), |<|, |>|, |<=|, |>=|, |!=|, -\item factorial via the post-fix operator |!|. +\item Boolean logic |!()|, |?()| (truth values), |&&| (equivalently |'and'|), \verb+||+ (equivalently + |'or'|), |'xor'|, +\item comparison operators |==|, |!=|, |<|, |>|, |<=|, |>=|, +\item factorial (exact or floating point, but only for integer arguments) via + the postfix operator |!|. \end{itemize} -\item the |"| is used to prefix hexadecimal input (uppercase, not lowercase); - but package \xintbinhexname must be loaded additionally to \xintexprname), +\item the |"| is used to prefix hexadecimal (only uppercase) input. This is + NOT activated by default: package \xintbinhexname \fbox{must} be explicitly + loaded, %\item |'| for octal input (\emph{not yet}), \item various \hyperref[tab:functions]{functions}: \begin{itemize}[nosep] @@ -4049,82 +3855,65 @@ Here is a (partial) list of the recognized symbols: point precision or with \func{float} to a given floating point precision, \item the square-root \func{sqrt} achieves correct rounding in arbitrary precision, - \item the \func{binomial} and (also partial) \func{factorial}, - \item \func{gcd} and \func{lcm} for general fractional operands, + \item \func{binomial}, \func{factorial}, \func{pfactorial}, + \item \func{gcd} and \func{lcm} both work with general fractions as input, \item randomness related functions such as \func{random} and \func{randrange} for random floats or integers; they require that \TeX\ engine provides \csa{pdfuniformdeviate} or \csa{uniformdeviate} primitive, \item trigonometrical functions \xinttrigname, - \item logarithm and exponential \xintlogname. - \end{itemize} -\item the capacity to work with dummy variables using functions or generators - such as \xintFor #1 in {add, mul, seq, subs, rseq, iter, rrseq, iterr}\do + \item logarithm and exponential functions \xintlogname. + \item pseudo-functions whose syntax involves usage of dummy variables: + \xintFor #1 in {subs, subsm, subsn, rseq, seq, add, mul, iter, rrseq, iterr, + ndseq, ndmap}\do {\func{#1}\xintifForLast{.}{, }} + \end{itemize} +\item built-in and user-defined \hyperref[ssec:uservariables]{variables} and \hyperref[ssec:userfunctions]{functions}. \end{itemize} -See \autoref{xintexpr} for basic information and \autoref{sec:xintexprsyntax} -for a complete description. The normal mode of operation of the parsers is to unveil the parsed material -token by token. This means (apart from some exceptions) that all tokens may -arise from expansion of encountered macros (or active characters). For example -a closing parenthesis does not have to be immediately visible, it may arise -later from expansion. - -However, this general behaviour has exceptions, in particular constructs with -dummy variables need at some location immediately visible balanced parentheses -and commas. +token by token. Unveiling is a process combining brace removal (one level +generally) and \fexpan sion (think of it as a kind of adaptative |\edef|). +Thus all tokens may arise from expansion of macros or active characters. For +example a closing parenthesis does not have generally to be immediately +visible, it may arise later from expansion. 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 to manipulate formally again +the whole thing; it can only re-discover it piece per piece. + +This general behaviour has significative exceptions mostly related to +«pseudo»-functions. A «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 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\NewWith{1.4}. The semi-colon catcode will be +set at the start of the process but of course this is too late if the whole +thing has already been grabbed in a macro. The expansion stops only when the ending |\relax| has been found; it is then removed from the token stream, and the final computation result is inserted. -Here is an example of a computation: -\begin{everbatim*} -\xinttheexpr (31.567^2 - 21.56*52)^3/13.52^5\relax -\end{everbatim*}\newline -This illustrates that -|\xinttheexpr..\relax| does its computations \emph{exactly}. The same example -as a floating point evaluation: -\begin{everbatim*} -\xintthefloatexpr (31.567^2 - 21.56*52)^3/13.52^5\relax -\end{everbatim*} - -Again, all computations done by |\xinttheexpr..\relax| are completely exact. -Thus, very quickly very big numbers are created (and computation times -increase, not to say explode if one goes into handling numbers with thousands -of digits). To compute something like |1.23456789^10000| it is thus better to -opt for the floating point version: -\begin{everbatim*} -\xintthefloatexpr 1.23456789^10000\relax -\end{everbatim*} -\newline -(we can deduce that the exact value has |80000+916=80916| digits). -A bigger example (the scope of -the assignment to |\xintDigits| is limited by the braces): -\begin{everbatim*} -{\xintDigits:=24\relax \xintthefloatexpr 1.23456789123456789^123456789\relax } -\end{everbatim*} -(<- notice the size of the power of ten: this surely largely exceeds your pocket -calculator abilities). - Some examples with dummy variables: \begin{everbatim*} -\xinttheiiexpr add(i^5, i=100..200)\relax\par -\noindent\xinttheexpr add(x/(x+1), x = 1000..1014)\relax\par -\noindent\xinttheexpr reduce(add(x/(x+1), x = 1000..1014))\relax +\xintiiexpr add(i^5, i=100..200)\relax\par +\noindent\xintexpr add(x/(x+1), x = 1000..1014)\relax\par +\noindent\xintexpr reduce(add(x/(x+1), x = 1000..1014))\relax \end{everbatim*} \newline In this example, the fraction obtained by addition was thus already irreducible, but this is not always the case: \begin{framed} - By default, the basic operations on fractions are not followed in an - automatic manner by reduction to smallest terms: |A/B| multiplied by |C/D| - returns |AC/BD|, and |A/B| added to |C/D| uses |lcm(B, D)| as denominator.\CHANGEDf{1.3} + By default, basic operations on fractions do not automatically reduce to + smallest terms the output: |A/B| multiplied by |C/D| + returns |AC/BD|, and |A/B| added to |C/D| uses |lcm(B, D)| as denominator. \end{framed} -Make sure to read \autoref{sec:expr}, \autoref{sec:xintexprsyntax} and -\autoref{ssec:outputs}. - \subsection{Printing big numbers on the page}\label{ssec:printnumber} When producing very long numbers there is the question of printing them on the page, without going beyond the page limits. In this document, I have most @@ -4140,468 +3929,399 @@ When producing very long numbers there is the question of printing them on It may be used like this: % -\leftedline{|\printnumber {\xintiiQuo{\xintiiPow {2}{1000}}{\xintiiFac{100}}}|} -% -or as |\printnumber\mybiginteger| or |\printnumber{\mybiginteger}| if -|\mybiginteger| was previously defined via a |\newcommand|, a |\def| or -an |\edef|. - -An alternative is to suitably configure the thousand -separator with the \href{http://ctan.org/pkg/numprint}{numprint} package -(see \autoref{fn:np}. This will not allow linebreaks when used in math -mode; I also tried \href{http://ctan.org/pkg/siunitx}{siunitx} but even -in text mode could not get it to break numbers accross lines). Recently -I became aware of the \href{http://ctan.org/pkg/seqsplit}{seqsplit} -package% -% -\footnote{\url{http://ctan.org/pkg/seqsplit}} -% -which can be used to achieve this splitting accross lines, and does work -in inline math mode (however it doesn't allow to separate digits by -groups of three, for example).\par +\begin{everbatim*} +\printnumber{\xintiieval{100!^3}}\newline +\end{everbatim*} +The rendering here uses extra decoration. -\subsection{Randomly chosen examples} +\subsection{Oples and nut-ples: terminology for a new \xintname generation} -This section is now quite old... +In this section I will describe a mathematical terminology appropriate to +understand the core functioning of the package in so far as it regards its +numerical mode of operation. The description requires some adaptations to +also cover the functioning during function declarations and this is not +covered here. -Here are some examples of use of the package macros. The first one uses only -the base module \xintname, the next one requires the \xintfracname package, -which deals with decimal numbers, scientific numbers (lowercase \dtt{e}), and -also fractions (it loads automatically \xintname). Then some examples with -expressions, which require the \xintexprname package (it loads automatically -\xintfracname). And finally some examples using \xintseriesname, \xintgcdname -which are among the extra packages included in the \xintname distribution. +We have \emph{atoms}, which represent numeric data. In \TeX{} syntax such +\emph{atoms} are always braced, more precisely, currently they look like +\dtt{\{raw xintcore or raw xintfrac format within \TeX{} braces\}}. Such +\TeX{} braces are not to be confused with set-theoretical braces: +\emph{atoms} are \emph{elements} and not \emph{sets}. -The printing of the outputs will either use a custom |\printnumber| macro as -described in the previous section, or sometimes the |\np| macro from the -\href{https://ctan.org/pkg/numprint}{numprint} package (see -\autoref{fn:np}). +Our category $\mathcal{C}$ of «oples» is the smallest collection of +\emph{totally ordered finite sets} verifying these properties: +\begin{enumerate} +\item The empty set \dtt{$\emptyset$} belongs to $\mathcal{C}$. +\item Each singleton set whose element is an atom qualifies as an + \emph{ople}. +\item $\mathcal{C}$ is stable by concatenation. +\item If \dtt{O} is an \emph{ople}, then the singleton \dtt{\{O\}} having + \dtt{O} as unique element is also an \emph{ople}. +\end{enumerate} +Notes: \begin{itemize} -\item {$123456^{99}$: }\\ -|\xintiiPow {123456}{99}|: -\dtt{\printnumber{\xintiiPow {123456}{99}}} - -\item {1234/56789 with 1500 digits after the decimal point: }\\ -|\xintTrunc {1500}{1234/56789}\dots|: -\dtt{\printnumber {\xintTrunc {1500}{1234/56789}}\dots } - -\item {$0.99^{-100}$ with 200 (+1) digits after the decimal point.}\\ - |\xinttheiexpr [201] .99^-100\relax|: - \dtt{\printnumber{\xinttheiexpr [201] .99^-100\relax}}\\ - Notice that this is rounded, hence we asked |\xinttheiexpr| for one - additional digit. To get a truncated result with 200 digits after the decimal - mark, we should have issued - |\xinttheexpr trunc(.99^-100,200)\relax|, rather. - -\begin{snugframed} - The fraction |0.99^-100|'s denominator is first evaluated \emph{exactly} - (\emph{i.e.} the integer |99^100| is evaluated exactly and then used to - divide the suitable power of ten to get the requested digits); for - some longer inputs, such as for example |0.7123045678952^-243|, the - exact evaluation before truncation would be costly, and it is more efficient - to use floating point numbers: -% -\leftedline{|\xintDigits:=20\relax - \np{\xintthefloatexpr .7123045678952^-243\relax}|}% -% -\leftedline{\xintDigits:=20\relax \dtt{\np{\xintthefloatexpr .7123045678952^-243\relax }}} -% -\xintDigits:=16\relax % -% -Side note: the exponent |-243| didn't have to be put inside parentheses, -contrarily to what happens with some professional computational -software. |;-)| -% 6.342,022,117,488,416,127,3 10^35 -% maple n'aime pas ^-243 il veut les parenthèses, bon et il donne, en Digits -% = 24: 0.634202211748841612732270 10^36 -\end{snugframed} - -\item {$200!$:}\\ -|\xinttheiiexpr 200!\relax|: -\dtt{\printnumber{\xinttheiiexpr 200!\relax}} - -\item {$2000!$ as a float. As \xintexprname does not handle |exp/log| so far, - the computation is done internally without the Stirling formula, - by repeated multiplications truncated suitably:}\\ - |\xintDigits:=50\relax |\newline |\xintthefloatexpr 2000!\relax|: - {\xintDigits:=50\relax \dtt{\printnumber{\xintthefloatexpr 2000!\relax}}} - -\item Just to show off (again), let's print 300 digits (after the decimal - point) of the decimal expansion of $0.7^{-25}$:% -% -\footnote{the |\np| typesetting macro is from the |numprint| package.} -% -\begin{everbatim*} -% % in the preamble: -% \usepackage[english]{babel} -% \usepackage[autolanguage,np]{numprint} -% \npthousandsep{,\hskip 1pt plus .5pt minus .5pt} -% \usepackage{xintexpr} -% in the body: -\np {\xinttheexpr trunc(.7^-25,300)\relax}\dots -\end{everbatim*} - -This computation is with \csbxint{theexpr} from package \xintexprname, which -allows to use standard infix notations and function names to access the package -macros, such as here |trunc| which corresponds to the \xintfracname macro -\csbxint{Trunc}. Regarding this computation, please keep in mind that -\csbxint{theexpr} computes \emph{exactly} the result before truncating. As -powers with fractions lead quickly to very big ones, it is good to know that -\xintexprname also provides \csbxint{thefloatexpr} which does computations -with floating point numbers. - -\item Computation of a Bézout identity with |7^200-3^200| and |2^200-1|: -(with \xintgcdname)\par -\begin{everbatim*} -\xintAssign{\xinttheiiexpr 7^200-3^200\relax} - {\xinttheiiexpr 2^200-1\relax}\to\A\B -\xintAssign\xintBezout{\A}{\B}\to\U\V\D -\printnumber\U${}\times(7^{200}-3^{200})+{}$\printnumber{\V}% -${}\times(2^{200}-1)=\D=\xinttheiiexpr \U*\A+\V*\B\relax$ -\end{everbatim*} - -\item The Euclide algorithm applied to \np{22206980239027589097} and -\np{8169486210102119257}: (with \xintgcdname)% -% -\footnote {this example is computed tremendously faster than the other - ones, but we had to limit the space taken by the output hence picked - up rather small big integers as input.}\par -\noindent\begingroup\parskip0pt\relax -|\xintTypesetEuclideAlgorithm {22206980239027589097}{8169486210102119257}|\par -\dtt -{\xintTypesetEuclideAlgorithm {22206980239027589097}{8169486210102119257}} -\endgroup -\smallskip - -\item $\sum_{n=1}^{500} (4n^2 - 9)^{-2}$ with each term rounded to twelve digits, -and the sum to nine digits: -\begin{everbatim*} -\def\coeff #1{\xintiRound {12}{1/\xintiiSqr{\the\numexpr 4*#1*#1-9\relax }[0]}} -\xintRound {9}{\xintiSeries {1}{500}{\coeff}[-12]} -\end{everbatim*} - -The complete series, extended to -infinity, has value -$\frac{\pi^2}{144}-\frac1{162}={}$% -\dtt{\np{0.06236607994583659534684445}\dots}\,% -% -\footnote{\label{fn:np}This number is typeset using the - \href{https://ctan.org/pkg/numprint}{numprint} package, with - |\npthousandsep{,\hskip 1pt plus .5pt minus .5pt}|. But the breaking - across lines works only in text mode. The number itself was (of - course...) computed initially with \xintname, with 30 digits of $\pi$ - as input. See \hyperref[ssec:Machin]{{how {\xintname} may compute - $\pi$ from scratch}}.} -% -I also used (this is a lengthier computation -than the one above) \xintseriesname to evaluate the sum with \np{100000} terms, -obtaining 16 -correct decimal digits for the complete sum. The -coefficient macro must be redefined to avoid a |\numexpr| overflow, as -|\numexpr| inputs must not exceed $2^{31}-1$; my choice -was: -\everb|@ -\def\coeff #1% -{\xintiRound {22}{1/\xintiiSqr{\xintiiMul{\the\numexpr 2*#1-3\relax} - {\the\numexpr 2*#1+3\relax}}[0]}} -| +\item +We denote the empty set \dtt{$\emptyset$} by \emph{nil}. There is +actually a built-in variable with this name. At |1.4|, |\xintexpr\relax| is +legal\NewWith{1.4} and also generates the \emph{nil}. -\restoreMacroFont -\edef\Temp {\xintFloatPow [24]{2}{999999999}} - -\item {Computation of $2^{\np{999999999}}$ with |24| significant - figures:} -% -\leftedline{|\numprint{\xintFloatPow [24]{2}{999999999}}|} -\leftedline{\dtt{\numprint{\Temp}}} -% -where the \href{https://ctan.org/pkg/numprint}{numprint} package was used -(\autoref{fn:np}), directly in text mode (it can also naturally be used from -inside math mode). \xintname provides a simple-minded \csbxint{Frac} -typesetting macro,% -% -\footnote{Plain \TeX{} users of \xintname have \csbxint{FwOver}.} -% -which is math-mode only: -% -\leftedline{|$\xintFrac{\xintFloatPow [24]{2}{999999999}}$|} -\leftedline{\dtt{$\xintFrac{\Temp}$}} -% -The exponent differs, but this is because -|\xintFrac| does not use a decimal mark in the significand of the output. -Admittedly most users will have the need of more powerful (and customizable) -number formatting macros than |\xintFrac|. -% -\footnote{There should be a |\xintFloatFrac|, but it is lacking.} -% -We have already mentioned -|\numprint| which is used above, there is also |\num| from package -\href{https://ctan.org/pkg/siunitx}{siunitx}. The raw output from -% -\leftedline{\detokenize{\xintFloatPow[24]{2}{999999999}}} -% -is $\Temp$. +\item +Concatenation is represented in the syntax by the +comma. Thus repeated commas are like only one and |nil| is a neutral element. -\edef\x{\xintiiQuo{\xintiiPow {2}{1000}}{\xintiiFac{100}}} -\edef\y{\xintLen{\x}} +\item +A singleton \emph{ople} \dtt{\{atom\}} whose single element is an atom +is called a \emph{number}. -\item As an example of nesting package macros, let us consider the following -code snippet within a file with filename |myfile.tex|: -\everb|@ -\newwrite\outstream -\immediate\openout\outstream \jobname-out\relax -\immediate\write\outstream {\xintiiQuo{\xintiiPow{2}{1000}}{\xintiiFac{100}}} -% \immediate\closeout\outstream -| -\noindent -The tex run creates a file |myfile-out.tex|, and then writes to it the -quotient from the Euclidean division of $2^{1000}$ by $100!$. The number of -digits is |\xintLen{\xintiiQuo{\xintiiPow{2}{1000}}{\xintiiFac{100}}}| which -expands (in two steps) and tells us that $[2^{1000}/100!]$ has \dtt{\y} -digits. This is not so many, let us print them here: -\dtt{\printnumber\x}.% +\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). +\item +A braced \emph{ople} is called a \emph{nut-ple}. Among them $\{nil\}$ is a bit +special. It is called the \emph{not-ple}. It is not |nil|! \end{itemize} -\subsection {More examples within this document} -\label{sec:awesome} +It is perhaps important to reflect on the following: +\noindent The notation |3,5,7| can +be seen in two distinct but related ways: \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}. +\item each one of |3|, |5|, |7| is an \emph{ople} (singleton) and |3,5,7| is their \emph{union} or rather \emph{concatenation} (order matters), +\item or each one of |3|, |5|, |7| refers to an \emph{atom} and |3,5,7| is an + enumeration of the atoms of the \emph{ople} it represents. +\end{itemize} +The second view is tempting, but recall that really the comma stands for +\emph{concatenation of totally ordered sets}, thus the first view is more +correct. This first view maps to \TeX{} notations where the value |3| is +stored as \dtt{\{\{3\}\}}. But under \csbxint{verbosetrue} regime, the +external brace pair, which is both a \TeX{} brace pair and a set-theoretical +notation gets removed. There only remains one, and what is shown is actually a +view of an \emph{atom}, where the braces are only \TeX{} braces. But more +complicated nested objects will have \TeX{} braces representing also +set-theoretical braces. If you are still here you can go on reading. + +Each \emph{ople} has a length which is its cardinality. The |oples| of length +1 are called \emph{one-ples}. There are two types of \emph{one-ples}: +\begin{itemize} +\item \emph{numbers}, +\item packed \emph{oples}: the \emph{nut-ples}. \end{itemize} -Almost all of the computational results interspersed throughout the -documentation are not hard-coded in the source file of this document but are -obtained via the expansion of the package macros during the \TeX{} -run.% -% - - - - -\subsection{License and installation instructions} - -\label{ssec:install} - -\xintname is made available under the -\href{http://www.latex-project.org/lppl/lppl-1-3c.txt}{LaTeX Project Public - License 1.3c} and is included in the major \TeX\ distributions, thus there -is probably no need for a custom install: just use the package manager to -update if necessary \xintname to the latest version available. - -The |README| files on \href{https://ctan.org/pkg/xint}{CTAN} explain how to -proceed with a custom installation. -On \TeX\ distributions with a |"texdoc"| or similar utility, -\centeredline{|texdoc --list xint|} -will offer to display one of those files: +As said before the \emph{not-ple} |{{}}| is special. It can be input as +|[]|. Recall that a \emph{number} as an \emph{ople} is a singleton whose sole +element is an \emph{atom}. It is convenient to put the empty set |nil| on the +same footing as \emph{atoms}. Then the \emph{not-ple} is analogous to an +\emph{empty number}. + +We say that the empty set |nil| and \emph{atoms} are \emph{leaves}. Indeed, we +can associate with any \emph{ople} a tree. The root is the ople. In the case +of the |nil|, there is nothing else than the root, which we then consider also +a \emph{leaf}. Else the children at top level are the successive items of the +ople. Among the items some are \emph{atoms} giving \emph{leaves} of the tree, +others are \emph{nut-ples} which in turn have children. In the special case of +the \emph{not-ple} we consider it has a child, which is the empty set and this +why we consider the empty set |nil| a \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. + +Considering the empty set as an \emph{atom} 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} $\{\{\}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*} + +«Set-theoretical» slicing of an \emph{ople} means replacing it by a +subset. 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{not-ple} can only be sliced to give itself or the +empty set. And more generally a \emph{nut-ple} is a singleton so also can only +be set-sliced to either the empty set or itself. + +\xintexprname extends «Python-like» slicing to act on \emph{oples}: \begin{itemize}[nosep] -\item |xint.pdf| (this file), -\item |sourcexint.pdf| (source code), -\item |README|, |README.pdf|, |README.html|, -\item |CHANGES.pdf|, and |CHANGES.html|. +\item if they are not \emph{nut-ples} set-theoretical slicing applies, +\item if they are \emph{nut-ples} (only case having a one-to-one + correspondance in Python) then the slicing happens \emph{within brackets}: + i.e. the \emph{nut-ple} is unpacked then the set-theoretical slicing is + applied, then the result is \emph{repacked} to produce a new \emph{nut-ple}. \end{itemize} +With these conventions the \emph{not-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{not-ple}. Slicing a general +\emph{nut-ple} returns a \emph{nut-ple} but now of course in general distinct +from the first one. + +The 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. + +«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 «Python-like» indexing to act on \emph{oples}: +\begin{itemize}[nosep] +\item if they are not \emph{nut-ples} set-theoretical item indexing applies, +\item if they are \emph{nut-ples} (only case having a one-to-one + correspondance in Python) then the meaning becomes \emph{extracting}: i.e. + the \emph{nut-ple} 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{not-ple} we always obtain +the |nil|. Whereas as we saw slicing the \emph{not-ple} always gives back the +\emph{not-ple}. Indexing is denoted in the syntax by postfixing by |[N]|. Thus +for \emph{nut-ples} (which are analogous to Python objects), there is genuine +diffence 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. + + +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 |nut-ple|. The +first slicer gives back a new |nut-ple|. The second slicer will be applied to +each of one of its remaining items. 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 items: such +items are necessarily |nut-ples|. 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 |nut-ple|. It is thus unpacked and replaced by the +selected item. This item may be an atom or the empty set and any further +slicer or extractor will remove them, or it is a |nut-ple| 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{nut-ple}. We +simply apply the first step as has been described previously and successive +steps will only get applied to either \emph{nut-ples} or \emph{leaves}, the +latter getting silently removed by any attempted operation. + +One last thing. In the syntax of \xintexprname, variables as well as functions +have a name and a value. The value is an |ople|. We can always use a variable +whose value is an |ople| +in a function call, it will occupy the place of as many arguments as its +length indicates. But in a function declaration, the variables must stand for +|one-ples|, i.e. either |numbers| or |nut-ples|. + +The |*| unpacks a +|nut-ple|. The last positional argument in a function declaration can have a +special form |*|\meta{name}. This means that \meta{name} is a |nut-ple| which +receives as items all arguments in the function call beyond the first ones +corresponding to the function declaration. -% For manual installation, follow the instructions from the |README| file which -% is to be found on \href{https://ctan.org/pkg/xint}{CTAN}; it is also -% available there in PDF and HTML formats. The simplest method proposed is to -% use the archive file \href{https://ctan.org/pkg/xint}{xint.tds.zip}, -% downloadable from the same location. - -% The next simplest one is to make use of the |Makefile|, which is also -% downloadable from -% \href{http://mirrors.ctan.org/macros/generic/xint}{CTAN}. This is -% for GNU/Linux systems and Mac OS X, and necessitates use of the command -% line. If for some reason you have |xint.dtx| but no internet access, -% you can recreate |Makefile| as a file with this name and the following -% contents: - -% {\def\everbatimindent {0pt }% -% \begin{everbatim} -% include Makefile.mk -% Makefile.mk: xint.dtx ; etex xint.dtx -% \end{everbatim}} - -% Then run |make| in a working repertory where there is |xint.dtx| and the file -% named |Makefile| and having only the two lines above. The |make| will extract -% the package files from |xint.dtx| and display some further instructions. - -% If you have |xint.dtx|, no internet access and can not use the Makefile -% method: |etex xint.dtx| extracts all files and among them the |README| as a -% file with name |README.md|. Further help and options will be found therein. - -\subsection {Recent changes} - -This is release \expandafter|\xintbndlversion| of \expandafter|\xintbndldate|. +\medskip -For more information see -|CHANGES.html|.\centeredline{Internet: - \url{http://mirrors.ctan.org/macros/generic/xint/CHANGES.html}} +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 «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}. -The formatted source code is available in file |sourcexint.pdf|: -\centeredline{|texdoc sourcexint|} +Numbers may be called the \emph{leaves} of the \textbf{input}, but once +converted to a structure in memory, the input becomes an \emph{ople} which is +(morally) a tree whose leaves are \emph{atoms} (and the empty set). -\noindent\expandafter|\xintbndlversion| (\expandafter|\xintbndldate|): -\begin{itemize}[nosep] -\item Fix bug preventing usage of \csbxint{defefunc} - to define a function with no variables. -\item Fix bug with usage of |\xintfloatexpr[D]..\relax| inside the parsed - expression for \csbxint{deffunc} and variants. -\item Revert |1.3e| ban on usage of \csbxint{eval} et al. inside a function - definition via \csbxint{deffunc} and variants. -\item Macro definitions via \csbxint{NewExpr} now also allow \csbxint{eval} et - al. within them. -\item Add \csbxint{Digits}|=P;| syntax with no colon. -\item Document that the ending semi-colon in \csbxint{Digits}|:=P;| must not - be active, and that it has always been allowed to use any non-expanding - token such as a dot or a |\relax| in its place. -\item Add \csbxint{SetDigits} user interface. -\item Add \csbxint{Digits*}|:=P;| and \csbxint{SetDigits*}|{P}| variants - which execute \csbxint{reloadxinttrig}. -\end{itemize} +\medskip +I hope this is clear to everyone. If not, maybe time to say this section was +absolutely not needed to understand the rest of the manual, but I needed to +write it for my own satisfaction. Believe me, you need this section if you +want to write the underlying software! -\noindent|1.3e| (|2019/04/05|): -\begin{itemize}[nosep] -\item An \xinttrigname library is automatically loaded by \xintexprname and - provides direct and inverse trigonometrical functions using either degrees - or radians (up to \dtt{60} digits). It is for the most part implemented - using high level user interface, but will probably get some optimizations in - future (and perhaps extension to more digits). -\item An \xintlogname library is loaded automatically; it uses - \href{http://ctan.org/pkg/poormanlog}{poormanlog} to provide logarithms and - exponentials. Support for more digits is planned for the future: the - \href{http://ctan.org/pkg/poormanlog}{poormanlog} support achieves only - about \dtt{8} or \dtt{9} digits of precision. On the other hand the - functions are fast. - Perhaps we will keep the current functions achieving limited precision under - some other names in future (they are amply precise enough for plots). -\item Under the hood refactoring of \csbxint{NewExpr} related matters for - support of user-defined functions; fixed bugs related to functions with no - variables. Added \csbxint{defefunc}, \csbxint{deffloatefunc}, - \csbxint{defiiefunc} and documented the ``protected'' nature of the - functions defined by the original variants \csbxint{deffunc} et al. This - whole area is complex and to be still considered work in progress. -\item Breaking change (\emph{which got reverted at - \texttt{1.3f}}):\CHANGED{1.3f} - only the - \csbxint{expr}|...\relax| syntax is accepted for sub-expressions when doing - function definitions via \csbxint{deffunc} and \csbxint{defefunc} et al. One - can not use \csbxint{eval}, \csbxint{ieval}, \csbxint{floateval} inside such - definitions. -\item \func{inv}, \func{ilog10}. -\item \func{sfloat}, slight modification of behaviour of \func{qfloat}. -\item \csbxint{ensuredummy}, \csbxint{restorelettervar}. -\item the optional argument of \csbxint{floatexpr} can be negative, it then - tells to round the result to a (rounded) float with a precision equal to - \csbxint{theDigits} diminished by this argument. -\end{itemize} +\clearpage +\let\xintexprnameUp\undefined +\csname Syntax referencenameUp\endcsname +\section{\xintexprname syntax reference and user guide} +\RaisedLabel{sec:xintexprsyntax} -% \noindent|1.3d| (|2019/01/06|): -% \begin{itemize}[nosep] -% \item \func{gcd} and \func{lcm} in \csbxint{expr}|...\relax| now handle -% general arguments, without converting them to integers, -% \item It is not needed anymore to load package \xintgcdname to benefit from -% \func{gcd} and \func{lcm} in the parsers. -% \item \csbxint{ifsgnexpr}, \csbxint{ifsgnfloatexpr}, \csbxint{ifsgniiexpr}. -% \item \csbxint{unassignexprfunc} and variants for the other parsers. -% \item \func{isone} and \func{isint}. -% \item \csbxint{eval}, \csbxint{ieval}, \csbxint{iieval}, and -% \csbxint{floateval}. Attention: these names were formerly used with some other -% (barely documented) meanings, for which |\xintexpro|, |\xintiexpro|, -% etc... are now used. -% \item Sadly, in \csbxint{iiexpr}|...\relax| division with a zero dividend and -% a one-digit divisor got broken at |1.2p|. Fixed. Thanks to \textsc{Kpym} for -% report. Sorry for long delay in releasing the bugfix, which was done shortly -% after |1.3c| release. -% \end{itemize} +\localtableofcontents -\section{The syntax of \xintexprname expressions} -\label{sec:xintexprsyntax} +\subsection{The three parsers} -\localtableofcontents +\xintexprname provides three numerical expression parsers and two subsidiary +ones. They are designed to be compatible with expansion only context; in +particular they can be nested arbitrarily one within the other, modifying on +the fly the context for computations (for such things, please use the core +syntax \csbxint{expr}|...\relax| as commented upon later on). -\subsection{The three parsers}\label{ssec:threeparsers} +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 are three expression parsers and two subsidiary ones. They -all admit comma separated expressions, and will then output a comma -separated list of results. -\begin{itemize}[nosep] -\item \csbxint{theiiexpr}| ... \relax| does exact computations \emph{only on - integers.} The forward slash \dtt{/} does the \emph{rounded} integer - division to match behaviour of |\the\numexpr - <int>/<int>\relax|.\footnote{For floored integer division, see the \dtt{//} - operator.} There are two square root extractors \func{sqrt} and - \func{sqrtr} for truncated and rounded square roots. Scientific notation - |6.02e23| is \emph{not} accepted on input, one needs to wrap it as - |num(6.02e23)| which will convert to an integer notation - \dtt{\printnumber{\xinttheiiexpr num(6.02e23)\relax}}. -\item \csbxint{thefloatexpr}| ... \relax| does computations with a given - precision \dtt{P}, as specified via a prior assignment |\xintDigits:=P\relax |. - The default is \dtt{P=16} digits. An optional argument controls the - precision for \emph{formatting the output} (this is not the precision of the - computations themselves). The four basic operations and the square root - realize \emph{correct rounding.}\footnote{when the inputs are already - floating point numbers with at most |P|-digits mantissas.} -\item \csbxint{theexpr}| ... \relax| handles integers, decimal numbers, +\begin{itemize} +\item \csbxint{eval}\marg{expression} handles integers, decimal numbers, numbers in scientific notation and fractions. The algebraic computations are - done \emph{exactly.} The \func{sqrt} function is available and obeys - either the |\xintDigits| precision or its second optional - argument. + done \emph{exactly.} +\item \csbxint{iieval}\marg{expression} does exact computations \emph{on (big) + integers only.} The forward slash \dtt{/} does the \emph{rounded} integer + division to match behaviour of |\numexpr|. +\item \csbxint{floateval}\marg{expression} does floating point computations + with a given precision \dtt{P}, as specified via a prior assignment + |\xintDigits:=P\relax |. The default is \dtt{P=16} digits. The four basic + operations and the square root realize \emph{correct + rounding.}\footnote{when the inputs are already floating point numbers + with at most |P|-digits mantissas.} + + It can be used with an optional argument |[Q]| and then do a float rounding + to mantissas of |Q| digits as the final step (this makes sense only if + |Q<P|). ATTENTION: the optional argument + |[Q]| is to be located \emph{within} the braces at the start of the expression. \end{itemize} Two derived parsers: -\begin{itemize}[nosep] -\item \csbxint{theiexpr}| ... \relax| does all computations like |\xinttheexpr - ... \relax| but rounds the result to the nearest integer. With an optional +\begin{itemize} +\item \csbxint{ieval}\marg{expression} does all computations like \csbxint{eval} + but rounds the result to the nearest integer. If there is an optional positive argument |[D]|, the rounding is to the nearest fixed point number - with |D| digits after the decimal mark. -\item \csbxint{theboolexpr}| ... \relax| does all computations like - |\xinttheexpr ... \relax| but converts the result to $1$ if it is not zero - (works also on comma separated expressions). - See also the booleans \csbxint{ifboolexpr}, \csbxint{ifbooliiexpr}, - \csbxint{ifboolfloatexpr}, \csbxint{ifsgnexpr}, \csbxint{ifsgniiexpr}, - \csbxint{ifsgnfloatexpr} (they do not handle comma separated expressions). + with |D| digits after the decimal mark. ATTENTION: the optional argument + |[D]| is to be located \emph{within} the braces at the start of the expression. +\item \csbxint{theboolexpr}\meta{expression}|\relax| does all computations like \csbxint{eval} + but converts the (itemwise) results to |True| or |False|. This + is configurable. There is no |\xintbooleval|. \end{itemize} -Release |1.3d| provides \csbxint{eval}, \csbxint{ieval}, -\NewWith{1.3d} -\csbxint{iieval}, \csbxint{floateval}. +These macros are wrappers for a more core syntax: +\begin{itemize}[nosep] + \item \csbxint{expr}\meta{expression}|\relax|, + \item \csbxint{iiexpr}\meta{expression}|\relax|, + \item \csbxint{floatexpr}\meta{expression}|\relax|, + \item \csbxint{iexpr}\meta{expression}|\relax|, + \item \csbxint{boolexpr}\meta{expression}|\relax|. +\end{itemize} +This core syntax can be used directly in typesetting flow. But in an |\edef| they +expand to some braced nested data prefixed with some non-expandable +«typesetting» macros. When using \csbxint{eval} in an |\edef|, the +\csa{XINTexprprint} typesetter is activated and the expansion gives explicit +digits and other characters such as those of scientific notation or +brackets. + +It is possible to use the core syntax +\csbxint{expr}\marg{expression}|\relax| also in so-called moving arguments, +because when written out to a file they use only standard catcodes and the +output will get retokenized and will expand as expected. + +One needs \csbxint{eval} et al. only if one really wants the final characters +of the typeset result. + +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}. + +Notice that in this documentation I will most of the time refer to +\csbxint{eval} and \csbxint{expr}. But beware that 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}. + +A word of warning on the bracketed optional argument of respectively +\csbxint{floatexpr} and \csbxint{iexpr}. If defining macros handing over an +argument to one of these two parsers, the argument may accidentally start with +a left square bracket |[| and this will break the parser. The fix is to use in +the macro definition |\xintfloatexpr\empty| for example. The extra |\empty| +token will prevent the parser thinking there is an optional argument and it +will then disappear during expansion. + +With \csbxint{thealign} one can get nested data use a \TeX{} alignment in the +output. Attention, this must be followed by \csbxint{expr} et al., never by +\csbxint{theexpr} or \csbxint{eval}. +Here is an example : +\begin{everbatim*} +\xintthealign\xintexpr ndseq(1/(i+j), i = 1..10; j=1..10)\relax +\end{everbatim*} + +\subsection{\csh{xintthealign} and output related customizations} +\label{xintthealign} +\label{xintexprEmptyItem} +\label{xintexprPrintOne} +\label{xintiiexprPrintOne} +\label{xintfloatexprPrintOne} +\label{xintboolexprPrintOne} + + +This is hopefully more or less self-explanatory: +\begin{everbatim} +\def\xintexprEmptyItem{[]} +% this is a macro from xintfrac.sty, must understand its raw format +\let\xintexprPrintOne\xintFracToSci +\def\xintiiexprPrintOne #1{#1} +% this is a macro from xintfrac.sty, must understand its raw format +\def\xintfloatexprPrintOne#1#2{\xintPFloat[#1]{#2}} +\def\xintboolexprPrintOne#1{\xintiiifNotZero{#1}{True}{False}} +% The package uses \protected here for no strong reason, but why not +\protected\def\xintexpralignbegin {\halign\bgroup\tabskip2ex\hfil##&&##\hfil\cr}% +\protected\def\xintexpralignend {\crcr\egroup}% +\protected\def\xintexpraligncr {\cr}% +\protected\def\xintexpralignleftbracket {[}% +\protected\def\xintexpralignrightbracket{]}% +\protected\def\xintexpraligninnercomma {,}% +\protected\def\xintexpralignoutercomma {,}% +\protected\def\xintexpraligntab {&}% +% Use for example this for outputting to a file. Better then without \protected. +% We assume here \newlinechar has the LaTeX setting. +\def\xintexpralignbegin {}% +\def\xintexpralignend {}% +\def\xintexpraligncr {^^J}% +\def\xintexpralignleftbracket {[}% +\def\xintexpralignrightbracket{]}% +\def\xintexpraligninnercomma {,}% +\def\xintexpralignoutercomma {,}% +\def\xintexpraligntab { }% +\end{everbatim} \subsection{Built-in operators and their precedences} @@ -4626,43 +4346,47 @@ Release |1.3d| provides \csbxint{eval}, \csbxint{ieval}, \hyperref[ssec:builtinfunctions]{built-in} or \hyperref[ssec:userfunctions]{user-defined} functions, \item \hyperref[ssec:uservariables]{variables}, + \item the |*| unpacking operator, \item and the intrinsic constituents of numbers: decimal mark |.|, |e| and |E| of scientific notation, hexadecimal prefix |"|. \end{itemize}\par\kern-\baselineskip\relax}% \\\hline\hline Precedence&``Operators'' at this level\strut\\ \hline - \prec{$10$}& the factorial (postfix) operator |!| and the conditional branching operators |?| and |??|\strut\\\hline + \prec{$20$}& the factorial (postfix) operator |!| and the conditional branching operators |?| and |??|\strut\\\hline \prec{$=$}& the minus sign |-| as unary operator acquires the precedence level of the previous infix operator\strut\\\hline - \prec{$9$}&the power |^|, |**| operators\strut\\\hline - \prec{$8$}&the action of tacit multiplication\strut\\\hline - \prec{$7$}&the multiplication, division, and modulo operators |*|, |/|, + \prec{$18$}&the power |^|, |**| operators\strut\\\hline + \prec{$16$}&the action of tacit multiplication\strut\\\hline + \prec{$14$}&the multiplication, division, and modulo operators |*|, |/|, |//|, |/:| (aka |'mod'|)\strut \\\hline - \prec{$6$}&the addition and subtraction |+|, |-|\strut\\\hline - \prec{$5$}&the comparison operators |<|, |>|, |==|, |<=|, |>=|, |!=|\strut\\\hline - \prec{$4$}&Boolean conjunction |&&| and its alias |'and'|\strut\\\hline - \prec{$3$}&Boolean disjunction \verb+||+ and |'or'|, and |'xor'|; also the + \prec{$12$}&the addition and subtraction |+|, |-|\strut\\\hline + \prec{$10$}&the comparison operators |<|, |>|, |==|, |<=|, |>=|, |!=|\strut\\\hline + \prec{$8$}&Boolean conjunction |&&| and its alias |'and'|\strut\\\hline + \prec{$6$}&Boolean disjunction \verb+||+ and |'or'|, and |'xor'|; also the sequence generators |..|, |..[|, |]..|, and the Python slicer |:| have this precedence\strut\\\hline - \prec{$2$}& the comma |,|\strut\\\hline - \prec{$1$}& the parentheses |(|, |)|, list brackets |[|, |]|, semi-colon |;| in an \func{iter} or - \func{rseq}\strut\\\hline\hline + \prec{$4$}& the brackets for |NumPy| slicing syntax |[|, |]|\strut\\\hline + \prec{$3$}& the comma |,|\strut\\\hline + \prec{$2$}& the bracketers |[|, |]|\strut\\\hline + \prec{$1$}& the parentheses |(|, |)|, and the semi-colon |;| in the + \func{iter}, + \func{rseq}, etc... constructs\strut\\\hline\hline \multicolumn{2}{|p{.6\textwidth}|}{% \begin{itemize}[nosep] + \item Actually operators have a left and a right precedence, which for + most coincide. But for some there is a crucial distinction. The above + table is indicative, see |sourcexint.pdf|. Roughly all precedence levels + were doubled at |1.4| to make room. \item In case of equal precedence, the rule is left-associativity: the first encountered operation is executed first. \hyperref[ssec:tacit multiplication]{Tacit multiplication} has an elevated precedence level hence seemingly breaks left-associativity: |(1+2)/(3+4)5| is computed as |(1+2)/((3+4)*5)| and |x/2y| is interpreted as |x/(2*y)| when using variables. - \item List variants |^[|, |**[|, |]^|, |]**|, - |*[|, |/[|, |]*|, |]/|, |+[|, |-[|, |]+|, |]-|, share the precedence - level of their respective associated operators on numbers. - \item There may - be some evolution in future, perhaps to distinguish some of the constructs - which currently share the same precedence or to make room for added syntax - elements. + % \item List variants |^[|, |**[|, |]^|, |]**|, + % |*[|, |/[|, |]*|, |]/|, |+[|, |-[|, |]+|, |]-|, share the precedence + % level of their respective associated operators on numbers. \end{itemize} }\\\hline \end{tabular} @@ -4691,13 +4415,16 @@ at each level. must be used with parentheses. These parentheses may arise from expansion after the function name is parsed (there are exceptions which are documented at the relevant locations.) +\item The |*| as Python-like «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, \item the |.| as decimal mark; the number scanner treats it as an inherent, optional and unique component of a being formed number. One can do things such as % - \leftedline{\restoreMicroFont|\xinttheexpr 0.^2+2^.0\relax|} + \leftedline{\restoreMicroFont|\xintexpr 0.^2+2^.0\relax|} % - which is |0^2+2^0| and produces \dtt{\xinttheexpr 0.^2+2^.0\relax}. + which is |0^2+2^0| and produces \dtt{\xintexpr 0.^2+2^.0\relax}. Since release |1.2| an isolated decimal mark |"."| is illegal input in |\xintexpr..\relax|, although it remains legal as argument to the @@ -4720,7 +4447,7 @@ at each level. \end{everbatim*} \end{itemize} -\precdesc{10} The postfix operators |!| and the branching conditionals |?|, |??|. +\precdesc{20} The postfix operators |!| and the branching conditionals |?|, |??|. \begin{description}[parsep=0pt,align=left,itemindent=0pt, leftmargin=\leftmarginii, labelwidth=\leftmarginii, labelsep=0pt, labelindent=0pt, listparindent=\leftmarginiii] @@ -4774,16 +4501,14 @@ at each level. - \precdesc{9} The power operator |^|, or equivalently |**|. It is left + \precdesc{18} The power operator |^|, or equivalently |**|. It is left associative: {\restoreMicroFont|\xinttheiexpr 2^2^3\relax|} evaluates to \xinttheiexpr 2^2^3\relax, not \xinttheiexpr 2^(2^3)\relax. See \csbxint{FloatPower} for additional information. - Also at this level the list operators |^[|, |**[|, |]^|, and |]**|. - -\precdesc{8} see \hyperref[ssec:tacit multiplication]{Tacit multiplication}. +\precdesc{16} see \hyperref[ssec:tacit multiplication]{Tacit multiplication}. -\precdesc{7} Multiplication and division |*|, |/|. The +\precdesc{14} Multiplication and division |*|, |/|. The division is left associative, too: % \begingroup\restoreMicroFont @@ -4810,7 +4535,7 @@ at each level. trunc(100000/:13/13,10)\relax \end{everbatim*} -\precdesc{6} Addition and subtraction |+|, |-|. According to the rule above, |-| +\precdesc{12} Addition and subtraction |+|, |-|. According to the rule above, |-| is left associative: % \begingroup\restoreMicroFont @@ -4822,10 +4547,10 @@ at each level. Also the list operators |+[|, |-[|, |]+|, |]-| are at this precedence level. -\precdesc{5} Comparison operators |<|, |>|, |=| (same as |==|), |<=|, |>=|, |!=| all +\precdesc{10} Comparison operators |<|, |>|, |==|, |<=|, |>=|, |!=| all at the same level of precedence, use parentheses for disambiguation. -\precdesc{4} Conjunction (logical and) |&&| or equivalently +\precdesc{8} Conjunction (logical and) |&&| or equivalently |'and'| (quotes mandatory).% % \footnote{with releases earlier than |1.1|, only single @@ -4834,25 +4559,26 @@ at each level. deprecated,\IMPORTANT{} and they may be assigned some new meaning in the future.} -\precdesc{3} Inclusive disjunction (logical or) \verb+||+ +\precdesc{6} Inclusive disjunction (logical or) \verb+||+ and equivalently |'or'| (quotes mandatory). Also the |'xor'| operator (quotes mandatory) is at this level. Also the list generation operators |..|, |..[|, |]..| are at this level. - Also the |:| for Python slicing of lists. + Also the |:| for Python/NumPy nested slicing of nested lists. -\precdesc{2} The comma: {\restoreMicroFont with |\xinttheexpr 2^3,3^4,5^6\relax| +\precdesc{4} The square brackets as involved in NumPy like slicing. The step +is not implemented yet. +\precdesc{3} The comma: {\restoreMicroFont with |\xinttheexpr 2^3,3^4,5^6\relax| one obtains as output \xinttheexpr 2^3,3^4,5^6\relax{}.}\footnote{The comma is really like a binary operator, which may be called ``join''. It has lowest precedence of all (apart the parentheses) because when it is encountered all postponed operations are executed in order to finalize its \emph{first} operand; only a new comma or a closing parenthesis or the end of the expression will finalize its \emph{second} operand.} - -\precdesc{1} The parentheses. The list outer brackets |[|, |]| share the same - functional precedence as parentheses. The semi-colon |;| in an |iter| or +\precdesc{2} The square brackets as |nut-ple| constructors. +\precdesc{1} The parentheses. The semi-colon |;| in an |iter| or |rseq| has the same precedence as a closing parenthesis.\footnote{It is not apt to describle the opening parenthesis as an operator, but the closing parenthesis is more closely like a postfix unary operator. It has lowest @@ -4884,31 +4610,37 @@ atan2, atan2d, binomial, bool, ceil, cos, cosd, cot, cotd, cotg, csc, cscd, divmod, even, exp, -factorial, first, float, floor, frac, gcd, +factorial, first, float, float\string_, floor, frac, gcd, if, ifint, ifone, ifsgn, ilog10, isint, isone, iter, iterr, inv, -last, lcm, len, log, log10, max, min, mod, mul, not, num, odd, +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, quo, -random, randrange, reduce, rem, reversed, round, rrseq, rseq, -sec, secd, seq, sgn, sin, sinc, sind, sqr, sqrt, sqrtr, subs, -tan, tand, tg, togl, trunc, +random, randrange, rbit, reduce, rem, reversed, round, rrseq, rseq, +sec, secd, seq, sgn, sin, sinc, sind, sqr, sqrt, sqrtr, +subs, subsm, subsn, +tan, tand, tg, togl, trunc, unpack, xor} \to\Functions \cnta\Functions{0} - \cntb\xinttheexpr ceil(\cnta/4)\relax\space + \cntb\xinttheexpr ceil(\cnta/7)\relax\space \newcommand\builtinfunction[1]{\expandafter\expandafter\expandafter\func \expandafter\expandafter\expandafter{\Functions{#1}}}% -\begin{tabular}{|*{4}{p{2.5cm}|}} +\centeredline{\begin{tabular}{|*{7}{p{2cm}|}} \hline \xintFor* #1 in {\xintSeq{1}{\cntb}}\do {\builtinfunction{#1}& \builtinfunction{#1+\cntb}&% \builtinfunction{#1+2*\cntb}&% - \ifnumgreater{#1+3*\cntb}{\cnta} + \builtinfunction{#1+3*\cntb}&% + \builtinfunction{#1+4*\cntb}&% + \builtinfunction{#1+5*\cntb}&% + \ifnumgreater{#1+6*\cntb}{\cnta} {} - {\builtinfunction{#1+3*\cntb}}% + {\builtinfunction{#1+6*\cntb}}% \\\hline}% -\end{tabular} +\end{tabular}} \caption{Functions (click on names)}\label{tab:functions} \etoctoccontentsline {table}{\textbf{(table)} \protect\emph{Functions in expressions}} \etocsetnexttocdepth{subsubsection} @@ -4918,7 +4650,7 @@ xor} Miscellaneous notes: \begin{itemize}[nosep] - \item since release |1.3d| \func{gcd}\NewWith{1.3d} and \func{lcm} are extended to apply + \item since release |1.3d| \func{gcd} and \func{lcm} are extended to apply to fractions too, and they do NOT require the loading of \xintgcdname, \item The randomness related functions \func{random}, \func{qrand} and @@ -4936,18 +4668,18 @@ Miscellaneous notes: \item Also \hyperlink{ssec:dummies}{functions with dummy variables} use delimited macros for some tasks. See the relevant explanations there. -\end{itemize} + \item A more prominent distinction should be made between built-in \emph{regular} and + \emph{pseudo} functions. But this documentation needs to be revamped at + a later time. + + \item Functions may be called with \emph{oples} as arguments as long as + the total length is the number of arguments the function expects. + + \item Some descriptions may be obsolete to various degree due to changes + at 1.4. +\end{itemize} -% \begin{description}[parsep=0pt,align=left, -% leftmargin=0pt, itemindent=0pt, -% labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, -% %! leftmargin+itemindent="labelindent"+labelwidth+labelsep -% %! leftmargin=labelindent+labelwidth+labelsep* (enumitem) -% %! Utiliser \mbox{} et non pas \noindent\par pour bon display -% %! (enfin c'était nécessaire avant chgt dans keys ci-dessus, ai oublié ancien -% %! attention que listparindent n'est apparemment pas hérité, faut le refaire -% listparindent=\leftmarginiii] \subsubsection{Functions with no argument} \begin{description} @@ -4959,7 +4691,7 @@ Miscellaneous notes: \funcdesc[]{random} returns a random float |x| verifying |0 <= x < 1|. It obeys the prevailing precision as set by \csbxint{Digits}: i.e. with |P| being the precision the random float multiplied by |10^P| is an integer, uniformly - distributed in the |0..10^P-1| range.\NewWith{1.3b} + 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| @@ -4973,19 +4705,10 @@ Miscellaneous notes: \xintthefloatexpr random()\relax\par \end{everbatim*} - \begin{framed} - Due to the way \csbxint{expr}|...\relax| are handled (see - \autoref{ssec:memory}), Monte-Carlo type simulations using expressions may - relatively easily exhaust \TeX{} memory.\IMPORTANT\ If possible use - \csbxint{NewFloatExpr} to construct from such expressions involving the - \func{random} function macros not creating the memory impact which is - described in \autoref{ssec:memory}. - \end{framed} - \funcdesc[]{qrand} returns a random float |0 <= x < 1| using \dtt{16} digits of precision (i.e. |10^{16}x| is an integer). This is provided when speed is a at premium as it is optimized for precision being precisely \dtt{16}.% - \NewWith{1.3b} + \begin{everbatim*} % still with 37 digits as prevailing float precision \xintthefloatexpr qrand(), random()\relax\newline @@ -5014,9 +4737,11 @@ Miscellaneous notes: }% \end{everbatim*} + \funcdesc[]{rbit} returns a random |0| or |1|.\NewWith{1.4} + \end{description} -\subsubsection{Functions with a single (numeric) argument} +\subsubsection{Functions with one argument} \begin{description} % [parsep=0pt,align=left, @@ -5062,13 +4787,13 @@ Recall that this is NOT done automatically, for example when adding fractions. \funcdesc{abs} absolute value \funcdesc{sgn} sign. See also \csbxint{ifsgnexpr}. - \funcdesc{inv} inverse.\NewWith{1.3e} + \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}$;\NewWith{1.3e} returns (this may evolve in future) + \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 @@ -5096,13 +4821,13 @@ Recall that this is NOT done automatically, for example when adding fractions. \end{everbatim*} \funcdesc{isint} evaluates to 1 if |x| is an integer, to 0 if - not.\NewWith{1.3d} See \func{ifint}. + 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.\NewWith{1.3d} + \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 @@ -5110,7 +4835,7 @@ $\xintthefloatexpr subs(((x-1)/x, x/x, (x+1)/x), x=2**30)\relax \xintthefloatexpr seq(isone(y), y=subs(((x-1)/x, x/x, (x+1)/x), x=2**30))\relax$ \end{everbatim*} - \funcdesc{qint} belong with \func{qfrac}, \func{qfloat}, \func{qraw} to a + \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 @@ -5142,7 +4867,7 @@ $\xintthefloatexpr subs(((x-1)/x, x/x, (x+1)/x), x=2**30)\relax \xinttheiiexpr qint(\x)*qint(\y)+qint(\y)^2\relax\par \end{everbatim} - \funcdesc{qfrac} does the same as \dtt{qint} excepts that it accepts + \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 @@ -5174,10 +4899,27 @@ $\xintthefloatexpr subs(((x-1)/x, x/x, (x+1)/x), x=2**30)\relax Note that if the input needs no special rounding, the internal form of the output keeps a short mantissa (it does not add padding zeros to make it of length equal to the float precision). For example |qfloat(2[20])| would - keep internally the input format.\CHANGED{1.3e} + keep internally the input format. + + \funcdesc{float\string_} is like \func{float} but does not accept the latter + second optional argument.\NewWith{1.4} This is provided as a utility to + speed-up things in some contexts, particularly when converting function + definitions done via \csbxint{deffunc} (see explanations there) to + functions usable in \csbxint{floateval}. + + \funcdesc{nuple} (WIP) is currently same as |[...]|. Do not use. Reserved + for possible alternative meaning in future.\NewWith{1.4} +\begin{everbatim*} +\xinteval{nuple(1,2,3)} +\end{everbatim*} + + \funcdesc{unpack} is alternative for |*| unpacking operator.\NewWith{1.4} +\begin{everbatim*} +\xinteval{unpack(nuple(1,2,3))} +\end{everbatim*} \end{description} -\subsubsection{Functions with an alphabetical argument} +\subsubsection{Functions with an alphanumeric argument} \begin{description} % [parsep=0pt,align=left, @@ -5288,7 +5030,7 @@ $\xintthefloatexpr subs(((x-1)/x, x/x, (x+1)/x), x=2**30)\relax these initial steps. To avoid that, use |\xintexpr2^9/3^5\relax| wrapper. Then the rounding or truncation will be applied on the exact fraction. - \funcdesc[{x[, n]}]{sfloat} It is the same as \func{float},\NewWith{1.3e} + \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 @@ -5300,7 +5042,7 @@ $\xintthefloatexpr subs(((x-1)/x, x/x, (x+1)/x), x=2**30)\relax mantissa. \funcdesc[{x[, n]}]{ilog10} If there is an optional argument |n|, returns the (relative) integer $a$ such that $10^a\leq - \mathrm{abs}(float(x, n)) < 10^{a+1}$.\NewWith{1.3e} In absence of the + \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 @@ -5352,7 +5094,7 @@ $\xintthefloatexpr subs(((x-1)/x, x/x, (x+1)/x), x=2**30)\relax integer |0 <= x < A|, and when used with two arguments |A| and |B| returns a random integer |A <= x < B|. As in Python it is an «empty range» error in first case if |A| is zero or negative and in second case if |B <= A|. - \NewWith{1.3b} + Attention that the arguments are first converted to integers using \csbxint{Num} (i.e. truncated towards zero). @@ -5387,21 +5129,21 @@ $\xintthefloatexpr subs(((x-1)/x, x/x, (x+1)/x), x=2**30)\relax computes the Euclidean remainder. Hence it computes an integer. \funcdesc[f, g]{mod} computes |f - g*floor(f/g)|. Hence its output is a - general fraction or floating point number or integer depending on the parser - where it is used. + general fraction or floating point number or integer depending on the + used parser. Prior to |1.2p| it computed |f - g*trunc(f/g)|. The |/:| and |'mod'| infix operators are both mapped to the same underlying macro as this |mod(f, g)| function. At |1.3| this macro produces smaller - denominators when handling fractions than formerly.\CHANGED{1.3} + 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 + 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} @@ -5423,7 +5165,9 @@ mod(11/7,1/13)- (11/7)/:(1/13), (11/7)//(1/13)\relax\newline |divmod| function next. \funcdesc[f, g]{divmod} computes the two mathematical values |floor(f/g)| and - |mod(f,g)=f - g*floor(f/g)| and produces them separated with a comma, in + |mod(f,g)=f - g*floor(f/g)| and produces them as a bracketed + pair\CHANGEDf{1.4} + 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. @@ -5431,7 +5175,8 @@ mod(11/7,1/13)- (11/7)/:(1/13), (11/7)//(1/13)\relax\newline 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|. + 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 @@ -5497,6 +5242,13 @@ The arguments must be (expand to) short integers. The arguments must (expand to) short integers. See \autoref{xintiiPFactorial} for the behaviour if the arguments are negative. +\funcdesc[macro, n-uple]{ndfillraw} (WIP) DO NOT USE.\NewWith{1.4} The second argument is +|[N1, N2, ..., Nk]|. The construct fills an |N1xN2x...xNk| hyperrectangular +nested list by evaluating the |macro| as many times as needed. Useful to generate either +constant or random +arrays. But, attention, |macro| is any \TeX{} macro, if one wants to evaluate +some expression one needs explicitly adding |\xinteval{..}|. Beware spaces or +other things this goes directly into internal data storage. \end{description} \subsubsection{Functions with 3 or 4 arguments} @@ -5517,13 +5269,13 @@ for the behaviour if the arguments are negative. \funcdesc[x,yes,no]{ifint} (twofold-way conditional)\mbox{} checks if |x| is an integer and in that case chooses the ``yes'' branch.% - \NewWith{1.3a} + See also \func{isint}. \funcdesc[x,yes,no]{ifone} (twofold-way conditional)\mbox{} checks if |x| is equal to one and in that case chooses the ``yes'' branch.% - \NewWith{1.3a} + Slightly more efficient than |if(x==1,..,..)|. See also \func{isone}. \funcdesc[cond,<0,=0,>0]{ifsgn} (threefold-way conditional)\mbox{} @@ -5536,8 +5288,18 @@ for the behaviour if the arguments are negative. \subsubsection{Functions with an arbitrary number of arguments} - Except for \func{qraw}, this argument may be generated by one or many - |a..b| or |a..[d]..b| constructs, separated by commas. +At |1.4| functions |all()|, |any()|, |xor()|, |`+`|, |`*`|, |max()|, |min()|, +|gcd()|, |lcm()|, |first()|, |last()|, |reversed()| and |len()| admit: +\begin{itemize} +\item at least two arguments, and then operate as expected in backward + compatible way, +\item or only one argument,\IMPORTANT{} which then \emph{must} be a |nut-ple|, i.e. a + variable or explicit bracketed list. In the case of |reversed()| the output + is a |nut-ple| if the input was one. +\end{itemize} +Notice that this is breaking change as the functions do not work anymore with +a single argument being a number (or give funny non-documented results +depending on internal data representation). \begin{description} % [parsep=0pt,align=left, @@ -5545,54 +5307,66 @@ for the behaviour if the arguments are negative. % labelwidth=-\fontdimen2\font, labelsep=\fontdimen2\font, labelindent=0pt, % listparindent=\leftmarginiii] - \funcdesc[a,b,c,...,z]{qraw} is provided for comma separated values. The - input must obide by the suitable format depending on the - parser:\NewWith{1.3c} strict integers, or raw fractions, or floats in - internal (non-documented) notation. Also, avoid spaces around the commas. - The usefulness is when some loop generates hundreds of comma separated - values. Without \func{qraw}, each new value means a new usage of a - |\csname..\endcsname| for storage of the growing list, with potential - impact on \TeX{} memory (see \autoref{ssec:memory}). See \func{qint}, - \func{qfrac}, \func{qfloat}, the difference being that \func{qraw} does - no post-processing at all of its input, apart from complete expansion. - This allows it to accept comma separated values, as the internal storage - also uses commas. + \funcdesc[stuff]{qraw} DO NOT USE. It allows to inject directly a nested \TeX-braced + list conforming to internal data structures manipulated by the package. Can + break at any release. \funcdesc[x, y, ...]{all} inserts a logical |AND| in-between its arguments and evaluates the -resulting logical assertion (as for all functions, all arguments are -evaluated, see the |?| operator for ``lazy'' conditional branching; an example -is to be found in \autoref{ssec:PrimesIV}.) +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, ...]{|`+`|} adds (left ticks mandatory): \begin{everbatim*} -\xinttheexpr `+`(1,3,19), `+`(1*2,3*4,19*20)\relax +\xinttheexpr `+`(1,3,19), `+`(1**2,3**2,sqr(19)), `+`([1**2,3**2,sqr(19)])\relax \end{everbatim*} + \funcdesc[x, y, ...]{|`*`|} multiplies (left ticks mandatory): \begin{everbatim*} -\xinttheexpr `*`(1,3,19), `*`(1^2,3^2,19^2), `*`(1*2,3*4,19*20)\relax +\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$.\CHANGED{1.3d} When the inputs are integers it is advantageous to use a sub -\csbxint{iiexpr}-ession, as the integer-only macro is more efficient than the +Q$. When the inputs are integers it is advantageous to use a sub +\csbxint{iiexpr}-ession, as the integer-only macro is more efficient (about +|6X|) than the one accepting general fractional inputs. Notice that this may require some \func{num} wrapper when using variables, as they may well be in fraction format, and \csbxint{iiexpr} accepts only strict integers. Since |1.3d|, this function and \func{lcm} are available whether or not package \xintgcdname is loaded. Note that like other operations with fractions it does not always produce a fraction in irreducible format. This example shows also how to -reduce an n-uple to its primitive part: +reduce an n-uple to its primitive part: (this example should be revisited) \begin{everbatim*} \xinttheexpr gcd(7/300, 11/150, 13/60)\relax\newline $(7/300, 11/150, 13/60)\to -(\xinttheexpr seq(reduce(x), x = [7/300, 11/150, 13/60]/gcd(7/300, 11/150, 13/60))\relax)$ +(\xinttheexpr subs(seq(reduce(x/D), x = 7/300, 11/150, 13/60), D=gcd(7/300, 11/150, 13/60))\relax)$\newline +\xintexpr gcd([7/300, 11/150, 13/60])\relax\par \end{everbatim*} Perhaps a future release will provide a |primpart()| function as built-in @@ -5600,41 +5374,42 @@ functionality. \funcdesc[x, y, ...]{lcm} computes the positive generator of the fractional ideal of rational numbers $x\mathbb Z \cap y\mathbb Z \cap ... -\subset \mathbb Q$.\CHANGED{1.3d} When the inputs are integers it is +\subset \mathbb Q$. When the inputs are integers it is advantageous to use a sub \csbxint{iiexpr}-ession, as the integer-only macro -is more efficient than the one accepting general fractional inputs. +is more efficient (about |9X|) than the one accepting general fractional inputs. \begin{everbatim*} -\xinttheexpr lcm(7/300, 11/150, 13/60)\relax +\xinttheexpr lcm([7/300, 11/150, 13/60])\relax \end{everbatim*} -\funcdesc[x, y, ...]{first} first item of the list argument: +\funcdesc[x, y, ...]{first} first item of the list or nut-ple argument: \begin{everbatim*} -\xinttheiiexpr first(last(-7..3), 58, 97..105)\relax +\xintiiexpr first([last(-7..3), [58, 97..105]])\relax \end{everbatim*} -\funcdesc[x, y, ...]{last} last item of the list argument: +\funcdesc[x, y, ...]{last} last item of the list or nut-ple argument: \begin{everbatim*} -\xinttheiiexpr last(-7..3, 58, first(97..105))\relax +\xintiiexpr last([-7..3, 58, first(97..105)])\relax \end{everbatim*} -\funcdesc[x, y, ...]{reversed} reverses the order of the comma separated list: +\funcdesc[x, y, ...]{reversed} reverses the order of the comma separated list +or inside a nut-ple: \begin{everbatim*} -\xinttheiiexpr first(reversed(123..150)), last(reversed(123..150))\relax +\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. Earlier syntax was |[a,b,...,z][0]| but since |1.2g| this now returns - the first element of the list. + list or inside a nut-ple (at first level only: it is not a counter of leaves). \begin{everbatim*} -\xinttheiiexpr len(1..50, 101..150, 1001..1050)\relax +\xinttheiiexpr len(1..50, [101..150], 1001..1050), len([1..10])\relax \end{everbatim*} \end{description} \subsubsection{Functions requiring dummy variables} \hypertarget{ssec:dummies}{} -The ``functions'' \xintFor #1 in {add, mul, seq, subs, rseq, iter, rrseq, +The pseudo-functions \xintFor #1 in {add, mul, seq, subs, subsm, subsn, ndmap, ndseq, rseq, iter, rrseq, iterr} \do {\func{#1}\xintifForLast{}{, }} use delimited macros to -identify the ``|,<letter>=|'' part.\footnote{In the current implementation any - token can be used rather than a |=|. What is looked for is a comma followed - by two tokens, the first one will be the |<letter>|.} This is done in a way +identify the ``|,<letter>=|'' part. This is done in a way allowing nesting via correctly balanced parentheses. The |<letter>| must not have been assigned a value before via \csbxint{defvar}. @@ -5653,13 +5428,21 @@ know the values which will be assigned to |<letter>|. The special over list (which currently must thus proceed by steps of one.) \func{seq}, \func{rseq}, \func{iter}, \func{rrseq}, -\func{iterr} but not \func{add}, \func{mul}, \func{subs} admit the -\keyword{omit}, \keyword{abort}, and \keyword{break}|()| keywords. In the case +\func{iterr} and also \func{add}, \func{mul}, but not \func{subs} admit the +\keyword{omit}, \keyword{abort}, and \keyword{break}|()| keywords. This is a +new feature for \func{add} and \func{mul}.\NewWith{1.4} + + +In the case of a potentially infinite list generated by the |<integer>++| syntax, use of \keyword{abort} or of \keyword{break}|()| is mandatory, naturally. -Dummy variables are necessarily single-character letters, and all lowercase and -uppercase Latin letters are pre-configured for that usage. +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. + +Further, since |1.4|, \csbxint{newdummy} works to turn a multi-letter word +into a dummy variable.\NewWith{1.4} \begin{description} % [parsep=0pt,align=left, @@ -5674,29 +5457,35 @@ uppercase Latin letters are pre-configured for that usage. Attention that |xz| generates an error, one must use explicitely |x*z|, else the parser expects a variable with name |xz|. -|subs| is useful when defining macros for which some argument will be used -more than once but may itself be a complicated expression or macro, and should -be evaluated only once, for matters of efficiency. +\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. -The substituted variable may be a comma separated list (this is impossible -with |seq| which will always pick one item after the other from a list). -\begin{everbatim*} -\xinttheexpr subs([x]^2,x=-123,17,32)\relax -\end{everbatim*} - -See the examples related to the |3x3| determinant in the -\autoref{xintNewExpr} for an illustration of list substitution. +One should rather define auxiliary functions to compute intermediate +results. Or one can use \func{seq}. See the documentation of +\csbxint{deffunc}. \funcdesc[expr, letter=values]{add} addition \begin{everbatim*} -\xinttheiiexpr add(x^3,x=1..50), add(x(x+1), x=1,3,19)\relax\newline -\end{everbatim*}% +\xinttheiiexpr add(x^3,x=1..50), add(x(x+1), x=1,3,19)\relax +\end{everbatim*} + +\noindent At |1.4|, the keywords \keyword{omit}, \keyword{abort} and +\keyword{break}|()| are allowed.\NewWith {1.4} + See |`+`| for syntax without a dummy variable. \funcdesc[expr, letter=values]{mul} multiplication \begin{everbatim*} -\xinttheiiexpr mul(x^2, x=1,3,19), mul(2n+1,n=1..10)\relax\newline -\end{everbatim*}% +\xinttheiiexpr mul(x^2, x=1,3,19), mul(2n+1,n=1..10)\relax +\end{everbatim*} + +\noindent At |1.4|, the keywords \keyword{omit}, \keyword{abort} and +\keyword{break}|()| are allowed.\NewWith {1.4} + See |`*`| for syntax without a dummy variable. \funcdesc[expr, letter=values]{seq} comma separated values generated according to a formula @@ -5740,10 +5529,10 @@ this ``nuple''. For example: {trunc(% I feel truncation is better than rounding to display decimals of π \xintfloatexpr iter(1, sqrt(0.5), 1, 1; % initial values - ([@][0]-[@][1]<2e-43)?% stopping criteria; takes into account that the + (@[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, + {break(sqr(@[0]+@[1])/@[2])} % ... do final computation, {BS(@)}, % else do iteration i=1++) % This generates infinite iteration. The i is not used. \relax @@ -5758,13 +5547,21 @@ this ``nuple''. For example: 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, letter=values]{rrseq} recursive sequence with multiple initial terms. Say, there are |K| of them. Then |@1|, ..., |@4| and then |@@(n)| up to |n=K| refer to the - last |K| values. Notice the difference with |rseq| for which |@| refers to - the complete list of all initial terms if there are more than one and may - thus be a ``list'' object. This is impossible with |rrseq|. This construct - is effective for scalar finite order recursions, and may be perhaps a bit - more efficient than using the |rseq| syntax with a ``list'' value. + 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*} @@ -5790,21 +5587,56 @@ previous items, but decided to drop it as the package was becoming big. \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.\NewWith{1.4} +\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. +\NewWith{1.4} +\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 an +|ndlist| with |N| dimensions from function values. The function must be an +|N|-variable function. Its value may be scalar... or not. An optional final +semi-colon is allowed. \NewWith{1.4} +\begin{everbatim*} +\xintdeffunc foo(a,b,c,d) = a+b+c+d; +\xintthealign\xintexpr ndmap(foo, 1000,2000,3000; 100,200,300; 10,20,30; 1,2,3)\relax +\end{everbatim*} + +\funcdesc[function, var1=values1; var2=values2; ....; varN = valuesN]{ndseq} +Construction of an |ndlist| with |N| dimensions from simultaneous substitutions in an expression +in |N| variables. Its value may be scalar... or not. An optional final +semi-colon is allowed. +\NewWith{1.4} +\begin{everbatim*} +\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{everbatim*} + \end{description} Recursions may be nested, with |@@@(n)| giving access to the values of the outer recursion\dots and there is even |@@@@(n)| to access the outer outer recursion but I never tried it! -The following keywords may be placed within the generating expression of a -\func{seq}, \func{rseq}, \func{iter}, \func{rrseq}, or -\func{iterr}: : +The following keywords are recognized: \begin{description} - \keyworddesc{abort} stop here and now. + \keyworddesc{abort} it is a pseudo-variable which indicates to stop here and now. - \keyworddesc{omit} omit this value. + \keyworddesc{omit} it is a pseudo-variable which says to omit this value and + go to next one. - \keyworddesc{break} |break(stuff)| to abort and have |stuff| as last value. + \keyworddesc{break} it is a function |break(stuff)| which says to abort and have |stuff| as last value. \keyworddesc{<integer>++} serves to generate a potentially infinite list. In conjunction with an \keyword{abort} or \keyword{break}|()| this is often @@ -5824,15 +5656,188 @@ First Fibonacci number at least |2^31| and its index \end{everbatim*} \end{description} -Some additional examples are to be found in \autoref{ssec:moredummies}. -\subsubsection{Trigonometrical functions} +All operations executed by the parsers are based on underlying macros from +packages \xintfracname and \xintname which are loaded automatically by +\xintexprname. With \xintbinhexname loaded the +parsers can handle hexadecimal notation on (even fractional) input. + +All macros doing computations ultimately rely on (and reduce to) the +|\numexpr| primitive from \eTeX{}. These \eTeX{} extensions date back to 1999 +and are by default incorporated into the |pdftex| etc... executables from +major modern \TeX{} installations since more than ten years now. + + + +\subsection{One-dimensional sequence generators} + + +\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 «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 «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|,\CHANGED{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-dimensional sequences} +\label{ssec:lists} + +There are some breaking changes in the syntax at |1.4|,\CHANGED{1.4} because previously +\xintexprname had no real notion of a list or sequence type. It now does, and +even allows nesting. + +We denote here by \emph{list} or \emph{sequence} a general \emph{ople}, either +given as a variable or explicitly. In the former case the parentheses are +optional. + +\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{nut-ples}, 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{nut-ples} 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{nut-ples} 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 nut-ples} -See \xinttrigname. +This is entirely new with |1.4|.\NewWith{1.4} -\subsubsection{Logarithm, exponential and power functions} +I will give one illustrative example and refer to the NumPy documentation for +more. -See \xintlogname. +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 + generate the |nil| variable (at the suitable depth). +\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} @@ -5913,125 +5918,6 @@ which is not at all the presumably hoped for: % \end{everbatim} -\subsection{More examples with dummy variables} -\label{ssec:moredummies} - -These examples were first added to this manual at the time of the |1.1| -release (|2014/10/29|). - -\begin{everbatim*} -Prime numbers are always cool -\xinttheiiexpr seq((seq((subs((x/:m)?{(m*m>x)?{1}{0}}{-1},m=2n+1)) - ??{break(0)}{omit}{break(1)},n=1++))?{x}{omit}, - x=10001..[2]..10200)\relax -\end{everbatim*} - -The syntax in this last example may look a bit involved (... and it is so I -admit). First |x/:m| computes |x modulo m| (this is the modulo with respect to -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| bound is -\xinttheiiexpr subs(iterr(0,1;(@1>N)?{break(i)}{@1+@2},i=1++),N=2^64)\relax{} -and the previous number was its index. -\end{everbatim*} - -% A006877 In the `3x+1' problem, these values for the starting value set new -% records for number of steps to reach 1. (Formerly M0748) 14 1, 2, 3, 6, 7, -% 9, 18, 25, 27, 54, 73, 97, 129, 171, 231, 313, 327, 649, 703, 871, 1161, -% 2223, 2463, 2919, 3711, 6171, 10971, 13255, 17647, 23529, 26623, 34239, -% 35655, 52527, 77031, 106239, 142587, 156159, 216367, 230631, 410011, 511935, -% 626331, 837799 - -One more recursion: -\begin{everbatim*} -\def\syr #1{\xinttheiiexpr rseq(#1; (@<=1)?{break(i)}{odd(@)?{3@+1}{@//2}},i=0++)\relax} -The 3x+1 problem: \syr{231}\par -\end{everbatim*} - -OK, a final one: -\begin{everbatim*} -\def\syrMax #1{\xinttheiiexpr iterr(#1,#1;even(i)? - {(@2<=1)?{break(i/2)}{odd(@2)?{3@2+1}{@2//2}}} - {(@1>@2)?{@1}{@2}},i=0++)\relax } -With initial value 1161, the maximal number attained is \syrMax{1161} and that latter -number is the number of steps which was needed to reach 1.\par -\end{everbatim*} - -Look at the - \hyperlink{BrentSalamin}{Brent-Salamin algorithm implementation} for a more - interesting recursion. - -% \begin{everbatim*} -% \newcommand\Factors [1]{\xinttheiiexpr -% subs(seq((i/:3=1)?{omit}{[L][i]},i=0..len(L)-1), -% L=rseq(#1;(p^2>[@][0])?{([@][0]>1)?{break(1,[@][0],1)}{abort}} -% {(([@][0])/:p)?{omit} -% {iter(([@][0])//p; (@/:p)?{break(@,p,e)}{@//p},e=1++)}},p=2++))\relax } -% \Factors {41^4*59^2*29^3*13^5*17^8*29^2*59^4*37^6} -% \end{everbatim*} - -% This might look a bit scary, I admit.% -% % -% \footnote{Look at the -% \hyperlink{BrentSalamin}{Brent-Salamin algorithm implementation} for a much -% saner example.} -% % - -% \xintexprname has minimal tools and -% is obstinate about doing everything expandably! We are hampered by absence of a -% notion of ``nuple''. The algorithm divides |N| by |2| until no more possible, -% then by |3|, then by |4| (which is silly), then by |5|, then by |6| (silly -% again), \dots. - -% The variable |L=rseq(#1;...)| expands, if one follows the steps, to a comma -% separated list starting with the initial (evaluated) |N=#1| and then -% pseudo-triplets where the first item is |N| trimmed of small primes, the -% second item is the last prime divisor found, and the third item is its -% exponent in original |N|. - -% The algorithm needs to keep handy the last computed quotient by prime powers, -% hence all of them, but at the very end it will be cleaner to get rid of them -% (this corresponds to the first line in the code above). This is achieved in a -% cumbersome inefficient way; indeed each item extraction |[L][i]| is costly: it -% is not like accessing an array stored in memory, due to expandability, nothing -% can be stored in memory! Nevertheless, this step could be done here in a far -% less inefficient manner if there was a variant of |seq| which, in the spirit -% of \csbxint{iloopindex}, would know how many steps it had been through so far. -% This is a feature to be added to |\xintexpr|! (as well as a |++| construct -% allowing a non unit step). - -% Notice that in |iter(([@][0])//p;| the |@| refers to the previous triplet (or -% in the first step to |N|), but the latter |@| showing up in |(@/:p)?| refers -% to the previous value computed by |iter|. - -% \begin{snugframed} -% Parentheses are essential in |..([y][0])| else the parser will see |..[| and -% end up in ultimate confusion, and also in |([@][0])/:p| else the parser will -% see the itemwise operator |]/| on lists and again be very confused (I could -% implement a |]/:| on lists, but in this situation this would also be very -% confusing to the parser.) -% \end{snugframed} - -% See \autoref{ssec:factorize} for a routine |\Factorize| written directly with -% \xintname macros. Last time I checked |\Factors| was about seven times slower -% than |\Factorize| in test cases such as -% |16246355912554185673266068721806243461403654781833| and others. Among the -% various things explaining the speed difference, there is fact that the -% |\Factorize| algorithm step by increments of two, not one, and also it divides -% only once, obtaining quotient and remainder in one go. These two things -% already make for a speed-up factor of about four. Thus, |\Factors| is not -% completely inefficient in comparison, and was quite easier to come up with -% than |\Factorize|. - \subsection{User defined variables} \label{ssec:uservariables} \label{xintdefvar} @@ -6055,7 +5941,7 @@ For catcodes issues (particularly, for the semi-colon used to delimit the fetched expression), see the discussion of \csbxint{exprSafeCatcodes}. \begin{framed} Both syntaxes |\xintdefvar foo := <expr>;| and |\xintdefvar foo = <expr>;| - are accepted.\NewWithf{1.3c} + are accepted. \end{framed} Spaces in the variable name or around the equal sign are removed and are immaterial. @@ -6073,6 +5959,12 @@ Simultaneous assignments are allowed: The last non zero remainder is \xinttheiiexpr A\relax. \end{everbatim*} +Note1: simultaneous assignments are more costly in terms of +memory impact. + +Note2:\NewWith{1.4} in case of simultaneous assignments, the right hand side will be +automatically unpacked if necessary. + The variable names are expanded in an |\edef| (and stripped of spaces). Example: \begin{everbatim} @@ -6080,14 +5972,9 @@ Example: \end{everbatim} This defines the variables |x0|, |x1|, \dots, |x10| for future usage. -Legal variable names are composed of letters, digits, |_| and |@| and characters. -A variable name must start with a letter: -\begin{itemize}[nosep] -\item the first character can not be a digit, -\item and names starting with |@| or |_| are reserved (worldwide, - extra-terrestrial locations included if under UNO supervision) by author for - internal purposes. -\end{itemize} +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. |x_1x| is a licit variable name, as well as |x_1x_| and |x_1x_2| and |x_1x_2y| etc... As the parser does not trace back its steps, it will raise an ``unknown @@ -6144,32 +6031,30 @@ to the log. For example like this (the line numbers here are artificial): \begin{everbatim} Package xintexpr Info: (on line 2875) - Variable "e" defined with value 2718281828459045235360287471352662497757247 -0936999595749669676[-61]. + Variable "e" defined with value {271828182845904523536028747135266249775724 +70936999595749669676[-61]}. Package xintexpr Info: (on line 2879) - Variable "e" defined with value 2718281828459045[-15]. + Variable "e" defined with value {2718281828459045[-15]}. Package xintexpr Info: (on line 2886) - Variable "e_1" defined with value 9864101/3628800[0]. + Variable "e_1" defined with value {9864101/3628800[0]}. Package xintexpr Info: (on line 2887) - Variable "e_2" defined with value 2718281801146385[-15]. + Variable "e_2" defined with value {2718281801146385[-15]}. Package xintexpr Info: (on line 2889) - Variable "e_3" defined with value 6613313319248080001/2432902008176640000[0 -]. + Variable "e_3" defined with value {6613313319248080001/2432902008176640000[ +0]}. Package xintexpr Info: (on line 2890) - Variable "e_4" defined with value 2718281828459046[-15]. + Variable "e_4" defined with value {2718281828459046[-15]}. Package xintexpr Info: (on line 2892) - Variable "e" defined with value 2718281828459045235360287471352662497757247 -0936999595749669676[-61]. + Variable "e" defined with value {271828182845904523536028747135266249775724 +70936999595749669676[-61]}. \end{everbatim} - \subsubsection{\csh{xintunassignvar}} \label{xintunassignvar} Variable declarations obey the current scope. To let a (multi-letter) name be -unknown to (all parsers of) \xintexprname\CHANGED{1.3d} without waiting the -end of the scope one issues \csa{xintunassignvar}\marg{variable}. Prior to -|1.3d|, this only redefined the variable to represent the value \dtt{0}. +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 @@ -6205,22 +6090,26 @@ For example with Xe\TeX\ or Lua\LaTeX\ the following works: Under \csbxint{globaldefstrue} regime the effect of \csa{xintnewdummy} is global. -\subsubsection{\csh{xintensuredummy}, \csh{xintrestorelettervar}} +Starting with |1.4|,\NewWith{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{xintrestorelettervar} +\label{xintrestorevariable} -Use\NewWith{1.3e} +Use \begin{everbatim} \xintensuredummy{<character>} ... ... code using the (catcode 11) character as a dummy variable ... -\xintrestorelettervar{<character>} +\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. +\csbxint{restorevariable} was formerly called \csa{xintrestorelettervar}.\CHANGED{1.4} \subsection{User defined functions} \label{ssec:userfunctions} @@ -6228,10 +6117,37 @@ and it uses \csbxint{ensuredummy} to be certain everything is ok. \etocsetnexttocdepth{subsubsection}\localtableofcontents \let\HOOKLOCALTOC\empty + +\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 «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). + + + + \subsubsection{\csh{xintdeffunc}} \label{xintdeffunc} -Since release |1.2c| it is possible to declare functions: +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; @@ -6239,161 +6155,194 @@ Since release |1.2c| it is possible to declare functions: and that |x/2y| is interpreted as |x/(2y)|.) \begin{framed} - The ending semi-colon is allowed to be of active catcode, as |\xintdeffunc| - temporarily resets (since |1.3c|) its catcode 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. - - The colon is optional (since |1.2e|) and its (reasonable) catcode does not - matter. + \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 variables used in the function signature are single letters - (lowercase or uppercase) which have \emph{not} been re-declared via - \csbxint{defvar} as assigned variables. The choice of the letters is - entirely up to the user and has nil influence on the actual function, - naturally. -\item A function can have at most nine variables. -\item The mechanism for functions shares a common code base with the one - implementing \csbxint{NewExpr}. This means it shares its features and also - its \hyperref[sssec:limitations]{limitations}. -\item In order to allow recursive constructs, a core mechanism is implemented - which inhibits immediate expansion in a new definition; think of - \csbxint{deffunc} as being - analogous to a |\protected\edef|. This means that another function - |bar(x,..)| whose definition uses |foo(17.5)| will only store that it should - at some point compute - |foo(17.5)|, in place of storing its actual value. -\item If |foo(x)| definition is not recursive, then you should use - \csbxint{defefunc} rather. This is analogous to an |\edef| without the - |\protected|.\NewWith{1.3e} Then |bar(x,...)| (defined with - \csbxint{deffunc} or \csbxint{defefunc}) will store the actual - evaluation of |foo(17.5)|. -\item If |foo(x)| definition does need recursivity and you want to use - efficiently |foo(17.5)| in another function definition, assign it to a - variable (see \csbxint{defvar}) and use that variable rather in the - definition of |bar()|. Notice that only the variable value, not its name, - gets stored, so the variable name is a temporary auxiliary. In the analogy - with TeX macros one can think of \csbxint{defvar} or \csbxint{eval} as - producing expansion like typesetting does, whereas \csbxint{deffunc} is like - a - |\protected\edef|, and \csbxint{defefunc} an |\edef| not making the defined - function |\protected|. -\item A function declared via \csbxint{deffunc} remains unknown to +\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.\NewWith{1.4} +\item A function can have at most nine arguments. It can be defined as a + function with no 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}.\CHANGED{1.4} +\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. Prior to |1.4| one needed deprecated \csa{xintdefefunc} for this. But + the latter is now but an alias for \csa{xintdeffunc}, the two have been + merged.\CHANGED{1.4} +\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 like this:\NewWith{1.3e} + transfer a function with scalar values like this: \begin{everbatim} -\xintdeffloatfunc foo(x) := float(\xintexpr foo(x)\relax); +\xintdeffloatfunc foo(x) := float_(\xintexpr foo(x)\relax); \end{everbatim} - The \func{float} wrapper is in order for the float variant to produce an - already-rounded value, possibly speeding-up usage if used as input for other - functions. And in the reverse direction one can do: + The \func{float\string_} wrapper\NewWith{1.4} is in order for the float + variant to produce an already-rounded value, possibly speeding-up usage if + used as input for other functions. Notice the final underscore in the name; + it is not mandatory but \func{float} here would mean adding a check for + optional argument hence silly overhead, as this check can only be done at + time of use (as |\xintexpr...\relax| may a priori produce an |ople|). + +\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 |float(x)| above is not mandatory but recommended. The macro associated - to the user float function |bar(x)| may use many times its argument |x| and - it does not care to round it, because it basically expect an already rounded - value; but in \csbxint{expr} that value could very well be a fraction - |19/13| and its float rounding will be done again by each float macro - receiving it as argument; with a \func{float} used as above this will have - already been done once and the ulterior roundings are faster: they have - nothing to do apart from realizing that they have nothing to do.... One can - also use \func{sfloat}, this would serve to nothing for the |19/13| case but - would possibly for a short integer input involved in multiplications. -\item If the expression uses an \func{iterr}, \func{rseq}, or \func{rrseq}) it - must hide its |;| inside braces to let it not be confused with the ending - |;|. + 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 \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_}, because it will be + identified at time of definition that \func{float} is used without optional + argument. + \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 +macro. + +When used its action is via this defined macro. For example \begin{everbatim*} \xintdeffunc e(z):=(((((((((z/10+1)z/9+1)z/8+1)z/7+1)z/6+1)z/5+1)z/4+1)z/3+1)z/2+1)z+1; \end{everbatim*} creates a macro whose meaning one can find in the log file, after -|\xintverbosetrue|. Here it is: +\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 {\xi -ntDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\x -intAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\ -xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {#1}{10}}{1}}{#1}}{9} -}{1}}{#1}}{8}}{1}}{#1}}{7}}{1}}{#1}}{6}}{1}}{#1}}{5}}{1}}{#1}}{4}}{1}}{#1}}{3}} -{1}}{#1}}{2}}{1}}{#1}}{1} +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 main problem is that dummy variables in the defining expression are usable -only to the extent that their values are numerical. For example -% -\centeredline{|\xintdeffunc f(x):=add(i^2,i=1..x);|} -% - is not currently possible. See \autoref{sssec:limitations} and the next - subsection. +The above is not entirely true.\CHANGED{1.4} 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. -% In this example one could use the alternative syntax with list -% operations:% -% % -% \footnote{It turns out |`+`(seq(i^2, i=1..x))| would work here, but this isn't -% always the case with |seq| constructs.} -% %! par exemple \xintdeffunc g(a,b,c):=seq(x+a+b,x=1..c); -% %! donne une erreur avec g(0,0,2). Mardi 08 mars 2016 à 09:12:43. -% \begin{everbatim*} -% \xintdeffunc f(x):=`+`([1..x]^2);\xinttheexpr seq(f(x), x=1..20)\relax -% \end{everbatim*} +The main difficulty of \csbxint{deffunc} is with the pseudo-functions +\func{seq}, \func{iter}, etc..., which admit the keywords \keyword{omit}, +\keyword{abort}, \keyword{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. -% Side remark: as the |seq(f(x), x=1..10)| does many times the same -% computations, an |rseq| here would be more efficient:\footnote{Note that -% |omit| and |abort| are not usable in |add| or |mul| (currently).} -% \begin{everbatim*} -% \xinttheexpr rseq(1; (x>20)?{abort}{@+x^2}, x=2++)\relax -% \end{everbatim*} +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} -On the other hand a construct like the following has no issue, as the values -iterated over do not depend upon the function parameters: +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 everywhere 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*} -\xintdeffunc f(x):=iter(1{;} @*x/i+1, i=10..1);% one must hide the first semi-colon ! -\xinttheexpr e(1), f(1)\relax +\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*} - -Another problem is with trying to do |g(f(x))| where |g()| expects two -arguments and |f()| was defined to output two comma separated values. This -works fine numerically but not with a variable |x| inside the definition of -another function. - -See \autoref{sssec:csv} for more about comma separated values in output and -input. +It produces in the log: +\begin{everbatim} +Package xintexpr Info: (on line 10) + 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 11) + 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 «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. - Cryptic error messages will signal failures of using with another parser a - function declared for one parser (particularly if the name is a single - letter, because the parser will have made an attempt to use the letter as a - dummy variable.) - For usage in the \csbxint{iiexpr} parser, it is required to use \csa{xintdefiifunc}. @@ -6402,91 +6351,61 @@ For usage in the \csbxint{iiexpr} parser, it is required to use With \csbxint{deffunc} the created function is known by the \csbxint{expr} parser only. For usage in the \csbxint{floatexpr} parser, it is required to use -\csa{xintdeffloatfunc}. See \csbxint{deffunc} for more information on this -point. +\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{Some examples of recursive definitions} -\label{sssec:recursive} -Since |1.3|, it is possible to make recursive definitions. Here -are two examples: -\begin{everbatim*} -\xintdeffunc GCD(a,b):=if(b,GCD(b,a/:b),a); -\end{everbatim*} -This of course is the Euclide algorithm: it will be here applied to variables -which may be fractions. For example: +\subsubsection{Deprecated: \csh{xintdefefunc}, \csh{xintdefiiefunc}, + \csh{xintdeffloatefunc}} +\label{xintdefefunc} +\label{xintdeffloatefunc} +\label{xintdefiiefunc} + +They\CHANGED{1.4} are deprecated and currently only aliases to \csbxint{deffunc} et +al.. Please update your documents as they may be removed at any +time. + +\subsubsection{\csh{xintdefufunc}, \csh{xintdefiiufunc}, \csh{xintdeffloatufunc}} +\label{xintdefufunc} +\label{xintdefiiufunc} +\label{xintdeffloatufunc} + +This allows to define so-called «Universal functions». This is terminology +borrowed from |NumPy|.\NewWith{1.4} + +Here is an example: \begin{everbatim*} -\xinttheexpr GCD(385/102, 605/238)\relax +\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*} -But there is already a built-in \func{gcd} (which -accepts arbitrarily many arguments): +The function can be applied to any nested strucure: \begin{everbatim*} -\xinttheexpr gcd(385/102, 605/238)\relax +\xintiiexpr foo([1, [2, [3, [4, [5, 6, 7, 8, 9, 10]]]]])\relax \end{everbatim*} -Since |1.3d| the built-in \func{gcd} accepts inputs being fractions and -produces the positive generator of the corresponding fractional ideal. And -loading of \xintgcdname is not needed for this function to be available.\NewWith{1.3d} - -Our second example is modular exponentiation: +It must be defined as function acting on scalars, but its value type is not constrained. \begin{everbatim*} -\xintdefiifunc powmod_a(x, m, n) := - ifone(m, - % m=1, return x modulo n - x /: n, - % m > 1 test if odd or even and do recursive call - if(odd(m), (x*sqr(powmod_a(x, m//2, n))) /: n, - sqr(powmod_a(x, m//2, n)) /: n - ) - ); -\xintdefiifunc powmod(x, m, n) := if(m, powmod_a(x, m, n), 1); +\xintdefiivar Array = [1..10]; +\xintdefiiufunc foo(x) = [1..x]; +\xintthealign\xintiiexpr foo(Array)\relax \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.) + +It is even allowed to produce oples and act on oples: \begin{everbatim*} -\xinttheiiexpr seq(powmod(x, 1000, 128), x=9, 11, 13, 15, 17, 19, 21)\relax\par +\xintdefiivar Ople = 1..10; +\xintdefiiufunc bar(x) = x, x^2, x^3; +\xintiiexpr bar(Ople)\relax \end{everbatim*} -The function assumes the exponent is non-negative (the Python |pow| behaves -the same), but zealous users will add the necessary code for negative -exponents, after having defined another function for modular inverse! - -It is mandatory for such definitions to use the \func{if} function, and not -the |(x)?{A}{B}| construct which much choose a branch. The parsing of the -\func{if} function keeps the memory of the two alternative branches; to the -contrary, the \emph{constructed} |powmod| function will expand \emph{only} the -then relevant branch. This is of course absolutely needed for things such as -the Euclide algorithm where it would be catastrophic to evaluate both branches -as the first one involves a division by |b| and the algorithm stops only when -|b| is actually zero. - -If function |A| needs function |B| which needs function |A| start by giving to -|B| some dummy definition, define |A|, then define |B| properly. TODO: add -some example here... - -\subsubsection{\csh{xintdefefunc}} -\label{xintdefefunc} - -Think of former described variant \csbxint{deffunc} as doing the same as this -\csbxint{defefunc}\NewWith{1.3e} but with an extra protection added to the -defined function. If you don't need recursivity, \csbxint{defefunc} is the -better tool, as numerical evaluations which will use the defined function -inside further -definitions will get converted on the spot to actual values, rather than being -delayed for expansion to actual use of the defined function in \csbxint{eval} -or \csbxint{ieval}. - -\subsubsection{\csh{xintdeffloatefunc}} -\label{xintdeffloatefunc} - -The ``unprotected'' variant of \csbxint{deffloatfunc}.\NewWith{1.3e} - -\subsubsection{\csh{xintdefiiefunc}} -\label{xintdefiiefunc} - -The ``unprotected'' variant of \csbxint{defiifunc}.\NewWith{1.3e} \subsubsection{Using the same name for both a variable and a function} @@ -6504,19 +6423,6 @@ from the context if the function or variable interpretation must be used \xintunassigniiexprfunc{f}\xintunassignexprfunc{f}% \end{everbatim*} -% N.B.: we have declared in this section |f| and |g| as functions. They remain -% usable as dummy variables, but tacit multiplication in front of parentheses is -% dropped, in order for their function meanings to prevail. - -% \begin{everbatim*} -% \xintdeffunc f(x):=x^2; -% \xinttheexpr seq(f(f+f), f= 1..10)\relax\newline % f is used both as function and dummy variable -% \xinttheexpr seq(f*(f+f), f= 1..10)\relax % f is used as dummy variable -% \xintunassignexprfunc{f}\newline % drop meaning as function -% \xinttheexpr seq(f(f+f), f= 1..10)\relax % f as dummy variable, tacit multiplication applies -% \end{everbatim*} - - \subsubsection{\csh{xintunassignexprfunc}, \csh{xintunassigniiexprfunc}, \csh{xintunassignfloatexprfunc}} \label{xintunassignexprfunc} @@ -6525,7 +6431,7 @@ from the context if the function or variable interpretation must be used Function names can be unassigned via \csa{xintunassignexprfunc}\marg{name}, \csa{xintunassigniiexprfunc}\marg{name}, and -\csa{xintunassignfloatexprfunc}\marg{name}.\NewWith{1.3d} +\csa{xintunassignfloatexprfunc}\marg{name}. \begin{everbatim*} \xintunassignexprfunc{e} \xintunassignexprfunc{f} @@ -6543,27 +6449,24 @@ functions (or rather their associated macros) will be written to the log. For example the |Rump| declaration above generates this in the log file: \begin{everbatim} Function Rump for \xintexpr parser associated to \XINT_expr_userfunc_Rump w -ith meaning macro:#1#2->\xintAdd {\xintAdd {\xintAdd {\xintDiv {\xintMul {1335} -{\xintPow {#2}{6}}}{4}}{\xintMul {\xintPow {#1}{2}}{\xintSub {\xintSub {\xintSu -b {\xintMul {11}{\xintMul {\xintPow {#1}{2}}{\xintPow {#2}{2}}}}{\xintPow {#2}{ -6}}}{\xintMul {121}{\xintPow {#2}{4}}}}{2}}}}{\xintDiv {\xintMul {11}{\xintPow -{#2}{8}}}{2}}}{\xintDiv {#1}{\xintMul {2}{#2}}} -\end{everbatim} -and the declaration |\xintdeffunc f(x):=iter(1{;} @*x/i+1, i=10..1);| generates: -\begin{everbatim} - Function f for \xintexpr parser associated to \XINT_expr_userfunc_f with me -aning macro:#1->\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\xi -ntAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\x -intMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\ -xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul {\xintAdd {\xintDiv {\xintMul { -1}{#1}}{10/1[0]}}{1}}{#1}}{9/1[0]}}{1}}{#1}}{8/1[0]}}{1}}{#1}}{7/1[0]}}{1}}{#1} -}{6/1[0]}}{1}}{#1}}{5/1[0]}}{1}}{#1}}{4/1[0]}}{1}}{#1}}{3/1[0]}}{1}}{#1}}{2/1[0 -]}}{1}}{#1}}{1/1[0]}}{1} +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} -Starting with |1.2d| the definitions made by \csbxint{NewExpr} have local -scope, hence this is also the case with the definitions made by -\csbxint{deffunc}. See also \csb{ifxintglobaldefs} conditional. +\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).\CHANGEDf{1.4} + + 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} @@ -6571,97 +6474,96 @@ scope, hence this is also the case with the definitions made by \label{ifxintglobaldefs} If true user defined variables (\csbxint{defvar}, ...) and functions -(\csbxint{deffunc}, ...) for the expression parsers,\NewWith{1.3c} as well as -macros obtained via \csbxint{NewExpr} et al have global scope. If false -(default) they have local scope. - -\subsubsection{Functions expanding to comma separated values} -\label{sssec:csv} - -It is possible to define functions which expand to comma-separated values, for -example the declarations: -\begin{everbatim*} -\xintdeffunc f(x):= x, x^2, x^3, x^x; -\xintdeffunc g(x):= x^[0..x];% x^[1, 2, 3, x] would be like f above. -\end{everbatim*} -will generate -\begin{everbatim} - Function f for \xintexpr parser associated to \XINT_expr_userfunc_f with me -aning macro:#1->#1,\xintPow {#1}{2},\xintPow {#1}{3},\xintPow {#1}{#1} +(\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. - Function g for \xintexpr parser associated to \XINT_expr_userfunc_g with me -aning macro:#1->\xintApply::csv {\xintPow {#1}}{\xintSeq::csv {0}{#1}} -\end{everbatim} -and we can check that they work: -\begin{everbatim*} -\xinttheexpr f(10)\relax; \xinttheexpr g(10)\relax -\end{everbatim*} +\subsection{Examples of user defined functions} -However please consider this as WIP. They are some known (or half-known, -because the author gets a headache whenever he reconsiders the whole thing) -thorny issues, mostly related to the fact that \xintexprname has no proper -variable type for lists. See \autoref{ssec:lists}. +\subsubsection{Example with vectors and matrices} +\label{sssec:csv} -Here is another aspect: the documentation of release |1.3c| included this paragraph: +This section\CHANGED{1.4} has changed significantly at |1.4| due to the new extended data +types manipulated by the syntax. -\begin{quote} - It is possible to define functions of variables which stand for lists (see - \autoref{ssec:lists}), or functions defining lists of comma separated items. - For example the scalar product and cross product of 3-dimensional vectors - can be defined this way: -\end{quote} +Suppose we want to manipulate 3-dimensional vectors, which will be represented +as |nut-ples| 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 dprod(V, W) := V[0]*W[0] + V[1]*W[1] + V[2]*W[2]; +\xintdeffunc cprod(V, W) := [V[1]*W[2] - V[2]*W[1], + V[2]*W[0] - V[0]*W[2], + V[0]*W[1] - V[1]*W[0]]; \xintdeffunc Det3(U, V, W) := dprod(cprod(U, V), W); -\end{everbatim*} - -But it should be added promptly that due to absence to typed variables of type -list (see \autoref{ssec:lists}), usage of the above is very subtle: although -it is possible to define variables |U|, |V|, |W| expanding to three components -each it is impossible to use them with |Det3(U, V, W)| because \csbxint{expr} -will convert |U, V, W| to a comma separated list of \dtt{9} numbers, and -|Det3| was defined as a function of only \dtt{3} things. - -The only way (currently) is to define |U|, |V|, |W| as \emph{functions} -(possibly of no variable), then to define a new \emph{function} |Z = Det3(U, V, -W)|, and finally to evaluate |Z| with no argument: -\begin{everbatim*} -\xintdeffunc V() := 1, 1, 1; -\xintdeffunc W() := 1, 5, 25; -\xintdeffunc Y() := 1, 10, 100; -\xintdeffunc Z() := Det3(V(), W(), Y()); -% \xinteval{Det3(V(), W(), Y())} does NOT work, one must go via Z() -\xinteval{Z()} -\end{everbatim*} - -It is better for pure numerics to define the |Det3()| initially as a function -of \dtt{9} variables. But the above works well if one really wants to work -with variables: -\begin{everbatim*} -\xintdeffunc V(x) := 1, x, x^2; -\xintdeffunc Z(x,y,z) := Det3(V(x), V(y), V(z)); -\xinteval{Z(1, 5, 10)} -\end{everbatim*} - -This can be combined with usage of my other package -\href{http://ctan.org/pkg/polexpr}{polexpr}. I thank Thomas \textsc{Söll} who -explored precisely that during 2018. - -To tell the whole truth,\CHANGED{1.3e} until |1.3e| the above worked -\emph{only} with at least one variable, the syntax with no variables had a -bug. +\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} -Cleaning up: -\begin{everbatim*} -\xintunassignexprfunc{g} -\xintunassignexprfunc{V} -\xintunassignexprfunc{W} -\xintunassignexprfunc{Y} -\xintunassignexprfunc{Z} -\xintunassignexprfunc{dprod}\xintunassignexprfunc{cprod}\xintunassignexprfunc{Det3} +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 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, B) = ndmap(dprod, *A; *Tr(B)); +\xintdefvar mat1212 = MatMul(mat12, mat12); +$$ + M_1\cdot M_2 \cdot M_1 \cdot M_2 = + \vcenter{\xintthealign \xintexpr mat1212\relax} +$$ +$$ + \det(M_1\cdot M_2 \cdot M_1 \cdot M_2) = \xinteval{reduce(DetMat(mat1212))} +$$ \end{everbatim*} \subsubsection{Example with the \textsc{Rump} test} @@ -6671,7 +6573,7 @@ Let's try out our |Rump()| function: \begin{everbatim*} \xinttheexpr Rump(77617,33096)\relax. \end{everbatim*} -Nothing problematic for an \emph{exact} evaluation, naturally ! +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 @@ -6695,185 +6597,930 @@ precision for the evaluation. } \end{everbatim*} -\subsubsection{\csh{xintNewFunction}} -\label{xintNewFunction} +\subsubsection{Examples of recursive definitions} +\label{sssec:recursive} -The syntax is analogous to the one of \csbxint{NewExpr} but achieves something -\emph{completely different} from -\csbxint{NewExpr}/\csbxint{deffunc}. Here is an example: +Recursive definitions \emph{require} using the short-circuit branching +operators.\CHANGED{1.4} Prior to |1.4|, to the contrary it was explained that +one should use the \func{if} or \func{ifsgn} functions and that they would get +converted into macros doing branching in a short-circuit manner. This was a +bit counter-intuitive. \begin{everbatim*} -\xintNewFunction {foo}[3]{add(mul(x+i, i=#1..#2),x=1..#3)} +\xintdeffunc GCD(a,b):=(b)?{GCD(b,a/:b)}{a}; \end{everbatim*} -\begin{framed} - We now have a genuine function |foo( , , )| of three variables which we can - use fully in \emph{all three parsers}, be it with numerical arguments or - variables or whatever. -\end{framed} +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*} -\xinttheexpr seq(foo(0, 3, j), j= 1..10)\relax +\xinttheiiexpr seq(powmod(x, 1000, 128), x=9, 11, 13, 15, 17, 19, 21)\relax\par \end{everbatim*} -See \autoref{ssec:PrimesIV} for some additional examples. +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 advanced (but 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} +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.% + + +\clearpage +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} + +\etocdepthtag.toc {part1B} + +\expandafter\let\csname Syntax referencenameUp\endcsname\undefined +\csname Older macros and docnameUp\endcsname +\section{Macros of the \xintexprname package (legacy documentation)}% +\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 is limited to some information which has not already been covered +in \autoref{sec:xintexprsyntax}. -This construct is only syntactic sugar to benefit from functional notation. -Each time the created «function-macro» |foo()| will be encountered the -corresponding expression will get inserted as a sub-expression (of the same -type as the surrounding one), the macro parameters having been replaced with -the (already evaluated) function arguments, and the parser \emph{will then - have to parse the expression.} It is very much like a macro substitution, -but with parentheses and comma separated arguments (which can be arbitrary -expressions themselves). +\subsection{The \csh{xintexpr} expressions} +\label{xintexpr} +\label{xinttheexpr} +\label{thexintexpr} +\label{xintthe} + +An \xintexprname{}ession is a construct +\csbxint{expr}\meta{expandable\_expression}|\relax|\etype{x} where the +expandable expression is read and completely expanded from left to right. + +An |\xintexpr...\relax| \emph{must} end in a |\relax| (which will be absorbed). +Contrarily to a |\numexpr| expression, it is printable\CHANGED{1.4} 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} - Function foo for the expression parsers is associated to \XINT_expr_macrofu -nc_foo with meaning macro:#1#2#3->add(mul(x+i, i=\XINT_expr_wrapit {#1}..\XINT_ -expr_wrapit {#2}),x=1..\XINT_expr_wrapit {#3}) +\xintexpr round(<expression>, D)\relax \end{everbatim} -Thus, this works with quite arbitrary constructs, contrarily to the mechanism -of |\xintdeffunc|. It is not currently possible to define a |foo| function -like the one above via |\xintdeffunc|.% -% -\footnote{Or rather, it turns out that no error is raised on making the - definition via \csbxint{deffunc} but the created supporting macro is only - garbage and raises errors on use.} +there is +\begin{everbatim} +\xintiexpr [D] <expression> \relax +\end{everbatim} +The parameter |D| must be zero or positive.\footnote{|D=0| + corresponds to using |round(<expression>)| not |round(<expression>,0)| which + would leave a trailing dot. Same for |trunc|. There is also function |float| + for floating point rounding to \csbxint{theDigits} or the given number of + significant digits as second argument.} Perhaps some future version will +give a meaning to using a negative |D|.\footnote{Thanks to KT for this + suggestion. Sorry for the delay in implementing it... matter of formatting + the output and corresponding choice of user interface are still in need of + some additional thinking.} + +\begin{itemize} +\item the expression may contain arbitrarily many levels of nested parenthesized + sub-expressions, +\item the expression may contain explicitely or from a macro expansion a + sub-expression |\xintexpr...\relax|, which itself may contain a + sub-expressions etc\dots +\item to let sub-contents evaluate as a sub-unit it should thus be either + \begin{enumerate} + \item parenthesized, + \item or a sub-expression |\xintexpr...\relax|. + \end{enumerate} + \item to use an expression as argument to 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} -One can declare a function |foo| with |[0]| arguments: it may be used -as |foo()| or |foo(nil)| (prior to |1.3b| only the latter was accepted).\CHANGED{1.3b} +The information now following is possibly in need of updates. -\subsection{List operations} -\label{ssec:lists} +\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) ; + +{\centering\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 -By \emph{list} we hereby mean simply comma-separated values, for example |3, --7, 1e5|. This section describes some syntax which allows to manipulate such -lists, for example |[3, -7, 1e5][1]| extracts |-7| (we follow the Python -convention of enumerating starting at zero.) +\item See also \csbxint{ifsgnexpr}. -In the context of dummy variables, lists can be used in substitutions: +\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*} -\xinttheiiexpr subs(`+`(L), L = 1, 3, 5, 7, 9)\relax\newline +\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*} -and also the |rseq| and |iter| constructs allow |@| to refer to a list: + + Floats are quickly indispensable when using the power function, as exact + results will easily have hundreds, even thousands of digits. + % \begin{everbatim*} -\xinttheiiexpr iter(0, 1; ([@][1], [@][0]+[@][1]), i=1..10)\relax\newline +\xintDigits:=48\relax \xintthefloatexpr 2^100000\relax \end{everbatim*} -where each step constructs a new list with two entries. -However, despite appearances there is not really internally a notion of a -\emph{list type} and it is currently impossible to create, -manipulate, or return on output a \emph{list of lists}. There is a special -reserved variable |nil| which stands for the empty list. + 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} -The syntax which is explained next includes in particular what are called -\emph{list itemwise operators} such as: +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*} -\xinttheiiexpr 37+[13,100,1000]\relax\newline -\end{everbatim*}% -This part of the syntax is considered provisory, for the reason that its -presence might make more difficult some extensions in the future. On the other -hand the Python-like slicing syntax should not change. +\xinttheexpr \numexpr 351+877\relax\numexpr 1000-125\relax\relax{} is the same +as \xinttheexpr 1228*875\relax. +\end{everbatim*} +Control sequences however (such as |\parindent|) are picked up as a whole by +|\xintexpr|, and the numbers they define cannot be extended extra digits, a +syntax error is raised if the parser finds digits rather than a legal +operation after such a control sequence. + +A token list variable must be prefixed by |\the|, it will not be unpacked +automatically (the parser will actually try |\number|, and thus fail). Do not +use |\the| but only |\number| with a dimen or skip, as the |\xintexpr| parser +doesn't understand |pt| and its presence is a syntax error. To use a dimension +expressed in terms of points or other \TeX{} recognized units, incorporate it in +|\dimexpr...\relax|. + +Regarding how dimensional expressions are converted by \TeX{} into scaled points +see also \autoref{sec:Dimensions}. + +\subsection{Catcodes and spaces} + +Active characters may (and will) break the functioning of \csbxint{expr}. +Inside an expression one may prefix, for example a |:| with |\string|. Or, for +a more radical way, there is \csbxint{exprSafeCatcodes}. This is a +non-expandable step as it changes catcodes. + +\subsubsection{\csh{xintexprSafeCatcodes}} +\label{xintexprSafeCatcodes} + +This macro sets the catcodes of many characters to safe values. This is used +internally by \csbxint{NewExpr} (restoring the catcodes on exit), hence it +does not have to be protected against active characters when used at +top-level. + +Also \csbxint{defvar}, \csbxint{deffunc}, ..., use it before fetching their +semi-colon delimited arguments, so they can be used (also in the document +body) for example with Babel+French which makes the semi-colon active in the +(\LaTeX) document body. + +As \csbxint{NewExpr} and \csbxint{deffunc} and variants use internally some +|\scantokens|, they will (reasonably) succeed in sanitizing catcodes in the +expressions, even if all is from the replacement text of some macro whose +definition was done under some special catcode regime. + +But \csbxint{deffunc}, \csbxint{defvar} and variants need the (catcode other) +semi-colon as delimiter. Thus make sure the semi-colon has its normal catcode +when using \csbxint{deffunc} inside some macro definition. + +The macros \csbxint{deffunc} and variants ignore completely the colon in |:=| +(which furthermore is optional) so it can have any (reasonable) frozen catcode. + +The macros \csbxint{defvar} and variants are also compatible with any +reasonable frozen catcode of the colon |:| in |:=|, and the colon presence is +only optional. + +\begin{framed} + It is important to ALWAYS shortly let \csbxint{exprSafeCatcodes} be followed + by \csbxint{exprRestoreCatcodes}.\IMPORTANTf{} If one uses twice + \csbxint{exprSafeCatcodes} then the next \csbxint{exprRestoreCatcodes} will + restore the ancient catcode regime at time of the first one. +\end{framed} + +\subsubsection{\csh{xintexprRestoreCatcodes}} +\label{xintexprRestoreCatcodes} + +Restores the catcodes to the earlier state. More precisely, +\csbxint{exprSafeCatcodes} sets a toggle (with local scope). If the toggle is +set already it does not restore the current catcodes. The next +\csa{xintexprRestoreCatcodes} unsets the toggle. +So, in case of nesting, the +catcodes are restored to what they were when the \emph{first} un-paired +\csbxint{exprSafeCatcodes} got executed. + +\bigskip + +Spaces inside an |\xinttheexpr...\relax| should mostly be +innocuous (except inside macro arguments). + +|\xintexpr| and |\xinttheexpr| are for the most part agnostic regarding +catcodes: (unbraced) digits, binary operators, minus and plus signs as +prefixes, dot as decimal mark, parentheses, may be indifferently of catcode +letter or other or subscript or superscript, ..., it doesn't matter.% +% +\footnote{Furthermore, although \csbxint{expr} uses \csa{string}, it is + escape-char agnostic. It should work with any \csa{escapechar} setting + including -1.} + +The characters |+|, |-|, |*|, |/|, |^|, |!|, |&|, \verb+|+, |?|, |:|, |<|, |>|, +|=|, |(|, |)|, |"|, |[|, |]|, |;|, the dot and the comma should not be active if +in the expression, as everything is expanded along the way. If one of them is +active, it should be prefixed with |\string|. + +The exclamation mark |!| should have its standard catcode: with catcode letter +it is used internally and hence will confuse the parsers if it comes from the +expression. + +Digits, slash, square brackets, minus sign, in the output from an +|\xinttheexpr| are all of catcode 12. For |\xintthefloatexpr| the `e' in the +output has its standard catcode ``letter''. + +A macro with arguments will expand and grab its arguments before the +parser may get a chance to see them, so the situation with catcodes and spaces +is not the same within such macro arguments. + + + +\subsection{Expandability, \csh{xintexpro}} + +As is the case with all other package macros |\xintexpr| \fexpan ds (in two +steps) to its final (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|. is 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}. + +\subsection{\csh{xintiexpr}, \csh{xinttheiexpr}} +\label{xintiexpr}\label{xinttheiexpr}\label{thexintiexpr} + +Equivalent\etype{x} to doing |\xintexpr round(...)\relax| (more precisely, +|round| is applied to each item independently of its depth inside square +brackets. 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>0| within brackets, immediately after |\xintiexpr| +is allowed: it instructs the expression to do its final rounding to the +nearest value with that many digits after the decimal mark, \emph{i.e.}, +|\xintiexpr [D] <expression>\relax| is equivalent (in case of a single +expression) to |\xintexpr round(<expression>, D)\relax|. + +|\xintiexpr [0] ...| is the same as |\xintiexpr ...|. + +If truncation rather than rounding is needed use (in case of a single +expression, naturally) |\xintexpr trunc(...)\relax| for truncation to an +integer or |\xintexpr trunc(...,D)\relax| for truncation to a decimal number +with |D>0| digits after the decimal mark (works only here for single scalar +value). + +Perhaps in the future some meaning will be given to using negative value for +the optional parameter |D|.\footnote{Thanks to Kpym for this suggestion.} + +\subsection{\csh{xintiiexpr}, \csh{xinttheiiexpr}} +\label{xintiiexpr}\label{xinttheiiexpr}\label{thexintiiexpr} + +This variant\etype{x} does not know fractions. It deals almost only with long +integers. Comma separated lists of expressions are allowed. + +\begin{framed} + It maps |/| to the \emph{rounded} quotient. The operator + |//| is, like in |\xintexpr...\relax|, mapped to \emph{truncated} division. + The Euclidean quotient (which for positive operands is like the truncated + quotient) was, prior to release |1.1|, associated to |/|. The function + |quo(a,b)| can still be employed. +\end{framed} + +The \csbxint{iiexpr}-essions use the `ii' macros for addition, subtraction, +multiplication, power, square, sums, products, Euclidean quotient and +remainder. + +The |round|, |trunc|, |floor|, |ceil| functions are still available, and are +about the only places where fractions can be used, but |/| within, if not +somehow hidden will be executed as integer rounded division. To avoid this one +can wrap the input in \dtt{qfrac}: this means however that none of the normal +expression parsing will be executed on the argument. + +To understand the illustrative examples, recall that |round| and |trunc| have +a second (non negative) optional argument. In a normal \csbxint{expr}-essions, +|round| and |trunc| are mapped to \csbxint{Round} and \csbxint{Trunc}, in +\csbxint{iiexpr}-essions, they are mapped to \csbxint{iRound} and +\csbxint{iTrunc}. -\begin{itemize} - \item |a..b| constructs the \textbf{small} integers from the ceil $\lceil - a\rceil$ to the floor - $\lfloor b\rfloor$ (possibly a decreasing sequence): one has to be careful - if using this for algorithms that |1..0| for example is not empty or |1| - but expands to |1, 0|. Again, |a..b| \emph{can not} be used with |a| and - |b| greater than $2^{31}-1$. Also, only about at most \dtt{5000} integers - can be generated (this depends upon some \TeX{} memory settings). - The |..| has lower precedence than the arithmetic operations. \begin{everbatim*} -\xinttheexpr 1.5+0.4..2.3+1.1\relax; \xinttheexpr 1.9..3.4\relax; \xinttheexpr 2..3\relax +\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*} - \item |a..[d]..b| allows to generate big integers, or also fractions, it - proceeds with step (non necessarily integral nor positive) |d|. It does - \emph{not} replace |a| by its ceil, nor |b| by its floor. The generated - list is empty if |b-a| and |d| are of opposite signs; if |d=0| or if |a=b| - the list expands to single element |a|. +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*} -\xinttheexpr 1.5..[1.01]..11.23\relax +\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. - \item |[list][n]| extracts the |n+1|th element if |n>=0|. If - |n<0| it extracts from the tail. List items are numbered (since |1.2g|) as - in Python, the first element corresponding to |n=0|. - |len(list)| computes the number of items of the list. \begin{everbatim*} -\xinttheiexpr \empty[0..10][6], len(0..10), [0..10][-1], [0..10][23*18-22*19]\relax\ -(and 23*18-22*19 has value \the\numexpr 23*18-22*19\relax). +\xinttheiiexpr \xintFloatSqrt [20]{2}, \xintFloatSqrt [20]{3}\relax % no operations + +\noindent The next example requires the |round|, and one could not put the |+| inside it: + +\xinttheiiexpr round(\xintFloatSqrt [20]{2},19)+round(\xintFloatSqrt [20]{3},19)\relax + +(the second argument of |round| and |trunc| tells how many digits from after the +decimal mark one should keep.) \end{everbatim*} -See the next frame for why the example above has |\empty| token at start. +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). -As shown, it is perfectly legal to do operations in the index parameter, which -will be handled by the parser as everything else. The same remark applies to -the next items. - \item |[list][:n]| extracts the first |n| elements if |n>0|, or suppresses - the last \verb+|n|+ elements if |n<0|. +\subsection{\csh{xintboolexpr}, \csh{xinttheboolexpr}} +\label{xintboolexpr}\label{xinttheboolexpr}\label{thexintboolexpr} + +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. +\CHANGED{1.4} + +It can be customized, one only needs to modify the following: +\begin{everbatim} +\def\xintboolexprPrintOne#1{\xintiiifNotZero{#1}{True}{False}}% +\end{everbatim} +Not only are |True| and |False| usable in input, also |true| and |false| are +pre-declared variables. + +Maybe obsolete: + +There is slight quirk in case it is used as a sub-expression: the boolean +expression needs at least one logic operation else the value is not +standardized to |1| or |0|, for example we get from \begin{everbatim*} -\xinttheiiexpr [0..10][:6]\relax\ and \xinttheiiexpr [0..10][:-6]\relax +\xinttheexpr \xintboolexpr 1.23\relax\relax\newline +\end{everbatim*}which is to be compared with +\begin{everbatim*} +\xinttheboolexpr 1.23\relax \end{everbatim*} - \item |[list][n:]| suppresses the first |n| elements if |n>0|, or extracts - the last \verb+|n|+ elements if |n<0|. + +% A related issue existed with +% |\xinttheexpr \xintiexpr 1.23\relax\relax|, which was fixed with |1.1| +% release, and I decided back then not to add the needed overhead also to the +% |\xintboolexpr| context, as one only needs to use |?(1.23)| for example or +% involve the |1.23| in any logic operation like |1.23 'and' 3.45|, or involve +% the |\xintboolexpr ..\relax | itself with any logical operation, contrarily to +% the sub-|\xintiexpr| case where |\xinttheexpr 1+\xintiexpr 1.23\relax\relax| +% did behave contrarily to expectations until |1.1|. + + +\subsection{\csh{xintfloatexpr}, + \csh{xintthefloatexpr}} +\label{xintfloatexpr}\label{xintthefloatexpr}\label{thexintfloatexpr} + +\csbxint{floatexpr}|...\relax|\etype{x} is exactly like |\xintexpr...\relax| +but with the four binary operations and the power function are mapped to +\csa{xintFloatAdd}, \csa{xintFloatSub}, \csa{xintFloatMul}, \csa{xintFloatDiv} +and \csa{xintFloatPower}, respectively.\footnote{Since |1.2f| the \string^ + handles half-integer exponents, contrarily to \csa{xintFloatPower}.} + +The target precision for the computation is from the +current setting of |\xintDigits|. Comma separated lists of expressions are +allowed. + +An optional parameter within brackets is allowed: +\begin{itemize} +\item if positive it instructs the macro to round the result to that many + digits of precision. It thus makes sense to employ it only if this parameter is + less than the \csbxint{theDigits} precision. +\item if negative it means to trim off that many digits (of course, 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. + +|\thexintfloatexpr| is synonym to |\xintthefloatexpr|. + +|\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. + +\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 +like this (DON'T BELIEVE THIS; it has been entirely revamped at |1.4|): +\begin{everbatim} +\def\xinteval#1{\romannumeral-`0\xinttheexpr#1\relax}% OLD DEFINITION < 1.4 +\end{everbatim} +thus expands in two steps (its exact definition differs from the one given +above in order to achieve a slight optimization). \begin{everbatim*} -\xinttheiiexpr [0..10][6:]\relax\ and \xinttheiiexpr [0..10][-6:]\relax +\xinteval{add(x^2, x = 100..110), add(x^3, x = 100..110)} \end{everbatim*} -\item More generally, |[list][a:b]| works according to the Python ``slicing'' - rules (inclusive of negative indices). Notice though that there is no - optional third argument for the step, which always defaults to |+1|. + +\csbxint{ieval}\etype{x} is similarly related to \csbxint{theiexpr}. Its optional +argument must be located inside the braces: \begin{everbatim*} -\xinttheiiexpr [1..20][6:13]\relax\ = \xinttheiiexpr [1..20][6-20:13-20]\relax +\xintieval{[7] 355/113} \end{everbatim*} -\item It is naturally possible to nest these things: + +\csbxint{iieval}\etype{x} is similarly related to \csbxint{theiiexpr}. \begin{everbatim*} -\xinttheexpr [[1..50][13:37]][10:-10]\relax +\xintiieval{add(x^2, x = 100..110), add(x^3, x = 100..110)} \end{everbatim*} -\item itemwise operations either on the left or the right are possible: + +\csbxint{floateval}\etype{x} is similarly related to \csbxint{thefloatexpr}. Its optional +argument must be located inside the braces: \begin{everbatim*} -\xinttheiiexpr 123*[1..10]^2\relax +\xintfloateval{[7] 355/113} \end{everbatim*} -\begin{snugframed} - List operations are implemented using square brackets, but the |\xintiexpr| - and |\xintfloatexpr| parsers also check to see if an optional parameter - within brackets is specified before the start of the expression. To avoid the - resulting confusion if this |[| actually serves to delimit - comma separated values for list operations, one can either:\IMPORTANT{} - \begin{itemize} - \item insert something before the bracket such as |\empty| token, +When negative it tells how many digits to remove from the prevailing precision +(\csbxint{theDigits}): \begin{everbatim*} -\xinttheiexpr \empty [1,3,6,99,100,200][2:4]\relax +\xintfloateval{[-2] 355/113} has \xinttheDigits\ minus 2 digits. \end{everbatim*} - \item use parentheses: + +These macros are useful when one uses some extra wrapper doing some parsing of +its input, like the |\num| macro of +\href{http://ctan.org/pkg/siunitx}{siunitx}, which would choke on some of the +syntax elements allowed inside \csb{xintexpr}|...\relax| (for example +brackets). +As shown in the above examples, these macros, like the underlying parsers +accept arbitrarily many comma separated expressions. + + +\subsection{Using an expression parser within another one} + +This was already illustrated before. In the following: \begin{everbatim*} -\xinttheiexpr ([1,3,6,99,100,200][2:4])\relax +\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*} - \end{itemize} +Not surprisingly this differs from the previous one which was exact until +raising to the |100|th power. - Notice though that |([1,3,6,99,100,200])[2:4]| would not work: it is - mandatory for |][| and |][:| not to be interspersed with parentheses. Spaces - are perfectly legal: +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*} -\xinttheiexpr \empty[1..10 ] [ : 7 ]\relax +\xintiiexpr round(\xintfloatexpr 3.14^10\relax)\relax % or trunc +\end{everbatim*} + + +\subsection{The \csh{xintthecoords} macro} +\label{xintthecoords} + +It converts a comma separated list into the format for list of coordinates as +expected by the |TikZ| |coordinates| syntax.% +% +\footnote{The implementation had to work around the +problem that |TikZ| seemingly allows only a maximal number of about one +hundred expansion steps for the list to be entirely produced.}% +% +\begin{everbatim*} +\begin{figure}[htbp] +\centering\begin{tikzpicture}[scale=10]\xintDigits:=8\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 (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 \cs{xintthecoords}.} +\end{figure} \end{everbatim*} -Similarly all the |+[|, |*[|, \dots and |]**|, |]/|, \dots operators admit -spaces but nothing else between their constituent characters. +% Notice: if x goes no take exactly value 1 or -1, the origin appears slightly +% off the curve, not MY fault!!! + +As examplified above, \csbxint{thecoords} is to be used followed immediately +by either \csbxint{floatexpr} or \csbxint{iexpr} or \csbxint{iiexpr}. + + +The next\IMPORTANT{} +paragraph is probably obsoleted by |1.4| as |\xintexpr| does use +scienttific notation on output however with a possible denominator. + +As |TikZ| will not understand the |A/B[N]| format which is used on output by +|\xintexpr|, |\xintthecoords\xintexpr| has no use inside a |TikZ| picture but +may have other usages; the reason for the spaces in output is to allow if +necessary to print on the page for examination and give \TeX\ a change to +establish line-breaks. + \begin{everbatim*} -\xinttheiexpr \empty [ 1 . . 1 0 ] * * 1 1 \relax +\edef\x{\xintthecoords \xintexpr rrseq(1/2,1/3; @1+@2, x=1..20)\relax } +\meaning\x +++ \end{everbatim*} -\end{snugframed} -In an other vein, the parser will be confused by |1..[a,b,c][1]|, and one must -write |1..([a,b,c][1])|. And things such as |[100,300,500,700][2]//11| or -|[100,300,500,700][2]/11| are syntax errors and one must use parentheses, as -in |([100,300,500,700][2])/11|. +\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}} @@ -6906,17 +7553,16 @@ for readability of long numbers.} evaluated, whereas |\numexpr| without |\the| or |\number| prefix would not, if not itself embedded in another |\the\numexpr| or similar context. \item (ctd.) The private format to which |\xintiiexpr...\relax| (et al.) - evaluates needs |\xintthe| prefix to be printed on the page, or be used in - macros (expanding their argument.) The |\the| \TeX\ primitive prefix would + 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.) As a synonym to |\xintthe\xintiiexpr| one can use |\xinttheiiexpr|, - or (since |1.2h|) |\thexintiiexpr|. \item (ctd.) One can embed a |\numexpr...\relax| (with its |\relax|!) inside an |\xintiiexpr...\relax| without |\the| or |\number|, but the reverse situation - requires use of |\xintthe|. -\item |\numexpr -(1)\relax| is illegal. But |\xintiiexpr -(1)\relax| is + 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.) But +\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 @@ -7155,6 +7801,1620 @@ 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{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 Older macros and docnameUp\endcsname\undefined +\csname xinttrignameUp\endcsname + +\def\n{|{N}|} +\def\m{|{M}|} +\def\x{|{x}|} +\section{Macros of the \xinttrigname package} +\RaisedLabel{sec:trig} + +\localtableofcontents + +This package provides trigonometric functions for use with \xintexprname. +The sole macro is \csbxint{reloadxinttrig}. + +This package was first included in release |1.3e| (|2019/04/05|) of +\xintexprname. It is automatically loaded by \xintexprname. + +\textbf{Acknowledgements:} I finally decided to release some such functions +under friendly pressure of Jürgen \textsc{Gilg} and Thomas \textsc{Söll}, let +them both be thanked here. + +\subsection{\csh{xintreloadxinttrig}}\label{xintreloadxinttrig} + +The library is loaded automatically by \xintexprname, thus with the default +value of \csbxint{theDigits} which is \dtt{16}. But it can handle a precision +of up to about \fbox{\dtt{60}} digits (make this \dtt{59} at most for the +inverse functions). For this, execute for example \csbxint{SetDigits*}|{48}|. + +\begin{framed} + Since |1.3f|, the starred variants \csbxint{Digits*}|:=P;| and + \csbxint{SetDigits*}\marg{num. expression} execute \csbxint{reloadxinttrig} + to let the package re-configure itself. + + The non-starred variants do not execute \csbxint{reloadxinttrig} (to avoid + adding artificial overhead to existing documents).\IMPORTANTf{} +\end{framed} + +Absence of guard digits (whether in the used hard-coded constants or in +passing over values from one auxiliary function to the next) due to high level +(user) interface used for the programming means that the produced values are +definitely expected to be wrong in the last digit or last two digits. I should +actually give some estimate of the actual maximal error in |ulps| unit, but I +have not done the complete analysis for lack of time. + +Final computation results should thus probably be printed via +\csbxint{floateval}|{[-2]....}| in order to strip off (with rounding) the last +two digits, if one does not like seeing those non-meaningful figures in the +last one or two positions (I don't say those last two figures are +\emph{systematically} off). For example, to achieve \dtt{16} digits of +precision one should work with a precision of 18 digits (being careful to have +issued \csbxint{reloadxinttrig}) and round results using +\csbxint{floateval}|{[-2]....}|. + +Another approach is to use \csbxint{ieval}|{[D]...}| for conversion to +a fixed point format. + +In future, lower level coding will probably replace the high-level interface, +or at least the macros produced by the high-level interface will be hacked +into to tell the float macros to work at a somewhat elevated precision. + +\subsection{Constants} + +They are the correct rounding to \csbxint{theDigits} precision of the +mathematically exact ones. Their values get incorporated into the +trigonometrical functions at the time of their definitions during loading or +reloading of the package. They are left free to use, or modified, or +\csbxint{unassignvar}'d, as this will have no impact whatsoever on the +functions. + +\begin{description} +\vardesc{twoPi} what could that be? +\vardesc{threePiover2} +\vardesc{Pi} +\vardesc{Piover2} +\vardesc{oneRadian} this is one radian in degrees: $180/\pi$ +\vardesc{oneDegree} this is one degree in radian: $\pi/180$ +\vardesc{invfact2} this is $1/2!$ +\vardesc{invfact3} this is $1/3!$ +\item[\dots] +\vardesc{invfact44} this is $1/44!$ +\end{description} + +For a (very) slight optimization of usage, it is recommended to convert them +to macro form, for example: +\begin{everbatim*} +\edef\oneDegree{\xintfloatexpr oneDegree\relax} +\xintfloateval{sin(37\oneDegree)}\newline +\xintfloateval{sind(37)}\newline +\end{everbatim*} +By the way, the above value differs by |1ulp| from correct rounding of exact +one (which looks \dtt{...520482}79917...), see \autoref{ssec:trignotes}. + +\subsection{Functions} + +\subsubsection{Direct trigonometry} + +With the variable in radians: + +\begin{description} +\funcdesc{sin} sine +\funcdesc{cos} cosine +\funcdesc{tan} tangent +\funcdesc{cot} cotangent +\funcdesc{sec} secant +\funcdesc{csc} cosecant +\end{description} + +With the variable in degrees: + +\begin{description} +\funcdesc{sind} sine +\funcdesc{cosd} cosine +\funcdesc{tand} tangent +\funcdesc{cotd} cotangent +\funcdesc{secd} secant +\funcdesc{cscd} cosecant +\end{description} + +Only available with the variable in radians: +\begin{description} +\funcdesc{tg} tangent +\funcdesc{cotg} cotangent +\funcdesc{sinc} cardinal sine $\sinc(x) = \sin(x)/x$ +\end{description} + +\subsubsection{Inverse trigonometry} + +With the value in radians: + +\begin{description} +\funcdesc{asin} arcsine +\funcdesc{acos} arccosine +\funcdesc{atan} arctangent +\funcdesc[x, y]{Arg} the main branch of the argument of the complex number +|x+iy|, from $-\pi$ (excluded) to $\pi$ (included). 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} +\xintdeffloatefunc radians(x) := x * oneDegree; +\xintdeffloatefunc degrees(x) := x * oneRadian; +\xintdefefunc radians(x) := x * oneDegree; +\xintdefefunc degrees(x) := x * oneRadian; +\end{everbatim} + +The variants for \csbxint{expr} above do an exact multiplication, I did not +add a \func{float} wrapper to force rounding as anyhow the trigonometrical +functions will do this initial rounding of their arguments. But if you define +a variable for multiple later use using such a |degrees()| function, it would +be better to add a \func{float} wrapper in the variable definition so the +rounding is already done: rounding an already rounded value is unavoidable +overhead but proceeds faster as it is quicly realized the input actually needs +no rounding. + +Notice however that the conversion factors above are without guard digits. One +can do this: +\begin{everbatim} +\xintdeffloatefunc radians(x) := float(\xintexpr x * oneDegreewithmoredigits\relax); +\xintdeffloatefunc degrees(x) := float(\xintexpr x * oneRadianwithmoredigits\relax); +\end{everbatim} +But recall that |x| will normally already be a rounded value, so this is +perhaps a bit complex for not much ado. Probably better to work overall with +an elevated precision and print final results at a lower precision. + +\subsection{Important implementation notes} +\label{ssec:trignotes} + +\begin{itemize} +\item The package is almost entirely implemented using the high level user + interface of \xintexprname, see \autoref{sec:xintexprsyntax} for + \csbxint{deffloatefunc} and \csbxint{deffloatvar}, the main two exceptions + were: + \begin{enumerate}[nolistsep] + \item the range reduction for the |sind()| and |cosd()| functions which + required for optimized efficiency the coding at some more core level. + \item some changes at core level + facilitate the transfer of the defined functions from the float parser to + the exact parser. + \end{enumerate} + To avoid problems if the package is reloaded at a time the user has + used some letter variables as assigned variables, I added + \csbxint{ensuredummy} and \csbxint{restorevariable}. +\item It is not possible from this interface to (easily) let the computation + proceed with a temporarily elevated precision (``guard digits''). Expect + thus some errors in the last places; basically one should use the optional + rounding argument of either \csbxint{floateval} or \csbxint{ieval} to reduce + the number of digits of printed values by about two digits, if one + hopes to get correct rounding (most of the time). +\item Currently, \xintname is lacking some dedicated internal representation + of floats which means that most operations re-parse the digit tokens of their + arguments to count them\dots\ this does not contribute to efficiency (you + can load the module under |\xintverbosetrue| regime and see how the nested + macros look like and get an idea of how many times some rather silly + re-counting of mantissa lengths will get done!) +\item One should not overwrite some function names which are employed as + auxiliaries: |sin_aux|, |cos_aux|, |sin_|, |cos_|, |sind_|, |cosd_|, + |asin_l|\dots others\dots |asin_a|, |asind_a|, |atan_a|, |atand_a|, + |atan_b|, |atand_b|. If you redefine any one of them, you break the + whole thing. +\item Floats with large exponents are integers and are multiple of \dtt{1000}; + hence modulo \dtt{360} all such ``angles'' are multiple of \dtt{40} degrees. + Needless to say that considering usage of the |sind()| and |cosd()| functions + with such large float numbers is meaningless. +\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* := 50\relax % target 48 digits via 2 guard digits +$sind(17)\approx\xintfloateval{[-2] sind(17)}$\newline +$cosd(17)\approx\xintfloateval{[-2] cosd(17)}$\newline +$tand(17)\approx\xintfloateval{[-2] tand(17)}$\newline +$sind(43)\approx\xintfloateval{[-2] sind(43)}$\newline +$cosd(43)\approx\xintfloateval{[-2] cosd(43)}$\newline +$tand(43)\approx\xintfloateval{[-2] tand(43)}$\newline +$asind(0.3)\approx\xintfloateval{[-2] asind(0.3)}$\newline +$acosd(0.3)\approx\xintfloateval{[-2] acosd(0.3)}$\newline +$atand(3)\approx\xintfloateval{[-2] atand(3)}$\newline +$tan(atan(7))\approx\xintfloateval{[-2] tan(atan(7))}$\newline +$asind(sind(25))\approx\xintfloateval{[-2] asind(sind(25))}$\par\medskip +\noindent\xintDigits* := 26\relax % target 24 digits via 2 guard digits +$sind(17)\approx\xintfloateval{[-2] sind(17)}$\newline +$cosd(17)\approx\xintfloateval{[-2] cosd(17)}$\newline +$tand(17)\approx\xintfloateval{[-2] tand(17)}$\newline +$sind(43)\approx\xintfloateval{[-2] sind(43)}$\newline +$cosd(43)\approx\xintfloateval{[-2] cosd(43)}$\newline +$tand(43)\approx\xintfloateval{[-2] tand(43)}$\newline +$asind(0.3)\approx\xintfloateval{[-2] asind(0.3)}$\newline +$acosd(0.3)\approx\xintfloateval{[-2] acosd(0.3)}$\newline +$atand(3)\approx\xintfloateval{[-2] atand(3)}$\newline +$tan(atan(7))\approx\xintfloateval{[-2] tan(atan(7))}$\newline +$asind(sind(25))\approx\xintfloateval{[-2] 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{Macros of the \xintlogname package} +\RaisedLabel{sec:log} + +\localtableofcontents + +This package provides logarithms, exponentials and fractional powers for use +with \xintexprname. + +This package was first included in release |1.3e| (|2019/04/05|) of +\xintexprname. It is automatically loaded by \xintexprname. + +Currently, the functions \func{log10}, \func{pow10}, \func{log}, \func{exp}, +and \func{pow} use at their core two fast expandable macros handling base 10 +logarithms and powers for mantissas of 9 digit tokens. They are +defined by package \href{https://ctan.org/pkg/poormanlog}{poormanlog} which is +automatically imported. The error is believed to be at most \dtt{2ulp} (see +its |README|). The package \href{https://ctan.org/pkg/poormanlog}{poormanlog} +has no dependencies and can be imported by any other \TeX\ macro file. + +Although the precision is thus limited to about \dtt{8} or \dtt{9} digits this +is amply enough for plots. + +\subsection{\csh{poormanloghack}} +\label{ssec:poormanloghack} + +\begin{description} +\item[\string\poormanloghack\string{**\string}] use it to let the |**| operator be remapped to the + \func{pow} function. +\item[\string\poormanloghack\string{\string^\string}] use it to let the |^| operator be remapped to the + \func{pow} function. +\end{description} +If used, they obey \TeX\ scoping as usual. +\begin{everbatim*} +\begingroup +\poormanloghack{**}\xintfloateval{[8]1.234**5.678}\newline +\poormanloghack{^}\xintfloateval{[8]1.234^5.678}\par +\endgroup +\end{everbatim*} + +Notice that in \csbxint{floateval} those (equivalent) operators already +natively handle half-integer exponents. Once remapped to the \func{pow} +function they will become less precise than the original ones for half-integer +and integer exponents. + +\subsection{Functions} + +All those functions achieve only about \dtt{8} or \dtt{9} digits of precision. +Notice in particular that the digits beyond the ninth printed by \func{log} +have no significance (here we suppose |1<x<10|), but I did not add the +rounding overhead as it is expected anyhow that the final result will be +appropriately rounded. Notice however that \func{log10} should be seen as +going from floating point to fixed point (in the sense of the number of +fractional digits) and \func{pow10} from fixed point to floating point. + +\begin{description} +\funcdesc{log10} logarithm in base 10 +\funcdesc{pow10} fractional powers of 10 +\funcdesc{log} natural logarithm via |log10(x)*2.3025850923| formula; only the +first 8 or 9 digits of the output are significant... +\funcdesc{exp} exponential function via |pow10(x*0.434294481903)| formula +\funcdesc[x, y]{pow} computes $x^y$ via the formula |pow10(y*log10(x))| +\end{description} + +\begin{everbatim*} +\xintfloateval{[9] log(2), exp(1), pow(2,0.5)} +\end{everbatim*} +Notice that the last digit of |log(2)| is not the correctly rounded one... I +did say 9 \textbf{or} 8 digits or precision... The documentation of +\href{https://ctan.org/pkg/poormanlog}{poormanlog} mentions an error of up +to 2 units in the ninth digit when computing |log10(x)| for |1<x<10| and +|10^x| for |0<x<1|. + +\clearpage +\let\xintlognameUp\undefined +\csname Old examplesnameUp\endcsname +\section {Additional examples using \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| bound is +\xinttheiiexpr subs(iterr(0,1;(@1>N)?{break(i)}{@1+@2},i=1++),N=2^64)\relax{} +and the previous number was its index. +\end{everbatim*} + +% A006877 In the `3x+1' problem, these values for the starting value set new +% records for number of steps to reach 1. (Formerly M0748) 14 1, 2, 3, 6, 7, +% 9, 18, 25, 27, 54, 73, 97, 129, 171, 231, 313, 327, 649, 703, 871, 1161, +% 2223, 2463, 2919, 3711, 6171, 10971, 13255, 17647, 23529, 26623, 34239, +% 35655, 52527, 77031, 106239, 142587, 156159, 216367, 230631, 410011, 511935, +% 626331, 837799 + +One more recursion: +\begin{everbatim*} +\def\syr #1{\xinttheiiexpr rseq(#1; (@<=1)?{break(i)}{odd(@)?{3@+1}{@//2}},i=0++)\relax} +The 3x+1 problem: \syr{231}\par +\end{everbatim*} + +OK, a final one: +\begin{everbatim*} +\def\syrMax #1{\xinttheiiexpr iterr(#1,#1;even(i)? + {(@2<=1)?{break(i/2)}{odd(@2)?{3@2+1}{@2//2}}} + {(@1>@2)?{@1}{@2}},i=0++)\relax } +With initial value 1161, the maximal number attained is \syrMax{1161} and that latter +number is the number of steps which was needed to reach 1.\par +\end{everbatim*} + +Look at the + \hyperlink{BrentSalamin}{Brent-Salamin algorithm implementation} for a more + interesting recursion. + +% \begin{everbatim*} +% \newcommand\Factors [1]{\xinttheiiexpr +% subs(seq((i/:3=1)?{omit}{[L][i]},i=0..len(L)-1), +% L=rseq(#1;(p^2>[@][0])?{([@][0]>1)?{break(1,[@][0],1)}{abort}} +% {(([@][0])/:p)?{omit} +% {iter(([@][0])//p; (@/:p)?{break(@,p,e)}{@//p},e=1++)}},p=2++))\relax } +% \Factors {41^4*59^2*29^3*13^5*17^8*29^2*59^4*37^6} +% \end{everbatim*} + +% This might look a bit scary, I admit.% +% % +% \footnote{Look at the +% \hyperlink{BrentSalamin}{Brent-Salamin algorithm implementation} for a much +% saner example.} +% % + +% \xintexprname has minimal tools and +% is obstinate about doing everything expandably! We are hampered by absence of a +% notion of ``nuple''. The algorithm divides |N| by |2| until no more possible, +% then by |3|, then by |4| (which is silly), then by |5|, then by |6| (silly +% again), \dots. + +% The variable |L=rseq(#1;...)| expands, if one follows the steps, to a comma +% separated list starting with the initial (evaluated) |N=#1| and then +% pseudo-triplets where the first item is |N| trimmed of small primes, the +% second item is the last prime divisor found, and the third item is its +% exponent in original |N|. + +% The algorithm needs to keep handy the last computed quotient by prime powers, +% hence all of them, but at the very end it will be cleaner to get rid of them +% (this corresponds to the first line in the code above). This is achieved in a +% cumbersome inefficient way; indeed each item extraction |[L][i]| is costly: it +% is not like accessing an array stored in memory, due to expandability, nothing +% can be stored in memory! Nevertheless, this step could be done here in a far +% less inefficient manner if there was a variant of |seq| which, in the spirit +% of \csbxint{iloopindex}, would know how many steps it had been through so far. +% This is a feature to be added to |\xintexpr|! (as well as a |++| construct +% allowing a non unit step). + +% Notice that in |iter(([@][0])//p;| the |@| refers to the previous triplet (or +% in the first step to |N|), but the latter |@| showing up in |(@/:p)?| refers +% to the previous value computed by |iter|. + +% \begin{snugframed} +% Parentheses are essential in |..([y][0])| else the parser will see |..[| and +% end up in ultimate confusion, and also in |([@][0])/:p| else the parser will +% see the itemwise operator |]/| on lists and again be very confused (I could +% implement a |]/:| on lists, but in this situation this would also be very +% confusing to the parser.) +% \end{snugframed} + +% See \autoref{ssec:factorize} for a routine |\Factorize| written directly with +% \xintname macros. Last time I checked |\Factors| was about seven times slower +% than |\Factorize| in test cases such as +% |16246355912554185673266068721806243461403654781833| and others. Among the +% various things explaining the speed difference, there is fact that the +% |\Factorize| algorithm step by increments of two, not one, and also it divides +% only once, obtaining quotient and remainder in one go. These two things +% already make for a speed-up factor of about four. Thus, |\Factors| is not +% completely inefficient in comparison, and was quite easier to come up with +% than |\Factorize|. + +\subsection{Completely expandable prime test} +\label{ssec:primesI} + +Let us now construct a completely expandable macro which returns $1$ if its +given input is prime and $0$ if not: +\everb|@ +\def\remainder #1#2{\the\numexpr #1-(#1/#2)*#2\relax } +\def\IsPrime #1% + {\xintANDof {\xintApply {\remainder {#1}}{\xintSeq {2}{\xintiiSqrt{#1}}}}} +| + +This uses \csbxint{iiSqrt} and assumes its input is at least $5$. Rather than +\xintname's own \csbxint{iiRem} we used a quicker |\numexpr| expression as we +are dealing with short integers. Also we used \csbxint{ANDof} which will +return $1$ only if all the items are non-zero. The macro is a bit +silly with an even input, ok, let's enhance it to detect an even input: +\everb|@ +\def\IsPrime #1% + {\xintiiifOdd {#1} + {\xintANDof % odd case + {\xintApply {\remainder {#1}} + {\xintSeq [2]{3}{\xintiiSqrt{#1}}}% + }% + } + {\xintifEq {#1}{2}{1}{0}}% + } +| + +We used the \xintname expandable tests (on big integers or fractions) +in order for |\IsPrime| to be \fexpan dable. + +Our integers are short, but without |\expandafter|'s with +|\@firstoftwo|, % @ n'est plus actif dans le dtx 1.1 ! +or some other related techniques, +direct use of |\ifnum..\fi| tests is dangerous. So to make the macro more +efficient we are going to use the expandable tests provided by the package +\href{http://ctan.org/pkg/etoolbox}{etoolbox}% +% +\footnote{\url{http://ctan.org/pkg/etoolbox}}. +% +The macro becomes: +% +\everb|@ +\def\IsPrime #1% + {\ifnumodd {#1} + {\xintANDof % odd case + {\xintApply {\remainder {#1}}{\xintSeq [2]{3}{\xintiiSqrt{#1}}}}} + {\ifnumequal {#1}{2}{1}{0}}} +| + +In the odd case however we have to assume the integer is at least $7$, as +|\xintSeq| generates an empty list if |#1=3| or |5|, and |\xintANDof| returns +$1$ when supplied an empty list. Let us ease up a bit |\xintANDof|'s work by +letting it work on only $0$'s and $1$'s. We could use: +% +\everb|@ +\def\IsNotDivisibleBy #1#2% + {\ifnum\numexpr #1-(#1/#2)*#2=0 \expandafter 0\else \expandafter1\fi} +| +\noindent +where the |\expandafter|'s are crucial for this macro to be \fexpan dable and +hence work within the applied \csbxint{ANDof}. Anyhow, now that we have loaded +\href{http://ctan.org/pkg/etoolbox}{etoolbox}, we might as well use: +% +\everb|@ +\newcommand{\IsNotDivisibleBy}[2]{\ifnumequal{#1-(#1/#2)*#2}{0}{0}{1}} +| +\noindent +Let us enhance our prime macro to work also on the small primes: +\everb|@ +\newcommand{\IsPrime}[1] % returns 1 if #1 is prime, and 0 if not + {\ifnumodd {#1} + {\ifnumless {#1}{8} + {\ifnumequal{#1}{1}{0}{1}}% 3,5,7 are primes + {\xintANDof + {\xintApply + { \IsNotDivisibleBy {#1}}{\xintSeq [2]{3}{\xintiiSqrt{#1}}}}% + }}% END OF THE ODD BRANCH + {\ifnumequal {#1}{2}{1}{0}}% EVEN BRANCH +} +| + +The input is still assumed positive. There is a deliberate blank before +\csa{IsNotDivisibleBy} to use this feature of \csbxint{Apply}: a space stops the +expansion of the applied macro (and disappears). This expansion will be done by +\csbxint{ANDof}, which has been designed to skip everything as soon as it finds +a false (i.e. zero) input. This way, the efficiency is considerably improved. + +We did generate via the \csbxint{Seq} too many potential divisors though. Later +sections give two variants: one with \csbxint{iloop} (\autoref{ssec:primesII}) +which is still expandable and another one (\autoref{ssec:primesIII}) which is a +close variant of the |\IsPrime| code above but with the \csbxint{For} loop, thus +breaking expandability. The \hyperref[ssec:primesII]{xintiloop variant} does not +first evaluate the integer square root, the \hyperref[ssec:primesIII]{xintFor + variant} still does. I did not compare their efficiencies. + + +Let us construct with this expandable primality test a table of the prime +numbers up to $1000$. We need to count how many we have in order to know how +many tab stops one shoud add in the last row.% +% +\footnote{although a tabular row may have less tabs than in the + preamble, there is a problem with the \char`\|\space\space vertical + rule, if one does that.} +% +There is some subtlety for this +last row. Turns out to be better to insert a |\\| only when we know for sure we +are starting a new row; this is how we have designed the |\OneCell| macro. And +for the last row, there are many ways, we use again |\xintApplyUnbraced| but +with a macro which gobbles its argument and replaces it with a tabulation +character. The \csbxint{For*} macro would be more elegant here. +% +\everb?@ +\newcounter{primecount} +\newcounter{cellcount} +\newcommand{\NbOfColumns}{13} +\newcommand{\OneCell}[1]{% + \ifnumequal{\IsPrime{#1}}{1} + {\stepcounter{primecount} + \ifnumequal{\value{cellcount}}{\NbOfColumns} + {\\\setcounter{cellcount}{1}#1} + {&\stepcounter{cellcount}#1}% + } % was prime + {}% not a prime, nothing to do +} +\newcommand{\OneTab}[1]{&} +\begin{tabular}{|*{\NbOfColumns}{r}|} +\hline +2 \setcounter{cellcount}{1}\setcounter{primecount}{1}% + \xintApplyUnbraced \OneCell {\xintSeq [2]{3}{999}}% + \xintApplyUnbraced \OneTab + {\xintSeq [1]{1}{\the\numexpr\NbOfColumns-\value{cellcount}\relax}}% + \\ +\hline +\end{tabular} +There are \arabic{primecount} prime numbers up to 1000. +? + +The table has been put in \hyperref[primesupto1000]{float} which appears +\vpageref{primesupto1000}. +We had to be careful to use in the last row \csbxint{Seq} with its optional +argument |[1]| so as to not generate a decreasing sequence from |1| to |0|, but +really an empty sequence in case the row turns out to already have all its +cells (which doesn't happen here but would with a number of columns dividing +$168$). +% +\newcommand{\IsNotDivisibleBy}[2]{\ifnumequal{#1-(#1/#2)*#2}{0}{0}{1}} + +\newcommand{\IsPrime}[1] + {\ifnumodd {#1} + {\ifnumless {#1}{8} + {\ifnumequal{#1}{1}{0}{1}}% 3,5,7 are primes + {\xintANDof + {\xintApply + { \IsNotDivisibleBy {#1}}{\xintSeq [2]{3}{\xintiiSqrt{#1}}}}% + }}% END OF THE ODD BRANCH + {\ifnumequal {#1}{2}{1}{0}}% EVEN BRANCH +} + +\newcounter{primecount} +\newcounter{cellcount} +\newcommand{\NbOfColumns}{13} +\newcommand{\OneCell}[1] + {\ifnumequal{\IsPrime{#1}}{1} + {\stepcounter{primecount} + \ifnumequal{\value{cellcount}}{\NbOfColumns} + {\\\setcounter{cellcount}{1}#1} + {&\stepcounter{cellcount}#1}% + } % was prime + {}% not a prime nothing to do +} +\newcommand{\OneTab}[1]{&} +\begin{figure*}[ht!] + \centering + \phantomsection\label{primesupto1000} + \begin{tabular}{|*{\NbOfColumns}{r}|} + \hline + 2\setcounter{cellcount}{1}\setcounter{primecount}{1}% + \xintApplyUnbraced \OneCell {\xintSeq [2]{3}{999}}% + \xintApplyUnbraced \OneTab + {\xintSeq [1]{1}{\the\numexpr\NbOfColumns-\value{cellcount}\relax}}% + \\ + \hline + \end{tabular} +\smallskip +\centeredline{There are \arabic{primecount} prime numbers up to 1000.} +\end{figure*} + +\subsection{Another completely expandable prime test} +\label{ssec:primesII} + +The |\IsPrime| macro from \autoref{ssec:primesI} checked expandably if a (short) +integer was prime, here is a partial rewrite using \csbxint{iloop}. We use the +|etoolbox| expandable conditionals for convenience, but not everywhere as +|\xintiloopindex| can not be evaluated while being braced. This is also the +reason why |\xintbreakiloopanddo| is delimited, and the next macro +|\SmallestFactor| which returns the smallest prime factor examplifies that. One +could write more efficient completely expandable routines, the aim here was only +to illustrate use of the general purpose \csbxint{iloop}. A little table giving +the first values of |\SmallestFactor| follows, its coding uses \csbxint{For}, +which is described later; none of this uses count registers. +% + + +\begin{everbatim*} +\let\IsPrime\undefined \let\SmallestFactor\undefined % clean up possible previous mess +\newcommand{\IsPrime}[1] % returns 1 if #1 is prime, and 0 if not + {\ifnumodd {#1} + {\ifnumless {#1}{8} + {\ifnumequal{#1}{1}{0}{1}}% 3,5,7 are primes + {\if + \xintiloop [3+2] + \ifnum#1<\numexpr\xintiloopindex*\xintiloopindex\relax + \expandafter\xintbreakiloopanddo\expandafter1\expandafter.% + \fi + \ifnum#1=\numexpr (#1/\xintiloopindex)*\xintiloopindex\relax + \else + \repeat 00\expandafter0\else\expandafter1\fi + }% + }% END OF THE ODD BRANCH + {\ifnumequal {#1}{2}{1}{0}}% EVEN BRANCH +}% +\catcode`_ 11 +\newcommand{\SmallestFactor}[1] % returns the smallest prime factor of #1>1 + {\ifnumodd {#1} + {\ifnumless {#1}{8} + {#1}% 3,5,7 are primes + {\xintiloop [3+2] + \ifnum#1<\numexpr\xintiloopindex*\xintiloopindex\relax + \xint_afterfi{\xintbreakiloopanddo#1.}% + \fi + \ifnum#1=\numexpr (#1/\xintiloopindex)*\xintiloopindex\relax + \xint_afterfi{\expandafter\xintbreakiloopanddo\xintiloopindex.}% + \fi + \iftrue\repeat + }% + }% END OF THE ODD BRANCH + {2}% EVEN BRANCH +}% +\catcode`_ 8 +{\centering + \begin{tabular}{|c|*{10}c|} + \hline + \xintFor #1 in {0,1,2,3,4,5,6,7,8,9}\do {&\bfseries #1}\\ + \hline + \bfseries 0&--&--&2&3&2&5&2&7&2&3\\ + \xintFor #1 in {1,2,3,4,5,6,7,8,9}\do + {\bfseries #1% + \xintFor #2 in {0,1,2,3,4,5,6,7,8,9}\do + {&\SmallestFactor{#1#2}}\\}% + \hline + \end{tabular}\par +} +\end{everbatim*} + +\subsection{Miller-Rabin Pseudo-Primality expandably} +\label{ssec:PrimesIV} + + +At the time of writing, the code at the link above is still the version from +April 2016 and it needed some hacks to get recursive (pseudo)-functions +defined. Since |1.2h| of |2016/11/20| there is \csbxint{NewFunction} which +allows us here to avoid such internal hacking. + +And since |1.3| of |2018/03/01|, it is possible to use \csbxint{defiifunc} +also for recursive definitions, so we use it here, but we can benefit from it +only for modular exponentiation as the rest of the code uses |iter| or |break| +statements which are not yet compatible with \csbxint{defiifunc}. + +The |isPseudoPrime(n)| is usable in \csbxint{iiexpr}-essions and establishes +if its (positive) argument is a Miller-Rabin PseudoPrime to the bases $2, 3, +5, 7, 11, 13, 17$. If this is true and $n<341550071728321$ (which has 15 +digits) then $n$ really is a prime number. + +Similarly $n=3825123056546413051$ (19 digits) is the smallest composite number +which is a strong pseudo prime for bases $2, 3, 5, 7, 11, 13, 17, 19$ and +$23$. It is easy to extend the code below to include these additional tests +(we could make the list of tested bases an argument too, now that I think +about it.) + +For more information see + \centeredline{\url{https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Deterministic_variants_of_the_test}} + and +\centeredline{\url{http://primes.utm.edu/prove/prove2_3.html}} + +In particular, according to \textsc{Jaeschke} \emph{On strong pseudoprimes to + several bases,} Math. Comp., 61 (1993) 915-926, if $n < 4,759,123,141$ it is +enough to establish Rabin-Miller pseudo-primality to bases $a = 2, 7, 61$ to +prove that $n$ is prime. This range is enough for \TeX\ numbers and we could +then write a very fast expandable primality test for such numbers using only +|\numexpr|. Left as an exercise\dots + +\begin{everbatim*} +% I -------------------------------- Modular Exponentiation +% Computes x^m modulo n (with m non negative). +% We will always use it with 1 < x < n + +\xintdefiifunc powmod_a(x, m, n) := + ifone(m, + % m=1, return x modulo n + x /: n, + % m > 1 test if odd or even and do recursive call + if(odd(m), (x*sqr(powmod_a(x, m//2, n))) /: n, + sqr(powmod_a(x, m//2, n)) /: n + ) + ); +\xintdefiifunc powmod(x, m, n) := if(m, powmod_a(x, m, n), 1); + + +% For comparison here are the underlying support macros defined by +% \xintdefiifunc from the code above (since 1.3a): (with linebreaks added by +% TeX when writing to the log) + +% Function powmod_a for \xintiiexpr parser associated to \XINT_iiexpr_userfun +% c_powmod_a with meaning macro:#1#2#3->\xintiiifOne {#2}{\xintiiMod {#1}{#3}}{\x +% intiiifNotZero {\xintiiOdd {#2}}{\xintiiMod {\xintiiMul {#1}{\xintiiSqr {\xintE +% xpandArgs {XINT_iiexpr_userfunc_powmod_a}{{#1}{\xintiiDivFloor {#2}{2}}{#3}}}}} +% {#3}}{\xintiiMod {\xintiiSqr {\xintExpandArgs {XINT_iiexpr_userfunc_powmod_a}{{ +% #1}{\xintiiDivFloor {#2}{2}}{#3}}}}{#3}}} + +% Function powmod for \xintiiexpr parser associated to \XINT_iiexpr_userfunc_ +% powmod with meaning macro:#1#2#3->\xintiiifNotZero {#2}{\xintExpandArgs {XINT_i +% iexpr_userfunc_powmod_a}{{#1}{#2}{#3}}}{1} + +% II ------------------------------ Miller-Rabin compositeness witness + +% n=2^k m + 1 with m odd and k at least 1 + +% Choose 1<x<n. +% compute y=x^m modulo n +% if equals 1 we can't say anything +% if equals n-1 we can't say anything +% else put j=1, and +% compute repeatedly the square, incrementing j by 1 each time, +% thus always we have y^{2^{j-1}} +% -> if at some point n-1 mod n found, we can't say anything and break out +% -> if however we never find n-1 mod n before reaching +% z=y^{2^{k-1}} with j=k +% we then have z^2=x^{n-1}. + % Suppose z is not -1 mod n. If z^2 is 1 mod n, then n can be prime only if + % z is 1 mod n, and we can go back up, until initial y, and we have already + % excluded y=1. Thus if z is not -1 mod n and z^2 is 1 then n is not prime. + % But if z^2 is not 1, then n is not prime by Fermat. Hence (z not -1 mod n) + % implies (n is composite). (Miller test) + +% let's use again xintexpr indecipherable (except to author) syntax. Of course +% doing it with macros only would be faster. + +% Here \xintdefiifunc is not usable because not compatible with iter, break, ... +% but \xintNewFunction comes to the rescue. + +\xintNewFunction{isCompositeWitness}[4]{% x=#1, n=#2, m=#3, k=#4 + subs((y==1)?{0} + {iter(y;(j=#4)?{break(!(@==#2-1))} + {(@==#2-1)?{break(0)}{sqr(@)/:#2}},j=1++)} + ,y=powmod(#1,#3,#2))} + +% added note (2018/03/07) it is possible in the above that m=#3 is never +% zero, so we should rather call powmod_a for a small gain, but I don't +% have time to re-read the code comments and settle this. + +% III ------------------------------------- Strong Pseudo Primes + +% cf +% http://oeis.org/A014233 +% <http://mathworld.wolfram.com/Rabin-MillerStrongPseudoprimeTest.html> +% <http://mathworld.wolfram.com/StrongPseudoprime.html> + +% check if positive integer <49 si a prime. +% 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47 +\def\IsVerySmallPrime #1% + {\ifnum#1=1 \xintdothis0\fi + \ifnum#1=2 \xintdothis1\fi + \ifnum#1=3 \xintdothis1\fi + \ifnum#1=5 \xintdothis1\fi + \ifnum#1=\numexpr (#1/2)*2\relax\xintdothis0\fi + \ifnum#1=\numexpr (#1/3)*3\relax\xintdothis0\fi + \ifnum#1=\numexpr (#1/5)*5\relax\xintdothis0\fi + \xintorthat 1} + +\xintNewFunction{isPseudoPrime}[1]{% n = #1 + (#1<49)?% use ? syntax to evaluate only what is needed + {\IsVerySmallPrime{\xintthe#1}}% macro needs to be fed with #1 unlocked. + {(even(#1))? + {0} + {subs(% + % L expands to two values m, k hence isCompositeWitness does get + % its four variables x, n, m, k + isCompositeWitness(2, #1, L)? + {0}% + {isCompositeWitness(3, #1, L)? + {0}% + {isCompositeWitness(5, #1, L)? + {0}% + {isCompositeWitness(7, #1, L)? + {0}% +% above enough for N<3215031751 hence all TeX numbers + {isCompositeWitness(11, #1, L)? + {0}% +% above enough for N<2152302898747, hence all 12-digits numbers + {isCompositeWitness(13, #1, L)? + {0}% +% above enough for N<3474749660383 + {isCompositeWitness(17, #1, L)? + {0}% +% above enough for N<341550071728321 + {1}% + }% not needed to comment-out end of lines spaces inside + }% \xintexpr but this is too much of a habit for me with TeX! + }% I left some after the ? characters. + }% + }% + }% this computes (m, k) such that n = 2^k m + 1, m odd, k>=1 + , L=iter(#1//2;(even(@))?{@//2}{break(@,k)},k=1++))% + }% + }% +} + +% if needed: +%\def\IsPseudoPrime #1{\xinttheiiexpr isPseudoPrime(#1)\relax} + +\noindent The smallest prime number at least equal to 3141592653589 is +\xinttheiiexpr + seq(isPseudoPrime(3141592653589+n)? + {break(3141592653589+n)}{omit}, n=0++)\relax. +% we could not use 3141592653589++ syntax because it works only with TeX numbers +\par +\end{everbatim*} + + + + + +\subsection{A table of factorizations} +\label{ssec:factorizationtable} + +As one more example with \csbxint{iloop} let us use an alignment to display the +factorization of some numbers. The loop will actually only play a minor r\^ole +here, just handling the row index, the row contents being almost entirely +produced via a macro |\factorize|. The factorizing macro does not use +|\xintiloop| as it didn't appear to be the convenient tool. As |\factorize| will +have to be used on |\xintiloopindex|, it has been defined as a delimited macro. + +To spare some fractions of a second in the compilation time of this document +(which has many many other things to do), \number"7FFFFFED{} and +\number"7FFFFFFF, which turn out to be prime numbers, are not given to +|factorize| but just typeset directly; this illustrates use of +\csbxint{iloopskiptonext}. + +The code next generates a \hyperref[floatfactorize]{table} which has +been made into a float appearing \vpageref{floatfactorize}. Here is now +the code for factorization; the conditionals use the package provided +|\xint_firstoftwo| and |\xint_secondoftwo|, one could have employed +rather \LaTeX{}'s own |\@firstoftwo| and |\@secondoftwo|, or, simpler +still in \LaTeX{} context, the |\ifnumequal|, |\ifnumless| \dots, +utilities from the package |etoolbox| which do exactly that under the +hood. Only \TeX{} acceptable numbers are treated here, but it would be +easy to make a translation and use the \xintname macros, thus extending +the scope to big numbers; naturally up to a cost in speed. + +The reason for some strange looking expressions is to avoid arithmetic overflow. + +\begin{everbatim*} +\catcode`_ 11 +\def\abortfactorize #1\xint_secondoftwo\fi #2#3{\fi} + +\def\factorize #1.{\ifnum#1=1 \abortfactorize\fi + \ifnum\numexpr #1-2=\numexpr ((#1/2)-1)*2\relax + \expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo + \fi + {2&\expandafter\factorize\the\numexpr#1/2.}% + {\factorize_b #1.3.}}% + +\def\factorize_b #1.#2.{\ifnum#1=1 \abortfactorize\fi + \ifnum\numexpr #1-(#2-1)*#2<#2 + #1\abortfactorize + \fi + \ifnum \numexpr #1-#2=\numexpr ((#1/#2)-1)*#2\relax + \expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo + \fi + {#2&\expandafter\factorize_b\the\numexpr#1/#2.#2.}% + {\expandafter\factorize_b\the\numexpr #1\expandafter.% + \the\numexpr #2+2.}}% +\catcode`_ 8 +\begin{figure*}[ht!] +\centering\phantomsection\label{floatfactorize}\normalcolor +\tabskip1ex +\centeredline{\vbox{\halign {\hfil\strut#\hfil&&\hfil#\hfil\cr\noalign{\hrule} + \xintiloop ["7FFFFFE0+1] + \expandafter\bfseries\xintiloopindex & + \ifnum\xintiloopindex="7FFFFFED + \number"7FFFFFED\cr\noalign{\hrule} + \expandafter\xintiloopskiptonext + \fi + \expandafter\factorize\xintiloopindex.\cr\noalign{\hrule} + \ifnum\xintiloopindex<"7FFFFFFE + \repeat + \bfseries \number"7FFFFFFF&\number "7FFFFFFF\cr\noalign{\hrule} +}}} +\centeredline{A table of factorizations} +\end{figure*} +\end{everbatim*} + +\subsection{Another table of primes} +\label{ssec:primesIII} + +As a further example, let us dynamically generate a tabular with the first $50$ +prime numbers after $12345$. First we need a macro to test if a (short) number +is prime. Such a completely expandable macro was given in \autoref{ssec:primesI}, +here we consider a variant which will be slightly more efficient. This new +|\IsPrime| has two parameters. The first one is a macro which it redefines to +expand to the result of the primality test applied to the second argument. For +convenience we use the \href{http://ctan.org/pkg/etoolbox}{etoolbox} wrappers to +various |\ifnum| tests, although here there isn't anymore the constraint of +complete expandability (but using explicit |\if..\fi| in tabulars has its +quirks); equivalent tests are provided by \xintname, but they have some overhead +as they are able to deal with arbitrarily big integers. + +\def\IsPrime #1#2% +{\edef\TheNumber {\the\numexpr #2}% positive integer + \ifnumodd {\TheNumber} + {\ifnumgreater {\TheNumber}{1} + {\edef\ItsSquareRoot{\xintiiSqrt \TheNumber}% + \xintFor ##1 in {\xintintegers [3+2]}\do + {\ifnumgreater {##1}{\ItsSquareRoot} + {\def#1{1}\xintBreakFor} + {}% + \ifnumequal {\TheNumber}{(\TheNumber/##1)*##1} + {\def#1{0}\xintBreakFor } + {}% + }} + {\def#1{0}}}% 1 is not prime + {\ifnumequal {\TheNumber}{2}{\def#1{1}}{\def#1{0}}}% +}% + +\everb|@ +\def\IsPrime #1#2% """color[named]{PineGreen}#1=\Result, #2=tested number (assumed >0).;! +{\edef\TheNumber {\the\numexpr #2}%"""color[named]{PineGreen} hence #2 may be a count or \numexpr.;! + \ifnumodd {\TheNumber} + {\ifnumgreater {\TheNumber}{1} + {\edef\ItsSquareRoot{\xintiiSqrt \TheNumber}% + \xintFor """color{red}##1;! in {"""color{red}\xintintegers;! [3+2]}\do + {\ifnumgreater {"""color{red}##1;!}{\ItsSquareRoot} """color[named]{PineGreen}% "textcolor{red}{##1} is a \numexpr.;! + {\def#1{1}\xintBreakFor} + {}% + \ifnumequal {\TheNumber}{(\TheNumber/##1)*##1} + {\def#1{0}\xintBreakFor } + {}% + }} + {\def#1{0}}}% 1 is not prime + {\ifnumequal {\TheNumber}{2}{\def#1{1}}{\def#1{0}}}% +} +| + +As we used \csbxint{For} inside a macro we had to double the |#| in its |#1| +parameter. Here is now the code which creates the prime table (the table has +been put in a \hyperref[primes]{float}, which should be found on page +\pageref{primes}): + +\everb?@ +\newcounter{primecount} +\newcounter{cellcount} +\begin{figure*}[ht!] + \centering + \begin{tabular}{|*{7}c|} + \hline + \setcounter{primecount}{0}\setcounter{cellcount}{0}% + \xintFor """color{red}#1;! in {"""color{red}\xintintegers;! [12345+2]} \do +"""color[named]{PineGreen}% "textcolor{red}{#1} is a \numexpr.;! + {\IsPrime\Result{#1}% + \ifnumgreater{\Result}{0} + {\stepcounter{primecount}% + \stepcounter{cellcount}% + \ifnumequal {\value{cellcount}}{7} + {"""color{red}\the#1;! \\\setcounter{cellcount}{0}} + {"""color{red}\the#1;! &}} + {}% + \ifnumequal {\value{primecount}}{50} + {\xintBreakForAndDo + {\multicolumn {6}{l|}{These are the first 50 primes after 12345.}\\}} + {}% + }\hline +\end{tabular} +\end{figure*} +? + +\begin{figure*}[ht!] + \centering\phantomsection\label{primes} + \begin{tabular}{|*{7}c|} + \hline + \setcounter{primecount}{0}\setcounter{cellcount}{0}% + \xintFor #1 in {\xintintegers [12345+2]} \do + {\IsPrime\Result{#1}% + \ifnumgreater{\Result}{0} + {\stepcounter{primecount}% + \stepcounter{cellcount}% + \ifnumequal {\value{cellcount}}{7} + {\the#1 \\\setcounter{cellcount}{0}} + {\the#1 &}} + {}% + \ifnumequal {\value{primecount}}{50} + {\xintBreakForAndDo + {\multicolumn {6}{l|}{These are the first 50 primes after 12345.}\\}} + {}% + }\hline +\end{tabular} +\end{figure*} + +\subsection{Factorizing again} +\label{ssec:factorize} + +Here is an \fexpan dable macro which computes the factors of an integer. It +uses the \xintname macros only. +\begin{everbatim*} +\catcode`\@ 11 +\let\factorize\relax +\newcommand\Factorize [1] + {\romannumeral0\expandafter\factorize\expandafter{\romannumeral-`0#1}}% +\newcommand\factorize [1]{\xintiiifOne{#1}{ 1}{\factors@a #1.{#1};}}% +\def\factors@a #1.{\xintiiifOdd{#1} + {\factors@c 3.#1.}% + {\expandafter\factors@b \expandafter1\expandafter.\romannumeral0\xinthalf{#1}.}}% +\def\factors@b #1.#2.{\xintiiifOne{#2} + {\factors@end {2, #1}}% + {\xintiiifOdd{#2}{\factors@c 3.#2.{2, #1}}% + {\expandafter\factors@b \the\numexpr #1+\@ne\expandafter.% + \romannumeral0\xinthalf{#2}.}}% +}% +\def\factors@c #1.#2.{% + \expandafter\factors@d\romannumeral0\xintiidivision {#2}{#1}{#1}{#2}% +}% +\def\factors@d #1#2#3#4{\xintiiifNotZero{#2} + {\xintiiifGt{#3}{#1} + {\factors@end {#4, 1}}% ultimate quotient is a prime with power 1 + {\expandafter\factors@c\the\numexpr #3+\tw@.#4.}}% + {\factors@e 1.#3.#1.}% +}% +\def\factors@e #1.#2.#3.{\xintiiifOne{#3} + {\factors@end {#2, #1}}% + {\expandafter\factors@f\romannumeral0\xintiidivision {#3}{#2}{#1}{#2}{#3}}% +}% +\def\factors@f #1#2#3#4#5{\xintiiifNotZero{#2} + {\expandafter\factors@c\the\numexpr #4+\tw@.#5.{#4, #3}}% + {\expandafter\factors@e\the\numexpr #3+\@ne.#4.#1.}% +}% +\def\factors@end #1;{\xintlistwithsep{, }{\xintRevWithBraces {#1}}}% +\catcode`@ 12 +\end{everbatim*} +The macro will be acceptably efficient only with numbers having somewhat small +prime factors. +\begin{everbatim} +\Factorize{16246355912554185673266068721806243461403654781833} +\end{everbatim} +\begingroup\fdef\Z +{\Factorize{16246355912554185673266068721806243461403654781833}} +\noindent{\small\dtt{\Z}} + + +It puts a little stress on the input save stack in order +not be bothered with previously gathered things.\footnote{2015/11/18 I have + not revisited this code for a long time, and perhaps I could improve it now + with some new techniques.} + +Its output is a comma separated list with the number first, then its prime +factors with multiplicity. Let's produce something prettier: +\begin{everbatim*} +\catcode`_ 11 +\def\ShowFactors #1{\expandafter\ShowFactors_a\romannumeral-`0\Factorize{#1},\relax,\relax,} +\def\ShowFactors_a #1,{#1=\ShowFactors_b} +\def\ShowFactors_b #1,#2,{\if\relax#1\else#1^{#2}\expandafter\ShowFactors_b\fi} +\catcode`_ 8 +\end{everbatim*} +\begin{everbatim} +$$\ShowFactors{16246355912554185673266068721806243461403654781833}$$ +\end{everbatim} +$$\csname ShowFactors_a\expandafter\endcsname\Z,\relax,\relax,$$ +\endgroup + +If we only considered small integers, we could write pure |\numexpr| methods +which would be very much faster (especially if we had a table of small primes +prepared first) but still ridiculously slow compared to any non expandable +implementation, not to mention use of programming languages directly accessing +the CPU registers\dots + +\subsection{The Quick Sort algorithm illustrated}\label{ssec:quicksort} + +First a completely expandable macro which sorts a comma separated list of +numbers.% +% +\footnote{The code in earlier versions of this manual handled inputs composed + of braced items. I have switched to comma separated inputs on the occasion + of (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{000}\scantokens\expandafter{\meaning\z}\par +\endgroup +\end{everbatim*} +\fi % fin de si pas xetex + + +All the previous examples were with numbers which could have been handled via +|\ifdim| tests rather than the \csbxint{ifCmp} macro from \xintfracname; using +|\ifdim| tests would naturally be faster. Even faster routine is |code 6| at +(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}}}% many \edef's are to follow anyhow +% earlier I did a first drawing of the list, here with the color of RIGHT elements, +% but the color should have been for example white, anyway I drop this first line + %\let\QSRr\DecoRIGHT + %\par\centerline{\QS@list}% +% + % loop as many times as needed + \QS@loop }% +% +% \catcode`? 12 % in case we had used a funny ? as delimiter. +\makeatother +%% End of macro definitions. +%% Start of Example +\begingroup\offinterlineskip +\small +% \QuickSort {1.0, 0.5, 0.3, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, +% 1.3, 1.1, 0.7, 1.6, 0.6, 0.9, 0.8, 0.2, 0.1, 1.9} +% \medskip +% with repeated values +\QuickSort {1.0, 0.5, 0.3, 0.8, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, + 1.3, 1.1, 0.7, 0.3, 1.6, 0.6, 0.3, 0.8, 0.2, 0.8, 0.7, 1.2} +\endgroup +\end{everbatim*} + +Here is the variant which always picks the pivot as the rightmost element. + +\begin{everbatim*} +\makeatletter +% +\def\QS@cmp@a #1{\noexpand\QS@sep@A\expandafter\QS@cmp@d\expandafter + {\romannumeral0\xintnthelt{-1}{#1}}#1??}% +% +\def\DecoLEFTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% + \xintFor* ##1 in {#1} \do + {\xintifForLast {\DecoPivot {##1}}{\colorbox{LEFT}{##1}}}} +\def\DecoINERTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% + \xintFor* ##1 in {#1} \do + {\xintifForLast {\colorbox{INERTpiv}{##1}}{\colorbox{INERT}{##1}}}} +\def\DecoRIGHTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% + \xintFor* ##1 in {#1} \do + {\xintifForLast {\DecoPivot {##1}}{\colorbox{RIGHT}{##1}}}} +\def\QuickSort #1{% + % initialize, doing conversion from comma separated values to a list of braced items + \edef\QS@list{\noexpand\QSLr {\xintCSVtoList{#1}}}% many \edef's are to follow anyhow + % + % loop as many times as needed + \QS@loop }% +\makeatother +\begingroup\offinterlineskip +\small +% \QuickSort {1.0, 0.5, 0.3, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, +% 1.3, 1.1, 0.7, 1.6, 0.6, 0.9, 0.8, 0.2, 0.1, 1.9} +% \medskip +% with repeated values +\QuickSort {1.0, 0.5, 0.3, 0.8, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, + 1.3, 1.1, 0.7, 0.3, 1.6, 0.6, 0.3, 0.8, 0.2, 0.8, 0.7, 1.2} +\endgroup +\end{everbatim*} + +The choice of the first or last item as pivot is not a good one as nearly +ordered lists will take quadratic time. But for explaining the algorithm via a +graphical interpretation, it is not that bad. If one wanted to pick up the +pivot randomly, the routine would have to be substantially rewritten: in +particular the |\Deco..withPivot| macros need to know where the pivot is, and +currently this is implemented by using either |\xintifForFirst| or +|\xintifForLast|. + +\etocdepthtag.toc {macros} +\addtocontents{toc}{\gdef\string\sectioncouleur{{joli}}} +\addtocontents{toc}{\gdef\string\SKIPSECTIONINTERSPACE{\kern\smallskipamount}} +\renewcommand{\etocaftertochook}{\addvspace{\bigskipamount}} + +\clearpage + +\expandafter\let\csname Old examplesnameUp\endcsname\undefined +\csname xintbundlenameUp\endcsname + +\def\xintRunningHeader{{\inheadertrue\catcode`,12\relax + \DOCxintfrontpage, + \xintbundlename, + \xintkernelname, + \xintcorename, + \xintname, + \xintfracname, + \xintbinhexname, + \xintgcdname, + \xintseriesname, + \xintcfracname, + \xinttoolsname}} +\markboth{\makebox[0pt]{\xintRunningHeader}}{\makebox[0pt]{\xintRunningHeader}} + +\part{The macro layer for expandable computations: \xintcorename, \xintname, + \xintfracname,...} +\RaisedLabel[15]{sec:bundle} + + +\begin{framed} + WARNING ! + + The documentation is old, although we try to keep updated the list of macros + defined by all the packages. +\end{framed} + +\etocsetnexttocdepth{section} +\localtableofcontents + \section{The \xintname bundle} \localtableofcontents @@ -7631,11 +9891,7 @@ margin annotation signals what is the argument type. accept fractions and its action is to truncate them to integers. At |1.2o| many macros from \xintcorename/\xintname which - use \csbxint{Num} to parse their arguments got deprecated, see - \autoref{ssec:coredeprecated}, \autoref{ssec:xintdeprecated}, and - \autoref{ssec:xintdeprecatedNum}. - - All these macros have now been removed at |1.3|.\CHANGEDf{1.3} + used. All these macros have now been removed at |1.3|. \item the fraction input format\ntype{\Ff} applies to the arguments of \xintfracname macros handling genuine fractions. It allows two types @@ -8011,8 +10267,6 @@ recover the $1238/1157$ therein! the fraction |XN/D| to an integer |M|. The dimension is represented by |M sp|. - For more details refer to:\newline - \url{http://tex.stackexchange.com/questions/338297/why-pdf-file-cannot-be-reproduced/338510#338510}. \end{framed} @@ -8248,11 +10502,11 @@ control sequence) must be left undefined. I trust it will be |;-)|.% {\catcode`/ 11 \catcode`! 11 \catcode32 11 |\ ! /|} was chosen for its shortness.} -Deprecated macros also generate an (expandable) error message. Just hit the -|RETURN| key once to proceed.\IMPORTANT\ Most deprecated macros at |1.2o| are -listed either in \autoref{ssec:coredeprecated} or -\autoref{ssec:xintdeprecated} or \autoref{ssec:xintdeprecatedNum}. All -were removed at |1.3|.\CHANGED{1.3} +% Deprecated macros also generate an (expandable) error message. Just hit the +% |RETURN| key once to proceed.\IMPORTANT\ Most deprecated macros at |1.2o| are +% listed either in \autoref{ssec:coredeprecated} or +% \autoref{ssec:xintdeprecated} or \autoref{ssec:xintdeprecatedNum}. All +% were removed at |1.3|. The expression parsers are at |1.2l| still using a slightly less evolved method which lets \TeX{} display an undefined control sequence name giving @@ -8401,1221 +10655,8 @@ with more than $19900$ digits (but not much more than $19950$). This is with the current common values of the input save stack and maximal expansion depth: $5000$ and $10000$ respectively. - -\section{Some utilities from the \xinttoolsname package}\label{sec:sometoolsutils} - -This is a first overview. Many examples combining these utilities with the -arithmetic macros of \xintname are to be found in \autoref{sec:tools}. See -also \autoref{sec:examples}. - -\subsection{Assignments}\label{sec:assign} - -\xintAssign {357}{323}\to\tmpA\tmpB -\xintAssign \xintBezout{357}{323}\to\tmpU\tmpV\tmpD - -It might not be necessary to maintain at all times complete expandability. A -devoted syntax is provided to make these things more efficient, for example when -using the \csbxint{iiDivision} macro which computes both quotient and remainder -at -the same time: -% -\leftedline{\csbxint{Assign} - |\xintiiDivision{\xintiiPow {2}{1000}}{\xintiiFac{100}}\A\B|} -% -give: -\xintAssign\xintiiDivision{\xintiiPow {2}{1000}}{\xintiiFac{100}}\to\A\B -|\meaning\A|\dtt{: \printnumber{\meaning\A}\relax} and -|\meaning\B|\dtt{: \printnumber{\meaning\B}\relax}. -% -Another example (which uses \csbxint{Bezout} from the \xintgcdname package): -% -\leftedline{\csbxint{Assign} -% - |\xintBezout{357}{323}\to\U\V\D|} -% -is equivalent to setting |\U| to -\dtt{\tmpU}, |\V| to \dtt{\tmpV}, and |\D| to \dtt{\tmpD}. And indeed -\dtt{$\tmpU\times\tmpA+\tmpV\times\tmpB= - \xintiiAdd{\xintiiMul\tmpU\tmpA}{\xintiiMul\tmpV\tmpB}$} is a Bézout Identity. - -Thus, what |\xintAssign| does is to first apply an -\hyperref[ssec:expansions]{\fexpan sion} to what comes next; it then defines one -after the other (using |\def|; an optional argument allows to modify the -expansion type, see \autoref{xintAssign} for details), the macros found after -|\to| to correspond to the successive braced contents (or single tokens) located -prior to |\to|. In case the first token (after the -optional parameter within brackets, \emph{cf.} the \csbxint{Assign} detailed -document) is not an opening brace |{|, |\xintAssign| consider that there is - only one macro to define, and that its replacement text should be all that - follows until the |\to|. - -\xintAssign -{3570902836026}{200467139463}\to\tmpA\tmpB -\xintAssign -\xintBezout{3570902836026}{200467139463}\to\tmpU\tmpV\tmpD - -\leftedline -{\csbxint{Assign}|\xintBezout{3570902836026}{200467139463}\to\U\V\D|} -\noindent -gives then |\U| with meaning \dtt{\tmpU}, - |\V| with meaning \dtt{\tmpV} and |\D| with meaning \dtt{\tmpD}. - -% -In situations when one does not know in advance the number of items, one has -\csbxint{AssignArray} or its synonym \csbxint{DigitsOf}: -% -\leftedline{\csbxint{DigitsOf}|\xintiiPow{2}{100}\to|\csa{DIGITS}} -% -This defines \csa{DIGITS} to be macro with one parameter, \csa{DIGITS}|{0}| -gives the size |N| of the array and \csa{DIGITS}|{n}|, for |n| from |1| to |N| -then gives the |n|th element of the array, here the |n|th digit of $2^{100}$, -from the most significant to the least significant. As usual, the generated -macro \csa{DIGITS} is completely expandable (in two steps). As it wouldn't make -much sense to allow indices exceeding the \TeX{} bounds, the macros created by -\csbxint{AssignArray} put their argument inside a \csa{numexpr}, so it is -completely expanded and may be a count register, not necessarily prefixed by -|\the| or |\number|. Consider the following code snippet: -% -\begin{everbatim*} -% \newcount\cnta -% \newcount\cntb -\begingroup -\xintDigitsOf\xintiiPow{2}{100}\to\DIGITS -\cnta = 1 -\cntb = 0 -\loop -\advance \cntb \xintiiSqr{\DIGITS{\cnta}} -\ifnum \cnta < \DIGITS{0} -\advance\cnta 1 -\repeat - -|2^{100}| (=\xintiiPow {2}{100}) has \DIGITS{0} digits and the sum of their squares is \the\cntb. -These digits are, from the least to the most significant: \cnta = \DIGITS{0} \loop -\DIGITS{\cnta}\ifnum \cnta > 1 \advance\cnta -1 , \repeat.\endgroup -\end{everbatim*} - -Warning: \csbxint{Assign}, \csbxint{AssignArray} and \csbxint{DigitsOf} -\emph{do not do any check} on whether the macros they define are already -defined. - - -\subsection{Utilities for expandable manipulations}\label{sec:utils} - -The package now has more utilities to deal expandably with `lists of things', -which were treated un-expandably in the previous section with \csa{xintAssign} -and \csa{xintAssignArray}: \csbxint{ReverseOrder} and \csbxint{Length} since the -first release, \csbxint{Apply} and \csbxint{ListWithSep} since |1.04|, -\csbxint{RevWithBraces}, \csbxint{CSVtoList}, \csbxint{NthElt} since |1.06|, -\csbxint{ApplyUnbraced}, since |1.06b|, \csbxint{loop} and \csbxint{iloop} since -|1.09g|.% -% -\footnote{All these utilities, as well as \csbxint{Assign}, - \csbxint{AssignArray} and the \csbxint{For} loops are now available from the - \xinttoolsname package, independently of the big integers facilities of - \xintname.} - -As an example the following code uses only expandable operations: -\begin{everbatim*} -$2^{100}$ (=\xintiiPow {2}{100}) has \xintLen{\xintiiPow {2}{100}} digits and the sum of their -squares is \xintiiSum{\xintApply {\xintiiSqr}{\xintiiPow {2}{100}}}. These digits are, from the -least to the most significant: \xintListWithSep {, }{\xintRev{\xintiiPow {2}{100}}}. The thirteenth -most significant digit is \xintNthElt{13}{\xintiiPow {2}{100}}. The seventh least significant one -is \xintNthElt{7}{\xintRev{\xintiiPow {2}{100}}}. -\end{everbatim*} - -It would be more efficient to do once and for all -|\edef\z{\xintiiPow {2}{100}}|, and then use |\z| in place of - |\xintiiPow {2}{100}| everywhere as this would spare the CPU some repetitions. - -Expandably computing primes is done in \autoref{xintSeq}. - -\subsection{A new kind of for loop} - -As part of the \hyperref[sec:tools]{utilities} coming with the \xinttoolsname -package, there is a new kind of for loop, \csbxint{For}. Check it out -(\autoref{xintFor} and also in next section). - -\subsection{A new kind of expandable loop} - -Also included in \xinttoolsname, \csbxint{iloop} is an expandable loop giving -access to an iteration index, without using count registers which would break -expandability. Check it out (\autoref{xintiloop} and also in next section). - - - -\section {Additional examples using \xinttoolsname or \xintexprname or both} -\label{sec:examples} - -Note: \xintexprname.sty automatically loads \xinttoolsname.sty. - -\subsection{Completely expandable prime test} -\label{ssec:primesI} - -Let us now construct a completely expandable macro which returns $1$ if its -given input is prime and $0$ if not: -\everb|@ -\def\remainder #1#2{\the\numexpr #1-(#1/#2)*#2\relax } -\def\IsPrime #1% - {\xintANDof {\xintApply {\remainder {#1}}{\xintSeq {2}{\xintiiSqrt{#1}}}}} -| - -This uses \csbxint{iiSqrt} and assumes its input is at least $5$. Rather than -\xintname's own \csbxint{iiRem} we used a quicker |\numexpr| expression as we -are dealing with short integers. Also we used \csbxint{ANDof} which will -return $1$ only if all the items are non-zero. The macro is a bit -silly with an even input, ok, let's enhance it to detect an even input: -\everb|@ -\def\IsPrime #1% - {\xintiiifOdd {#1} - {\xintANDof % odd case - {\xintApply {\remainder {#1}} - {\xintSeq [2]{3}{\xintiiSqrt{#1}}}% - }% - } - {\xintifEq {#1}{2}{1}{0}}% - } -| - -We used the \xintname expandable tests (on big integers or fractions) -in order for |\IsPrime| to be \fexpan dable. - -Our integers are short, but without |\expandafter|'s with -|\@firstoftwo|, % @ n'est plus actif dans le dtx 1.1 ! -or some other related techniques, -direct use of |\ifnum..\fi| tests is dangerous. So to make the macro more -efficient we are going to use the expandable tests provided by the package -\href{http://ctan.org/pkg/etoolbox}{etoolbox}% -% -\footnote{\url{http://ctan.org/pkg/etoolbox}}. -% -The macro becomes: -% -\everb|@ -\def\IsPrime #1% - {\ifnumodd {#1} - {\xintANDof % odd case - {\xintApply {\remainder {#1}}{\xintSeq [2]{3}{\xintiiSqrt{#1}}}}} - {\ifnumequal {#1}{2}{1}{0}}} -| - -In the odd case however we have to assume the integer is at least $7$, as -|\xintSeq| generates an empty list if |#1=3| or |5|, and |\xintANDof| returns -$1$ when supplied an empty list. Let us ease up a bit |\xintANDof|'s work by -letting it work on only $0$'s and $1$'s. We could use: -% -\everb|@ -\def\IsNotDivisibleBy #1#2% - {\ifnum\numexpr #1-(#1/#2)*#2=0 \expandafter 0\else \expandafter1\fi} -| -\noindent -where the |\expandafter|'s are crucial for this macro to be \fexpan dable and -hence work within the applied \csbxint{ANDof}. Anyhow, now that we have loaded -\href{http://ctan.org/pkg/etoolbox}{etoolbox}, we might as well use: -% -\everb|@ -\newcommand{\IsNotDivisibleBy}[2]{\ifnumequal{#1-(#1/#2)*#2}{0}{0}{1}} -| -\noindent -Let us enhance our prime macro to work also on the small primes: -\everb|@ -\newcommand{\IsPrime}[1] % returns 1 if #1 is prime, and 0 if not - {\ifnumodd {#1} - {\ifnumless {#1}{8} - {\ifnumequal{#1}{1}{0}{1}}% 3,5,7 are primes - {\xintANDof - {\xintApply - { \IsNotDivisibleBy {#1}}{\xintSeq [2]{3}{\xintiiSqrt{#1}}}}% - }}% END OF THE ODD BRANCH - {\ifnumequal {#1}{2}{1}{0}}% EVEN BRANCH -} -| - -The input is still assumed positive. There is a deliberate blank before -\csa{IsNotDivisibleBy} to use this feature of \csbxint{Apply}: a space stops the -expansion of the applied macro (and disappears). This expansion will be done by -\csbxint{ANDof}, which has been designed to skip everything as soon as it finds -a false (i.e. zero) input. This way, the efficiency is considerably improved. - -We did generate via the \csbxint{Seq} too many potential divisors though. Later -sections give two variants: one with \csbxint{iloop} (\autoref{ssec:primesII}) -which is still expandable and another one (\autoref{ssec:primesIII}) which is a -close variant of the |\IsPrime| code above but with the \csbxint{For} loop, thus -breaking expandability. The \hyperref[ssec:primesII]{xintiloop variant} does not -first evaluate the integer square root, the \hyperref[ssec:primesIII]{xintFor - variant} still does. I did not compare their efficiencies. - - -Let us construct with this expandable primality test a table of the prime -numbers up to $1000$. We need to count how many we have in order to know how -many tab stops one shoud add in the last row.% -% -\footnote{although a tabular row may have less tabs than in the - preamble, there is a problem with the \char`\|\space\space vertical - rule, if one does that.} -% -There is some subtlety for this -last row. Turns out to be better to insert a |\\| only when we know for sure we -are starting a new row; this is how we have designed the |\OneCell| macro. And -for the last row, there are many ways, we use again |\xintApplyUnbraced| but -with a macro which gobbles its argument and replaces it with a tabulation -character. The \csbxint{For*} macro would be more elegant here. -% -\everb?@ -\newcounter{primecount} -\newcounter{cellcount} -\newcommand{\NbOfColumns}{13} -\newcommand{\OneCell}[1]{% - \ifnumequal{\IsPrime{#1}}{1} - {\stepcounter{primecount} - \ifnumequal{\value{cellcount}}{\NbOfColumns} - {\\\setcounter{cellcount}{1}#1} - {&\stepcounter{cellcount}#1}% - } % was prime - {}% not a prime, nothing to do -} -\newcommand{\OneTab}[1]{&} -\begin{tabular}{|*{\NbOfColumns}{r}|} -\hline -2 \setcounter{cellcount}{1}\setcounter{primecount}{1}% - \xintApplyUnbraced \OneCell {\xintSeq [2]{3}{999}}% - \xintApplyUnbraced \OneTab - {\xintSeq [1]{1}{\the\numexpr\NbOfColumns-\value{cellcount}\relax}}% - \\ -\hline -\end{tabular} -There are \arabic{primecount} prime numbers up to 1000. -? - -The table has been put in \hyperref[primesupto1000]{float} which appears -\vpageref{primesupto1000}. -We had to be careful to use in the last row \csbxint{Seq} with its optional -argument |[1]| so as to not generate a decreasing sequence from |1| to |0|, but -really an empty sequence in case the row turns out to already have all its -cells (which doesn't happen here but would with a number of columns dividing -$168$). -% -\newcommand{\IsNotDivisibleBy}[2]{\ifnumequal{#1-(#1/#2)*#2}{0}{0}{1}} - -\newcommand{\IsPrime}[1] - {\ifnumodd {#1} - {\ifnumless {#1}{8} - {\ifnumequal{#1}{1}{0}{1}}% 3,5,7 are primes - {\xintANDof - {\xintApply - { \IsNotDivisibleBy {#1}}{\xintSeq [2]{3}{\xintiiSqrt{#1}}}}% - }}% END OF THE ODD BRANCH - {\ifnumequal {#1}{2}{1}{0}}% EVEN BRANCH -} - -\newcounter{primecount} -\newcounter{cellcount} -\newcommand{\NbOfColumns}{13} -\newcommand{\OneCell}[1] - {\ifnumequal{\IsPrime{#1}}{1} - {\stepcounter{primecount} - \ifnumequal{\value{cellcount}}{\NbOfColumns} - {\\\setcounter{cellcount}{1}#1} - {&\stepcounter{cellcount}#1}% - } % was prime - {}% not a prime nothing to do -} -\newcommand{\OneTab}[1]{&} -\begin{figure*}[ht!] - \centering - \phantomsection\label{primesupto1000} - \begin{tabular}{|*{\NbOfColumns}{r}|} - \hline - 2\setcounter{cellcount}{1}\setcounter{primecount}{1}% - \xintApplyUnbraced \OneCell {\xintSeq [2]{3}{999}}% - \xintApplyUnbraced \OneTab - {\xintSeq [1]{1}{\the\numexpr\NbOfColumns-\value{cellcount}\relax}}% - \\ - \hline - \end{tabular} -\smallskip -\centeredline{There are \arabic{primecount} prime numbers up to 1000.} -\end{figure*} - -\subsection{Another completely expandable prime test} -\label{ssec:primesII} - -The |\IsPrime| macro from \autoref{ssec:primesI} checked expandably if a (short) -integer was prime, here is a partial rewrite using \csbxint{iloop}. We use the -|etoolbox| expandable conditionals for convenience, but not everywhere as -|\xintiloopindex| can not be evaluated while being braced. This is also the -reason why |\xintbreakiloopanddo| is delimited, and the next macro -|\SmallestFactor| which returns the smallest prime factor examplifies that. One -could write more efficient completely expandable routines, the aim here was only -to illustrate use of the general purpose \csbxint{iloop}. A little table giving -the first values of |\SmallestFactor| follows, its coding uses \csbxint{For}, -which is described later; none of this uses count registers. -% - - -\begin{everbatim*} -\let\IsPrime\undefined \let\SmallestFactor\undefined % clean up possible previous mess -\newcommand{\IsPrime}[1] % returns 1 if #1 is prime, and 0 if not - {\ifnumodd {#1} - {\ifnumless {#1}{8} - {\ifnumequal{#1}{1}{0}{1}}% 3,5,7 are primes - {\if - \xintiloop [3+2] - \ifnum#1<\numexpr\xintiloopindex*\xintiloopindex\relax - \expandafter\xintbreakiloopanddo\expandafter1\expandafter.% - \fi - \ifnum#1=\numexpr (#1/\xintiloopindex)*\xintiloopindex\relax - \else - \repeat 00\expandafter0\else\expandafter1\fi - }% - }% END OF THE ODD BRANCH - {\ifnumequal {#1}{2}{1}{0}}% EVEN BRANCH -}% -\catcode`_ 11 -\newcommand{\SmallestFactor}[1] % returns the smallest prime factor of #1>1 - {\ifnumodd {#1} - {\ifnumless {#1}{8} - {#1}% 3,5,7 are primes - {\xintiloop [3+2] - \ifnum#1<\numexpr\xintiloopindex*\xintiloopindex\relax - \xint_afterfi{\xintbreakiloopanddo#1.}% - \fi - \ifnum#1=\numexpr (#1/\xintiloopindex)*\xintiloopindex\relax - \xint_afterfi{\expandafter\xintbreakiloopanddo\xintiloopindex.}% - \fi - \iftrue\repeat - }% - }% END OF THE ODD BRANCH - {2}% EVEN BRANCH -}% -\catcode`_ 8 -{\centering - \begin{tabular}{|c|*{10}c|} - \hline - \xintFor #1 in {0,1,2,3,4,5,6,7,8,9}\do {&\bfseries #1}\\ - \hline - \bfseries 0&--&--&2&3&2&5&2&7&2&3\\ - \xintFor #1 in {1,2,3,4,5,6,7,8,9}\do - {\bfseries #1% - \xintFor #2 in {0,1,2,3,4,5,6,7,8,9}\do - {&\SmallestFactor{#1#2}}\\}% - \hline - \end{tabular}\par -} -\end{everbatim*} - -\subsection{Miller-Rabin Pseudo-Primality expandably} -\label{ssec:PrimesIV} - -This section is based on my \url{http://tex.stackexchange.com/a/165008} post. - -At the time of writing, the code at the link above is still the version from -April 2016 and it needed some hacks to get recursive (pseudo)-functions -defined. Since |1.2h| of |2016/11/20| there is \csbxint{NewFunction} which -allows us here to avoid such internal hacking. - -And since |1.3| of |2018/03/01|, it is possible to use \csbxint{defiifunc} -also for recursive definitions, so we use it here, but we can benefit from it -only for modular exponentiation as the rest of the code uses |iter| or |break| -statements which are not yet compatible with \csbxint{defiifunc}. - -The |isPseudoPrime(n)| is usable in \csbxint{iiexpr}-essions and establishes -if its (positive) argument is a Miller-Rabin PseudoPrime to the bases $2, 3, -5, 7, 11, 13, 17$. If this is true and $n<341550071728321$ (which has 15 -digits) then $n$ really is a prime number. - -Similarly $n=3825123056546413051$ (19 digits) is the smallest composite number -which is a strong pseudo prime for bases $2, 3, 5, 7, 11, 13, 17, 19$ and -$23$. It is easy to extend the code below to include these additional tests -(we could make the list of tested bases an argument too, now that I think -about it.) - -For more information see - \centeredline{\url{https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Deterministic_variants_of_the_test}} - and -\centeredline{\url{http://primes.utm.edu/prove/prove2_3.html}} - -In particular, according to \textsc{Jaeschke} \emph{On strong pseudoprimes to - several bases,} Math. Comp., 61 (1993) 915-926, if $n < 4,759,123,141$ it is -enough to establish Rabin-Miller pseudo-primality to bases $a = 2, 7, 61$ to -prove that $n$ is prime. This range is enough for \TeX\ numbers and we could -then write a very fast expandable primality test for such numbers using only -|\numexpr|. Left as an exercise\dots - -\begin{everbatim*} -% I -------------------------------- Modular Exponentiation -% Computes x^m modulo n (with m non negative). -% We will always use it with 1 < x < n - -\xintdefiifunc powmod_a(x, m, n) := - ifone(m, - % m=1, return x modulo n - x /: n, - % m > 1 test if odd or even and do recursive call - if(odd(m), (x*sqr(powmod_a(x, m//2, n))) /: n, - sqr(powmod_a(x, m//2, n)) /: n - ) - ); -\xintdefiifunc powmod(x, m, n) := if(m, powmod_a(x, m, n), 1); - -% See http://tex.stackexchange.com/a/165008 for macros written directly by a -% human. - -% For comparison here are the underlying support macros defined by -% \xintdefiifunc from the code above (since 1.3a): (with linebreaks added by -% TeX when writing to the log) - -% Function powmod_a for \xintiiexpr parser associated to \XINT_iiexpr_userfun -% c_powmod_a with meaning macro:#1#2#3->\xintiiifOne {#2}{\xintiiMod {#1}{#3}}{\x -% intiiifNotZero {\xintiiOdd {#2}}{\xintiiMod {\xintiiMul {#1}{\xintiiSqr {\xintE -% xpandArgs {XINT_iiexpr_userfunc_powmod_a}{{#1}{\xintiiDivFloor {#2}{2}}{#3}}}}} -% {#3}}{\xintiiMod {\xintiiSqr {\xintExpandArgs {XINT_iiexpr_userfunc_powmod_a}{{ -% #1}{\xintiiDivFloor {#2}{2}}{#3}}}}{#3}}} - -% Function powmod for \xintiiexpr parser associated to \XINT_iiexpr_userfunc_ -% powmod with meaning macro:#1#2#3->\xintiiifNotZero {#2}{\xintExpandArgs {XINT_i -% iexpr_userfunc_powmod_a}{{#1}{#2}{#3}}}{1} - -% II ------------------------------ Miller-Rabin compositeness witness - -% n=2^k m + 1 with m odd and k at least 1 - -% Choose 1<x<n. -% compute y=x^m modulo n -% if equals 1 we can't say anything -% if equals n-1 we can't say anything -% else put j=1, and -% compute repeatedly the square, incrementing j by 1 each time, -% thus always we have y^{2^{j-1}} -% -> if at some point n-1 mod n found, we can't say anything and break out -% -> if however we never find n-1 mod n before reaching -% z=y^{2^{k-1}} with j=k -% we then have z^2=x^{n-1}. - % Suppose z is not -1 mod n. If z^2 is 1 mod n, then n can be prime only if - % z is 1 mod n, and we can go back up, until initial y, and we have already - % excluded y=1. Thus if z is not -1 mod n and z^2 is 1 then n is not prime. - % But if z^2 is not 1, then n is not prime by Fermat. Hence (z not -1 mod n) - % implies (n is composite). (Miller test) - -% let's use again xintexpr indecipherable (except to author) syntax. Of course -% doing it with macros only would be faster. - -% Here \xintdefiifunc is not usable because not compatible with iter, break, ... -% but \xintNewFunction comes to the rescue. - -\xintNewFunction{isCompositeWitness}[4]{% x=#1, n=#2, m=#3, k=#4 - subs((y==1)?{0} - {iter(y;(j=#4)?{break(!(@==#2-1))} - {(@==#2-1)?{break(0)}{sqr(@)/:#2}},j=1++)} - ,y=powmod(#1,#3,#2))} - -% added note (2018/03/07) it is possible in the above that m=#3 is never -% zero, so we should rather call powmod_a for a small gain, but I don't -% have time to re-read the code comments and settle this. - -% III ------------------------------------- Strong Pseudo Primes - -% cf -% http://oeis.org/A014233 -% <http://mathworld.wolfram.com/Rabin-MillerStrongPseudoprimeTest.html> -% <http://mathworld.wolfram.com/StrongPseudoprime.html> - -% check if positive integer <49 si a prime. -% 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47 -\def\IsVerySmallPrime #1% - {\ifnum#1=1 \xintdothis0\fi - \ifnum#1=2 \xintdothis1\fi - \ifnum#1=3 \xintdothis1\fi - \ifnum#1=5 \xintdothis1\fi - \ifnum#1=\numexpr (#1/2)*2\relax\xintdothis0\fi - \ifnum#1=\numexpr (#1/3)*3\relax\xintdothis0\fi - \ifnum#1=\numexpr (#1/5)*5\relax\xintdothis0\fi - \xintorthat 1} - -\xintNewFunction{isPseudoPrime}[1]{% n = #1 - (#1<49)?% use ? syntax to evaluate only what is needed - {\IsVerySmallPrime{\xintthe#1}}% macro needs to be fed with #1 unlocked. - {(even(#1))? - {0} - {subs(% - % L expands to two values m, k hence isCompositeWitness does get - % its four variables x, n, m, k - isCompositeWitness(2, #1, L)? - {0}% - {isCompositeWitness(3, #1, L)? - {0}% - {isCompositeWitness(5, #1, L)? - {0}% - {isCompositeWitness(7, #1, L)? - {0}% -% above enough for N<3215031751 hence all TeX numbers - {isCompositeWitness(11, #1, L)? - {0}% -% above enough for N<2152302898747, hence all 12-digits numbers - {isCompositeWitness(13, #1, L)? - {0}% -% above enough for N<3474749660383 - {isCompositeWitness(17, #1, L)? - {0}% -% above enough for N<341550071728321 - {1}% - }% not needed to comment-out end of lines spaces inside - }% \xintexpr but this is too much of a habit for me with TeX! - }% I left some after the ? characters. - }% - }% - }% this computes (m, k) such that n = 2^k m + 1, m odd, k>=1 - , L=iter(#1//2;(even(@))?{@//2}{break(@,k)},k=1++))% - }% - }% -} - -% if needed: -%\def\IsPseudoPrime #1{\xinttheiiexpr isPseudoPrime(#1)\relax} - -\noindent The smallest prime number at least equal to 3141592653589 is -\xinttheiiexpr - seq(isPseudoPrime(3141592653589+n)? - {break(3141592653589+n)}{omit}, n=0++)\relax. -% we could not use 3141592653589++ syntax because it works only with TeX numbers -\par -\end{everbatim*} - - - - - -\subsection{A table of factorizations} -\label{ssec:factorizationtable} - -As one more example with \csbxint{iloop} let us use an alignment to display the -factorization of some numbers. The loop will actually only play a minor r\^ole -here, just handling the row index, the row contents being almost entirely -produced via a macro |\factorize|. The factorizing macro does not use -|\xintiloop| as it didn't appear to be the convenient tool. As |\factorize| will -have to be used on |\xintiloopindex|, it has been defined as a delimited macro. - -To spare some fractions of a second in the compilation time of this document -(which has many many other things to do), \number"7FFFFFED{} and -\number"7FFFFFFF, which turn out to be prime numbers, are not given to -|factorize| but just typeset directly; this illustrates use of -\csbxint{iloopskiptonext}. - -The code next generates a \hyperref[floatfactorize]{table} which has -been made into a float appearing \vpageref{floatfactorize}. Here is now -the code for factorization; the conditionals use the package provided -|\xint_firstoftwo| and |\xint_secondoftwo|, one could have employed -rather \LaTeX{}'s own |\@firstoftwo| and |\@secondoftwo|, or, simpler -still in \LaTeX{} context, the |\ifnumequal|, |\ifnumless| \dots, -utilities from the package |etoolbox| which do exactly that under the -hood. Only \TeX{} acceptable numbers are treated here, but it would be -easy to make a translation and use the \xintname macros, thus extending -the scope to big numbers; naturally up to a cost in speed. - -The reason for some strange looking expressions is to avoid arithmetic overflow. - -\begin{everbatim*} -\catcode`_ 11 -\def\abortfactorize #1\xint_secondoftwo\fi #2#3{\fi} - -\def\factorize #1.{\ifnum#1=1 \abortfactorize\fi - \ifnum\numexpr #1-2=\numexpr ((#1/2)-1)*2\relax - \expandafter\xint_firstoftwo - \else\expandafter\xint_secondoftwo - \fi - {2&\expandafter\factorize\the\numexpr#1/2.}% - {\factorize_b #1.3.}}% - -\def\factorize_b #1.#2.{\ifnum#1=1 \abortfactorize\fi - \ifnum\numexpr #1-(#2-1)*#2<#2 - #1\abortfactorize - \fi - \ifnum \numexpr #1-#2=\numexpr ((#1/#2)-1)*#2\relax - \expandafter\xint_firstoftwo - \else\expandafter\xint_secondoftwo - \fi - {#2&\expandafter\factorize_b\the\numexpr#1/#2.#2.}% - {\expandafter\factorize_b\the\numexpr #1\expandafter.% - \the\numexpr #2+2.}}% -\catcode`_ 8 -\begin{figure*}[ht!] -\centering\phantomsection\label{floatfactorize}\normalcolor -\tabskip1ex -\centeredline{\vbox{\halign {\hfil\strut#\hfil&&\hfil#\hfil\cr\noalign{\hrule} - \xintiloop ["7FFFFFE0+1] - \expandafter\bfseries\xintiloopindex & - \ifnum\xintiloopindex="7FFFFFED - \number"7FFFFFED\cr\noalign{\hrule} - \expandafter\xintiloopskiptonext - \fi - \expandafter\factorize\xintiloopindex.\cr\noalign{\hrule} - \ifnum\xintiloopindex<"7FFFFFFE - \repeat - \bfseries \number"7FFFFFFF&\number "7FFFFFFF\cr\noalign{\hrule} -}}} -\centeredline{A table of factorizations} -\end{figure*} -\end{everbatim*} - -\subsection{Another table of primes} -\label{ssec:primesIII} - -As a further example, let us dynamically generate a tabular with the first $50$ -prime numbers after $12345$. First we need a macro to test if a (short) number -is prime. Such a completely expandable macro was given in \autoref{ssec:primesI}, -here we consider a variant which will be slightly more efficient. This new -|\IsPrime| has two parameters. The first one is a macro which it redefines to -expand to the result of the primality test applied to the second argument. For -convenience we use the \href{http://ctan.org/pkg/etoolbox}{etoolbox} wrappers to -various |\ifnum| tests, although here there isn't anymore the constraint of -complete expandability (but using explicit |\if..\fi| in tabulars has its -quirks); equivalent tests are provided by \xintname, but they have some overhead -as they are able to deal with arbitrarily big integers. - -\def\IsPrime #1#2% -{\edef\TheNumber {\the\numexpr #2}% positive integer - \ifnumodd {\TheNumber} - {\ifnumgreater {\TheNumber}{1} - {\edef\ItsSquareRoot{\xintiiSqrt \TheNumber}% - \xintFor ##1 in {\xintintegers [3+2]}\do - {\ifnumgreater {##1}{\ItsSquareRoot} - {\def#1{1}\xintBreakFor} - {}% - \ifnumequal {\TheNumber}{(\TheNumber/##1)*##1} - {\def#1{0}\xintBreakFor } - {}% - }} - {\def#1{0}}}% 1 is not prime - {\ifnumequal {\TheNumber}{2}{\def#1{1}}{\def#1{0}}}% -}% - -\everb|@ -\def\IsPrime #1#2% """color[named]{PineGreen}#1=\Result, #2=tested number (assumed >0).;! -{\edef\TheNumber {\the\numexpr #2}%"""color[named]{PineGreen} hence #2 may be a count or \numexpr.;! - \ifnumodd {\TheNumber} - {\ifnumgreater {\TheNumber}{1} - {\edef\ItsSquareRoot{\xintiiSqrt \TheNumber}% - \xintFor """color{red}##1;! in {"""color{red}\xintintegers;! [3+2]}\do - {\ifnumgreater {"""color{red}##1;!}{\ItsSquareRoot} """color[named]{PineGreen}% "textcolor{red}{##1} is a \numexpr.;! - {\def#1{1}\xintBreakFor} - {}% - \ifnumequal {\TheNumber}{(\TheNumber/##1)*##1} - {\def#1{0}\xintBreakFor } - {}% - }} - {\def#1{0}}}% 1 is not prime - {\ifnumequal {\TheNumber}{2}{\def#1{1}}{\def#1{0}}}% -} -| - -As we used \csbxint{For} inside a macro we had to double the |#| in its |#1| -parameter. Here is now the code which creates the prime table (the table has -been put in a \hyperref[primes]{float}, which should be found on page -\pageref{primes}): - -\everb?@ -\newcounter{primecount} -\newcounter{cellcount} -\begin{figure*}[ht!] - \centering - \begin{tabular}{|*{7}c|} - \hline - \setcounter{primecount}{0}\setcounter{cellcount}{0}% - \xintFor """color{red}#1;! in {"""color{red}\xintintegers;! [12345+2]} \do -"""color[named]{PineGreen}% "textcolor{red}{#1} is a \numexpr.;! - {\IsPrime\Result{#1}% - \ifnumgreater{\Result}{0} - {\stepcounter{primecount}% - \stepcounter{cellcount}% - \ifnumequal {\value{cellcount}}{7} - {"""color{red}\the#1;! \\\setcounter{cellcount}{0}} - {"""color{red}\the#1;! &}} - {}% - \ifnumequal {\value{primecount}}{50} - {\xintBreakForAndDo - {\multicolumn {6}{l|}{These are the first 50 primes after 12345.}\\}} - {}% - }\hline -\end{tabular} -\end{figure*} -? - -\begin{figure*}[ht!] - \centering\phantomsection\label{primes} - \begin{tabular}{|*{7}c|} - \hline - \setcounter{primecount}{0}\setcounter{cellcount}{0}% - \xintFor #1 in {\xintintegers [12345+2]} \do - {\IsPrime\Result{#1}% - \ifnumgreater{\Result}{0} - {\stepcounter{primecount}% - \stepcounter{cellcount}% - \ifnumequal {\value{cellcount}}{7} - {\the#1 \\\setcounter{cellcount}{0}} - {\the#1 &}} - {}% - \ifnumequal {\value{primecount}}{50} - {\xintBreakForAndDo - {\multicolumn {6}{l|}{These are the first 50 primes after 12345.}\\}} - {}% - }\hline -\end{tabular} -\end{figure*} - -\subsection{Factorizing again} -\label{ssec:factorize} - -Here is an \fexpan dable macro which computes the factors of an integer. It -uses the \xintname macros only. -\begin{everbatim*} -\catcode`\@ 11 -\let\factorize\relax -\newcommand\Factorize [1] - {\romannumeral0\expandafter\factorize\expandafter{\romannumeral-`0#1}}% -\newcommand\factorize [1]{\xintiiifOne{#1}{ 1}{\factors@a #1.{#1};}}% -\def\factors@a #1.{\xintiiifOdd{#1} - {\factors@c 3.#1.}% - {\expandafter\factors@b \expandafter1\expandafter.\romannumeral0\xinthalf{#1}.}}% -\def\factors@b #1.#2.{\xintiiifOne{#2} - {\factors@end {2, #1}}% - {\xintiiifOdd{#2}{\factors@c 3.#2.{2, #1}}% - {\expandafter\factors@b \the\numexpr #1+\@ne\expandafter.% - \romannumeral0\xinthalf{#2}.}}% -}% -\def\factors@c #1.#2.{% - \expandafter\factors@d\romannumeral0\xintiidivision {#2}{#1}{#1}{#2}% -}% -\def\factors@d #1#2#3#4{\xintiiifNotZero{#2} - {\xintiiifGt{#3}{#1} - {\factors@end {#4, 1}}% ultimate quotient is a prime with power 1 - {\expandafter\factors@c\the\numexpr #3+\tw@.#4.}}% - {\factors@e 1.#3.#1.}% -}% -\def\factors@e #1.#2.#3.{\xintiiifOne{#3} - {\factors@end {#2, #1}}% - {\expandafter\factors@f\romannumeral0\xintiidivision {#3}{#2}{#1}{#2}{#3}}% -}% -\def\factors@f #1#2#3#4#5{\xintiiifNotZero{#2} - {\expandafter\factors@c\the\numexpr #4+\tw@.#5.{#4, #3}}% - {\expandafter\factors@e\the\numexpr #3+\@ne.#4.#1.}% -}% -\def\factors@end #1;{\xintlistwithsep{, }{\xintRevWithBraces {#1}}}% -\catcode`@ 12 -\end{everbatim*} -The macro will be acceptably efficient only with numbers having somewhat small -prime factors. -\begin{everbatim} -\Factorize{16246355912554185673266068721806243461403654781833} -\end{everbatim} -\begingroup\fdef\Z -{\Factorize{16246355912554185673266068721806243461403654781833}} -\noindent{\small\dtt{\Z}} - - -It puts a little stress on the input save stack in order -not be bothered with previously gathered things.\footnote{2015/11/18 I have - not revisited this code for a long time, and perhaps I could improve it now - with some new techniques.} - -Its output is a comma separated list with the number first, then its prime -factors with multiplicity. Let's produce something prettier: -\begin{everbatim*} -\catcode`_ 11 -\def\ShowFactors #1{\expandafter\ShowFactors_a\romannumeral-`0\Factorize{#1},\relax,\relax,} -\def\ShowFactors_a #1,{#1=\ShowFactors_b} -\def\ShowFactors_b #1,#2,{\if\relax#1\else#1^{#2}\expandafter\ShowFactors_b\fi} -\catcode`_ 8 -\end{everbatim*} -\begin{everbatim} -$$\ShowFactors{16246355912554185673266068721806243461403654781833}$$ -\end{everbatim} -$$\csname ShowFactors_a\expandafter\endcsname\Z,\relax,\relax,$$ -\endgroup - -If we only considered small integers, we could write pure |\numexpr| methods -which would be very much faster (especially if we had a table of small primes -prepared first) but still ridiculously slow compared to any non expandable -implementation, not to mention use of programming languages directly accessing -the CPU registers\dots - -\subsection{The Quick Sort algorithm illustrated}\label{ssec:quicksort} - -First a completely expandable macro which sorts a comma separated list of -numbers.% -% -\footnote{The code in earlier versions of this manual handled inputs composed - of braced items. I have switched to comma separated inputs on the occasion - of \url{http://tex.stackexchange.com/a/273084}. The version here is like - |code 3| on \url{http://tex.stackexchange.com} (which is about |3x| faster - than the earlier code it replaced in this manual) with a modification to - make it more efficient if the data has many repeated values. - - A faster routine (for sorting hundreds of values) is provided as |code 6| at - the link mentioned in the footnote, it is based on Merge Sort, but limited - to inputs which one can handle as \TeX{} dimensions.% - - This |code 6| could be extended to handle more general numbers, as - acceptable by \xintfracname. I have also written a non expandable version, - which is even faster, but this matters really only when handling hundreds or - rather thousands of values.} -% - -The |\QSx| macro expands its list argument, which may thus be a macro; its -comma separated items must expand to integers or decimal numbers or fractions -or scientific notation as acceptable to \xintfracname, but if an item is -itself some (expandable) macro, this macro will be expanded each time the item -is considered in a comparison test! This is actually good if the macro expands -in one step to the digits, and there are many many digits, but bad if the macro -needs to do many computations. Thus |\QSx| should be used with either explicit -numbers or with items being macros expanding in one step to the numbers -(particularly if these numbers are very big). - -If the interest is only in \TeX{} integers, then one should replace the -|\xintifCmp| macro with a suitable conditional, possibly helped by tools such as -|\ifnumgreater|, |\ifnumequal| and |\ifnumless| from -\href{http://ctan.org/pkg/etoolbox}{etoolbox} (\LaTeX{} only; I didn't see a -direct equivalent to |\xintifCmp|.) Or, if we are dealing with decimal numbers -with at most four+four digits, then one should use suitable |\ifdim| tests. -Naturally this will boost consequently the speed, from having skipped all the -overhead in parsing fractions and scientific numbers as are acceptable by -\xintfracname macros, and subsequent treatment. - -\begin{everbatim*} -% THE QUICK SORT ALGORITHM EXPANDABLY -% \usepackage{xintfrac} in the preamble (latex) -\makeatletter -% use extra safe delimiters -\catcode`! 3 \catcode`? 3 -\def\QSx {\romannumeral0\qsx }% -% first we check if empty list (else \qsx@finish will not find a comma) -\def\qsx #1{\expandafter\qsx@a\romannumeral-`0#1,!,?}% -\def\qsx@a #1{\ifx,#1\expandafter\qsx@abort\else - \expandafter\qsx@start\fi #1}% -\def\qsx@abort #1?{ }% -\def\qsx@start {\expandafter\qsx@finish\romannumeral0\qsx@b,}% -\def\qsx@finish ,#1{ #1}% -% -% we check if empty of single and if not pick up the first as Pivot: -\def\qsx@b ,#1#2,#3{\ifx?#3\xintdothis\qsx@empty\fi - \ifx!#3\xintdothis\qsx@single\fi - \xintorthat\qsx@separate {#1#2}{}{}{#1#2}#3}% -\def\qsx@empty #1#2#3#4#5{ }% -\def\qsx@single #1#2#3#4#5?{, #4}% -\def\qsx@separate #1#2#3#4#5#6,% -{% - \ifx!#5\expandafter\qsx@separate@done\fi - \xintifCmp {#5#6}{#4}% - \qsx@separate@appendtosmaller - \qsx@separate@appendtoequal - \qsx@separate@appendtogreater {#5#6}{#1}{#2}{#3}{#4}% -}% -% -\def\qsx@separate@appendtoequal #1#2{\qsx@separate {#2,#1}}% -\def\qsx@separate@appendtogreater #1#2#3{\qsx@separate {#2}{#3,#1}}% -\def\qsx@separate@appendtosmaller #1#2#3#4{\qsx@separate {#2}{#3}{#4,#1}}% -% -\def\qsx@separate@done\xintifCmp #1% - \qsx@separate@appendtosmaller - \qsx@separate@appendtoequal - \qsx@separate@appendtogreater #2#3#4#5#6#7?% -{% - \expandafter\qsx@f\expandafter {\romannumeral0\qsx@b #4,!,?}{\qsx@b #5,!,?}{#3}% -}% -% -\def\qsx@f #1#2#3{#2, #3#1}% -% -\catcode`! 12 \catcode`? 12 -\makeatother - -% EXAMPLE -\begingroup -\edef\z {\QSx {1.0, 0.5, 0.3, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, - 1.3, 1.1, 0.7, 1.6, 0.6, 0.9, 0.8, 0.2, 0.1, 1.9}} -\meaning\z - -\def\a {3.123456789123456789}\def\b {3.123456789123456788} -\def\c {3.123456789123456790}\def\d {3.123456789123456787} -\oodef\z {\QSx { \a, \b, \c, \d}}% -% The space before \a to let it not be expanded during the conversion from CSV -% values to List. The \oodef expands exactly twice (via a bunch of \expandafter's) -\meaning\z -\endgroup -\end{everbatim*} (the spaces after \string\d, etc... come from the use of the -|\meaning| primitive.) - -The choice of pivot as first element is bad if the list is already almost -sorted. Let's add a variant which will pick up the pivot index randomly. The -previous routine worked also internally with comma separated lists, but for a -change this one will use internally lists of braced items (the initial -conversion via \csbxint{CSVtoList} handles all potential spurious space -problems). - -\unless\ifxetex % pour tester compilation de xint.dtx avec xetex qui n'a pas - % \pdfuniformdeviate -\begin{everbatim*} -% QuickSort expandably on comma separated values with random choice of pivots -% ====> Requires availability of \pdfuniformdeviate <==== -% \usepackage{xintfrac, xinttools} in preamble -\makeatletter -\def\QSx {\romannumeral0\qsx }% This is a f-expandable macro. -% This converts from comma separated values on input and back on output. -% **** NOTE: these steps (and the other ones too, actually) are costly if input -% has thousands of items. -\def\qsx #1{\xintlistwithsep{, }% - {\expandafter\qsx@sort@a\expandafter{\romannumeral0\xintcsvtolist{#1}}}}% -% -% we check if empty or single or double and if not pick up the first as Pivot: -\def\qsx@sort@a #1% - {\expandafter\qsx@sort@b\expandafter{\romannumeral0\xintlength{#1}}{#1}}% -\def\qsx@sort@b #1{\ifcase #1 - \expandafter\qsx@sort@empty - \or\expandafter\qsx@sort@single - \or\expandafter\qsx@sort@double - \else\expandafter\qsx@sort@c\fi {#1}}% -\def\qsx@sort@empty #1#2{ }% -\def\qsx@sort@single #1#2{#2}% -\catcode`_ 11 -\def\qsx@sort@double #1#2{\xintifGt #2{\xint_exchangetwo_keepbraces}{}#2}% -\catcode`_ 8 -\def\qsx@sort@c #1#2{% - \expandafter\qsx@sort@sep@a\expandafter - {\romannumeral0\xintnthelt{\pdfuniformdeviate #1+\@ne}{#2}}#2?}% -\def\qsx@sort@sep@a #1{\qsx@sort@sep@loop {}{}{}{#1}}% -\def\qsx@sort@sep@loop #1#2#3#4#5% -{% - \ifx?#5\expandafter\qsx@sort@sep@done\fi - \xintifCmp {#5}{#4}% - \qsx@sort@sep@appendtosmaller - \qsx@sort@sep@appendtoequal - \qsx@sort@sep@appendtogreater {#5}{#1}{#2}{#3}{#4}% -}% -% -\def\qsx@sort@sep@appendtoequal #1#2{\qsx@sort@sep@loop {#2{#1}}}% -\def\qsx@sort@sep@appendtogreater #1#2#3{\qsx@sort@sep@loop {#2}{#3{#1}}}% -\def\qsx@sort@sep@appendtosmaller #1#2#3#4{\qsx@sort@sep@loop {#2}{#3}{#4{#1}}}% -% -\def\qsx@sort@sep@done\xintifCmp #1% - \qsx@sort@sep@appendtosmaller - \qsx@sort@sep@appendtoequal - \qsx@sort@sep@appendtogreater #2#3#4#5#6% -{% - \expandafter\qsx@sort@recurse\expandafter - {\romannumeral0\qsx@sort@a {#4}}{\qsx@sort@a {#5}}{#3}% -}% -% -\def\qsx@sort@recurse #1#2#3{#2#3#1}% -% -\makeatother - -% EXAMPLES -\begingroup -\edef\z {\QSx {1.0, 0.5, 0.3, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, - 1.3, 1.1, 0.7, 1.6, 0.6, 0.9, 0.8, 0.2, 0.1, 1.9}} -\meaning\z - -\def\a {3.123456789123456789}\def\b {3.123456789123456788} -\def\c {3.123456789123456790}\def\d {3.123456789123456787} -\oodef\z {\QSx { \a, \b, \c, \d}}% -% The space before \a to let it not be expanded during the conversion from CSV -% values to List. The \oodef expands exactly twice (via a bunch of \expandafter's) -\meaning\z - -\def\somenumbers{% -3997.6421, 8809.9358, 1805.4976, 5673.6478, 3179.1328, 1425.4503, 4417.7691, -2166.9040, 9279.7159, 3797.6992, 8057.1926, 2971.9166, 9372.2699, 9128.4052, -1228.0931, 3859.5459, 8561.7670, 2949.6929, 3512.1873, 1698.3952, 5282.9359, -1055.2154, 8760.8428, 7543.6015, 4934.4302, 7526.2729, 6246.0052, 9512.4667, -7423.1124, 5601.8436, 4433.5361, 9970.4849, 1519.3302, 7944.4953, 4910.7662, -3679.1515, 8167.6824, 2644.4325, 8239.4799, 4595.1908, 1560.2458, 6098.9677, -3116.3850, 9130.5298, 3236.2895, 3177.6830, 5373.1193, 5118.4922, 2743.8513, -8008.5975, 4189.2614, 1883.2764, 9090.9641, 2625.5400, 2899.3257, 9157.1094, -8048.4216, 3875.6233, 5684.3375, 8399.4277, 4528.5308, 6926.7729, 6941.6278, -9745.4137, 1875.1205, 2755.0443, 9161.1524, 9491.1593, 8857.3519, 4290.0451, -2382.4218, 3678.2963, 5647.0379, 1528.7301, 2627.8957, 9007.9860, 1988.5417, -2405.1911, 5065.8063, 5856.2141, 8989.8105, 9349.7840, 9970.3013, 8105.4062, -3041.7779, 5058.0480, 8165.0721, 9637.7196, 1795.0894, 7275.3838, 5997.0429, -7562.6481, 8084.0163, 3481.6319, 8078.8512, 2983.7624, 3925.4026, 4931.5812, -1323.1517, 6253.0945}% - -\oodef\z {\QSx \somenumbers}% produced as a comma+space separated list -% black magic as workaround to the shrinkability of spaces in last line... -\hsize 87\fontcharwd\font`0 -\lccode`~=32 -\lowercase{\def~}{\discretionary{}{}{\kern\fontcharwd\font`0}}\catcode32 13 -\noindent\phantom{000}\scantokens\expandafter{\meaning\z}\par -\endgroup -\end{everbatim*} -\fi % fin de si pas xetex - - -All the previous examples were with numbers which could have been handled via -|\ifdim| tests rather than the \csbxint{ifCmp} macro from \xintfracname; using -|\ifdim| tests would naturally be faster. Even faster routine is |code 6| at -\url{http://tex.stackexchange.com/a/273084} which uses |\pdfescapestring| and a -Merge Sort algorithm. - -We then turn to a graphical illustration of the algorithm.% -% -\footnote{I have rewritten (2015/11/21) the routine to do only once (and not thrice) the - needed calls to \csa{xintifCmp}, up to the price of one additional |\edef|, - although due to the context execution time on our side is not an issue and - moreover is anyhow overwhelmed by the TikZ's activities. Simultaneously I - have updated the code \url{http://tex.stackexchange.com/a/142634/4686}. The - variant with the choice of pivot on the right has more overhead: the reason - is simply that we do not convert the data into an array, but maintain a list - of tokens with self-reorganizing delimiters.} -% -For simplicity the pivot is always chosen as the first list item. Then we also -give a variant which picks up the last item as pivot. -\begin{everbatim*} -% in LaTeX preamble: -% \usepackage{xintfrac, xinttools} -% \usepackage{color} -% or, when using Plain TeX: -% \input xintfrac.sty \input xinttools.sty -% \input color.tex -% -% Color definitions -\definecolor{LEFT}{RGB}{216,195,88} -\definecolor{RIGHT}{RGB}{208,231,153} -\definecolor{INERT}{RGB}{199,200,194} -\definecolor{INERTpiv}{RGB}{237,237,237} -\definecolor{PIVOT}{RGB}{109,8,57} -% Start of macro defintions -\makeatletter -% \catcode`? 3 % a bit too paranoid. Normal ? will do. -% -% argument will never be empty -\def\QS@cmp@a #1{\QS@cmp@b #1??}% -\def\QS@cmp@b #1{\noexpand\QS@sep@A\@ne{#1}\QS@cmp@d {#1}}% -\def\QS@cmp@d #1#2{\ifx ?#2\expandafter\QS@cmp@done\fi - \xintifCmp {#1}{#2}\tw@\@ne\z@{#2}\QS@cmp@d {#1}}% -\def\QS@cmp@done #1?{?}% -% -\def\QS@sep@A #1?{\QSLr\QS@sep@L #1\thr@@?#1\thr@@?#1\thr@@?}% -\def\QS@sep@L #1#2{\ifcase #1{#2}\or\or\else\expandafter\QS@sep@I@start\fi \QS@sep@L}% -\def\QS@sep@I@start\QS@sep@L {\noexpand\empty?\QSIr\QS@sep@I}% -\def\QS@sep@I #1#2{\ifcase#1\or{#2}\or\else\expandafter\QS@sep@R@start\fi\QS@sep@I}% -\def\QS@sep@R@start\QS@sep@I {\noexpand\empty?\QSRr\QS@sep@R}% -\def\QS@sep@R #1#2{\ifcase#1\or\or{#2}\else\expandafter\QS@sep@done\fi\QS@sep@R}% -\def\QS@sep@done\QS@sep@R {\noexpand\empty?}% -% -\def\QS@loop {% - \xintloop - % pivot phase - \def\QS@pivotcount{0}% - \let\QSLr\DecoLEFTwithPivot \let\QSIr \DecoINERT - \let\QSRr\DecoRIGHTwithPivot \let\QSIrr\DecoINERT - \centerline{\QS@list}% - % sorting phase - \ifnum\QS@pivotcount>\z@ - \def\QSLr {\QS@cmp@a}\def\QSRr {\QS@cmp@a}% - \def\QSIr {\QSIrr}\let\QSIrr\relax - \edef\QS@list{\QS@list}% compare - \let\QSLr\relax\let\QSRr\relax\let\QSIr\relax - \edef\QS@list{\QS@list}% separate - \def\QSLr ##1##2?{\ifx\empty##1\else\noexpand \QSLr {{##1}##2}\fi}% - \def\QSIr ##1##2?{\ifx\empty##1\else\noexpand \QSIr {{##1}##2}\fi}% - \def\QSRr ##1##2?{\ifx\empty##1\else\noexpand \QSRr {{##1}##2}\fi}% - \edef\QS@list{\QS@list}% gather - \let\QSLr\DecoLEFT \let\QSRr\DecoRIGHT - \let\QSIr\DecoINERTwithPivot \let\QSIrr\DecoINERT - \centerline{\QS@list}% - \repeat }% -% -% \xintFor* loops handle gracefully empty lists. -\def\DecoLEFT #1{\xintFor* ##1 in {#1} \do {\colorbox{LEFT}{##1}}}% -\def\DecoINERT #1{\xintFor* ##1 in {#1} \do {\colorbox{INERT}{##1}}}% -\def\DecoRIGHT #1{\xintFor* ##1 in {#1} \do {\colorbox{RIGHT}{##1}}}% -\def\DecoPivot #1{\begingroup\color{PIVOT}\advance\fboxsep-\fboxrule\fbox{#1}\endgroup}% -% -\def\DecoLEFTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% - \xintFor* ##1 in {#1} \do - {\xintifForFirst {\DecoPivot {##1}}{\colorbox{LEFT}{##1}}}}% -\def\DecoINERTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% - \xintFor* ##1 in {#1} \do - {\xintifForFirst {\colorbox{INERTpiv}{##1}}{\colorbox{INERT}{##1}}}}% -\def\DecoRIGHTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% - \xintFor* ##1 in {#1} \do - {\xintifForFirst {\DecoPivot {##1}}{\colorbox{RIGHT}{##1}}}}% -% -\def\QuickSort #1{% warning: not compatible with empty #1. - % initialize, doing conversion from comma separated values to a list of braced items - \edef\QS@list{\noexpand\QSRr{\xintCSVtoList{#1}}}% many \edef's are to follow anyhow -% earlier I did a first drawing of the list, here with the color of RIGHT elements, -% but the color should have been for example white, anyway I drop this first line - %\let\QSRr\DecoRIGHT - %\par\centerline{\QS@list}% -% - % loop as many times as needed - \QS@loop }% -% -% \catcode`? 12 % in case we had used a funny ? as delimiter. -\makeatother -%% End of macro definitions. -%% Start of Example -\begingroup\offinterlineskip -\small -% \QuickSort {1.0, 0.5, 0.3, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, -% 1.3, 1.1, 0.7, 1.6, 0.6, 0.9, 0.8, 0.2, 0.1, 1.9} -% \medskip -% with repeated values -\QuickSort {1.0, 0.5, 0.3, 0.8, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, - 1.3, 1.1, 0.7, 0.3, 1.6, 0.6, 0.3, 0.8, 0.2, 0.8, 0.7, 1.2} -\endgroup -\end{everbatim*} - -Here is the variant which always picks the pivot as the rightmost element. - -\begin{everbatim*} -\makeatletter -% -\def\QS@cmp@a #1{\noexpand\QS@sep@A\expandafter\QS@cmp@d\expandafter - {\romannumeral0\xintnthelt{-1}{#1}}#1??}% -% -\def\DecoLEFTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% - \xintFor* ##1 in {#1} \do - {\xintifForLast {\DecoPivot {##1}}{\colorbox{LEFT}{##1}}}} -\def\DecoINERTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% - \xintFor* ##1 in {#1} \do - {\xintifForLast {\colorbox{INERTpiv}{##1}}{\colorbox{INERT}{##1}}}} -\def\DecoRIGHTwithPivot #1{\xdef\QS@pivotcount{\the\numexpr\QS@pivotcount+\@ne}% - \xintFor* ##1 in {#1} \do - {\xintifForLast {\DecoPivot {##1}}{\colorbox{RIGHT}{##1}}}} -\def\QuickSort #1{% - % initialize, doing conversion from comma separated values to a list of braced items - \edef\QS@list{\noexpand\QSLr {\xintCSVtoList{#1}}}% many \edef's are to follow anyhow - % - % loop as many times as needed - \QS@loop }% -\makeatother -\begingroup\offinterlineskip -\small -% \QuickSort {1.0, 0.5, 0.3, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, -% 1.3, 1.1, 0.7, 1.6, 0.6, 0.9, 0.8, 0.2, 0.1, 1.9} -% \medskip -% with repeated values -\QuickSort {1.0, 0.5, 0.3, 0.8, 1.5, 1.8, 2.0, 1.7, 0.4, 1.2, 1.4, - 1.3, 1.1, 0.7, 0.3, 1.6, 0.6, 0.3, 0.8, 0.2, 0.8, 0.7, 1.2} -\endgroup -\end{everbatim*} - -The choice of the first or last item as pivot is not a good one as nearly -ordered lists will take quadratic time. But for explaining the algorithm via a -graphical interpretation, it is not that bad. If one wanted to pick up the -pivot randomly, the routine would have to be substantially rewritten: in -particular the |\Deco..withPivot| macros need to know where the pivot is, and -currently this is implemented by using either |\xintifForFirst| or -|\xintifForLast|. - -\etocdepthtag.toc {macros} -\addtocontents{toc}{\gdef\string\sectioncouleur{{joli}}} -\addtocontents{toc}{\gdef\string\SKIPSECTIONINTERSPACE{\kern\smallskipamount}} -\renewcommand{\etocaftertochook}{\addvspace{\bigskipamount}} - \clearpage -\def\n{|{N}|} -\def\m{|{M}|} -\def\x{|{x}|} +\let\xintbundlenameUp\undefined \csname xintkernelnameUp\endcsname \section{Macros of the \xintkernelname package} \RaisedLabel{sec:kernel} @@ -9702,24 +10743,63 @@ which first \fexpan ds its argument and then applies the same code. \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.\NewWith{1.4} + +It does no expansion. For this and the next similar ones, see +|sourcexint.pdf| for comments on limitations. + \subsection{\csh{xintLastItem}} \label{xintLastItem} -\csa{xintLastItem}\marg{list}\etype{n} returns the last item (unbraced) of its -argument. If the list has no items the output is empty. +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{xintreplicate}} +\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.\NewWith{1.4} + +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.\NewWith{1.4} + +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}'s answer to \url{http://tex.stackexchange.com/questions/16189/repeat-command-n-times}.} +\footnote{I started with the code from Joseph \textsc{Wright} +available on an online site.} + +And \csa{xintReplicate}|{x}| integrates the +\csa{romannumeeral} prefix.\NewWith{1.4} + 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 @@ -9730,14 +10810,16 @@ and does nothing.% Note that expansion must be triggered by a |\romannumeral|. -\subsection{\csh{xintgobble}} +\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}.\NewWith{1.4} Note that expansion must be triggered by a |\romannumeral|. @@ -9763,7 +10845,7 @@ its salt compared to \csbxint{Length}. \footnote{The |\uniformdeviate| primitive has been added to Xe\TeX\ and will be available with \TeX Live 2019 release.} The implementation is to be -considered experimental for the time being.\NewWith{1.3b}% +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 @@ -9824,30 +10906,19 @@ be bounded by \dtt{$x/2^{56}$}.% With such a small non-uniformity, modulo phenomena as mentioned earlier are not observable in reasonable computing time.% % -\footnote{The function \func{qraw} is used here not so much to speed up the - loop expansion, but in relation to \autoref{ssec:memory} to avoid too much - usage of |\csname...\endcsname| storage. Besides, if we had used |mod3| - function we would have needed |\xinttheiiexpr mod3(\pdfun...)\relax| - wrapping for each individual macro. So we decided rather to use a macro - |\ModThree|; of course we could have used |\numexpr|, with the technical - problem to expand only once |\pdfuniformdeviate|, which would have led to - some extra manoeuver, so ok for |\ModThree|.} -% \begin{everbatim*} %\xintdefiifunc mod3(x):= x 'mod' 3; \xintNewIIExpr\ModThree[1]{#1 'mod' 3} \pdfsetrandomseed 87654321 \xintdefiivar BadDigits:=qraw(% - \romannumeral\xintreplicate{503}{\ModThree{\pdfuniformdeviate "C000000},}% - \ModThree{\pdfuniformdeviate "C000000}% -);% 504=503+1 + \romannumeral\xintreplicate{504}{{\ModThree{\pdfuniformdeviate "C000000}}}% +);% \pdfsetrandomseed 87654321 \xintdefiivar GoodDigits:=qraw(% - \romannumeral\xintreplicate{503}{\ModThree{\xintUniformDeviate{"C000000}},}% - \ModThree{\xintUniformDeviate{"C000000}}% -);% 504=503+1 + \romannumeral\xintreplicate{504}{{\ModThree{\xintUniformDeviate{"C000000}}}}% +);% These 504 digits generated from \string\pdfuniformdeviate: \xinttheiiexpr BadDigits\relax\hfill\break @@ -9978,26 +11049,27 @@ strict integer format on output, except:\IMPORTANT input and which truncates them to integers. \end{itemize} -Most removed macros listed in \autoref{ssec:coredeprecated} were by design -applying \csbxint{Num} to their inputs. Typically these macros had a single -|i| in their names, for example \csa{xintiAdd} was such a companion to -\csa{xintiiAdd}. \xintfracname redefined \csbxint{Num} to be the macro -accepting general fractional input and truncating it to an integer. Hence a -macro such as \csa{xintiAdd} was compatible with the output format of -\xintfracname macros, contrarily to \csbxint{iiAdd} which handles only strict -integer format for its inputs. Of course, \xintfracname defined also its own -\csbxint{Add} which did the addition of its arguments without truncating them -to integers... but whose output format is the |A/B[N]| format explained in -\autoref{ssec:outputs}, hence even if representing a small integer it can not -be used directly in a \TeX\ context such as |\ifnum|, contrarily to -\csa{xintiAdd} or to \csbxint{iiAdd}. +% Most removed macros listed in \autoref{ssec:coredeprecated} were by design +% applying \csbxint{Num} to their inputs. Typically these macros had a single +% |i| in their names, for example \csa{xintiAdd} was such a companion to +% \csa{xintiiAdd}. \xintfracname redefined \csbxint{Num} to be the macro +% accepting general fractional input and truncating it to an integer. Hence a +% macro such as \csa{xintiAdd} was compatible with the output format of +% \xintfracname macros, contrarily to \csbxint{iiAdd} which handles only strict +% integer format for its inputs. Of course, \xintfracname defined also its own +% \csbxint{Add} which did the addition of its arguments without truncating them +% to integers... but whose output format is the |A/B[N]| format explained in +% \autoref{ssec:outputs}, hence even if representing a small integer it can not +% be used directly in a \TeX\ context such as |\ifnum|, contrarily to +% \csa{xintiAdd} or to \csbxint{iiAdd}. + +% \begin{framed} +% This situation was the result of some early-on design +% decisions which now appear misguided and impede further development. Hence, +% at |1.2o| it has been decided to deprecate \emph{all} such |i|-macros. And +% they got removed from the package at |1.3|. +% \end{framed} -\begin{framed} - This situation was the result of some early-on design - decisions which now appear misguided and impede further development. Hence, - at |1.2o| it has been decided to deprecate \emph{all} such |i|-macros. And - they got removed from the package at |1.3|.\CHANGEDf{1.3} -\end{framed} The |ii| in the names of the macros such as \csbxint{iiAdd} serves to stress that they accept only strict integers as input (this is signaled by the margin annotation \textcolor[named]{PineGreen}{\emph{f}}), or macros \fexpan ding to @@ -10006,10 +11078,12 @@ 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.% +input and format of output as the |ii|-macros. + % -\footnote{Regarding \csbxint{FDg} and \csbxint{LDg}, this is a breaking change - because formerly they used \csbxint{Num}.} +% % +% \footnote{Regarding \csbxint{FDg} and \csbxint{LDg}, this is a breaking change +% because formerly they used \csbxint{Num}.} The letter \texttt{x} (with margin annotation \smash{\textcolor[named]{PineGreen}{\numx}}) stands for an argument which will @@ -10241,29 +11315,29 @@ retained as \csa{xintiiModTrunc}. more general inputs. It then becomes an alias to \csbxint{TTrunc} which truncates the general input to an integer in strict format. -\subsection{Removed macros}\label{ssec:coredeprecated} - -These macros were deprecated at |1.2o| and removed at |1.3|.\CHANGED{1.3} -|\xintiiFDg| (renamed to \csbxint{FDg}), -|\xintiiLDg| (renamed to \csbxint{LDg}), -|\xintiOpp|, -|\xintiAbs|, -|\xintiAdd|, -|\xintCmp| (it gets defined by \xintfracname, so deprecation will usually not be -seen; the macro with this name from former \xintcorename should have been -called |\xintiCmp| actually), -|\xintSgn| (it also gets its proper definition from \xintfracname), -|\xintiSub|, -|\xintiMul|, -|\xintiDivision|, -|\xintiQuo|, -|\xintiRem|, -|\xintiDivRound|, -|\xintiDivTrunc|, -|\xintiMod|, -|\xintiSqr|, -|\xintiPow|, -|\xintiFac|. +% \subsection{Removed macros}\label{ssec:coredeprecated} + +% These macros were deprecated at |1.2o| and removed at |1.3|. +% |\xintiiFDg| (renamed to \csbxint{FDg}), +% |\xintiiLDg| (renamed to \csbxint{LDg}), +% |\xintiOpp|, +% |\xintiAbs|, +% |\xintiAdd|, +% |\xintCmp| (it gets defined by \xintfracname, so deprecation will usually not be +% seen; the macro with this name from former \xintcorename should have been +% called |\xintiCmp| actually), +% |\xintSgn| (it also gets its proper definition from \xintfracname), +% |\xintiSub|, +% |\xintiMul|, +% |\xintiDivision|, +% |\xintiQuo|, +% |\xintiRem|, +% |\xintiDivRound|, +% |\xintiDivTrunc|, +% |\xintiMod|, +% |\xintiSqr|, +% |\xintiPow|, +% |\xintiFac|. \clearpage @@ -10323,7 +11397,7 @@ example. Prior to release |1.2o|, \xintname defined additional macros which applied \csbxint{Num} to their input arguments. All these macros were deprecated at -|1.2o| and have been removed at |1.3|.\CHANGED{1.3} +|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 @@ -10372,14 +11446,6 @@ upfront in the output. \end{everbatim*} \endgroup -\subsection{\csh{xintiiGCD}} - -This is the same as the \csbxint{iiGCD} from package \xintgcdname. - -\subsection{\csh{xintiiLCM}} - -This is the same as the \csbxint{iiLCM} from package \xintgcdname. - \subsection{\csh{xintDecSplit}} \label{xintDecSplit} @@ -10863,56 +11929,123 @@ argument may be a macro, it is \fexpan ded first. 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{Removed macros (they require \xintfracname)}\label{ssec:xintdeprecated} - -These macros now require \xintfracname. They have been removed from \xintname -at |1.3|.\CHANGED{1.3} -|\xintEq|, -|\xintNeq|, -|\xintGeq|, -|\xintGt|, -|\xintLt|, -|\xintGtorEq|, -|\xintLtorEq|, -|\xintIsZero|, -|\xintIsNotZero|, -|\xintIsOne|, -|\xintOdd|, -|\xintEven|, -|\xintifSgn|, -|\xintifCmp|, -|\xintifEq|, -|\xintifGt|, -|\xintifLt|, -|\xintifZero|, -|\xintifNotZero|, -|\xintifOne|, -|\xintifOdd|. - -With the exception of |\xintNeq| which was renamed to |\xintNotEq|, the above -listed macros all belong to \xintfracname. - -\subsection{Removed macros (they used \csh{xintNum})}\label{ssec:xintdeprecatedNum} - -These macros filtered their arguments via \csbxint{Num}. They got deprecated -at |1.2o| and removed at |1.3|:\CHANGED{1.3} -|\xintMON|, -|\xintMMON|, -|\xintiMax|, -|\xintiMin|, -|\xintiMaxof|, -|\xintiMinof|, -|\xintiSquareRoot|, -|\xintiSqrt|, -|\xintiSqrtR|, -|\xintiBinomial|, -|\xintiPFactorial|. +% \subsection{Removed macros (they require \xintfracname)}\label{ssec:xintdeprecated} + +% These macros now require \xintfracname. They have been removed from \xintname +% at |1.3|. +% |\xintEq|, +% |\xintNeq|, +% |\xintGeq|, +% |\xintGt|, +% |\xintLt|, +% |\xintGtorEq|, +% |\xintLtorEq|, +% |\xintIsZero|, +% |\xintIsNotZero|, +% |\xintIsOne|, +% |\xintOdd|, +% |\xintEven|, +% |\xintifSgn|, +% |\xintifCmp|, +% |\xintifEq|, +% |\xintifGt|, +% |\xintifLt|, +% |\xintifZero|, +% |\xintifNotZero|, +% |\xintifOne|, +% |\xintifOdd|. + +% With the exception of |\xintNeq| which was renamed to |\xintNotEq|, the above +% listed macros all belong to \xintfracname. + +% At |1.4|, these macros formerly available via \xintgcdname have been moved to +% \xintfracname as well. +% |\xintGCD|, +% |\xintLCM|, +% |\xintGCDof|, +% |\xintLCMof|. + +% \subsection{Removed macros (they used \csh{xintNum})}\label{ssec:xintdeprecatedNum} + +% These macros filtered their arguments via \csbxint{Num}. They got deprecated +% at |1.2o| and removed at |1.3|: +% |\xintMON|, +% |\xintMMON|, +% |\xintiMax|, +% |\xintiMin|, +% |\xintiMaxof|, +% |\xintiMinof|, +% |\xintiSquareRoot|, +% |\xintiSqrt|, +% |\xintiSqrtR|, +% |\xintiBinomial|, +% |\xintiPFactorial|. + +\subsection{(WIP) \csh{xintRandomDigits}}\label{xintRandomDigits} \begin{framed} All randomness related macros are Work-In-Progress: implementation and user @@ -10921,11 +12054,9 @@ at |1.2o| and removed at |1.3|:\CHANGED{1.3} \csbxint{UniformDeviate} for additional information. \end{framed} -\subsection{(WIP) \csh{xintRandomDigits}}\label{xintRandomDigits} - |\xintRandomDigits{N}|\etype{\numx} expands in two steps to |N| random decimal digits. The argument must be non-negative and is limited by \TeX\ memory -parameters.\NewWith{1.3b} +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). @@ -10943,7 +12074,7 @@ result from \csbxint{UniformDeviate}|{100000000}| but with less overhead. |\xintXRandomDigits{N}|\retype{\numx} expands under exhaustive expansion (|\edef|, |\write|, |\csname| ...) to |N| random decimal -digits. The argument must be non-negative.\NewWith{1.3b} +digits. The argument must be non-negative. For example: \begin{everbatim} \newwrite\out @@ -10974,7 +12105,7 @@ result from \csbxint{UniformDeviate}|{100000000}| but with less overhead. |\xintiiRandRange{A}|\etype{f} expands to a random (big) integer |N| such that |0<=N<A|. It is a supporting macro for \func{randrange}. As with -Python's function of the same name, it is an error if |A<=0|.\NewWith{1.3b} +Python's function of the same name, it is an error if |A<=0|. \begin{everbatim*} \pdfsetrandomseed 271828314 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\newline @@ -11007,7 +12138,7 @@ result from \csbxint{UniformDeviate}|{100000000}| but with less overhead. |\xintiiRandRangeAtoB{A}{B}|\etype{ff} expands to a random (big) integer |N| such that |A<=N<B|. It is a supporting macro for \func{randrange}. As with -Python's function of the same name, it is an error if |B<=A|.\NewWith{1.3b} +Python's function of the same name, it is an error if |B<=A|. \begin{everbatim*} \pdfsetrandomseed 271828314 12345678911111111111111111111\newline @@ -11035,7 +12166,7 @@ First version of this package was in release |1.03| (|2013/04/14|) of the \xintname bundle. At release |1.3| (|2018/02/28|) the behaviour of \csbxint{Add} (and of -\csbxint{Sub}) was modified:\CHANGED{1.3} when adding |a/b| and |c/d| they +\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 @@ -11177,7 +12308,7 @@ trailing |/1|. This puts the fraction\etype{\Ff} into irreducible form, \emph{keeping as is the - decimal part} |[N]| from raw internal |A/B[N]| format.\NewWith{1.3} + 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]} @@ -11223,16 +12354,35 @@ from removing the |[N]| part if |N=0| and removing the |B| if |B=1|. \xintPRaw {123e10/321e10}, \xintPRaw {123e9/321e10}, \xintPRaw {\xintIrr{861/123}} \end{everbatim*} +\subsection{\csh{xintFracToSci}}\label{xintFracToSci} + +\csa{FracToSci}\etype{\Ff} is not really part of public interface. It is a +macro used by \csbxint{expr} for output, on data which is guaranteed to be +in raw \xintfracname format (apart from lacking possibly a denominator and/or the +|[N]| postfix). It is basically like \csbxint{PRaw} but +using scientific notation in the output.\NewWith{1.4} + +Use with care, and always with the argument nested in at least one +\xintfracname macro, such as \csbxint{Raw} or \csbxint{Irr}. + +\begin{everbatim*} +\xintFracToSci {\xintRaw{123e10/321e10}}, +\xintFracToSci {\xintRaw{123e9/321e10}}, +\xintFracToSci {\xintIrr{861/123}} +\end{everbatim*} + \subsection{\csh{xintDecToString}}\label{xintDecToString} This is\etype{\Ff} a macro tailored for printing decimal numbers. It does not trim trailing zeros, use |\xintDecToString{\xintREZ{<foo>}}| for that. -\NewWith{1.3} + \begin{everbatim*} \xintDecToString {123456789e5}\newline \xintDecToString {123456789e-5}\newline \xintDecToString {12345e-10}\newline -\xintDecToString {12345e-10/123}\par % just leave denominator as is +\xintDecToString {12345e-10/123}\newline % leaves the denominator as is +\xintDecToString {1234567890000e-6}\newline % does not trim trailing zeros +\xintDecToString {\xintREZ{1234567890000e-6}}\par % does trim trailing zeros \end{everbatim*} Consider it an unstable macro, what it does exactly is yet to be decided. It is a backport from \href{http://ctan.org/pkg/polexpr}{polexpr}'s @@ -11717,7 +12867,7 @@ where |\xintiiAbs {-2}| outputs \dtt{=\xintiiAbs {-2}}. Computes the addition\etype{\Ff\Ff} of two fractions. Since |1.3| always uses the least common multiple of the -denominators.\CHANGED{1.3} +denominators. \subsection{\csh{xintSub}}\label{xintSub} @@ -11725,7 +12875,7 @@ Computes the difference\etype{\Ff\Ff} of two fractions (|\xintSub{F}{G}| computes |F-G|). Since |1.3| always uses the least common multiple of the -denominators.\CHANGED{1.3} +denominators. \subsection{\csh{xintMul}}\label{xintMul} @@ -11762,7 +12912,7 @@ Computes the remainder associated to the floored division\etype{\Ff\Ff} \end{everbatim*} Modified at |1.3| to use a l.c.m. for the denominator of the result. -\CHANGED{1.3} + \subsection{\csh{xintDivMod}} \label{xintDivMod} @@ -11793,7 +12943,7 @@ got associated with floored division. \end{everbatim*} Modified at |1.3| to use a l.c.m. for the denominator of the result. -\CHANGED{1.3} + \subsection{\csh{xintDivRound}} \label{xintDivRound} @@ -11919,6 +13069,53 @@ No simplification attempted. $\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} + +A macro of the same name existed formerly in \xintgcdname but it truncated +its arguments to integers via \csbxint{Num}. + +\subsection{\csh{xintLCM}}\label{xintLCM} + +The least common multiple of its two arguments, which are possibly +\emph{fractions}.\etype{\Ff\Ff} + +A macro of the same name existed formerly in \xintgcdname but it truncated +its arguments to integers via \csbxint{Num}. + +\subsection{\csh{xintGCDof}}\label{xintGCDof} + +\csa{xintGCDof}|{{a}{b}{c}...}|\etype{f{$\to$}{\lowast\Ff}} computes the +greatest common divisor of a|a|, |b|, \dots{}, which are +possibly\emph{fractions} (i.e. the non-negative generator of the fractional +ideal they generate). The list argument may be a macro as it is \fexpan ded +first. It is a support macro for the |gcd()| function of +\xintexprname. + +A macro of the same name existed formerly in \xintgcdname: it truncated all +its arguments to integers via \csbxint{Num}. It has now been removed and one +must load \xintfracname to get the macro. + +Added this documentation. See \csbxint{iiGCDof} for the integer +only variant. + +\subsection{\csh{xintLCMof}}\label{xintLCMof} + +\csa{xintLCMof}|{{a}{b}{c}...}|\etype{f{$\to$}{\lowast\Ff}} computes the least +common multiple of |a|, |b|, \dots{}, which are possibly \emph{fractions}. The +list argument may be a macro, it is \fexpan ded first. If one of the item +vanishes, then also the output. It is a support macro for the |lcm()| function +of \xintexprname. + +A macro of the same name existed formerly in \xintgcdname: it truncated all +its arguments to integers via \csbxint{Num}. It has now been removed and one +must load \xintfracname to get the macro. + +Added this documentation. See \csbxint{iiLCMof} for the integer +only variant. + \subsection{\csh{xintDigits}, \csh{xinttheDigits}} \label{xintDigits} \label{xinttheDigits} @@ -11940,7 +13137,7 @@ Spaces do not matter (but they must not occur in-between digit tokens, as such a \end{everbatim*} It has always been the case that an active colon |:| was allowed. -It\NewWith{1.3f} is now even possible to drop it and to use |\xintDigits = D;| +It is now even possible to drop it and to use |\xintDigits = D;| syntax. An ending active semi-colon |;| is \emph{not} compatible: it can and most @@ -11973,7 +13170,7 @@ This is the syntax now in use in most examples from the documentation. 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|\NewWith{1.3f}. +|\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 @@ -12467,1714 +13664,6 @@ general tokens (or rather braced items). \clearpage \let\xintfracnameUp\undefined -\csname xintexprnameUp\endcsname -\def\n{|{N}|} -\def\m{|{M}|} -\def\x{|{x}|} -\section{Macros of the \xintexprname package}% -\RaisedLabel{sec:expr} - -\localtableofcontents - -The \xintexprname package was first released with version |1.07| -(|2013/05/25|) of the \xintname bundle. It was substantially enhanced with -release |1.1| from |2014/10/28|. - -The package loads automatically \xintfracname and \xinttoolsname. -\begin{itemize} -\item |1.3d| adds \csbxint{eval}, \csbxint{ieval}, \csbxint{iieval}, - \csbxint{floateval}.\NewWith{1.3d} -\item for the \func{gcd} and \func{lcm} functions, it is NOT necessary anymore - to - load package \xintgcdname. And they now work not only with integers:\NewWith{1.3d} -\begin{everbatim*} -\xinttheiiexpr lcm (2^5*7*13^10*17^5,2^3*13^15*19^3,7^3*13*23^2)\relax\newline -\end{everbatim*}% -but also with fractions:\IMPORTANT -\begin{everbatim*} -\xinttheexpr lcm(7/300, 11/150, 13/60), gcd(7/300, 11/150, 13/60)\relax\par -\end{everbatim*} -\item for allowing hexadecimal (uppercase letters only) input, it is \emph{necessary} - to load package \xintbinhexname.\IMPORTANT - \begin{everbatim*} -\xinttheexpr "A*"B*"C*"D*"D*"F, "FF.FF, reduce("FF.FFF + 16^-3)\relax -\end{everbatim*} -\end{itemize} - -Please refer to \autoref{sec:xintexprsyntax} for a more detailed description -of some syntax elements. - -\subsection{The \csh{xintexpr} expressions} -\label{xintexpr} -\label{xinttheexpr} -\label{thexintexpr} -\label{xintthe} - -An \xintexprname{}ession is a construct -\csbxint{expr}\meta{expandable\_expression}|\relax|\etype{x} where the -expandable expression is read and completely expanded from left to right. - -An |\xintexpr...\relax| \emph{must} end in a |\relax| (which will be absorbed). -Like a |\numexpr| expression, it is not printable as is, nor can it be directly -employed as argument to the other package macros. For this one must use one -of the three equivalent forms: -\begin{itemize} -\item \csb{thexintexpr}\meta{expandable\_expression}|\relax|\etype{x}, or -\item \csb{xinttheexpr}\meta{expandable\_expression}|\relax|\etype{x}, or -\item \csb{xintthe}|\xintexpr|\meta{expandable\_expression}|\relax|.\etype{x} -\end{itemize} - -The computations are done \emph{exactly}, and with no simplification of the -result. See \csbxint{floatexpr} for a similar parser which rounds each -operation inside the expression to \csbxint{theDigits} digits of precision. - -As an alternative and equivalent syntax to -\begin{everbatim} -\xintexpr round(<expression>, D)\relax -\end{everbatim} -there is\footnote{For truncation rather than rounding, one uses -|\xintexpr trunc(<expression>, D)\relax|.} -\begin{everbatim} -\xintiexpr [D] <expression> \relax -\end{everbatim} -The parameter |D| must be zero or positive.\footnote{|D=0| - corresponds to using |round(<expression>)| not |round(<expression>,0)| which - would leave a trailing dot. Same for |trunc|. There is also function |float| - for floating point rounding to \csbxint{theDigits} or the given number of - significant digits as second argument.} Perhaps some future version will -give a meaning to using a negative |D|.\footnote{Thanks to KT for this - suggestion. Sorry for the delay in implementing it... matter of formatting - the output and corresponding choice of user interface are still in need of - some additional thinking.} - -\begin{itemize} -\item the expression may contain arbitrarily many levels of nested parenthesized - sub-expressions, -\item the expression may contain explicitely or from a macro expansion a - sub-expression |\xintexpr...\relax|, which itself may contain a - sub-expressions etc\dots -\item to let sub-contents evaluate as a sub-unit it should thus be either - \begin{enumerate} - \item parenthesized, - \item or a sub-expression |\xintexpr...\relax|. - \end{enumerate} - \item to use an expression as argument to the other package macros, - or more generally to macros which expand their arguments, one must use the - |\xinttheexpr...\relax| or |\xintthe\xintexpr...\relax| forms. - \item similarly, - printing the result itself must be done with these forms. - \item one should not use |\xinttheexpr...\relax| as a sub-constituent of an - |\xintexpr...\relax| but only the - |\xintexpr...\relax| form which is more efficient in this context. - \item each \xintexprname{}ession, whether prefixed or not with |\xintthe|, is - completely expandable and obtains its result in two expansion steps. -\end{itemize} - -See \autoref{sec:xintexprsyntax} for the primary information on built-in -operators and functions. This section now adds some complementary information. - - -\begin{itemize}[parsep=0pt, labelwidth=\leftmarginii, - itemindent=0pt, listparindent=\leftmarginiii, leftmargin=\leftmarginii] -\item An expression is built the standard way with opening and closing - parentheses, infix operators, and (big) numbers, with possibly a fractional - part, and/or scientific notation (except for \csbxint{iiexpr} which only - admits big integers). All variants work with comma separated expressions. On - output each comma will be followed by a space. A decimal number must have - digits either before or after the decimal mark. - -\item As everything gets expanded, the characters |.|, |+|, |-|, |*|, |/|, |^|, - |!|, |&|, \verb+|+, |?|, |:|, |<|, |>|, |=|, |(|, |)|, |"|, |]|, |[|, |@| - and the comma |,| should not (if used in the expression) be active. For - example, the French language in |Babel| system, for pdf\LaTeX, activates |!|, - |?|, |;| and |:|. Turn off the activity before expressions using such characters. - - Alternatively the macro \csbxint{exprSafeCatcodes} resets all - characters potentially needed by \csbxint{expr} to their standard catcodes - and \csbxint{exprRestoreCatcodes} restores the former status. - -\item Count registers and |\numexpr|-essions are accepted (LaTeX{}'s counters - can be inserted using |\value|) natively without |\the| or |\number| as - prefix. Also dimen registers and control sequences, skip registers and - control sequences (\LaTeX{}'s lengths), |\dimexpr|-essions, - |\glueexpr|-essions are automatically unpacked using |\number|, discarding - the stretch and shrink components and giving the dimension value in |sp| - units ($1/65536$th of a \TeX{} point). Furthermore, tacit multiplication is - implied, when the (count or dimen or glue) register or variable, or the - (|\numexpr| or |\dimexpr| or |\glueexpr|) expression is immediately prefixed - by a (decimal) number. See \autoref{ssec:tacit multiplication} for the complete rules - of tacit multiplication.\IMPORTANT - -\item With a macro |\x| defined like this: - % - \leftedline{|\def\x {\xintexpr \a + \b \relax}| or |\edef\x {\xintexpr - \a+\b\relax}|} - % - one may then do |\xintthe\x|, either for printing the result on the page or - to use it in some other macros expanding their arguments. The |\edef| does - the computation immediately but keeps it in an internal private format. - Naturally, the |\edef| is only possible if |\a| and |\b| are already - defined. With both approaches the |\x| can be inserted in other expressions, - as for example (assuming naturally as we use an |\edef| that in the - `yet-to-be computed' case the |\a| and |\b| now have some suitable meaning): - % - \leftedline {|\edef\y {\xintexpr \x^3\relax}|} - -\item There is also \csbxint{boolexpr}| ... \relax| and - \csbxint{theboolexpr}| ... \relax|. Same as |\xintexpr| with the final - result converted to $1$ if it is not zero. - -\item See also - \csbxint{ifboolexpr} (\autoref{xintifboolexpr}) and the - \func{bool} and \func{togl} functions - in \autoref{sec:expr}. Here is an example: -\catcode`| 12 % -\begin{everbatim*} -\xintNewBoolExpr \AssertionA[3]{ #1 && (#2||#3) } -\xintNewBoolExpr \AssertionB[3]{ #1 || (#2&) } -\xintNewBoolExpr \AssertionC[3]{ xor(#1,#2,#3) } -{\centering\normalcolor\xintFor #1 in {0,1} \do {% - \xintFor #2 in {0,1} \do {% - \xintFor #3 in {0,1} \do {% - #1 AND (#2 OR #3) is \textcolor[named]{OrangeRed}{\AssertionA {#1}{#2}{#3}}\hfil - #1 OR (#2 AND #3) is \textcolor[named]{OrangeRed}{\AssertionB {#1}{#2}{#3}}\hfil - #1 XOR #2 XOR #3 is \textcolor[named]{OrangeRed}{\AssertionC {#1}{#2}{#3}}\\}}}} -\end{everbatim*}\catcode`| 13 - - This example used for efficiency \csbxint{NewBoolExpr}. See also the - \autoref{xintNewExpr}. - -\item See also \csbxint{ifsgnexpr}. - -\item There is \csbxint{floatexpr}| ... \relax| where the algebra is done - in floating point approximation (also for each intermediate result). Use the - syntax |\xintDigits:=N\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, if not 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 once cannot use the syntax there, except if the arguments - are themselves wrapped as |\xinttheexpr...\relax| and assuming the macro - \fexpan ds these arguments. -\end{itemize} - - -\subsection{\texorpdfstring{\texttt{\protect\string\numexpr}}{\textbackslash - numexpr} or \texorpdfstring{\texttt{\protect\string\dimexpr}}{\textbackslash - dimexpr} expressions, count and dimension registers and variables} -\label{ssec:countinexpr} - -Count registers, count control sequences, dimen registers, dimen control -sequences (like |\parindent|), skips and skip control sequences, |\numexpr|, -|\dimexpr|, |\glueexpr|, |\fontdimen| can be inserted directly, they will be -unpacked using |\number| which gives the internal value in terms of scaled -points for the dimensional variables: $1$\,|pt|${}=65536$\,|sp| (stretch and -shrink components are thus discarded). - -Tacit multiplication (see \autoref{ssec:tacit multiplication}) is implied, -when a number or decimal number prefixes such a register or control sequence. -\LaTeX{} lengths are skip control sequences and \LaTeX{} counters should be -inserted using |\value|. - -Release |1.2| of the |\xintexpr| parser also recognizes and prefixes with -|\number| the |\ht|, |\dp|, and |\wd| \TeX{} primitives as well as the -|\fontcharht|, |\fontcharwd|, |\fontchardp| and |\fontcharic| \eTeX{} -primitives. - -In the case of numbered registers like |\count255| or |\dimen0| (or |\ht0|), -the resulting digits will be re-parsed, so for example |\count255 0| is like -|100| if |\the\count255| would give |10|. The same happens with inputs such -as |\fontdimen6\font|. And |\numexpr 35+52\relax| will be exactly as if |87| -as been encountered by the parser, thus more digits may follow: |\numexpr -35+52\relax 000| is like |87000|. If a new |\numexpr| follows, it is treated -as what would happen when |\xintexpr| scans a number and finds a non-digit: it -does a tacit multiplication. -\begin{everbatim*} -\xinttheexpr \numexpr 351+877\relax\numexpr 1000-125\relax\relax{} is the same -as \xinttheexpr 1228*875\relax. -\end{everbatim*} - -Control sequences however (such as |\parindent|) are picked up as a whole by -|\xintexpr|, and the numbers they define cannot be extended extra digits, a -syntax error is raised if the parser finds digits rather than a legal -operation after such a control sequence. - -A token list variable must be prefixed by |\the|, it will not be unpacked -automatically (the parser will actually try |\number|, and thus fail). Do not -use |\the| but only |\number| with a dimen or skip, as the |\xintexpr| parser -doesn't understand |pt| and its presence is a syntax error. To use a dimension -expressed in terms of points or other \TeX{} recognized units, incorporate it in -|\dimexpr...\relax|. - -Regarding how dimensional expressions are converted by \TeX{} into scaled points -see also \autoref{sec:Dimensions}. - -\subsection{Catcodes and spaces} - -Active characters may (and will) break the functioning of \csbxint{expr}. -Inside an expression one may prefix, for example a |:| with |\string|. Or, for -a more radical way, there is \csbxint{exprSafeCatcodes}. This is a -non-expandable step as it changes catcodes. - -\subsubsection{\csh{xintexprSafeCatcodes}} -\label{xintexprSafeCatcodes} - -This macro sets the catcodes of many characters to safe values. This is used -internally by \csbxint{NewExpr} (restoring the catcodes on exit), hence it -does not have to be protected against active characters when used at -top-level. - -Also \csbxint{defvar}, \csbxint{deffunc}, ..., use it before fetching their -semi-colon delimited arguments, so they can be used (also in the document -body) for example with Babel+French which makes the semi-colon active in the -(\LaTeX) document body.\CHANGED{1.3c} - -As \csbxint{NewExpr} and \csbxint{deffunc} and variants use internally some -|\scantokens|, they will (reasonably) succeed in sanitizing catcodes in the -expressions, even if all is from the replacement text of some macro whose -definition was done under some special catcode regime. - -But \csbxint{deffunc}, \csbxint{defvar} and variants need the (catcode other) -semi-colon as delimiter. Thus make sure the semi-colon has its normal catcode -when using \csbxint{deffunc} inside some macro definition. - -The macros \csbxint{deffunc} and variants ignore completely the colon in |:=| -(which furthermore is optional) so it can have any (reasonable) frozen catcode. - -The macros \csbxint{defvar} and variants are also compatible with any -reasonable frozen catcode of the colon |:| in |:=|, and the colon presence is -only optional.\NewWith{1.3c} - -\begin{framed} - It is important to ALWAYS shortly let \csbxint{exprSafeCatcodes} be followed - by \csbxint{exprRestoreCatcodes}.\IMPORTANTf{} If one uses twice - \csbxint{exprSafeCatcodes} then the next \csbxint{exprRestoreCatcodes} will - restore the ancien catcode regime at time of the first one. -\end{framed} - -\subsubsection{\csh{xintexprRestoreCatcodes}} -\label{xintexprRestoreCatcodes} - -Restores the catcodes to the earlier state. More precisely, -\csbxint{exprSafeCatcodes} sets a toggle (with local scope). If the toggle is -set already it does not restore the current catcodes. The next -\csa{xintexprRestoreCatcodes} unsets the toggle.\CHANGED{1.3c} -So, in case of nesting, the -catcodes are restored to what they were when the \emph{first} un-paired -\csbxint{exprSafeCatcodes} got executed. - -\bigskip - -Spaces inside an |\xinttheexpr...\relax| should mostly be -innocuous (except inside macro arguments). - -|\xintexpr| and |\xinttheexpr| are for the most part agnostic regarding -catcodes: (unbraced) digits, binary operators, minus and plus signs as -prefixes, dot as decimal mark, parentheses, may be indifferently of catcode -letter or other or subscript or superscript, ..., it doesn't matter.% -% -\footnote{Furthermore, although \csbxint{expr} uses \csa{string}, it is - escape-char agnostic. It should work with any \csa{escapechar} setting - including -1.} - -The characters |+|, |-|, |*|, |/|, |^|, |!|, |&|, \verb+|+, |?|, |:|, |<|, |>|, -|=|, |(|, |)|, |"|, |[|, |]|, |;|, the dot and the comma should not be active if -in the expression, as everything is expanded along the way. If one of them is -active, it should be prefixed with |\string|. - -The exclamation mark |!| should have its standard catcode: with catcode letter -it is used internally and hence will confuse the parsers if it comes from the -expression. - -Digits, slash, square brackets, minus sign, in the output from an -|\xinttheexpr| are all of catcode 12. For |\xintthefloatexpr| the `e' in the -output has its standard catcode ``letter''. - -A macro with arguments will expand and grab its arguments before the -parser may get a chance to see them, so the situation with catcodes and spaces -is not the same within such macro arguments. - - - -\subsection{Expandability, \csh{xintexpro}} - -As is the case with all other package macros |\xintexpr| \fexpan ds (in two -steps) to its final (non-printable) result; and |\xinttheexpr| \fexpan ds (in -two steps) to the chain of digits (and possibly minus sign |-|, decimal mark -|.|, fraction slash |/|, scientific |e|, square brackets |[|, |]|) representing -the result. - -Starting with |1.09j|, an |\xintexpr..\relax| can be inserted without -|\xintthe| prefix inside an |\edef|, or a |\write|. It expands to a private -more compact representation (five tokens) than |\xinttheexpr| or -|\xintthe\xintexpr|. - -The material between |\xintexpr| and |\relax| should contain only expandable -material. - -The once expanded |\xintexpr| is |\romannumeral0\xintexpro|.\CHANGED{1.3d} -\centeredline{ATTENTION! Prior to |1.3d| the |\xintexpro| macro was named - |\xinteval|.} -But \csbxint{eval} is now something else. And there -is similarly |\xintiexpro| (formerly |\xintieval|), |\xintiiexpro| (formerly -|\xintiieval|), and |\xintfloatexpro| (formerly |\xintfloateval|). For an -example see \autoref{ssec:fibonacci}. - -An expression can only be legally finished by a |\relax| token, which -will be absorbed. - -It is quite possible to nest expressions among themselves; for example, if one -needs inside an |\xintiiexpr...\relax| to do some computations with fractions, -rounding the final result to an integer, one just has to insert -|\xintiexpr...\relax|. The functioning of the infix operators will not be in -the least affected from the fact that the surrounding ``environment'' is the -|\xintiiexpr| one. - -\subsection{Memory considerations} -\label{ssec:memory} - -The parser creates an undefined control sequence for each intermediate -computation evaluation: addition, subtraction, etc\dots Thus, a moderately sized -expression might create 10, or 20 such control sequences. On my \TeX{} -installation, the memory available for such things is of circa \np{200000} -multi-letter control words. So this means that a document containing hundreds, -perhaps even thousands of expressions will compile with no problem. - -Besides the hash table, also \TeX{} main memory is impacted. Thus, if -\xintexprname is used for computing plots% -% -\footnote{this is not very probable as so far \xintname does not include - a mathematical library with floating point calculations, but provides - only the basic operations of algebra.}% -% -, this may cause a problem. In my testing and with current |TL2015| memory -settings, I ran into problems after doing about \emph{ten thousand} -evaluations (for example |(#1+#2)*#3-#1*#3-#2*#3)|) each with number having -\emph{hundreds} of digits. Typical error message can be: -\begin{everbatim} -./testaleatoires.tex:243: TeX capacity exceeded, sorry [pool size=6134970]. -<argument> ...19140037877484848545931233090884903 -\end{everbatim} - -There is a (partial) solution.% -% -\footnote{which convinced me that I could stick with the parser - implementation despite its potential impact on the hash-table and - other parts of \TeX{}'s memory.} - -A document can possibly do tens of thousands of evaluations only if some -identical formulae are being used repeatedly, with varying arguments (from -previous computations possibly) or coming from data being fetched from a file. -Most certainly, there will be a a few dozens formulae at most, but they will -be used again and again with varying inputs. - -With the \csbxint{NewExpr} macro, it is possible to convert once and -for all an expression containing parameters into an expandable macro -with parameters. Only this initial definition of this macro actually -activates the \csbxint{expr} parser and will (very moderately) impact -the hash-table: once this unique parsing is done, a macro with -parameters is produced which is built-up recursively from the -\csbxint{Add}, \csbxint{Mul}, etc... macros, exactly as it would be -necessary to do without the facilities of the \xintexprname package. - -Notice that since |1.2c| the \csbxint{deffunc} construct allows an alternative -to \csa{xintNewExpr} whose syntax uses arbitrary letters rather than macro -parameters |#1|, |#2|, ..., |#9|. The declared function must still be used -inside an expression, but its use will need only as many |\csname|'s as were -needed for the function arguments plus one more for encapsulating the function -result. - -\subsection{\csh{xintDigits*}, \csh{xintSetDigits*}} -\label{xintDigits*} -\label{xintSetDigits*} - -These starred variants of \csbxint{Digits} and \csbxint{SetDigits} execute -\csbxint{reloadxinttrig}.\NewWith{1.3f} - -\subsection{\csh{xintiexpr}, \csh{xinttheiexpr}} -\label{xintiexpr}\label{xinttheiexpr}\label{thexintiexpr} - -Equivalent\etype{x} to doing |\xintexpr round(...)\relax| (more precisely, -|round| is applied to each one of the evaluated values, if the expression was -comma separated). Thus, only the \emph{final result value} is rounded to an -integer. Half integers are rounded towards $+\infty$ for positive numbers and -towards $-\infty$ for negative ones. - -An optional parameter |d>0| within brackets, immediately after |\xintiexpr| -is allowed: it instructs the expression to do its final rounding to the -nearest value with that many digits after the decimal mark, \emph{i.e.}, -|\xintiexpr [d] <expression>\relax| is equivalent (in case of a single -expression) to |\xintexpr round(<expression>, d)\relax|. - -|\xintiexpr [0] ...| is the same as |\xintiexpr ...|.\footnote{Incidentally - using |round(...,0)| in place of |round(...)| in |\xintexpr| would leave a - trailing dot in the produced value.} - -If truncation rather than rounding is needed use (in case of a single -expression, naturally) |\xintexpr trunc(...)\relax| for truncation to an -integer or |\xintexpr trunc(...,d)\relax| for truncation to a decimal number -with |d>0| digits after the decimal mark. - -Perhaps in the future some meaning will be given to using negative value for -the optional parameter |d|.\footnote{Thanks to KT for this suggestion.} - -|\thexintiexpr| is synonym to |\xinttheiexpr|. - -\subsection{\csh{xintiiexpr}, \csh{xinttheiiexpr}} -\label{xintiiexpr}\label{xinttheiiexpr}\label{thexintiiexpr} - -This variant\etype{x} does not know fractions. It deals almost only with long -integers. Comma separated lists of expressions are allowed. - -\begin{framed} - It maps |/| to the \emph{rounded} quotient. The operator - |//| is, like in |\xintexpr...\relax|, mapped to \emph{truncated} division. - The Euclidean quotient (which for positive operands is like the truncated - quotient) was, prior to release |1.1|, associated to |/|. The function - |quo(a,b)| can still be employed. -\end{framed} - -The \csbxint{iiexpr}-essions use the `ii' macros for addition, subtraction, -multiplication, power, square, sums, products, Euclidean quotient and -remainder. - -The |round|, |trunc|, |floor|, |ceil| functions are still available, and are -about the only places where fractions can be used, but |/| within, if not -somehow hidden will be executed as integer rounded division. To avoid this one -can wrap the input in \dtt{qfrac}: this means however that none of the normal -expression parsing will be executed on the argument. - -To understand the illustrative examples, recall that |round| and |trunc| have -a second (non negative) optional argument. In a normal \csbxint{expr}-essions, -|round| and |trunc| are mapped to \csbxint{Round} and \csbxint{Trunc}, in -\csbxint{iiexpr}-essions, they are mapped to \csbxint{iRound} and -\csbxint{iTrunc}. - - -\begin{everbatim*} -\xinttheiiexpr 5/3, round(5/3,3), trunc(5/3,3), trunc(\xintDiv {5}{3},3), -trunc(\xintRaw {5/3},3)\relax{} are problematic, but -% -\xinttheiiexpr 5/3, round(qfrac(5/3),3), trunc(qfrac(5/3),3), floor(qfrac(5/3)), -ceil(qfrac(5/3))\relax{} work! -\end{everbatim*} - -On the other hand decimal numbers and scientific numbers can be used directly -as arguments to the |num|, |round|, or any function producing an integer. - -\begin{framed} - Scientific numbers will be - represented with as many zeroes as necessary, thus one does not want to - insert \dtt{num(1e100000)} for example in an \csa{xintiiexpr}ession ! -\end{framed} - -% -\begin{everbatim*} -\xinttheiiexpr num(13.4567e3)+num(10000123e-3)\relax % should (num truncates) compute 13456+10000 -\end{everbatim*} -% - -The |reduce| function is not available and will raise un error. The |frac| -function also. The |sqrt| function is mapped to \csbxint{iiSqrt} which gives -a truncated square root. The |sqrtr| function is mapped to \csbxint{iiSqrtR} -which gives a rounded square root. - -One can use the Float macros if one is careful to use |num|, or |round| -etc\dots on their output. - -\begin{everbatim*} -\xinttheiiexpr \xintFloatSqrt [20]{2}, \xintFloatSqrt [20]{3}\relax % no operations - -\noindent The next example requires the |round|, and one could not put the |+| inside it: - -\xinttheiiexpr round(\xintFloatSqrt [20]{2},19)+round(\xintFloatSqrt [20]{3},19)\relax - -(the second argument of |round| and |trunc| tells how many digits from after the -decimal mark one should keep.) -\end{everbatim*} - -The whole point of \csbxint{iiexpr} is to gain some speed in -\emph{integer-only} algorithms, and the above explanations related to how to -nevertheless use fractions therein are a bit peripheral. We observed -(2013/12/18) of the order of $30$\% speed gain when dealing with numbers with -circa one hundred digits (1.2: this info may be obsolete). - - -|\thexintiiexpr| is synonym to |\xinttheiiexpr|. - -\subsection{\csh{xintboolexpr}, - \csh{xinttheboolexpr}} -\label{xintboolexpr}\label{xinttheboolexpr}\label{thexintboolexpr} - - -Equivalent\etype{x} to doing |\xintexpr ...\relax| and returning $1$ if the -result does not vanish, and $0$ is the result is zero. As |\xintexpr|, this -can be used on comma separated lists of expressions, and will return a -comma separated list of $0$'s and $1$'s. - -|\thexintboolexpr| is synonym to |\xinttheboolexpr|. - -There is slight quirk in case it is used as a sub-expression: the boolean -expression needs at least one logic operation else the value is not -standardized to |1| or |0|, for example we get from -\begin{everbatim*} -\xinttheexpr \xintboolexpr 1.23\relax\relax\newline -\end{everbatim*}which is to be compared with -\begin{everbatim*} -\xinttheboolexpr 1.23\relax -\end{everbatim*} - -A related issue existed with -|\xinttheexpr \xintiexpr 1.23\relax\relax|, which was fixed with |1.1| -release, and I decided back then not to add the needed overhead also to the -|\xintboolexpr| context, as one only needs to use |?(1.23)| for example or -involve the |1.23| in any logic operation like |1.23 'and' 3.45|, or involve -the |\xintboolexpr ..\relax | itself with any logical operation, contrarily to -the sub-|\xintiexpr| case where |\xinttheexpr 1+\xintiexpr 1.23\relax\relax| -did behave contrarily to expectations until |1.1|. - - -\subsection{\csh{xintfloatexpr}, - \csh{xintthefloatexpr}} -\label{xintfloatexpr}\label{xintthefloatexpr}\label{thexintfloatexpr} - -\csbxint{floatexpr}|...\relax|\etype{x} is exactly like |\xintexpr...\relax| -but with the four binary operations and the power function are mapped to -\csa{xintFloatAdd}, \csa{xintFloatSub}, \csa{xintFloatMul}, \csa{xintFloatDiv} -and \csa{xintFloatPower}, respectively.\footnote{Since |1.2f| the \string^ - handles half-integer exponents, contrarily to \csa{xintFloatPower}.} - -The target precision for the computation is from the -current setting of |\xintDigits|. Comma separated lists of expressions are -allowed. - -An optional parameter within brackets is allowed: -\begin{itemize} -\item if positive it instructs the macro to round the result to that many - digits of precision. It thus makes sense to employ it only if this parameter is - less than the \csbxint{theDigits} precision. -\item if negative it means to trim off that many digits (of course, rounding - the value).\NewWith{1.3e} Don't use it to trim all digits (or more than all)! -\end{itemize} - -Since |1.2f| all float operations first round their arguments; a parsed number -is not rounded prior to its use as operand to such a float operation. - -|\thexintfloatexpr| is synonym to |\xintthefloatexpr|. - -|\xintDigits:=36\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. - -\subsection{\csh{xinteval}, \csh{xintieval}, \csh{xintiieval}, - \csh{xintfloateval}} -\label{xinteval}\label{xintieval}\label{xintiieval}\label{xintfloateval} - -\begin{framed} - Prior to |1.3d|,\NewWithf{1.3d} these macros existed but with a different meaning: they - arose in the once-expanded \csbxint{expr}, etc..., i.e. one had: -\begin{everbatim} -\def\xintexpr{\romannumeral0\xinteval} -\end{everbatim} - The\IMPORTANTf\ old macros were renamed into \csa{xintexpro}, etc..., in order to free - their names for new meanings, more alike what one finds in - other math packages. -\end{framed} - -\csbxint{eval}\etype{x} is an \fexpan dable macro which is basically defined -like this: -\begin{everbatim} -\def\xinteval#1{\romannumeral-`0\xinttheexpr#1\relax} -\end{everbatim} -thus expands in two steps (its exact definition differs from the one given -above in order to achieve a slight optimization). -\begin{everbatim*} -\xinteval{add(x^2, x = 100..110), add(x^3, x = 100..110)} -\end{everbatim*} - -\csbxint{ieval}\etype{x} is similarly related to \csbxint{theiexpr}. Its optional -argument must be located inside the braces: -\begin{everbatim*} -\xintieval{[7] 355/113} -\end{everbatim*} - -\csbxint{iieval}\etype{x} is similarly related to \csbxint{theiiexpr}. -\begin{everbatim*} -\xintiieval{add(x^2, x = 100..110), add(x^3, x = 100..110)} -\end{everbatim*} - -\csbxint{floateval}\etype{x} is similarly related to \csbxint{thefloatexpr}. Its optional -argument must be located inside the braces: -\begin{everbatim*} -\xintfloateval{[7] 355/113} -\end{everbatim*} - -When negative it tells how many digits to remove from the prevailing precision -(\csbxint{theDigits}):\NewWith{1.3e} -\begin{everbatim*} -\xintfloateval{[-2] 355/113} has \xinttheDigits\ minus 2 digits. -\end{everbatim*} - -These macros are useful when one uses some extra wrapper doing some parsing of -its input, like the |\num| macro of -\href{http://ctan.org/pkg/siunitx}{siunitx}, which would choke on some of the -syntax elements allowed inside \csb{xintexpr}|...\relax| (for example -brackets). -As shown in the above examples, these macros, like the underlying parsers -accept arbitrarily many comma separated expressions. - - -\subsection{Using an expression parser within another one} - -This was already illustrated before. In the following: -\begin{everbatim*} -\xintthefloatexpr \xintexpr add(1/i, i=1234..1243)\relax ^100\relax -\end{everbatim*}, -the inner sum is computed exactly. Then it will be rounded to |\xinttheDigits| -significant digits, and then its power will be evaluated as a float operation. -One should avoid the "|\xintthe|" parsers in inner positions as this induces -digit by digit parsing of the inner computation result by the outer parser. -Here is the same computation done with floats all the way: -\begin{everbatim*} -\xintthefloatexpr add(1/i, i=1234..1243)^100\relax -\end{everbatim*} - -Not surprisingly this differs from the previous one which was exact until -raising to the |100|th power. - -The fact that the inner expression occurs inside a bigger one has nil -influence on its behaviour. There is the limitation though that the outputs -from \csbxint{expr} and \csbxint{floatexpr} can not be used directly in -\csbxint{theiiexpr} integer-only parser. But one can do: -\begin{everbatim*} -\xinttheiiexpr round(\xintfloatexpr 3.14^10\relax)\relax % or trunc -\end{everbatim*} - - -\subsection{The \csh{xintthecoords} macro} -\label{xintthecoords} - -It converts a comma separated list into the format for list of coordinates as -expected by the |TikZ| |coordinates| syntax.% -% -\footnote{The implementation had to work around the -problem that |TikZ| seemingly allows only a maximal number of about one -hundred expansion steps for the list to be entirely produced.}% -% -\begin{everbatim*} -\begin{figure}[htbp] -\centering\begin{tikzpicture}[scale=10]\xintDigits:=8\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 what is next into (x1, y1) (x2, y2)... format) - \xintfloatexpr seq((x^2-1,mul(x-t,t=-1+[0..4]/2)),x=-1.2..[0.1]..+1.2) \relax }; -\end{tikzpicture} -\caption{Coordinates with \cs{xintthecoords}.} -\end{figure} -\end{everbatim*} - -% Notice: if x goes no take exactly value 1 or -1, the origin appears slightly -% off the curve, not MY fault!!! - -As examplified above, \csbxint{thecoords} is to be used followed immediately -by either \csbxint{floatexpr} or \csbxint{iexpr} or \csbxint{iiexpr}. See -\url{https://tex.stackexchange.com/a/447290} for another example. - -As |TikZ| will not understand the |A/B[N]| format which is used on output by -|\xintexpr|, |\xintthecoords\xintexpr| has no use inside a |TikZ| picture but -may have other usages; the reason for the spaces in output is to allow if -necessary to print on the page for examination and give \TeX\ a change to -establish line-breaks. - -\begin{everbatim*} -\edef\x{\xintthecoords \xintexpr rrseq(1/2,1/3; @1+@2, x=1..20)\relax } -\meaning\x +++ -\end{everbatim*} - -\subsection{\csh{xintifboolexpr}, \csh{xintifboolfloatexpr}, \csh{xintifbooliiexpr}} -\label{xintifboolexpr} -\label{xintifboolfloatexpr} -\label{xintifbooliiexpr} - -\csh{xintifboolexpr}\marg{expr}\marg{YES}\marg{NO}\etype{xnn} does -\csbxint{theexpr}<expr>|\relax| and then executes the \meta{YES} or the -\meta{NO} branch depending on whether the outcome was non-zero or zero. Thus -one can read \emph{if bool expr} as meaning \emph{if not zero}: -\centeredline{if \meta{expr}-ession does not vanish do \meta{YES} else do - \meta{NO}} - -The expression is not limited to using only comparison operators and Boolean -logic (|<|, |>|, |==|, |!=|, |&&|, \verb+||+, \func{all}, \func{any}, -\func{xor}, \func{bool}, \func{togl}, ...), it can be the most general -computation. - -\csh{xintifboolfloatexpr}\marg{expr}\marg{YES}\marg{NO}\etype{xnn} does -\csbxint{thefloatexpr}\meta{expr}|\relax| and then executes the \meta{YES} or the -\meta{NO} branch depending on whether the outcome was non zero or zero. - -\csh{xintifbooliiexpr}\marg{expr}\marg{YES}\marg{NO}\etype{xnn} does -\csbxint{theiiexpr}\meta{expr}|\relax| and then executes the \meta{YES} or the -\meta{NO} branch depending on whether the outcome was non zero or zero. - -The expression argument must be a single one, comma separated sub-expressions -will cause low-level errors. - -\subsection{\csh{xintifsgnexpr}, \csh{xintifsgnfloatexpr}, \csh{xintifsgniiexpr}} -\label{xintifsgnexpr} -\label{xintifsgnfloatexpr} -\label{xintifsgniiexpr} - -\csh{xintifsgnexpr}\marg{expr}\marg{<0}\marg{=0}\marg{>0}\etype{xnnn} evaluates -the \csbxint{expr}ession and chooses the branch corresponding to its sign. - -\csh{xintifsgnfloatexpr}\marg{expr}\marg{<0}\marg{=0}\marg{>0}\etype{xnnn} evaluates -the \csbxint{floatexpr}ession and chooses the branch corresponding to its sign. - -\csh{xintifsgniiexpr}\marg{expr}\marg{<0}\marg{=0}\marg{>0}\etype{xnnn} evaluates -the \csbxint{iiexpr}ession and chooses the branch corresponding to its sign.\NewWith{1.3d} - -The expression argument must be a single one, comma separated sub-expressions -will cause low-level errors. - -\subsection{The \csh{xintNewExpr} macro} -\label{xintNewExpr} - -The macro is used as: -% -\leftedline{|\xintNewExpr{\myformula}[n]|\marg{stuff}, where} -\begin{itemize} -\item \meta{stuff} will be inserted inside |\xinttheexpr . . . \relax|, -\item |n| is an integer between zero and nine, inclusive, which is the number - of parameters of |\myformula|, -\item the placeholders |#1|, |#2|, ..., |#n| are used inside \meta{stuff} in - their usual r\^ole,% -% -\catcode`# 12 -\footnote{if \csa{xintNewExpr} is used inside a macro, - the |#|'s must be doubled as usual.} - \footnote{the |#|'s will in pratice have their usual - catcode, but category code other |#|'s are accepted too.} -\catcode`# 6 -% -\item the |[n]| is \emph{mandatory}, even for |n=0|.% -\footnote{there is some use for \csa{xintNewExpr}|[0]| compared to an - \csa{edef} as \csa{xintNewExpr} has some built-in catcode protection.} -\item the macro |\myformula| is defined without checking if it already exists, - \LaTeX{} users might prefer to do first |\newcommand*\myformula {}| to get a - reasonable error message in case |\myformula| already exists, -\item the protection against active characters is done automatically (as long - as the whole thing has not already been fetched as a macro argument and - the catcodes correspondingly already frozen). -\end{itemize} - -It will be a completely expandable macro entirely built-up using |\xintAdd|, -|\xintSub|, |\xintMul|, |\xintDiv|, |\xintPow|, etc\dots as corresponds to the -expression written with the infix operators. -Macros created by |\xintNewExpr| can thus be nested. - -\begin{everbatim*} - \xintNewFloatExpr \FA [2]{(#1+#2)^10} - \xintNewFloatExpr \FB [2]{sqrt(#1*#2)} -\begin{enumerate}[nosep] - \item \FA {5}{5} - \item \FB {30}{10} - \item \FA {\FB {30}{10}}{\FB {40}{20}} -\end{enumerate} -\end{everbatim*} - - The use of \csbxint{NewExpr} circumvents the impact of the |\xintexpr| - parsers on \TeX's memory: it is useful if one has a formula which has to be - re-evaluated thousands of times with distinct inputs each with dozens, or - hundreds of digits. - - A ``formula'' created by |\xintNewExpr| is thus a macro whose parameters are - given to a possibly very complicated combination of the various macros of - \xintname and \xintfracname. Consequently, one can not use at all any infix - notation in the inputs, but only the formats which are recognized by the - \xintfracname macros. - - This is thus quite different from a macro with parameters which one would - have defined via a simple |\def| or |\newcommand| as for example: - % - \leftedline{|\newcommand\myformula [1]{\xinttheexpr (#1)^3\relax}|} - % - Such a macro |\myformula|, if it was used tens of thousands of times with - various big inputs would end up populating large parts of \TeX's memory. It - would thus be better for such use cases to go for: - % - \leftedline{|\xintNewExpr\myformula [1]{#1^3\relax}|} - % - Here naturally the situation is over-simplified and it would be even simpler - to go directly for the use of the macro |\xintPow| or |\xintPower|. - - -|\xintNewExpr| tries to do as many evaluations as are possible at the time the -macro parameters are still parameters. Let's see a few examples. For this I -will use |\meaning| which reveals the contents of a macro. - -\begin{enumerate} -\item the examples use a mysterious |\fixmeaning| macro, which is there to get - in the display |\romannumeral`^^@| rather than the frankly cabalistic - |\romannumeral``| which made the admiration of the readers of the - documentation dated |2015/10/19| (the second |`| stood for an ascii code - zero token as per |T1| encoded |newtxtt| font). Thus the true meaning is - ``fixed'' to display something different which is how the macro could be - defined in a standard |tex| source file (modulo, as one can see in example, - the use of characters such as |:| as letters in control sequence names). - Prior to |1.2a|, the meaning would have started with a more mundane - |\romannumeral-`0|, but I decided at the time of releasing |1.2a| to imitate - the serious guys and switch for the more hacky yet |\romannumeral`^^@| - everywhere in the source code (not only in the macros produced by - \csbxint{NewExpr}), or to be more precise for an equivalent as the caret has - catcode letter in \xintname's source code, and I had to use another - character. -\item the meaning reveals the use of some private macros from the \xintname - bundle, which should not be directly used. If the things look a bit - complicated, it is because they have to cater for many possibilities. -\item the point of showing the meaning is also to see what has already been - evaluated in the construction of the macros. -\end{enumerate} - -\begin{everbatim*} -\xintNewIIExpr\FA [1]{13*25*78*#1+2826*292}\fixmeaning\FA -\end{everbatim*} -\smallskip - -\begin{everbatim*} -\xintNewIExpr\FA [2]{(3/5*9/7*13/11*#1-#2)*3^7} -\printnumber{\fixmeaning\FA} -\end{everbatim*} - -\smallskip - -\begin{everbatim*} -% an example with optional parameter -\xintNewIExpr\FA [3]{[24] (#1+#2)/(#1-#2)^#3} -\printnumber{\fixmeaning\FA} -\end{everbatim*} - -\smallskip - -\begin{everbatim*} -\xintNewFloatExpr\FA [2]{[12] 3.1415^3*#1-#2^5} -\printnumber{\fixmeaning\FA} -\end{everbatim*} - -\smallskip - -\begin{everbatim*} -\xintNewExpr\DET[9]{ #1*#5*#9+#2*#6*#7+#3*#4*#8-#1*#6*#8-#2*#4*#9-#3*#5*#7 } -\printnumber{\fixmeaning\DET} -\end{everbatim*} - -\unless\ifxetex -Notice that since |1.2c| it is perhaps more natural to do: -\begin{everbatim*} -% attention that «ad» would try to use non-existent variable "ad" -\xintdeffunc det2(a, b, c, d) := a*d - b*c ; -% This is impossible because we must use single letters : -% \xintdeffunc det3(x_11, x_12, x_13, x_21, x_22, x_23, x_31, x_32, x_33) := -% x_11 * det2 (x_22, x_23, x_32, x_33) + x_21 * det2 (x_32, x_33, x_12, x_13) -% + x_31 * det2 (x_12, x_13, x_22, x_23); -\xintdeffunc det3 (a, b, c, u, v, w, x, y, z) := a*v*z + b*w*x + c*u*y - b*u*z - c*v*x - a*w*y ; -\xinttheexpr det3 (1,1,1,1,2,4,1,3,9), det3 (1,10,100,1,100,10000,1,1000,1000000), - 90*900*990, reduce(det3 (1,1/2,1/3,1/2,1/3,1/4,1/3,1/4,1/5))\relax\newline -\xintdeffunc det3bis (a, b, c, u, v, w, x, y, z) := - a*det2(v,w,y,z)-b*det2(u,w,x,z)+c*det2(u,v,x,y); -\pdfsetrandomseed 123456789 % xint.pdf should be predictable from xint.dtx ! -\xinttheexpr subs(subs(subs(subs(subs(subs(subs(subs(subs( -% we use one extra pair of parentheses to hide the commas from the subs - (a, b, c, u, v, w, x, y, z, det3 (a, b, c, u, v, w, x, y, z), - det3bis (a, b, c, u, v, w, x, y, z)), - z=\pdfuniformdeviate 1000), y=\pdfuniformdeviate 1000), x=\pdfuniformdeviate 1000), - w=\pdfuniformdeviate 1000), v=\pdfuniformdeviate 1000), u=\pdfuniformdeviate 1000), - c=\pdfuniformdeviate 1000), b=\pdfuniformdeviate 1000), a=\pdfuniformdeviate 1000)\relax -\end{everbatim*} - - -The last computation with its nine nested |subs| can be coded more -economically (and efficiently), exploiting the fact that a single dummy -variable can expand to a whole list: -\begin{everbatim*} -\pdfsetrandomseed 123456789 % xint.pdf should be predictable from xint.dtx ! -\xinttheexpr subs((L, det3(L), det3bis(L)), % parentheses used to hide the inner commas - L=\pdfuniformdeviate 1000, \pdfuniformdeviate 1000, \pdfuniformdeviate 1000, - \pdfuniformdeviate 1000, \pdfuniformdeviate 1000, \pdfuniformdeviate 1000, - \pdfuniformdeviate 1000, \pdfuniformdeviate 1000, \pdfuniformdeviate 1000)\relax -\end{everbatim*} -\fi % de pas de xetex - -With |\xintverbosetrue| we will find in the log: - -\begin{everbatim} - Function det3 for \xintexpr parser associated to \XINT_expr_userfunc_det3 w -ith meaning macro:#1#2#3#4#5#6#7#8#9->\xintSub {\xintSub {\xintSub {\xintAdd {\ -xintAdd {\xintMul {\xintMul {#1}{#5}}{#9}}{\xintMul {\xintMul {#2}{#6}}{#7}}}{\ -xintMul {\xintMul {#3}{#4}}{#8}}}{\xintMul {\xintMul {#2}{#4}}{#9}}}{\xintMul { -\xintMul {#3}{#5}}{#7}}}{\xintMul {\xintMul {#1}{#6}}{#8}} - - Function det3bis for \xintexpr parser associated to \XINT_expr_userfunc_det -3bis with meaning macro:#1#2#3#4#5#6#7#8#9->\xintAdd {\xintSub {\xintMul {#1}{\ -xintExpandArgs {XINT_expr_userfunc_det2}{{#5}{#6}{#8}{#9}}}}{\xintMul {#2}{\xin -tExpandArgs {XINT_expr_userfunc_det2}{{#4}{#6}{#7}{#9}}}}}{\xintMul {#3}{\xintE -xpandArgs {XINT_expr_userfunc_det2}{{#4}{#5}{#7}{#8}}}} -\end{everbatim} - - - -\medskip -Lists, including Python-like selectors, are compatible with -\csa{xintNewExpr}:% -% -\footnote{The |\empty| token is optional here, but it would - be needed in case of \csbxint{NewFloatExpr} or \csbxint{NewIExpr}.} -% -\begin{everbatim*} -\xintNewExpr\Foo[5]{\empty[#1..[#2]..#3][#4:#5]} -\begin{itemize}[nosep] -\item |\Foo{1}{3}{90}{20}{30}|->\Foo{1}{3}{90}{20}{30} -\item |\Foo{1}{3}{90}{-40}{-15}|->\Foo{1}{3}{90}{-40}{-15} -\item |\Foo{1.234}{-0.123}{-10}{3}{7}|->\Foo{1.234}{-0.123}{-10}{3}{7} -\end{itemize} -\fdef\test {\Foo {0}{10}{100}{3}{6}}\meaning\test +++ -\end{everbatim*} - -In this last example the macro |\Foo| will not be able to handle an empty |#4| -or |#5|: this is only possible in an expression, because the parser identifies -|][:| or |:]| and handles them appropriately. During the construction of |\Foo| -the parser will find |][#4:| and not |][:|. - -\begin{framed} - The \csbxint{deffunc}, \csbxint{defiifunc}, \csbxint{deffloatfunc} - declarators added to \xintexprname since release |1.2c| are based on the - same underlying mechanism as \csa{xintNewExpr}, \csa{xintNewIIExpr}, ... The - discussion that follows applies to them too. -\end{framed} - -\subsubsection {Conditional operators and \csh{NewExpr}} -\label{sssec:cond} - -The |?| and |??| conditional operators cannot be parsed by |\xintNewExpr| when -they contain macro parameters |#1|,\dots, |#9| within their scope. However -replacing them with the functions |if| and, respectively |ifsgn|, the parsing -should succeed. And the created macro will \emph{not evaluate the branches to - be skipped}, thus behaving exactly like |?| and |??| would have in the -|\xintexpr|. - -\begin{everbatim*} -\xintNewExpr\Formula [3]{ if((#1>#2) && (#2>#3), sqrt(#1-#2)*sqrt(#2-#3), #1^2+#3/#2) }% -\printnumber{\fixmeaning\Formula } -\end{everbatim*} - -This formula (with its |\xintiiifNotZero|) will gobble the false branch without -evaluating it when used with given arguments. - -Remark: the meaning above reveals some of the private macros used by the -package. They are not for direct use. - -Another example - -\begin{everbatim*} -\xintNewExpr\myformula[3]{ ifsgn(#1,#2/#3,#2-#3,#2*#3) }% -\fixmeaning\myformula -\end{everbatim*} - -Again, this macro gobbles the false branches, as would have the operator |??| -inside an |\xintexpr|-ession. - -\subsubsection{External macros and \csh{xintNewExpr}; the protect function} -\label{sssec:protect} - -For macros within such a created \xintname-formula macro, there -are two cases: -\begin{itemize} -\item the macro does not involve the numbered parameters in its arguments: it - may then be left as is, and will be evaluated once during the construction of - the formula, -\item it does involve at least one of the macro parameters as argument. Then: - \begin{snugframed} - the whole thing (macro + argument) should be |protect|-ed, not in the - \LaTeX{} sense (!), but in the following way: |protect(\macro {#1})|.\IMPORTANT - \end{snugframed} -\end{itemize} - -Here is a silly example illustrating the general principle: the macros here have -equivalent functional forms which are more convenient; but some of the more -obscure package macros of \xintname dealing with integers do not have functions -pre-defined to be in correspondance with them, use this mechanism could be -applied to them. - -\begin{everbatim*} -\xintNewExpr\formulaA[2]{protect(\xintRound{#1}{#2}) - protect(\xintTrunc{#1}{#2})}% -\printnumber{\fixmeaning\formulaA} - -\xintNewIIExpr\formulaB [3]{rem(#1,quo(protect(\the\numexpr #2\relax),#3))}% -\noindent\printnumber{\fixmeaning\formulaB } -\end{everbatim*} - -Only macros involving the |#1|, |#2|, etc\dots should be protected in this -way; the |+|, |*|, etc\dots symbols, the functions from the \csbxint{expr} -syntax, none should ever be included in a protected string. - - -\subsubsection{Limitations of \csh{NewExpr} and \csh{deffunc}} -\label{sssec:limitations} - -\csbxint{NewExpr} will pre-evaluate everything as long as it does not contain -the macro parameters |#1|, |#2|, ... and the special measures to take when -these are inside branches to |?| and |??| (replace these operators by |if| and -|ifsgn|) or as arguments to macros external to \xintexprname (use |protect|) -were discussed in \autoref{sssec:cond} and \autoref{sssec:protect}. - -The main remaining limitation is that expressions with dummy variables are -compatible with \csa{xintNewExpr} only to the extent that the iterated-over -list of values does not depend on the macro parameters |#1|, |#2|, ... For -example, this works: -\begin{everbatim*} -\xintNewExpr \FA [2] {reduce(add((t+#1)/(t+#2), t=0..5))} -\FA {1}{1}, \FA {1}{2}, \FA {2}{3} -\end{everbatim*} -but the |5| can not be abstracted into a third argument |#3|. - -There are no restriction on using macro parameters |#1|, |#2|, ... with list -constructs. For example, this works: -\begin{everbatim*} -\xintNewIExpr \FB [3] {[4] `+`([1/3..[#1/3]..#2]*#3)} -\begin{itemize}[nosep] -\item \FB {1}{10/3}{100} % (1/3+2/3+...+10/3)*100 -\item \FB {5}{5}{20} % (1/3+6/3+11/3)*20 -\item \FB {3}{4}{1} % (1/3+4/3+7/3+10/3)*1 -\end{itemize} -\end{everbatim*} - -Some simple expressions with |add| or |mul| can be also expressed with |`+`| -and |`*`| and list operations. But there is no hope for |seq|, |iter|, etc... -if the |#1|, |#2|, ... are used inside the list argument: -|seq(x(x+#1)(x+#2),x=1..#3)| is currently not compatible with -\csa{xintNewExpr}. But |seq(x(x+#1)(x+#2), x=1..10)| has no problem. - -All the preceeding applies identically for \csbxint{deffunc}, \csbxint{defiifunc}, -\csbxint{deffloatfunc} which share the same routines as \csa{xintNewExpr}, -\csa{xintNewIIExpr}, ..., replacing the |#1|, |#2|, ... in the discussion by -the letters used as function arguments. - -Here is a final syntax restriction: it is possible to use sub-expressions only -if they use \csbxint{expr} (or \csbxint{eval} since |1.3f|) but using -\csbxint{theexpr} (or \csbxint{the}) is illegal. -\begin{everbatim*} -\xintNewExpr \FC [4] {#1+\xintexpr #2*#3\relax + #4} -\printnumber{\fixmeaning\FC} -\end{everbatim*}\newline -works, and -\begin{everbatim*} -\xintNewExpr \FD [1] {#1+\xinteval{1}} -\printnumber{\fixmeaning\FD} -\end{everbatim*}\newline -also,\CHANGED{1.3f} but -\begin{everbatim} -\xintNewExpr \FD [1] {#1+\xinttheexpr 1\relax} -\end{everbatim} -is illegal. - -Prior to |1.3e| it would have been possible to do\CHANGED{1.3e} -\begin{everbatim} -\xintdeffunc FE(t) := t + \xinttheexpr 1\relax ; -\end{everbatim} -and even -\begin{everbatim} -\xintdeffunc FF(t,u) := t + \xinttheexpr u\relax ; -\end{everbatim} -They are now illegal, but fortunately things such as -\begin{everbatim*} -\xintdeffunc FG(t, u, v) := t + \xintexpr u + v\relax ; -\expandafter\meaning\csname XINT_expr_userfunc_FG\endcsname -\end{everbatim*}\newline -and even for example -\begin{everbatim*} -\xintdeffunc FH(t,u, v) := t + \xintfloateval{u + v} ; -\expandafter\meaning\csname XINT_expr_userfunc_FH\endcsname -\end{everbatim*}\newline -do work.\CHANGED{1.3f} - -Anyway, one should never use |\xinttheexpr| for sub-expressions but only -|\xintexpr|, so these restrictions on the \csbxint{NewExpr} and -\csbxint{deffunc} syntax are of no real significance. - -\subsection{\csh{xintNewFloatExpr}}\label{xintNewFloatExpr} - -This is exactly like \csbxint{NewExpr} except that the created formulas are -set-up to use |\xintthefloatexpr|. Careful though that the |[...]| list syntax -if first thing in the expression will be confused by the parser with the -optional rounding argument |[N]| of \csbxint{floatexpr} (cf. -\autoref{ssec:lists}.) Use an |\empty| token: -\begin{everbatim*} -\xintNewFloatExpr\F[1]{\empty[divmod(11.7,#1)][1]} -% this is a bit silly example, done only to check that it works -\F{1.35} -\end{everbatim*} - -The numbers hard-wired in the original expression are evaluated using the -prevailing |\xintDigits| precision at time of creation; the rest of the -formula will be evaluated using the precision valid at the time of use. -\begin{everbatim*} -\xintNewFloatExpr \f [1] {sqrt(#1)} -\f {2} (with \xinttheDigits{} digits of precision). - -{\xintDigits := 32\relax\f {2} (with \xinttheDigits{} digits of precision).} - -\xintNewFloatExpr \f [1] {sqrt(#1)*sqrt(2)} -\f {2} (with \xinttheDigits {} digits of precision). - -\xintDigits := 32\relax\f {2} (?? we thought we had a higher precision.) - -\xintNewFloatExpr \f [1] {sqrt(#1)*sqrt(2)} -\f {2} (with \xinttheDigits {} digits of precision) - -\xintDigits := 16\relax back to default -\end{everbatim*} - -The |sqrt(2)| in the first |sqrt(#1)*sqrt(2)| NewFloatExpression was computed -with only \dtt{\xinttheDigits} digits of precision. In the second one, the -|sqrt(2)| gets pre-evaluated with \dtt{32} digits of precision. - -\subsection{\csh{xintNewIExpr}}\label{xintNewIExpr} - -Like \csbxint{NewExpr} but using |\xinttheiexpr|. As |\xintiexpr| admits an -optional rounding argument |[N]| the same caveat when square brackets come -first in the expression as in the discussion of \csbxint{NewFloatExpr} -applies. - - -\subsection{\csh{xintNewIIExpr}}\label{xintNewIIExpr} - -Like \csbxint{NewExpr} but using |\xinttheiiexpr|. - -\subsection{\csh{xintNewBoolExpr}}\label{xintNewBoolExpr} - -Like \csbxint{NewExpr} but using |\xinttheboolexpr|. - -\xintDigits:= 16\relax - -\subsection{The \cshnolabel{xintdefvar}, \cshnolabel{xintdefiivar}, \cshnolabel{xintdeffloatvar} macros} - -See \autoref{xintdefvar} for their documentation. - -\subsection{The \cshnolabel{xintdeffunc}, \cshnolabel{xintdefiifunc}, \cshnolabel{xintdeffloatfunc} macros} - -See \autoref{xintdeffunc} for their documentation. - -\subsection{The \cshnolabel{xintNewFunction} macro} - -See \autoref{xintNewFunction} for its documentation. - -\subsection{Technicalities} - -As already mentioned \csa{xintNewExpr}|\myformula[n]| does not check the prior -existence of a macro |\myformula|. And the number of parameters |n| given as -mandatory argument within square brackets should be (at least) equal -to the number of parameters in the expression. - -Obviously I should mention that \csa{xintNewExpr} itself can not be used in an -expansion-only context, as it creates a macro. - -The |\escapechar| setting may be arbitrary when using |\xintexpr|. - -The format of the output of -|\xintexpr|\meta{stuff}|\relax| is a |!| (with catcode 11) followed by various things: -\begin{everbatim*} -\edef\f {\xintexpr 1.23^10\relax }\meaning\f -\end{everbatim*} - -\begin{framed} - Note that |\xintexpr| expands in an |\edef|, contrarily - to |\numexpr| which is non-expandable, if not prefixed by |\the|, |\number|, - or |\romannumeral| or in some other context where \TeX{} is building a number. See - \autoref{ssec:fibonacci} for some illustration. -\end{framed} - -I decided to put all intermediate results (from each evaluation of an infix -operators, or of a parenthesized subpart of the expression, or from application -of the minus as prefix, or of the exclamation sign as postfix, or any -encountered braced material) inside |\csname...\endcsname|, as this can be done -expandably and encapsulates an arbitrarily long fraction in a single token (left -with undefined meaning), thus providing tremendous relief to the programmer in -his/her expansion control. - -\begin{framed} - As the |\xintexpr| computations corresponding to functions and infix - or postfix operators are done inside |\csname...\endcsname|, the - \fexpan dability could possibly be dropped and one could imagine - implementing the basic operations with expandable but not \fexpan - dable macros (as \csbxint{XTrunc}.) I have not investigated that - possibility. -\end{framed} - -Syntax errors in the input such as using a one-argument function with two -arguments will generate low-level \TeX{} processing unrecoverable errors, with -cryptic accompanying message. - -Some other problems will give rise to `error messages' macros giving some -indication on the location and nature of the problem. Mainly, an attempt has -been made to handle gracefully missing or extraneous parentheses. - -However, this mechanism is completely inoperant for parentheses involved in -the syntax of the |seq|, |add|, |mul|, |subs|, |rseq| and |rrseq| functions, -and missing parentheses may cause the parser to fetch tokens beyond the ending -|\relax| necessarily ending up in cryptic low-level \TeX-errors. - -Note that the |,<letter>=| part must be visible, it can not arise from -expansion (the equal sign does not have to be an equal sign, it can be any -token and will be gobbled).\IMPORTANT{} However for |iter|, |iterr|, |rseq|, -|rrseq|, the initial values delimited by a |;| are parsed in the normal way, -and in particular may be braced or arise from expansion. This is useful as the -|;| may be hidden from \csa{xintdeffunc} as |{;}| for example. Again, this -remark does \emph{not} apply to the comma |,| which precedes the |<letter>=| -part. The comma will be fetched by delimited macros and must be there. Nesting -is handled by checking (again using suitable delimited macros) that -parentheses are suitably balanced. - - -Note that |\relax| is \emph{mandatory} (contrarily to the situation for |\numexpr|). - -\subsection{Acknowledgements (2013/05/25)} - -I was greatly helped in my preparatory thinking, prior to producing such an -expandable parser, by the commented source of the -\href{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 -\let\xintexprnameUp\undefined -\csname xinttrignameUp\endcsname -\def\n{|{N}|} -\def\m{|{M}|} -\def\x{|{x}|} -\section{Macros of the \xinttrigname package} -\RaisedLabel{sec:trig} - -\localtableofcontents - -This package provides trigonometric functions for use with \xintexprname. -The sole macro is \csbxint{reloadxinttrig}. - -This package was first included in release |1.3e| (|2019/04/05|) of -\xintexprname. It is automatically loaded by \xintexprname. - -\textbf{Acknowledgements:} I finally decided to release some such functions -under friendly pressure of Jürgen \textsc{Gilg} and Thomas \textsc{Söll}, let -them both be thanked here. - -\subsection{\csh{xintreloadxinttrig}}\label{xintreloadxinttrig} - -The library is loaded automatically by \xintexprname, thus with the default -value of \csbxint{theDigits} which is \dtt{16}. But it can handle a precision -of up to about \fbox{\dtt{60}} digits (make this \dtt{59} at most for the -inverse functions). For this, execute for example \csbxint{SetDigits*}|{48}|. - -\begin{framed} - Since |1.3f|, the starred variants \csbxint{Digits*}|:=P;| and\NewWithf{1.3f} - \csbxint{SetDigits*}\marg{num. expression} execute \csbxint{reloadxinttrig} - to let the package re-configure itself. - - The non-starred variants do not execute \csbxint{reloadxinttrig} (to avoid - adding artificial overhead to existing documents).\IMPORTANTf{} -\end{framed} - -Absence of guard digits (whether in the used hard-coded constants or in -passing over values from one auxiliary function to the next) due to high level -(user) interface used for the programming means that the produced values are -definitely expected to be wrong in the last digit or last two digits. I should -actually give some estimate of the actual maximal error in |ulps| unit, but I -have not done the complete analysis for lack of time. - -Final computation results should thus probably be printed via -\csbxint{floateval}|{[-2]....}| in order to strip off (with rounding) the last -two digits, if one does not like seeing those non-meaningful figures in the -last one or two positions (I don't say those last two figures are -\emph{systematically} off). For example, to achieve \dtt{16} digits of -precision one should work with a precision of 18 digits (being careful to have -issued \csbxint{reloadxinttrig}) and round results using -\csbxint{floateval}|{[-2]....}|. - -Another approach is to use \csbxint{ieval}|{[D]...}| for conversion to -a fixed point format. - -In future, lower level coding will probably replace the high-level interface, -or at least the macros produced by the high-level interface will be hacked -into to tell the float macros to work at a somewhat elevated precision. - -\subsection{Constants} - -They are the correct rounding to \csbxint{theDigits} precision of the -mathematically exact ones. Their values get incorporated into the -trigonometrical functions at the time of their definitions during loading or -reloading of the package. They are left free to use, or modified, or -\csbxint{unassignvar}'d, as this will have no impact whatsoever on the -functions. - -\begin{description} -\vardesc{twoPi} what could that be? -\vardesc{threePiover2} -\vardesc{Pi} -\vardesc{Piover2} -\vardesc{oneRadian} this is one radian in degrees: $180/\pi$ -\vardesc{oneDegree} this is one degree in radian: $\pi/180$ -\vardesc{invfact2} this is $1/2!$ -\vardesc{invfact3} this is $1/3!$ -\item[\dots] -\vardesc{invfact44} this is $1/44!$ -\end{description} - -For a (very) slight optimization of usage, it is recommended to convert them -to macro form, for example: -\begin{everbatim*} -\edef\oneDegree{\xintfloatexpr oneDegree\relax} -\xintfloateval{sin(37\oneDegree)}\newline -\xintfloateval{sind(37)}\newline -\end{everbatim*} -By the way, the above value differs by |1ulp| from correct rounding of exact -one (which looks \dtt{...520482}79917...), see \autoref{ssec:trignotes}. - -\subsection{Functions} - -\subsubsection{Direct trigonometry} - -With the variable in radians: - -\begin{description} -\funcdesc{sin} sine -\funcdesc{cos} cosine -\funcdesc{tan} tangent -\funcdesc{cot} cotangent -\funcdesc{sec} secant -\funcdesc{csc} cosecant -\end{description} - -With the variable in degrees: - -\begin{description} -\funcdesc{sind} sine -\funcdesc{cosd} cosine -\funcdesc{tand} tangent -\funcdesc{cotd} cotangent -\funcdesc{secd} secant -\funcdesc{cscd} cosecant -\end{description} - -Only available with the variable in radians: -\begin{description} -\funcdesc{tg} tangent -\funcdesc{cotg} cotangent -\funcdesc{sinc} cardinal sine $\sinc(x) = \sin(x)/x$ -\end{description} - -\subsubsection{Inverse trigonometry} - -With the value in radians: - -\begin{description} -\funcdesc{asin} arcsine -\funcdesc{acos} arccosine -\funcdesc{atan} arctangent -\funcdesc[x, y]{Arg} the main branch of the argument of the complex number -|x+iy|, from $-\pi$ (excluded) to $\pi$ (included). 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} -\xintdeffloatefunc radians(x) := x * oneDegree; -\xintdeffloatefunc degrees(x) := x * oneRadian; -\xintdefefunc radians(x) := x * oneDegree; -\xintdefefunc degrees(x) := x * oneRadian; -\end{everbatim} - -The variants for \csbxint{expr} above do an exact multiplication, I did not -add a \func{float} wrapper to force rounding as anyhow the trigonometrical -functions will do this initial rounding of their arguments. But if you define -a variable for multiple later use using such a |degrees()| function, it would -be better to add a \func{float} wrapper in the variable definition so the -rounding is already done: rounding an already rounded value is unavoidable -overhead but proceeds faster as it is quicly realized the input actually needs -no rounding. - -Notice however that the conversion factors above are without guard digits. One -can do this: -\begin{everbatim} -\xintdeffloatefunc radians(x) := float(\xintexpr x * oneDegreewithmoredigits\relax); -\xintdeffloatefunc degrees(x) := float(\xintexpr x * oneRadianwithmoredigits\relax); -\end{everbatim} -But recall that |x| will normally already be a rounded value, so this is -perhaps a bit complex for not much ado. Probably better to work overall with -an elevated precision and print final results at a lower precision. - -\subsection{Important implementation notes} -\label{ssec:trignotes} - -\begin{itemize} -\item The package is almost entirely implemented using the high level user - interface of \xintexprname, see \autoref{sec:xintexprsyntax} for - \csbxint{deffloatefunc} and \csbxint{deffloatvar}, the main two exceptions - are: - \begin{enumerate}[nolistsep] - \item the range reduction for the |sind()| and |cosd()| functions which - required for optimized efficiency the coding at some more core level. - \item a change at core level was done to \csbxint{deffunc} in order to - facilitate the transfer of the defined functions from the float parser to - the exact parser. See \autoref{sssec:limitations}, the source code - comments in |sourcexint.pdf| and the discussion of \csbxint{deffunc} for - details. The \csbxint{defefunc} added at |1.3e| was also motivated by this - context. - \end{enumerate} - To avoid problems if the package is reloaded at a time the user has - used some letter variables as assigned variables, I added - \csbxint{ensuredummy} and \csbxint{restorelettervar}. -\item It is not possible from this interface to (easily) let the computation - proceed with a temporarily elevated precision (``guard digits''). Expect - thus some errors in the last places; basically one should use the optional - rounding argument of either \csbxint{floateval} or \csbxint{ieval} to reduce - the number of digits of printed values by about two digits, if one - hopes to get correct rounding (most of the time). -\item Currently, \xintname is lacking some dedicated internal representation - of floats which means that most operations re-parse the digit tokens of their - arguments to count them\dots\ this does not contribute to efficiency (you - can load the module under |\xintverbosetrue| regime and see how the nested - macros look like and get an idea of how many times some rather silly - re-counting of mantissa lengths will get done!) -\item One should not overwrite some function names which are employed as - auxiliaries: |sin_aux|, |cos_aux|, |sin_|, |cos_|, |sind_|, |cosd_|, - |asin_l|\dots others\dots |asin_a|, |asind_a|, |atan_a|, |atand_a|, - |atan_b|, |atand_b|. If you redefine any one of them, you break the - whole thing. -\item Floats with large exponents are integers and are multiple of \dtt{1000}; - hence modulo \dtt{360} all such ``angles'' are multiple of \dtt{40} degrees. - Needless to say that considering usage of the |sind()| and |cosd()| functions - with such large float numbers is meaningless. -\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* := 50\relax % target 48 digits via 2 guard digits -$sind(17)\approx\xintfloateval{[-2] sind(17)}$\newline -$cosd(17)\approx\xintfloateval{[-2] cosd(17)}$\newline -$tand(17)\approx\xintfloateval{[-2] tand(17)}$\newline -$sind(43)\approx\xintfloateval{[-2] sind(43)}$\newline -$cosd(43)\approx\xintfloateval{[-2] cosd(43)}$\newline -$tand(43)\approx\xintfloateval{[-2] tand(43)}$\newline -$asind(0.3)\approx\xintfloateval{[-2] asind(0.3)}$\newline -$acosd(0.3)\approx\xintfloateval{[-2] acosd(0.3)}$\newline -$atand(3)\approx\xintfloateval{[-2] atand(3)}$\newline -$tan(atan(7))\approx\xintfloateval{[-2] tan(atan(7))}$\newline -$asind(sind(25))\approx\xintfloateval{[-2] asind(sind(25))}$\par\medskip -\noindent\xintDigits* := 26\relax % target 24 digits via 2 guard digits -$sind(17)\approx\xintfloateval{[-2] sind(17)}$\newline -$cosd(17)\approx\xintfloateval{[-2] cosd(17)}$\newline -$tand(17)\approx\xintfloateval{[-2] tand(17)}$\newline -$sind(43)\approx\xintfloateval{[-2] sind(43)}$\newline -$cosd(43)\approx\xintfloateval{[-2] cosd(43)}$\newline -$tand(43)\approx\xintfloateval{[-2] tand(43)}$\newline -$asind(0.3)\approx\xintfloateval{[-2] asind(0.3)}$\newline -$acosd(0.3)\approx\xintfloateval{[-2] acosd(0.3)}$\newline -$atand(3)\approx\xintfloateval{[-2] atand(3)}$\newline -$tan(atan(7))\approx\xintfloateval{[-2] tan(atan(7))}$\newline -$asind(sind(25))\approx\xintfloateval{[-2] 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{Macros of the \xintlogname package} -\RaisedLabel{sec:log} - -\localtableofcontents - -This package provides logarithms, exponentials and fractional powers for use -with \xintexprname. - -This package was first included in release |1.3e| (|2019/04/05|) of -\xintexprname. It is automatically loaded by \xintexprname. - -Currently, the functions \func{log10}, \func{pow10}, \func{log}, \func{exp}, -and \func{pow} use at their core two fast expandable macros handling base 10 -logarithms and powers for mantissas of 9 digit tokens. They are -defined by package \href{https://ctan.org/pkg/poormanlog}{poormanlog} which is -automatically imported. The error is believed to be at most \dtt{2ulp} (see -its |README|). The package \href{https://ctan.org/pkg/poormanlog}{poormanlog} -has no dependencies and can be imported by any other \TeX\ macro file. - -Although the precision is thus limited to about \dtt{8} or \dtt{9} digits this -is amply enough for plots. - -\subsection{\csh{poormanloghack}} -\label{ssec:poormanloghack} - -\begin{description} -\item[\string\poormanloghack\string{**\string}] use it to let the |**| operator be remapped to the - \func{pow} function. -\item[\string\poormanloghack\string{\string^\string}] use it to let the |^| operator be remapped to the - \func{pow} function. -\end{description} -If used, they obey \TeX\ scoping as usual. -\begin{everbatim*} -\begingroup -\poormanloghack{**}\xintfloateval{[8]1.234**5.678}\newline -\poormanloghack{^}\xintfloateval{[8]1.234^5.678}\par -\endgroup -\end{everbatim*} - -Notice that in \csbxint{floateval} those (equivalent) operators already -natively handle half-integer exponents. Once remapped to the \func{pow} -function they will become less precise than the original ones for half-integer -and integer exponents. - -\subsection{Functions} - -All those functions achieve only about \dtt{8} or \dtt{9} digits of precision. -Notice in particular that the digits beyond the ninth printed by \func{log} -have no significance (here we suppose |1<x<10|), but I did not add the -rounding overhead as it is expected anyhow that the final result will be -appropriately rounded. Notice however that \func{log10} should be seen as -going from floating point to fixed point (in the sense of the number of -fractional digits) and \func{pow10} from fixed point to floating point. - -\begin{description} -\funcdesc{log10} logarithm in base 10 -\funcdesc{pow10} fractional powers of 10 -\funcdesc{log} natural logarithm via |log10(x)*2.3025850923| formula; only the -first 8 or 9 digits of the output are significant... -\funcdesc{exp} exponential function via |pow10(x*0.434294481903)| formula -\funcdesc[x, y]{pow} computes $x^y$ via the formula |pow10(y*log10(x))| -\end{description} - -\begin{everbatim*} -\xintfloateval{[9] log(2), exp(1), pow(2,0.5)} -\end{everbatim*} -Notice that the last digit of |log(2)| is not the correctly rounded one... I -did say 9 \textbf{or} 8 digits or precision... The documentation of -\href{https://ctan.org/pkg/poormanlog}{poormanlog} mentions an error of up -to 2 units in the ninth digit when computing |log10(x)| for |1<x<10| and -|10^x| for |0<x<1|. - -\clearpage -\let\xintlognameUp\undefined \csname xintbinhexnameUp\endcsname \def\n{|{N}|} \def\m{|{M}|} @@ -14352,6 +13841,7 @@ $000000001111101001010001\xrightarrow{\text{\string\xintBinToHex}} \xintCHexToBin{\xintBinToHex{000000001111101001010001}}$ \par \end{everbatim*} + \clearpage \let\xintbinhexnameUp\undefined \csname xintgcdnameUp\endcsname @@ -14366,76 +13856,33 @@ $000000001111101001010001\xrightarrow{\text{\string\xintBinToHex}} This package was included in the original release |1.0| (|2013/03/28|) of the \xintname bundle. -Since release |1.09a| the macros filter their inputs through the \csbxint{Num} -macro, so one can use count registers, or fractions as long as they reduce to -integers. +! Since release |1.09a| the macros filter their inputs through the \csbxint{Num} +! macro, so one can use count registers, or fractions as long as they reduce to +! integers. -Since release |1.1|, the two ``|typeset|'' macros require the explicit -loading by the user of package \xinttoolsname. +! Since release |1.1|, the two ``|typeset|'' macros require the explicit +! loading by the user of package \xinttoolsname. At |1.3d| macros \csbxint{iiGCD} and \csbxint{iiLCM} are copied over to -\xintname, hence \func{gcd} and \func{lcm} functions in \csbxint{iiexpr} are -available simply from loading \xintexprname, \xintgcdname is not -needed.\NewWith{1.3d} - - -%% \clearpage - -\subsection{\csh{xintiiGCD}}\label{xintiiGCD} - -|\xintiiGCD|\n\m\etype{ff} computes the greatest common divisor. It is -positive, except when both |N| and |M| vanish, in which case the macro returns -zero. -% -\leftedline{\csa{xintiiGCD}|{10000}{1113}|\dtt{=\xintiiGCD{10000}{1113}}} -% -\leftedline{|\xintiiGCD{123456789012345}{9876543210321}=|\dtt - {\xintiiGCD{123456789012345}{9876543210321}}} - -With release |1.3d|, this macro is also available from loading -\xintname\NewWith{1.3d}, hence also with \xintexprname, as it used by the -\func{gcd} function in \csbxint{iiexpr}, hence removes a dependency of -\xintexprname on \xintgcdname. - -\subsection{\csh{xintGCD}}\label{xintGCD} +\xintname, hence \func{gcd} and \func{lcm} functions in \csbxint{iiexpr} were +available simply from loading only \xintexprname, and the \xintgcdname dependency +got removed. -\csa{xintGCD} uses \csbxint{Num} overhead to make its arguments into strict -integers\etype{\Numf\Numf} first. With \xintfracname loaded this conversion -means truncation to integers. - -\subsection{\csh{xintGCDof}}\label{xintGCDof} - -\csa{xintGCDof}|{{a}{b}{c}...}|\etype{f{$\to$}{\lowast\Numf}} computes the greatest common divisor of all -integers |a|, |b|, \dots{} The list argument -may be a macro, it is \fexpan ded first and must contain at least one item. - -\subsection{\csh{xintiiLCM}}\label{xintiiLCM} - -|\xintiiLCM|\n\m\etype{ff} computes the least common multiple of integers. It -is positive, except if one |N| or |M| vanishes, in which case the macro -returns zero. -% -\leftedline{\csa{xintiiLCM}|{10000}{1113}|\dtt{=\xintiiLCM{10000}{1113}}} -% -\leftedline{|\xintiiLCM{123456789012345}{9876543210321}=|\dtt - {\xintiiLCM{123456789012345}{9876543210321}}} - -With release |1.3d|, this macro is also available from loading -\xintname\NewWith{1.3d}, hence also with \xintexprname, as it used by the -\func{lcm} function in \csbxint{iiexpr}, hence removes a dependency of -\xintexprname on \xintgcdname. - -\subsection{\csh{xintLCM}}\label{xintLCM} - -\csa{xintLCM} uses \csbxint{Num} overhead to make its arguments into strict -integers\etype{\Numf\Numf} first. With \xintfracname loaded this conversion -means truncation to integers. - -\subsection{\csh{xintLCMof}}\label{xintLCMof} +\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} -\csa{xintLCMof}|{{a}{b}{c}...}|\etype{f{$\to$}{\lowast\Numf}} computes the least -common multiple of all integers |a|, |b|, \dots{} The list argument may be a -macro, it is \fexpan ded first and must contain at least one item. \subsection{\csh{xintBezout}}\label{xintBezout} @@ -14487,8 +13934,6 @@ This macro is just an example of how to organize the data returned by \csa{xintEuclideAlgorithm}.\ntype{\Numf\Numf} Copy the source code to a new macro and modify it to what is needed. -\emph{Usage of this macro requires the user to load} \xinttoolsname.\IMPORTANT - \leftedline{|\xintTypesetEuclideAlgorithm {123456789012345}{9876543210321}|} \xintTypesetEuclideAlgorithm {123456789012345}{9876543210321} @@ -14499,8 +13944,6 @@ This macro is just an example of how to organize the data returned by \csa{xintBezoutAlgorithm}.\ntype{\Numf\Numf} Copy the source code to a new macro and modify it to what is needed. -\emph{Usage of this macro requires the user to load} \xinttoolsname.\IMPORTANT - \leftedline{|\xintTypesetBezoutAlgorithm {10000}{1113}|} \xintTypesetBezoutAlgorithm {10000}{1113} @@ -16230,8 +15673,8 @@ accept |\par| tokens on input. The completely expandable utilities (up to \csbxint{iloop}) are documented first, then the non expandable utilities. -A brief overview is in \autoref{sec:sometoolsutils} and \autoref{sec:examples} -has more examples of use of macros of this package. +\autoref{sec:examples} +gives additional (also dated) examples of use of macros of this package. \subsection{\csh{xintRevWithBraces}}\label{xintRevWithBraces} @@ -16579,6 +16022,18 @@ first expanding the list argument: |\xintNthEltNoExpand {-4}{\u\v\w T\x\y\z}| is 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.\NewWith{1.4} + +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| @@ -16860,7 +16315,8 @@ illustrate use of the nesting capabilities of |\xintloop|.% \footnote{for a more sophisticated implementation of matrix multiplication, inclusive of determinants, inverses, and display utilities, with entries big integers or decimal numbers or even - fractions see \url{http://tex.stackexchange.com/a/143035/4686} from + fractions see some code online posted + from November 11, 2013.} % @@ -17250,6 +16706,12 @@ separated list and the replacement text. 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. @@ -17893,7 +17355,7 @@ be treated as first item) number. %% END OF MACRO DEFINITIONS FOR SOURCEXINT -\def\xintImpRunningHeader{{\catcode`,12\relax +\def\xintImpRunningHeader{{\inheadertrue\catcode`,12\relax \DOCxintfrontpage, \xintkernelnameimp, \xinttoolsnameimp, @@ -17914,24 +17376,23 @@ be treated as first item) number. This is \expandafter|\xintbndlversion| of \expandafter|\xintbndldate|. -Please refer to |CHANGES.pdf| or |CHANGES.html|.\centeredline{Internet: +Please refer |CHANGES.html|.\centeredline{Internet: \url{http://mirrors.ctan.org/macros/generic/xint/CHANGES.html}} We keep here only a brief timeline of the most important changes. -At |1.3e| the indices which were added at |1.3c| got removed: their inclusion -caused extra time in the build of |sourcexint.pdf|, larger file size, and the -macros created using |\csname...\endcsname| were not indexed, of course the -indexing of functions would have needed systematic extra mark-up. Besides -their functionality is advantageously made available via the search function -in PDF viewers. Already the local tables of contents are useful enough most of -the time when one searches something. - \begin{itemize} +\item Release |1.4| of |2020/01/31|: this was a major release with + breaking changes, devoted to a re-write of \xintexprnameimp + with |\expanded| based expansion control rather than |\csname| storage + of intermediate computation results. Support for input and output + of nested structures, and multiple additions to \xintexprnameimp. \item Release |1.3f| of |2019/09/10|: starred variant \csbxint{Digits*}. \item Release |1.3e| of |2019/04/05|: \xinttrignameimp, \xintlognameimp, - \csbxint{defefunc} ``non-protected'' variant of \csbxint{deffunc}. + \csa{xintdefefunc} ``non-protected'' variant of \csbxint{deffunc}. - Indices removed from |sourcexint.pdf|. + 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|: bugfix of |1.2p| bug for division with a zero dividend and a one-digit divisor, \csbxint{eval} et al. wrappers, |gcd()| and |lcm()| work with fractions. @@ -18015,6 +17476,9 @@ math shift catcode. % \changed{1.3b}{} % \csbxint{UniformDeviate}. % +% \changed{1.4}{2020/01/11} +% \csbxint{Replicate}, \csbxint{Gobble}, \csbxint{LastOne}, \csbxint{FirstOne}. +% % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code for reload detection was initially copied from \textsc{Heiko @@ -18139,6 +17603,7 @@ math shift catcode. \catcode126=3 % ~ MATH \catcode59=12 % ; \catcode0=12 % for \romannumeral`&&@ trick + \catcode1=3 % for ultra-safe séparateur &&A }% \XINT_setcatcodes }% @@ -18173,7 +17638,7 @@ math shift catcode. \fi \XINT_providespackage \ProvidesPackage {xintkernel}% - [2019/09/10 v1.3f Paraphernalia for the xint packages (JFB)]% + [2020/01/31 v1.4 Paraphernalia for the xint packages (JFB)]% % \end{macrocode} % \subsection{Constants} % \begin{macrocode} @@ -18192,6 +17657,7 @@ math shift catcode. \chardef\xint_c_xiv 14 \chardef\xint_c_xvi 16 \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 @@ -18216,26 +17682,34 @@ math shift catcode. % \changed{1.3b}{} % |\xint_gobandstop_...| macros because this is handy for % \csbxint{RandomDigits}. +% |1.3g| forces \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: ATTENTION!}% + \immediate\write-1{Package xintkernel Warning:}% \immediate\write-1{\string\space\XINT_tmpa macro does not have its normal - meaning.}% - \immediate\write-1{\XINT_tmpa\XINT_tmpa\XINT_tmpa\XINT_tmpa - All kinds of catastrophes will ensue!!!!}% + 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_tmpb {}% -\ifx\XINT_tmpb\empty\else - \immediate\write-1{Package xintkernel Warning: ATTENTION!}% - \immediate\write-1{\string\empty\XINT_tmpa macro does not have its normal - meaning.}% - \immediate\write-1{\XINT_tmpa\XINT_tmpa\XINT_tmpa\XINT_tmpa - All kinds of catastrophes will ensue!!!!}% +\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_tmpb\relax -\ifdefined\space\else\def\space { }\fi -\ifdefined\empty\else\def\empty {}\fi +\let\XINT_tmpa\relax \let\xint_gobble_\empty \long\def\xint_gobble_i #1{}% \long\def\xint_gobble_ii #1#2{}% @@ -18286,6 +17760,7 @@ math shift catcode. \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!{}% \long\def\xint_gob_til_sc #1;{}% @@ -18327,15 +17802,11 @@ math shift catcode. % \subsection{\csh{xint_zapspaces}} % \changed{1.1}{} % -% This little utility zaps leading, intermediate, trailing, spaces in -% completely expanding context (|\edef|, |\csname...\endcsname|). +% 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|} % -% Will remove some brace pairs (but not spaces inside them). By the way the -% |\zap@spaces| of LaTeX2e handles unexpectedly things such as -% \centeredline{|\zap@spaces 1 {22} 3 4 \@empty|} (spaces are not all -% removed). This does not happen with |\xint_zapspaces|. -% % Explanation: if there are leading spaces, then the first |#1| will be empty, % and the first |#2| being undelimited will be stripped from all the remaining % leading spaces, if there was more than one to start with. Of course @@ -18344,16 +17815,27 @@ math shift catcode. % and |#1| will end at the first space. Ultimately |#2| will be % |\xint_gobble_i|. % -% This is not really robust as it may switch the expansion order of macros, -% and the |\xint_zapspaces| token might end up being fetched up by a macro. -% But it is enough for our purposes, for example: -% \centeredline{|\the\numexpr\xint_zapspaces 1 2 \xint_gobble_i\relax|} -% expands to |12|, not to |12\relax|. +% 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. % -% \changed{1.2e}{} |\xint_zapspaces_o|. Expansion of |#1| should not gobble a -% space! +% 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}% @@ -18410,10 +17892,15 @@ math shift catcode. % \changed{1.2g}{} added \csbxint{CSVLength} to \xinttoolsnameimp. % % \changed{1.2i}{} rewrote this venerable macro. New code about 40\% -% faster across all lengths. +% 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% +\def\xintlength #1{% +\long\def\xintlength ##1% {% \expandafter#1\the\numexpr\XINT_length_loop ##1\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint:\xint: @@ -18434,8 +17921,16 @@ math shift catcode. % \end{macrocode} % \subsection{\csh{xintLastItem}} % \changed{1.2i}{2016/12/10} -% Output empty if input empty. One level -% of braces removed in output. Does not expand its argument. +% 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% @@ -18461,6 +17956,76 @@ math shift catcode. \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}} +% \lverb|1.4. There must be neither \xint: +% nor \xint_bye in its first item.| +% \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}} +% \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 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. +% +% | +% \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}} +% \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 brace 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. +% | +% \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**. @@ -18503,7 +18068,7 @@ math shift catcode. \krof }% % \end{macrocode} -% \subsection{\csh{xintreplicate}} +% \subsection{\csh{xintreplicate}, \csh{xintReplicate}} % \changed{1.2i}{} % % This is cloned from LaTeX3's |\prg_replicate:nn|, see Joseph's post @@ -18521,7 +18086,15 @@ math shift catcode. % call the macro as % \centeredline{|\romannumeral\XINT_rep N\endcsname {foo}|} % to skip the |\numexpr|. +% +% \changed{1.4}{2020/01/11} +% 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 @@ -18573,14 +18146,17 @@ math shift catcode. \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}} +% \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{1.4}{2020/01/11} +% 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}% @@ -18759,6 +18335,7 @@ math shift catcode. % This is copied over from l3kernel code. I am using |\ ! /| control sequence % though, which must be left undefined. |\xintError:| would be 6 letters more % already. +% \changed{1.4}{2020/01/25} Finally rather than |\ ! /| I use |\xint/|. % \begin{macrocode} \def\XINT_expandableerror #1#2{% \def\XINT_expandableerror ##1{% @@ -18766,10 +18343,10 @@ math shift catcode. \XINT_expandableerror_continue\xint_firstofone{#2#1##1#1}}% \def\XINT_expandableerror_continue ##1#1##2#1{##1}% }% -\begingroup\lccode`$ 32 \catcode`/ 11 \catcode`! 11 \catcode32 11 % $ +\begingroup\lccode`$ 32 \catcode`/ 11 % $ % \end{macrocode} % \begin{macrocode} -\lowercase{\endgroup\XINT_expandableerror$\ ! /\let\ ! /\xint_undefined}% $ +\lowercase{\endgroup\XINT_expandableerror$\xint/\let\xint/\xint_undefined}% $ \XINT_restorecatcodes_endinput% % \end{macrocode} % \StoreCodelineNo {xintkernel} @@ -18847,7 +18424,7 @@ math shift catcode. % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xinttools}% - [2019/09/10 v1.3f Expandable and non-expandable utilities (JFB)]% + [2020/01/31 v1.4 Expandable and non-expandable utilities (JFB)]% % \end{macrocode} % \lverb|\XINT_toks is used in macros such as \xintFor. It is not used % elsewhere in the xint bundle.| @@ -19223,6 +18800,55 @@ math shift catcode. \xint_gob_til_xint:##1\expandafter#1\xint_gobble_ii\xint:#1##1}% }\XINT_nthelt_pos_done{ }% % \end{macrocode} +% \subsection{\csh{xintNthOnePy}} +% \lverb| +% First included in release 1.4. See relevant code comments in xintexpr. +% | +% \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}} % \lverb@& % @@ -19522,6 +19148,50 @@ math shift catcode. \long\def\XINT_apply_end\xint_bye\expandafter\XINT_apply_loop_b \expandafter #1#2#3{ #2}% % \end{macrocode} +% \subsection{\csh{xintApply:x} (not public)} +% \lverb|Done for 1.4, 2020/01/27. For usage in the NumPy-like slicing routines. +% +% Supposed to expand in an \expanded context, does not need to +% do any expansion of its second argument. +% +% 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... +% +% Could be however that picking one by one would be better for small +% number of items. +% +% And anyhow for small number of items gain with respect to \xintApply is little +% if any (might even be a loss).| +% \begin{macrocode} +\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}}% +% \end{macrocode} % \subsection{\csh{xintApplyUnbraced}} % \lverb|\xintApplyUnbraced {\macro}{{a}{b}...{z}} returns \macro{a}...\macro{z} % where each instance of \macro is f-expanded using \romannumeral-`0. The second @@ -19549,6 +19219,64 @@ math shift catcode. \long\def\XINT_applyunbr_end\xint_bye\expandafter\XINT_applyunbr_loop_b \expandafter #1#2#3{ #2}% % \end{macrocode} +% \subsection{\csh{xintApplyUnbraced:x} (not public)} +% \lverb|Done for 1.4, 2020/01/27. For usage in the NumPy-like slicing +% routines. +% +% The items should not contain \xint: and the applied macro should not contain +% \empty.| +% \begin{macrocode} +\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{macrocode} % \subsection{\csh{xintSeq}} % \lverb|1.09c. Without the optional argument puts stress on the input stack, % should not be used to generated thousands of terms then.| @@ -20245,14 +19973,6 @@ math shift catcode. }% \let\xintDigitsOf\xintAssignArray % \end{macrocode} -% \subsection{\csh{xintExpandArgs}} -% \lverb|1.3a. Added for the needs of user defined functions for the -% expression parsers. Should I re-code it to gain a bit in argument grabbing? -% Must be f-expandable.| -% \begin{macrocode} -\def\xintExpandArgs#1#2{\csname #1\expandafter\endcsname - \romannumeral0\xintapply\xint_firstofone{#2}}% -% \end{macrocode} %\subsection{CSV (non user documented) variants of Length, Keep, Trim, NthElt, Reverse} % % These routines are for use by |\xintListSel:x:csv| and |\xintListSel:f:csv| @@ -20712,8 +20432,59 @@ math shift catcode. \XINT_last:f:csv_loop {#9}.% }% % \end{macrocode} +% \subsubsection{\csh{xintKeep:x:csv}} +% \lverb|Added to xintexpr at 1.2j. +% +% But data model changed at 1.4, this macro moved to xinttools, not part of +% publicly supported macros, may be removed at any time. +% +% This macro is used only with positive first argument. +% | +% \begin{macrocode} +\def\xintKeep:x:csv #1#2% +{% + \expandafter\xint_gobble_i + \romannumeral0\expandafter\XINT_keep:x:csv_pos + \the\numexpr #1\expandafter.\expandafter{\romannumeral`&&@#2}% +}% +\def\XINT_keep:x:csv_pos #1.#2% +{% + \expandafter\XINT_keep:x:csv_loop\the\numexpr#1-\xint_c_viii.% + #2\xint_Bye,\xint_Bye,\xint_Bye,\xint_Bye,% + \xint_Bye,\xint_Bye,\xint_Bye,\xint_Bye,\xint_bye +}% +\def\XINT_keep:x:csv_loop #1% +{% + \xint_gob_til_minus#1\XINT_keep:x:csv_finish-% + \XINT_keep:x:csv_loop_pickeight #1% +}% +\def\XINT_keep:x:csv_loop_pickeight #1.#2,#3,#4,#5,#6,#7,#8,#9,% +{% + ,#2,#3,#4,#5,#6,#7,#8,#9% + \expandafter\XINT_keep:x:csv_loop\the\numexpr#1-\xint_c_viii.% +}% +\def\XINT_keep:x:csv_finish-\XINT_keep:x:csv_loop_pickeight -#1.% +{% + \csname XINT_keep:x:csv_finish#1\endcsname +}% +\expandafter\def\csname XINT_keep:x:csv_finish1\endcsname + #1,#2,#3,#4,#5,#6,#7,{,#1,#2,#3,#4,#5,#6,#7\xint_Bye}% +\expandafter\def\csname XINT_keep:x:csv_finish2\endcsname + #1,#2,#3,#4,#5,#6,{,#1,#2,#3,#4,#5,#6\xint_Bye}% +\expandafter\def\csname XINT_keep:x:csv_finish3\endcsname + #1,#2,#3,#4,#5,{,#1,#2,#3,#4,#5\xint_Bye}% +\expandafter\def\csname XINT_keep:x:csv_finish4\endcsname + #1,#2,#3,#4,{,#1,#2,#3,#4\xint_Bye}% +\expandafter\def\csname XINT_keep:x:csv_finish5\endcsname + #1,#2,#3,{,#1,#2,#3\xint_Bye}% +\expandafter\def\csname XINT_keep:x:csv_finish6\endcsname + #1,#2,{,#1,#2\xint_Bye}% +\expandafter\def\csname XINT_keep:x:csv_finish7\endcsname + #1,{,#1\xint_Bye}% +\expandafter\let\csname XINT_keep:x:csv_finish8\endcsname\xint_Bye +% \end{macrocode} % \subsubsection{Public names for the undocumented csv macros: -% \csh{xintCSVLength}, \csh{xintCSVKeep}, \csh{xintCSVTrim}, +% \csh{xintCSVLength}, \csh{xintCSVKeep}, \csh{xintCSVKeepx}, \csh{xintCSVTrim}, % \csh{xintCSVNthEltPy}, \csh{xintCSVReverse}, % \csh{xintCSVFirstItem}, \csh{xintCSVLastItem}} % @@ -20725,6 +20496,7 @@ math shift catcode. % \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 @@ -20816,7 +20588,7 @@ math shift catcode. % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintcore}% - [2019/09/10 v1.3f Expandable arithmetic on big integers (JFB)]% + [2020/01/31 v1.4 Expandable arithmetic on big integers (JFB)]% % \end{macrocode} % \subsection{(WIP!) Error conditions and exceptions} % \lverb|As per the Mike Cowlishaw/IBM's General Decimal Arithmetic Specification @@ -22379,7 +22151,9 @@ math shift catcode. \expandafter\XINT_mul_nfork\expandafter #1\romannumeral`&&@#3\xint:#2\xint: }% % \end{macrocode} -% \lverb|(1.2) I have changed the fork, and it complicates matters elsewhere.| +% \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.| % \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% @@ -24116,7 +23890,7 @@ math shift catcode. % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xint}% - [2019/09/10 v1.3f Expandable operations on big integers (JFB)]% + [2020/01/31 v1.4 Expandable operations on big integers (JFB)]% % \end{macrocode} % \subsection{More token management} % \begin{macrocode} @@ -24953,54 +24727,69 @@ math shift catcode. % % 1.2o's \xintifTrueAelseB is now an ii macro, actually. % -% This macro as well as ORof and XORof are actually not used by xintexpr, -% which has its own csv handling macros.| +% 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. +% +% | % \begin{macrocode} -\def\xintANDof {\romannumeral0\xintandof }% -\def\xintandof #1{\expandafter\XINT_andof_a\romannumeral`&&@#1\xint:}% -\def\XINT_andof_a #1{\expandafter\XINT_andof_b\romannumeral`&&@#1!}% -\def\XINT_andof_b #1% - {\xint_gob_til_xint: #1\XINT_andof_e\xint:\XINT_andof_c #1}% -\def\XINT_andof_c #1!% - {\xintifTrueAelseB {#1}{\XINT_andof_a}{\XINT_andof_no}}% -\def\XINT_andof_no #1\xint:{ 0}% -\def\XINT_andof_e #1!{ 1}% +\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}} % \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.| +% 1.2l made \xintORof robust against non terminated items. +% +% Refactored at 1.4.| % \begin{macrocode} -\def\xintORof {\romannumeral0\xintorof }% -\def\xintorof #1{\expandafter\XINT_orof_a\romannumeral`&&@#1\xint:}% -\def\XINT_orof_a #1{\expandafter\XINT_orof_b\romannumeral`&&@#1!}% -\def\XINT_orof_b #1% - {\xint_gob_til_xint: #1\XINT_orof_e\xint:\XINT_orof_c #1}% -\def\XINT_orof_c #1!% - {\xintifTrueAelseB {#1}{\XINT_orof_yes}{\XINT_orof_a}}% -\def\XINT_orof_yes #1\xint:{ 1}% -\def\XINT_orof_e #1!{ 0}% +\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}} % \lverb|New with 1.09a. Works with an empty list, too. Empty items % however are not accepted. \XINT_xorof_c more % efficient in 1.09i. % -% 1.2l made \xintXORof robust against non terminated items.| -% \begin{macrocode} -\def\xintXORof {\romannumeral0\xintxorof }% -\def\xintxorof #1{\expandafter\XINT_xorof_a\expandafter - 0\romannumeral`&&@#1\xint:}% -\def\XINT_xorof_a #1#2{\expandafter\XINT_xorof_b\romannumeral`&&@#2!#1}% -\def\XINT_xorof_b #1% - {\xint_gob_til_xint: #1\XINT_xorof_e\xint:\XINT_xorof_c #1}% -\def\XINT_xorof_c #1!#2% - {\xintifTrueAelseB {#1}{\if #20\xint_afterfi{\XINT_xorof_a 1}% - \else\xint_afterfi{\XINT_xorof_a 0}\fi}% - {\XINT_xorof_a #2}% - }% -\def\XINT_xorof_e #1!#2{ #2}% +% 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. +% | +% \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}} % \lverb|& @@ -25131,62 +24920,142 @@ math shift catcode. % % NOT compatible with empty list. % -% 1.2l made \xintiiMaxof robust against non terminated items.| +% 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. +% | % \begin{macrocode} -\def\xintiiMaxof {\romannumeral0\xintiimaxof }% -\def\xintiimaxof #1{\expandafter\XINT_iimaxof_a\romannumeral`&&@#1\xint:}% -\def\XINT_iimaxof_a #1{\expandafter\XINT_iimaxof_b\romannumeral`&&@#1!}% -\def\XINT_iimaxof_b #1!#2% - {\expandafter\XINT_iimaxof_c\romannumeral`&&@#2!{#1}!}% -\def\XINT_iimaxof_c #1% - {\xint_gob_til_xint: #1\XINT_iimaxof_e\xint:\XINT_iimaxof_d #1}% -\def\XINT_iimaxof_d #1!% - {\expandafter\XINT_iimaxof_b\romannumeral0\xintiimax {#1}}% -\def\XINT_iimaxof_e #1!#2!{ #2}% +\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}} -% \lverb|1.09a. 1.2a adds \xintiiMinof which was lacking.| -% \begin{macrocode} -\def\xintiiMinof {\romannumeral0\xintiiminof }% -\def\xintiiminof #1{\expandafter\XINT_iiminof_a\romannumeral`&&@#1\xint:}% -\def\XINT_iiminof_a #1{\expandafter\XINT_iiminof_b\romannumeral`&&@#1!}% -\def\XINT_iiminof_b #1!#2% - {\expandafter\XINT_iiminof_c\romannumeral`&&@#2!{#1}!}% -\def\XINT_iiminof_c #1% - {\xint_gob_til_xint: #1\XINT_iiminof_e\xint:\XINT_iiminof_d #1}% -\def\XINT_iiminof_d #1!% - {\expandafter\XINT_iiminof_b\romannumeral0\xintiimin {#1}}% -\def\XINT_iiminof_e #1!#2!{ #2}% +% \lverb|1.09a. 1.2a adds \xintiiMinof which was lacking. +% +% 1.4 refactoring for \xintiiexpr matters.| +% \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}} % \lverb|\xintiiSum {{a}{b}...{z}} -%| +% Refactored at 1.4 for matters initially related to xintexpr delimiter +% choice. +% +% +% | % \begin{macrocode} \def\xintiiSum {\romannumeral0\xintiisum }% -\def\xintiisum #1{\expandafter\XINT_sumexpr\romannumeral`&&@#1\xint:}% -\def\XINT_sumexpr {\XINT_sum_loop_a 0\Z }% -\def\XINT_sum_loop_a #1\Z #2% - {\expandafter\XINT_sum_loop_b \romannumeral`&&@#2\xint:#1\xint:\Z}% -\def\XINT_sum_loop_b #1% - {\xint_gob_til_xint: #1\XINT_sum_finished\xint:\XINT_sum_loop_c #1}% -\def\XINT_sum_loop_c - {\expandafter\XINT_sum_loop_a\romannumeral0\XINT_add_fork }% -\def\XINT_sum_finished\xint:\XINT_sum_loop_c\xint:\xint:#1\xint:\Z{ #1}% +\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} +% \lverb|bad coding as it depends on internal conventions of \XINT_add_nfork| +% \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} +% \lverb|see previous comment!| +% \begin{macrocode} +\def\XINT_iisum_loop_end ^#1\XINT_add_nfork #2#3\xint:#4\xint:\xint:{ #2#4}% % \end{macrocode} % \subsection{\csh{xintiiPrd}} % \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. +% +% %| % \begin{macrocode} \def\xintiiPrd {\romannumeral0\xintiiprd }% -\def\xintiiprd #1{\expandafter\XINT_prdexpr\romannumeral`&&@#1\xint:}% -\def\XINT_prdexpr {\XINT_prod_loop_a 1\Z }% -\def\XINT_prod_loop_a #1\Z #2% - {\expandafter\XINT_prod_loop_b\romannumeral`&&@#2\xint:#1\xint:\Z}% -\def\XINT_prod_loop_b #1% - {\xint_gob_til_xint: #1\XINT_prod_finished\xint:\XINT_prod_loop_c #1}% -\def\XINT_prod_loop_c - {\expandafter\XINT_prod_loop_a\romannumeral0\XINT_mul_fork }% -\def\XINT_prod_finished\xint:\XINT_prod_loop_c\xint:\xint:#1\xint:\Z { #1}% +\def\xintiiprd #1{\expandafter\XINT_iiprd\romannumeral`&&@#1^}% +\def\XINT_iiPrd{\romannumeral0\XINT_iiprd}% +% \end{macrocode} +% \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. +% +% | +% \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} +% \lverb|bad coding as it depends on internal conventions of \XINT_mul_nfork| +% \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} +% \lverb|see previous comment!| +% \begin{macrocode} +\def\XINT_iiprd_loop_end ^#1\XINT_mul_nfork #2#3\xint:#4\xint:\xint:{ #2#4}% % \end{macrocode} % \subsection{\csh{xintiiSquareRoot}} % \lverb|First done with 1.08. @@ -26196,9 +26065,12 @@ math shift catcode. \csname if#1\endcsname\expandafter1\else\expandafter0\fi }% \def\xintToggle #1{\romannumeral`&&@\iftoggle{#1}{1}{0}}% % \end{macrocode} -% \subsection{\cshnolabel{xintGCD}, \cshnolabel{xintiiGCD}} -% Copied over from \csbxint{iiGCD} of \xintgcdnameimp at |1.3d| to +% \subsection{\csh{xintiiGCD}} +% Copied over |\xintiiGCD| code from \xintgcdnameimp at |1.3d| in order to % support |gcd()| function in \csbxint{iiexpr}. +% +% At |1.4| original code removed from +% \xintgcdnameimp as the latter now requires \xintnameimp. % \begin{macrocode} \def\xintiiGCD {\romannumeral0\xintiigcd }% \def\xintiigcd #1{\expandafter\XINT_iigcd\romannumeral0\xintiiabs#1\xint:}% @@ -26230,7 +26102,12 @@ math shift catcode. }% \def\XINT_gcd_end0\XINT_gcd_loop #1\xint:#2\xint:{ #2}% % \end{macrocode} -% \subsection{\cshnolabel{xintLCM}, \cshnolabel{xintiiLCM}} +% \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:}% @@ -26259,6 +26136,38 @@ math shift catcode. }% \def\XINT_lcm_end #1\xint:#2\xint:#3\xint:{\xintiimul {#2}{\xintiiQuo{#3}{#1}}}% % \end{macrocode} +% \subsection{\csh{xintiiGCDof}} +% \lverb|New with 1.09a (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. +% See comments +% in xintfrac.sty about \xintGCDof macro there.| +% +% \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{xintiiLCMof}} +% \lverb|See comments of \xintiiGCDof|. +% \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}} % \lverb|1.3b. See user manual. Whether this will be part of xintkernel, % xintcore, or xint is yet to be decided.| @@ -26293,8 +26202,8 @@ math shift catcode. \def\XINT_rdg_aux#1{XINT_rdg\endcsname}% \let\XINT_XINT_rdg\endcsname % \end{macrocode} -% \subsection{(WIP) \csh{XINT_eightrandomdigits}} -% \lverb|1.3b.| +% \subsection{(WIP) \csh{XINT_eightrandomdigits}, \csh{xintEightRandomDigits}} +% \lverb|1.3b. 1.4 adds some public alias...| % \begin{macrocode} \def\XINT_eightrandomdigits {% @@ -26307,6 +26216,13 @@ math shift catcode. +\xint_texuniformdeviate\xint_c_x^viii% \relax% }% +\let\xintEightRandomDigits\XINT_eightrandomdigits +\def\xintRandBit{\xint_texuniformdeviate\xint_c_ii}% +% \end{macrocode} +% \subsection{(WIP) \csh{xintRandBit}} +% \lverb|1.4 And let's add also \xintRandBit while we are at it.| +% \begin{macrocode} +\def\xintRandBit{\xint_texuniformdeviate\xint_c_ii}% % \end{macrocode} % \subsection{(WIP) \csh{xintXRandomDigits}} % \lverb|1.3b.| @@ -26330,7 +26246,7 @@ math shift catcode. % \subsection{(WIP) \csh{xintiiRandRangeAtoB}} % \lverb|1.3b. Support for randrange() function. % -% Wee do it f-expandably for matters of \xintNewExpr etc... The \xintexpr will +% 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. % @@ -26437,7 +26353,7 @@ math shift catcode. \def\XINT_randrange_E #1\xint:#2\xint:{ #1}% \def\XINT_randrange_again #1\xint:{\XINT_randrange_c}% % \end{macrocode} -% \subsection{Adjustments for engines without uniformdeviate primitive} +% \subsection{(WIP) Adjustments for engines without uniformdeviate primitive} % \lverb|1.3b.| % \begin{macrocode} \ifdefined\xint_texuniformdeviate @@ -26540,7 +26456,7 @@ math shift catcode. % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintbinhex}% - [2019/09/10 v1.3f Expandable binary and hexadecimal conversions (JFB)]% + [2020/01/31 v1.4 Expandable binary and hexadecimal conversions (JFB)]% % \end{macrocode} % \subsection{Constants, etc...} % \lverb|1.2n switches to \csname-governed expansion at various places.| @@ -27121,20 +27037,33 @@ math shift catcode. % % \localtableofcontents % -% The commenting is currently (\xintdocdate) very sparse. Release |1.09h| has +% The commenting is currently (\xintdocdate) very sparse. +% +% Release |1.09h| has % modified a bit the |\xintTypesetEuclideAlgorithm| and % |\xintTypesetBezoutAlgorithm| layout with respect to line indentation in % particular. And they use the \xinttoolsnameimp |\xintloop| rather than the % Plain \TeX{} or \LaTeX{}'s |\loop|. % -% Since |1.1| the package only loads \xintcorenameimp, not \xintnameimp. And -% for the |\xintTypesetEuclideAlgorithm| and |\xintTypesetBezoutAlgorithm| -% macros to be functional the package \xinttoolsnameimp needs to be loaded -% explicitely by the user. % % Breaking change at |1.2p|: |\xintBezout{A}{B}| formerly had output % |{A}{B}{U}{V}{D}| with |AU-BV=D|, now it is |{U}{V}{D}| with |AU+BV=D|. % +% 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 integer-only macros have been renamed into respectively +% \csbxint{iiGCD}, \csbxint{iiLCM}, \csbxint{iiGCDof}, and \csbxint{iiLCMof} +% and got relocated into \xintnameimp package.\CHANGEDf{1.4} +% \end{framed} +% % \subsection{Catcodes, \protect\eTeX{} and reload detection} % % The code for reload detection was initially copied from \textsc{Heiko @@ -27155,9 +27084,10 @@ math shift catcode. \catcode45=12 % - \catcode46=12 % . \catcode58=12 % : - \let\z\endgroup + \def\z{\endgroup}% \expandafter\let\expandafter\x\csname ver@xintgcd.sty\endcsname - \expandafter\let\expandafter\w\csname ver@xintcore.sty\endcsname + \expandafter\let\expandafter\w\csname ver@xint.sty\endcsname + \expandafter\let\expandafter\t\csname ver@xinttools.sty\endcsname \expandafter \ifx\csname PackageInfo\endcsname\relax \def\y#1#2{\immediate\write-1{Package #1 Info: #2.}}% @@ -27170,15 +27100,21 @@ math shift catcode. \aftergroup\endinput \else \ifx\x\relax % plain-TeX, first loading of xintgcd.sty - \ifx\w\relax % but xintcore.sty not yet loaded. - \def\z{\endgroup\input xintcore.sty\relax}% + \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 \def\empty {}% \ifx\x\empty % LaTeX, first loading, % variable is initialized, but \ProvidesPackage not yet seen - \ifx\w\relax % xintcore.sty not yet loaded. - \def\z{\endgroup\RequirePackage{xintcore}}% + \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 \aftergroup\endinput % xintgcd already loaded. @@ -27192,94 +27128,7 @@ math shift catcode. % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintgcd}% - [2019/09/10 v1.3f Euclide algorithm with xint package (JFB)]% -% \end{macrocode} -% \subsection{\csh{xintGCD}, \csh{xintiiGCD}} -% \lverb|& -% | -% \changed{1.3d}{} -% \lverb|Removed some braces in favor of \xint: delimiter at 1.3d (but -% \xintiiGCD was already robust against non-delimited \numexpr inputs -% thanks to using \xintiiabs{...}) and refactored the whole -% \XINT_iigcd_fork. | -% \begin{macrocode} -\def\xintGCD {\romannumeral0\xintgcd }% -\def\xintgcd #1#2{\xintiigcd {\xintNum{#1}}{\xintNum{#2}}}% -\def\xintiiGCD {\romannumeral0\xintiigcd }% -% \end{macrocode} -% \lverb|This abuses the way \xintiiabs expands.| -% \begin{macrocode} -\def\xintiigcd #1{\expandafter\XINT_iigcd\romannumeral0\xintiiabs#1\xint:}% -\def\XINT_iigcd #1#2\xint:#3% -{% - \expandafter\XINT_gcd_fork\expandafter#1% - \romannumeral0\xintiiabs#3\xint:#1#2\xint: -}% -% \end{macrocode} -% \lverb|First argument now in second position (after \xint:) but -% its first digit is also the #1.| -% \begin{macrocode} -\def\XINT_gcd_fork #1#2% -{% - \xint_UDzerofork - #1\XINT_gcd_Aiszero - #2\XINT_gcd_Biszero - 0\XINT_gcd_loop - \krof - #2% -}% -\def\XINT_gcd_AisZero #1\xint:#2\xint:{ #1}% -\def\XINT_gcd_BisZero #1\xint:#2\xint:{ #2}% -% \end{macrocode} -% \lverb|\XINT_div_prepare{#1}{#2} divides #2 by #1, and outputs -% {Quotient}{Remainder}.| -% \begin{macrocode} -\def\XINT_gcd_loop #1\xint:#2\xint: -{% - \expandafter\expandafter\expandafter\XINT_gcd_CheckRem - \expandafter\xint_secondoftwo - \romannumeral0\XINT_div_prepare {#1}{#2}\xint:#1\xint: -}% -\def\XINT_gcd_CheckRem #1% -{% - \xint_gob_til_zero #1\XINT_gcd_end0\XINT_gcd_loop #1% -}% -\def\XINT_gcd_end0\XINT_gcd_loop #1\xint:#2\xint:{ #2}% -% \end{macrocode} -% \subsection{\csh{xintLCM}, \csh{xintiiLCM}} -% \lverb|See comments of \xintiiGCD for the refactoring done at 1.3d. -% No time to make \xintiiLCM code more efficient now. -% -% Macros \xintLCM, \xintlcm only for backwards compatibility.| -% \begin{macrocode} -\def\xintLCM {\romannumeral0\xintlcm}% -\def\xintlcm #1#2{\xintiilcm{\xintNum{#1}}{\xintNum{#2}}}% -\def\xintiiLCM {\romannumeral0\xintiilcm}% -\def\xintiilcm #1{\expandafter\XINT_iilcm\romannumeral0\xintiiabs#1\xint:}% -\def\XINT_iilcm #1#2\xint:#3% -{% - \expandafter\XINT_lcm_fork\expandafter#1% - \romannumeral0\xintiiabs#3\xint:#1#2\xint: -}% -\def\XINT_lcm_fork #1#2% -{% - \xint_UDzerofork - #1\XINT_lcm_iszero - #2\XINT_lcm_iszero - 0\XINT_lcm_notzero - \krof - #2% -}% -\def\XINT_lcm_iszero #1\xint:#2\xint:{ 0}% -\def\XINT_lcm_notzero #1\xint:#2\xint: -{% - \expandafter\XINT_lcm_end\romannumeral0% - \expandafter\expandafter\expandafter\XINT_gcd_CheckRem - \expandafter\xint_secondoftwo - \romannumeral0\XINT_div_prepare {#1}{#2}\xint:#1\xint: - \xint:#1\xint:#2\xint: -}% -\def\XINT_lcm_end #1\xint:#2\xint:#3\xint:{\xintiimul {#2}{\xintiiQuo{#3}{#1}}}% + [2020/01/31 v1.4 Euclide algorithm with xint package (JFB)]% % \end{macrocode} % \subsection{\csh{xintBezout}} % \lverb|& @@ -27699,29 +27548,6 @@ math shift catcode. % \begin{macrocode} \def\XINT_bezalg_end_a #1#2#3#4{{#1}{#3}{0}{1}{#2}{#4}{1}{0}}% % \end{macrocode} -% \subsection{\csh{xintGCDof}} -% \lverb|1.2l adds protection against items being non-terminated \the\numexpr...| -% \begin{macrocode} -\def\xintGCDof {\romannumeral0\xintgcdof }% -\def\xintgcdof #1{\expandafter\XINT_gcdof_a\romannumeral`&&@#1\xint:}% -\def\XINT_gcdof_a #1{\expandafter\XINT_gcdof_b\romannumeral`&&@#1!}% -\def\XINT_gcdof_b #1!#2{\expandafter\XINT_gcdof_c\romannumeral`&&@#2!{#1}!}% -\def\XINT_gcdof_c #1{\xint_gob_til_xint: #1\XINT_gcdof_e\xint:\XINT_gcdof_d #1}% -\def\XINT_gcdof_d #1!{\expandafter\XINT_gcdof_b\romannumeral0\xintgcd {#1}}% -\def\XINT_gcdof_e #1!#2!{ #2}% -% \end{macrocode} -% \subsection{\csh{xintLCMof}} -% \lverb|New with 1.09a| -% \lverb|1.2l adds protection against items being non-terminated \the\numexpr...| -% \begin{macrocode} -\def\xintLCMof {\romannumeral0\xintlcmof }% -\def\xintlcmof #1{\expandafter\XINT_lcmof_a\romannumeral`&&@#1\xint:}% -\def\XINT_lcmof_a #1{\expandafter\XINT_lcmof_b\romannumeral`&&@#1!}% -\def\XINT_lcmof_b #1!#2{\expandafter\XINT_lcmof_c\romannumeral`&&@#2!{#1}!}% -\def\XINT_lcmof_c #1{\xint_gob_til_xint: #1\XINT_lcmof_e\xint:\XINT_lcmof_d #1}% -\def\XINT_lcmof_d #1!{\expandafter\XINT_lcmof_b\romannumeral0\xintlcm {#1}}% -\def\XINT_lcmof_e #1!#2!{ #2}% -% \end{macrocode} % \subsection{\csh{xintTypesetEuclideAlgorithm}} % \lverb|& % TYPESETTING @@ -27902,7 +27728,7 @@ math shift catcode. % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintfrac}% - [2019/09/10 v1.3f Expandable operations on fractions (JFB)]% + [2020/01/31 v1.4 Expandable operations on fractions (JFB)]% % \end{macrocode} % \subsection{\csh{XINT_cntSgnFork}} % \lverb|1.09i. Used internally, #1 must expand to \m@ne, \z@, or \@ne or @@ -28461,6 +28287,72 @@ math shift catcode. \fi { #2}{ #2/#3}% }% % \end{macrocode} +% \subsection{\csh{xintSPRaw}, \csh{xintFracToSci}} +% \lverb|This private macro was for usage by \xinttheexpr. It got moved here +% at 1.4. +% +% Attention that \xintSPRaw assumes that if the number has no [N] +% part it does not have a fraction part /B either. Indeed this was +% the case always with 1.3f (parsing of an integer by \xintexpr +% does not add the [0] because the code is shared with \xintiiexpr +% and when there is /B, \xintexpr always adds [0]; even qfrac() +% parses via \xintRaw; and reduce() internally uses \xintIrr +% whose outputs is A/B but it add [0]). +% +% \xintFracToSci is now used in its place. As reduce() does +% not anymore append the [0] at 1.4, \xintFracToSci has to recognize +% A, A[N], A/B and A/B[N] but does not have to parse multiple plus +% or minus signs or scientific part etc like \xintRaw knows. +% It has to identify say 0/5 (although I don't think that can +% arise) and -0 is never occuring. +% +% The difference with former case is that it outputs AeN/B hence +% does not anymore use the xintfrac.sty raw format. +% It will not printe the /B if B=1 and not print the «eN» if N is zero. +% +% If input is empty \xintFracToSci output is also empty, +% whereas \xintRaw produces 0/1[0] out of empty. But \XINTexprprint +% anyhow has it own special routine for empty input. +% | +% +% \begin{macrocode} +\def\xintSPRaw {\romannumeral0\xintspraw }% +\def\xintspraw #1{\expandafter\XINT_spraw\romannumeral`&&@#1[\W]}% +\def\XINT_spraw #1[#2#3]{\xint_gob_til_W #2\XINT_spraw_a\W\XINT_spraw_p #1[#2#3]}% +\def\XINT_spraw_a\W\XINT_spraw_p #1[\W]{ #1}% +\def\XINT_spraw_p #1[\W]{\xintpraw {#1}}% +\def\xintFracToSci #1% + {\expandafter\XINT_FracToSci\romannumeral`&&@#1/\W[\R]}% +\def\XINT_FracToSci #1/#2#3[#4% +{% + \xint_gob_til_W #2\XINT_FracToSci_no\W + \xint_gob_til_R #4\XINT_FracToSci_yesno\R + \XINT_FracToSci_yesyes #1/#2#3[#4% +}% +\def\XINT_FracToSci_no #1\XINT_FracToSci_yesyes #2[#3% +{% + \xint_gob_til_R #3\XINT_FracToSci_nono\R + \XINT_FracToSci_noyes #2[#3% +}% +\def\XINT_FracToSci_nono\R\XINT_FracToSci_noyes #1/\W[\R]{#1}% +\def\XINT_FracToSci_noyes #1#2[#3]/\W[\R]% +{% + #1\xint_gob_til_zero#1\expandafter\iffalse\xint_gobble_ii0\iftrue + #2\ifnum #3=\xint_c_\else\xintFracToSciE#3\fi\fi +}% +\def\XINT_FracToSci_yesno\R\XINT_FracToSci_yesyes #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_yesyes #1#2/#3[#4]/\W[\R]% +{% + #1\xint_gob_til_zero#1\expandafter\iffalse\xint_gobble_ii0\iftrue + #2\ifnum #4=\xint_c_\else\xintFracToSciE#4\fi + \if\XINT_isOne{#3}1\else/#3\fi\fi +}% +\def\xintFracToSciE{e}% +% \end{macrocode} % \subsection{\csh{xintRawWithZeros}} % \lverb|& % This was called \xintRaw in versions earlier than 1.07| @@ -29662,24 +29554,30 @@ math shift catcode. % \lverb|There was (not documented anymore since 1.09d, 2013/10/22) a macro % \xintSumExpr, but it has been deleted at 1.2l. % -% Empty items are not accepted by this macro.| +% 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. +% +% +% | % \begin{macrocode} \def\xintSum {\romannumeral0\xintsum }% -\def\xintsum #1{\expandafter\XINT_fsumexpr\romannumeral`&&@#1\xint:}% -\def\XINT_fsumexpr {\XINT_fsum_loop_a {0/1[0]}}% -\def\XINT_fsum_loop_a #1#2% -{% - \expandafter\XINT_fsum_loop_b \romannumeral`&&@#2\xint:{#1}% -}% -\def\XINT_fsum_loop_b #1% +\def\xintsum #1{\expandafter\XINT_sum\romannumeral`&&@#1^}% +\def\XINT_Sum{\romannumeral0\XINT_sum}% +\def\XINT_sum#1% {% - \xint_gob_til_xint: #1\XINT_fsum_finished\xint:\XINT_fsum_loop_c #1% + \xint_gob_til_^ #1\XINT_sum_empty ^% + \expandafter\XINT_sum_loop\romannumeral0\xintraw{#1}\xint: }% -\def\XINT_fsum_loop_c #1\xint:#2% +\def\XINT_sum_empty ^#1\xint:{ 0/1[0]}% +\def\XINT_sum_loop #1\xint:#2% {% - \expandafter\XINT_fsum_loop_a\expandafter{\romannumeral0\xintadd {#2}{#1}}% + \xint_gob_til_^ #2\XINT_sum_end ^% + \expandafter\XINT_sum_loop + \romannumeral0\xintadd{#1}{\romannumeral0\xintraw{#2}}\xint: }% -\def\XINT_fsum_finished #1\xint:\xint:#2{ #2}% +\def\XINT_sum_end ^#1\xintadd #2#3\xint:{ #2}% % \end{macrocode} % \subsection{\csh{xintMul}} % \begin{macrocode} @@ -29810,26 +29708,29 @@ math shift catcode. }% % \end{macrocode} % \subsection{\csh{xintPrd}} -% \lverb|There was (not documented anymore since 1.09d, 2013/10/22) a macro -% \xintPrdExpr, but it has been deleted at 1.2l +% \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). % | % \begin{macrocode} \def\xintPrd {\romannumeral0\xintprd }% -\def\xintprd #1{\expandafter\XINT_fprdexpr \romannumeral`&&@#1\xint:}% -\def\XINT_fprdexpr {\XINT_fprod_loop_a {1/1[0]}}% -\def\XINT_fprod_loop_a #1#2% -{% - \expandafter\XINT_fprod_loop_b \romannumeral`&&@#2\xint:{#1}% -}% -\def\XINT_fprod_loop_b #1% +\def\xintprd #1{\expandafter\XINT_prd\romannumeral`&&@#1^}% +\def\XINT_Prd{\romannumeral0\XINT_prd}% +\def\XINT_prd#1% {% - \xint_gob_til_xint: #1\XINT_fprod_finished\xint:\XINT_fprod_loop_c #1% + \xint_gob_til_^ #1\XINT_prd_empty ^% + \expandafter\XINT_prd_loop\romannumeral0\xintraw{#1}\xint: }% -\def\XINT_fprod_loop_c #1\xint:#2% +\def\XINT_prd_empty ^#1\xint:{ 1/1[0]}% +\def\XINT_prd_loop #1\xint:#2% {% - \expandafter\XINT_fprod_loop_a\expandafter{\romannumeral0\xintmul {#1}{#2}}% + \xint_gob_til_^ #2\XINT_prd_end ^% + \expandafter\XINT_prd_loop + \romannumeral0\xintmul{#1}{\romannumeral0\xintraw{#2}}\xint: }% -\def\XINT_fprod_finished#1\xint:\xint:#2{ #2}% +\def\XINT_prd_end ^#1\xintmul #2#3\xint:{ #2}% % \end{macrocode} % \subsection{\csh{xintDiv}} % \begin{macrocode} @@ -30157,18 +30058,29 @@ math shift catcode. % \lverb|1.2l protects \xintMaxof against items with non terminated % \the\numexpr expressions. % -% The macro is not compatible with an empty list.| +% 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). +% +% | % \begin{macrocode} -\def\xintMaxof {\romannumeral0\xintmaxof }% -\def\xintmaxof #1{\expandafter\XINT_maxof_a\romannumeral`&&@#1\xint:}% -\def\XINT_maxof_a #1{\expandafter\XINT_maxof_b\romannumeral0\xintraw{#1}!}% -\def\XINT_maxof_b #1!#2% - {\expandafter\XINT_maxof_c\romannumeral`&&@#2!{#1}!}% -\def\XINT_maxof_c #1% - {\xint_gob_til_xint: #1\XINT_maxof_e\xint:\XINT_maxof_d #1}% -\def\XINT_maxof_d #1!% - {\expandafter\XINT_maxof_b\romannumeral0\xintmax {#1}}% -\def\XINT_maxof_e #1!#2!{ #2}% +\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} @@ -30211,18 +30123,23 @@ math shift catcode. % \lverb|1.2l protects \xintMinof against items with non terminated % \the\numexpr expressions. % -% The macro is not compatible with an empty list.| +% 1.4 version is compatible with an empty input (empty items are handled as zero).| % \begin{macrocode} -\def\xintMinof {\romannumeral0\xintminof }% -\def\xintminof #1{\expandafter\XINT_minof_a\romannumeral`&&@#1\xint:}% -\def\XINT_minof_a #1{\expandafter\XINT_minof_b\romannumeral0\xintraw{#1}!}% -\def\XINT_minof_b #1!#2% - {\expandafter\XINT_minof_c\romannumeral`&&@#2!{#1}!}% -\def\XINT_minof_c #1% - {\xint_gob_til_xint: #1\XINT_minof_e\xint:\XINT_minof_d #1}% -\def\XINT_minof_d #1!% - {\expandafter\XINT_minof_b\romannumeral0\xintmin {#1}}% -\def\XINT_minof_e #1!#2!{ #2}% +\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} @@ -30348,6 +30265,132 @@ math shift catcode. \def\xintSgn {\romannumeral0\xintsgn }% \def\xintsgn #1{\expandafter\XINT_sgn\romannumeral0\xintraw {#1}\xint:}% % \end{macrocode} +% \subsection{\csh{xintGCD}, \csh{xintLCM}} +% \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. +% \begin{macrocode} +\def\xintGCD {\romannumeral0\xintgcd}% +\def\xintgcd #1#2{\XINT_fgcdof{#1}{#2}^}% +\def\xintLCM {\romannumeral0\xintlcm}% +\def\xintlcm #1#2{\XINT_flcmof{#1}{#2}^}% +% \end{macrocode} +% \subsection{\csh{xintGCDof}} +% \changed{1.4}{} +% This inherits from former non public \xintexprnameimp macro called |\xintGCDof:csv|, +% handling comma separated items, and former \xintgcdnameimp macro called +% |\xintGCDof| which handled braced items to which it applied |\xintNum| +% before handling the computations on integers only. The macro keeps the +% former name \xintgcdnameimp, and handles fractions presented as braced +% items. It is now the support macro for the |gcd()| function in |\xintexpr| +% and |\xintfloatexpr|. +% +% The support macro for the |gcd()| function in |\xintiiexpr| is +% \csbxint{iiGCDof} which is located in \xintnameimp. +% +% +% \begin{macrocode} +\def\xintGCDof {\romannumeral0\xintgcdof}% +\def\xintgcdof #1{\expandafter\XINT_fgcdof\romannumeral`&&@#1^}% +\def\XINT_GCDof{\romannumeral0\XINT_fgcdof}% +% \end{macrocode} +% \lverb|This abuses the way \xintiiabs works in order to avoid fetching whole +% argument again: \xintiiabs ^ raises no error. +% | +% \begin{macrocode} +\def\XINT_fgcdof #1% +{% + \xint_gob_til_^ #1\XINT_fgcdof_empty ^% + \expandafter\XINT_fgcdof_loop\romannumeral0\xintiiabs#1\xint: +}% +\def\XINT_fgcdof_empty ^#1\xint:{ 1/1[0]}% +\def\XINT_fgcdof_loop #1\xint:#2% +{% + \expandafter\XINT_fgcdof_loop_a\romannumeral0\xintiiabs#2\xint:#1\xint: +}% +% \end{macrocode} +% \begin{macrocode} +\def\XINT_fgcdof_loop_a#1#2\xint:#3\xint: +{% + \xint_gob_til_^ #1\XINT_fgcdof_end ^% + \xint_gob_til_zero #1\XINT_fgcdof_skip 0% + \expandafter\XINT_fgcdof_loop_b\romannumeral0\xintmod{#1#2}{#3}\xint:#3\xint: +}% +\def\XINT_fgcdof_end ^#1\xint:#2\xint:{ #2}% +\def\XINT_fgcdof_skip 0% + \expandafter\XINT_fgcdof_loop_b\romannumeral0\xintmod#1\xint: +{% + \XINT_fgcdof_loop +}% +\def\XINT_fgcdof_loop_b#1#2\xint:#3\xint: +{% + \xint_gob_til_zero #1\XINT_fgcdof_next 0% + \expandafter\XINT_fgcdof_loop_b\romannumeral0\xintmod{#3}{#1#2}\xint:#1#2\xint: +}% +\def\XINT_fgcdof_next 0% + \expandafter\XINT_fgcdof_loop_b\romannumeral0\xintmod#1#2\xint:#3\xint:#4% +{% + \expandafter\XINT_fgcdof_loop_a\romannumeral0\xintiiabs#4\xint:#1\xint: +}% +% \end{macrocode} +% \subsection{\csh{xintLCMof}} +% See comments for |\xintGCDof|. \xintnameimp provides integer only \csbxint{iiLCMof}. +% +% \begin{macrocode} +\def\xintLCMof {\romannumeral0\xintlcmof}% +\def\xintlcmof #1{\expandafter\XINT_flcmof\romannumeral`&&@#1^}% +\def\XINT_LCMof{\romannumeral0\XINT_flcmof}% +\def\XINT_flcmof #1% +{% + \xint_gob_til_^ #1\XINT_flcmof_empty ^% + \expandafter\XINT_flcmof_loop\romannumeral0\xintiiabs\xintRaw{#1}\xint: +}% +\def\XINT_flcmof_empty ^#1\xint:{ 0/1[0]}% +% \end{macrocode} +% \lverb|\XINT_inv expects A/B[N] format which is the case here.| +% \begin{macrocode} +\def\XINT_flcmof_loop #1% +{% + \xint_gob_til_zero #1\XINT_flcmof_zero 0% + \expandafter\XINT_flcmof_d\romannumeral0\XINT_inv #1% +}% +\def\XINT_flcmof_zero #1^{ 0/1[0]}% +% \end{macrocode} +% \lverb|\xintRaw{^} would raise an error thus we delay application of +% \xintRaw to new item. As soon as we hit against a zero item, the l.c.m is +% known to be zero itself. Else we need to inverse new item, but this requires +% full A/B[N] raw format, hence the \xintraw.| +% \begin{macrocode} +\def\XINT_flcmof_d #1\xint:#2% +{% + \expandafter\XINT_flcmof_loop_a\romannumeral0\xintiiabs#2\xint:#1\xint: +}% +\def\XINT_flcmof_loop_a #1#2\xint:% +{% + \xint_gob_til_^ #1\XINT_flcmof_end ^% + \xint_gob_til_zero #1\XINT_flcmof_zero 0% + \expandafter\XINT_flcmof_loop_b\romannumeral0\expandafter\XINT_inv + \romannumeral0\xintraw{#1#2}\xint: +}% +\def\XINT_flcmof_end ^#1\xint:#2\xint:{\XINT_inv #2}% +% \end{macrocode} +% \lverb|This is Euclide algorithm.| +% \begin{macrocode} +\def\XINT_flcmof_loop_b #1#2\xint:#3\xint: +{% + \xint_gob_til_zero #1\XINT_flcmof_next 0% + \expandafter\XINT_flcmof_loop_b\romannumeral0\xintmod{#3}{#1#2}\xint:#1#2\xint: +}% +\def\XINT_flcmof_next 0% + \expandafter\XINT_flcmof_loop_b\romannumeral0\xintmod#1#2\xint:#3\xint:#4% +{% + \expandafter\XINT_flcmof_loop_a\romannumeral0\xintiiabs#4\xint:#1\xint: +}% +% \end{macrocode} % \subsection{Floating point macros} % % For a long time the float routines dating back to releases |1.07/1.08a| @@ -32524,7 +32567,15 @@ math shift catcode. % 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.| +% 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. +% | % \begin{macrocode} \def\XINTinFloatDivMod {\romannumeral0\XINTinfloatdivmod [\XINTdigits]}% \def\XINTinfloatdivmod [#1]#2#3% @@ -32535,7 +32586,7 @@ math shift catcode. {\romannumeral0\XINTinfloat[#1]{#3}}% {#1}% }% -\def\XINT_infloatdivmod #1#2#3{ #1,\XINTinFloat[#3]{#2}}% +\def\XINT_infloatdivmod #1#2#3{\expanded{{#1}{\XINTinFloat[#3]{#2}}}}% % \end{macrocode} % \subsection{\csh{xintifFloatInt}} % \lverb|1.3a for ifint() function in \xintfloatexpr.| @@ -32557,6 +32608,24 @@ math shift catcode. \def\xintfloatisint #1{\expandafter\XINT_iffloatint \romannumeral0\xintrez{\XINTinFloat[\XINTdigits]{#1}}10}% % \end{macrocode} +% \subsection{\csh{XINTinFloatdigits}, \csh{XINTinFloatSqrtdigits}, +% \csh{XINTinFloatFacdigits}, \csh{XINTiLogTendigits}} +% \lverb|For \xintNewExpr matters, mainly. +% +% At 1.3e I add \XINTinFloatSdigits and use it at various places. I also modified +% \XINTinFloatFac to use S(hort) output format. +% +% Also added \XINTiLogTendigits. +% +% This whole stuff moved over from xintexpr.sty at 1.4 +% | +% \begin{macrocode} +\def\XINTinFloatdigits {\XINTinFloat [\XINTdigits]}% +\def\XINTinFloatSdigits {\XINTinFloatS [\XINTdigits]}% +\def\XINTinFloatSqrtdigits {\XINTinFloatSqrt[\XINTdigits]}% +\def\XINTinFloatFacdigits {\XINTinFloatFac [\XINTdigits]}% +\def\XINTFloatiLogTendigits{\XINTFloatiLogTen[\XINTdigits]}% +% \end{macrocode} % \subsection{(WIP) \csh{XINTinRandomFloatS}, \csh{XINTinRandomFloatSdigits}} % \lverb|1.3b. Support for random() function. % @@ -32642,7 +32711,14 @@ math shift catcode. % \lverb|1.3f. Transferred from poormanlog v0.4. Produces the 10^#1 with 9 % digits of float precision, with an error (believed to be) at most 2 units in % the last place. Of course for this the input must be precise enough to have -% 9 fractional digits of **fixed point** precision.| +% 9 fractional digits of **fixed point** precision. +% +% Attention that this breaks with low level Number too big error if +% integral part of argument exceeds TeX bound on integers. Indeed some +% \numexpr is used in the code to subtract 8... but anyway xintfrac +% allows for scientific exponents only integers within TeX bounds, so +% even if it did not break here it would quickly elsewhere. +% | % \begin{macrocode} \def\PoorManPowerOfTen{\the\numexpr\poormanpoweroften}% \def\poormanpoweroften #1% @@ -32691,6 +32767,10 @@ math shift catcode. \def\XINTinFloatLog#1{\XINTinFloatMul{\PoorManLogBaseTen{#1}}{23025850923[-10]}}% \def\xintExp#1{\PoorManPowerOfTen{\xintMul{#1}{434294481903[-12]}}}% \def\XINTinFloatExp#1{\PoorManPowerOfTen{\XINTinFloatMul{#1}{434294481903[-12]}}}% +\let\XINTinFloatMaxof\XINT_Maxof +\let\XINTinFloatMinof\XINT_Minof +\let\XINTinFloatSum\XINT_Sum +\let\XINTinFloatPrd\XINT_Prd \XINT_restorecatcodes_endinput% % \end{macrocode} % \StoreCodelineNo {xintfrac} @@ -32766,7 +32846,7 @@ math shift catcode. % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintseries}% - [2019/09/10 v1.3f Expandable partial sums with xint package (JFB)]% + [2020/01/31 v1.4 Expandable partial sums with xint package (JFB)]% % \end{macrocode} % \subsection{\csh{xintSeries}} % \begin{macrocode} @@ -33267,7 +33347,7 @@ math shift catcode. % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintcfrac}% - [2019/09/10 v1.3f Expandable continued fractions with xint package (JFB)]% + [2020/01/31 v1.4 Expandable continued fractions with xint package (JFB)]% % \end{macrocode} % \subsection{\csh{xintCFrac}} % \begin{macrocode} @@ -34386,14 +34466,150 @@ math shift catcode. % \RaisedLabel{sec:exprimp} % \etocarticlestylenomarks % \etocstandardlines -% \etocsetnexttocdepth {subsection} +% \etocsetnexttocdepth {subsubsection} +% +% +% This is release \expandafter|\xintbndlversion| of +% \expandafter|\xintbndldate|. % % \localtableofcontents % % \etocsettocstyle{}{} % -% This is release \expandafter|\xintbndlversion| of -% \expandafter|\expandafter[\xintbndldate]|. +% \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 }% +% \def\myenditemize{\end{itemize}} +% \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 possible to let the [...] syntax be associated to a true internal type of «tuple» +% or «list». +% +% The output of \xintexpr after 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 {<number>} leaves. +% The <number> is some internal representation, possibly empty. +% Both on input and output from \xintthexpr an empty leaf is rendered as []. +% The $xintfracnameimp numerical macros convert this to 0, but the integer +% only parser \xintiiexpr will currently not do this and will break +% if some arithmetic operation is attempted. +% +% Only normal catcodes are output, i.e. the backslash, regular braces, and the +% catcode 12 characters which are used for the internal number representations +% <number> (scientific notation is internally converted to raw +% $xintfracnameimp representation [N]). +% +% See the user manual for changes the novel internal representation implies at +% interface level, in particular regarding the way the commas are interpreted. +% The user manual explains some terminology («ople», «oneple», «nutple»,...) whose +% meaning I don't repeat here. +% +% 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 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. See user manual for +% some further comments. +% +% \XINTexprprint is \protected. +% +% The f-expansion (\romannumeral-`0 type of expansion) of an \xintexpr +% <expression>\relax is a complete expansion, i.e. 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>. For example +% \xintthe\xintboolexpr will (this is tentative) use True and False in output. +% +% 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. +% +% | +% +% \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} +% +% +% \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 intially launched becasue 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.| % % \subsection{Old comments} % @@ -34477,8 +34693,9 @@ math shift catcode. \def\y#1#2{\PackageInfo{#1}{#2}}% \fi \expandafter - \ifx\csname numexpr\endcsname\relax - \y{xintexpr}{\numexpr not available, aborting input}% + % I don't think engine exists providing \expanded but not \numexpr + \ifx\csname expanded\endcsname\relax + \y{xintexpr}{\expanded not available, aborting input}% \aftergroup\endinput \else \ifx\x\relax % plain-TeX, first loading of xintexpr.sty @@ -34512,13 +34729,17 @@ math shift catcode. % \end{macrocode} % \subsection{Package identification} % \lverb|& +% \XINT_Cmp alias for \xintiiCmp needed for some forgotten reason related to +% \xintNewExpr (FIX THIS!) +% % | % \begin{macrocode} \XINT_providespackage \ProvidesPackage{xintexpr}% - [2019/09/10 v1.3f Expandable expression parser (JFB)]% + [2020/01/31 v1.4 Expandable expression parser (JFB)]% \catcode`! 11 \let\XINT_Cmp \xintiiCmp +\def\XINTfstop{\noexpand\XINTfstop}% % \end{macrocode} % \subsection{\csh{xintDigits*}, \csh{xintSetDigits*}} % \lverb|1.3f| @@ -34531,29 +34752,165 @@ math shift catcode. \else\afterassignment\xintreloadxinttrig\fi \xintfracSetDigits}% % \end{macrocode} -% \subsection{\csh{xintexpr}, \csh{xintiexpr}, \csh{xintfloatexpr}, +% \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} +% \lverb|1.4| +% \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 + \xint_orthat\XINT:expr:toblist_b #1#2% +>% +\def\XINT:expr:toblist_b #1!#2}% +<% + \if\relax#2\relax\xintexprEmptyItem\else#1<#2>\fi\XINT:expr:toblist_c #1!}% +>% +\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{Braced contents rendering via a \TeX{} alignment with prettifying of leaves} +% \lverb|1.4.| +% \begin{macrocode} +\catcode`& 4 +\protected\def\xintexpralignbegin {\halign\bgroup\tabskip2ex\hfil##&&##\hfil\cr}% +\protected\def\xintexpralignend {\crcr\egroup}% +\protected\def\xintexpraligncr {\cr}% +\protected\def\xintexpralignleftbracket {[}% +\protected\def\xintexpralignrightbracket{]}% +\protected\def\xintexpraligninnercomma {,}% +\protected\def\xintexpralignoutercomma {,}% +\protected\def\xintexpraligntab {&}% +\catcode`& 7 +\def\XINT:expr:toalignwith#1#2% +{% + {\expandafter\XINT:expr:toalign_checkempty + \expanded{\noexpand#1!\expandafter}\detokenize{#2}^}% + \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\XINT:expr:toalign_b #1#2% +>% +\def\XINT:expr:toalign_b #1!#2}% +<% + \xintexpraligntab + \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<\xintexpraligninnercomma\XINT:expr:toalign_a>\fi + \xint_orthat<\xintexpraligntab\xintexpralignrightbracket\XINT:expr:toalign_C>#1#2% +>% +\def\XINT:expr:toalign_C #1}#2% +<% + \if ^#2\xint_dothis<\xint_gob_til_^>\fi + \if {#2\xint_dothis<\xintexpralignoutercomma\xintexpraligncr\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} +% +% \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 into braces : +% +% \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». +% | +% +% \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 % should I check lccode s generally if corrupted context at load? +\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}} -% \lverb|ATTENTION! 1.3d renamed \xinteval to \xintexpro etc...| +% \lverb|& +% +% \xintiexpr and \xintfloatexpr have an optional argument since 1.1. +% +% ATTENTION! 1.3d renamed \xinteval to \xintexpro etc... +% +% +% | % \begin{macrocode} \def\xintexpr {\romannumeral0\xintexpro }% \def\xintiexpr {\romannumeral0\xintiexpro }% \def\xintfloatexpr {\romannumeral0\xintfloatexpro }% \def\xintiiexpr {\romannumeral0\xintiiexpro }% -% \end{macrocode} -% \subsection{\csh{xintexpro}, \csh{xintiiexpro}} -% \lverb|ATTENTION! 1.3d renamed \xinteval to \xintexpro etc...| -% \begin{macrocode} \def\xintexpro {\expandafter\XINT_expr_wrap\romannumeral0\xintbareeval }% \def\xintiiexpro {\expandafter\XINT_iiexpr_wrap\romannumeral0\xintbareiieval }% -% \end{macrocode} -% \subsection{\csh{xintiexpro}, \csh{xintfloatexpro}} -% \lverb|Optional argument since 1.1. -% -% ATTENTION! 1.3d renamed \xinteval to \xintexpro etc... -% -% Some renaming of macros at 1.3e here. Again at 1.3f with some real changes -% (to fix the \xintfloatexpr [D] issue inside \xintdeffunc).| -% \begin{macrocode} \def\xintiexpro #1% {% \ifx [#1\expandafter\XINT_iexpr_withopt\else\expandafter\XINT_iexpr_noopt @@ -34561,20 +34918,33 @@ math shift catcode. }% \def\XINT_iexpr_noopt {% - \expandafter\XINT_iexpr_round\expandafter 0% - \romannumeral0\xintbareeval + \expandafter\XINT_iexpr_iiround\romannumeral0\xintbareeval }% +\def\XINT_iexpr_iiround +{% + \expandafter\XINT_expr_wrap + \expanded + \XINT:NEhook:x:mapwithin\XINT:expr:mapwithin{\XINTbracediRoundzero}% +}% +\def\XINTbracediRoundzero#1{{\xintiRound{0}{#1}}}% \def\XINT_iexpr_withopt [#1]% {% - \expandafter\XINT_iexpr_round\expandafter - {\the\numexpr \xint_zapspaces #1 \xint_gobble_i\expandafter}% + \expandafter\XINT_iexpr_round + \the\numexpr \xint_zapspaces #1 \xint_gobble_i\expandafter.% \romannumeral0\xintbareeval }% -\def\XINT_iexpr_round #1#2% +\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_expr_wrap - \csname .=\xintRound::csv {#1}{\XINT_expr_unlock #2}\endcsname + \expanded + \XINT:NEhook:x:mapwithin\XINT:expr:mapwithin{\XINTbracedRound{#1}}% }% +\def\XINTbracedRound#1#2{{\xintRound{#1}{#2}}}% \def\xintfloatexpro #1% {% \ifx [#1\expandafter\XINT_flexpr_withopt\else\expandafter\XINT_flexpr_noopt @@ -34582,12 +34952,8 @@ math shift catcode. }% \def\XINT_flexpr_noopt {% - \expandafter\XINT_flexpr_noopt_a\romannumeral0\xintbarefloateval -}% -\def\XINT_flexpr_noopt_a #1% -{% - \expandafter\XINT_flexpr_wrap - \csname .;\xinttheDigits.=\XINT_expr_unlock #1\endcsname + \expandafter\XINT_flexpr_wrap\the\numexpr\XINTdigits\expandafter.% + \romannumeral0\xintbarefloateval }% \def\XINT_flexpr_withopt [#1]% {% @@ -34595,183 +34961,176 @@ math shift catcode. \the\numexpr\xint_zapspaces #1 \xint_gobble_i\expandafter.% \romannumeral0\xintbarefloateval }% -\def\XINT_flexpr_withopt_a #1.#2% +\def\XINT_flexpr_withopt_a #1#2.% {% - \expandafter\XINT_flexpr_wrap - \csname .;#1.=\XINTinFloat::csv {#1}{\XINT_expr_unlock #2}\endcsname + \expandafter\XINT_flexpr_withopt_b\the\numexpr\if#1-\XINTdigits\fi#1#2.% }% -% \end{macrocode} -% \lverb|& -% 1.3f fixes some problems with using \xintfloatexpr [D]..\relax as a sub -% expression inside \xintdeffunc. Comma separated expressions are not allowed -% inside such sub-expression. -% | -% \begin{macrocode} -\def\XINT:NE_flexpr_withopt_a #1.#2% +\def\XINT_flexpr_withopt_b #1.% {% \expandafter\XINT_flexpr_wrap - \csname .;#1.=\XINT:NE:one{\XINTinFloat::csv{#1}}{\XINT_expr_unlock #2}\endcsname + \the\numexpr#1\expandafter.% + \expanded + \XINT:NEhook:x:mapwithin\XINT:expr:mapwithin{\XINTbracedinFloat[#1]}% }% +\def\XINTbracedinFloat[#1]#2{{\XINTinFloat[#1]{#2}}}% % \end{macrocode} -% \subsection{\csh{XINT_expr_wrap}, \csh{XINT_iiexpr_wrap}, \csh{XINT_flexpr_wrap}} +% \subsubsection{\csh{XINT_expr_wrap}, \csh{XINT_iiexpr_wrap}, \csh{XINT_flexpr_wrap}} % \lverb|1.3e removes some leading space tokens which served nothing. There is % no \XINT_iexpr_wrap, because \XINT_expr_wrap is used directly.| % \begin{macrocode} -\def\XINT_expr_wrap {!\XINT_expr_usethe\XINT_protectii\XINT_expr_print}% -\def\XINT_iiexpr_wrap {!\XINT_expr_usethe\XINT_protectii\XINT_iiexpr_print}% -\def\XINT_flexpr_wrap {!\XINT_expr_usethe\XINT_protectii\XINT_flexpr_print}% -% \end{macrocode} -% \subsection{\csh{XINT_expr_usethe}, \csh{XINT_protectii}} -% \begin{macrocode} -\def\XINT_protectii #1{\noexpand\XINT_protectii\noexpand #1\noexpand }% -\protected\def\XINT_expr_usethe\XINT_protectii {\xintError:missing_xintthe!}% -% \end{macrocode} -% \subsection{\csh{XINT_expr_print}, \csh{XINT_iiexpr_print}, \csh{XINT_flexpr_print}} -% \begin{macrocode} -\def\XINT_expr_print #1{\xintSPRaw::csv {\XINT_expr_unlock #1}}% -\def\XINT:NE_expr_print#1{\expandafter - \xintSPRaw::csv\expandafter{\romannumeral`&&@\XINT_expr_unlock #1}}% -\def\XINT_iiexpr_print #1{\xintCSV::csv {\XINT_expr_unlock #1}}% -\def\XINT:NE_iiexpr_print #1{\expandafter - \xintCSV::csv\expandafter{\romannumeral`&&@\XINT_expr_unlock #1}}% -\def\XINT_flexpr_print #1% -{% - \expandafter\xintPFloat::csv - \romannumeral`&&@\expandafter\XINT_expr_unlock_sp\string #1!% -}% -\def\XINT_expr_unlock_sp #1.;#2.=#3!{{#2}{#3}}% +\def\XINT_expr_wrap {\XINTfstop\XINTexprprint.}% +\def\XINT_iiexpr_wrap {\XINTfstop\XINTiiexprprint.}% +\def\XINT_flexpr_wrap {\XINTfstop\XINTflexprprint}% % \end{macrocode} -% \subsection{\csh{xinttheexpr}, \csh{xinttheiexpr}, \csh{xintthefloatexpr}, +% \subsubsection{\csh{XINTexprprint}, \csh{XINTiiexprprint}, \csh{XINTflexprprint}} +% \lverb| +% +% Comments currently under reconstruction. +% +% 1.4: The reason for \expanded is to ensure \xintthe mechanism does expand +% completely in two steps, now that the print helper macros are not f-expandable +% anymore. +% +% It is possible that the expression gave an empty object (e.g. \xintexpr +% [4][1]\relax). Thus we do not use \romannumeral`^^@ trigger else +% twice expansion of \xinttheexpr will propagate beyond empty expression. +% Thus \romannumeral ended via a chardef zero token. +% +% | +% \begin{macrocode} +\protected\def\XINTexprprint.% + {\XINT:NEhook:x:toblist\XINT:expr:toblistwith\xintexprPrintOne}% +\let\xintexprPrintOne\xintFracToSci +\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}}}% +\def\xintfloatexprPrintOne#1% + {\romannumeral0\XINT_pfloat_opt [\xint:#1]}% bad direct jump +\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}} % \lverb|The reason why \xinttheiexpr et \xintthefloatexpr are handled % differently is that they admit an optional argument which acts via a custom -% «printing» stage.| -% \begin{macrocode} +% «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...| +% \begin{macrocode} +\def\xintthe #1{\expanded\expandafter\xint_gobble_i\romannumeral`&&@#1}% +\def\xintthealign #1{\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 - {\romannumeral`&&@\expandafter\XINT_expr_print\romannumeral0\xintbareeval}% + {\expanded\expandafter\XINTexprprint\expandafter.\romannumeral0\xintbareeval}% \def\xinttheiexpr - {\romannumeral`&&@\expandafter\xint_gobble_iii\romannumeral`&&@\xintiexpr}% + {\expanded\expandafter\xint_gobble_i\romannumeral`&&@\xintiexpr}% \def\xintthefloatexpr - {\romannumeral`&&@\expandafter\xint_gobble_iii\romannumeral`&&@\xintfloatexpr}% + {\expanded\expandafter\xint_gobble_i\romannumeral`&&@\xintfloatexpr}% \def\xinttheiiexpr - {\romannumeral`&&@\expandafter\XINT_iiexpr_print\romannumeral0\xintbareiieval}% + {\expanded\expandafter\XINTiiexprprint\expandafter.\romannumeral0\xintbareiieval}% % \end{macrocode} -% \subsection{\csh{thexintexpr}, \csh{thexintiexpr}, \csh{thexintfloatexpr}, +% \subsubsection{\csh{thexintexpr}, \csh{thexintiexpr}, \csh{thexintfloatexpr}, % \csh{thexintiiexpr}} % \lverb|New with 1.2h. I have been for the last three years very strict -% regarding macros with \xint or \XINT, but well.| +% regarding macros with \xint or \XINT, but well. +% +% 1.4. Definitely I don't like those. Don't use them, I will remove one day!| % \begin{macrocode} \let\thexintexpr \xinttheexpr \let\thexintiexpr \xinttheiexpr \let\thexintfloatexpr\xintthefloatexpr \let\thexintiiexpr \xinttheiiexpr % \end{macrocode} -% \subsection{\csh{xinteval}, \csh{xintieval}, \csh{xintfloateval}, -% \csh{xintiieval}} -% \begin{macrocode} -\def\xinteval #1% - {\romannumeral`&&@\expandafter\XINT_expr_print\romannumeral0\xintbareeval#1\relax}% -\def\xintieval #1% - {\romannumeral`&&@\expandafter\xint_gobble_iii\romannumeral`&&@\xintiexpr#1\relax}% -\def\xintfloateval #1% - {\romannumeral`&&@\expandafter\xint_gobble_iii\romannumeral`&&@\xintfloatexpr#1\relax}% -\def\xintiieval #1% - {\romannumeral`&&@\expandafter\XINT_iiexpr_print\romannumeral0\xintbareiieval#1\relax}% -% \end{macrocode} -% \lverb|The «print» macros are made into inert entities when an expression is -% parsed by \xintNewExpr or \xintdeffunc. In order to allow usage of \xinteval -% et al., we need to replace them by the corresponding \xintexpr et al and -% drop the macro wrappers (because they do not expand and will trap the -% expression parser). The behaviour of \xinteval{3}7 will not be as in a -% normal expression but such syntax is anyhow obscure.| -% \begin{macrocode} -\def\XINT:NE:eval #1{\xintexpr #1\relax}% -\def\XINT:NE:ieval #1{\xintiexpr #1\relax}% -\def\XINT:NE:floateval#1{\xintfloatexpr #1\relax}% -\def\XINT:NE:iieval #1{\xintiiexpr #1\relax}% -% \end{macrocode} -% \subsection{\csh{xintthe}} +% \subsubsection{\csh{xintbareeval}, \csh{xintbarefloateval}, \csh{xintbareiieval}} +% \lverb|At 1.4 added one expansion step via _start macros. Triggering is expected to be +% via either \romannumeral`^^@ or \romannumeral0 is also ok| % \begin{macrocode} -\def\xintthe #1{\romannumeral`&&@\expandafter\xint_gobble_iii\romannumeral`&&@#1}% +\def\xintbareeval {\XINT_expr_start }% +\def\xintbarefloateval{\XINT_flexpr_start}% +\def\xintbareiieval {\XINT_iiexpr_start}% % \end{macrocode} -% \subsection{\csh{xintbareeval}, \csh{xintbarefloateval}, \csh{xintbareiieval}} +% \subsubsection{\csh{xintthebareeval}, \csh{xintthebarefloateval}, +% \csh{xintthebareiieval}} +% \lverb|For matters of \XINT_NewFunc| % \begin{macrocode} -\def\xintbareeval - {\expandafter\XINT_expr_until_end_a\romannumeral`&&@\XINT_expr_getnext }% -\def\xintbarefloateval - {\expandafter\XINT_flexpr_until_end_a\romannumeral`&&@\XINT_expr_getnext }% -\def\xintbareiieval - {\expandafter\XINT_iiexpr_until_end_a\romannumeral`&&@\XINT_expr_getnext }% +\def\xintthebareeval {\romannumeral0\expandafter\xint_stop_atfirstofone\romannumeral0\xintbareeval}% +\def\xintthebarefloateval {\romannumeral0\expandafter\xint_stop_atfirstofone\romannumeral0\xintbarefloateval}% +\def\xintthebareiieval {\romannumeral0\expandafter\xint_stop_atfirstofone\romannumeral0\xintbareiieval}% % \end{macrocode} -% \subsection{\csh{xintthebareeval}, \csh{xintthebarefloateval}, \csh{xintthebareiieval}} +% \subsubsection{\csh{xinteval}, \csh{xintieval}, \csh{xintfloateval}, \csh{xintiieval}} % \begin{macrocode} -\def\xintthebareeval {\expandafter\XINT_expr_unlock\romannumeral0\xintbareeval}% -\def\xintthebarefloateval {\expandafter\XINT_expr_unlock\romannumeral0\xintbarefloateval}% -\def\xintthebareiieval {\expandafter\XINT_expr_unlock\romannumeral0\xintbareiieval}% +\def\xinteval #1% + {\expanded\expandafter\XINTexprprint\expandafter.\romannumeral0\xintbareeval#1\relax}% +\def\xintieval #1% + {\expanded\expandafter\xint_gobble_i\romannumeral`&&@\xintiexpr#1\relax}% +\def\xintfloateval #1% + {\expanded\expandafter\xint_gobble_i\romannumeral`&&@\xintfloatexpr#1\relax}% +\def\xintiieval #1% + {\expanded\expandafter\XINTiiexprprint\expandafter.\romannumeral0\xintbareiieval#1\relax}% % \end{macrocode} -% \subsection{\csh{xintboolexpr}, \csh{XINT_boolexpr_print}, \csh{xinttheboolexpr}, +% \subsubsection{\csh{xintboolexpr}, \csh{XINT_boolexpr_print}, \csh{xinttheboolexpr}, % \csh{thexintboolexpr}} -% \lverb|ATTENTION! 1.3d renamed \xinteval to \xintexpro etc...| +% \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.| % \begin{macrocode} \def\xintboolexpr {% - \romannumeral0\expandafter\expandafter\expandafter - \XINT_boolexpr_done\expandafter\xint_gobble_iv\romannumeral0\xintexpro + \romannumeral0\expandafter\XINT_boolexpr_done\romannumeral0\xintexpro }% -\def\XINT_boolexpr_done {!\XINT_expr_usethe\XINT_protectii\XINT_boolexpr_print}% -\def\XINT_boolexpr_print #1{\xintIsTrue::csv {\XINT_expr_unlock #1}}% -\def\XINT:NE_boolexpr_print #1{\expandafter - \xintIsTrue::csv\expandafter{\romannumeral`&&@\XINT_expr_unlock #1}}% +\def\XINT_boolexpr_done #1.{\XINTfstop\XINTboolexprprint.}% \def\xinttheboolexpr {% - \romannumeral`&&@\expandafter\expandafter\expandafter - \XINT_boolexpr_print\expandafter\xint_gobble_iv\romannumeral0\xintexpro + \expanded\expandafter\XINTboolexprprint\expandafter.\romannumeral0\xintbareeval }% \let\thexintboolexpr\xinttheboolexpr % \end{macrocode} -% \subsection{\csh{xintifboolexpr}, \csh{xintifboolfloatexpr}, \csh{xintifbooliiexpr}} -% \lverb|Do not work with comma separated expressions.| +% \subsubsection{\csh{xintifboolexpr}, \csh{xintifboolfloatexpr}, \csh{xintifbooliiexpr}} +% \lverb|They do not accept comma separated expressions input.| % \begin{macrocode} \def\xintifboolexpr #1{\romannumeral0\xintiiifnotzero {\xinttheexpr #1\relax}}% \def\xintifboolfloatexpr #1{\romannumeral0\xintiiifnotzero {\xintthefloatexpr #1\relax}}% \def\xintifbooliiexpr #1{\romannumeral0\xintiiifnotzero {\xinttheiiexpr #1\relax}}% % \end{macrocode} -% \subsection{\csh{xintifsgnexpr}, \csh{xintifsgnfloatexpr}, \csh{xintifsgniiexpr}} +% \subsubsection{\csh{xintifsgnexpr}, \csh{xintifsgnfloatexpr}, \csh{xintifsgniiexpr}} % \changed{1.3d}{} -% \lverb|Do not work with comma separated expressions.| +% \lverb|They do not accept comma separated expressions.| % \begin{macrocode} \def\xintifsgnexpr #1{\romannumeral0\xintiiifsgn {\xinttheexpr #1\relax}}% \def\xintifsgnfloatexpr #1{\romannumeral0\xintiiifsgn {\xintthefloatexpr #1\relax}}% \def\xintifsgniiexpr #1{\romannumeral0\xintiiifsgn {\xinttheiiexpr #1\relax}}% % \end{macrocode} -% \subsection{\csh{xintthecoords}} -% \lverb|1.1 Wraps up an even number of comma separated items into pairs of -% TikZ coordinates; for use in the following way: -% -% coordinates {\xintthecoords\xintfloatexpr ... \relax} -% -% The crazyness with the \csname and unlock is due to TikZ somewhat STRANGE -% control of the TOTAL number of expansions which should not exceed the very low -% value of 100 !! As we implemented \XINT_thecoords_b in an "inline" style for -% efficiency, we need to hide its expansions. -% -% Not to be used as \xintthecoords\xintthefloatexpr, only as -% \xintthecoords\xintfloatexpr (or \xintiexpr etc...). Perhaps \xintthecoords -% could make an extra check, but one should not accustom users to too loose -% requirements!| -% \begin{macrocode} -\def\xintthecoords #1{\romannumeral`&&@\expandafter\expandafter\expandafter - \XINT_thecoords_a - \expandafter\xint_gobble_iii\romannumeral0#1}% -\def\XINT_thecoords_a #1#2% #1=print macro, indispensible for scientific notation - {\expandafter\XINT_expr_unlock\csname.=\expandafter\XINT_thecoords_b - \romannumeral`&&@#1#2,!,!,^\endcsname }% -\def\XINT_thecoords_b #1#2,#3#4,% - {\xint_gob_til_! #3\XINT_thecoords_c ! (#1#2, #3#4)\XINT_thecoords_b }% -\def\XINT_thecoords_c #1^{}% -% \end{macrocode} -% \subsection{Locking and unlocking} -% \lverb|Some renaming and modifications here with release 1.2 to switch from +% \subsubsection{Small bits we have to put somewhere} +% \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 @@ -34793,197 +35152,174 @@ math shift catcode. % \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...).| +% (which would be hard for the fraction part...). +% | % \begin{macrocode} +\def\XINT_embrace#1{{#1}}% \def\xint_gob_til_! #1!{}% ! with catcode 11 -\def\XINT_expr_lockscan#1{% not used for decimal numbers in xintexpr 1.2 -\def\XINT_expr_lockscan##1!{\expandafter#1\csname .=##1\endcsname}% -}\XINT_expr_lockscan{ }% -\def\XINT_expr_lockit#1{% -\def\XINT_expr_lockit##1{\expandafter#1\csname .=##1\endcsname}% -}\XINT_expr_lockit{ }% -\def\XINT_expr_unlock_hex_in #1% expanded inside \csname..\endcsname - {\expandafter\XINT_expr_inhex\romannumeral`&&@\XINT_expr_unlock#1;}% -\def\XINT_expr_inhex #1.#2#3;% expanded inside \csname..\endcsname -{% - \if#2>% - \xintHexToDec{#1}% - \else - \xintiiMul{\xintiiPow{625}{\xintLength{#3}}}{\xintHexToDec{#1#3}}% - [\the\numexpr-4*\xintLength{#3}]% - \fi +\def\xintError:noopening +{% + \XINT_expandableerror{Extra ) found during balancing, e(X)it before the worst.}% }% -\def\XINT_expr_unlock {\expandafter\XINT_expr_unlock_a\string }% -\def\XINT_expr_unlock_a #1.={}% -\def\XINT_expr_unexpectedtoken {\xintError:ignored }% -\let\XINT_expr_done\space -% \end{macrocode} -% \subsection{Hooks for the functioning of \cshnolabel{xintNewExpr} and -% \cshnolabel{xintdeffunc}} -% \lverb|This is new with 1.3. See \XINT_expr_redefinemacros.| -% \begin{macrocode} -\let\XINT:NEhook:one\empty -\let\XINT:NEhook:two\empty -\let\XINT:NEhook:csv\empty -\def\XINT:NEhook:twosp #1,#2,!#3{#3{#1}{#2}}% -% \end{macrocode} -% \subsection{Macros handling csv lists on output (for \cshnolabel{XINT_expr_print} et -% al. routines)} -% \localtableofcontents -% \lverb|Changed completely for 1.1, which adds the optional arguments to -% \xintiexpr and \xintfloatexpr.| -% \subsubsection{\csh{XINT_::_end}} -% \lverb|Le mécanisme est le suivant, #2 est dans des accolades et commence par -% ,<sp>. Donc le gobble se débarrasse du, et le <sp> après brace stripping -% arrête un \romannumeral0 ou \romannumeral-`0| -% \begin{macrocode} -\def\XINT_::_end #1,#2{\xint_gobble_i #2}% -% \end{macrocode} -% \subsubsection{\csh{xintCSV::csv}} -% \begin{macrocode} -\def\xintCSV::csv #1{\expandafter\XINT_csv::_a\romannumeral`&&@#1,^,}% -\def\XINT_csv::_a {\XINT_csv::_b {}}% -\def\XINT_csv::_b #1#2,{\expandafter\XINT_csv::_c \romannumeral`&&@#2,{#1}}% -\def\XINT_csv::_c #1{\if ^#1\expandafter\XINT_::_end\fi\XINT_csv::_d #1}% -\def\XINT_csv::_d #1,#2{\XINT_csv::_b {#2, #1}}% possibly, item #1 is empty. % \end{macrocode} -% \subsubsection{\csh{xintSPRaw}, \csh{xintSPRaw::csv}} -% \begin{macrocode} -\def\xintSPRaw {\romannumeral0\xintspraw }% -\def\xintspraw #1{\expandafter\XINT_spraw\romannumeral`&&@#1[\W]}% -\def\XINT_spraw #1[#2#3]{\xint_gob_til_W #2\XINT_spraw_a\W\XINT_spraw_p #1[#2#3]}% -\def\XINT_spraw_a\W\XINT_spraw_p #1[\W]{ #1}% -\def\XINT_spraw_p #1[\W]{\xintpraw {#1}}% -\def\xintSPRaw::csv #1{\romannumeral0\expandafter\XINT_spraw::_a\romannumeral`&&@#1,^,}% -\def\XINT_spraw::_a {\XINT_spraw::_b {}}% -\def\XINT_spraw::_b #1#2,{\expandafter\XINT_spraw::_c \romannumeral`&&@#2,{#1}}% -\def\XINT_spraw::_c #1{\if ,#1\xint_dothis\XINT_spraw::_e\fi - \if ^#1\xint_dothis\XINT_::_end\fi - \xint_orthat\XINT_spraw::_d #1}% -\def\XINT_spraw::_d #1,{\expandafter\XINT_spraw::_e\romannumeral0\XINT_spraw #1[\W],}% -\def\XINT_spraw::_e #1,#2{\XINT_spraw::_b {#2, #1}}% -% \end{macrocode} -% \subsubsection{\csh{xintIsTrue::csv}} -% \begin{macrocode} -\def\xintIsTrue::csv #1{\romannumeral0\expandafter\XINT_istrue::_a\romannumeral`&&@#1,^,}% -\def\XINT_istrue::_a {\XINT_istrue::_b {}}% -\def\XINT_istrue::_b #1#2,{\expandafter\XINT_istrue::_c \romannumeral`&&@#2,{#1}}% -\def\XINT_istrue::_c #1{\if ,#1\xint_dothis\XINT_istrue::_e\fi - \if ^#1\xint_dothis\XINT_::_end\fi - \xint_orthat\XINT_istrue::_d #1}% -\def\XINT_istrue::_d #1,{\expandafter\XINT_istrue::_e\romannumeral0\xintisnotzero {#1},}% -\def\XINT_istrue::_e #1,#2{\XINT_istrue::_b {#2, #1}}% -% \end{macrocode} -% \subsubsection{\csh{xintRound::csv}} -% \lverb| -% 1.3e Emploi d'un point comme délimiteur. Dans le futur donner une signification -% à un #1 négatif dans \XINT_round::_a ? -% | -% \begin{macrocode} -\def\XINT_:::_end #1,#2#3{\xint_gobble_i #3}% -\def\xintRound::csv #1#2{\romannumeral0\expandafter\XINT_round::_a - \the\numexpr#1\expandafter.\romannumeral`&&@#2,^,}% -\def\XINT_round::_a #1.{\XINT_round::_b #1.{}}% -\def\XINT_round::_b #1.#2#3,{\expandafter\XINT_round::_c \romannumeral`&&@#3,{#1}{#2}}% -\def\XINT_round::_c #1{\if ,#1\xint_dothis\XINT_round::_e\fi - \if ^#1\xint_dothis\XINT_:::_end\fi - \xint_orthat\XINT_round::_d #1}% -\def\XINT_round::_d #1,#2{% - \expandafter\XINT_round::_e\romannumeral0\ifnum#2>\xint_c_ - \expandafter\xintround\else\expandafter\xintiround\fi {#2}{#1},{#2}}% -\def\XINT_round::_e #1,#2#3{\XINT_round::_b #2.{#3, #1}}% -% \end{macrocode} -% \subsubsection{\csh{XINTinFloat::csv}} -% \lverb|& -% 1.3e adds support for a negative specifier (\XINT_infloat::_a inserted, by -% luck formerly it started straight with \XINT_infloat::_b ...). +% \paragraph{\csh{xintthecoords}} +% \lverb|1.1 Wraps up an even number of comma separated items into pairs of +% TikZ coordinates; for use in the following way: % -% | +% coordinates {\xintthecoords\xintfloatexpr ... \relax} +% +% The crazyness with the \csname and unlock is due to TikZ somewhat STRANGE +% control of the TOTAL number of expansions which should not exceed the very low +% value of 100 !! As we implemented \XINT_thecoords_b in an "inline" style for +% efficiency, we need to hide its expansions. +% +% Not to be used as \xintthecoords\xintthefloatexpr, only as +% \xintthecoords\xintfloatexpr (or \xintiexpr etc...). Perhaps \xintthecoords +% could make an extra check, but one should not accustom users to too loose +% requirements!| % \begin{macrocode} -\def\XINTinFloat::csv #1#2{\romannumeral0\expandafter\XINT_infloat::_a - \the\numexpr #1\expandafter.\romannumeral`&&@#2,^,}% -\def\XINT_infloat::_a #1#2.% - {\expandafter\XINT_infloat::_b\the\numexpr\if#1-\XINTdigits\fi#1#2.{}}% -\def\XINT_infloat::_b #1.#2#3,{\XINT_infloat::_c #3,{#1}{#2}}% -\def\XINT_infloat::_c #1{\if ,#1\xint_dothis\XINT_infloat::_e\fi - \if ^#1\xint_dothis\XINT_:::_end\fi - \xint_orthat\XINT_infloat::_d #1}% -\def\XINT_infloat::_d #1,#2% - {\expandafter\XINT_infloat::_e\romannumeral0\XINTinfloat [#2]{#1},{#2}}% -\def\XINT_infloat::_e #1,#2#3{\XINT_infloat::_b #2.{#3, #1}}% +\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} -% \subsubsection{\csh{xintPFloat::csv}} -% \lverb|& -% Also extended at 1.3e to handle negative optional specifier for digits -% precision. This macro formats output. -% +% \subsection{Hooks into the numeric parser for usage by the +% \cshnolabel{xintdeffunc} symbolic parser} +% \lverb|This is new with 1.3 and considerably refactored at 1.4. See +% «Mysterious stuff». % | % \begin{macrocode} -\def\xintPFloat::csv #1#2{\romannumeral0\expandafter\XINT_pfloat::_a - \the\numexpr #1\expandafter.\romannumeral`&&@#2,^,}% -\def\XINT_pfloat::_a #1#2.% - {\expandafter\XINT_pfloat::_b\the\numexpr\if#1-\XINTdigits\fi#1#2.{}}% -\def\XINT_pfloat::_b #1.#2#3,{\expandafter\XINT_pfloat::_c \romannumeral`&&@#3,{#1}{#2}}% -\def\XINT_pfloat::_c #1{\if ,#1\xint_dothis\XINT_pfloat::_e\fi - \if ^#1\xint_dothis\XINT_:::_end\fi - \xint_orthat\XINT_pfloat::_d #1}% -\def\XINT_pfloat::_d #1,#2% - {\expandafter\XINT_pfloat::_e\romannumeral0\XINT_pfloat_opt [\xint:#2]{#1},{#2}}% -\def\XINT_pfloat::_e #1,#2#3{\XINT_pfloat::_b #2.{#3, #1}}% -% \end{macrocode} -% \subsection{\csh{XINT_expr_getnext}: fetching some number then an operator} +\def\XINT:NEhook:unpack{\xint_stop_atfirstofone}% +\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:x:one:from:twoandone\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 +\def\XINT:NEhook:f:from:delim:u #1#2^{#1#2^}% +\def\XINT:NEhook:f:noeval:from:braced:u#1#2^{#1{#2}}% +\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} % \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.| +% 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. +% | % \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% -{% screens out sub-expressions and \count or \dimen registers/variables - \xint_gob_til_! #1\XINT_expr_subexpr !% recall this ! has catcode 11 - \ifcat\relax#1% \count or \numexpr etc... token or count, dimen, skip cs - \expandafter\XINT_expr_countetc - \else - \expandafter\expandafter\expandafter\XINT_expr_getnextfork\expandafter\string - \fi - #1% -}% -\def\XINT_expr_subexpr !#1\fi !{\expandafter\XINT_expr_getop\xint_gobble_iii }% -% \end{macrocode} -% \lverb|1.2 adds \ht, \dp, \wd and the eTeX font things.| -% \begin{macrocode} -\def\XINT_expr_countetc #1% {% - \ifx\count#1\else\ifx\dimen#1\else\ifx\numexpr#1\else\ifx\dimexpr#1\else - \ifx\skip#1\else\ifx\glueexpr#1\else\ifx\fontdimen#1\else\ifx\ht#1\else - \ifx\dp#1\else\ifx\wd#1\else\ifx\fontcharht#1\else\ifx\fontcharwd#1\else - \ifx\fontchardp#1\else\ifx\fontcharic#1\else - \XINT_expr_unpackvar - \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi - \expandafter\XINT_expr_getnext\number #1% -}% -\def\XINT_expr_unpackvar\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi - \expandafter\XINT_expr_getnext\number #1% - {\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi - \expandafter\XINT_expr_getop\csname .=\number#1\endcsname }% + \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} +% \lverb|1.2 adds \ht, \dp, \wd and the eTeX font things. 1.4 avoids big +% nested \if's, simply for code readability| +% \begin{macrocode} +\def\XINT_expr_countetc\XINT_expr_getnextfork#1% +{% + \if0\ifx\count#11\fi + \ifx\dimen#11\fi + \ifx\numexpr#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} +% \lverb|This is a key component which is involved in: +%( +%: - support for \xintdeffunc via special handling of parameter character, +%: - support for skipping over ignored + signs, +%: - support for Python-like * «unpacking» unary operator (added at 1.4), +%: - support for [..] nutple constructor (1.4, formerly [..] by itself was like (...)), +%: - support for numbers starting with a decimal point, +%: - support for the minus as unary operator of variable precedence level, +%: - support for sub-expressions inside parenthesis (with possibly tacit multiplication) +%: - else starting the scan of explicit digits or letters for a number or a function name +%) +% | +% \begin{macrocode} \begingroup -\lccode`*=`# +\lccode`;=`# \lowercase{\endgroup \def\XINT_expr_getnextfork #1{% - \if#1*\xint_dothis {\XINT_expr_scan_macropar *}\fi - \if#1[\xint_dothis {\xint_c_xviii ({}}\fi - \if#1+\xint_dothis \XINT_expr_getnext \fi + \if#1;\xint_dothis {\XINT_expr_scan_macropar ;}\fi + \if#1+\xint_dothis \XINT_expr_getnext_a \fi + \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 {\XINT_expr_startdec}\fi - \if#1-\xint_dothis -\fi - \if#1(\xint_dothis {\xint_c_xviii ({}}\fi + \if#1-\xint_dothis {{}{}-}\fi + \if#1(\xint_dothis {{}\xint_c_ii^v (}\fi \xint_orthat {\XINT_expr_scan_nbr_or_func #1}% }}% -\def\XINT_expr_scan_macropar #1#2{\expandafter\XINT_expr_getop\csname .=#1#2\endcsname }% +\def\XINT_expr_scan_macropar #1#2% +{% + \expandafter{\expandafter{\expandafter#1\expandafter + #2\expandafter}\expandafter}\romannumeral`&&@\XINT_expr_getop +}% % \end{macrocode} -% \subsection{\csh{XINT_expr_scan_nbr_or_func}: the integer or decimal number or hexa-decimal number or -% function name or variable name or special hacky things big parser} +% \subsection{\csh{XINT_expr_scan_nbr_or_func}: parsing the integer or decimal number or hexa-decimal number or +% function name or variable name or special hacky things} % \localtableofcontents % \lverb@1.2 release has replaced chains of \romannumeral-`0 by \csname % governed expansion. Thus there is no more the limit at about 5000 digits for @@ -35023,33 +35359,38 @@ math shift catcode. % \XINT_expr_op_` this then becomes a suitable % \XINT_{expr|iiexpr|flexpr}_func_+ (or *). Documentation says to use % `+`(...), but `+(...) is also valid. The opening parenthesis must be there, -% it is not allowed to come from expansion.@ +% it is not allowed to come from expansion. +% +% Attention at this location #1 was of catcode 12 in all versions prior to +% 1.4. +% +% Besides using principally \if tests, we will assume anyhow that +% catcodes of digits are 12... +% @ % % \begin{macrocode} \catcode96 11 % ` -\def\XINT_expr_scan_nbr_or_func #1% this #1 has necessarily here catcode 12 -{%( - \if )#1\xint_dothis \XINT_expr_gotnil \fi +\def\XINT_expr_scan_nbr_or_func #1% +{% \if "#1\xint_dothis \XINT_expr_scanhex_I\fi \if `#1\xint_dothis {\XINT_expr_onliteral_`}\fi - \ifnum \xint_c_ix<1#1 \xint_dothis \XINT_expr_startint\fi + \ifnum \xint_c_ix<1\string#1 \xint_dothis \XINT_expr_startint\fi \xint_orthat \XINT_expr_scanfunc #1% }% -\def\XINT_expr_gotnil{\expandafter\XINT_expr_getop\csname.= \endcsname}% -\def\XINT_expr_onliteral_` #1#2#3({\xint_c_xviii `{#2}}% +\def\XINT_expr_onliteral_` #1#2#3({{#2}\xint_c_ii^v `}% \catcode96 12 % ` \def\XINT_expr_startint #1% {% - \if #10\expandafter\XINT_expr_gobz_a\else\XINT_expr_scanint_a\fi #1% + \if #10\expandafter\XINT_expr_gobz_a\else\expandafter\XINT_expr_scanint_a\fi #1% }% \def\XINT_expr_scanint_a #1#2% - {\expandafter\XINT_expr_getop\csname.=#1% - \expandafter\XINT_expr_scanint_b\romannumeral`&&@#2}% -\def\XINT_expr_gobz_a #1% - {\expandafter\XINT_expr_getop\csname.=% - \expandafter\XINT_expr_gobz_scanint_b\romannumeral`&&@#1}% + {\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% - {\expandafter\XINT_expr_getop\csname.=% + {\expanded\bgroup{{\iffalse}}\fi \expandafter\XINT_expr_scandec_a\romannumeral`&&@#1}% % \end{macrocode} % \subsubsection{Integral part (skipping zeroes)} @@ -35057,17 +35398,20 @@ math shift catcode. % accelerating impact is non-negligeable. I don't think the doubled \string is % a serious penalty.| % \begin{macrocode} -\def\XINT_expr_scanint_b #1% +\def\XINT_expr_scanint_main #1% {% - \ifcat \relax #1\expandafter\XINT_expr_scanint_endbycs\expandafter #1\fi - \ifnum\xint_c_ix<1\string#1 \else\expandafter\XINT_expr_scanint_c\fi - \string#1\XINT_expr_scanint_d + \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_d #1% +\def\XINT_expr_scanint_again #1% {% - \expandafter\XINT_expr_scanint_b\romannumeral`&&@#1% + \expandafter\XINT_expr_scanint_main\romannumeral`&&@#1% +}% +\def\XINT_expr_scanint_hit_cs \ifnum#1\fi#2\XINT_expr_scanint_again +{% + \iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop#2% }% -\def\XINT_expr_scanint_endbycs#1#2\XINT_expr_scanint_d{\endcsname #1}% % \end{macrocode} % \lverb|With 1.2d the tacit multiplication in front of a variable name or % function name is now done with a higher precedence, intermediate between the @@ -35084,52 +35428,67 @@ math shift catcode. % % Extended for 1.2l to ignore underscore character _ if encountered within % digits; so it can serve as separator for better readability.| -% \begin{macrocode} -\def\XINT_expr_scanint_c\string #1\XINT_expr_scanint_d -{% - \if _#1\xint_dothis\XINT_expr_scanint_d\fi +% +% \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.| +% \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 {\endcsname #1}% + \xint_orthat + {\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop#1}% }% -\def\XINT_expr_startdec_a .#1% +\def\XINT_expr_rawxintfrac {% - \expandafter\XINT_expr_scandec_a\romannumeral`&&@#1% + \iffalse{{{\fi}}\expandafter}\csname XINT_expr_precedence_&&@\endcsname&&@% }% -\def\XINT_expr_scandec_a #1% +\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% {% - \if .#1\xint_dothis{\endcsname..}\fi - \xint_orthat {\XINT_expr_scandec_b 0.#1}% + \expandafter\XINT_expr_gobz_scanint_main\romannumeral`&&@#1% }% -\def\XINT_expr_gobz_scanint_b #1% +\def\XINT_expr_gobz_scanint_hit_cs\ifnum#1\fi#2\XINT_expr_scanint_again {% - \ifcat \relax #1\expandafter\XINT_expr_gobz_scanint_endbycs\expandafter #1\fi - \ifnum\xint_c_x<1\string#1 \else\expandafter\XINT_expr_gobz_scanint_c\fi - \string#1\XINT_expr_scanint_d + 0\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop#2% }% -\def\XINT_expr_gobz_scanint_endbycs#1#2\XINT_expr_scanint_d{0\endcsname #1}% -\def\XINT_expr_gobz_scanint_c\string #1\XINT_expr_scanint_d +\def\XINT_expr_gobz_scanint_next #1\XINT_expr_scanint_again {% - \if _#1\xint_dothis\XINT_expr_gobz_scanint_d\fi + \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_d\fi - \xint_orthat {0\endcsname #1}% -}% -\def\XINT_expr_gobz_scanint_d #1% -{% - \expandafter\XINT_expr_gobz_scanint_b\romannumeral`&&@#1% -}% -\def\XINT_expr_gobz_startdec_a .#1% -{% - \expandafter\XINT_expr_gobz_scandec_a\romannumeral`&&@#1% -}% -\def\XINT_expr_gobz_scandec_a #1% -{% - \if .#1\xint_dothis{0\endcsname..}\fi - \xint_orthat {\XINT_expr_gobz_scandec_b 0.#1}% + \if 0#1\xint_dothis\XINT_expr_gobz_scanint_again\fi + \xint_orthat + {0\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop#1}% }% % \end{macrocode} % \subsubsection{Fractional part} @@ -35141,45 +35500,73 @@ math shift catcode. % reported the issue. Does it improve things if I say the bug was introduced % in 1.2, it wasn't present before ?| % \begin{macrocode} -\def\XINT_expr_scandec_b #1.#2% +\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..}\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..}\fi + \xint_orthat {\XINT_expr_gobz_scandec_main 0.#1}% +}% +\def\XINT_expr_scandec_main #1.#2% {% - \ifcat \relax #2\expandafter\XINT_expr_scandec_endbycs\expandafter#2\fi - \ifnum\xint_c_ix<1\string#2 \else\expandafter\XINT_expr_scandec_c\fi - \string#2\expandafter\XINT_expr_scandec_d\the\numexpr #1-\xint_c_i.% + \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_endbycs #1#2\XINT_expr_scandec_d - \the\numexpr#3-\xint_c_i.{[#3]\endcsname #1}% -\def\XINT_expr_scandec_d #1.#2% +\def\XINT_expr_scandec_again #1.#2% {% - \expandafter\XINT_expr_scandec_b + \expandafter\XINT_expr_scandec_main \the\numexpr #1\expandafter.\romannumeral`&&@#2% }% -\def\XINT_expr_scandec_c\string #1#2\the\numexpr#3-\xint_c_i.% +\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#2% +}% +\def\XINT_expr_scandec_next #1#2\the\numexpr#3-\xint_c_i.% {% - \if _#1\xint_dothis{\XINT_expr_scandec_d#3.}\fi + \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]\endcsname #1}% + \xint_orthat + {[#3]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop#1}% }% % \end{macrocode} % \begin{macrocode} -\def\XINT_expr_gobz_scandec_b #1.#2% +\def\XINT_expr_gobz_scandec_main #1.#2% {% - \ifcat \relax #2\expandafter\XINT_expr_gobz_scandec_endbycs\expandafter#2\fi - \ifnum\xint_c_ix<1\string#2 \else\expandafter\XINT_expr_gobz_scandec_c\fi + \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_b}% - {\string#2\expandafter\XINT_expr_scandec_d}\the\numexpr#1-\xint_c_i.% + {\expandafter\XINT_expr_gobz_scandec_main}% + {#2\expandafter\XINT_expr_scandec_again}\the\numexpr#1-\xint_c_i.% }% % \end{macrocode} % \begin{macrocode} -\def\XINT_expr_gobz_scandec_endbycs #1#2\xint_c_i.{0[0]\endcsname #1}% -\def\XINT_expr_gobz_scandec_c\if0#1#2\fi #3\numexpr#4-\xint_c_i.% +\def\XINT_expr_gobz_scandec_hit_cs \ifnum#1\fi\if0#2#3\xint_c_i.% {% - \if _#1\xint_dothis{\XINT_expr_gobz_scandec_b #4.}\fi + 0[0]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop#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]\endcsname #1}% + \xint_orthat + {0[0]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop#1}% }% % \end{macrocode} % \subsubsection{Scientific notation} @@ -35188,41 +35575,49 @@ math shift catcode. % \begin{macrocode} \def\XINT_expr_scanexp_a #1#2% {% - #1\expandafter\XINT_expr_scanexp_b\romannumeral`&&@#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_b #1% +\def\XINT_expr_scanexp_again #1% {% - \ifcat \relax #1\expandafter\XINT_expr_scanexp_endbycs\expandafter #1\fi - \ifnum\xint_c_ix<1\string#1 \else\expandafter\XINT_expr_scanexp_c\fi - \string#1\XINT_expr_scanexp_d + \expandafter\XINT_expr_scanexp_main_b\romannumeral`&&@#1% }% -\def\XINT_expr_scanexpr_endbycs#1#2\XINT_expr_scanexp_d {]\endcsname #1}% -\def\XINT_expr_scanexp_d #1% +\def\XINT_expr_scanexpr_hit_cs\ifnum#1\fi#2\XINT_expr_scanexp_again {% - \expandafter\XINT_expr_scanexp_bb\romannumeral`&&@#1% + ]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop#2% }% -\def\XINT_expr_scanexp_c\string #1\XINT_expr_scanexp_d +\def\XINT_expr_scanexp_next #1\XINT_expr_scanexp_again {% - \if _#1\xint_dothis \XINT_expr_scanexp_d \fi + \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 {]\endcsname #1}% + \xint_orthat + {]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop#1}% }% -\def\XINT_expr_scanexp_bb #1% +\def\XINT_expr_scanexp_main_b #1% {% - \ifcat \relax #1\expandafter\XINT_expr_scanexp_endbycs_b\expandafter #1\fi - \ifnum\xint_c_ix<1\string#1 \else\expandafter\XINT_expr_scanexp_cb\fi - \string#1\XINT_expr_scanexp_db + \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 }% -\def\XINT_expr_scanexp_endbycs_b#1#2\XINT_expr_scanexp_db {]\endcsname #1}% -\def\XINT_expr_scanexp_db #1% +\def\XINT_expr_scanexp_hit_cs_b\ifnum#1\fi#2\XINT_expr_scanexp_again_b {% - \expandafter\XINT_expr_scanexp_bb\romannumeral`&&@#1% + ]\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\XINT_expr_getop#2% }% -\def\XINT_expr_scanexp_cb\string #1\XINT_expr_scanexp_db +\def\XINT_expr_scanexp_again_b #1% {% - \if _#1\xint_dothis\XINT_expr_scanexp_d\fi - \xint_orthat{]\endcsname #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#1}% }% % \end{macrocode} % \subsubsection{Hexadecimal numbers} @@ -35237,16 +35632,23 @@ math shift catcode. % Extended for 1.2l to ignore underscore character _ if encountered within % digits.| % \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 +}% \def\XINT_expr_scanhex_I #1% #1=" {% - \expandafter\XINT_expr_getop\csname.=\expandafter - \XINT_expr_unlock_hex_in\csname.=\XINT_expr_scanhexI_a + \expandafter\XINT_expr_hex_in\expanded\bgroup\XINT_expr_scanhexI_a }% \def\XINT_expr_scanhexI_a #1% {% - \ifcat #1\relax\xint_dothis{.>\endcsname\endcsname #1}\fi - \ifx !#1\xint_dothis{.>\endcsname\endcsname !}\fi - \xint_orthat {\expandafter\XINT_expr_scanhexI_aa\string #1}% + \ifcat #1\relax\xint_dothis{.>;\iffalse{\fi}#1}\fi + \xint_orthat {\XINT_expr_scanhexI_aa #1}% }% \def\XINT_expr_scanhexI_aa #1% {% @@ -35259,8 +35661,7 @@ math shift catcode. \else \if _#1\xint_dothis{\expandafter\XINT_expr_scanhexI_bgob}\fi \if .#1\xint_dothis{\expandafter\XINT_expr_scanhex_transition}\fi - \xint_orthat % gather what we got so far, leave catcode 12 #1 in stream - {\xint_afterfi {.>\endcsname\endcsname}}% + \xint_orthat {\xint_afterfi {.>;\iffalse{\fi}}}% \fi #1% }% @@ -35279,9 +35680,8 @@ math shift catcode. }% \def\XINT_expr_scanhexII_a #1% {% - \ifcat #1\relax\xint_dothis{\endcsname\endcsname#1}\fi - \ifx !#1\xint_dothis{\endcsname\endcsname !}\fi - \xint_orthat {\expandafter\XINT_expr_scanhexII_aa\string #1}% + \ifcat #1\relax\xint_dothis{;\iffalse{\fi}#1}\fi + \xint_orthat {\XINT_expr_scanhexII_aa #1}% }% \def\XINT_expr_scanhexII_aa #1% {% @@ -35293,7 +35693,7 @@ math shift catcode. \expandafter\XINT_expr_scanhexII_b \else \if _#1\xint_dothis{\expandafter\XINT_expr_scanhexII_bgob}\fi - \xint_orthat{\xint_afterfi {\endcsname\endcsname}}% + \xint_orthat{\xint_afterfi {;\iffalse{\fi}}}% \fi #1% }% @@ -35306,15 +35706,42 @@ math shift catcode. \expandafter\XINT_expr_scanhexII_a\romannumeral`&&@#2% }% % \end{macrocode} -% \subsubsection{\csh{XINT_expr_scanfunc}: parsing names of functions and variables} +% \subsubsection{\csh{XINT_expr_scanfunc}: collecting names of functions and +% variables} +% +% \lverb|At 1.4 the first token left over in string 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 (which +% however can cause breakage of arithmetic operations, although xintfrac.sty +% converts empty to 0). +% +% The @ causes a problem because it must work with both catcode 11 or 12. +% +% The _ can be used internally for starting variables but it will have catcode +% 11 then. +% +% 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. +% +% But we have to be careful that !(...) and ?(...) are part of the syntax +% and genuine functions. Because we now do earlier to getop we must filter +% them out. +%| % \begin{macrocode} -\def\XINT_expr_scanfunc +\def\XINT_expr_scanfunc #1% {% - \expandafter\XINT_expr_func\romannumeral`&&@\XINT_expr_scanfunc_a + \if 1\ifcat a#10\fi\if @#10\fi\if !#10\fi\if ?#10\fi 1% + \expandafter\xint_firstoftwo + \else\expandafter\xint_secondoftwo + \fi + {\expandafter{\expandafter}\romannumeral`&&@\XINT_expr_getop#1}% + {\expandafter\XINT_expr_func\expanded\bgroup#1\XINT_expr_scanfunc_a}% }% -\def\XINT_expr_scanfunc_a #1#2% +\def\XINT_expr_scanfunc_a #1% {% - \expandafter #1\romannumeral`&&@\expandafter\XINT_expr_scanfunc_b\romannumeral`&&@#2% + \expandafter\XINT_expr_scanfunc_b\romannumeral`&&@#1% }% % \end{macrocode} % \lverb|This handles: 1) (indirectly) tacit multiplication by a variable in @@ -35345,24 +35772,26 @@ math shift catcode. % \begin{macrocode} \def\XINT_expr_scanfunc_b #1% {% - \ifx !#1\xint_dothis{(_}\fi - \ifcat \relax#1\xint_dothis{(_}\fi - \if (#1\xint_dothis{\xint_firstoftwo{(`}}\fi - \if @#1\xint_dothis \XINT_expr_scanfunc_a \fi - \if _#1\xint_dothis \XINT_expr_scanfunc_a \fi - \ifnum \xint_c_ix<1\string#1 \xint_dothis \XINT_expr_scanfunc_a \fi - \ifcat a#1\xint_dothis \XINT_expr_scanfunc_a \fi - \xint_orthat {(_}% - #1% + \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} % \lverb@Comments written 2015/11/12: earlier there was an \ifcsname test for % checking if we had a variable in front of a (, for tacit multiplication for % example in x(y+z(x+w)) to work. But after I had implemented functions (that % was yesterday...), I had the problem if was impossible to re-declare a % variable name such as "f" as a function name. The problem is that here we % can not test if the function is available because we don't know if we are in -% expr, iiexpr or floatexpr. The \xint_c_xviii causes all fetching operations +% 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. @@ -35380,19 +35809,112 @@ math shift catcode. % iter ... routines as now the variables fetch only one token. I think the % thing is more efficient. % -% 1.2c had \def\XINT_expr_func #1(#2{\xint_c_xviii #2{#1}} +% 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_xviii is there because _op_` must know in which parser +% The \xint_c_ii^v is there because _op_` must know in which parser % it works. Dispendious for _. Hence I modify for 1.2d. @ % \begin{macrocode} -\def\XINT_expr_func #1(#2{\if _#2\xint_dothis\XINT_expr_op__\fi - \xint_orthat{\xint_c_xviii #2}{#1}}% +\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} +% +% \lverb|The "onliteral" intercepts is for bool, togl, protect, ... but also +% for add, mul, seq, etc... Genuine functions have expr, iiexpr and flexpr +% versions (or only one or two of the three). +% +% With 1.2c "onliteral" is also used to disambiguate 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. +% | +% \begin{macrocode} +\def\XINT_tmpa #1#2#3{% + \def #1##1% + {% + \ifcsname XINT_#3_func_##1\endcsname + \csname XINT_#3_func_##1\expandafter\endcsname + \romannumeral`&&@\expandafter#2% + \else + \ifcsname XINT_expr_onliteral_##1\endcsname + \csname XINT_expr_onliteral_##1\expandafter\expandafter\expandafter + \endcsname + \else + \csname XINT_#3_func_\XINT_expr_unknown_function {##1}% + \expandafter\endcsname + \romannumeral`&&@\expandafter\expandafter\expandafter#2% + \fi + \fi + }% +}% +\def\XINT_expr_unknown_function #1% + {\XINT_expandableerror{"#1" is unknown as function. (I)nsert correct name:}}% +\def\XINT_expr_func_ #1#2#3{#1#2{{0}}}% +\xintFor #1 in {expr,flexpr,iiexpr} \do {% + \expandafter\XINT_tmpa + \csname XINT_#1_op_`\expandafter\endcsname + \csname XINT_#1_oparen\endcsname + {#1}% +}% +% \end{macrocode} +% +% \subsection{\csh{XINT_expr_op__}: replace a variable by its value and +% then fetch next operator} +% \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 dummy variables +% which rely on possibility to modify upstream tokens. If we did here +% something such as +% _var_#1\expandafter\endcsname\romannumeral`^^@\XINT_expr_getop +% the premature expansion of getop would break things. Thus we revert +% to former code which put \XINT_expr_getop (call it _legacy) +% in front of variable expansion (in xintexpr < 1.4 this expanded +% to a single token so the overhead was not serious). +% +% Abusing variables to manipulate token stream is a bit bad, usually +% I prefer functions for this (such as the break() function) but +% then I have define 3 macros for the 3 parsers. +% +% The situation here is not satisfactory. But 1.4 has to be released +% now.| +% \begin{macrocode} +\def\XINT_expr_op__ #1% op__ with two _'s +{% + \ifcsname XINT_expr_var_#1\endcsname + \expandafter\expandafter\expandafter\XINT_expr_getop_legacy + \csname XINT_expr_var_#1\expandafter\endcsname + \else + \expandafter\expandafter\expandafter\XINT_expr_getop_legacy + \csname XINT_expr_var_\XINT_expr_unknown_variable {#1}% + \expandafter\endcsname + \fi +}% +\def\XINT_expr_unknown_variable #1% + {\XINT_expandableerror {"#1" is unknown as a variable. (I)nsert correct one:}}% +\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}: finding the next operator or closing +% \subsection{\csh{XINT_expr_getop}: fetch the next operator or closing % parenthesis or end of expression} % \lverb|Release 1.1 implements multi-character operators. % @@ -35415,64 +35937,85 @@ math shift catcode. % the catcode 11 ! had to be identified in all branches of the number or % function scans. Here it is simply treated as a special case of a letter. % -% 1.2q adds tacit multiplication in cases such as (1+1)3 or 5!7!| +% 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. +% +% | % \begin{macrocode} -\def\XINT_expr_getop #1#2% this #1 is the current locked computed value +\def\XINT_expr_getop #1% {% - \expandafter\XINT_expr_getop_a\expandafter #1\romannumeral`&&@#2% + \expandafter\XINT_expr_getop_a\romannumeral`&&@#1% }% \catcode`* 11 -\def\XINT_expr_getop_a #1#2% -{% - \ifx \relax #2\xint_dothis\xint_firstofthree\fi - \ifcat \relax #2\xint_dothis\xint_secondofthree\fi - \ifnum\xint_c_ix<1\string#2 \xint_dothis\xint_secondofthree\fi - \if _#2\xint_dothis \xint_secondofthree\fi - \if @#2\xint_dothis \xint_secondofthree\fi - \if (#2\xint_dothis \xint_secondofthree\fi - \ifcat a#2\xint_dothis \xint_secondofthree\fi +\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 + \if (#1\xint_dothis \xint_secondofthree\fi %) + \ifcat a#1\xint_dothis \xint_secondofthree\fi \xint_orthat \xint_thirdofthree - {\XINT_expr_foundend #1}% - {\XINT_expr_precedence_*** *#1#2}% tacit multiplication with higher precedence - {\expandafter\XINT_expr_getop_b \string#2#1}% + {\XINT_expr_foundend}% +% \end{macrocode} +% \lverb|tacit multiplication with higher precedence.| +% \begin{macrocode} + {\XINT_expr_precedence_*** *#1}% + {\expandafter\XINT_expr_getop_b \string#1}% }% \catcode`* 12 -\def\XINT_expr_foundend {\xint_c_ \relax }% \relax is a place holder here. +% \end{macrocode} +% \lverb|\relax is a place holder here.| +% \begin{macrocode} +\def\XINT_expr_foundend {\xint_c_ \relax}% % \end{macrocode} % \lverb|? is a very special operator with top precedence which will check if % the next token is another ?, while avoiding removing a brace pair from token % stream due to its syntax. Pre 1.1 releases used : rather than ??, but we % need : for Python like slices of lists.| +% +% \lverb|null char is used as hack to implement A/B[N] raw input at 1.4. See +% also \XINT_expr_scanint_c.| % \begin{macrocode} \def\XINT_expr_getop_b #1% {% + \if &&@#1\xint_dothis{\csname XINT_expr_precedence_&&@\endcsname&&@}\fi \if '#1\xint_dothis{\XINT_expr_binopwrd }\fi \if ?#1\xint_dothis{\XINT_expr_precedence_? ?}\fi \xint_orthat {\XINT_expr_scanop_a #1}% }% -\def\XINT_expr_binopwrd #1#2'{\expandafter\XINT_expr_foundop_a - \csname XINT_expr_itself_\xint_zapspaces #2 \xint_gobble_i\endcsname #1}% -\def\XINT_expr_scanop_a #1#2#3% - {\expandafter\XINT_expr_scanop_b\expandafter #1\expandafter #2\romannumeral`&&@#3}% -\def\XINT_expr_scanop_b #1#2#3% +\def\XINT_expr_binopwrd #1'% {% - \ifcat#3\relax\xint_dothis{\XINT_expr_foundop_a #1#2#3}\fi - \ifcsname XINT_expr_itself_#1#3\endcsname - \xint_dothis - {\expandafter\XINT_expr_scanop_c\csname XINT_expr_itself_#1#3\endcsname #2}\fi - \xint_orthat {\XINT_expr_foundop_a #1#2#3}% + \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% }% -\def\XINT_expr_scanop_c #1#2#3% +\def\XINT_expr_scanop_b #1#2% {% - \expandafter\XINT_expr_scanop_d\expandafter #1\expandafter #2\romannumeral`&&@#3% + \ifcat#2\relax\xint_dothis{\XINT_expr_foundop_a #1#2}\fi + \ifcsname XINT_expr_itself_#1#2\endcsname + \xint_dothis + {\expandafter\XINT_expr_scanop_c\csname XINT_expr_itself_#1#2\endcsname}\fi + \xint_orthat {\XINT_expr_foundop_a #1#2}% }% -\def\XINT_expr_scanop_d #1#2#3% +\def\XINT_expr_scanop_c #1#2% {% - \ifcat#3\relax \xint_dothis{\XINT_expr_foundop #1#2#3}\fi - \ifcsname XINT_expr_itself_#1#3\endcsname + \expandafter\XINT_expr_scanop_d\expandafter#1\romannumeral`&&@#2% +}% +\def\XINT_expr_scanop_d #1#2% +{% + \ifcat#2\relax \xint_dothis{\XINT_expr_foundop #1#2}\fi + \ifcsname XINT_expr_itself_#1#2\endcsname \xint_dothis - {\expandafter\XINT_expr_scanop_c\csname XINT_expr_itself_#1#3\endcsname #2}\fi - \xint_orthat {\csname XINT_expr_precedence_#1\endcsname #1#2#3}% + {\expandafter\XINT_expr_scanop_c\csname XINT_expr_itself_#1#2\endcsname }\fi + \xint_orthat {\csname XINT_expr_precedence_#1\endcsname #1#2}% }% \def\XINT_expr_foundop_a #1% {% @@ -35480,1173 +36023,1139 @@ math shift catcode. \csname XINT_expr_precedence_#1\expandafter\endcsname \expandafter #1% \else - \xint_afterfi{\XINT_expr_unknown_operator {#1}\XINT_expr_getop}% + \xint_afterfi{\XINT_expr_getop\romannumeral0% + \XINT_expandableerror + {"#1" is unknown as operator. (I)nsert one:} }%<<deliberate space \fi }% -\def\XINT_expr_unknown_operator #1{\xintError:removed \xint_gobble_i {#1}}% \def\XINT_expr_foundop #1{\csname XINT_expr_precedence_#1\endcsname #1}% % \end{macrocode} % \subsection{Expansion spanning; opening and closing parentheses} -% \lverb|Version 1.1 had a hack inside the until macros for handling the omit +% \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.| +% 1.2c, see the subsection where omit and abort are discussed. +% +% Exceptionally, the check- is here abbreviated to check. +% | % % \begin{macrocode} \catcode`) 11 -\def\XINT_tmpa #1#2#3#4% +\def\XINT_tmpa #1#2#3#4#5#6% {% - \def#1##1% + \def#1% start + {% + \expandafter#2\romannumeral`&&@\XINT_expr_getnext + }% + \def#2##1% check {% \xint_UDsignfork - ##1{\expandafter#1\romannumeral`&&@#3}% - -{#2##1}% + ##1{\expandafter#3\romannumeral`&&@#4}% + -{#3##1}% \krof }% - \def#2##1##2% + \def#3##1##2% checkp {% - \ifcase ##1\expandafter\XINT_expr_done - \or\xint_afterfi{\XINT_expr_extra_) - \expandafter #1\romannumeral`&&@\XINT_expr_getop }% + \ifcase ##1% + \expandafter\XINT_expr_done + \or\expandafter#5% \else - \xint_afterfi{\expandafter#1\romannumeral`&&@\csname XINT_#4_op_##2\endcsname }% + \expandafter#3\romannumeral`&&@\csname XINT_#6_op_##2\expandafter\endcsname \fi }% + \def#5% + {% + \XINT_expandableerror + {An extra ) has been removed. Hit Return, fingers crossed.}% + \expandafter#2\romannumeral`&&@\expandafter\XINT_expr_put_op_first + \romannumeral`&&@\XINT_expr_getop_legacy + }% }% -\def\XINT_expr_extra_) {\xintError:removed }% +\let\XINT_expr_done\space \xintFor #1 in {expr,flexpr,iiexpr} \do {% \expandafter\XINT_tmpa - \csname XINT_#1_until_end_a\expandafter\endcsname - \csname XINT_#1_until_end_b\expandafter\endcsname - \csname XINT_#1_op_-vi\endcsname + \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}% }% -\def\XINT_tmpa #1#2#3#4#5#6% +% \end{macrocode} +% \lverb|& +% Here also we take some shortcuts relative to general philosophy and have no explicit +% exec macro.| +% \begin{macrocode} +\def\XINT_tmpa #1#2#3#4#5#6#7% {% - \def #1##1{\expandafter #3\romannumeral`&&@\XINT_expr_getnext }% - \def #2{\expandafter #3\romannumeral`&&@\XINT_expr_getnext }% - \def #3##1{\xint_UDsignfork - ##1{\expandafter #3\romannumeral`&&@#5}% - -{#4##1}% - \krof }% - \def #4##1##2{\ifcase ##1\expandafter\XINT_expr_missing_) - \or \csname XINT_#6_op_##2\expandafter\endcsname - \else - \xint_afterfi{\expandafter #3\romannumeral`&&@\csname XINT_#6_op_##2\endcsname }% - \fi + \def #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_) {\xintError:inserted \xint_c_ \XINT_expr_done }% -% \end{macrocode} -% \lverb|We should be using until_( notation to stay synchronous with until_+, -% until_* etc..., but I found that until_) was more telling.| -% \begin{macrocode} -\catcode`) 12 +\def\XINT_expr_missing_) + {\XINT_expandableerror{Sorry to report a missing ) at the end of this journey.}% + \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_until_)_a\expandafter\endcsname - \csname XINT_#1_until_)_b\expandafter\endcsname - \csname XINT_#1_op_-vi\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_i +\let\XINT_expr_precedence_)\xint_c_i +\catcode`) 12 % \end{macrocode} -% \subsection{\textbar, \textbar\textbar, \&, -% \&\&, <, >, =, ==, <=, >=, !=, +, \textendash, -% \texorpdfstring{\protect\lowast}{*}, /, \textasciicircum, -% \texorpdfstring{\protect\lowast\protect\lowast}{**}, //, /:, .., ..[, ].., -% ][, ][:, :], and ++ operators} -% \localtableofcontents -% \subsubsection{Square brackets for lists, the -% !? for omit and abort, and the ++ postfix construct} -% \lverb|This is all very clever and only need setting some suitable precedence -% levels, if only I could understand what I did in 2014... just joking. Notice -% that op_) macros are defined here in the \xintFor loop. -% -% There is some clever business going on here with the letter a for handling -% constructs such as [3..5]*2 (I think...). -% -% 1.2c has replaced 1.1's private dealings with "^C" (which was done before -% dummy variables got implemented) by use of "!?". See discussion of omit and -% abort. -% | +% \subsection{The comma as binary operator} +% \lverb|New with 1.09a. Refactored at 1.4.| % \begin{macrocode} -\expandafter\let\csname XINT_expr_precedence_]\endcsname\xint_c_i -\expandafter\let\csname XINT_expr_precedence_;\endcsname\xint_c_i -\let\XINT_expr_precedence_a \xint_c_xviii -\let\XINT_expr_precedence_!? \xint_c_ii -\expandafter\let\csname XINT_expr_precedence_++)\endcsname \xint_c_i -% \end{macrocode} -% \lverb|Comments added 2015/11/13 Here we have in particular the mechanism -% for post action on lists via op_] The precedence_] is the one of a closing -% parenthesis. We need the closing parenthesis to do its job, hence we can not -% define a op_]+ operator for example, as we want to assign it the precedence -% of addition not the one of closing parenthesis. The trick I used in 1.1 was -% to let the op_] insert the letter a, this letter exceptionnally also being a -% legitimate operator, launch the _getop and let it find a a*, a+, a/, a-, a^, -% a** operator standing for ]*, ]+, ]/, ]^, ]** postfix item by item list -% operator. I thought I had in mind an example to show that having defined -% op_a and precedence_a for the letter a caused a reduction in syntax for this -% letter, but it seems I am lacking now an example. -% -% 2015/11/18: for 1.2d I accelerate \XINT_expr_op_] to jump over the -% \XINT_expr_getop_a which now does tacit multiplications also in front of -% letters, for reasons of things like, (x+y)z, hence it must not see the "a". -% I could have used a catcode12 a possibly, but anyhow jumping straight to -% \XINT_expr_scanop_a skips a few expansion steps (up to the potential price -% of less conceptual programming if I change things in the future.)| -% \begin{macrocode} -\catcode`. 11 \catcode`= 11 \catcode`+ 11 +\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\let\csname XINT_#1_op_)\endcsname \XINT_expr_getop - \expandafter\let\csname XINT_#1_op_;\endcsname \space - \expandafter\def\csname XINT_#1_op_]\endcsname ##1{\XINT_expr_scanop_a a##1}% - \expandafter\let\csname XINT_#1_op_a\endcsname \XINT_expr_getop +\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} -% \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... +% \subsection{The minus as prefix operator of variable precedence level} +% \lverb|Inherits the precedence level of the previous infix operator. +% Refactored at 1.4| +% \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% +}% +% \end{macrocode} +% \lverb|1.2d needs precedence 8 for *** and 9 for ^. Earlier, precedence +% level for ^ was only 8 but nevertheless the code did also "ix" here, which I +% think was unneeded back then.| +% \begin{macrocode} +\xintApplyInline{\XINT_tmpa {expr}\xintOpp}{{xii}{xiv}{xvi}{xviii}}% +\xintApplyInline{\XINT_tmpa {flexpr}\xintOpp}{{xii}{xiv}{xvi}{xviii}}% +\xintApplyInline{\XINT_tmpa {iiexpr}\xintiiOpp}{{xii}{xiv}{xvi}{xviii}}% +% \end{macrocode} +% \subsection{The \texorpdfstring{\protect\lowast}{*}{} as Python-like «unpacking» prefix operator} % -% 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. +% \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.| % -% The \xintiCeil appears a bit dispendious, but I need the starting value in a -% \numexpr compatible form in the iteration loops.| +% % \begin{macrocode} - \expandafter\def\csname XINT_#1_op_++)\endcsname ##1##2\relax - {\expandafter\XINT_expr_foundend \expandafter - {\expandafter\.=+\csname .=\XINT:NEhook:one\xintiCeil{\XINT_expr_unlock ##1}\endcsname }}% +\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 + }% }% -\catcode`. 12 \catcode`= 12 \catcode`+ 12 +\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 +% % \lverb|1.2d adds the *** for tying via tacit multiplication, for example % x/2y. Actually I don't need the _itself mechanism for ***, only a precedence.| % \begin{macrocode} \catcode`& 12 -\xintFor* #1 in {{==}{<=}{>=}{!=}{&&}{||}{**}{//}{/:}{..}{..[}{].}{]..}% - {+[}{-[}{*[}{/[}{**[}{^[}{a+}{a-}{a*}{a/}{a**}{a^}% - {][}{][:}{:]}{!?}{++}{++)}}%{***}} +\xintFor* #1 in {{==}{<=}{>=}{!=}{&&}{||}{**}{//}{/:}{..}{..[}{].}{]..}}% \do {\expandafter\def\csname XINT_expr_itself_#1\endcsname {#1}}% \catcode`& 7 -\expandafter\let\csname XINT_expr_precedence_***\endcsname \xint_c_viii +\expandafter\let\csname XINT_expr_precedence_***\endcsname \xint_c_xvi % \end{macrocode} -% \subsubsection{The \textbar, \&, xor, <, >, =, <=, >=, !=, //, /:, .., +, -% \textendash, \texorpdfstring{\protect\lowast}{*}, /, \textasciicircum, ..[, -% and ].. operators for expr, floatexpr and iiexpr operators} -% \lverb|1.2d needed some room between /, * and ^. Hence precedence for ^ -% is now at 9| +% \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} +% +% \lverb@& +% Usage of $& and | is deprecated and only $&$& and || should be used. +% @ % \begin{macrocode} \def\XINT_expr_defbin_c #1#2#3#4#5#6#7#8#9% {% - \def #1##1% \XINT_expr_op_<op> ou flexpr ou iiexpr - {% keep value, get next number and operator, then do until - \expandafter #2\expandafter ##1% - \romannumeral`&&@\expandafter\XINT_expr_getnext }% - \def #2##1##2% \XINT_expr_until_<op>_a ou flexpr ou iiexpr - {\xint_UDsignfork ##2{\expandafter #2\expandafter ##1\romannumeral`&&@#4}% - -{#3##1##2}% - \krof }% - \def #3##1##2##3##4% \XINT_expr_until_<op>_b ou flexpr ou iiexpr - {% either execute next operation now, or first do next (possibly unary) - \ifnum ##2>#7% - \xint_afterfi {\expandafter #2\expandafter ##1\romannumeral`&&@% - \csname XINT_#8_op_##3\endcsname {##4}}% - \else \xint_afterfi {\expandafter ##2\expandafter ##3% - \csname .=#9#6{\XINT_expr_unlock ##1}{\XINT_expr_unlock ##4}\endcsname }% - \fi }% - \let #7#5% + \def #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 + {#9{\romannumeral`&&@#6##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>#7% + \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_until_#2_a\expandafter\endcsname - \csname XINT_#1_until_#2_b\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_-#4\expandafter\endcsname - \csname xint_c_#3\expandafter\endcsname \csname #5\expandafter\endcsname - \csname XINT_expr_precedence_#2\endcsname {#1}\XINT:NEhook:two -}% -\XINT_expr_defbin_b {expr} | {iii}{vi} {xintOR}% -\XINT_expr_defbin_b {flexpr} | {iii}{vi} {xintOR}% -\XINT_expr_defbin_b {iiexpr} | {iii}{vi} {xintOR}% -\XINT_expr_defbin_b {expr} & {iv}{vi} {xintAND}% -\XINT_expr_defbin_b {flexpr} & {iv}{vi} {xintAND}% -\XINT_expr_defbin_b {iiexpr} & {iv}{vi} {xintAND}% -\XINT_expr_defbin_b {expr} {xor}{iii}{vi} {xintXOR}% -\XINT_expr_defbin_b {flexpr}{xor}{iii}{vi} {xintXOR}% -\XINT_expr_defbin_b {iiexpr}{xor}{iii}{vi} {xintXOR}% -\XINT_expr_defbin_b {expr} < {v}{vi} {xintLt}% -\XINT_expr_defbin_b {flexpr} < {v}{vi} {xintLt}% -\XINT_expr_defbin_b {iiexpr} < {v}{vi} {xintiiLt}% -\XINT_expr_defbin_b {expr} > {v}{vi} {xintGt}% -\XINT_expr_defbin_b {flexpr} > {v}{vi} {xintGt}% -\XINT_expr_defbin_b {iiexpr} > {v}{vi} {xintiiGt}% -\XINT_expr_defbin_b {expr} = {v}{vi} {xintEq}% -\XINT_expr_defbin_b {flexpr} = {v}{vi} {xintEq}% -\XINT_expr_defbin_b {iiexpr} = {v}{vi} {xintiiEq}% -\XINT_expr_defbin_b {expr} {<=} {v}{vi} {xintLtorEq}% -\XINT_expr_defbin_b {flexpr}{<=} {v}{vi} {xintLtorEq}% -\XINT_expr_defbin_b {iiexpr}{<=} {v}{vi} {xintiiLtorEq}% -\XINT_expr_defbin_b {expr} {>=} {v}{vi} {xintGtorEq}% -\XINT_expr_defbin_b {flexpr}{>=} {v}{vi} {xintGtorEq}% -\XINT_expr_defbin_b {iiexpr}{>=} {v}{vi} {xintiiGtorEq}% -\XINT_expr_defbin_b {expr} {!=} {v}{vi} {xintNotEq}% -\XINT_expr_defbin_b {flexpr}{!=} {v}{vi} {xintNotEq}% -\XINT_expr_defbin_b {iiexpr}{!=} {v}{vi} {xintiiNotEq}% -\XINT_expr_defbin_b {expr} {//} {vii}{vii}{xintDivFloor}% CHANGED IN 1.2p! -\XINT_expr_defbin_b {flexpr}{//} {vii}{vii}{XINTinFloatDivFloor}% " -\XINT_expr_defbin_b {iiexpr}{//} {vii}{vii}{xintiiDivFloor}% " -\XINT_expr_defbin_b {expr} {/:} {vii}{vii}{xintMod}% " -\XINT_expr_defbin_b {flexpr}{/:} {vii}{vii}{XINTinFloatMod}% " -\XINT_expr_defbin_b {iiexpr}{/:} {vii}{vii}{xintiiMod}% " -\XINT_expr_defbin_b {expr} + {vi}{vi} {xintAdd}% -\XINT_expr_defbin_b {flexpr} + {vi}{vi} {XINTinFloatAdd}% -\XINT_expr_defbin_b {iiexpr} + {vi}{vi} {xintiiAdd}% -\XINT_expr_defbin_b {expr} - {vi}{vi} {xintSub}% -\XINT_expr_defbin_b {flexpr} - {vi}{vi} {XINTinFloatSub}% -\XINT_expr_defbin_b {iiexpr} - {vi}{vi} {xintiiSub}% -\XINT_expr_defbin_b {expr} * {vii}{vii}{xintMul}% -\XINT_expr_defbin_b {flexpr} * {vii}{vii}{XINTinFloatMul}% -\XINT_expr_defbin_b {iiexpr} * {vii}{vii}{xintiiMul}% -\XINT_expr_defbin_b {expr} / {vii}{vii}{xintDiv}% -\XINT_expr_defbin_b {flexpr} / {vii}{vii}{XINTinFloatDiv}% -\XINT_expr_defbin_b {iiexpr} / {vii}{vii}{xintiiDivRound}% CHANGED IN 1.1! -\XINT_expr_defbin_b {expr} ^ {ix}{ix} {xintPow}% -\XINT_expr_defbin_b {flexpr} ^ {ix}{ix} {XINTinFloatPowerH}% -\XINT_expr_defbin_b {iiexpr} ^ {ix}{ix} {xintiiPow}% -\XINT_expr_defbin_b {expr} {..[}{iii}{vi} {xintSeqA::csv}% -\XINT_expr_defbin_b {flexpr}{..[}{iii}{vi} {XINTinFloatSeqA::csv}% -\XINT_expr_defbin_b {iiexpr}{..[}{iii}{vi} {xintiiSeqA::csv}% -\def\XINT_expr_defbin_b #1#2#3#4#5% -{% - \expandafter\XINT_expr_defbin_c - \csname XINT_#1_op_#2\expandafter\endcsname - \csname XINT_#1_until_#2_a\expandafter\endcsname - \csname XINT_#1_until_#2_b\expandafter\endcsname - \csname XINT_#1_op_-#4\expandafter\endcsname - \csname xint_c_#3\expandafter\endcsname - \csname #5\expandafter\endcsname - \csname XINT_expr_precedence_#2\endcsname {#1}{}% -}% -\XINT_expr_defbin_b {expr} {..} {iii}{vi} {xintSeq::csv}% -\XINT_expr_defbin_b {flexpr}{..} {iii}{vi} {xintSeq::csv}% -\XINT_expr_defbin_b {iiexpr}{..} {iii}{vi} {xintiiSeq::csv}% -\XINT_expr_defbin_b {expr} {]..}{iii}{vi} {xintSeqB::csv}% -\XINT_expr_defbin_b {flexpr}{]..}{iii}{vi} {XINTinFloatSeqB::csv}% -\XINT_expr_defbin_b {iiexpr}{]..}{iii}{vi} {xintiiSeqB::csv}% -% \end{macrocode} -% \subsubsection{The ]+, ]\textendash, ]\texorpdfstring{\protect\lowast}{*}, ]/, ]\textasciicircum, +[, \textendash[, \texorpdfstring{\protect\lowast}{*}[, /[, and \textasciicircum[ list -% operators} -% \paragraph{\csh{XINT_expr_binop_inline_b}}\par -% \lverb|This handles acting on comma separated values (no need to bother -% about spaces in this context; expansion in a \csname...\endcsname.| -% \begin{macrocode} -\def\XINT_expr_binop_inline#1% - {\XINT_expr_binop_inline_a{\expandafter\XINT:NEhook:two\expandafter#1}}% -\def\XINT_expr_binop_inline_a - {\expandafter\xint_gobble_i\romannumeral`&&@\XINT_expr_binop_inline_b }% -\def\XINT_expr_binop_inline_b #1#2,{\XINT_expr_binop_inline_c #2,{#1}}% -\def\XINT_expr_binop_inline_c #1{% - \if ,#1\xint_dothis\XINT_expr_binop_inline_e\fi - \if ^#1\xint_dothis\XINT_expr_binop_inline_end\fi - \xint_orthat\XINT_expr_binop_inline_d #1}% -\def\XINT_expr_binop_inline_d #1,#2{,#2{#1}\XINT_expr_binop_inline_b {#2}}% -\def\XINT_expr_binop_inline_e #1,#2{,\XINT_expr_binop_inline_b {#2}}% -\def\XINT_expr_binop_inline_end #1,#2{}% -\def\XINT_expr_deflistopr_c #1#2#3#4#5#6#7#8% -{% - \def #1##1% \XINT_expr_op_<op> ou flexpr ou iiexpr - {% keep value, get next number and operator, then do until - \expandafter #2\expandafter ##1% - \romannumeral`&&@\expandafter\XINT_expr_getnext }% - \def #2##1##2% \XINT_expr_until_<op>_a ou flexpr ou iiexpr - {\xint_UDsignfork ##2{\expandafter #2\expandafter ##1\romannumeral`&&@#4}% - -{#3##1##2}% - \krof }% - \def #3##1##2##3##4% \XINT_expr_until_<op>_b ou flexpr ou iiexpr - {% either execute next operation now, or first do next (possibly unary) - \ifnum ##2>#7% - \xint_afterfi {\expandafter #2\expandafter ##1\romannumeral`&&@% - \csname XINT_#8_op_##3\endcsname {##4}}% - \else \xint_afterfi {\expandafter ##2\expandafter ##3% - \csname .=\expandafter\XINT_expr_binop_inline\expandafter - {\expandafter#6\expandafter\xint_exchangetwo_keepbraces\expandafter - {\expandafter\XINT_expr_unlock\expandafter ##4\expandafter}\expandafter}% - \romannumeral`&&@\XINT_expr_unlock ##1,^,\endcsname }% - \fi }% - \let #7#5% -}% -\def\XINT_expr_deflistopr_b #1#2#3#4% -{% - \expandafter\XINT_expr_deflistopr_c - \csname XINT_#1_op_#2\expandafter\endcsname - \csname XINT_#1_until_#2_a\expandafter\endcsname - \csname XINT_#1_until_#2_b\expandafter\endcsname - \csname XINT_#1_op_-#3\expandafter\endcsname - \csname xint_c_#3\expandafter\endcsname - \csname #4\expandafter\endcsname - \csname XINT_expr_precedence_#2\endcsname {#1}% -}% -% \end{macrocode} -% \lverb|This is for [x..y]*z syntax etc.... Attention that with 1.2d, -% precedence level of ^ raised to ix to make room for ***.| -% \begin{macrocode} -\XINT_expr_deflistopr_b {expr} {a+}{vi} {xintAdd}% -\XINT_expr_deflistopr_b {expr} {a-}{vi} {xintSub}% -\XINT_expr_deflistopr_b {expr} {a*}{vii}{xintMul}% -\XINT_expr_deflistopr_b {expr} {a/}{vii}{xintDiv}% -\XINT_expr_deflistopr_b {expr} {a^}{ix} {xintPow}% -\XINT_expr_deflistopr_b {iiexpr}{a+}{vi} {xintiiAdd}% -\XINT_expr_deflistopr_b {iiexpr}{a-}{vi} {xintiiSub}% -\XINT_expr_deflistopr_b {iiexpr}{a*}{vii}{xintiiMul}% -\XINT_expr_deflistopr_b {iiexpr}{a/}{vii}{xintiiDivRound}% -\XINT_expr_deflistopr_b {iiexpr}{a^}{ix} {xintiiPow}% -\XINT_expr_deflistopr_b {flexpr}{a+}{vi} {XINTinFloatAdd}% -\XINT_expr_deflistopr_b {flexpr}{a-}{vi} {XINTinFloatSub}% -\XINT_expr_deflistopr_b {flexpr}{a*}{vii}{XINTinFloatMul}% -\XINT_expr_deflistopr_b {flexpr}{a/}{vii}{XINTinFloatDiv}% -\XINT_expr_deflistopr_b {flexpr}{a^}{ix} {XINTinFloatPowerH}% -\def\XINT_expr_deflistopl_c #1#2#3#4#5#6#7% -{% - \def #1##1{\expandafter#2\expandafter##1\romannumeral`&&@% - \expandafter #3\romannumeral`&&@\XINT_expr_getnext }% - \def #2##1##2##3##4% - {% either execute next operation now, or first do next (possibly unary) - \ifnum ##2>#6% - \xint_afterfi {\expandafter #2\expandafter ##1\romannumeral`&&@% - \csname XINT_#7_op_##3\endcsname {##4}}% - \else \xint_afterfi {\expandafter ##2\expandafter ##3% - \csname .=\expandafter\XINT_expr_binop_inline\expandafter - {\expandafter#5\expandafter - {\expandafter\XINT_expr_unlock\expandafter ##1\expandafter}\expandafter}% - \romannumeral`&&@\XINT_expr_unlock ##4,^,\endcsname }% - \fi }% - \let #6#4% -}% -\def\XINT_expr_deflistopl_b #1#2#3#4% -{% - \expandafter\XINT_expr_deflistopl_c - \csname XINT_#1_op_#2\expandafter\endcsname - \csname XINT_#1_until_#2\expandafter\endcsname - \csname XINT_#1_until_)_a\expandafter\endcsname - \csname xint_c_#3\expandafter\endcsname - \csname #4\expandafter\endcsname - \csname XINT_expr_precedence_#2\endcsname {#1}% -}% -% \end{macrocode} -% \lverb|This is for z*[x..y] syntax etc...| -% \begin{macrocode} -\XINT_expr_deflistopl_b {expr} {+[}{vi} {xintAdd}% -\XINT_expr_deflistopl_b {expr} {-[}{vi} {xintSub}% -\XINT_expr_deflistopl_b {expr} {*[}{vii}{xintMul}% -\XINT_expr_deflistopl_b {expr} {/[}{vii}{xintDiv}% -\XINT_expr_deflistopl_b {expr} {^[}{ix} {xintPow}% -\XINT_expr_deflistopl_b {iiexpr}{+[}{vi} {xintiiAdd}% -\XINT_expr_deflistopl_b {iiexpr}{-[}{vi} {xintiiSub}% -\XINT_expr_deflistopl_b {iiexpr}{*[}{vii}{xintiiMul}% -\XINT_expr_deflistopl_b {iiexpr}{/[}{vii}{xintiiDivRound}% -\XINT_expr_deflistopl_b {iiexpr}{^[}{ix} {xintiiPow}% -\XINT_expr_deflistopl_b {flexpr}{+[}{vi} {XINTinFloatAdd}% -\XINT_expr_deflistopl_b {flexpr}{-[}{vi} {XINTinFloatSub}% -\XINT_expr_deflistopl_b {flexpr}{*[}{vii}{XINTinFloatMul}% -\XINT_expr_deflistopl_b {flexpr}{/[}{vii}{XINTinFloatDiv}% -\XINT_expr_deflistopl_b {flexpr}{^[}{ix} {XINTinFloatPowerH}% -% \end{macrocode} -% \subsubsection{The \textquotesingle and\textquotesingle, \textquotesingle -% or\textquotesingle, \textquotesingle xor\textquotesingle, and -% \textquotesingle mod\textquotesingle\ as infix operator words} -% \begin{macrocode} -\xintFor #1 in {and,or,xor,mod} \do {% - \expandafter\def\csname XINT_expr_itself_#1\endcsname {#1}}% + \csname XINT_expr_precedence_#2\endcsname + {#1}{\romannumeral`&&@\XINT:NEhook:f:one:from:two}% + \expandafter % done 3 times but well + \let\csname XINT_expr_precedence_#2\expandafter\endcsname + \csname xint_c_#3\endcsname +}% +\catcode`& 12 +\XINT_expr_defbin_b {expr} {||} {vi}{xii} {xintOR}% +\XINT_expr_defbin_b {flexpr}{||} {vi}{xii} {xintOR}% +\XINT_expr_defbin_b {iiexpr}{||} {vi}{xii} {xintOR}% +\XINT_expr_defbin_b {expr} {&&} {viii}{xii} {xintAND}% +\XINT_expr_defbin_b {flexpr}{&&} {viii}{xii} {xintAND}% +\XINT_expr_defbin_b {iiexpr}{&&} {viii}{xii} {xintAND}% +\XINT_expr_defbin_b {expr} {xor}{vi}{xii} {xintXOR}% +\XINT_expr_defbin_b {flexpr}{xor}{vi}{xii} {xintXOR}% +\XINT_expr_defbin_b {iiexpr}{xor}{vi}{xii} {xintXOR}% +\XINT_expr_defbin_b {expr} < {x}{xii} {xintLt}% +\XINT_expr_defbin_b {flexpr} < {x}{xii} {xintLt}% +\XINT_expr_defbin_b {iiexpr} < {x}{xii} {xintiiLt}% +\XINT_expr_defbin_b {expr} > {x}{xii} {xintGt}% +\XINT_expr_defbin_b {flexpr} > {x}{xii} {xintGt}% +\XINT_expr_defbin_b {iiexpr} > {x}{xii} {xintiiGt}% +\XINT_expr_defbin_b {expr} {==} {x}{xii} {xintEq}% +\XINT_expr_defbin_b {flexpr}{==} {x}{xii} {xintEq}% +\XINT_expr_defbin_b {iiexpr}{==} {x}{xii} {xintiiEq}% +\XINT_expr_defbin_b {expr} {<=} {x}{xii} {xintLtorEq}% +\XINT_expr_defbin_b {flexpr}{<=} {x}{xii} {xintLtorEq}% +\XINT_expr_defbin_b {iiexpr}{<=} {x}{xii} {xintiiLtorEq}% +\XINT_expr_defbin_b {expr} {>=} {x}{xii} {xintGtorEq}% +\XINT_expr_defbin_b {flexpr}{>=} {x}{xii} {xintGtorEq}% +\XINT_expr_defbin_b {iiexpr}{>=} {x}{xii} {xintiiGtorEq}% +\XINT_expr_defbin_b {expr} {!=} {x}{xii} {xintNotEq}% +\XINT_expr_defbin_b {flexpr}{!=} {x}{xii} {xintNotEq}% +\XINT_expr_defbin_b {iiexpr}{!=} {x}{xii} {xintiiNotEq}% +\XINT_expr_defbin_b {expr} {//} {xiv}{xiv}{xintDivFloor}% CHANGED IN 1.2p! +\XINT_expr_defbin_b {flexpr}{//} {xiv}{xiv}{XINTinFloatDivFloor}% " +\XINT_expr_defbin_b {iiexpr}{//} {xiv}{xiv}{xintiiDivFloor}% " +\XINT_expr_defbin_b {expr} {/:} {xiv}{xiv}{xintMod}% " +\XINT_expr_defbin_b {flexpr}{/:} {xiv}{xiv}{XINTinFloatMod}% " +\XINT_expr_defbin_b {iiexpr}{/:} {xiv}{xiv}{xintiiMod}% " +\XINT_expr_defbin_b {expr} + {xii}{xii} {xintAdd}% +\XINT_expr_defbin_b {flexpr} + {xii}{xii} {XINTinFloatAdd}% +\XINT_expr_defbin_b {iiexpr} + {xii}{xii} {xintiiAdd}% +\XINT_expr_defbin_b {expr} - {xii}{xii} {xintSub}% +\XINT_expr_defbin_b {flexpr} - {xii}{xii} {XINTinFloatSub}% +\XINT_expr_defbin_b {iiexpr} - {xii}{xii} {xintiiSub}% +\XINT_expr_defbin_b {expr} * {xiv}{xiv}{xintMul}% +\XINT_expr_defbin_b {flexpr} * {xiv}{xiv}{XINTinFloatMul}% +\XINT_expr_defbin_b {iiexpr} * {xiv}{xiv}{xintiiMul}% +\XINT_expr_defbin_b {expr} / {xiv}{xiv}{xintDiv}% +\XINT_expr_defbin_b {flexpr} / {xiv}{xiv}{XINTinFloatDiv}% +\XINT_expr_defbin_b {iiexpr} / {xiv}{xiv}{xintiiDivRound}% CHANGED IN 1.1! +\XINT_expr_defbin_b {expr} ^ {xviii}{xviii} {xintPow}% +\XINT_expr_defbin_b {flexpr} ^ {xviii}{xviii} {XINTinFloatPowerH}% +\XINT_expr_defbin_b {iiexpr} ^ {xviii}{xviii} {xintiiPow}% +\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 + \csname XINT_expr_precedence_&&\endcsname \expandafter\let\csname XINT_expr_precedence_or\expandafter\endcsname - \csname XINT_expr_precedence_|\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 {% +\xintFor #1 in {expr, flexpr, iiexpr} \do +{% \expandafter\let\csname XINT_#1_op_and\expandafter\endcsname - \csname XINT_#1_op_&\endcsname + \csname XINT_#1_op_&&\endcsname \expandafter\let\csname XINT_#1_op_or\expandafter\endcsname - \csname XINT_#1_op_|\endcsname + \csname XINT_#1_op_||\endcsname \expandafter\let\csname XINT_#1_op_mod\expandafter\endcsname \csname XINT_#1_op_/:\endcsname }% -% \end{macrocode} -% \subsubsection{The \textbar\textbar, -% \&\&, \texorpdfstring{\protect\lowast\protect\lowast, -% \protect\lowast\protect\lowast[, ]\protect\lowast\protect\lowast}{**, **[, ]**}{} operators as synonyms} -% \begin{macrocode} -\expandafter\let\csname XINT_expr_precedence_==\expandafter\endcsname - \csname XINT_expr_precedence_=\endcsname -\expandafter\let\csname XINT_expr_precedence_&\string&\expandafter\endcsname - \csname XINT_expr_precedence_&\endcsname -\expandafter\let\csname XINT_expr_precedence_||\expandafter\endcsname - \csname XINT_expr_precedence_|\endcsname +\expandafter\let\csname XINT_expr_precedence_=\expandafter\endcsname + \csname XINT_expr_precedence_==\endcsname +\expandafter\let\csname XINT_expr_precedence_&\expandafter\endcsname + \csname XINT_expr_precedence_&&\endcsname +\expandafter\let\csname XINT_expr_precedence_|\expandafter\endcsname + \csname XINT_expr_precedence_||\endcsname \expandafter\let\csname XINT_expr_precedence_**\expandafter\endcsname \csname XINT_expr_precedence_^\endcsname -\expandafter\let\csname XINT_expr_precedence_a**\expandafter\endcsname - \csname XINT_expr_precedence_a^\endcsname -\expandafter\let\csname XINT_expr_precedence_**[\expandafter\endcsname - \csname XINT_expr_precedence_^[\endcsname -\xintFor #1 in {expr, flexpr, iiexpr} \do {% - \expandafter\let\csname XINT_#1_op_==\expandafter\endcsname - \csname XINT_#1_op_=\endcsname - \expandafter\let\csname XINT_#1_op_&\string&\expandafter\endcsname - \csname XINT_#1_op_&\endcsname - \expandafter\let\csname XINT_#1_op_||\expandafter\endcsname - \csname XINT_#1_op_|\endcsname +\xintFor #1 in {expr, flexpr, iiexpr} \do +{% + \expandafter\let\csname XINT_#1_op_=\expandafter\endcsname + \csname XINT_#1_op_==\endcsname + \expandafter\let\csname XINT_#1_op_&\expandafter\endcsname + \csname XINT_#1_op_&&\endcsname + \expandafter\let\csname XINT_#1_op_|\expandafter\endcsname + \csname XINT_#1_op_||\endcsname \expandafter\let\csname XINT_#1_op_**\expandafter\endcsname \csname XINT_#1_op_^\endcsname - \expandafter\let\csname XINT_#1_op_a**\expandafter\endcsname - \csname XINT_#1_op_a^\endcsname - \expandafter\let\csname XINT_#1_op_**[\expandafter\endcsname - \csname XINT_#1_op_^[\endcsname +}% +\catcode`& 7 +% \end{macrocode} +% \subsubsection{.., ..[, and ].. as infix operators} +% \lverb|1.2d needed some room between /, * and ^. Hence precedence for ^ +% is now at 9| +% \begin{macrocode} +\def\XINT_expr_defbin_b #1#2#3#4% +{% + \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_-#4\expandafter\endcsname + \expandafter{\expandafter}% + \csname XINT_expr_precedence_#2\endcsname + {#1}{\expandafter}% REVOIR + \expandafter + \let\csname XINT_expr_precedence_#2\expandafter\endcsname + \csname xint_c_#3\endcsname +}% +\XINT_expr_defbin_b {expr} {..[}{vi}{xii}% +\XINT_expr_defbin_b {flexpr}{..[}{vi}{xii}% +\XINT_expr_defbin_b {iiexpr}{..[}{vi}{xii}% +\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#3\romannumeral`&&@\XINT_expr_getnext + }% + \def #2##1##2##3##4% \XINT_expr_exec_<op> + {% + \expandafter##2\expandafter##3\expanded{{#9#6##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>#7% + \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#6% +{% + \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_-#4\expandafter\endcsname + \csname #5\expandafter\endcsname + \csname XINT_expr_precedence_#2\endcsname {#1}#6% + \expandafter\let + \csname XINT_expr_precedence_#2\expandafter\endcsname + \csname xint_c_#3\endcsname +}% +\XINT_expr_defbin_b {expr} {..} {vi}{xii}{xintSeq:tl:x}\XINT:NEhook:x:one:from:two +\XINT_expr_defbin_b {flexpr}{..} {vi}{xii}{xintSeq:tl:x}\XINT:NEhook:x:one:from:two +\XINT_expr_defbin_b {iiexpr}{..} {vi}{xii}{xintiiSeq:tl:x}\XINT:NEhook:x:one:from:two +\XINT_expr_defbin_b {expr} {]..}{vi}{xii}{xintSeqB:tl:x}\XINT:NEhook:x:one:from:twoandone +\XINT_expr_defbin_b {flexpr}{]..}{vi}{xii}{xintSeqB:tl:x}\XINT:NEhook:x:one:from:twoandone +\XINT_expr_defbin_b {iiexpr}{]..}{vi}{xii}{xintiiSeqB:tl:x}\XINT:NEhook:x:one:from:twoandone +% \end{macrocode} +% \subsubsection{Support macros for .., ..[ and ]..} +% +% +%\paragraph{\csh{xintSeq:tl:x}} +%\lverb|Commence par remplacer a par ceil(a) et b par floor(b) et renvoie +% ensuite les entiers entre les deux, possiblement en décroissant, et +% extrémités comprises. Si a=b est non entier en obtient donc ceil(a) et +% floor(a). Ne renvoie jamais une liste vide. +% +% Note: le a..b dans \xintfloatexpr utilise cette routine.| +% \begin{macrocode} +\def\xintSeq: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} +% \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.| +% +% \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}} +%\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.| +% \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} -% \subsection{Macros for list selectors: [list][N], [list][:b], [list][a:], [list][a:b]} +% \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 [\,] both as a container and a Python slicer} +% Refactored at |1.4| +% +% \lverb|The architecture allows to implement separately a «left» and a «right» +% precedence and this is crucial.| % \localtableofcontents % -% \lverb|Python slicing was first implemented for 1.1 (27 octobre 2014). But -% it used \xintCSVtoList and \xintListWithSep{,} to convert back and forth to -% token lists for use of \xintKeep, \xintTrim, \xintNthElt. Not very -% efficient! Also [list][a:b] was Python like but not [list][N] which counted -% items starting at one, and returned the length for N=0. % -% Release 1.2g changed this so [list][N] now counts starting at zero and -% len(list) computes the number of items. Also 1.2g had its own f-expandable -% macros handling directly the comma separated lists. They are located into -% $xinttoolsnameimp.sty. +% \subsubsection{[...] as «oneple» constructor} % -% 1.2j improved the $xinttoolsnameimp.sty macros and furthermore it made the -% Python slicing in expressions a bit more efficient still by exploiting in -% some cases that expansion happens in \csname...\endcsname and does not have -% to be f-expandable. But the f-expandable variants must be kept for use by -% \xintNewExpr and \xintdeffunc. +% \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. % | % \begin{macrocode} +\def\XINT_expr_itself_obracket{obracket}% +\catcode`] 11 \catcode`[ 11 \def\XINT_tmpa #1#2#3#4#5#6% {% - \def #1##1% \XINT_expr_op_][ + \def #1##1% {% - \expandafter #2\expandafter ##1\romannumeral`&&@\XINT_expr_getnext + \expandafter#3\romannumeral`&&@\XINT_expr_getnext }% - \def #2##1##2% \XINT_expr_until_][_a - {\xint_UDsignfork - ##2{\expandafter #2\expandafter ##1\romannumeral`&&@#4}% - -{#3##1##2}% - \krof }% - \def #3##1##2##3##4% \XINT_expr_until_][_b + \def #2##1% op_] + {% + \expanded{\unexpanded{\XINT_expr_put_op_first{{##1}}}\expandafter}% + \romannumeral`&&@\XINT_expr_getop + }% + \def #3##1% until_cbracket_a {% - \ifnum ##2>#5% - \xint_afterfi {\expandafter #2\expandafter ##1\romannumeral`&&@% - \csname XINT_#6_op_##3\endcsname {##4}}% + \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 - \xint_afterfi - {\expandafter ##2\expandafter ##3\csname - .=\expandafter\xintListSel:x:csv % will be \xintListSel:f:csv in \xintNewExpr output - \romannumeral`&&@\XINT_expr_unlock ##4;% selector - \XINT_expr_unlock ##1;\endcsname % unlock already pre-positioned for \xintNewExpr - }% + \expandafter #4% + \romannumeral`&&@\csname XINT_#6_op_##2\expandafter\endcsname + \fi + }% +}% +\xintFor #1 in {expr,flexpr,iiexpr} \do {% + \expandafter\XINT_tmpa + \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}% +}% +\def\XINT_expr_missing_] + {\XINT_expandableerror{Ooops, looks like we are missing a ] here. Goodbye!}% + \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} +% \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.| +% \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% \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 #5\xint_c_ii }% +\let\XINT_expr_precedence_[ \xint_c_xx \xintFor #1 in {expr,flexpr,iiexpr} \do {% \expandafter\XINT_tmpa - \csname XINT_#1_op_][\expandafter\endcsname - \csname XINT_#1_until_][_a\expandafter\endcsname - \csname XINT_#1_until_][_b\expandafter\endcsname - \csname XINT_#1_op_-vi\expandafter\endcsname - \csname XINT_expr_precedence_][\endcsname {#1}% + \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}% }% +\catcode`] 12 \catcode`[ 12 +% \end{macrocode} +% \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.| +% \begin{macrocode} \def\XINT_tmpa #1#2#3#4#5#6% {% \def #1##1% \XINT_expr_op_: {% - \expandafter #2\expandafter ##1\romannumeral`&&@\XINT_expr_getnext + \expanded{\unexpanded{#2{##1}}\expandafter}% + \romannumeral`&&@\expandafter#3\romannumeral`&&@\XINT_expr_getnext }% - \def #2##1##2% \XINT_expr_until_:_a + \def #2##1##2##3##4% \XINT_expr_exec_: + {% + ##2##3{:##1{0};##4:_}% + }% + \def #3##1% \XINT_expr_check-_: {\xint_UDsignfork - ##2{\expandafter #2\expandafter ##1\romannumeral`&&@#4}% - -{#3##1##2}% - \krof }% - \def #3##1##2##3##4% \XINT_expr_until_:_b + ##1{\expandafter#4\romannumeral`&&@#5}% + -{#4##1}% + \krof + }% + \def #4##1##2% \XINT_expr_checkp_: {% - \ifnum ##2>#5% - \xint_afterfi {\expandafter #2\expandafter ##1\romannumeral`&&@% - \csname XINT_#6_op_##3\endcsname {##4}}% + \ifnum ##1>\XINT_expr_precedence_: + \expandafter #4\romannumeral`&&@% + \csname XINT_#6_op_##2\expandafter\endcsname \else - \xint_afterfi - {\expandafter ##2\expandafter ##3\csname - .=:\XINT:NEhook:one\xintNum{\XINT_expr_unlock ##1};% - \XINT:NEhook:one\xintNum{\XINT_expr_unlock ##4}% - \endcsname - }% + \expandafter##1\expandafter##2% \fi }% - \let #5\xint_c_iii }% +\let\XINT_expr_precedence_: \xint_c_vi \xintFor #1 in {expr,flexpr,iiexpr} \do {% \expandafter\XINT_tmpa \csname XINT_#1_op_:\expandafter\endcsname - \csname XINT_#1_until_:_a\expandafter\endcsname - \csname XINT_#1_until_:_b\expandafter\endcsname - \csname XINT_#1_op_-vi\expandafter\endcsname - \csname XINT_expr_precedence_:\endcsname {#1}% -}% -\catcode`[ 11 \catcode`] 11 -\let\XINT_expr_precedence_:] \xint_c_iii -\def\XINT_expr_op_:] #1% -{% - \expandafter\xint_c_i\expandafter )% - \csname .=]\XINT:NEhook:one\xintNum{\XINT_expr_unlock #1}\endcsname + \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}% }% -\let\XINT_flexpr_op_:] \XINT_expr_op_:] -\let\XINT_iiexpr_op_:] \XINT_expr_op_:] -\let\XINT_expr_precedence_][: \xint_c_iii % \end{macrocode} -% \lverb|At the end of the replacement text of \XINT_expr_op_][:, the : after -% index 0 must be catcode 12, else will be mistaken for the start of variable -% by expression parser (as <digits><variable> is allowed by the syntax and does -% tacit multiplication).| -% \begin{macrocode} -\edef\XINT_expr_op_][: #1{\xint_c_ii\noexpand\XINT_expr_itself_][#10\string :}% -\let\XINT_flexpr_op_][: \XINT_expr_op_][: -\let\XINT_iiexpr_op_][: \XINT_expr_op_][: -\catcode`[ 12 \catcode`] 12 -% \end{macrocode} -% \subsubsection{\csh{xintListSel:x:csv}} -% \lverb|1.2j. Because there is \xintKeep:x:csv which is faster than -% \xintKeep:f:csv.| +% \subsubsection{Macro layer implementing indexing and slicing} +% \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. +% | % \begin{macrocode} -\def\xintListSel:x:csv #1% +\def\XINT_ListSel_deeper #1% {% - \if ]\noexpand#1\xint_dothis\XINT_listsel:_s\fi - \if :\noexpand#1\xint_dothis\XINT_listxsel:_:\fi - \xint_orthat {\XINT_listsel:_nth #1}% + \if :#1\xint_dothis\XINT_ListSel_slice_next\fi + \xint_orthat {\XINT_ListSel_extract_next {#1}}% }% -\def\XINT_listsel:_s #1#2;#3;% +\def\XINT_ListSel_slice_next #1(% {% - \if-#1\expandafter\xintKeep:f:csv\else\expandafter\xintTrim:f:csv\fi - {#1#2}{#3}% + \xintApply{\XINT_ListSel_recurse{:#1}}% }% -\def\XINT_listsel:_nth #1;#2;{\xintNthEltPy:f:csv {\xintNum{#1}}{#2}}% -% \end{macrocode} -% \lverb|\XINT_listsel:_nth and \XINT_listsel:_s located in \xintListSel:f:csv.| -% \begin{macrocode} -\def\XINT_listxsel:_: #1#2;#3#4;% +\def\XINT_ListSel_extract_next #1(% {% - \xint_UDsignsfork - #1#3\XINT_listxsel:_N:N - #1-\XINT_listxsel:_N:P - -#3\XINT_listxsel:_P:N - --\XINT_listxsel:_P:P - \krof #1#2;#3#4;% + \xintApplyUnbraced{\XINT_ListSel_recurse{#1}}% }% -\def\XINT_listxsel:_P:P #1;#2;#3;% +\def\XINT_ListSel_recurse #1#2% {% - \unless\ifnum #1<#2 \expandafter\xint_gobble_iii\fi - \xintKeep:x:csv{#2-#1}{\xintTrim:f:csv{#1}{#3}}% + \XINT_ListSel_check #2__#1({#2}\expandafter\empty\empty }% -\def\XINT_listxsel:_N:N #1;#2;#3;% +\def\XINT_ListSel_check{\expandafter\XINT_ListSel_check_a \string}% +\def\XINT_ListSel_check_a #1% {% - \expandafter\XINT_listxsel:_N:N_a - \the\numexpr #2-#1\expandafter;\the\numexpr#1+\xintLength:f:csv{#3};#3;% + \if #1\bgroup\xint_dothis\XINT_ListSel_check_is_ok\fi + \xint_orthat\XINT_ListSel_check_leaf }% -\def\XINT_listxsel:_N:N_a #1;#2;#3;% +\def\XINT_ListSel_check_leaf #1\expandafter{\expandafter}% +\def\XINT_ListSel_check_is_ok {% - \unless\ifnum #1>\xint_c_ \expandafter\xint_gobble_iii\fi - \xintKeep:x:csv{#1}{\xintTrim:f:csv{\ifnum#2<\xint_c_\xint_c_\else#2\fi}{#3}}% + \expandafter\XINT_ListSel_check_is_ok_a\expandafter{\string}% }% -\def\XINT_listxsel:_N:P #1;#2;#3;{\expandafter\XINT_listxsel:_N:P_a - \the\numexpr #1+\xintLength:f:csv{#3};#2;#3;}% -\def\XINT_listxsel:_N:P_a #1#2;% - {\if -#1\expandafter\XINT_listxsel:_O:P\fi\XINT_listxsel:_P:P #1#2;}% -\def\XINT_listxsel:_O:P\XINT_listxsel:_P:P #1;{\XINT_listxsel:_P:P 0;}% -\def\XINT_listxsel:_P:N #1;#2;#3;{\expandafter\XINT_listxsel:_P:N_a - \the\numexpr #2+\xintLength:f:csv{#3};#1;#3;}% -\def\XINT_listxsel:_P:N_a #1#2;#3;% - {\if -#1\expandafter\XINT_listxsel:_P:O\fi\XINT_listxsel:_P:P #3;#1#2;}% -\def\XINT_listxsel:_P:O\XINT_listxsel:_P:P #1;#2;{\XINT_listxsel:_P:P #1;0;}% -% \end{macrocode} -% \subsubsection{\csh{xintListSel:f:csv}} -% \lverb|1.2g. Since 1.2j this is needed only for \xintNewExpr and user -% defined functions. Some extras compared to \xintListSel:x:csv because things -% may not yet have been expanded in the \xintNewExpr context.| -% \begin{macrocode} -\def\xintListSel:f:csv #1% +\def\XINT_ListSel_check_is_ok_a #1__#2% {% - \if ]\noexpand#1\xint_dothis{\expandafter\XINT_listsel:_s\romannumeral`&&@}\fi - \if :\noexpand#1\xint_dothis{\XINT_listsel:_:}\fi - \xint_orthat {\XINT_listsel:_nth #1}% + \if :#2\xint_dothis{\XINT_ListSel_slice}\fi + \xint_orthat {\XINT_ListSel_nthone {#2}}% }% -\def\XINT_listsel:_: #1;#2;% +\def\XINT_ListSel_top #1#2% {% - \expandafter\XINT_listsel:_:a - \the\numexpr #1\expandafter;\the\numexpr #2\expandafter;\romannumeral`&&@% + \if _\noexpand#2% + \expandafter\XINT_ListSel_top_one_or_none\string#1.\else + \expandafter\XINT_ListSel_top_at_least_two\fi }% -\def\XINT_listsel:_:a #1#2;#3#4;% +\def\XINT_ListSel_top_at_least_two #1__{\XINT_ListSel_top_ople}% +\def\XINT_ListSel_top_one_or_none #1% {% - \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;% + \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:_P:P #1;#2;#3;% +\def\XINT_ListSel_top_nil #1\expandafter#2\expandafter{\fi\expandafter}% +\def\XINT_ListSel_top_nutple {% - \unless\ifnum #1<#2 \xint_afterfi{\expandafter\space\xint_gobble_iii}\fi - \xintKeep:f:csv{#2-#1}{\xintTrim:f:csv{#1}{#3}}% + \expandafter\XINT_ListSel_top_nutple_a\expandafter{\string}% }% -\def\XINT_listsel:_N:N #1;#2;#3;% +\def\XINT_ListSel_top_nutple_a #1_#2#3(#4% {% - \unless\ifnum #1<#2 \expandafter\XINT_listsel:_N:N_abort\fi - \expandafter\XINT_listsel:_N:N_a - \the\numexpr#1+\xintLength:f:csv{#3}\expandafter;\the\numexpr#2-#1;#3;% + \fi\if :#2\xint_dothis{{\XINT_ListSel_slice #3(#4}}\fi + \xint_orthat {\XINT_ListSel_nthone {#2}#3(#4}% }% -\def\XINT_listsel:_N:N_abort #1;#2;#3;{ }% -\def\XINT_listsel:_N:N_a #1;#2;#3;% +\def\XINT_ListSel_top_number #1_{\fi\XINT_ListSel_top_ople}% +\def\XINT_ListSel_top_ople #1% {% - \xintKeep:f:csv{#2}{\xintTrim:f:csv{\ifnum#1<\xint_c_\xint_c_\else#1\fi}{#3}}% + \if :#1\xint_dothis\XINT_ListSel_slice\fi + \xint_orthat {\XINT_ListSel_nthone {#1}}% }% -\def\XINT_listsel:_N:P #1;#2;#3;{\expandafter\XINT_listsel:_N:P_a - \the\numexpr #1+\xintLength:f:csv{#3};#2;#3;}% -\def\XINT_listsel:_N:P_a #1#2;% - {\if -#1\expandafter\XINT_listsel:_O:P\fi\XINT_listsel:_P:P #1#2;}% -\def\XINT_listsel:_O:P\XINT_listsel:_P:P #1;{\XINT_listsel:_P:P 0;}% -\def\XINT_listsel:_P:N #1;#2;#3;{\expandafter\XINT_listsel:_P:N_a - \the\numexpr #2+\xintLength:f:csv{#3};#1;#3;}% -\def\XINT_listsel:_P:N_a #1#2;#3;% - {\if -#1\expandafter\XINT_listsel:_P:O\fi\XINT_listsel:_P:P #3;#1#2;}% -\def\XINT_listsel:_P:O\XINT_listsel:_P:P #1;#2;{\XINT_listsel:_P:P #1;0;}% -% \end{macrocode} -% \subsubsection{\csh{xintKeep:x:csv}} -% \lverb|1.2j. This macro is used only with positive first argument. -% | -% \begin{macrocode} -\def\xintKeep:x:csv #1#2% +\def\XINT_ListSel_slice #1% {% - \expandafter\xint_gobble_i - \romannumeral0\expandafter\XINT_keep:x:csv_pos - \the\numexpr #1\expandafter.\expandafter{\romannumeral`&&@#2}% + \expandafter\XINT_ListSel_slice_a \expandafter{\romannumeral0\xintnum{#1}}% }% -\def\XINT_keep:x:csv_pos #1.#2% +\def\XINT_ListSel_slice_a #1#2;#3#4% {% - \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 + \if _#4\expandafter\XINT_ListSel_s_b + \else\expandafter\XINT_ListSel_slice_b\fi + #1;#3% }% -\def\XINT_keep:x:csv_loop #1% +\def\XINT_ListSel_s_b #1#2;#3#4% {% - \xint_gob_til_minus#1\XINT_keep:x:csv_finish-% - \XINT_keep:x:csv_loop_pickeight #1% + \if \expandafter\XINT_ListSel_s_last\fi + \XINT_ListSel_s_c #1{#1#2}{#4}% }% -\def\XINT_keep:x:csv_loop_pickeight #1.#2,#3,#4,#5,#6,#7,#8,#9,% +\def\XINT_ListSel_s_last\XINT_ListSel_s_c #1#2#3(#4% {% - ,#2,#3,#4,#5,#6,#7,#8,#9% - \expandafter\XINT_keep:x:csv_loop\the\numexpr#1-\xint_c_viii.% + \if-#1\expandafter\xintKeep\else\expandafter\xintTrim\fi {#2}{#4}% }% -\def\XINT_keep:x:csv_finish-\XINT_keep:x:csv_loop_pickeight -#1.% +\def\XINT_ListSel_s_c #1#2#3(#4% {% - \csname XINT_keep:x:csv_finish#1\endcsname + \expandafter\XINT_ListSel_deeper + \expanded{\unexpanded{#3}(\expandafter}\expandafter{% + \romannumeral0% + \if-#1\expandafter\xintkeep\else\expandafter\xinttrim\fi {#2}{#4}}% }% -\expandafter\def\csname XINT_keep:x:csv_finish1\endcsname - #1,#2,#3,#4,#5,#6,#7,{,#1,#2,#3,#4,#5,#6,#7\xint_Bye}% -\expandafter\def\csname XINT_keep:x:csv_finish2\endcsname - #1,#2,#3,#4,#5,#6,{,#1,#2,#3,#4,#5,#6\xint_Bye}% -\expandafter\def\csname XINT_keep:x:csv_finish3\endcsname - #1,#2,#3,#4,#5,{,#1,#2,#3,#4,#5\xint_Bye}% -\expandafter\def\csname XINT_keep:x:csv_finish4\endcsname - #1,#2,#3,#4,{,#1,#2,#3,#4\xint_Bye}% -\expandafter\def\csname XINT_keep:x:csv_finish5\endcsname - #1,#2,#3,{,#1,#2,#3\xint_Bye}% -\expandafter\def\csname XINT_keep:x:csv_finish6\endcsname - #1,#2,{,#1,#2\xint_Bye}% -\expandafter\def\csname XINT_keep:x:csv_finish7\endcsname - #1,{,#1\xint_Bye}% -\expandafter\let\csname XINT_keep:x:csv_finish8\endcsname\xint_Bye % \end{macrocode} -% \subsubsection{\cshnolabel{xintKeep:f:csv}} -% \changed{1.2g}{} moved to \xinttoolsnameimp. -% \subsubsection{\cshnolabel{xintTrim:f:csv}} -% \changed{1.2g}{} moved to \xinttoolsnameimp. -% \subsubsection{\cshnolabel{xintNthEltPy:f:csv}} -% \changed{1.2g}{} moved to \xinttoolsnameimp. -% \subsubsection{\cshnolabel{xintLength:f:csv}} -% \changed{1.2g}{} moved to \xinttoolsnameimp. -% \subsubsection{\cshnolabel{xintReverse:f:csv}} -% \changed{1.2g}{} moved to \xinttoolsnameimp. -% -% \subsection{Macros for a..b list generation} -% \localtableofcontents +% \lverb|& % -% \lverb|Ne produit que des listes d'entiers inférieurs à la borne -% de TeX ! mais sous la forme N/1[0] en ce qui concerne \xintSeq::csv.| +% \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): % -%\subsubsection{\csh{xintSeq::csv}} -%\lverb|Commence par remplacer a par ceil(a) et b par floor(b) et renvoie -% ensuite les entiers entre les deux, possiblement en décroissant, et -% extrémités comprises. Si a=b est non entier en obtient donc ceil(a) et -% floor(a). Ne renvoie jamais une liste vide. +%( 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} +%) % -% Note: le a..b dans \xintfloatexpr utilise cette routine.| +% 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. +% +% | % \begin{macrocode} -\def\xintSeq::csv {\romannumeral0\xintseq::csv }% -\def\xintseq::csv #1#2% +\def\XINT_ListSel_nthone #1#2% {% - \expandafter\XINT_seq::csv\expandafter - {\the\numexpr \xintiCeil{#1}\expandafter}\expandafter - {\the\numexpr \xintiFloor{#2}}% + \if \expandafter\XINT_ListSel_nthone_last\fi + \XINT_ListSel_nthone_a {#1}{#2}% }% -\def\XINT_seq::csv #1#2% +\def\XINT_ListSel_nthone_a #1#2(#3% {% - \ifcase\ifnum #1=#2 0\else\ifnum #2>#1 1\else -1\fi\fi\space - \expandafter\XINT_seq::csv_z - \or - \expandafter\XINT_seq::csv_p - \else - \expandafter\XINT_seq::csv_n - \fi - {#2}{#1}% + \expandafter\XINT_ListSel_deeper + \expanded{\unexpanded{#2}(\expandafter}\expandafter{% + \romannumeral0\expandafter\XINT_nthonepy_a\the\numexpr\xintNum{#1}.{#3}}% }% -\def\XINT_seq::csv_z #1#2{ #1/1[0]}% -\def\XINT_seq::csv_p #1#2% +\def\XINT_ListSel_nthone_last\XINT_ListSel_nthone_a #1#2(%#3% {% - \ifnum #1>#2 - \expandafter\expandafter\expandafter\XINT_seq::csv_p - \else - \expandafter\XINT_seq::csv_e - \fi - \expandafter{\the\numexpr #1-\xint_c_i}{#2},#1/1[0]% + \romannumeral0\expandafter\XINT_nthonepy_a\the\numexpr\xintNum{#1}.%{#3} }% -\def\XINT_seq::csv_n #1#2% -{% - \ifnum #1<#2 - \expandafter\expandafter\expandafter\XINT_seq::csv_n - \else - \expandafter\XINT_seq::csv_e - \fi - \expandafter{\the\numexpr #1+\xint_c_i}{#2},#1/1[0]% -}% -\def\XINT_seq::csv_e #1,{ }% % \end{macrocode} -%\subsubsection{\csh{xintiiSeq::csv}} +% \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. +% | % \begin{macrocode} -\def\xintiiSeq::csv {\romannumeral0\xintiiseq::csv }% -\def\xintiiseq::csv #1#2% +\def\XINT_ListSel_slice_b #1;#2_#3% {% - \expandafter\XINT_iiseq::csv\expandafter - {\the\numexpr #1\expandafter}\expandafter{\the\numexpr #2}% + \if \expandafter\XINT_ListSel_slice_last\fi + \expandafter\XINT_ListSel_slice_c \expandafter{\romannumeral0\xintnum{#2}};#1;{#3}% }% -\def\XINT_iiseq::csv #1#2% +\def\XINT_ListSel_slice_last\expandafter\XINT_ListSel_slice_c #1;#2;#3(%#4 {% - \ifcase\ifnum #1=#2 0\else\ifnum #2>#1 1\else -1\fi\fi\space - \expandafter\XINT_iiseq::csv_z - \or - \expandafter\XINT_iiseq::csv_p - \else - \expandafter\XINT_iiseq::csv_n - \fi - {#2}{#1}% + \expandafter\XINT_ListSel_slice_last_c #1;#2;%{#4} }% -\def\XINT_iiseq::csv_z #1#2{ #1}% -\def\XINT_iiseq::csv_p #1#2% +\def\XINT_ListSel_slice_last_c #1;#2;#3% {% - \ifnum #1>#2 - \expandafter\expandafter\expandafter\XINT_iiseq::csv_p - \else - \expandafter\XINT_seq::csv_e - \fi - \expandafter{\the\numexpr #1-\xint_c_i}{#2},#1% + \romannumeral0\XINT_ListSel_slice_d #2;#1;{#3}% }% -\def\XINT_iiseq::csv_n #1#2% +\def\XINT_ListSel_slice_c #1;#2;#3(#4% {% - \ifnum #1<#2 - \expandafter\expandafter\expandafter\XINT_iiseq::csv_n - \else - \expandafter\XINT_seq::csv_e - \fi - \expandafter{\the\numexpr #1+\xint_c_i}{#2},#1% + \expandafter\XINT_ListSel_deeper + \expanded{\unexpanded{#3}(\expandafter}\expandafter{% + \romannumeral0\XINT_ListSel_slice_d #2;#1;{#4}}% }% -\def\XINT_seq::csv_e #1,{ }% -% \end{macrocode} -%\subsection{Macros for a..[d]..b list generation} -% \localtableofcontents -% -% \lverb|Contrarily to a..b which is limited to small integers, this works -% with a, b, and d (big) fractions. It will produce a «nil» list, if a>b and -% d<0 or a<b and d>0.| -% -%\subsubsection{\csh{xintSeqA::csv}, \csh{xintiiSeqA::csv}, \csh{XINTinFloatSeqA::csv}} -% -% \begin{macrocode} -\def\xintSeqA::csv #1% - {\expandafter\XINT_seqa::csv\expandafter{\romannumeral0\xintraw {#1}}}% -\def\XINT_seqa::csv #1#2{\expandafter\XINT_seqa::csv_a \romannumeral0\xintraw {#2};#1;}% -\def\xintiiSeqA::csv #1{\expandafter\XINT_iiseqa::csv\expandafter{\romannumeral`&&@#1}}% -\def\XINT_iiseqa::csv #1#2{\expandafter\XINT_seqa::csv_a\romannumeral`&&@#2;#1;}% -\def\XINTinFloatSeqA::csv #1{\expandafter\XINT_flseqa::csv\expandafter - {\romannumeral0\XINTinfloat [\XINTdigits]{#1}}}% -\def\XINT_flseqa::csv #1#2% - {\expandafter\XINT_seqa::csv_a\romannumeral0\XINTinfloat [\XINTdigits]{#2};#1;}% -\def\XINT_seqa::csv_a #1{\xint_UDzerominusfork - #1-{z}% - 0#1{n}% - 0-{p}% - \krof #1}% -% \end{macrocode} -%\subsubsection{\csh{xintSeqB::csv}} -% \lverb|With one year late documentation, let's just say, the #1 is -% \XINT_expr_unlock\.=Ua;b; with U=z or n or p, a=step, b=start.| -% \begin{macrocode} -\def\xintSeqB::csv #1#2% - {\expandafter\XINT_seqb::csv \expandafter{\romannumeral0\xintraw{#2}}{#1}}% -\def\XINT_seqb::csv #1#2{\expandafter\XINT_seqb::csv_a\romannumeral`&&@#2#1!}% -\def\XINT_seqb::csv_a #1#2;#3;#4!{\expandafter\XINT_expr_seq_empty? - \romannumeral0\csname XINT_seqb::csv_#1\endcsname {#3}{#4}{#2}}% -\def\XINT_seqb::csv_p #1#2#3% +\def\XINT_ListSel_slice_d #1#2;#3#4;% {% - \xintifCmp {#1}{#2}{,#1\expandafter\XINT_seqb::csv_p\expandafter}% - {,#1\xint_gobble_iii}{\xint_gobble_iii}% -% \end{macrocode} -% \lverb|\romannumeral0 stopped by \endcsname, XINT_expr_seq_empty? constructs -% "nil".| -% \begin{macrocode} - {\romannumeral0\xintadd {#3}{#1}}{#2}{#3}% + \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_seqb::csv_n #1#2#3% +\def\XINT_ListSel_P:P #1;#2;#3% {% - \xintifCmp {#1}{#2}{\xint_gobble_iii}{,#1\xint_gobble_iii}% - {,#1\expandafter\XINT_seqb::csv_n\expandafter}% - {\romannumeral0\xintadd {#3}{#1}}{#2}{#3}% + \unless\ifnum #1<#2 \expandafter\xint_gob_andstop_iii\fi + \xintkeep{#2-#1}{\xintTrim{#1}{#3}}% }% -\def\XINT_seqb::csv_z #1#2#3{,#1}% -% \end{macrocode} -%\subsubsection{\csh{xintiiSeqB::csv}} -% \begin{macrocode} -\def\xintiiSeqB::csv #1#2{\XINT_iiseqb::csv #1#2}% -\def\XINT_iiseqb::csv #1#2#3#4% - {\expandafter\XINT_iiseqb::csv_a - \romannumeral`&&@\expandafter \XINT_expr_unlock\expandafter#2% - \romannumeral`&&@\XINT_expr_unlock #4!}% -\def\XINT_iiseqb::csv_a #1#2;#3;#4!{\expandafter\XINT_expr_seq_empty? - \romannumeral`&&@\csname XINT_iiseqb::csv_#1\endcsname {#3}{#4}{#2}}% -\def\XINT_iiseqb::csv_p #1#2#3% +\def\XINT_ListSel_N:N #1;#2;#3% {% - \xintSgnFork{\XINT_Cmp {#1}{#2}}{,#1\expandafter\XINT_iiseqb::csv_p\expandafter}% - {,#1\xint_gobble_iii}{\xint_gobble_iii}% - {\romannumeral0\xintiiadd {#3}{#1}}{#2}{#3}% + \expandafter\XINT_ListSel_N:N_a + \the\numexpr #2-#1\expandafter;\the\numexpr#1+\xintLength{#3};{#3}% }% -\def\XINT_iiseqb::csv_n #1#2#3% +\def\XINT_ListSel_N:N_a #1;#2;#3% {% - \xintSgnFork{\XINT_Cmp {#1}{#2}}{\xint_gobble_iii}{,#1\xint_gobble_iii}% - {,#1\expandafter\XINT_iiseqb::csv_n\expandafter}% - {\romannumeral0\xintiiadd {#3}{#1}}{#2}{#3}% + \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_iiseqb::csv_z #1#2#3{,#1}% -% \end{macrocode} -%\subsubsection{\csh{XINTinFloatSeqB::csv}} -% \begin{macrocode} -\def\XINTinFloatSeqB::csv #1#2{\expandafter\XINT_flseqb::csv \expandafter - {\romannumeral0\XINTinfloat [\XINTdigits]{#2}}{#1}}% -\def\XINT_flseqb::csv #1#2{\expandafter\XINT_flseqb::csv_a\romannumeral`&&@#2#1!}% -\def\XINT_flseqb::csv_a #1#2;#3;#4!{\expandafter\XINT_expr_seq_empty? - \romannumeral`&&@\csname XINT_flseqb::csv_#1\endcsname {#3}{#4}{#2}}% -\def\XINT_flseqb::csv_p #1#2#3% +\def\XINT_ListSel_N:P #1;#2;#3% {% - \xintifCmp {#1}{#2}{,#1\expandafter\XINT_flseqb::csv_p\expandafter}% - {,#1\xint_gobble_iii}{\xint_gobble_iii}% - {\romannumeral0\XINTinfloatadd {#3}{#1}}{#2}{#3}% + \expandafter\XINT_ListSel_N:P_a + \the\numexpr #1+\xintLength{#3};#2;{#3}% }% -\def\XINT_flseqb::csv_n #1#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% {% - \xintifCmp {#1}{#2}{\xint_gobble_iii}{,#1\xint_gobble_iii}% - {,#1\expandafter\XINT_flseqb::csv_n\expandafter}% - {\romannumeral0\XINTinfloatadd {#3}{#1}}{#2}{#3}% + \expandafter\XINT_ListSel_P:N_a + \the\numexpr #2+\xintLength{#3};#1;{#3}% }% -\def\XINT_flseqb::csv_z #1#2#3{,#1}% +\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{The comma as binary operator} -% \lverb|New with 1.09a. Suffices to set its precedence level to two.| +% \subsection{Support for raw A/B[N]} +% \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).| % \begin{macrocode} -\def\XINT_tmpa #1#2#3#4#5#6% +\catcode0 11 +\let\XINT_expr_precedence_&&@ \xint_c_xiv +\def\XINT_expr_op_&&@ #1#2]% {% - \def #1##1% \XINT_expr_op_, - {% - \expandafter #2\expandafter ##1\romannumeral`&&@\XINT_expr_getnext - }% - \def #2##1##2% \XINT_expr_until_,_a - {\xint_UDsignfork - ##2{\expandafter #2\expandafter ##1\romannumeral`&&@#4}% - -{#3##1##2}% - \krof }% - \def #3##1##2##3##4% \XINT_expr_until_,_b - {% - \ifnum ##2>\xint_c_ii - \xint_afterfi {\expandafter #2\expandafter ##1\romannumeral`&&@% - \csname XINT_#6_op_##3\endcsname {##4}}% - \else - \xint_afterfi - {\expandafter ##2\expandafter ##3% - \csname .=\XINT_expr_unlock ##1,\XINT_expr_unlock ##4\endcsname }% - \fi - }% - \let #5\xint_c_ii + \expandafter\XINT_expr_put_op_first + \expanded{{{\xintE#1{\xint_zapspaces #2 \xint_gobble_i}}}% + \expandafter}\romannumeral`&&@\XINT_expr_getop }% -\xintFor #1 in {expr,flexpr,iiexpr} \do {% -\expandafter\XINT_tmpa - \csname XINT_#1_op_,\expandafter\endcsname - \csname XINT_#1_until_,_a\expandafter\endcsname - \csname XINT_#1_until_,_b\expandafter\endcsname - \csname XINT_#1_op_-vi\expandafter\endcsname - \csname XINT_expr_precedence_,\endcsname {#1}% -}% -% \end{macrocode} -% \subsection{The minus as prefix operator of variable precedence level} -% \lverb|Inherits the precedence level of the previous infix operator.| -% \begin{macrocode} -\def\XINT_tmpa #1#2#3% +\def\XINT_iiexpr_op_&&@ #1#2]% {% - \expandafter\XINT_tmpb - \csname XINT_#1_op_-#3\expandafter\endcsname - \csname XINT_#1_until_-#3_a\expandafter\endcsname - \csname XINT_#1_until_-#3_b\expandafter\endcsname - \csname xint_c_#3\endcsname {#1}#2% + \expandafter\XINT_expr_put_op_first + \expanded{{{\xintiiE#1{\xint_zapspaces #2 \xint_gobble_i}}}% + \expandafter}\romannumeral`&&@\XINT_expr_getop }% -\def\XINT_tmpb #1#2#3#4#5#6% +\def\XINT_flexpr_op_&&@ #1#2]% {% - \def #1% \XINT_expr_op_-<level> - {% get next number+operator then switch to _until macro - \expandafter #2\romannumeral`&&@\XINT_expr_getnext - }% - \def #2##1% \XINT_expr_until_-<l>_a - {\xint_UDsignfork - ##1{\expandafter #2\romannumeral`&&@#1}% - -{#3##1}% - \krof }% - \def #3##1##2##3% \XINT_expr_until_-<l>_b - {% _until tests precedence level with next op, executes now or postpones - \ifnum ##1>#4% - \xint_afterfi {\expandafter #2\romannumeral`&&@% - \csname XINT_#5_op_##2\endcsname {##3}}% - \else - \xint_afterfi {\expandafter ##1\expandafter ##2% - \csname .=% - \XINT:NEhook:one#6{\XINT_expr_unlock ##3}\endcsname }% - \fi - }% + \expandafter\XINT_expr_put_op_first + \expanded{{{\XINTinFloatE#1{\xint_zapspaces #2 \xint_gobble_i}}}% + \expandafter}\romannumeral`&&@\XINT_expr_getop }% +\catcode0 12 % \end{macrocode} -% \lverb|1.2d needs precedence 8 for *** and 9 for ^. Earlier, precedence -% level for ^ was only 8 but nevertheless the code did also "ix" here, which I -% think was unneeded back then.| +% \subsection{? as two-way and ?? as three-way «short-circuit» conditionals} +% \lverb| +% Comments undergoing reconstruction. +% | +% % \begin{macrocode} -\xintApplyInline{\XINT_tmpa {expr}\xintOpp}{{vi}{vii}{viii}{ix}}% -\xintApplyInline{\XINT_tmpa {flexpr}\xintOpp}{{vi}{vii}{viii}{ix}}% -\xintApplyInline{\XINT_tmpa {iiexpr}\xintiiOpp}{{vi}{vii}{viii}{ix}}% +\let\XINT_expr_precedence_? \xint_c_xx +\catcode`- 11 +\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 }% % \end{macrocode} -% \subsection{? as two-way and ?? as three-way conditionals with braced branches} -% \lverb|In 1.1, I overload ? with ??, as : will be used for list extraction, -% problem with (stuff)?{?(1)}{0} for example, one should put a space (stuff)?{ -% ?(1)}{0} will work. Small idiosyncrasy. (which has been removed in 1.2h, -% there is no problem anymore with (test)?{?(1)}{0}, however (test)?{?}{!}(x) -% is not accepted; but (test)?{?(x)}{!(x)} is or even with {?(}{!(}x).) -% -% syntax: ?{yes}{no} and ??{<0}{=0}{>0}. -% -% The difficulty is to recognize the second ? without removing braces as would -% be the case with standard parsing of operators. Hence the ? operator is -% intercepted in \XINT_expr_getop_b. -% -% 1.2h corrects a bug in \XINT_expr_op_? which in context like -% (test)?{\foo}{bar} would provoke expansion of \foo, or also with -% (test)?{}{bar} would result in an error. The fix also solves the -% (test)?{?(1)}{0} issue mentioned above. -% | % \begin{macrocode} -\let\XINT_expr_precedence_? \xint_c_x -\def\XINT_expr_op_? #1#2% - {\XINT_expr_op_?checka #2!\xint_bye\XINT_expr_op_?a #1{#2}}% -\def\XINT_expr_op_?checka #1{\expandafter\XINT_expr_op_?checkb\detokenize{#1}}% -\def\XINT_expr_op_?checkb #1{\if ?#1\expandafter\XINT_expr_op_?checkc - \else\expandafter\xint_bye\fi }% -\def\XINT_expr_op_?checkc #1{\xint_gob_til_! #1\XINT_expr_op_?? !\xint_bye}% -\def\XINT_expr_op_?a #1#2#3% +\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% {% - \xintiiifNotZero{\XINT_expr_unlock #1}{\XINT_expr_getnext #2}{\XINT_expr_getnext #3}% + \expandafter\XINT_expr_check-_after?\expandafter#1% + \romannumeral`&&@\expandafter\XINT_expr_getnext\romannumeral0\xintiiifnotzero#2% }% -\let\XINT_flexpr_op_?\XINT_expr_op_? -\let\XINT_iiexpr_op_?\XINT_expr_op_? -\def\XINT_expr_op_?? !\xint_bye\xint_bye\XINT_expr_op_?a #1#2#3#4#5% +\def\XINT_expr_exec_?? #1#2#3% {% - \xintiiifSgn {\XINT_expr_unlock #1}% - {\XINT_expr_getnext #3}{\XINT_expr_getnext #4}{\XINT_expr_getnext #5}% + \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} % \subsection{! as postfix factorial operator} % \lverb|& % | % \begin{macrocode} -\let\XINT_expr_precedence_! \xint_c_x -\def\XINT_expr_op_! #1{\expandafter\XINT_expr_getop - \csname .=\XINT:NEhook:one\xintFac{\XINT_expr_unlock #1}\endcsname }% -\def\XINT_flexpr_op_! #1{\expandafter\XINT_expr_getop - \csname .=\XINT:NEhook:one\XINTinFloatFac{\XINT_expr_unlock #1}\endcsname }% -\def\XINT_iiexpr_op_! #1{\expandafter\XINT_expr_getop - \csname .=\XINT:NEhook:one\xintiiFac{\XINT_expr_unlock #1}\endcsname }% -% \end{macrocode} -% \subsection{The A/B[N] mechanism} -% \lverb|Releases earlier than 1.1 required the use of braces around A/B[N] -% input. The [N] is now implemented directly. *BUT* this uses a delimited macro! -% thus N is not allowed to be itself an expression (I could add it...). -% \xintE, \xintiiE, and \XINTinFloatE all put #2 in a \numexpr. But attention -% to the fact that \numexpr stops at spaces separating digits: -% \the\numexpr 3 + 7 9\relax gives 109\relax !! Hence we have to be -% careful. -% -% \numexpr will not handle catcode 11 digits, but adding a \detokenize will -% suddenly make illicit for N to rely on macro expansion.| -% -% \begin{macrocode} -\catcode`[ 11 -\let\XINT_expr_precedence_[ \xint_c_vii -\def\XINT_expr_op_[ #1#2]{\expandafter\XINT_expr_getop - \csname .=\xintE{\XINT_expr_unlock #1}% - {\xint_zapspaces #2 \xint_gobble_i}\endcsname}% -\def\XINT_iiexpr_op_[ #1#2]{\expandafter\XINT_expr_getop - \csname .=\xintiiE{\XINT_expr_unlock #1}% - {\xint_zapspaces #2 \xint_gobble_i}\endcsname}% -\def\XINT_flexpr_op_[ #1#2]{\expandafter\XINT_expr_getop - \csname .=\XINTinFloatE{\XINT_expr_unlock #1}% - {\xint_zapspaces #2 \xint_gobble_i}\endcsname}% -\catcode`[ 12 -% \end{macrocode} -% \subsection{\csh{XINT_expr_op_`} for recognizing functions} -% \lverb|The "onliteral" intercepts is for bool, togl, protect, ... but also -% for add, mul, seq, etc... Genuine functions have expr, iiexpr and -% flexpr versions (or only one or two of the three). -% -% With 1.2c "onliteral" is also used to disambiguate variables from -% functions. However as I use only a \ifcsname test, in order to be able to -% re-define a variable as function, I move the check for being a function -% first. Each variable name now has its onliteral_<name> associated macro -% which is the new way tacit multiplication in front of a parenthesis is -% implemented. This used to be decided much earlier at the time of -% \XINT_expr_func. -% -% The advantage of our choices for 1.2c is that the same name can be used for -% a variable or a function, the parser will apply the correct interpretation -% which is decided by the presence or not of an opening parenthesis next.| -% \begin{macrocode} -\def\XINT_tmpa #1#2#3{% - \def #1##1% - {% - \ifcsname XINT_#3_func_##1\endcsname - \xint_dothis{\expandafter\expandafter - \csname XINT_#3_func_##1\endcsname\romannumeral`&&@#2}\fi - \ifcsname XINT_expr_onliteral_##1\endcsname - \xint_dothis{\csname XINT_expr_onliteral_##1\endcsname}\fi - \xint_orthat{\XINT_expr_unknown_function {##1}% - \expandafter\XINT_expr_func_unknown\romannumeral`&&@#2}% - }% +\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_expr_unknown_function #1{\xintError:removed \xint_gobble_i {#1}}% -\xintFor #1 in {expr,flexpr,iiexpr} \do {% - \expandafter\XINT_tmpa - \csname XINT_#1_op_`\expandafter\endcsname - \csname XINT_#1_oparen\endcsname - {#1}% +\def\XINT_flexpr_op_! #1% +{% + \expandafter\XINT_expr_put_op_first + \expanded{{\romannumeral`&&@\XINT:NEhook:f:one:from:one + {\romannumeral`&&@\XINTinFloatFac#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 }% -\def\XINT_expr_func_unknown #1#2#3% - {\expandafter #1\expandafter #2\csname .=0\endcsname }% -% \end{macrocode} -% \subsection{The \csh{bool()}, \csh{togl()}, \csh{protect()} pseudo ``functions''} -% \lverb|bool, togl and protect use delimited macros. They are not true -% functions, they turn off the parser to gather their "variable".| -% \begin{macrocode} -\def\XINT_expr_onliteral_bool #1)% - {\expandafter\XINT_expr_getop\csname .=\xintBool{#1}\endcsname }% -\def\XINT_expr_onliteral_togl #1)% - {\expandafter\XINT_expr_getop\csname .=\xintToggle{#1}\endcsname }% -\def\XINT_expr_onliteral_protect #1)% - {\expandafter\XINT_expr_getop\csname .=\detokenize{#1}\endcsname }% -% \end{macrocode} -% \subsection{The \csh{break()} function} -% \lverb|break is a true function, the parsing via expansion of the succeeding -% material proceeded via _oparen macros as with any other function.| -% \begin{macrocode} -\def\XINT_expr_func_break #1#2#3% - {\expandafter #1\expandafter #2\csname.=?\romannumeral`&&@\XINT_expr_unlock #3\endcsname }% -\let\XINT_flexpr_func_break \XINT_expr_func_break -\let\XINT_iiexpr_func_break \XINT_expr_func_break % \end{macrocode} -% \subsection{The \csh{qraw()}, \csh{qint()}, \csh{qfrac()}, and -% \csh{qfloat()} ``functions''} -% -% \changed{1.2}{} adds |qint()|, |qfrac()|, |qfloat()|. -% -% \changed{1.3c}{} adds |qraw()|. Useful to limit impact on \TeX{} memory -% from abuse of |\csname|'s storage when generating many comma separated -% values from a loop. -% -% \changed{1.3e}{} |qfloat()| keeps a short mantissa if possible. +% \subsection{User defined variables} +% \localtableofcontents % -% \lverb|They allow the user to hand over quickly a big number to the parser, -% spaces not immediately removed but should be harmless in general. The qraw() -% does no post-processing at all apart complete expansion, useful for -% comma-separated values, but must be obedient to (non really documented) -% expected format. Each uses a delimited macro, the closing parenthesis can -% not emerge from expansion.| -% \begin{macrocode} -\def\XINT_expr_onliteral_qint #1)% - {\expandafter\XINT_expr_getop\csname .=\xintiNum{#1}\endcsname }% -\def\XINT_expr_onliteral_qfrac #1)% - {\expandafter\XINT_expr_getop\csname .=\xintRaw{#1}\endcsname }% -\def\XINT_expr_onliteral_qfloat #1)% - {\expandafter\XINT_expr_getop\csname .=\XINTinFloatSdigits{#1}\endcsname }% -\def\XINT_expr_onliteral_qraw #1)% - {\expandafter\XINT_expr_getop\csname .=#1\endcsname }% -% \end{macrocode} -% \subsection{The \csh{random()} and \csh{qrand()} ``functions''} -% \lverb|1.3b. Function-like syntax but with no argument currently, so let's -% use fast parsing which requires though the closing parenthesis to be -% explicit.| -% \begin{macrocode} -\def\XINT_expr_onliteral_random #1)% - {\expandafter\XINT_expr_getop\csname .=\XINTinRandomFloatSdigits\endcsname }% -\def\XINT_expr_onliteral_qrand #1)% - {\expandafter\XINT_expr_getop\csname .=\XINTinRandomFloatSixteen\endcsname }% -% \end{macrocode} -% \subsection{\csh{XINT_expr_op__} for recognizing variables} -% \lverb|The 1.1 mechanism for \XINT_expr_var_<varname> has been -% modified in 1.2c. The <varname> associated macro is now only expanded -% once, not twice. We arrive here via \XINT_expr_func.| -% \begin{macrocode} -\def\XINT_expr_op__ #1% op__ with two _'s - {% - \ifcsname XINT_expr_var_#1\endcsname - \expandafter\xint_firstoftwo - \else - \expandafter\xint_secondoftwo - \fi - {\expandafter\expandafter\expandafter - \XINT_expr_getop\csname XINT_expr_var_#1\endcsname}% - {\XINT_expr_unknown_variable {#1}% - \expandafter\XINT_expr_getop\csname .=0\endcsname}% - }% -\def\XINT_expr_unknown_variable #1{\xintError:removed \xint_gobble_i {#1}}% -\let\XINT_flexpr_op__ \XINT_expr_op__ -\let\XINT_iiexpr_op__ \XINT_expr_op__ -% \end{macrocode} -% \subsection{User defined variables: \csh{xintdefvar}, \csh{xintdefiivar}, +% \subsubsection{\csh{xintdefvar}, \csh{xintdefiivar}, % \csh{xintdeffloatvar}} % \changed{1.1}{} % @@ -36678,56 +37187,100 @@ math shift catcode. % an undefined or wrong variable name, or none at all if the variable % name was an initial |_| followed by digits. % \end{itemize} -% \lverb| -% | +% +% \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.| +% +% \changed{1.4}{2020/01/27} +% 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. +% +% TODO: prior to |1.4| a variable «value» was passed along as a single token. +% Now it is managed, like everything else, as explicit braced contents. But +% most of the code is ready for passing it along again as a single (braced, +% now) token again, because all needed |\expanded/\unexpanded| things are in +% place. However this is «most of the code». I am really eager to get |1.4| +% released now, because I can't devote more time in immediate future. It is +% too late to engage into an umpteenth deep refactoring at a time where things +% work and many new features were added and most aspects of inner working got +% adapted. However in future it could be that variables holding large data +% will be managed much faster. +% % \begin{macrocode} \catcode`* 11 \def\XINT_expr_defvar_one #1#2% {% \XINT_global - \expandafter\edef\csname XINT_expr_var_#1\endcsname - {\expandafter\noexpand#2}% + \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_onliteral_#1\endcsname - {\XINT_expr_precedence_*** *\expandafter\noexpand#2(}% + {\noexpand\expandafter\XINT_expr_precedence_*** + \noexpand\expandafter *\expandafter + \noexpand\csname XINT_expr_var_#1\endcsname(}% \ifxintverbose\xintMessage{xintexpr}{Info} {Variable "#1" \ifxintglobaldefs globally \fi - defined with value \expandafter\XINT_expr_unlock#2.}% + 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#3;% +\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\expandafter#1\romannumeral\XINT_expr_fetch_to_semicolon +}% +\def\XINT_expr_defvar_a #1#2% {% \xintexprRestoreCatcodes % \end{macrocode} % \lverb|Maybe SafeCatcodes was without effect because the colon and the rest % are from some earlier macro definition. Give a safe definition to active -% colon (even if in math mode with a math active colon..).| +% colon (even if in math mode with a math active colon..). +% +% The \XINT_expr_defvar_getname closes the group opened here.| % \begin{macrocode} \begingroup\lccode`~`: \lowercase{\let~}\empty - \edef\XINT_defvar_tmpa{#2}% + \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}{Warning} + \xintMessage {xintexpr}{Error} {Aborting: not allowed to declare variable with empty name.}% \or - \edef\XINT_defvar_tmpb{\romannumeral0#1#3\relax}% - \XINT_expr_defvar_one\XINT_defvar_tmpa\XINT_defvar_tmpb + \XINT_global + \expandafter\edef\csname XINT_expr_varvalue_\XINT_defvar_tmpa\endcsname + {\romannumeral0#1#2\relax}% + \XINT_expr_defvar_one_b\XINT_defvar_tmpa \else - \edef\XINT_defvar_tmpb - {\expandafter\XINT_expr_unlock\romannumeral0#1#3\relax}% - \edef\XINT_defvar_tmpd{\xintCSVLength{\XINT_defvar_tmpb}}% + \edef\XINT_defvar_tmpb{\romannumeral0#1#2\relax}% + \edef\XINT_defvar_tmpd{\expandafter\xintLength\expandafter{\XINT_defvar_tmpb}}% + \let\XINT_defvar_tmpe\empty + \if1\XINT_defvar_tmpd + \def\XINT_defvar_tmpe{unpacked }% + \oodef\XINT_defvar_tmpb{\expandafter\xint_firstofone\XINT_defvar_tmpb}% + \edef\XINT_defvar_tmpd{\expandafter\xintLength\expandafter{\XINT_defvar_tmpb}}% + \fi \ifnum\XINT_defvar_tmpc=\XINT_defvar_tmpd\space \xintAssignArray\xintCSVtoList\XINT_defvar_tmpa\to\XINT_defvar_tmpvar - \xintAssignArray - \xintApply\XINT_expr_lockit{\xintCSVtoList\XINT_defvar_tmpb}% - \to\XINT_defvar_tmpval + \xintAssignArray\xintApply\XINT_embrace{\XINT_defvar_tmpb}\to\XINT_defvar_tmpval \def\XINT_defvar_tmpd{1}% \xintloop \expandafter\XINT_expr_defvar_one @@ -36739,11 +37292,15 @@ math shift catcode. \xintRelaxArray\XINT_defvar_tmpvar \xintRelaxArray\XINT_defvar_tmpval \else - \xintMessage {xintexpr}{Warning} + \xintMessage {xintexpr}{Error} {Aborting: mismatch between number of variables (\XINT_defvar_tmpc) - and number of values (\XINT_defvar_tmpd).}% + and number of \XINT_defvar_tmpe values (\XINT_defvar_tmpd).}% \fi \fi + \let\XINT_defvar_tmpa\empty + \let\XINT_defvar_tmpb\empty + \let\XINT_defvar_tmpc\empty + \let\XINT_defvar_tmpd\empty }% \catcode`~ 3 \catcode`: 11 @@ -36754,11 +37311,11 @@ math shift catcode. \def\xintdefvar {\xintexprSafeCatcodes\xintdefvar_a}% \def\xintdefiivar {\xintexprSafeCatcodes\xintdefiivar_a}% \def\xintdeffloatvar {\xintexprSafeCatcodes\xintdeffloatvar_a}% -\def\xintdefvar_a #1={\XINT_expr_defvar\xintbareeval {#1}}% -\def\xintdefiivar_a #1={\XINT_expr_defvar\xintbareiieval {#1}}% -\def\xintdeffloatvar_a #1={\XINT_expr_defvar\xintbarefloateval {#1}}% +\def\xintdefvar_a #1={\XINT_expr_defvar\xintthebareeval {#1}}% +\def\xintdefiivar_a #1={\XINT_expr_defvar\xintthebareiieval {#1}}% +\def\xintdeffloatvar_a #1={\XINT_expr_defvar\xintthebarefloateval {#1}}% % \end{macrocode} -% \subsection{\csh{xintunassignvar}} +% \subsubsection{\csh{xintunassignvar}} % \changed{1.2e}{} % % \changed{1.3d}{} @@ -36779,6 +37336,8 @@ math shift catcode. \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_onliteral_\XINT_unvar_tmpa\endcsname\xint_undefined @@ -36793,1178 +37352,1335 @@ math shift catcode. \fi }% % \end{macrocode} -% \subsection{seq and the implementation of dummy variables} +% \subsection{Support for dummy variables} % \localtableofcontents -% \lverb|All of seq, add, mul, rseq, etc... (actually all of the extensive -% changes from xintexpr 1.09n to 1.1) was done around June 15-25th 2014, but the -% problem is that I did not document the code enough, and I had a hard time -% understanding in October what I had done in June. Despite the lesson, again -% being short on time, I do not document enough my current understanding of the -% innards of the beast... -% -% I added subs, and iter in October (also the [:n], [n:] list extractors), -% proving I did at least understand a bit (or rather could imitate) my earlier -% code (but don't ask me to explain \xintNewExpr !) -% -% The \XINT_expr_onliteral_seq_a parses: "expression, variable=list)" -% (when it is called the opening ( has been swallowed, and it looks for -% the ending one.) Both expression and list may themselves contain -% parentheses and commas, we allow nesting. For example "x^2,x=1..10)", -% at the end of seq_a we have {variable{expression}}{list}, in this -% example {x{x^2}}{1..10}, or more complicated -% "seq(add(y,y=1..x),x=1..10)" will work too. The variable is a single -% lowercase Latin letter. -% -% The complications with \xint_c_xviii in seq_f is for the recurrent -% thing that we don't know in what type of expressions we are, hence we -% must move back up, with some loss of efficiency (superfluous check for -% minus sign, etc...). But the code manages simultaneously expr, flexpr -% and iiexpr.| -% -% \subsubsection{All letters usable as dummy variables, \csh{xintnewdummy}} -% \lverb|The nil variable was introduced in 1.1 but isn't used under that -% name. However macros handling a..[d]..b, or for seq with dummy variable -% where omit has omitted everyting may in practice inject a nil value as -% current number. -% -% 1.2c has changed the way variables are disambiguated from functions and for -% this it has added here the definitions of \XINT_expr_onliteral_<name>. -% -% In 1.1 a letter variable say X was acting as a delimited macro looking for -% !X{stuff} and then would expand the stuff inside a \csname.=...\endcsname. I -% don't think I used the possibilities this opened and the 1.2c version has -% stuff _already_ encapsulated thus a single token. Only one expansion, not -% two is then needed in \XINT_expr_op__. -% -% I had to accordingly modify seq, add, mul and subs, but fortunately realized -% that the @, @1, etc... variables for rseq, rrseq and iter already had been -% defined in the way now also followed by the Latin letters as dummy -% variables. -% -% The 1.2e \XINT_expr_makedummy was adjoined \xintnewdummy by -% 1.2k for a public interface. It should not be used with multi-letter -% argument. The add, mul, seq, etc... can only work with one-letter long dummy -% variable. And this will almost certainly not change. -% -% Also 1.2e does the tacit multiplication x(stuff)->x*(stuff) in its higher -% precedence form. Things are easy now that variables always fetch a single -% already locked value \.=<number>. -% -% The tacit multiplication in case of the ``nil'' variable doesn't make much -% sense but we do it anyhow. -% -% 1.3e stores earlier meaning for usage by xinttrig and xintlog with -% \xintensuredummy and \xintrestoredummy as high-level interface. +% \subsubsection{\csh{xintnewdummy}} +% \lverb|& +% Comments under reconstruction. % -% Do an \xintrestorevar, and patch \xintdefvar to always store previous -% meaning? +% 1.4 adds multi-letter names as usable dummy variables! % | % +% % \begin{macrocode} \catcode`* 11 \def\XINT_expr_makedummy #1% {% - \ifcsname XINT_expr_var_#1\endcsname + \edef\XINT_tmpa{\xint_zapspaces #1 \xint_gobble_i}% + \ifcsname XINT_expr_var_\XINT_tmpa\endcsname \XINT_global - \expandafter\let\csname XINT_expr_var_#1/old\expandafter\endcsname - \csname XINT_expr_var_#1\expandafter\endcsname + \expandafter\let\csname XINT_expr_var_\XINT_tmpa/old\expandafter\endcsname + \csname XINT_expr_var_\XINT_tmpa\expandafter\endcsname \fi - \ifcsname XINT_expr_onliteral_#1\endcsname + \ifcsname XINT_expr_onliteral_\XINT_tmpa\endcsname \XINT_global - \expandafter\let\csname XINT_expr_onliteral_#1/old\expandafter\endcsname - \csname XINT_expr_onliteral_#1\expandafter\endcsname + \expandafter\let\csname XINT_expr_onliteral_\XINT_tmpa/old\expandafter\endcsname + \csname XINT_expr_onliteral_\XINT_tmpa\expandafter\endcsname \fi - \XINT_global - \expandafter\def\csname XINT_expr_var_#1\endcsname ##1\relax !#1##2% - {##2##1\relax !#1##2}% - \XINT_global - \expandafter\def\csname XINT_expr_onliteral_#1\endcsname ##1\relax !#1##2% - {\XINT_expr_precedence_*** *##2(##1\relax !#1##2}% + \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_onliteral_\XINT_tmpa\endcsname ##1\relax !\XINT_tmpa##2}% + {\XINT_expr_precedence_*** *{##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}% - {#1 (with letter catcode) now + {\XINT_tmpa\space now \ifxintglobaldefs globally \fi usable as dummy variable.}% \fi }% -\edef\XINT_expr_var_nil {\expandafter\noexpand\csname .= \endcsname}% -\edef\XINT_expr_onliteral_nil - {\XINT_expr_precedence_*** *\expandafter\noexpand\csname .= \endcsname (}% +% \begin{macrocode} +% Je ne définis pas de onliteral for them (it only serves for allowing +% tacit multiplication if variable name is in front of an opening +% parenthesis). +% +% 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 |[]|. +% \begin{macrocode} +\def\XINT_expr_var_nil{{}}% +\def\XINT_expr_var_None{{{}}}% ? tentative +\def\XINT_expr_var_false{{{0}}}% Maple, TeX +\def\XINT_expr_var_true{{{1}}}% +\def\XINT_expr_var_False{{{0}}}% Python +\def\XINT_expr_var_True{{{1}}}% \catcode`* 12 % \end{macrocode} -% \subsubsection{\cshn{xintensuredummy}, \cshn{xintrestorelettervar}} -% \lverb|\xintensuredummy differs only in the informational message... -% Attention that this is not meant to be nested.| +% \subsubsection{\csh{xintensuredummy}, \csh{xintrestorevariable}} +% \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.| % \begin{macrocode} \def\xintensuredummy #1{% \XINT_expr_makedummy{#1}% \ifxintverbose\xintMessage {xintexpr}{Info}% - {#1 (with letter catcode) now + {\XINT_tmpa\space now \ifxintglobaldefs globally \fi usable as dummy variable.&&J - Use \string\xintrestoredummy{#1} to restore it to its former meaning.}% + Issue \string\xintrestorevariable{\XINT_tmpa} to restore former meaning.}% \fi }% -\def\xintrestorelettervar #1{% - \ifcsname XINT_expr_var_#1/old\endcsname +\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_#1\expandafter\endcsname - \csname XINT_expr_var_#1/old\expandafter\endcsname + \expandafter\let\csname XINT_expr_var_\XINT_tmpa\expandafter\endcsname + \csname XINT_expr_var_\XINT_tmpa/old\expandafter\endcsname \fi - \ifcsname XINT_expr_onliteral_#1/old\endcsname + \ifcsname XINT_expr_onliteral_\XINT_tmpa/old\endcsname \XINT_global - \expandafter\let\csname XINT_expr_onliteral_#1\expandafter\endcsname - \csname XINT_expr_onliteral_#1/old\expandafter\endcsname + \expandafter\let\csname XINT_expr_onliteral_\XINT_tmpa\expandafter\endcsname + \csname XINT_expr_onliteral_\XINT_tmpa/old\expandafter\endcsname \fi +}% +\def\xintrestorevariable #1{% + \xintrestorevariablesilently {#1}% \ifxintverbose\xintMessage {xintexpr}{Info}% - {Character #1 (with letter catcode) + {\XINT_tmpa\space \ifxintglobaldefs globally \fi restored to its earlier status, if any.}% \fi }% % \end{macrocode} -% \subsubsection{\csh{omit()} and \csh{abort()}} -% \lverb|& attention à ce & qui est de catcode 14 dans les \lverb -% June 24 and 25, 2014. +% \subsubsection{Checking (without expansion) that a symbolic expression +% contains correctly nested parentheses} +% +% \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. +% | +% \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} +% \lverb|if #2 is not \xint_bye, a ) was found, but there was no (. Hence error -> -1| +% \begin{macrocode} +\def\XINT_isbalanced_error #1)\xint_bye {\xint_c_mone}% +% \end{macrocode} +% \lverb|#2 was \xint_bye, was there a ) in original #1?| +% \begin{macrocode} +\def\XINT_isbalanced_c\xint_bye\XINT_isbalanced_error #1% + {\xint_bye #1\XINT_isbalanced_yes\xint_bye\XINT_isbalanced_d #1}% +% \end{macrocode} +% \lverb|#1 is \xint_bye, there was never ( nor ) in original #1, hence OK.| +% \begin{macrocode} +\def\XINT_isbalanced_yes\xint_bye\XINT_isbalanced_d\xint_bye )\xint_bye {\xint_c_ }% +% \end{macrocode} +% \lverb|#1 is not \xint_bye, there was indeed a ( in original #1. We check if +% we see a ). If we do, we then loop until no ( nor ) is to be found.| +% \begin{macrocode} +\def\XINT_isbalanced_d #1)#2% + {\xint_bye #2\XINT_isbalanced_no\xint_bye\XINT_isbalanced_a #1#2}% +% \end{macrocode} +% \lverb|#2 was \xint_bye, we did not find a closing ) in original #1. Error.| +% \begin{macrocode} +\def\XINT_isbalanced_no\xint_bye #1\xint_bye\xint_bye {\xint_c_i }% +% \end{macrocode} +% \subsubsection{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} % -% Added comments 2015/11/13: +% \lverb|1.4. For subsn() leaner syntax of nested substitutions. % -% Et la documentation ? on n'y comprend plus rien. Trop -% rusé.$newline -% \def\XINT_expr_var_omit #1\relax !{1^C!{}{}{}\.=!\relax !}$newline -% \def\XINT_expr_var_abort #1\relax !{1^C!{}{}{}\.=^\relax !}$newline -% C'était accompagné de \XINT_expr_precedence_^C=0 et d'un hack au sein même -% des macros until de plus bas niveau. +% Will also serve to \xintdeffunc, to not have to hide inner semi-colons in +% for example an iter() from \xintdeffunc. % -% Le mécanisme sioux était le suivant: ^C est déclaré comme un opérateur de -% précédence nulle. Lorsque le parseur trouve un "omit" dans un seq ou autre, -% il va insérer dans le stream \XINT_expr_getop suivi du texte de -% remplacement. Donc ici on avait un 1 comme place holder, puis l'opérateur -% ^C. Celui-ci étant de précédence zéro provoque la finalisation de tous les -% calculs antérieurs dans le sous-bareeval. Mais j'ai dû hacker le until_end_b -% (et le until_)_b) qui confronté à ^C, va se relancer à zéro, le getnext va -% trouver le !{}{}{}\.=! et ensuite il y aura \relax, et le résultat sera \.=! -% pour omit ou \.=^ pour abort. Les routines des boucles seq, iter, etc... -% peuvent alors repérer le ! ou ^ et agir en conséquence (un long paragraphe -% pour ne décrire que partiellement une ou deux lignes de codes...). +% Adding brace removal protection for no serious reason, anyhow the xintexpr +% parsers always removes braces when moving forward, but well. % -% Mais ^C a été fait alors que je n'avais pas encore les variables muettes. Je -% dois trouver autre chose, car seq(2^C, C=1..5) est alors impossible. De -% toute façon ce ^C était à usage interne uniquement. +% Trigger by \romannumeral\XINT_expr_fetch_to_semicolon upfront.| % -% Il me faut un symbole d'opérateur qui ne rentre pas en conflit. Bon je vais -% prendre !?. Ensuite au lieu de hacker until_end, il vaut mieux lui donner -% précédence 2 (mais ça ne pourra pas marcher à l'intérieur de parenthèses il -% faut d'abord les fermer manuellement) et lui associer un simplement un op -% spécial. Je n'avais pas fait cela peut-être pour éviter d'avoir à définir -% plusieurs macros. Le #1 dans la définition de \XINT_expr_op_!? est le -% résultat de l'évaluation forcée précédente. +% \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()} +% \lverb|There is some clever play simply based on setting suitable precedence +% levels combined with special meanings given to op macros. % -% Attention que les premier ! doiventt être de catcode 12 sinon ils -% signalent une sous-expression qui déclenche une multiplication tacite. +% 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. % | +% \paragraph{The n++ construct} +% \lverb|1.1 2014/10/29 did \expandafter\.=+\xintiCeil which transformed it into +% \romannumeral0\xinticeil, which seems a bit weird. This exploited the fact +% that dummy variables macros could back then pick braced material (which in the +% case at hand here ended being {\romannumeral0\xinticeil...} and were submitted +% to two expansions. The result of this was to provide a not value which got +% expanded only in the first loop of the :_A and following macros of seq, +% iter, rseq, etc... +% +% Anyhow with 1.2c I have changed the implementation of dummy variables which +% now need to fetch a single locked token, which they do not expand. +% +% The \xintiCeil appears a bit dispendious, but I need the starting value in a +% \numexpr compatible form in the iteration loops.| +% \begin{macrocode} +\expandafter\def\csname XINT_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} +% \lverb|break is a true function, the parsing via expansion of the enclosed +% material proceeds via _oparen macros as with any other function.| +% \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} +% \lverb|& +% Comments are currently undergoing reconstruction. +% | +% % \begin{macrocode} \edef\XINT_expr_var_omit #1\relax !{1\string !?!\relax !}% \edef\XINT_expr_var_abort #1\relax !{1\string !?^\relax !}% -\def\XINT_expr_op_!? #1#2\relax {\expandafter\XINT_expr_foundend\csname .=#2\endcsname}% +\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} -% \subsubsection{The special variables @, @1, @2, @3, @4, @@, @@(1), \dots, @@@, -% @@@(1), \dots for recursion} -% \lverb|October 2014: I had completely forgotten what the @@@ etc... stuff -% were supposed to do: this is for nesting recursions! (I was mad back in -% June). @@(N) gives the Nth back, @@@(N) gives the Nth back of the higher -% recursion! +% \paragraph{The semi-colon} +% +% \lverb|Obsolete comments undergoing re-construction| +% +% \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} +% \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. % -% 1.2c adds the needed "onliteral" now that tacit multiplication between a -% variable and a ( has a new mechanism. 1.2e does this tacit multiplication -% with higher precedence. +% Brace stripping in \XINT_expr_func_@@ +% is prevented by some ending 0 or other token see iterr() and rrseq() code. % -% For the record, the ~ has catcode 3 in this code.| +% For the record, the ~ and ? have catcode 3 in this code. +% +% | % % \begin{macrocode} -\catcode`? 3 \catcode`* 11 -\def\XINT_expr_var_@ #1~#2{#2#1~#2}% -\expandafter\let\csname XINT_expr_var_@1\endcsname \XINT_expr_var_@ -\expandafter\def\csname XINT_expr_var_@2\endcsname #1~#2#3{#3#1~#2#3}% -\expandafter\def\csname XINT_expr_var_@3\endcsname #1~#2#3#4{#4#1~#2#3#4}% -\expandafter\def\csname XINT_expr_var_@4\endcsname #1~#2#3#4#5{#5#1~#2#3#4#5}% -\def\XINT_expr_onliteral_@ #1~#2{\XINT_expr_precedence_*** *#2(#1~#2}% -\expandafter\let\csname XINT_expr_onliteral_@1\endcsname \XINT_expr_onliteral_@ +\catcode`* 11 +\def\XINT_expr_var_@ #1~#2{{#2}#1~{#2}}% +\def\XINT_expr_onliteral_@ #1~#2{\XINT_expr_precedence_*** *{#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_onliteral_@1\endcsname #1~#2% + {\XINT_expr_precedence_*** *{{#2}}(#1~{#2}}% \expandafter\def\csname XINT_expr_onliteral_@2\endcsname #1~#2#3% - {\XINT_expr_precedence_*** *#3(#1~#2#3}% + {\XINT_expr_precedence_*** *{{#3}}(#1~{#2}{#3}}% \expandafter\def\csname XINT_expr_onliteral_@3\endcsname #1~#2#3#4% - {\XINT_expr_precedence_*** *#4(#1~#2#3#4}% + {\XINT_expr_precedence_*** *{{#4}}(#1~{#2}{#3}{#4}}% \expandafter\def\csname XINT_expr_onliteral_@4\endcsname #1~#2#3#4#5% - {\XINT_expr_precedence_*** *#5(#1~#2#3#4#5}% + {\XINT_expr_precedence_*** *{{#5}}(#1~{#2}{#3}{#4}{#5}}% \catcode`* 12 +\catcode`? 3 \def\XINT_expr_func_@@ #1#2#3#4~#5?% {% - \expandafter#1\expandafter#2\romannumeral0\xintntheltnoexpand - {\xintNum{\XINT_expr_unlock#3}}{#5}#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\romannumeral0\xintntheltnoexpand - {\xintNum{\XINT_expr_unlock#3}}{#6}#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\romannumeral0\xintntheltnoexpand - {\xintNum{\XINT_expr_unlock#3}}{#7}#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\romannumeral0\xintntheltnoexpand - {\XINT_expr_unlock#3}{#5}#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\romannumeral0\xintntheltnoexpand - {\XINT_expr_unlock#3}{#6}#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\romannumeral0\xintntheltnoexpand - {\XINT_expr_unlock#3}{#7}#4~#5~#6~#7?% + \expandafter#1\expandafter#2\expandafter{\expandafter{% + \romannumeral0\xintntheltnoexpand{\xint_firstofone#3}{#7}}}#4~#5~#6~#7?% }% \catcode`? 11 % \end{macrocode} -% \subsubsection{\csh{XINT_expr_onliteral_seq}} +% \subsection{Pseudo-functions involving dummy variables and generating scalars or sequences} +% \localtableofcontents +% +% \subsubsection{Comments} +% \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.| +% +% \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 ! +% | +% \subsubsection{\cshn{subs()}: substitution of one variable} % \begin{macrocode} -\def\XINT_expr_onliteral_seq - {\expandafter\XINT_expr_onliteral_seq_f\romannumeral`&&@\XINT_expr_onliteral_seq_a {}}% -\def\XINT_expr_onliteral_seq_f #1#2{\xint_c_xviii `{seqx}#2)\relax #1}% +\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} -% \subsubsection{\csh{XINT_expr_onliteral_seq_a}} +% \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 +% | % \begin{macrocode} -\def\XINT_expr_onliteral_seq_a #1#2,% +\def\XINT_allexpr_subsx #1#2#3#4% {% - \ifcase\XINT_isbalanced_a \relax #1#2(\xint_bye)\xint_bye - \expandafter\XINT_expr_onliteral_seq_c - \or\expandafter\XINT_expr_onliteral_seq_b - \else\expandafter\xintError:we_are_doomed - \fi {#1#2},% + \expandafter\XINT_expr_put_op_first + \expanded + \bgroup\romannumeral0#1#4\relax \iffalse\relax !#3{#2}{\fi + \expandafter}\romannumeral`&&@\XINT_expr_getop }% -\def\XINT_expr_onliteral_seq_b #1,{\XINT_expr_onliteral_seq_a {#1,}}% -\def\XINT_expr_onliteral_seq_c #1,#2#3% #3 pour absorber le = +% \end{macrocode} +% \subsubsection{\cshn{subsm()}: simultaneous independent substitutions} +% \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. +% +% | +% \begin{macrocode} +\def\XINT_expr_onliteral_subsm {% - \XINT_expr_onliteral_seq_d {#2{#1}}{}% + \expandafter\XINT_allexpr_subsm_f + \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% -\def\XINT_expr_onliteral_seq_d #1#2#3)% +\def\XINT_allexpr_subsm_f #1#2{\xint_c_ii^v `{subsmx}#2)\relax #1}% +\def\XINT_expr_func_subsmx {% - \ifcase\XINT_isbalanced_a \relax #2#3(\xint_bye)\xint_bye - \or\expandafter\XINT_expr_onliteral_seq_e - \else\expandafter\xintError:we_are_doomed - \fi - {#1}{#2#3}% + \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% }% -\def\XINT_expr_onliteral_seq_e #1#2{\XINT_expr_onliteral_seq_d {#1}{#2)}}% -% \end{macrocode} -% \subsubsection{\csh{XINT_isbalanced_a} for \cshnolabel{XINT_expr_onliteral_seq_a}} -% \lverb|Expands to \xint_c_mone in case a closing ) had no opening ( matching -% it, to \@ne if opening ) had no closing ) matching it, to \z@ if expression -% was balanced.| -% \begin{macrocode} -% use as \XINT_isbalanced_a \relax #1(\xint_bye)\xint_bye -\def\XINT_isbalanced_a #1({\XINT_isbalanced_b #1)\xint_bye }% -\def\XINT_isbalanced_b #1)#2% - {\xint_bye #2\XINT_isbalanced_c\xint_bye\XINT_isbalanced_error }% -% \end{macrocode} -% \lverb|if #2 is not \xint_bye, a ) was found, but there was no (. Hence error -> -1| -% \begin{macrocode} -\def\XINT_isbalanced_error #1)\xint_bye {\xint_c_mone}% -% \end{macrocode} -% \lverb|#2 was \xint_bye, was there a ) in original #1?| -% \begin{macrocode} -\def\XINT_isbalanced_c\xint_bye\XINT_isbalanced_error #1% - {\xint_bye #1\XINT_isbalanced_yes\xint_bye\XINT_isbalanced_d #1}% -% \end{macrocode} -% \lverb|#1 is \xint_bye, there was never ( nor ) in original #1, hence OK.| -% \begin{macrocode} -\def\XINT_isbalanced_yes\xint_bye\XINT_isbalanced_d\xint_bye )\xint_bye {\xint_c_ }% % \end{macrocode} -% \lverb|#1 is not \xint_bye, there was indeed a ( in original #1. We check if -% we see a ). If we do, we then loop until no ( nor ) is to be found.| +% \lverb| +% #1 = \xintbareeval, or \xintbarefloateval or \xintbareiieval +% #2 = evaluation of last variable assignment +% | % \begin{macrocode} -\def\XINT_isbalanced_d #1)#2% - {\xint_bye #2\XINT_isbalanced_no\xint_bye\XINT_isbalanced_a #1#2}% +\def\XINT_allexpr_subsm_done #1#2{{#2}\iffalse{{\fi}}}% % \end{macrocode} -% \lverb|#2 was \xint_bye, we did not find a closing ) in original #1. Error.| +% \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 +% | % \begin{macrocode} -\def\XINT_isbalanced_no\xint_bye #1\xint_bye\xint_bye {\xint_c_i }% +\def\XINT_allexpr_subsmx #1#2#3#4% +{% + \expandafter\XINT_expr_put_op_first + \expanded + \bgroup\romannumeral0#1#4\relax \iffalse\relax !#3#2{\fi + \expandafter}\romannumeral`&&@\XINT_expr_getop +}% % \end{macrocode} -% \subsubsection{\csh{XINT_allexpr_func_seqx}} -% \lverb|1.2c uses \xintthebareval, ... which strangely were not available at -% 1.1 time. This spares some tokens from \XINT_expr_seq:_d and cousins. Also now -% variables have changed their mode of operation they pick only one token which -% must be an already encapsulated value. +% \subsubsection{\cshn{subsn()}: leaner syntax for nesting (possibly dependent) substitutions} +% \lverb|New with 1.4. 2020/01/24 % -% In \XINT_allexp_seqx, #2 is the list, evaluated and encapsulated, #3 is the -% dummy variable, #4 is the expression to evaluate repeatedly. -% -% A special case is a list generated by <variable>++: then #2 is {\.=+\.=<start>}.| +% | % \begin{macrocode} -\def\XINT_expr_func_seqx #1#2{\XINT_allexpr_seqx \xintthebareeval }% -\def\XINT_flexpr_func_seqx #1#2{\XINT_allexpr_seqx \xintthebarefloateval}% -\def\XINT_iiexpr_func_seqx #1#2{\XINT_allexpr_seqx \xintthebareiieval }% -\def\XINT_allexpr_seqx #1#2#3#4% +\def\XINT_expr_onliteral_subsn {% - \expandafter \XINT_expr_getop - \csname .=\expandafter\XINT_expr_seq:_aa - \romannumeral`&&@\XINT_expr_unlock #2!{#1#4\relax !#3}\endcsname -}% -\def\XINT_expr_seq:_aa #1{\if +#1\expandafter\XINT_expr_seq:_A\else - \expandafter\XINT_expr_seq:_a\fi #1}% -% \end{macrocode} -% \subsubsection{Evaluation over list, \csh{XINT_expr_seq:_a} with break, -% abort, omit} -% \lverb|The #2 here is \...bareeval <expression>\relax !<variable name>. The #1 -% is a comma separated list of values to assign to the dummy variable. The -% \XINT_expr_seq_empty? intervenes immediately after handling of firstvalue. -% -% 1.2c has rewritten to a large extent this and other similar loops because -% the dummy variables now fetch a single encapsulated token (apart from a good -% means to lose a few hours needlessly -- as I have had to rewrite and review -% most everything, this change could make the thing more efficient if the same -% variable is used many times in an expression, but we are talking -% micro-seconds here anyhow.)| -% \begin{macrocode} -\def\XINT_expr_seq:_a #1!#2{\expandafter\XINT_expr_seq_empty? - \romannumeral0\XINT_expr_seq:_b {#2}#1,^,}% -\def\XINT_expr_seq:_b #1#2#3,{% - \if ,#2\xint_dothis\XINT_expr_seq:_noop\fi - \if ^#2\xint_dothis\XINT_expr_seq:_end\fi - \xint_orthat{\expandafter\XINT_expr_seq:_c}\csname.=#2#3\endcsname {#1}% -}% -\def\XINT_expr_seq:_noop\csname.=,#1\endcsname #2{\XINT_expr_seq:_b {#2}#1,}% -\def\XINT_expr_seq:_end \csname.=^\endcsname #1{}% -\def\XINT_expr_seq:_c #1#2{\expandafter\XINT_expr_seq:_d\romannumeral`&&@#2#1{#2}}% -\def\XINT_expr_seq:_d #1{\if #1^\xint_dothis\XINT_expr_seq:_abort\fi - \if #1?\xint_dothis\XINT_expr_seq:_break\fi - \if #1!\xint_dothis\XINT_expr_seq:_omit\fi - \xint_orthat{\XINT_expr_seq:_goon #1}}% -\def\XINT_expr_seq:_abort #1!#2#3#4#5^,{}% -\def\XINT_expr_seq:_break #1!#2#3#4#5^,{,#1}% -\def\XINT_expr_seq:_omit #1!#2#3#4{\XINT_expr_seq:_b {#4}}% -\def\XINT_expr_seq:_goon #1!#2#3#4{,#1\XINT_expr_seq:_b {#4}}% -% \end{macrocode} -% \lverb|If all is omitted or list is empty, _empty? will fetch within the ##1 -% a \endcsname token and construct "nil" via <space>\endcsname, if not ##1 -% will be a comma and the gobble will swallow the space token and the -% extra \endcsname.| -% \begin{macrocode} -\def\XINT_expr_seq_empty? #1{% -\def\XINT_expr_seq_empty? ##1{\if ,##1\expandafter\xint_gobble_i\fi #1\endcsname }}% -\XINT_expr_seq_empty? { }% -% \end{macrocode} -% \subsubsection{Evaluation over ++ generated lists with \csh{XINT_expr_seq:_A}} -% \lverb|This is for index lists generated by n++. The starting point will have -% been replaced by its ceil (added: in fact with version 1.1. the ceil was not -% yet evaluated, but _var_<letter> did an expansion of what they fetch). We use -% \numexpr rather than \xintInc, hence the indexing is limited to small -% integers. -% -% The 1.2c version of n++ produces a #1 here which is already a single -% \.=<value> token.| -% \begin{macrocode} -\def\XINT_expr_seq:_A +#1!% - {\expandafter\XINT_expr_seq_empty?\romannumeral0\XINT_expr_seq:_D #1}% -\def\XINT_expr_seq:_D #1#2{\expandafter\XINT_expr_seq:_E\romannumeral`&&@#2#1{#2}}% -\def\XINT_expr_seq:_E #1{\if #1^\xint_dothis\XINT_expr_seq:_Abort\fi - \if #1?\xint_dothis\XINT_expr_seq:_Break\fi - \if #1!\xint_dothis\XINT_expr_seq:_Omit\fi - \xint_orthat{\XINT_expr_seq:_Goon #1}}% -\def\XINT_expr_seq:_Abort #1!#2#3#4{}% -\def\XINT_expr_seq:_Break #1!#2#3#4{,#1}% -\def\XINT_expr_seq:_Omit #1!#2#3% - {\expandafter\XINT_expr_seq:_D - \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\endcsname}% -\def\XINT_expr_seq:_Goon #1!#2#3% - {,#1\expandafter\XINT_expr_seq:_D - \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\endcsname}% -% \end{macrocode} -% \subsection{\csh{add()}, \csh{mul()}} -% \lverb|1.2c uses more directly the \xintiiAdd etc... macros and has -% opxadd/opxmul rather than a single opx. This is less conceptual as I use -% explicitely the associated macro names for +, * but this makes other things -% more efficient, and the code more readable.| -% \begin{macrocode} -\def\XINT_expr_onliteral_add - {\expandafter\XINT_expr_onliteral_add_f\romannumeral`&&@\XINT_expr_onliteral_seq_a {}}% -\def\XINT_expr_onliteral_add_f #1#2{\xint_c_xviii `{opxadd}#2)\relax #1}% -\def\XINT_expr_onliteral_mul - {\expandafter\XINT_expr_onliteral_mul_f\romannumeral`&&@\XINT_expr_onliteral_seq_a {}}% -\def\XINT_expr_onliteral_mul_f #1#2{\xint_c_xviii `{opxmul}#2)\relax #1}% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_func_opxadd}, \csh{XINT_flexpr_func_opxadd}, -% \csh{XINT_iiexpr_func_opxadd} and same for mul} -% |modified 1.2c.| -% \begin{macrocode} -\def\XINT_expr_func_opxadd #1#2{\XINT_allexpr_opx \xintbareeval {\xintAdd 0}}% -\def\XINT_flexpr_func_opxadd #1#2{\XINT_allexpr_opx \xintbarefloateval {\XINTinFloatAdd 0}}% -\def\XINT_iiexpr_func_opxadd #1#2{\XINT_allexpr_opx \xintbareiieval {\xintiiAdd 0}}% -\def\XINT_expr_func_opxmul #1#2{\XINT_allexpr_opx \xintbareeval {\xintMul 1}}% -\def\XINT_flexpr_func_opxmul #1#2{\XINT_allexpr_opx \xintbarefloateval {\XINTinFloatMul 1}}% -\def\XINT_iiexpr_func_opxmul #1#2{\XINT_allexpr_opx \xintbareiieval {\xintiiMul 1}}% + \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} -% \lverb|#1=bareeval etc, #2={Add0} ou {Mul1}, #3=liste encapsulée, #4=la variable, #5=expression| +% \lverb| +%( #1 = Name1 +%: #2 = Expression in all variables which is to evaluate +%: #3 = all the stuff after Name1 = and up to final parenthesis +%) +% | % \begin{macrocode} -\def\XINT_allexpr_opx #1#2#3#4#5% +\def\XINT_allexpr_subsn_g #1#2#3% {% - \expandafter\XINT_expr_getop - \csname.=\romannumeral`&&@\expandafter\XINT_expr_op:_a - \romannumeral`&&@\XINT_expr_unlock #3!{#1#5\relax !#4}{#2}\endcsname + \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_expr_op:_a #1!#2#3{\XINT_expr_op:_b #3{#2}#1,^,}% -% \end{macrocode} -% \lverb|#2 in \XINT_expr_op:_b is the partial result of computation so far, not -% locked. A noop with have #4=, and #5 the next item which we need to recover. -% No need to be very efficient for that in op:_noop. In op:_d, #4 is \xintAdd or -% similar.| -% \begin{macrocode} -\def\XINT_expr_op:_b #1#2#3#4#5,{% - \if ,#4\xint_dothis\XINT_expr_op:_noop\fi - \if ^#4\xint_dothis\XINT_expr_op:_end\fi - \xint_orthat{\expandafter\XINT_expr_op:_c}\csname.=#4#5\endcsname {#3}#1{#2}% +\def\XINT_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_expr_op:_c #1#2#3#4% - {\expandafter\XINT_expr_op:_d\romannumeral0#2#1#3{#4}{#2}}% -\def\XINT_expr_op:_d #1!#2#3#4#5% - {\expandafter\XINT_expr_op:_b\expandafter #4\expandafter - {\romannumeral`&&@\XINT:NEhook:two#4{\XINT_expr_unlock#1}{#5}}}% -% \end{macrocode} -% \lverb|The replacement text had expr_seq:_b rather than expr_op:_b due to a -% left-over from copy-paste. This made add and mul fail with an empty range -% for the variable (or "nil" in the list of values). Fixed in 1.2h.| -% \begin{macrocode} -\def\XINT_expr_op:_noop\csname.=,#1\endcsname #2#3#4{\XINT_expr_op:_b #3{#4}{#2}#1,}% -\def\XINT_expr_op:_end \csname.=^\endcsname #1#2#3{#3}% -% \end{macrocode} -% \subsection{\csh{subs()}} -% \lverb|Got simpler with 1.2c as now the dummy variable fetches an -% already encapsulated value, which is anyhow the form in which we get -% it.| -% \begin{macrocode} -\def\XINT_expr_onliteral_subs - {\expandafter\XINT_expr_onliteral_subs_f\romannumeral`&&@\XINT_expr_onliteral_seq_a {}}% -\def\XINT_expr_onliteral_subs_f #1#2{\xint_c_xviii `{subx}#2)\relax #1}% -\def\XINT_expr_func_subx #1#2{\XINT_allexpr_subx \xintbareeval }% -\def\XINT_flexpr_func_subx #1#2{\XINT_allexpr_subx \xintbarefloateval}% -\def\XINT_iiexpr_func_subx #1#2{\XINT_allexpr_subx \xintbareiieval }% -\def\XINT_allexpr_subx #1#2#3#4% #2 is the value to assign to the dummy variable -{% #3 is the dummy variable, #4 is the expression to evaluate - \expandafter\expandafter\expandafter\XINT_expr_getop - \expandafter\XINT_expr_subx:_end\romannumeral0#1#4\relax !#3#2% -}% -\def\XINT_expr_subx:_end #1!#2#3{#1}% -% \end{macrocode} -% \subsection{\csh{rseq()}} -% \localtableofcontents -% -% \lverb|When func_rseq has its turn, initial segment has been scanned by -% oparen, the ; mimicking the rôle of a closing parenthesis, and stopping -% further expansion. Notice that the ; is discovered during standard parsing -% mode, it may be for example {;} or arise from expansion as rseq does not use -% a delimited macro to locate it. -% -% Here and in rrseq and iter, 1.2c adds also use of \xintthebareeval, etc...| -% \begin{macrocode} -\def\XINT_expr_func_rseq {\XINT_allexpr_rseq \xintbareeval \xintthebareeval }% -\def\XINT_flexpr_func_rseq {\XINT_allexpr_rseq \xintbarefloateval \xintthebarefloateval }% -\def\XINT_iiexpr_func_rseq {\XINT_allexpr_rseq \xintbareiieval \xintthebareiieval }% -\def\XINT_allexpr_rseq #1#2#3% +\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_rseqx\expandafter #1\expandafter#2\expandafter - #3\romannumeral`&&@\XINT_expr_onliteral_seq_a {}% + \expandafter\XINT_expr_put_op_first + \expanded{\unexpanded{{#1}}\expandafter}\romannumeral`&&@\XINT_expr_getop }% % \end{macrocode} -% \subsubsection{\csh{XINT_expr_rseqx}} -% \lverb|The (#5) is for ++ mechanism which must have its closing parenthesis.| +% \subsubsection{\cshn{seq()}: sequences from assigning values to a +% dummy variable} +% \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. +% | +% +% % \begin{macrocode} -\def\XINT_expr_rseqx #1#2#3#4#5% +\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_rseqy\romannumeral0#1(#5)\relax #3#4#2% + \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} -% \subsubsection{\csh{XINT_expr_rseqy}} -% \lverb|#1=valeurs pour variable (locked), -% #2=toutes les valeurs initiales (csv,locked), -% #3=variable, #4=expr, -% #5=\xintthebareeval ou \xintthebarefloateval ou \xintthebareiieval| +% +% \lverb|Comments undergoing reconstruction.| % \begin{macrocode} -\def\XINT_expr_rseqy #1#2#3#4#5% -{% - \expandafter \XINT_expr_getop - \csname .=\XINT_expr_unlock #2% - \expandafter\XINT_expr_rseq:_aa - \romannumeral`&&@\XINT_expr_unlock #1!{#5#4\relax !#3}#2\endcsname -}% -\def\XINT_expr_rseq:_aa #1{\if +#1\expandafter\XINT_expr_rseq:_A\else - \expandafter\XINT_expr_rseq:_a\fi #1}% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_rseq:_a} etc\dots} -% \begin{macrocode} -\def\XINT_expr_rseq:_a #1!#2#3{\XINT_expr_rseq:_b {#3}{#2}#1,^,}% -\def\XINT_expr_rseq:_b #1#2#3#4,{% - \if ,#3\xint_dothis\XINT_expr_rseq:_noop\fi - \if ^#3\xint_dothis\XINT_expr_rseq:_end\fi - \xint_orthat{\expandafter\XINT_expr_rseq:_c}\csname.=#3#4\endcsname - {#1}{#2}% -}% -\def\XINT_expr_rseq:_noop\csname.=,#1\endcsname #2#3{\XINT_expr_rseq:_b {#2}{#3}#1,}% -\def\XINT_expr_rseq:_end \csname.=^\endcsname #1#2{}% -\def\XINT_expr_rseq:_c #1#2#3% - {\expandafter\XINT_expr_rseq:_d\romannumeral`&&@#3#1~#2{#3}}% -\def\XINT_expr_rseq:_d #1{% - \if ^#1\xint_dothis\XINT_expr_rseq:_abort\fi - \if ?#1\xint_dothis\XINT_expr_rseq:_break\fi - \if !#1\xint_dothis\XINT_expr_rseq:_omit\fi - \xint_orthat{\XINT_expr_rseq:_goon #1}}% -\def\XINT_expr_rseq:_goon #1!#2#3~#4#5{,#1\expandafter\XINT_expr_rseq:_b - \romannumeral0\XINT_expr_lockit {#1}{#5}}% -\def\XINT_expr_rseq:_omit #1!#2#3~{\XINT_expr_rseq:_b }% -\def\XINT_expr_rseq:_abort #1!#2#3~#4#5#6^,{}% -\def\XINT_expr_rseq:_break #1!#2#3~#4#5#6^,{,#1}% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_rseq:_A} etc\dots} -% \lverb |n++ for rseq. With 1.2c dummy variables pick a single token.| -% \begin{macrocode} -\def\XINT_expr_rseq:_A +#1!#2#3{\XINT_expr_rseq:_D #1#3{#2}}% -\def\XINT_expr_rseq:_D #1#2#3% - {\expandafter\XINT_expr_rseq:_E\romannumeral`&&@#3#1~#2{#3}}% -\def\XINT_expr_rseq:_E #1{\if #1^\xint_dothis\XINT_expr_rseq:_Abort\fi - \if #1?\xint_dothis\XINT_expr_rseq:_Break\fi - \if #1!\xint_dothis\XINT_expr_rseq:_Omit\fi - \xint_orthat{\XINT_expr_rseq:_Goon #1}}% -\def\XINT_expr_rseq:_Goon #1!#2#3~#4#5% - {,#1\expandafter\XINT_expr_rseq:_D - \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\expandafter\endcsname - \romannumeral0\XINT_expr_lockit{#1}{#5}}% -\def\XINT_expr_rseq:_Omit #1!#2#3~%#4#5% - {\expandafter\XINT_expr_rseq:_D - \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\endcsname }% -\def\XINT_expr_rseq:_Abort #1!#2#3~#4#5{}% -\def\XINT_expr_rseq:_Break #1!#2#3~#4#5{,#1}% -% \end{macrocode} -% \subsection{\csh{iter()}} -% \localtableofcontents +\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()}} % % \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.| +% 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. +% +% | % \begin{macrocode} -\def\XINT_expr_func_iter {\XINT_allexpr_iter \xintbareeval \xintthebareeval }% -\def\XINT_flexpr_func_iter {\XINT_allexpr_iter \xintbarefloateval \xintthebarefloateval }% -\def\XINT_iiexpr_func_iter {\XINT_allexpr_iter \xintbareiieval \xintthebareiieval }% -\def\XINT_allexpr_iter #1#2#3% +\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\expandafter#2\expandafter - #3\romannumeral`&&@\XINT_expr_onliteral_seq_a {}% + \expandafter\XINT_expr_iterx + \expandafter#1\expanded{\unexpanded{{#4}}\expandafter}% + \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_iterx}} -% \lverb|The (#5) is for ++ mechanism which must have its closing parenthesis.| +\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()}} +% \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. +% | +% % \begin{macrocode} -\def\XINT_expr_iterx #1#2#3#4#5% +\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 }% +\def\XINT_allexpr_opx #1#2#3#4#5#6#7#8% {% - \expandafter\XINT_expr_itery\romannumeral0#1(#5)\relax #3#4#2% + \expandafter\XINT_expr_put_op_first + \expanded \bgroup {\iffalse}\fi + \XINT_expr_iter:_b {#1(#6)#7\relax !#5}#4^~{{#8}}\XINT_expr_cb_and_getop }% % \end{macrocode} -% \subsubsection{\csh{XINT_expr_itery}} -% \lverb|#1=valeurs pour variable (locked), -% #2=toutes les valeurs initiales (csv,locked), -% #3=variable, #4=expr, -% #5=\xintthebareeval ou \xintthebarefloateval ou \xintthebareiieval| +% \subsubsection{\cshn{rseq()}} +% +% \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. +% | % \begin{macrocode} -\def\XINT_expr_itery #1#2#3#4#5% +\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_getop - \csname .=% - \expandafter\XINT_expr_iter:_aa - \romannumeral`&&@\XINT_expr_unlock #1!{#5#4\relax !#3}#2\endcsname -}% -\def\XINT_expr_iter:_aa #1{\if +#1\expandafter\XINT_expr_iter:_A\else - \expandafter\XINT_expr_iter:_a\fi #1}% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_iter:_a} etc\dots} -% \begin{macrocode} -\def\XINT_expr_iter:_a #1!#2#3{\XINT_expr_iter:_b {#3}{#2}#1,^,}% -\def\XINT_expr_iter:_b #1#2#3#4,{% - \if ,#3\xint_dothis\XINT_expr_iter:_noop\fi - \if ^#3\xint_dothis\XINT_expr_iter:_end\fi - \xint_orthat{\expandafter\XINT_expr_iter:_c}% - \csname.=#3#4\endcsname {#1}{#2}% -}% -\def\XINT_expr_iter:_noop\csname.=,#1\endcsname #2#3{\XINT_expr_iter:_b {#2}{#3}#1,}% -\def\XINT_expr_iter:_end \csname.=^\endcsname #1#2{\XINT_expr:_unlock #1}% -\def\XINT_expr_iter:_c #1#2#3% - {\expandafter\XINT_expr_iter:_d\romannumeral`&&@#3#1~#2{#3}}% -\def\XINT_expr_iter:_d #1{% - \if ^#1\xint_dothis\XINT_expr_iter:_abort\fi - \if ?#1\xint_dothis\XINT_expr_iter:_break\fi - \if !#1\xint_dothis\XINT_expr_iter:_omit\fi - \xint_orthat{\XINT_expr_iter:_goon #1}}% -\def\XINT_expr_iter:_goon #1!#2#3~#4#5% - {\expandafter\XINT_expr_iter:_b\romannumeral0\XINT_expr_lockit {#1}{#5}}% -\def\XINT_expr_iter:_omit #1!#2#3~{\XINT_expr_iter:_b }% -\def\XINT_expr_iter:_abort #1!#2#3~#4#5#6^,{\XINT_expr_unlock #4}% -\def\XINT_expr_iter:_break #1!#2#3~#4#5#6^,{#1}% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_iter:_A} etc\dots} -% \lverb |n++ for iter. With 1.2c dummy variables pick a single token.| -% \begin{macrocode} -\def\XINT_expr_iter:_A +#1!#2#3{\XINT_expr_iter:_D #1#3{#2}}% -\def\XINT_expr_iter:_D #1#2#3% - {\expandafter\XINT_expr_iter:_E\romannumeral`&&@#3#1~#2{#3}}% -\def\XINT_expr_iter:_E #1{\if #1^\xint_dothis\XINT_expr_iter:_Abort\fi - \if #1?\xint_dothis\XINT_expr_iter:_Break\fi - \if #1!\xint_dothis\XINT_expr_iter:_Omit\fi - \xint_orthat{\XINT_expr_iter:_Goon #1}}% -\def\XINT_expr_iter:_Goon #1!#2#3~#4#5% - {\expandafter\XINT_expr_iter:_D - \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\expandafter\endcsname - \romannumeral0\XINT_expr_lockit{#1}{#5}}% -\def\XINT_expr_iter:_Omit #1!#2#3~%#4#5% - {\expandafter\XINT_expr_iter:_D - \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\endcsname }% -\def\XINT_expr_iter:_Abort #1!#2#3~#4#5{\XINT_expr:_unlock #4}% -\def\XINT_expr_iter:_Break #1!#2#3~#4#5{#1}% -% \end{macrocode} -% \subsection{\csh{rrseq()}} -% \localtableofcontents + \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()}} +% \lverb|ATTENTION! at 1.4 the @ and @1 are not synonymous anymore. One *must* use +% @1 in iterr() context.| +% \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()}} % % \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.| +% stopping further expansion. #2 = \xint_c_i and #3 are left-over trash.| % \begin{macrocode} -\def\XINT_expr_func_rrseq {\XINT_allexpr_rrseq \xintbareeval \xintthebareeval }% -\def\XINT_flexpr_func_rrseq {\XINT_allexpr_rrseq \xintbarefloateval \xintthebarefloateval }% -\def\XINT_iiexpr_func_rrseq {\XINT_allexpr_rrseq \xintbareiieval \xintthebareiieval }% -\def\XINT_allexpr_rrseq #1#2#3% +\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\expandafter#2\expandafter - #3\romannumeral`&&@\XINT_expr_onliteral_seq_a {}% + \expandafter\XINT_expr_rrseqx\expandafter#1\expanded + {\unexpanded{{#4}}{\xintRevWithBraces{#4}}\expandafter}% + \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_rrseqx}} -% \lverb|The (#5) is for ++ mechanism which must have its closing parenthesis.| -% \begin{macrocode} \def\XINT_expr_rrseqx #1#2#3#4#5% {% - \expandafter\XINT_expr_rrseqy\romannumeral0#1(#5)\expandafter\relax - \expandafter{\romannumeral0\xintapply \XINT_expr_lockit - {\xintRevWithBraces{\xintCSVtoListNonStripped{\XINT_expr_unlock #3}}}}% - #3#4#2% + \XINT:NEhook:rrseq\XINT_expr_rrseqy\romannumeral0#1(#5)\relax {#2}{#3}#4#1% }% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_rrseqy}} -% \lverb|#1=valeurs pour variable (locked), -% #2=initial values (reversed, one (braced) token each) -% #3=toutes les valeurs initiales (csv,locked), -% #4=variable, #5=expr, -% #6=\xintthebareeval ou \xintthebarefloateval ou \xintthebareiieval| -% \begin{macrocode} \def\XINT_expr_rrseqy #1#2#3#4#5#6% {% - \expandafter \XINT_expr_getop - \csname .=\XINT_expr_unlock #3% - \expandafter\XINT_expr_rrseq:_aa - \romannumeral`&&@\XINT_expr_unlock #1!{#6#5\relax !#4}{#2}\endcsname + \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?% }% -\def\XINT_expr_rrseq:_aa #1{\if +#1\expandafter\XINT_expr_rrseq:_A\else - \expandafter\XINT_expr_rrseq:_a\fi #1}% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_rrseq:_a} etc\dots} -% \lverb|Attention que ? a catcode 3 ici et dans iter.| -% \begin{macrocode} -\catcode`? 3 -\def\XINT_expr_rrseq:_a #1!#2#3{\XINT_expr_rrseq:_b {#3}{#2}#1,^,}% -\def\XINT_expr_rrseq:_b #1#2#3#4,{% - \if ,#3\xint_dothis\XINT_expr_rrseq:_noop\fi - \if ^#3\xint_dothis\XINT_expr_rrseq:_end\fi - \xint_orthat{\expandafter\XINT_expr_rrseq:_c}\csname.=#3#4\endcsname - {#1}{#2}% -}% -\def\XINT_expr_rrseq:_noop\csname.=,#1\endcsname #2#3{\XINT_expr_rrseq:_b {#2}{#3}#1,}% -\def\XINT_expr_rrseq:_end \csname.=^\endcsname #1#2{}% -\def\XINT_expr_rrseq:_c #1#2#3% - {\expandafter\XINT_expr_rrseq:_d\romannumeral`&&@#3#1~#2?{#3}}% -\def\XINT_expr_rrseq:_d #1{% - \if ^#1\xint_dothis\XINT_expr_rrseq:_abort\fi - \if ?#1\xint_dothis\XINT_expr_rrseq:_break\fi - \if !#1\xint_dothis\XINT_expr_rrseq:_omit\fi - \xint_orthat{\XINT_expr_rrseq:_goon #1}% -}% -\def\XINT_expr_rrseq:_goon #1!#2#3~#4?#5{,#1\expandafter\XINT_expr_rrseq:_b\expandafter - {\romannumeral0\xinttrim{-1}{\XINT_expr_lockit{#1}#4}}{#5}}% -\def\XINT_expr_rrseq:_omit #1!#2#3~{\XINT_expr_rrseq:_b }% -\def\XINT_expr_rrseq:_abort #1!#2#3~#4?#5#6^,{}% -\def\XINT_expr_rrseq:_break #1!#2#3~#4?#5#6^,{,#1}% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_rrseq:_A} etc\dots} -% \lverb |n++ for rrseq. With 1.2C, the #1 in \XINT_expr_rrseq:_A is a single token.| -% \begin{macrocode} -\def\XINT_expr_rrseq:_A +#1!#2#3{\XINT_expr_rrseq:_D #1{#3}{#2}}% -\def\XINT_expr_rrseq:_D #1#2#3% - {\expandafter\XINT_expr_rrseq:_E\romannumeral`&&@#3#1~#2?{#3}}% -\def\XINT_expr_rrseq:_Goon #1!#2#3~#4?#5% - {,#1\expandafter\XINT_expr_rrseq:_D - \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\expandafter\endcsname - \expandafter{\romannumeral0\xinttrim{-1}{\XINT_expr_lockit{#1}#4}}{#5}}% -\def\XINT_expr_rrseq:_Omit #1!#2#3~%#4?#5% - {\expandafter\XINT_expr_rrseq:_D - \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\endcsname}% -\def\XINT_expr_rrseq:_Abort #1!#2#3~#4?#5{}% -\def\XINT_expr_rrseq:_Break #1!#2#3~#4?#5{,#1}% -\def\XINT_expr_rrseq:_E #1{\if #1^\xint_dothis\XINT_expr_rrseq:_Abort\fi - \if #1?\xint_dothis\XINT_expr_rrseq:_Break\fi - \if #1!\xint_dothis\XINT_expr_rrseq:_Omit\fi - \xint_orthat{\XINT_expr_rrseq:_Goon #1}}% -% \end{macrocode} -% \subsection{\csh{iterr()}} -% \localtableofcontents -% \begin{macrocode} -\def\XINT_expr_func_iterr {\XINT_allexpr_iterr \xintbareeval \xintthebareeval }% -\def\XINT_flexpr_func_iterr {\XINT_allexpr_iterr \xintbarefloateval \xintthebarefloateval }% -\def\XINT_iiexpr_func_iterr {\XINT_allexpr_iterr \xintbareiieval \xintthebareiieval }% -\def\XINT_allexpr_iterr #1#2#3% -{% - \expandafter\XINT_expr_iterrx\expandafter #1\expandafter #2\expandafter - #3\romannumeral`&&@\XINT_expr_onliteral_seq_a {}% -}% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_iterrx}} -% \lverb|The (#5) is for ++ mechanism which must have its closing parenthesis.| -% \begin{macrocode} -\def\XINT_expr_iterrx #1#2#3#4#5% -{% - \expandafter\XINT_expr_iterry\romannumeral0#1(#5)\expandafter\relax - \expandafter{\romannumeral0\xintapply \XINT_expr_lockit - {\xintRevWithBraces{\xintCSVtoListNonStripped{\XINT_expr_unlock #3}}}}% - #3#4#2% -}% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_iterry}} -% \lverb|#1=valeurs pour variable (locked), -% #2=initial values (reversed, one (braced) token each) -% #3=toutes les valeurs initiales (csv,locked), -% #4=variable, #5=expr, -% #6=\xintbareeval ou \xintbarefloateval ou \xintbareiieval| -% \begin{macrocode} -\def\XINT_expr_iterry #1#2#3#4#5#6% -{% - \expandafter \XINT_expr_getop - \csname .=% - \expandafter\XINT_expr_iterr:_aa - \romannumeral`&&@\XINT_expr_unlock #1!{#6#5\relax !#4}{#2}\endcsname -}% -\def\XINT_expr_iterr:_aa #1{\if +#1\expandafter\XINT_expr_iterr:_A\else - \expandafter\XINT_expr_iterr:_a\fi #1}% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_iterr:_a} etc\dots} -% \begin{macrocode} -\def\XINT_expr_iterr:_a #1!#2#3{\XINT_expr_iterr:_b {#3}{#2}#1,^,}% -\def\XINT_expr_iterr:_b #1#2#3#4,{% - \if ,#3\xint_dothis\XINT_expr_iterr:_noop\fi - \if ^#3\xint_dothis\XINT_expr_iterr:_end\fi - \xint_orthat{\expandafter\XINT_expr_iterr:_c}% - \csname.=#3#4\endcsname {#1}{#2}% -}% -\def\XINT_expr_iterr:_noop\csname.=,#1\endcsname #2#3{\XINT_expr_iterr:_b {#2}{#3}#1,}% -\def\XINT_expr_iterr:_end \csname.=^\endcsname #1#2% - {\expandafter\xint_gobble_i\romannumeral0\xintapplyunbraced - {,\XINT_expr:_unlock}{\xintReverseOrder{#1\space}}}% -\def\XINT_expr_iterr:_c #1#2#3% - {\expandafter\XINT_expr_iterr:_d\romannumeral`&&@#3#1~#2?{#3}}% -\def\XINT_expr_iterr:_d #1{% - \if ^#1\xint_dothis\XINT_expr_iterr:_abort\fi - \if ?#1\xint_dothis\XINT_expr_iterr:_break\fi - \if !#1\xint_dothis\XINT_expr_iterr:_omit\fi - \xint_orthat{\XINT_expr_iterr:_goon #1}% -}% -\def\XINT_expr_iterr:_goon #1!#2#3~#4?#5{\expandafter\XINT_expr_iterr:_b\expandafter - {\romannumeral0\xinttrim{-1}{\XINT_expr_lockit{#1}#4}}{#5}}% -\def\XINT_expr_iterr:_omit #1!#2#3~{\XINT_expr_iterr:_b }% -\def\XINT_expr_iterr:_abort #1!#2#3~#4?#5#6^,% - {\expandafter\xint_gobble_i\romannumeral0\xintapplyunbraced - {,\XINT_expr:_unlock}{\xintReverseOrder{#4\space}}}% -\def\XINT_expr_iterr:_break #1!#2#3~#4?#5#6^,% - {\expandafter\xint_gobble_iv\romannumeral0\xintapplyunbraced - {,\XINT_expr:_unlock}{\xintReverseOrder{#4\space}},#1}% -\def\XINT_expr:_unlock #1{\XINT_expr_unlock #1}% -% \end{macrocode} -% \subsubsection{\csh{XINT_expr_iterr:_A} etc\dots} -% \lverb |n++ for iterr. ? is of catcode 3 here.| -% \begin{macrocode} -\def\XINT_expr_iterr:_A +#1!#2#3{\XINT_expr_iterr:_D #1{#3}{#2}}% -\def\XINT_expr_iterr:_D #1#2#3% - {\expandafter\XINT_expr_iterr:_E\romannumeral`&&@#3#1~#2?{#3}}% -\def\XINT_expr_iterr:_Goon #1!#2#3~#4?#5% - {\expandafter\XINT_expr_iterr:_D - \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\expandafter\endcsname - \expandafter{\romannumeral0\xinttrim{-1}{\XINT_expr_lockit{#1}#4}}{#5}}% -\def\XINT_expr_iterr:_Omit #1!#2#3~%#4?#5% - {\expandafter\XINT_expr_iterr:_D - \csname.=\the\numexpr \XINT_expr_unlock#3+\xint_c_i\endcsname}% -\def\XINT_expr_iterr:_Abort #1!#2#3~#4?#5% - {\expandafter\xint_gobble_i\romannumeral0\xintapplyunbraced - {,\XINT_expr:_unlock}{\xintReverseOrder{#4\space}}}% -\def\XINT_expr_iterr:_Break #1!#2#3~#4?#5% - {\expandafter\xint_gobble_iv\romannumeral0\xintapplyunbraced - {,\XINT_expr:_unlock}{\xintReverseOrder{#4\space}},#1}% -\def\XINT_expr_iterr:_E #1{\if #1^\xint_dothis\XINT_expr_iterr:_Abort\fi - \if #1?\xint_dothis\XINT_expr_iterr:_Break\fi - \if #1!\xint_dothis\XINT_expr_iterr:_Omit\fi - \xint_orthat{\XINT_expr_iterr:_Goon #1}}% \catcode`? 11 % \end{macrocode} -% \subsection{Macros handling csv lists for functions with multiple comma -% separated arguments in expressions} -% \localtableofcontents -% \lverb|These macros are used inside \csname...\endcsname. These things -% are not initiated by a \romannumeral in general, but in some cases they are, -% especially when involved in an \xintNewExpr. They will then be protected -% against expansion and expand only later in contexts governed by an -% initial \romannumeral-`0. There each new item may need to be expanded, which -% would not be the case in the use for the _func_ things. -% -% 1.2g adds (to be continued)| -% -% \subsubsection{\csh{xintANDof:csv}} -% \lverb|1.09a. For use by \xintexpr inside \csname. 1.1, je remplace -% ifTrueAelseB par iiNotZero pour des raisons d'optimisations.| -% \begin{macrocode} -\def\xintANDof:csv #1{\expandafter\XINT_andof:_a\romannumeral`&&@#1,,^}% -\def\XINT_andof:_a #1{\if ,#1\expandafter\XINT_andof:_e - \else\expandafter\XINT_andof:_c\fi #1}% -\def\XINT_andof:_c #1,{\xintiiifNotZero {#1}{\XINT_andof:_a}{\XINT_andof:_no}}% -\def\XINT_andof:_no #1^{0}% -\def\XINT_andof:_e #1^{1}% works with empty list -% \end{macrocode} -% \subsubsection{\csh{xintORof:csv}} -% \lverb|1.09a. For use by \xintexpr.| -% \begin{macrocode} -\def\xintORof:csv #1{\expandafter\XINT_orof:_a\romannumeral`&&@#1,,^}% -\def\XINT_orof:_a #1{\if ,#1\expandafter\XINT_orof:_e - \else\expandafter\XINT_orof:_c\fi #1}% -\def\XINT_orof:_c #1,{\xintiiifNotZero{#1}{\XINT_orof:_yes}{\XINT_orof:_a}}% -\def\XINT_orof:_yes #1^{1}% -\def\XINT_orof:_e #1^{0}% works with empty list -% \end{macrocode} -% \subsubsection{\csh{xintXORof:csv}} -% \lverb|1.09a. For use by \xintexpr (inside a \csname..\endcsname).| -% \begin{macrocode} -\def\xintXORof:csv #1{\expandafter\XINT_xorof:_a\expandafter 0\romannumeral`&&@#1,,^}% -\def\XINT_xorof:_a #1#2,{\XINT_xorof:_b #2,#1}% -\def\XINT_xorof:_b #1{\if ,#1\expandafter\XINT_xorof:_e - \else\expandafter\XINT_xorof:_c\fi #1}% -\def\XINT_xorof:_c #1,#2% - {\xintiiifNotZero {#1}{\if #20\xint_afterfi{\XINT_xorof:_a 1}% - \else\xint_afterfi{\XINT_xorof:_a 0}\fi}% - {\XINT_xorof:_a #2}% - }% -\def\XINT_xorof:_e ,#1#2^{#1}% allows empty list (then returns 0) -% \end{macrocode} -% \subsubsection{Generic csv routine (\csh{XINT_oncsv:_a})} -% \lverb|1.1. generic routine. up to the loss of some efficiency, especially -% for Sum:csv and Prod:csv, where \XINTinFloat will be done twice for each -% argument. -% -% FIXME: DOCUMENT BETTER. HOW IS THIS CALLED? WHAT IS MEANING OF ARGUMENTS? IS -% THERE ANY POST-PROCESSING OF FINAL RESULT?| -% \begin{macrocode} -\def\XINT_oncsv:_empty #1,^,#2{#2}% -\def\XINT_oncsv:_end ^,#1#2#3#4{#1}% -\def\XINT_oncsv:_a #1#2#3% - {\if ,#3\expandafter\XINT_oncsv:_empty\else\expandafter\XINT_oncsv:_b\fi #1#2#3}% -\def\XINT_oncsv:_b #1#2#3,% - {\expandafter\XINT_oncsv:_c \expandafter{\romannumeral`&&@#2{#3}}#1#2}% -\def\XINT_oncsv:_c #1#2#3#4,{\expandafter\XINT_oncsv:_d \romannumeral`&&@#4,{#1}#2#3}% -\def\XINT_oncsv:_d #1% - {\if ^#1\expandafter\XINT_oncsv:_end\else\expandafter\XINT_oncsv:_e\fi #1}% -\def\XINT_oncsv:_e #1,#2#3#4% - {\expandafter\XINT_oncsv:_c\expandafter {\romannumeral`&&@#3{#4{#1}}{#2}}#3#4}% -% \end{macrocode} -% \subsubsection{\csh{xintMaxof:csv}, \csh{xintiiMaxof:csv}} -% \lverb|1.09i. Rewritten for 1.1. Compatible avec liste vide donnant valeur par -% défaut. Pas compatible avec items manquants. -% ah je m'aperçois au dernier moment que je n'ai pas en effet de \xintiiMax. -% Je devrais le rajouter. En tout cas ici c'est uniquement pour xintiiexpr, -% dans il faut bien sûr ne pas faire de xintNum, donc il faut un iimax.| -% \begin{macrocode} -\def\xintMaxof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintmax - \expandafter\xint_firstofone\romannumeral`&&@#1,^,{0/1[0]}}% -\def\xintiiMaxof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintiimax - \expandafter\xint_firstofone\romannumeral`&&@#1,^,0}% -% \end{macrocode} -% \subsubsection{\csh{xintMinof:csv}, \csh{xintiiMinof:csv}} -% \lverb|1.09i. Rewritten for 1.1. For use by \xintiiexpr.| -% \begin{macrocode} -\def\xintMinof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintmin - \expandafter\xint_firstofone\romannumeral`&&@#1,^,{0/1[0]}}% -\def\xintiiMinof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintiimin - \expandafter\xint_firstofone\romannumeral`&&@#1,^,0}% -% \end{macrocode} -% \subsubsection{\csh{xintSum:csv}, \csh{xintiiSum:csv}} -% \lverb|1.09a. Rewritten for 1.1. For use by \xintexpr.| -% \begin{macrocode} -\def\xintSum:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintadd - \expandafter\xint_firstofone\romannumeral`&&@#1,^,{0/1[0]}}% -\def\xintiiSum:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintiiadd - \expandafter\xint_firstofone\romannumeral`&&@#1,^,0}% -% \end{macrocode} -% \subsubsection{\csh{xintPrd:csv}, \csh{xintiiPrd:csv}} -% \lverb|1.09a. Rewritten for 1.1. For use by \xintexpr.| -% \begin{macrocode} -\def\xintPrd:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintmul - \expandafter\xint_firstofone\romannumeral`&&@#1,^,{1/1[0]}}% -\def\xintiiPrd:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintiimul - \expandafter\xint_firstofone\romannumeral`&&@#1,^,1}% -% \end{macrocode} -% \subsubsection{\csh{xintGCDof:csv}, \csh{xintLCMof:csv}} -% \changed{1.09a}{} -% Non-integer arguments are replaced by integers as |\xintGCD| and |\xintLCM| -% apply |\xintNum|. -% \changed{1.1}{} -% As with other "csv" macros, the (list) argument needs to be expanded in case -% it arises within a macro created from \csbxint{NewExpr}. -% \changed{1.3d}{} -% No more usage of the integer-only \xintgcdnameimp macros, replaced by direct -% coding here, in order to extend scope to fractions (and produce fractions). -% Hesitation about allowing empty input, and what to return then. -% \begin{macrocode} -\def\xintGCDof:csv #1{\expandafter\XINT_gcdof:_a\romannumeral`&&@#1,^,{1/1[0]}}% -\def\XINT_gcdof:_a #1% - {\if ,#1\expandafter\XINT_oncsv:_empty\else\expandafter\XINT_gcdof:_b\fi #1}% -% \end{macrocode} -% This abuses the way |\xintiiabs| works in order to avoid fetching whole -% argument again. +% \subsection{Pseudo-functions related to N-dimensional hypercubic lists} +% \subsubsection{\cshn{ndseq()}} +% \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 !| % \begin{macrocode} -\def\XINT_gcdof:_b #1,% - {\expandafter\XINT_gcdof:_c\romannumeral0\xintiiabs#1\xint:}% -\def\XINT_gcdof:_c #1\xint:#2,% - {\expandafter\XINT_gcdof:_d\romannumeral0\xintiiabs#2\xint:#1\xint:}% -\def\XINT_gcdof:_d #1% - {\if ^#1\expandafter\XINT_gcdof:_end\else\expandafter\XINT_gcdof:_e\fi #1}% -% \end{macrocode} -% \lverb|\xintMod will apply \xintRaw on its arguments, and will output in -% normalized format. But in exceptional case with a one-item or one item and -% then zeros, the output is (absolute value of) this item, not necessarily in -% A/B[N] format.| -% \begin{macrocode} -\def\XINT_gcdof:_e#1#2\xint:#3\xint: +\def\XINT_expr_onliteral_ndseq {% - \if0#1\expandafter\XINT_gcdof:_f\fi - \expandafter\XINT_gcdof:_e\romannumeral0\xintmod{#3}{#1#2}\xint:#1#2\xint: + \expandafter\XINT_allexpr_ndseq_f + \romannumeral`&&@\XINT_expr_fetch_E_comma_V_equal_E_a {}% }% -\def\XINT_gcdof:_f - \expandafter\XINT_gcdof:_e\romannumeral0\xintmod#1#2\xint:#3\xint:#4,% +\def\XINT_allexpr_ndseq_f #1#2{\xint_c_ii^v `{ndseqx}#2)\relax #1}% +\def\XINT_expr_func_ndseqx {% - \expandafter\XINT_gcdof:_d\romannumeral0\xintiiabs#4\xint:#1\xint: + \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} -% \lverb|As for others :csv macros here expansion in the case of \xintNewExpr -% crafted macros is triggered by (an equivalent to) \romannumeral-`0. Else it -% happens inside \csname...\endcsname, and there is no triggering -% \romannumeral, attention to not leave a space upfront.| -% \begin{macrocode} -\def\XINT_gcdof:_end ^\xint:#1\xint:#2{#1}% -% \end{macrocode} -% \lverb|For least common multiple, we will use \xintInv, but this requires to -% make sure fractional input is in raw format.| +% \lverb| +% #1 = \xintbareeval, or \xintbarefloateval or \xintbareiieval +% #2 = values for last coordinate +% | % \begin{macrocode} -\def\xintLCMof:csv #1{\expandafter\XINT_lcmof:_a\romannumeral`&&@#1,^,{0/1[0]}}% -\def\XINT_lcmof:_a #1% - {\if ,#1\expandafter\XINT_oncsv:_empty\else\expandafter\XINT_lcmof:_b\fi #1}% -\def\XINT_lcmof:_b #1,% - {\expandafter\XINT_lcmof:_c\romannumeral0\xintiiabs\xintRaw{#1}\xint:}% -\def\XINT_lcmof:_c #1{\if0#1\expandafter\XINT_lcmof:_zero\fi - \expandafter\XINT_lcmof:_d\romannumeral0\XINT_inv #1}% +\def\XINT_allexpr_ndseq_C #1#2{{#2}\iffalse{{{\fi}}}}% % \end{macrocode} -% \lverb|We can do \xintiiabs^, but \xintiiabs\xintRaw{^} would throw -% an error. So we need to delay applying \xintRaw to new item.| +% \lverb| +% #1 = \xintbareeval or \xintbarefloateval or \xintbareiieval +% #2 = {valuesN}...{values2}{var2}{values1} +% #3 = {var1} +% #4 = the expression to evaluate +% | % \begin{macrocode} -\def\XINT_lcmof:_d #1\xint:#2,% - {\expandafter\XINT_lcmof:_e\romannumeral0\xintiiabs#2\xint:#1\xint:}% -\def\XINT_lcmof:_e #1% - {\if ^#1\expandafter\XINT_lcmof:_end\else\expandafter\XINT_lcmof:_f\fi #1}% +\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} -% \lverb|As soon as we hit against a zero item, the l.c.m is known to be zero -% itself. Else we need to inverse it, but this requires full A/B[N] raw format, -% hence the \xintraw.| +% \subsubsection{\cshn{ndmap()}} +% \lverb|New with 1.4. 2020/01/24.| % \begin{macrocode} -\def\XINT_lcmof:_f#1#2\xint: +\def\XINT_expr_onliteral_ndmap #1,{\xint_c_ii^v `{ndmapx}\XINTfstop.{#1};}% +\def\XINT_expr_func_ndmapx #1#2#3% {% - \if0#1\expandafter\XINT_lcmof:_zero\fi - \expandafter\XINT_lcmof:_g\romannumeral0\expandafter\XINT_inv - \romannumeral0\xintraw{#1#2}\xint: + \expandafter\XINT_allexpr_ndmapx + \csname XINT_expr_func_\xint_zapspaces #3 \xint_gobble_i\endcsname + \XINT_expr_oparen }% -\def\XINT_lcmof:_g #1#2\xint:#3\xint: +\def\XINT_flexpr_func_ndmapx #1#2#3% {% - \if0#1\expandafter\XINT_lcmof:_h\fi - \expandafter\XINT_lcmof:_g\romannumeral0\xintmod{#3}{#1#2}\xint:#1#2\xint: + \expandafter\XINT_allexpr_ndmapx + \csname XINT_flexpr_func_\xint_zapspaces #3 \xint_gobble_i\endcsname + \XINT_flexpr_oparen }% -\def\XINT_lcmof:_h - \expandafter\XINT_lcmof:_g\romannumeral0\xintmod#1#2\xint:#3\xint:#4,% +\def\XINT_iiexpr_func_ndmapx #1#2#3% {% - \expandafter\XINT_lcmof:_e\romannumeral0\xintiiabs#4\xint:#1\xint: + \expandafter\XINT_allexpr_ndmapx + \csname XINT_iiexpr_func_\xint_zapspaces #3 \xint_gobble_i\endcsname + \XINT_iiexpr_oparen }% -\def\XINT_lcmof:_zero #1^,#2{0/1[0]}% -% \end{macrocode} -% \lverb|We need this \romannumeral0 to remove the up-front space token which -% will be left by \XINT_inv, in case of \csname..\endcsname expansion.| -% \begin{macrocode} -\def\XINT_lcmof:_end ^\xint:#1\xint:#2{\romannumeral0\XINT_inv #1}% -% \end{macrocode} -% \subsubsection{\csh{xintiiGCDof:csv}, \csh{xintiiLCMof:csv}} -% \changed{1.1a}{} -% For \csbxint{iiexpr}. Requires the \xintgcdnameimp provided macros. -% \begin{macrocode} -\def\xintiiGCDof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintiigcd - \expandafter\xint_firstofone\romannumeral`&&@#1,^,1}% -\def\xintiiLCMof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintiilcm - \expandafter\xint_firstofone\romannumeral`&&@#1,^,0}% +\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{\csh{XINTinFloatdigits}, \csh{XINTinFloatSqrtdigits}, -% \csh{XINTinFloatFacdigits}, \csh{XINTiLogTendigits}} -% \lverb|For \xintNewExpr matters, mainly. +% \subsubsection{\cshn{ndfillraw()}} +% \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. % -% At 1.3e I add \XINTinFloatSdigits and use it at various places. I also modified -% \XINTinFloatFac to use S(hort) output format. +% Pour des choses comme ndfillraw(\xintRandomBit,[10,10]). % -% Also added \XINTiLogTendigits| -% \begin{macrocode} -\def\XINTinFloatdigits {\XINTinFloat [\XINTdigits]}% -\def\XINTinFloatSdigits {\XINTinFloatS [\XINTdigits]}% -\def\XINTinFloatSqrtdigits {\XINTinFloatSqrt[\XINTdigits]}% -\def\XINTinFloatFacdigits {\XINTinFloatFac [\XINTdigits]}% -\def\XINTFloatiLogTendigits{\XINTFloatiLogTen[\XINTdigits]}% -% \end{macrocode} -% \subsubsection{\csh{XINTinFloatMaxof:csv}, \csh{XINTinFloatMinof:csv}} -% \lverb|1.09a. Rewritten for 1.1. For use by \xintfloatexpr. Name changed in -% 1.09h. Changed at 1.3e to use \XINTinFloatSdigits.| +% 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. +% | % \begin{macrocode} -\def\XINTinFloatMaxof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintmax - \expandafter\XINTinFloatSdigits\romannumeral`&&@#1,^,{0[0]}}% -\def\XINTinFloatMinof:csv #1{\expandafter\XINT_oncsv:_a\expandafter\xintmin - \expandafter\XINTinFloatSdigits\romannumeral`&&@#1,^,{0[0]}}% +\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} -% \subsubsection{\csh{XINTinFloatSum:csv}, \csh{XINTinFloatPrd:csv}} -% \lverb|1.09a. Rewritten for 1.1. For use by \xintfloatexpr. Modified at 1.3e -% to use \XINTinFloatSdigits.| +% \subsection{Other pseudo-functions: \cshn{bool()}, \cshn{togl()}, \cshn{protect()}, +% \cshn{qraw()}, \cshn{qint()}, \cshn{qfrac()}, \cshn{qfloat()}, \cshn{qrand()}, +% \cshn{random()}, \cshn{rbit()}} +% +% \lverb|bool, togl and protect use delimited macros. They are not true +% functions, they turn off the parser to gather their "variable".| +% +% \changed{1.2}{} adds |qint()|, |qfrac()|, |qfloat()|. +% +% \changed{1.3c}{} adds |qraw()|. Useful to limit impact on \TeX{} memory +% from abuse of |\csname|'s storage when generating many comma separated +% values from a loop. +% +% \changed{1.3e}{} |qfloat()| keeps a short mantissa if possible. +% +% \lverb|They allow the user to hand over quickly a big number to the parser, +% spaces not immediately removed but should be harmless in general. The qraw() +% does no post-processing at all apart complete expansion, useful for +% comma-separated values, but must be obedient to (non really documented) +% expected format. Each uses a delimited macro, the closing parenthesis can +% not emerge from expansion.| +% +% \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.| +% +% \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. +% | % \begin{macrocode} -\def\XINTinFloatSum:csv #1{\expandafter\XINT_oncsv:_a\expandafter\XINTinfloatadd - \expandafter\XINTinFloatSdigits\romannumeral`&&@#1,^,{0[0]}}% -\def\XINTinFloatPrd:csv #1{\expandafter\XINT_oncsv:_a\expandafter\XINTinfloatmul - \expandafter\XINTinFloatSdigits\romannumeral`&&@#1,^,{1[0]}}% +\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} -% \subsection{Auxiliary wrappers for function macros} +% \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} +% {quo}{rem}{gcd}{lcm}{max}{min} +% {`+`}{`*`} +% {all}{any}{xor} +% {len}{first}{last}{reversed} +% {if}{ifint}{ifone}{ifsgn} +% {nuple}}} +% and \noexpand\cshn{unpack()}} +% \expandafter\subsection\expandafter{\zzz} % \begin{macrocode} -\def\XINT:expr:one:and:opt #1,#2,#3!#4#5% +\def\XINT:expr:f:one:and:opt #1#2#3!#4#5% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else - \expandafter\xint_secondoftwo\fi + \expandafter\xint_secondoftwo\fi {#4}{#5[\xintNum{#2}]}{#1}% }% -\def\XINT:expr:tacitzeroifonearg #1,#2,#3!#4#5% +\def\XINT:expr:f:tacitzeroifone #1#2#3!#4#5% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else - \expandafter\xint_secondoftwo\fi + \expandafter\xint_secondoftwo\fi {#4{0}}{#5{\xintNum{#2}}}{#1}% }% -\def\XINT:iiexpr:tacitzeroifonearg #1,#2,#3!#4% +\def\XINT:expr:f:iitacitzeroifone #1#2#3!#4% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else - \expandafter\xint_secondoftwo\fi + \expandafter\xint_secondoftwo\fi {#4{0}}{#4{#2}}{#1}% }% -\def\XINT:expr:totwo #1#2{#1,#2}% -\def\XINT:expr:two:to:two #1,#2,!#3% -{% - \expandafter\XINT:expr:totwo\romannumeral`&&@#3{#1}{#2}% -}% -\let\XINT:flexpr:two:to:two\XINT:expr:two:to:two -\let\XINT:iiexpr:two:to:two\XINT:expr:two:to:two -% \end{macrocode} -% \def\auxiliarymacro#1{ \noexpand\cshn{#1()}} -% \edef\zzz{The \xintListWithSep{, }{\xintApply\auxiliarymacro -% {{num}{reduce}{preduce}{abs}{sgn}{frac}{floor}{ceil}{sqr}{sqrt}{sqrtr}{float} -% {sfloat}{ilog10}{inv}{round}{trunc}{mod}{quo}{rem}{divmod}{gcd}{lcm}{max}{min} -% {`+`} -% {`*`} -% {?}{!}{not}{all}{any}{xor}{if}{ifsgn}{ifint}{ifone}{even}{odd}{isint}{isone} -% {first}{last}{len}{reversed}{factorial}{binomial}}} -% and \noexpand\cshn{randrange()} functions} -% \expandafter\subsection\expandafter{\zzz} -% \begin{macrocode} \def\XINT_expr_func_num #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:one\xintNum{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintIrr{\XINT_expr_unlock #3}[0]\endcsname + \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\csname.=% - \XINT:NEhook:one\xintPIrr{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintAbs{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintiiAbs{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintSgn{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintiiSgn{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintTFrac{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\XINTinFloatFracdigits{\XINT_expr_unlock #3}\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:one + {\romannumeral`&&@\XINTinFloatFracdigits#3}}% }% % \end{macrocode} % \lverb|no \XINT_iiexpr_func_frac| % \begin{macrocode} \def\XINT_expr_func_floor #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:one\xintFloor{\XINT_expr_unlock #3}\endcsname + \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} @@ -37974,182 +38690,206 @@ math shift catcode. % \begin{macrocode} \def\XINT_iiexpr_func_floor #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:one\xintiFloor{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintCeil{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintiCeil{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintSqr{\XINT_expr_unlock #3}\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:one + {\romannumeral`&&@\xintSqr#3}}% }% -\def\XINTinFloatSqr#1{\XINTinFloatMul{#1}{#1}}% revoir après +\def\XINTinFloatSqr#1{\XINTinFloatMul{#1}{#1}}% \def\XINT_flexpr_func_sqr #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:one\XINTinFloatSqr{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintiiSqr{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintiiIsNotZero{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintiiIsZero{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintiiIsZero{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintOdd{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintiiOdd{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintEven{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintiiEven{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintIsInt{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintFloatIsInt{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintIsOne{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintiiIsOne{\XINT_expr_unlock #3}\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:one + {\romannumeral`&&@\xintiiIsOne#3}}% }% -% REVOIR nuple -\def\XINT_expr_func_nuple #1#2#3% - {\expandafter #1\expandafter #2\csname.=\XINT_expr_unlock #3\endcsname }% -\let\XINT_flexpr_func_nuple\XINT_expr_func_nuple -\let\XINT_iiexpr_func_nuple\XINT_expr_func_nuple \def\XINT_expr_func_factorial #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\XINT:expr:one:and:opt - \romannumeral`&&@\XINT_expr_unlock#3,,!\xintFac\XINTinFloatFac - \endcsname + \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\csname.=% - \expandafter\XINT:expr:one:and:opt - \romannumeral`&&@\XINT_expr_unlock#3,,!\XINTinFloatFacdigits\XINTinFloatFac - \endcsname + \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\csname.=% - \XINT:NEhook:one\xintiiFac{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \expandafter\XINT:expr:one:and:opt - \romannumeral`&&@\XINT_expr_unlock#3,,!\XINTinFloatSqrtdigits\XINTinFloatSqrt - \endcsname + \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_expr_func_sqrt_ #1#2#3% +{% + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:one + {\romannumeral`&&@\XINTinFloatSqrtdigits#3}}% +}% +\let\XINT_flexpr_func_sqrt_\XINT_expr_func_sqrt_ \def\XINT_iiexpr_func_sqrt #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:one\xintiiSqrt{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintiiSqrtR{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintInv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\XINTinFloatInv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \expandafter\XINT:expr:tacitzeroifonearg - \romannumeral`&&@\XINT_expr_unlock #3,,!\xintiRound\xintRound - \endcsname + \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\csname.=% - \expandafter\XINT:iiexpr:tacitzeroifonearg - \romannumeral`&&@\XINT_expr_unlock #3,,!\xintiRound - \endcsname + \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\csname.=% - \expandafter\XINT:expr:tacitzeroifonearg - \romannumeral`&&@\XINT_expr_unlock #3,,!\xintiTrunc\xintTrunc - \endcsname + \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\csname.=% - \expandafter\XINT:iiexpr:tacitzeroifonearg - \romannumeral`&&@\XINT_expr_unlock #3,,!\xintiTrunc - \endcsname + \expandafter #1\expandafter #2\expandafter{\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:iitacitzeroifone:direct + \XINT:expr:f:iitacitzeroifone #3,!\xintiTrunc + }}% }% % \end{macrocode} % \lverb|Hesitation at 1.3e about using \XINTinFloatSdigits and \XINTinFloatS. @@ -38157,500 +38897,447 @@ math shift catcode. % \begin{macrocode} \def\XINT_expr_func_float #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\XINT:expr:one:and:opt - \romannumeral`&&@\XINT_expr_unlock #3,,!\XINTinFloatdigits\XINTinFloat - \endcsname + \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} +% \lverb|float_() added at 1.4. Does not check for optional argument. Useful +% to transfer functions defined with \xintdeffunc to functions usable in +% \xintfloateval. I hesitated briefly about notation but here we go. +% Unfortunately I will have to document it (contrarily to sqrt_). +% +% No need to do same for sfloat() currently used in xinttrig.sty to go from +% float to expr, because sfloat(x) sees there is no optional argument. +% +% Still I wonder if better would not be to have some function «single()» which +% signals to outer one it is a single argument? Must think about this. Too +% late now for 1.4.| +% \begin{macrocode} +\def\XINT_expr_func_float_ #1#2#3% +{% + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:one + {\romannumeral`&&@\XINTinFloatdigits#3}}% +}% +\let\XINT_flexpr_func_float_\XINT_expr_func_float_ \def\XINT_expr_func_sfloat #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\XINT:expr:one:and:opt - \romannumeral`&&@\XINT_expr_unlock #3,,!\XINTinFloatSdigits\XINTinFloatS - \endcsname + \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 % \XINT_iiexpr_func_sfloat not defined \expandafter\def\csname XINT_expr_func_ilog10\endcsname #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\XINT:expr:one:and:opt - \romannumeral`&&@\XINT_expr_unlock #3,,!\xintiLogTen\XINTFloatiLogTen - \endcsname + \expandafter #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\csname.=% - \expandafter\XINT:expr:one:and:opt - \romannumeral`&&@\XINT_expr_unlock #3,,!\XINTFloatiLogTendigits\XINTFloatiLogTen - \endcsname + \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\csname.=% - \XINT:NEhook:one\xintiiLogTen{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \expandafter\XINT:expr:two:to:two - \romannumeral`&&@\XINT_expr_unlock #3,!\xintDivMod - \endcsname + \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% + \XINT:NEhook:f:one:from:two + {\romannumeral`&&@\xintDivMod #3}}% }% -% \end{macrocode} -% \lverb|\XINTinFloatDivMod a un output déjà comma separated| -% \begin{macrocode} \def\XINT_flexpr_func_divmod #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\XINTinFloatDivMod - \endcsname + \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\csname.=% - \expandafter\XINT:expr:two:to:two - \romannumeral`&&@\XINT_expr_unlock #3,!\xintiiDivMod - \endcsname + \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\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\xintMod - \endcsname + \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\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\XINTinFloatMod - \endcsname + \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\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\xintiiMod - \endcsname + \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\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\xintBinomial - \endcsname + \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\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\XINTinFloatBinomial - \endcsname + \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\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\xintiiBinomial - \endcsname + \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\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\xintPFactorial - \endcsname + \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\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\XINTinFloatPFactorial - \endcsname + \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\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\xintiiPFactorial - \endcsname + \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\csname.=% - \expandafter\XINT:expr:randrange - \romannumeral`&&@\XINT_expr_unlock #3,,!% - \endcsname + \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\csname.=% - \expandafter\XINT:iiexpr:randrange - \romannumeral`&&@\XINT_expr_unlock #3,,!% - \endcsname + \expandafter #1\expandafter #2\expanded{{{% + \XINT:iiexpr:randrange #3,!% + }}}% }% -\def\XINT:expr:randrange #1,#2,#3!% +\def\XINT:expr:randrange #1#2#3!% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi - {\xintiiRandRange{\XINT:NEhook:one\xintNum{#1}}}% - {\xintiiRandRangeAtoB{\XINT:NEhook:one\xintNum{#1}}% - {\XINT:NEhook:one\xintNum{#2}}}% + {\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!% +\def\XINT:iiexpr:randrange #1#2#3!% {% \if\relax#3\relax\expandafter\xint_firstoftwo\else \expandafter\xint_secondoftwo\fi - {\xintiiRandRange{#1}}{\xintiiRandRangeAtoB{#1}{#2}}% + {\xintiiRandRange{#1}}% + {\xintiiRandRangeAtoB{#1}{#2}}% }% \def\XINT_expr_func_quo #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\xintiQuo - \endcsname + \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% + \XINT:NEhook:f:one:from:two + {\romannumeral`&&@\xintiQuo #3}}% }% \let\XINT_flexpr_func_quo\XINT_expr_func_quo \def\XINT_iiexpr_func_quo #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\xintiiQuo - \endcsname + \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% + \XINT:NEhook:f:one:from:two + {\romannumeral`&&@\xintiiQuo #3}}% }% \def\XINT_expr_func_rem #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\xintiRem - \endcsname + \expandafter #1\expandafter #2\expandafter{\romannumeral`&&@% + \XINT:NEhook:f:one:from:two + {\romannumeral`&&@\xintiRem #3}}% }% \let\XINT_flexpr_func_rem\XINT_expr_func_rem \def\XINT_iiexpr_func_rem #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\xintiiRem - \endcsname + \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\csname.=% - \XINT:NEhook:csv\xintGCDof:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintiiGCDof:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintLCMof:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintiiLCMof:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintMaxof:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintiiMaxof:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\XINTinFloatMaxof:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintMinof:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintiiMinof:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\XINTinFloatMinof:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintSum:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\XINTinFloatSum:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintiiSum:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintPrd:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\XINTinFloatPrd:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintiiPrd:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintANDof:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintORof:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintXORof:csv{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:csv\xintLength:f:csv{\XINT_expr_unlock#3}\endcsname + \expandafter#1\expandafter#2\expandafter{\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:noeval:from:braced:u\xintLength#3^% + }}% }% \let\XINT_flexpr_func_len \XINT_expr_func_len \let\XINT_iiexpr_func_len \XINT_expr_func_len -% \end{macrocode} -% \lverb|1.2k has \xintFirstItem:f:csv for improved -% \xintNewExpr compatibility.| -% \begin{macrocode} \def\XINT_expr_func_first #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:csv\xintFirstItem:f:csv{\XINT_expr_unlock #3}\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:noeval:from:braced:u\xintFirstOne#3^% + }% }% \let\XINT_flexpr_func_first\XINT_expr_func_first \let\XINT_iiexpr_func_first\XINT_expr_func_first -% \end{macrocode} -% \lverb|1.2k has \xintLastItem:f:csv for efficiency and improved -% \xintNewExpr compatibility.| -% \begin{macrocode} \def\XINT_expr_func_last #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:csv\xintLastItem:f:csv{\XINT_expr_unlock #3}\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:noeval:from:braced:u\xintLastOne#3^% + }% }% \let\XINT_flexpr_func_last\XINT_expr_func_last \let\XINT_iiexpr_func_last\XINT_expr_func_last -% \end{macrocode} -% \lverb|1.2c I hesitated but left the function "reversed" from 1.1 with -% this name, not "reverse". But the inner not public macro got renamed -% into \xintReverse::csv. 1.2g opts for the name \xintReverse:f:csv, and -% rewrites it for direct handling of csv lists. 2016/03/17.| -% \begin{macrocode} \def\XINT_expr_func_reversed #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:csv\xintReverse:f:csv{\XINT_expr_unlock #3}\endcsname + \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\xintiiifNotZero: #1,#2,#3,{\xintiiifNotZero{#1}{#2}{#3}}% \def\XINT_expr_func_if #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\xintiiifNotZero:% - \romannumeral`&&@\XINT_expr_unlock #3,\endcsname + \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\xintifInt: #1,#2,#3,{\xintifInt{#1}{#2}{#3}}% \def\XINT_expr_func_ifint #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\xintifInt:% - \romannumeral`&&@\XINT_expr_unlock #3,\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\xintifInt #3}}% }% \let\XINT_iiexpr_func_ifint\XINT_expr_func_ifint -\def\xintifFloatInt: #1,#2,#3,{\xintifFloatInt{#1}{#2}{#3}}% \def\XINT_flexpr_func_ifint #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\xintifFloatInt:% - \romannumeral`&&@\XINT_expr_unlock #3,\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\xintifFloatInt #3}}% }% -\def\xintifOne: #1,#2,#3,{\xintifOne{#1}{#2}{#3}}% \def\XINT_expr_func_ifone #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\xintifOne:% - \romannumeral`&&@\XINT_expr_unlock #3,\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\xintifOne #3}}% }% \let\XINT_flexpr_func_ifone\XINT_expr_func_ifone -\def\xintiiifOne: #1,#2,#3,{\xintiiifOne{#1}{#2}{#3}}% \def\XINT_iiexpr_func_ifone #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\xintiiifOne:% - \romannumeral`&&@\XINT_expr_unlock #3,\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:branch{\romannumeral`&&@\xintiiifOne #3}}% }% -\def\xintiiifSgn: #1,#2,#3,#4,{\xintiiifSgn{#1}{#2}{#3}{#4}}% \def\XINT_expr_func_ifsgn #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\xintiiifSgn:% - \romannumeral`&&@\XINT_expr_unlock #3,\endcsname + \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 % \end{macrocode} -% \subsection{f-expandable versions of the \cshnolabel{xintSeqB::csv} and alike -% routines, for \cshnolabel{xintNewExpr}} +% \subsection{User declared functions} +% \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. +% | +% % \localtableofcontents -% \subsubsection{\csh{xintSeqB:f:csv}} -% \lverb|Produces in f-expandable way. If the step is zero, gives empty result -% except if start and end coincide.| -% \begin{macrocode} -\def\xintSeqB:f:csv #1#2% - {\expandafter\XINT_seqb:f:csv \expandafter{\romannumeral0\xintraw{#2}}{#1}}% -\def\XINT_seqb:f:csv #1#2{\expandafter\XINT_seqb:f:csv_a\romannumeral`&&@#2#1!}% -\def\XINT_seqb:f:csv_a #1#2;#3;#4!{% - \expandafter\xint_gobble_i\romannumeral`&&@% - \xintifCmp {#3}{#4}\XINT_seqb:f:csv_bl\XINT_seqb:f:csv_be\XINT_seqb:f:csv_bg - #1{#3}{#4}{}{#2}}% -\def\XINT_seqb:f:csv_be #1#2#3#4#5{,#2}% -\def\XINT_seqb:f:csv_bl #1{\if #1p\expandafter\XINT_seqb:f:csv_pa\else - \xint_afterfi{\expandafter,\xint_gobble_iv}\fi }% -\def\XINT_seqb:f:csv_pa #1#2#3#4{\expandafter\XINT_seqb:f:csv_p\expandafter - {\romannumeral0\xintadd{#4}{#1}}{#2}{#3,#1}{#4}}% -\def\XINT_seqb:f:csv_p #1#2% -{% - \xintifCmp {#1}{#2}\XINT_seqb:f:csv_pa\XINT_seqb:f:csv_pb\XINT_seqb:f:csv_pc - {#1}{#2}% -}% -\def\XINT_seqb:f:csv_pb #1#2#3#4{#3,#1}% -\def\XINT_seqb:f:csv_pc #1#2#3#4{#3}% -\def\XINT_seqb:f:csv_bg #1{\if #1n\expandafter\XINT_seqb:f:csv_na\else - \xint_afterfi{\expandafter,\xint_gobble_iv}\fi }% -\def\XINT_seqb:f:csv_na #1#2#3#4{\expandafter\XINT_seqb:f:csv_n\expandafter - {\romannumeral0\xintadd{#4}{#1}}{#2}{#3,#1}{#4}}% -\def\XINT_seqb:f:csv_n #1#2% -{% - \xintifCmp {#1}{#2}\XINT_seqb:f:csv_nc\XINT_seqb:f:csv_nb\XINT_seqb:f:csv_na - {#1}{#2}% -}% -\def\XINT_seqb:f:csv_nb #1#2#3#4{#3,#1}% -\def\XINT_seqb:f:csv_nc #1#2#3#4{#3}% -% \end{macrocode} -%\subsubsection{\csh{xintiiSeqB:f:csv}} -% \lverb|Produces in f-expandable way. If the step is zero, gives empty result -% except if start and end coincide. -% -% 2015/11/11. I correct a typo dating back to release 1.1 (2014/10/29): the -% macro name had a "b" rather than "B", hence was not functional (causing -% \xintNewIIExpr to fail on inputs such as #1..[1]..#2).| -% \begin{macrocode} -\def\xintiiSeqB:f:csv #1#2% - {\expandafter\XINT_iiseqb:f:csv \expandafter{\romannumeral`&&@#2}{#1}}% -\def\XINT_iiseqb:f:csv #1#2{\expandafter\XINT_iiseqb:f:csv_a\romannumeral`&&@#2#1!}% -\def\XINT_iiseqb:f:csv_a #1#2;#3;#4!{% - \expandafter\xint_gobble_i\romannumeral`&&@% - \xintSgnFork{\XINT_Cmp {#3}{#4}}% - \XINT_iiseqb:f:csv_bl\XINT_seqb:f:csv_be\XINT_iiseqb:f:csv_bg - #1{#3}{#4}{}{#2}}% -\def\XINT_iiseqb:f:csv_bl #1{\if #1p\expandafter\XINT_iiseqb:f:csv_pa\else - \xint_afterfi{\expandafter,\xint_gobble_iv}\fi }% -\def\XINT_iiseqb:f:csv_pa #1#2#3#4{\expandafter\XINT_iiseqb:f:csv_p\expandafter - {\romannumeral0\xintiiadd{#4}{#1}}{#2}{#3,#1}{#4}}% -\def\XINT_iiseqb:f:csv_p #1#2% -{% - \xintSgnFork{\XINT_Cmp {#1}{#2}}% - \XINT_iiseqb:f:csv_pa\XINT_iiseqb:f:csv_pb\XINT_iiseqb:f:csv_pc {#1}{#2}% -}% -\def\XINT_iiseqb:f:csv_pb #1#2#3#4{#3,#1}% -\def\XINT_iiseqb:f:csv_pc #1#2#3#4{#3}% -\def\XINT_iiseqb:f:csv_bg #1{\if #1n\expandafter\XINT_iiseqb:f:csv_na\else - \xint_afterfi{\expandafter,\xint_gobble_iv}\fi }% -\def\XINT_iiseqb:f:csv_na #1#2#3#4{\expandafter\XINT_iiseqb:f:csv_n\expandafter - {\romannumeral0\xintiiadd{#4}{#1}}{#2}{#3,#1}{#4}}% -\def\XINT_iiseqb:f:csv_n #1#2% -{% - \xintSgnFork{\XINT_Cmp {#1}{#2}}% - \XINT_seqb:f:csv_nc\XINT_seqb:f:csv_nb\XINT_iiseqb:f:csv_na {#1}{#2}% -}% -% \end{macrocode} -%\subsubsection{\csh{XINTinFloatSeqB:f:csv}} -% \lverb|Produces in f-expandable way. If the step is zero, gives empty result -% except if start and end coincide. This is all for \xintNewExpr.| -% \begin{macrocode} -\def\XINTinFloatSeqB:f:csv #1#2{\expandafter\XINT_flseqb:f:csv \expandafter - {\romannumeral0\XINTinfloat [\XINTdigits]{#2}}{#1}}% -\def\XINT_flseqb:f:csv #1#2{\expandafter\XINT_flseqb:f:csv_a\romannumeral`&&@#2#1!}% -\def\XINT_flseqb:f:csv_a #1#2;#3;#4!{% - \expandafter\xint_gobble_i\romannumeral`&&@% - \xintifCmp {#3}{#4}\XINT_flseqb:f:csv_bl\XINT_seqb:f:csv_be\XINT_flseqb:f:csv_bg - #1{#3}{#4}{}{#2}}% -\def\XINT_flseqb:f:csv_bl #1{\if #1p\expandafter\XINT_flseqb:f:csv_pa\else - \xint_afterfi{\expandafter,\xint_gobble_iv}\fi }% -\def\XINT_flseqb:f:csv_pa #1#2#3#4{\expandafter\XINT_flseqb:f:csv_p\expandafter - {\romannumeral0\XINTinfloatadd{#4}{#1}}{#2}{#3,#1}{#4}}% -\def\XINT_flseqb:f:csv_p #1#2% -{% - \xintifCmp {#1}{#2}% - \XINT_flseqb:f:csv_pa\XINT_flseqb:f:csv_pb\XINT_flseqb:f:csv_pc {#1}{#2}% -}% -\def\XINT_flseqb:f:csv_pb #1#2#3#4{#3,#1}% -\def\XINT_flseqb:f:csv_pc #1#2#3#4{#3}% -\def\XINT_flseqb:f:csv_bg #1{\if #1n\expandafter\XINT_flseqb:f:csv_na\else - \xint_afterfi{\expandafter,\xint_gobble_iv}\fi }% -\def\XINT_flseqb:f:csv_na #1#2#3#4{\expandafter\XINT_flseqb:f:csv_n\expandafter - {\romannumeral0\XINTinfloatadd{#4}{#1}}{#2}{#3,#1}{#4}}% -\def\XINT_flseqb:f:csv_n #1#2% -{% - \xintifCmp {#1}{#2}% - \XINT_seqb:f:csv_nc\XINT_seqb:f:csv_nb\XINT_flseqb:f:csv_na {#1}{#2}% -}% -% \end{macrocode} -% \subsection{\csh{xintdeffunc}, \csh{xintdefiifunc}, +% +% \subsubsection{\csh{xintdeffunc}, \csh{xintdefiifunc}, % \csh{xintdeffloatfunc}} % % \changed{1.2c}{2015/11/12} % \lverb|Note: it is possible to have same name assigned both to a variable % and a function: things such as add(f(f), f=1..10) are possible.| % +% \changed{1.2c}{2015/11/13} +% \lverb|Function names first expanded then detokenized and cleaned of spaces.| +% +% \changed{1.2e}{2015/11/21} +% \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.| +% +% \changed{1.2f}{2016/02/22} +% \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.| +% % \changed{1.2f}{2016/03/08} % \lverb|Comma separated expressions allowed (formerly this required using % parenthesis \xintdeffunc foo(x,..):=(.., .., ..);| @@ -38659,33 +39346,85 @@ math shift catcode. % \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.| % +% \changed{1.3e}{??} +% \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.| +% +% \changed{1.4}{2020/01/10} +% \lverb|Multi-letter variables can be used (with no prior declaration)| +% +% \changed{1.4}{2020/01/11} +% \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. +% +% Thus the 1.3e \xintdefefunc, \xintdefiiefunc, \xintdeffloatefunc constructors +% of «expanding» functions are kept only as aliases of legacy \xintdeffunc et al. and +% deprecated. +% +% 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. +% +% | +% +% % \begin{macrocode} -\def\XINT_tmpa #1#2#3#4% +\def\XINT_tmpa #1#2#3#4#5% {% - \def #1##1(##2)##3=##4;{% + \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}% - \def\XINT_deffunc_tmpc {(##4)}% \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 - {\edef\XINT_deffunc_tmpb {\the\numexpr\XINT_deffunc_tmpb+\xint_c_i}% + {% + \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},% - ####1=################\XINT_deffunc_tmpb)}% + \XINT_deffunc_tmpf=################\XINT_deffunc_tmpb)}% }% \fi % \end{macrocode} -% \lverb|Something like this must be done before the NewFunc, else recursive -% definitions are impossible as the function will be unknown.| +% Place holder for comments. Logic at 1.4 is simplified here compared to +% earlier releases. +% % \begin{macrocode} - \ifnum\XINT_deffunc_tmpb=\xint_c_ - \expandafter\XINT_expr_defuserfunc_none\csname + \ifcase\XINT_deffunc_tmpb\space + \expandafter\XINT_expr_defuserfunc_none\csname \else - \expandafter\XINT_expr_defuserfunc\csname + \expandafter\XINT_expr_defuserfunc\csname \fi - XINT_#2_func_\XINT_deffunc_tmpa\expandafter\endcsname - \expandafter{\XINT_deffunc_tmpa}{#2}% + 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} @@ -38694,207 +39433,119 @@ math shift catcode. 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}% -\XINT_tmpa\xintdefiifunc_a {iiexpr}\XINT_NewIIFunc {iiexpr}% -\XINT_tmpa\xintdeffloatfunc_a{flexpr}\XINT_NewFloatFunc{floatexpr}% -\def\XINT_expr_defuserfunc #1#2#3% +\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% - \csname.=\XINT:expr:userfunc{#3}{#2}{\XINT_expr_unlock ##3}\endcsname + \def #1##1##2##3% + {% + \expandafter##1\expandafter##2\expanded{% + {\XINT:NEhook:usernoargfunc\csname XINT_#4_userfunc_#3\endcsname}% + }% }% }% -\def\XINT:expr:userfunc #1#2#3% -{% - \csname XINT_#1_userfunc_#2\expandafter\endcsname - \romannumeral0\xintcsvtolistnonstripped{#3}% -}% -\def\XINT_expr_defuserfunc_none #1#2#3% +\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% - \csname.=\XINT:expr:userfunc:none{#3}{#2}\endcsname + \def #1##1##2%##3% + {% + \expandafter ##1\expandafter##2\expanded\bgroup{\iffalse}\fi + \XINT:NEhook:userfunc{XINT_#4_userfunc_#3}#2%##3% }% -}% -\def\XINT:expr:userfunc:none #1#2{\csname XINT_#1_userfunc_#2\endcsname}% -% \end{macrocode} -% \subsection{\csh{xintdefefunc}, \csh{xintdefiiefunc}, \csh{xintdeffloatefunc}} -% \lverb|Added at 1.3e. Please consider the whole business of \xintdeffunc, -% \xintdefefunc, \xintNewExpr as somewhat like a work in progress, it is -% complex indeed.| -% \begin{macrocode} -\def\XINT_tmpa #1#2#3#4% -{% - \def #1##1(##2)##3=##4;{% - \edef\XINT_defefunc_tmpa {##1}% - \edef\XINT_defefunc_tmpa {\xint_zapspaces_o \XINT_defefunc_tmpa}% - \def\XINT_defefunc_tmpb {0}% - \def\XINT_defefunc_tmpc {(##4)}% - \edef\XINT_defefunc_tmpd {##2}% - \ifnum\xintLength:f:csv{\XINT_defefunc_tmpd}>\xint_c_ - \xintFor ####1 in {\XINT_defefunc_tmpd}\do - {\edef\XINT_defefunc_tmpb {\the\numexpr\XINT_defefunc_tmpb+\xint_c_i}% - \edef\XINT_defefunc_tmpc {subs(\unexpanded\expandafter{\XINT_defefunc_tmpc},% - ####1=################\XINT_defefunc_tmpb)}% - }% - \fi -% \end{macrocode} -% \lverb|No recursivity allowed here with the function to be defined.| -% \begin{macrocode} - \expandafter#3\csname XINT_#2_userefunc_\XINT_defefunc_tmpa\endcsname - [\XINT_defefunc_tmpb]{\XINT_defefunc_tmpc}% - \edef\XINT_defefunc_tmpd{\xintLength:f:csv - {\expandafter\meaning\csname - XINT_#2_userfunc_\XINT_defefunc_tmpa\endcsname}}% + \else + \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 +}% +\def\XINT:NEhook:userfunc #1#2#3{#2#3\iffalse{{\fi}}}% +\def\XINT:NEhook:userfunc:argv #1#2#3#4% + {\expandafter#3\expanded{\xintKeep{#1}{#4}{\xintTrim{#1}{#4}}}\iffalse{{\fi}}}% +\let\xintdefefunc\xintdeffunc +\let\xintdefiifunc\xintdefiifunc +\let\xintdeffloatefunc\xintdeffloatfunc % \end{macrocode} -% \lverb|We try to distinguish wheter the function is supposed to deliver only -% one value or more than two. And we separate the cases of 0, 1 or 2 variables -% which can be set-up a bit better for usage in other definitions, in -% generator environments. But there are many shortcomings. I don't have a very -% clear view of all the complex situation, in fact. -% | +% \subsubsection{\csh{xintdefufunc}, \csh{xintdefiiufunc}, +% \csh{xintdeffloatufunc}} +% +% \lverb|1.4| +% % \begin{macrocode} - \ifcase\XINT_defefunc_tmpb\space - \expandafter\XINT_expr_defuserefunc_none\csname - \or -% \ifnum\XINT_defefunc_tmpd=\xint_c_i - \expandafter\XINT_expr_defuserefunc_one\csname -% \else -% \expandafter\XINT_expr_defuserefunc_onetocsv\csname -% \fi - \or -% \ifnum\XINT_defefunc_tmpd=\xint_c_i - \expandafter\XINT_expr_defuserefunc_two\csname -% \else -% \expandafter\XINT_expr_defuserefunc_twotocsv\csname -% \fi +\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 -% \ifnum\XINT_defefunc_tmpd=\xint_c_i - \expandafter\XINT_expr_defuserefunc_many\csname -% \else -% \expandafter\XINT_expr_defuserefunc_manytocsv\csname -% \fi + \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. Cancelled.}% + \xintexprRestoreCatcodes \fi - XINT_#2_func_\XINT_defefunc_tmpa\expandafter\endcsname - \expandafter{\XINT_defefunc_tmpa}{#2}% + }% 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} - {Function \XINT_defefunc_tmpa\space for \string\xint #4 parser - associated to \string\XINT_#2_userefunc_\XINT_defefunc_tmpa\space + {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_userefunc_\XINT_defefunc_tmpa\endcsname}% + \csname XINT_#2_userufunc_\XINT_defufunc_tmpa\endcsname}% \fi - \xintexprRestoreCatcodes - }% -}% -\def\xintdefefunc {\xintexprSafeCatcodes\xintdefefunc_a}% -\def\xintdefiiefunc {\xintexprSafeCatcodes\xintdefiiefunc_a}% -\def\xintdeffloatefunc {\xintexprSafeCatcodes\xintdeffloatefunc_a}% -\XINT_tmpa\xintdefefunc_a {expr} \XINT_NewFunc {expr}% -\XINT_tmpa\xintdefiiefunc_a {iiexpr}\XINT_NewIIFunc {iiexpr}% -\XINT_tmpa\xintdeffloatefunc_a{flexpr}\XINT_NewFloatFunc{floatexpr}% -\def\XINT_expr_defuserefunc_none #1#2#3% -{% - \expandafter\XINT_expr_defuserefunc_none_a - \csname XINT_#3_userefunc_#2\endcsname #1% -}% -\def\XINT_expr_defuserefunc_none_a #1#2% + }% 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 #2##1##2##3{\expandafter ##1\expandafter ##2\csname.=#1\endcsname}% -}% -% \end{macrocode} -% \lverb|Je définis une macro auxiliaire qui fait l'expansion mais tout cela -% pour éviter le très léger overhead de \xintExpandArgs... c'est idiot et le -% devient encore plus pour deux arguments. Mais c'est aussi dû à -% \xintApply::csv que l'on veut utiliser commodément -% dans \XINT:NE:userefunc:one_a.| -% \begin{macrocode} -\def\XINT_expr_defuserefunc_one #1#2#3% -{% - \expandafter\XINT_expr_defuserefunc_one_a - \csname XINT_#3_userefunc_#2\expandafter\endcsname - \csname XINT_#3_userefunc:f_#2\endcsname #1{#2}{#3}% -}% -\def\XINT_expr_defuserefunc_one_a #1#2#3#4#5% -{% - \XINT_global - \def #2##1{\expandafter#1\expandafter{\romannumeral`&&@##1}}% - \XINT_global - \def #3##1##2##3% + \def #1##1##2%##3% {% - \expandafter ##1\expandafter ##2% - \csname.=\XINT:expr:userefunc:one{#5}{#4}{\XINT_expr_unlock##3}\endcsname + \expandafter ##1\expandafter##2\expanded + \XINT:NEhook:userufunc{XINT_#4_userufunc_#3}#2%##3% }% }% -\def\XINT:expr:userefunc:one #1#2#3% -{% - \csname XINT_#1_userefunc_#2\expandafter\endcsname\expandafter - {\romannumeral`&&@#3}% -}% -\def\XINT_expr_defuserefunc_two #1#2#3% -{% - \expandafter\XINT_expr_defuserefunc_two_a - \csname XINT_#3_userefunc:f_#2\endcsname #1{#2}{#3}% -}% +\def\XINT:NEhook:userufunc #1{\XINT:expr:mapwithin}% % \end{macrocode} -% \lverb|Le fait que \xintExpandArgs demande que les arguments sont regroupés -% explique pourquoi plus bas j'ai dû faire \XINT:NE:userefunc:two. -% -% \xintExpandArgs#1{{##1}{##2}} -% -% Mais bon finalement je rajouter encore un helper d'expansion. Que j'ai -% peut-être d'ailleurs déjà... C'est un peu de l'abus la macro auxiliaire -% userefunc:f pour chaque userefunc, mais je dois gérer le problème que les -% noms de macros ici peuvent contenir des chiffres. -% -% Il y a de la perte dans le grabbing de l'argument qui aura lieu et qu'on -% pourrait optimiser, mais je commence à sérieusement fatiguer pour 1.3e.| -% \begin{macrocode} -\def\XINT_expr_defuserefunc_two_a #1#2#3#4% -{% - \XINT_global - \def #1##1##2{\xintExpandArgs{XINT_#4_userefunc_#3}{{##1}{##2}}}% - \XINT_global - \def #2##1##2##3% - {% - \expandafter ##1\expandafter ##2% - \csname.=\XINT:expr:userefunc:two{#4}{#3}{\XINT_expr_unlock##3}\endcsname - }% -}% -\def\XINT:expr:userefunc:two #1#2#3% -{% - \expandafter\XINT:expr:userefunc:two_a - \csname XINT_#1_userefunc_#2\expandafter\endcsname - \romannumeral`&&@#3,% -}% -\def\XINT:expr:userefunc:two_a #1#2,#3,{#1{#2}{#3}}% -% \end{macrocode} -% \lverb|Paradoxically the general case is code faster. But this is explained -% because we try to hook into special handlers for one or two variables (see -% "Mysterious stuff" subsection in NewExpr.| -% \begin{macrocode} -\def\XINT_expr_defuserefunc_many #1#2#3% -{% - \XINT_global - \def #1##1##2##3% - {% - \expandafter ##1\expandafter ##2% - \csname.=\XINT:expr:userefunc{#3}{#2}{\XINT_expr_unlock##3}\endcsname - }% -}% -\def\XINT:expr:userefunc #1#2#3% -{% - \csname XINT_#1_userefunc_#2\expandafter\endcsname - \romannumeral0\xintcsvtolistnonstripped{#3}% -}% -% \end{macrocode} -% \subsection{\csh{xintunassignexprfunc}, \csh{xintunassigniiexprfunc}, \csh{xintunassignfloatexprfunc}} +% +% \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. @@ -38907,23 +39558,27 @@ math shift catcode. \XINT_global\expandafter \let\csname XINT_#1_userfunc_\XINT_unfunc_tmpa\endcsname\xint_undefined \XINT_global\expandafter - \let\csname XINT_#1_userefunc_\XINT_unfunc_tmpa\endcsname\xint_undefined + \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} -% \subsection{\csh{xintNewFunction}} +% \subsubsection{\csh{xintNewFunction}} % \lverb|1.2h (2016/11/20). Syntax is \xintNewFunction{<name>}[nb of % arguments]{expression with #1, #2,... as in \xintNewExpr}. This defines % a function for all three parsers but the expression parsing is delayed until % function execution. Hence the expression admits all constructs, contrarily % to \xintNewExpr or \xintdeffunc. % +% 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. % | % \begin{macrocode} -\def\XINT_expr_wrapit #1{\expandafter\XINT_expr_wrap\csname.=#1\endcsname}% \def\xintNewFunction #1#2[#3]#4% {% \edef\XINT_newfunc_tmpa {#1}% @@ -38947,18 +39602,18 @@ math shift catcode. \XINT_global\expandafter \def\csname XINT_expr_macrofunc_\XINT_newfunc_tmpa\expandafter\endcsname \the\toks0\expandafter{\XINT_newfunc_tmpb - {\XINT_expr_wrapit{##1}}{\XINT_expr_wrapit{##2}}{\XINT_expr_wrapit{##3}}% - {\XINT_expr_wrapit{##4}}{\XINT_expr_wrapit{##5}}{\XINT_expr_wrapit{##6}}% - {\XINT_expr_wrapit{##7}}{\XINT_expr_wrapit{##8}}{\XINT_expr_wrapit{##9}}}% + {\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}{eval}\xintbareeval + \expandafter{\XINT_newfunc_tmpa}\xintbareeval \expandafter\XINT_expr_newfunction \csname XINT_iiexpr_func_\XINT_newfunc_tmpa\expandafter\endcsname - \expandafter{\XINT_newfunc_tmpa}{iieval}\xintbareiieval + \expandafter{\XINT_newfunc_tmpa}\xintbareiieval \expandafter\XINT_expr_newfunction \csname XINT_flexpr_func_\XINT_newfunc_tmpa\expandafter\endcsname - \expandafter{\XINT_newfunc_tmpa}{floateval}\xintbarefloateval + \expandafter{\XINT_newfunc_tmpa}\xintbarefloateval \ifxintverbose \xintMessage {xintexpr}{Info} {Function \XINT_newfunc_tmpa\space for the expression parsers is @@ -38967,472 +39622,668 @@ math shift catcode. \csname XINT_expr_macrofunc_\XINT_newfunc_tmpa\endcsname}% \fi }% -\def\XINT_expr_newfunction #1#2#3#4% +\def\XINT_expr_newfunction #1#2#3% {% \XINT_global - \def#1##1##2##3{\expandafter ##1\expandafter ##2\romannumeral0% - \XINT:expr:macrofunc{#4}{#3}{#2}{\XINT_expr_unlock##3}}% -}% -\def\XINT:expr:macrofunc #1#2#3#4% -{% - #1\csname XINT_expr_macrofunc_#3\expandafter\endcsname - \romannumeral0\xintcsvtolistnonstripped{#4}\relax -}% -\catcode`~ 12 -\def\XINT:newexpr:macrofunc #1{% -\def\XINT:newexpr:macrofunc ##1##2##3##4% -{% - \expandafter#1\csname.=~XINT:newexpr:macrofunc:a{##2}{##3}% - {\xintCSVtoListNonStripped{##4}}\endcsname -}% -}\XINT:newexpr:macrofunc { }% -\catcode`~ 3 -\def\XINT:newexpr:macrofunc:a #1#2#3% -{% - \expandafter\XINT_expr_unlock\romannumeral0\csname xintbare#1\endcsname - \csname XINT_expr_macrofunc_#2\endcsname#3\relax + \def#1##1##2##3% + {\expandafter ##1\expandafter ##2% + \romannumeral0\XINT:NEhook:macrofunc + #3{\csname XINT_expr_macrofunc_#2\endcsname##3}\relax + }% }% -% \end{macrocode} -% \subsection{\csh{xintNewExpr}, \csh{xintNewIExpr}, \csh{xintNewFloatExpr}, -% \csh{xintNewIIExpr}} -% \localtableofcontents -% \lverb|& -% There was an \xintNewExpr already in 1.07 from May 2013, which was -% modified in September 2013 to work with the # macro parameter character, -% and then refactored into a more powerful version in June 2014 for 1.1 -% release of 2014/10/28. List handling causes special -% challenges, addressed by \xintApply::csv, \xintApply:::csv, ... next. -% -% Comments finally added 2015/12/11 (with later edits): -% -% The whole point is to expand completely macros when they have only numerical -% arguments and to inhibit this expansion if not. This is done in a recursive -% way: the catcode 12 ~ is used to register a macro name whose expansion must -% be inhibited. Any argument itself starting with such a ~ will -% force use of ~ for the macro which receives it. -% -% In this context the catcode 12 $$ is used to signal a "virtual -% list" argument. It triggers insertion of \xintApply::csv or -% \xintApply:::csv for delayed handling later. This succeeds into handling -% inputs such as [#1..[#2]..#3][#4:#5]... -% -% A final -% \scantokens converts the "~" prefixed names into real control sequences. -% -% For this whole mechanism we need to have everything expressed using -% exclusively f-expandable macros. We avoid \csname...\endcsname like -% construct, but if absolutely needed perhaps we will do it ultimately. -% -% For the iterating loops seq, iter, etc..., and dummy variables, we have no -% macros to our disposal to handle the case where the list -% of indices is not explicit. Moreover omit, abort, break can not work with -% non numerical data. Thus the whole mechanism is currently not appicable to -% them. It does work when the macro parameters (or variables for \xintdeffunc) -% do not intervene in the list of values to iterate over. But we can not delay -% expansion of dummy variables. -% -% Comments added 2018/02/28: -% -% At 1.3 of February 2018, there was important refactoring. Earlier, -% \XINT_expr_redefinemacros was a very big macro which made aliases of the -% dozens of macros (most from xintfrac and some defined especially by xintexpr -% for acting on csv lists primarily) involved in the expression rendering and -% then redefined them all to expand to their original selves only when applied -% to purely numeric arguments. At 1.3 only very few such re-definitions are -% made, as what is redefined are a limited number of core wrapper macros. -% -% Only when the original macros have one or two arguments is it examined if -% they can expand immediately (this includes case of function having possibly -% only one, or possibly two arguments). For macros applying to three or more -% or an undefined number of arguments, we don't complicate matters into -% checking if expansion is possible, and we delay that expansion -% automatically (but if() and ifsgn() do check if first argument is numeric -% and expand to suitable branch in that case). -% -% In particular any function defined by \xintdeffunc or \xintNewFunction (it -% is then basically only a macro abstraction) when used in new function -% definitions will never be expanded immediately, because the detection of -% whether they are applied to only numerical data has not yet been added. -% (this might be added in future). -% -% Some aspects of the 1.3 refactoring have made recursive definition via -% \xintdeffunc possible (of course they always were via \xintNewFunction as -% the latter is but a wrapper of a standard TeX macro definition, where -% \xintexpr parsing is not at all involved). -% -% A somewhat complicated layer (not modified at 1.3) is devoted to making -% possible the parsing of constructs such as [#1..[#2]..#3][#4:#5] or -% [#1..#2]*#3 and it seems to work. At 1.3, even esoteric construct such as -% [divmod(#1,#2)]*#3 is parsable by \xintNewExpr. (In \xintNewFloatExpr, don't -% forget \empty token so that square brackets are not mistaken for optional -% argument of \xintthefloatexpr; same for \xintdeffloatfunc.) -% -% Side note: I wonder if I really had a good idea to define these list -% operations [..]*foo or foo^[...] which do not seem to occur in other -% languages with the meanings I used. And they caused me lots of efforts for -% support at \xintNewExpr level... -% -% The catcode 12 dollar sign is used to signal when a macro can not be -% expanded but would produce a csv list. Furthermore some cases require -% f-expandable macros as the original code expanding in \xintexpr is in -% \csname context and did not need f-expandability. -% -% As mentioned above, currently syntax with dummy variables can not go through -% where the values iterated over are not explicit; and omit, abort, break -% mechanisms are not parsable with non purely numerical data, in part because -% they are not implemented internally via pure f-expansion. -% | -% \subsubsection{\csh{xintApply::csv} and \csh{xintApply:::csv}} -% \lverb|Serve in particular to support things such as -% -% \xintdeffunc foo(x):=seq(sqr(i), i=0..x); -% -% ... as far as I still understand what is going on here! The most complicated -% is for list operations; many things involving sequences don't go through -% \xintNewExpr, especially with functions of more than one variable. -% -% | -% \begin{macrocode} -\def\xintApply::csv #1#2% - {\expandafter\XINT_applyon::_a\expandafter {\romannumeral`&&@#2}{#1}}% -\def\XINT_applyon::_a #1#2{\XINT_applyon::_b {#2}{}#1,,}% -\def\XINT_applyon::_b #1#2#3,{\expandafter\XINT_applyon::_c \romannumeral`&&@#3,{#1}{#2}}% -\def\XINT_applyon::_c #1{\if #1,\expandafter\XINT_applyon::_end - \else\expandafter\XINT_applyon::_d\fi #1}% -\def\XINT_applyon::_d #1,#2{\expandafter\XINT_applyon::_e\romannumeral`&&@#2{#1},{#2}}% -\def\XINT_applyon::_e #1,#2#3{\XINT_applyon::_b {#2}{#3, #1}}% -\def\XINT_applyon::_end #1,#2#3{\xint_secondoftwo #3}% -\def\xintApply:::csv #1#2#3% - {\expandafter\XINT_applyon:::_a\expandafter{\romannumeral`&&@#2}{#1}{#3}}% -\def\XINT_applyon:::_a #1#2#3{\XINT_applyon:::_b {#2}{#3}{}#1,,}% -\def\XINT_applyon:::_b #1#2#3#4,% - {\expandafter\XINT_applyon:::_c \romannumeral`&&@#4,{#1}{#2}{#3}}% -\def\XINT_applyon:::_c #1{\if #1,\expandafter\XINT_applyon:::_end - \else\expandafter\XINT_applyon:::_d\fi #1}% -\def\XINT_applyon:::_d #1,#2#3% - {\expandafter\XINT_applyon:::_e\expandafter - {\romannumeral`&&@\xintApply::csv {#2{#1}}{#3}},{#2}{#3}}% -\def\XINT_applyon:::_e #1,#2#3#4{\XINT_applyon:::_b {#2}{#3}{#4, #1}}% -\def\XINT_applyon:::_end #1,#2#3#4{\xint_secondoftwo #4}% +\let\XINT:NEhook:macrofunc\empty % \end{macrocode} % \subsubsection{Mysterious stuff} -% \lverb|~ and $$ of catcode 12 in what follows. There was some refactoring at -% 1.3e, particulary \XINT:NE:userefunc was added.| +% +% 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 -\catcode`$ 12 % $ -\def\xint_dfork #1$#2#3\krof {#2}% $ -\def\xint_ddfork #1$$#2#3\krof {#2}% $$ -\def\XINT:NE:RApply::csv #1#2#3#4% - {~xintApply::csv{~expandafter #2~xint_exchangetwo_keepbraces{#4}}{#3}}% -\def\XINT:NE:LApply::csv #1#2#3{~xintApply::csv{#2{#3}}}% -\def\XINT:NE:RLApply:::csv #1{~xintApply:::csv}% -\def\XINT:NE:two#1{\XINT:NE:two_{#1}{\detokenize{#1}}}% -\def\XINT:NE:two_#1#2#3#4% - {\expandafter\XINT:NE:two_a\romannumeral`&&@#4!{#3}{#1}{#2}}% -\def\XINT:NE:two_a#1#2!#3#4#5% - {\expandafter\XINT:NE:two_b\romannumeral`&&@#3!#1{#4}{#5}{#1#2}}% -\def\XINT:NE:two_b#1#2!#3#4#5{\XINT:NE:two_fork_dd#1#3{#4}{#5}{#1#2}}% -\def\XINT:NE:two_fork_dd #1#2{% - \xint_ddfork - #1#2\XINT:NE:RLApply:::csv - #1$\XINT:NE:RApply::csv% $ - $#2\XINT:NE:LApply::csv% $ - $${\XINT:NE:two_fork_nn #1#2}% $$ - \krof +\def\XINT:NE: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:two_fork_nn #1#2#3#4{% - \if #1##\xint_dothis{#4}\fi - \if #1~\xint_dothis{#4}\fi - \if #2##\xint_dothis{#4}\fi - \if #2~\xint_dothis{#4}\fi - \xint_orthat{#3}% +\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}}% }% -% \end{macrocode} -% \lverb|& -% At 1.3f, added braces around #1 and #3 in \XINT:NE:one to handle the -% \xintfloatexpr [D] issue inside an \xintdeffunc. -% | -% \begin{macrocode} -\def\XINT:NE:twosp#1#2,#3#4,!#5% +\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% {% - \XINT:NE:two_fork_dd#1#3{#5}{\detokenize{#5}}{#1#2}{#3#4}% + \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:one#1#2{\expandafter\XINT:NE:one_a\romannumeral`&&@#2!{#1}}% -\def\XINT:NE:one_a#1#2!#3% +\def\XINT:NE:f:one:and:opt:direct#1{% +\def\XINT:NE:f:one:and:opt:direct##1!% {% - \if ###1\xint_dothis {\detokenize{#3}}\fi - \if ~#1\xint_dothis {\detokenize{#3}}\fi - \if $#1\xint_dothis {~xintApply::csv{\detokenize{#3}}}\fi %$ - \xint_orthat {#3}{#1#2}% + \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}%$ }% -% \end{macrocode} -% \lverb|\xintExpandArgs is defined in xinttools.sty (I don't recall why; not -% for reasons internal to xint I guess). Attention here that user function -% names may contain digits, so we don't use a \detokenize or ~ approach.| -% \begin{macrocode} -\def\XINT:NE:userfunc #1#2#3% - {~xintExpandArgs{XINT_#1_userfunc_#2}{\xintCSVtoListNonStripped{#3}}}% -\def\XINT:NE:userfunc:none #1#2{~!{XINT_#1_userfunc_#2}}% -% \end{macrocode} -% \lverb|\XINT:NE:userefunc et al. added at 1.3e. For one and two I can not -% use \XINT:NE:one due to possible digits in names. For more than two nothing -% special done with mysterious "Apply" macros above. -% -% Should they ever use $ in -% output? Je crois que j'ai des problèmes en particulier car j'utilise le most -% liste dans plusieurs sens il y a en particulier la confusion possible pour -% liste dans le sens restreint devant être géré par les opérations genre ]* ou -% celui avec les seq() ou finalement la liste des arguments d'une fonction. -% -% When expansion of the user func can not happend on the spot, the version -% which will be expanded later one must first expand its argument for -% efficiency because the functions from \XINT_NewFunc do not do that and we -% must thus have an auxiliary variant expanding its argument.| -% \begin{macrocode} -\def\XINT:NE:userefunc:one#1#2#3% - {\expandafter\XINT:NE:userefunc:one_a\romannumeral`&&@#3!{#1}{#2}}% -\def\XINT:NE:userefunc:one_a#1#2!#3#4% +\def\XINT:NE:f:one:and:opt_b\XINT:expr:f:one:and:opt #1#2#3&&A#4#5% {% - \if ###1\xint_dothis {~!{XINT_#3_userefunc:f_#4}}\fi - \if ~#1\xint_dothis {~!{XINT_#3_userefunc:f_#4}}\fi -% \end{macrocode} -% \lverb|Quickly checked this \csname presentation ok for \xintApply::csv.| -% \begin{macrocode} - \if $#1\xint_dothis {~xintApply::csv~!{XINT_#3_userefunc:f_#4}}\fi %$ - \xint_orthat {\csname XINT_#3_userefunc_#4\endcsname}% - {#1#2}% + \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:direct\XINT:expr:f:tacizeroifone #1#2#3&&A#4#5% +{% + \if\relax#3\relax\expandafter\xint_firstoftwo\else + \expandafter\xint_secondoftwo\fi + {\XINT:NE:f:one:from:two#4{0}}% + {\expandafter\XINT:NE:f:one:from:two\expandafter#5% + \expanded{{\XINT:NE:f:one:from:one:direct\xintNum{#2}}}}% + {#1}% }% -\def\XINT:NE:twosp#1#2,#3#4,!#5% +\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% {% - \XINT:NE:two_fork_dd#1#3{#5}{\detokenize{#5}}{#1#2}{#3#4}% + \detokenize{\romannumeral`-0\expandafter#1\expanded{#2}$XINT_expr_exclam#3}%$ }% -\def\XINT:NE:userefunc:two#1#2#3% - {\expandafter\XINT:NE:userefunc:two_a\romannumeral`&&@#3,!{#1}{#2}}% -% \end{macrocode} -% \lverb|Je ne peux pas faire ~xintExpandArgs{XINT_#5_userefunc_#6} à cause du -% fait que j'ai {#1#2}{#3#4} pas {{#1#2}{#3#4}} à cause de la première -% branche, celle qui s'étend.| -% \begin{macrocode} -\def\XINT:NE:userefunc:two_a#1#2,#3#4,!#5#6% +\def\XINT:NE:f:iitacitzeroifone:direct\XINT:expr:f:iitacizeroifone #1#2#3&&A#4% {% - \XINT:NE:two_fork_dd#1#3{\csname XINT_#5_userefunc_#6\endcsname}% - {~!{XINT_#5_userefunc:f_#6}}% - {#1#2}{#3#4}% + \if\relax#3\relax\expandafter\xint_firstoftwo\else + \expandafter\xint_secondoftwo\fi + {\XINT:NE:f:one:from:two#4{0}}% + {\XINT:NE:f:one:from:two#4{#2}}% + {#1}% }% -\def\XINT:NE:userefunc#1#2#3% +\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:one:from:twoandone #1#2#3{\XINT:NE:x:one:from:twoandone_a #2#3&&A#1{#2}{#3}}% +\def\XINT:NE:x:one:from:twoandone_a #1#2{\XINT:NE:x:one:from:twoandone_fork #1&&A#2&&A}% +\def\XINT:NE:x:one:from:twoandone_fork #1{% +\def\XINT:NE:x:one:from:twoandone_fork ##1##2&&A##3##4&&A##5##6&&A% +{% + \if0\XINT:NE:hastilde ##1##3##5~!\relax\XINT:NE:hashash ##1##3##5#1!\relax 0% + \else + \expandafter\XINT:NE:x:one:from:two:p + \fi +}}\expandafter\XINT:NE:x:one:from:twoandone_fork\string#% +\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% {% - \expandafter\XINT:NE:userefunc_a\romannumeral`&&@#3,2,3,4,5,6,7,8,9,!% - {#1}{#2}{#3}% + \detokenize + {% + \expanded{\expandafter#1\expanded{#2$XINT_expr_tab({#3}}\expandafter\empty\empty}%$ + }% }% -\def\XINT:NE:userefunc_a#1#2,#3#4,#5#6,#7#8,#9% +\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 {% - \XINT:NE:userefunc_b{#1#3#5#7#9}% + \detokenize + {% + \romannumeral0\expandafter\XINT:expr:f:reverse + \expandafter{\expanded\expandafter{\xint_gobble_i#1}}% + }% }% -\def\XINT:NE:userefunc_b#1#2,#3#4,#5#6,#7#8,#9% +\def\XINT:expr:f:reverse #1% {% - \XINT:NE:userefunc_c{#1#3#5#7#9}% + \XINT_expr_reverse #1^^#1\xint:\xint:\xint:\xint: + \xint:\xint:\xint:\xint:\xint_bye }% -\def\XINT:NE:iftilde #1~#2#3\relax{\unless\if !#21\fi}% -\def\XINT:NE:ifdollar #1$#2#3\relax{\unless\if !#21\fi}%$ -\def\XINT:NE:ifhash#1{% -\def\XINT:NE:ifhash##1#1##2##3\relax{\unless\if !##21\fi}% -}\expandafter\XINT:NE:ifhash\string#% -\def\XINT:NE:userefunc_c#1#2!% +\def\XINT:NE:f:from:delim:u #1{% +\def\XINT:NE:f:from:delim:u ##1##2^% {% - \if0\XINT:NE:iftilde #1~!\relax\XINT:NE:ifdollar #1$!\relax%$ - \XINT:NE:ifhash #1##!\relax 0% - \expandafter\XINT:NE:userefunc_x + \if0\expandafter\XINT:NE:hastilde\detokenize{##2}~!\relax + \expandafter\XINT:NE:hashash\detokenize{##2}#1!\relax 0% + \expandafter##1% \else - \expandafter\XINT:NE:userefunc_p + \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#1}~expanded{#2}$XINT_expr_caret}%$ +\def\XINT:NE:f:noeval:from:braced:u #1{% +\def\XINT:NE:f:noeval:from:braced:u ##1##2^% +{% + \if0\XINT:NE:hastilde ##2~!\relax\XINT:NE:hashash ##2#1!\relax 0% + \else + \expandafter\XINT:NE:f:noeval:from:braced:u:p + \fi + ##1{##2}% +}}\expandafter\XINT:NE:f:noeval:from:braced:u\string#% +\def\XINT:NE:f:noeval:from:braced:u:p #1#2% + {\detokenize{\expandafter#1}~expanded{{#2}}}% +\catcode`- 11 +\def\XINT:NE:exec_? #1#2% +{% + \XINT:NE:exec_?_b #2&&A#1{#2}% }% -\def\XINT:NE:userefunc_x#1#2% - {\csname XINT_#1_userefunc_#2\expandafter\endcsname - \romannumeral0\xintcsvtolistnonstripped}% -\def\XINT:NE:userefunc_p #1#2#3% - {~xintExpandArgs{XINT_#1_userefunc_#2}{\xintCSVtoListNonStripped{#3}}}% -% \end{macrocode} -% \lverb|Back to older stuff.| -% \begin{macrocode} -\def\XINT:NE:oneopt#1[#2]#3% - {\expandafter\XINT:NE:oneopt_a\romannumeral`&&@#3!{#2}#1}% -\def\XINT:NE:oneopt_a#1#2!#3#4% - {\expandafter\XINT:NE:oneopt_b\romannumeral`&&@#3!#1#4{#1#2}}% -\def\XINT:NE:oneopt_b#1#2!#3#4% - {\expandafter\XINT:NE:oneopt_fork#1#3#4{#1#2}}% -\def\XINT:NE:oneopt_fork#1#2#3#4{% - \if1\if###11\else\if~#11\else\if###21\else\if~#21\else0\fi\fi\fi\fi - \xint_dothis {\detokenize{#3}[#4]}\fi - \if $#2\xint_dothis {~xintApply::csv{\detokenize{#3}[#4]}}\fi %$ - \xint_orthat{#3[#4]}% -}% pas complétement général, mais bon -\def\XINT:NE:csv #1{\detokenize{#1}}% radicalement fainéant -\def\XINT:newexpr:one:and:opt #1,#2,#3!#4#5% +\def\XINT:NE:exec_?_b #1{% +\def\XINT:NE:exec_?_b ##1&&A% {% - \if\relax#3\relax\expandafter\xint_firstoftwo\else - \expandafter\xint_secondoftwo\fi - {\XINT:NE:one#4}{\XINT:NE:oneopt#5[\XINT:NE:one\xintNum{#2}]}{#1}% + \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:newexpr:tacitzeroifonearg #1,#2,#3!#4#5% +\def\XINT:NE:exec_?:p #1#2#3#4#5% {% - \if\relax#3\relax\expandafter\xint_firstoftwo\else - \expandafter\xint_secondoftwo\fi - {\XINT:NE:two#4{0}}{\XINT:NE:two#5{\XINT:NE:one\xintNum{#2}}}{#1}% + \csname XINT_expr_func_*If\expandafter\endcsname + \romannumeral`&&@#2\XINTfstop.{#3},[#4],[#5])% }% -\def\XINT:newiiexpr:tacitzeroifonearg #1,#2,#3!#4% +\expandafter\def\csname XINT_expr_func_*If\endcsname #1#2#3% {% - \if\relax#3\relax\expandafter\xint_firstoftwo\else - \expandafter\xint_secondoftwo\fi - {\XINT:NE:two#4{0}}{\XINT:NE:two#4{#2}}{#1}% + #1#2{~expanded{~xintiiifNotZero#3}}% }% -\def\XINT:newexpr:insertdollar~{$noexpand$}% -\def\XINT:newexpr:two:to:two #1,#2,!#3% +\def\XINT:NE:exec_?? #1#2#3% {% - \XINT:NE:two_ - {\expandafter\XINT:expr:totwo\romannumeral`&&@#3}% - {$noexpand$expandafter~XINT:expr:totwo~romannumeral-`0\detokenize{#3}}% - {#1}{#2}% + \XINT:NE:exec_??_b #2&&A#1{#2}% }% -\def\XINT:newflexpr:two:to:two #1,#2,!#3% +\def\XINT:NE:exec_??_b #1{% +\def\XINT:NE:exec_??_b ##1&&A% {% - \XINT:NE:two_ - {#3}% - {\expandafter\XINT:newexpr:insertdollar\detokenize{#3}}% - {#1}{#2}% + \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\xintiiifNotZeroNE:#1#2,#3,#4,% +\def\XINT:NE:exec_??:p #1#2#3#4#5#6% {% - \if1\if###11\else\if~#11\else\if$#11\else0%$ - \fi\fi\fi - \xint_dothis{~xintiiifNotZero}\fi - \xint_orthat\xintiiifNotZero - {#1#2}{#3}{#4}% + \csname XINT_expr_func_*IfSgn\expandafter\endcsname + \romannumeral`&&@#2\XINTfstop.{#3},[#4],[#5],[#6])% }% -\def\xintifIntNE:#1#2,#3,#4,% +\expandafter\def\csname XINT_expr_func_*IfSgn\endcsname #1#2#3% {% - \if1\if###11\else\if~#11\else\if$#11\else0%$ - \fi\fi\fi - \xint_dothis{~xintifInt}\fi - \xint_orthat\xintifInt - {#1#2}{#3}{#4}% + #1#2{~expanded{~xintiiifSgn#3}}% }% -\def\xintifFloatIntNE:#1#2,#3,#4,% +\catcode`- 12 +\def\XINT:NE:branch #1% {% - \if1\if###11\else\if~#11\else\if$#11\else0%$ - \fi\fi\fi - \xint_dothis{~xintifFloatInt}\fi - \xint_orthat\xintifFloatInt - {#1#2}{#3}{#4}% + \if0\XINT:NE:hastilde #1~!\relax 0\else + \xint_dothis\XINT:NE:branch_a\fi + \xint_orthat\XINT:NE:branch_b #1&&A% }% -\def\xintiiifOneNE:#1#2,#3,#4,% +\def\XINT:NE:branch_a\romannumeral`&&@#1#2&&A% {% - \if1\if###11\else\if~#11\else\if$#11\else0%$ - \fi\fi\fi - \xint_dothis{~xintiiifOne}\fi - \xint_orthat\xintiiifOne - {#1#2}{#3}{#4}% + \expandafter{\detokenize{\expandafter#1\expanded}{#2}}% }% -\def\xintifOneNE:#1#2,#3,#4,% +\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% {% - \if1\if###11\else\if~#11\else\if$#11\else0%$ - \fi\fi\fi - \xint_dothis{~xintifOne}\fi - \xint_orthat\xintifOne - {#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\xintiiifSgnNE:#1#2,#3,#4,#5,% +\def\XINT:NE:opx#1{% +\def\XINT:NE:opx\XINT_allexpr_opx ##1##2##3##4%##5##6##7##8% {% - \if1\if###11\else\if~#11\else\if$#11\else0%$ - \fi\fi\fi - \xint_dothis{~xintiiifSgn}\fi - \xint_orthat\xintiiifSgn - {#1#2}{#3}{#4}{#5}% + \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(#6)#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: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 + {% +%% \expanded +%% {% + \expandafter\XINT:expr:mapwithin_checkempty + \expanded{\noexpand#1$XINT_expr_exclam\expandafter}%$ + \detokenize\expandafter{\expanded{#2}}$XINT_expr_caret%$ +%% }% + }% + }}% +}% +\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} -% \subsubsection{\csh{XINT_expr_redefinemacros}} -% \lverb|Completely refactored at 1.3.| -% \begin{macrocode} -\def\XINT_expr_redefinemacros {% - \let\XINT:NEhook:one \XINT:NE:one - \let\XINT:NEhook:two \XINT:NE:two - \let\XINT:NEhook:csv \XINT:NE:csv - \let\XINT:NEhook:twosp\XINT:NE:twosp - \let\XINT:expr:userfunc \XINT:NE:userfunc - \let\XINT:expr:userfunc:none \XINT:NE:userfunc:none - \let\XINT:expr:userefunc \XINT:NE:userefunc - \let\XINT:expr:userefunc:one \XINT:NE:userefunc:one - \let\XINT:expr:userefunc:two \XINT:NE:userefunc:two - \let\XINT:expr:macrofunc \XINT:newexpr:macrofunc - \let\XINT:expr:one:and:opt \XINT:newexpr:one:and:opt - \let\XINT:expr:one:or:two:nums \XINT:newexpr:one:or:two:nums - \let\XINT:iiexpr:one:or:two: \XINT:newiiexpr:one:or:two: - \let\XINT:expr:tacitzeroifonearg \XINT:newexpr:tacitzeroifonearg - \let\XINT:iiexpr:tacitzeroifonearg \XINT:newiiexpr:tacitzeroifonearg - \let\XINT:expr:two:to:two \XINT:newexpr:two:to:two - \let\XINT:flexpr:two:to:two \XINT:newflexpr:two:to:two - \let\xintiiifNotZero: \xintiiifNotZeroNE: - \let\xintifInt: \xintifIntNE: - \let\xintifFloatInt: \xintifFloatIntNE: - \let\xintiiifOne: \xintiiifOneNE: - \let\xintifOne: \xintifOneNE: - \let\xintiiifSgn: \xintiiifSgnNE: - \let\xintSeqNumeric::csv \xintSeq::csv - \let\xintiiSeqNumeric::csv \xintiiSeq::csv - \let\xintSeqBNumeric::csv \xintSeqB::csv - \let\xintiiSeqBNumeric::csv \xintiiSeqB::csv - \let\XINTinFloatSeqBNumeric::csv\XINTinFloatSeqB::csv - \def\xintSeq::csv - {\XINT:NE:two_\xintSeqNumeric::csv{$noexpand$xintSeq::csv}}% - \def\xintiiSeq::csv - {\XINT:NE:two_\xintiiSeqNumeric::csv{$noexpand$xintiiSeq::csv}}% - \def\xintSeqB::csv - {\XINT:NE:two_\xintSeqBNumeric::csv{$noexpand$xintSeqB:f:csv}}% - \def\xintiiSeqB::csv - {\XINT:NE:two_\xintiiSeqBNumeric::csv{$noexpand$xintiiSeqB:f:csv}}% - \def\XINTinFloatSeqB::csv - {\XINT:NE:two_\XINTinFloatSeqBNumeric::csv{$noexpand$XINTinFloatSeqB:f:csv}}% - \def\xintListSel:x:csv {~xintListSel:f:csv }% - \def\XINTinRandomFloatSdigits{~XINTinRandomFloatSdigits }% - \def\XINTinRandomFloatSixteen{~XINTinRandomFloatSixteen }% - \def\xintiiRandRange{~xintiiRandRange }% - \def\xintiiRandRangeAtoB{~xintiiRandRangeAtoB }% -% \end{macrocode} -% \lverb|1.3f authorizes usage of \xinteval et al. inside expression -% definitions. The computed value must end up purely numerical. +% \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. % | % \begin{macrocode} - \let\xinteval\XINT:NE:eval - \let\xintieval\XINT:NE:ieval - \let\xintiieval\XINT:NE:iieval - \let\xintfloateval\XINT:NE:floateval +\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_redefineprints}} -% \lverb|& -% This was used by \xintNewExpr but not by \xintdeffunc until 1.3e. -% Since then, used by both. +% \subsubsection{\csh{XINT_expr_redefinemacros}} +% \lverb|Completely refactored at 1.3. % -% Comma separated sub-expressions are not supported, the expansion -% is inhibited but it is not checked if it would have given strictly -% more than one value. +% 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. % % | % \begin{macrocode} -\def\XINT_expr_redefineprints -{% - \let\XINT_flexpr_withopt_a\XINT:NE_flexpr_withopt_a - \let\XINT_expr_print \XINT:NE_expr_print - \let\XINT_iiexpr_print \XINT:NE_iiexpr_print - \let\XINT_boolexpr_print \XINT:NE_boolexpr_print - \def\xintCSV::csv {~xintCSV::csv }% - \def\xintSPRaw::csv {~xintSPRaw::csv }% - \def\xintPFloat::csv {~xintPFloat::csv }% - \def\xintIsTrue::csv {~xintIsTrue::csv }% - \def\xintRound::csv {~xintRound::csv }% +\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:x:one:from:twoandone \XINT:NE:x:one:from:twoandone + \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:noeval:from:braced:u\XINT:NE:f:noeval:from:braced:u + \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: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} -% \subsubsection{\cshnolabel{xintNewExpr}, ..., at last.} +% \subsubsection{\csh{xintNewExpr}, \csh{xintNewIExpr}, \csh{xintNewFloatExpr}, +% \csh{xintNewIIExpr}} % \lverb|& % 1.2c modifications to accomodate \XINT_expr_deffunc_newexpr etc.. % @@ -39442,30 +40293,40 @@ math shift catcode. % 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). % | % \begin{macrocode} -\def\xintNewExpr {\XINT_NewExpr\xint_firstofone - \xinttheexpr\XINT_newexpr_clean}% -\def\xintNewFloatExpr{\XINT_NewExpr\xint_firstofone - \xintthefloatexpr\XINT_newexpr_clean}% -\def\xintNewIExpr {\XINT_NewExpr\xint_firstofone - \xinttheiexpr\XINT_newexpr_clean}% -\def\xintNewIIExpr {\XINT_NewExpr\xint_firstofone - \xinttheiiexpr\XINT_newexpr_clean}% -\def\xintNewBoolExpr {\XINT_NewExpr\xint_firstofone - \xinttheboolexpr\XINT_newexpr_clean}% -\def\XINT_newexpr_clean #1>{\noexpand\romannumeral`&&@}% +\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} % \lverb|1.2c for \xintdeffunc, \xintdefiifunc, \xintdeffloatfunc. % -% At 1.3, NewFunc does not use a comma delimited pattern anymore.| +% 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 +% | % \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 {\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} % \lverb|1.2c adds optional logging. For this needed to pass to _NewExpr_a the @@ -39477,11 +40338,6 @@ math shift catcode. % Modified at 1.3c so that \XINT_NewFunc et al. do not execute the % \xintexprSafeCatcodes, as it is now already done earlier by \xintdeffunc. % -% Modified at 1.3e: \XINT_NewFunc et al. do issue \XINT_expr_redefineprints. -% I suppose I did not use it formely as I considered it unneeded overhead, -% but this meant that \xintdeffunc foo(x):=\xintfloatexpr bar(x)\relax; was -% impossible. But such a syntax is convenient for xinttrig.sty to transfer -% float functions to normal functions. % | % \begin{macrocode} \def\XINT_NewExpr #1#2#3#4#5[#6]% @@ -39501,7 +40357,6 @@ math shift catcode. \fi #1\xintexprSafeCatcodes \XINT_expr_redefinemacros - \XINT_expr_redefineprints \XINT_NewExpr_a #1#2#3#4% }% % \end{macrocode} @@ -39516,15 +40371,46 @@ math shift catcode. % The $%1 is \xint_firstofone for \xintNewExpr, \xint_gobble_i % for \xintdeffunc. % -% The ~ action was modified at 1.3e for ~! constructs (userefunc:f macros). -% | -% \begin{macrocode} +% 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. | +% \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 \catcode`~ 13 \catcode`@ 14 \catcode`\% 6 \catcode`# 12 \catcode`$ 11 @ $ \def\XINT_NewExpr_a %1%2%3%4%5@ {@ \def\XINT_tmpa %%1%%2%%3%%4%%5%%6%%7%%8%%9{%5}@ - \def~%%1{\if !%%1\noexpand~\else $noexpand$%%1\fi}@ - \catcode`: 11 \catcode`_ 11 + \def~{$noexpand$}@ + \catcode`: 11 \catcode`_ 11 \catcode`\@ 11 \catcode`# 12 \catcode`~ 13 \escapechar 126 \endlinechar -1 \everyeof {\noexpand }@ \edef\XINT_tmpb @@ -39532,7 +40418,6 @@ math shift catcode. %2\XINT_tmpa{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}\relax}@ }@ \escapechar 92 \catcode`# 6 \catcode`$ 0 @ $ - \def~%%1{\expandafter\noexpand\csname %%1\endcsname}@ \edef\XINT_tmpa %%1%%2%%3%%4%%5%%6%%7%%8%%9@ {\scantokens\expandafter{\expandafter%3\meaning\XINT_tmpb}}@ \the\toks0\expandafter @@ -39610,6 +40495,7 @@ math shift catcode. \catcode32=10 % space }% \let\XINT_tmpa\undefined \let\XINT_tmpb\undefined \let\XINT_tmpc\undefined +\let\XINT_tmpd\undefined \let\XINT_tmpe\undefined \ifdefined\RequirePackage\expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo\fi {\RequirePackage{xinttrig}% \RequirePackage{xintlog}}% @@ -39634,6 +40520,8 @@ math shift catcode. % % \localtableofcontents % +% Comments under reconstruction. +% % The original was done in January 15 and 16, 2019. It provided |asin()| and % |acos()| based on a Newton algorithm approach. Then during March 25-31 I % revisited the code, adding more inverse trigonometrical functions (with a @@ -39643,7 +40531,7 @@ math shift catcode. % level coding. % % This led me next to improve upon the innards of \csbxint{deffunc} and -% \csbxint{NewExpr}, and to add to \xintexprnameimp the \csbxint{defefunc} +% \csbxint{NewExpr}, and to add to \xintexprnameimp the \csa{xintdefefunc} % macro (see user documentation). % % Finally on April 5, 2019 I pushed further the idea of the algorithm for the @@ -39708,10 +40596,10 @@ math shift catcode. \expandafter\xint_secondoftwo \fi {\immediate\write-1{Reloading xinttrig library using Digits=\xinttheDigits.}}% -{\expandafter\gdef\csname xintlibver@trig\endcsname{2019/09/10 v1.3f}% +{\expandafter\gdef\csname xintlibver@trig\endcsname{2020/01/31 v1.4}% \XINT_providespackage \ProvidesPackage{xinttrig}% -[2019/09/10 v1.3f Trigonometrical functions for xintexpr (JFB)]% +[2020/01/31 v1.4 Trigonometrical functions for xintexpr (JFB)]% }% % \end{macrocode} % \subsection{Ensure used letters are dummy letters} @@ -39792,7 +40680,7 @@ math shift catcode. %) % % We can see that for D=16, the problem is there with N=22, 25, 26, 27, -% 28...and more. If we were to use 1/i! directly in the \xintdeffloatefunc of +% 28...and more. If we were to use 1/i! directly in the \xintdeffloatfunc of % sin_aux(X) and cos_aux(X) we would have this problem. % % If we use \xintexpr1/i!\relax encapsulation in the function declaration the @@ -39803,10 +40691,15 @@ math shift catcode. % seq(0+\xintexpr1/i!\relax, i = 2..44) but opt for an rseq. The semi-colon % must be braced to hide it from \xintdeffloatvar grabbing of the delimited % argument. +% +% 1.4 update: use \xintfloatexpr with optional argument for the rounding +% rather than «0+x» method. % | % \begin{macrocode} \xintdeffloatvar invfact\xintListWithSep{, invfact}{\xintSeq{2}{44}}% - := seq(0+x, x=\xintexpr rseq(1/2{;}@/i, i=3..44)\relax);% need to hide inner ; + := \xintfloatexpr [\XINTdigits] % force float rounding after exact evaluations + \xintexpr rseq(1/2{;}@/i, i=3..44)\relax % need to hide inner ; from \xintdeffloatvar + \relax;% % \end{macrocode} % \subsection{The sine and cosine series} % \subsubsection{\cshn{sin_aux()}, \cshn{cos_aux()}} @@ -39821,7 +40714,7 @@ math shift catcode. % shorter truncation of the sine series should be used. % | % \begin{macrocode} -\xintdeffloatefunc sin_aux(X) := 1 - X(invfact3 - X(invfact5 +\xintdeffloatfunc sin_aux(X) := 1 - X(invfact3 - X(invfact5 \ifnum\XINTdigits>4 - X(invfact7 \ifnum\XINTdigits>6 @@ -39866,7 +40759,7 @@ math shift catcode. % transition values and this makes them a bit less favourable at 24, 26, % 29...and some more probably. Again this is very bad for small X.| % \begin{macrocode} -\xintdeffloatefunc cos_aux(X) := 1 - X(invfact2 - X(invfact4 +\xintdeffloatfunc cos_aux(X) := 1 - X(invfact2 - X(invfact4 \ifnum\XINTdigits>3 - X(invfact6 \ifnum\XINTdigits>5 @@ -39926,13 +40819,13 @@ math shift catcode. % Use this only between -pi/4 and pi/4 % | % \begin{macrocode} -\xintdeffloatefunc sin_(x) := x * sin_aux(sqr(x));% +\xintdeffloatfunc sin_(x) := x * sin_aux(sqr(x));% % \end{macrocode} % \lverb|& % Use this only between -pi/4 and pi/4 % | % \begin{macrocode} -\xintdeffloatefunc cos_(x) := cos_aux(sqr(x));% +\xintdeffloatfunc cos_(x) := cos_aux(sqr(x));% % \end{macrocode} % \subsection{Range reduction for sine and cosine using degrees} % @@ -39988,13 +40881,13 @@ math shift catcode. % % sind_() coded directly at macro level with a macro \xintSind (ATTENTION! it % requires a positive argument) -% which will suitably use \XINT_flexpr_func_sin_ defined from \xintdeffloatefunc +% which will suitably use \XINT_flexpr_func_sin_ defined from \xintdeffloatfunc % | % \begin{macrocode} \def\XINT_flexpr_func_sind_ #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:one\xintSind{\XINT_expr_unlock#3}\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:one{\romannumeral`&&@\xintSind#3}}% }% % \end{macrocode} % \lverb|& @@ -40003,6 +40896,7 @@ math shift catcode. % ATTENTION ONLY FOR POSITIVE ARGUMENTS % | % \begin{macrocode} +\def\XINT_expr_unlock{\expandafter\xint_firstofone\romannumeral`&&@}% \def\xintSind#1{\romannumeral`&&@\expandafter\xintsind \romannumeral0\XINTinfloatS[\XINTdigits]{#1}}% \def\xintsind #1[#2#3]% @@ -40041,9 +40935,6 @@ math shift catcode. % maybe some leading zero and then xintfrac.sty will think the whole thing is % zero due to the requirements of my own core format A[N].... % -% The "userefunc" auxiliary macros do not pre-expand their arguments (but the -% macros which end up used in other ones defined from \csbxintdeffunc do). -% % Multiplication is done exactly but anyway currently float multiplication % goes via exact multiplication after rounding arguments ; as here integer % part has at most three digits, doing exact multiplication will prove @@ -40053,8 +40944,8 @@ math shift catcode. \def\XINT_sind_A#1{% \def\XINT_sind_A##1.##2.% {% - \expandafter\XINT_flexpr_userefunc_sin_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% + \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}#1}}% }% }\expandafter \XINT_sind_A\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% @@ -40062,13 +40953,13 @@ math shift catcode. \def\XINT_tmpa#1{% \def\XINT_sind_B_n-##1.##2.% {% - \expandafter\XINT_flexpr_userefunc_cos_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% + \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}#1}}% }% \def\XINT_sind_B_p##1.##2.% {% - \expandafter\XINT_flexpr_userefunc_cos_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% + \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}#1}}% }% }\expandafter \XINT_tmpa\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% @@ -40076,13 +40967,13 @@ math shift catcode. \def\XINT_tmpa#1{% \def\XINT_sind_C_n-##1.##2.% {% - \expandafter\XINT_flexpr_userefunc_sin_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% + \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}#1}}% }% \def\XINT_sind_C_p##1.##2.% {% - \xintiiopp\expandafter\XINT_flexpr_userefunc_sin_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% + \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}#1}}% }% }\expandafter \XINT_tmpa\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% @@ -40090,21 +40981,21 @@ math shift catcode. \def\XINT_tmpa#1{% \def\XINT_sind_D_n-##1.##2.% {% - \xintiiopp\expandafter\XINT_flexpr_userefunc_cos_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% + \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}#1}}% }% \def\XINT_sind_D_p##1.##2.% {% - \xintiiopp\expandafter\XINT_flexpr_userefunc_cos_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% + \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}#1}}% }% }\expandafter \XINT_tmpa\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% \def\XINT_sind_E#1{% \def\XINT_sind_E-##1.##2.% {% - \xintiiopp\expandafter\XINT_flexpr_userefunc_sin_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% + \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}#1}}% }% }\expandafter \XINT_sind_E\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% @@ -40113,8 +41004,8 @@ math shift catcode. % \begin{macrocode} \def\XINT_flexpr_func_cosd_ #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:one\xintCosd{\XINT_expr_unlock#3}\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:one{\romannumeral`&&@\xintCosd#3}}% }% % \end{macrocode} % \lverb|& @@ -40122,7 +41013,7 @@ math shift catcode. % | % \begin{macrocode} \def\xintCosd#1{\romannumeral`&&@\expandafter\xintcosd - \romannumeral0\XINTinfloatS[\XINTdigits]{#1}}% + \romannumeral0\XINTinfloatS[\XINTdigits]{#1}}% \def\xintcosd #1[#2#3]% {% \xint_UDsignfork @@ -40159,8 +41050,8 @@ math shift catcode. \def\XINT_cosd_A#1{% \def\XINT_cosd_A##1.##2.% {% - \expandafter\XINT_flexpr_userefunc_cos_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% + \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}#1}}% }% }\expandafter \XINT_cosd_A\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% @@ -40168,13 +41059,13 @@ math shift catcode. \def\XINT_tmpa#1{% \def\XINT_cosd_B_n-##1.##2.% {% - \expandafter\XINT_flexpr_userefunc_sin_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% + \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}#1}}% }% \def\XINT_cosd_B_p##1.##2.% {% - \xintiiopp\expandafter\XINT_flexpr_userefunc_sin_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% + \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}#1}}% }% }\expandafter \XINT_tmpa\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% @@ -40182,13 +41073,13 @@ math shift catcode. \def\XINT_tmpa#1{% \def\XINT_cosd_C_n-##1.##2.% {% - \xintiiopp\expandafter\XINT_flexpr_userefunc_cos_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% + \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}#1}}% }% \def\XINT_cosd_C_p##1.##2.% {% - \xintiiopp\expandafter\XINT_flexpr_userefunc_cos_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% + \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}#1}}% }% }\expandafter \XINT_tmpa\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% @@ -40196,45 +41087,67 @@ math shift catcode. \def\XINT_tmpa#1{% \def\XINT_cosd_D_n-##1.##2.% {% - \xintiiopp\expandafter\XINT_flexpr_userefunc_sin_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% + \xintiiopp\XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}#1}}% }% \def\XINT_cosd_D_p##1.##2.% {% - \expandafter\XINT_flexpr_userefunc_sin_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}{#1}}}% + \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_sin_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{##1.##2}#1}}% }% }\expandafter \XINT_tmpa\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% \def\XINT_cosd_E#1{% \def\XINT_cosd_E-##1.##2.% {% - \expandafter\XINT_flexpr_userefunc_cos_\expandafter - {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}{#1}}}% + \XINT_expr_unlock\expandafter\XINT_flexpr_userfunc_cos_\expandafter + {\romannumeral0\XINTinfloat[\XINTdigits]{\xintMul{\xintSub{##1[0]}{.##2}}#1}}% }% }\expandafter \XINT_cosd_E\expandafter{\romannumeral`&&@\xintthebarefloateval oneDegree\relax}% % \end{macrocode} % \subsection{\cshn{sind()}, \cshn{cosd()}} % \begin{macrocode} -\xintdeffloatefunc sind(x) := ifsgn(x, if(x>=-45, sin_(x*oneDegree), -sind_(-x)), - 0, - if(x<=45, sin_(x*oneDegree), sind_(x)));% -\xintdeffloatefunc cosd(x) := ifsgn(x, if(x>=-45, cos_(x*oneDegree), cosd_(-x)), - 1, - if(x<=45, cos_(x*oneDegree), cosd_(x)));% +\xintdeffloatfunc sind(x) := (x)?? + {(x>=-45)? + {sin_(x*oneDegree)} + {-sind_(-x)} + } + {0} + {(x<=45)? + {sin_(x*oneDegree)} + {sind_(x)} + } + ;% +\xintdeffloatfunc cosd(x) := (x)?? + {(x>=-45)? + {cos_(x*oneDegree)} + {cosd_(-x)} + } + {1} + {(x<=45)? + {cos_(x*oneDegree)} + {cosd_(x)} + } + ;% % \end{macrocode} % \subsection{\cshn{sin()}, \cshn{cos()}} % \lverb|& % For some reason I did not define sin() and cos() in January 2019 ?? % | % \begin{macrocode} -\xintdeffloatefunc sin(x):= if(abs(x)<0.79, sin_(x),% - ifsgn(x, -sind_(-x*oneRadian), - 0, - sind_(x*oneRadian)) - );% -\xintdeffloatefunc cos(x):= if(abs(x)<0.79, cos_(x), cosd_(abs(x*oneRadian)));% +\xintdeffloatfunc sin(x):= (abs(x)<0.79)? + {sin_(x)} + {(x)?? + {-sind_(-x*oneRadian)} + {0} + {sind_(x*oneRadian)} + } + ;% +\xintdeffloatfunc cos(x):= (abs(x)<0.79)? + {cos_(x)} + {cosd_(abs(x*oneRadian))} + ;% % \end{macrocode} % \subsection{\cshn{sinc()}} % \lverb|& @@ -40242,32 +41155,44 @@ math shift catcode. % avoids a square. % | % \begin{macrocode} -\xintdeffloatefunc sinc(x):= - if(abs(x)<0.79, sin_aux(sqr(x)), sind_(abs(x)*oneRadian)/abs(x));% +\xintdeffloatfunc sinc(x):= (abs(x)<0.79) ? + {sin_aux(sqr(x))} + {sind_(abs(x)*oneRadian)/abs(x)} + ;% % \end{macrocode} % \subsection{\cshn{tan()}, \cshn{tand()}, \cshn{cot()}, \cshn{cotd()}} % \lverb|The 0 in cot(x) is a dummy place holder, 1/0 would raise an error at % time of definition...| % \begin{macrocode} -\xintdeffloatefunc tand(x):= sind(x)/cosd(x);% -\xintdeffloatefunc cotd(x):= cosd(x)/sind(x);% -\xintdeffloatefunc tan(x) := ifsgn(x, if(x>-0.79, sin(x)/cos(x), -cotd(90+x*oneRadian)), - 0, - if(x<0.79, sin(x)/cos(x), cotd(90-x*oneRadian)) - );% -\xintdeffloatefunc cot(x) := if(abs(x)<0.79, cos(x)/sin(x), - ifsgn(x, -tand(90+x*oneRadian), - 0, - tand(90-x*oneRadian)) - );% +\xintdeffloatfunc tand(x):= sind(x)/cosd(x);% +\xintdeffloatfunc cotd(x):= cosd(x)/sind(x);% +\xintdeffloatfunc tan(x) := (x)?? + {(x>-0.79)? + {sin(x)/cos(x)} + {-cotd(90+x*oneRadian) + } + } + {0} + {(x<0.79)? + {sin(x)/cos(x)} + {cotd(90-x*oneRadian)} + } + ;% +\xintdeffloatfunc cot(x) := (abs(x)<0.79)? + {cos(x)/sin(x)} + {(x)?? + {-tand(90+x*oneRadian)} + {0} + {tand(90-x*oneRadian)} + };% % \end{macrocode} % % \subsection{\cshn{sec()}, \cshn{secd()}, \cshn{csc()}, \cshn{cscd()}} % \begin{macrocode} -\xintdeffloatefunc sec(x) := inv(cos(x));% -\xintdeffloatefunc csc(x) := inv(sin(x));% -\xintdeffloatefunc secd(x):= inv(cosd(x));% -\xintdeffloatefunc cscd(x):= inv(sind(x));% +\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} % \lverb|& @@ -40378,7 +41303,7 @@ math shift catcode. % Certainly I can do similar things to compute logarithms. % | % \begin{macrocode} -\xintdeffloatefunc asin_aux(X) := 1 +\xintdeffloatfunc asin_aux(X) := 1 \ifnum\XINTdigits>3 % actually 4 would achieve 1ulp in place of <0.5ulp + X(1/6 \ifnum\XINTdigits>9 @@ -40392,32 +41317,50 @@ math shift catcode. \ifnum\XINTdigits>46 + X(231/13312 )\fi)\fi)\fi)\fi)\fi)\fi;% -\xintdeffloatefunc asin_o(D, T) := T + D*asin_aux(sqr(D));% -\xintdeffloatefunc asin_n(V, T, t, u) :=% V is square of T +\xintdeffloatfunc asin_o(D, T) := T + D*asin_aux(sqr(D));% +\xintdeffloatfunc asin_n(V, T, t, u) :=% V is square of T asin_o (\xintexpr t*cos_aux(V) - u*T*sin_aux(V)\relax, T);% -\xintdeffloatefunc asin_m(T, t, u) := asin_n(sqr(T), T, t, u);% -\xintdeffloatefunc asin_l(t, u) := asin_m(t*asin_aux(sqr(t)), t, u);% +\xintdeffloatfunc asin_m(T, t, u) := asin_n(sqr(T), T, t, u);% +\xintdeffloatfunc asin_l(t, u) := asin_m(t*asin_aux(sqr(t)), t, u);% % \end{macrocode} % \subsection{\cshn{asin()}, \cshn{asind()}} % \lverb|& % Only non-negative arguments t and u for asin_a(t,u), and asind_a(t,u). % | -% \begin{macrocode} -\xintdeffloatefunc asin_a(t, u) := - if(t<u, asin_l(t, u), Piover2 - asin_l(u, t));% -\xintdeffloatefunc asind_a(t, u):= - if(t<u, asin_l(t, u) * oneRadian, 90 - asin_l(u, t) * oneRadian);% -\xintdeffloatefunc asin(t) := ifsgn(t, -asin_a(-t, sqrt(1-sqr(t))), - 0, - asin_a(t, sqrt(1-sqr(t))));% -\xintdeffloatefunc asind(t) := ifsgn(t, -asind_a(-t, sqrt(1-sqr(t))), - 0, - asind_a(t, sqrt(1-sqr(t))));% +% +% \lverb|At 1.4 usage of sqrt_() which has only one argument, whereas +% currently sqrt() admits a second optional argument hence sub-optimality here +% if we use sqrt(), especially since 1.4 handles more fully such functions +% with optional argument in \xintdeffunc. +% +% Actually thinking of making sqrt() a one argument only function and +% sqrt_() will be the one with two arguments. But I worked hard on the +% \xintdeffunc hooks, thus some reticence, because why then not do that +% for all others?| +% \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} + {90 - asin_l(u, t) * oneRadian} + ;% +\xintdeffloatfunc asin(t) := (t)?? + {-asin_a(-t, sqrt_(1-sqr(t)))} + {0} + {asin_a(t, sqrt_(1-sqr(t)))} + ;% +\xintdeffloatfunc asind(t) := (t)?? + {-asind_a(-t, sqrt_(1-sqr(t)))} + {0} + {asind_a(t, sqrt_(1-sqr(t)))} + ;% % \end{macrocode} % \subsection{\cshn{acos()}, \cshn{acosd()}} % \begin{macrocode} -\xintdeffloatefunc acos(t) := Piover2 - asin(t);% -\xintdeffloatefunc acosd(t):= 90 - asind(t);% +\xintdeffloatfunc acos(t) := Piover2 - asin(t);% +\xintdeffloatfunc acosd(t):= 90 - asind(t);% % \end{macrocode} % \subsection{\cshn{atan()}, \cshn{atand()}} % \lverb|& @@ -40437,90 +41380,127 @@ math shift catcode. % % TeX hackers note 2: % -% The if(,,) and ifsgn(,,,) tests when used numerically compute all ; but when -% used into a \xintdeffloatefunc, they are converted to macros with basically -% \firstofthree, \secondofthree, \thirdofthree behaviour so then only the -% actually executed branch will do computations. +% At 1.4, the way to inject lazy conditionals in function definitions has changed. +% Prior one used if(,,) and ifsgn(,,,) which was counter-intuitive because +% in pure numeric context they evaluate all branches. Now one must use ? and ?? +% which the are the lazy conditionals from the numeric context. % -% For numeric computations the ? and ?? operators are used for this effect, -% but they can not be used in \xintdeffloatefunc if the test involves unknown -% variables; as explained above fortunately then if(,,) and ifsgn(,,) work. % % radians % | % \begin{macrocode} -\xintdeffloatefunc atan_b(t, w, z):=% - 0.5 * if(w< 0, Pi - asin_a(2z * t, -w*z), asin_a(2z * t, w*z));% -\xintdeffloatefunc atan_a(t, T) := atan_b(t, 1-T, inv(1+T));% -\xintdeffloatefunc atan(t):= ifsgn(t,-atan_a(-t, sqr(t)), 0, atan_a(t, sqr(t)));% +\xintdeffloatfunc atan_b(t, w, z):= 0.5 * (w< 0)? + {Pi - asin_a(2z * t, -w*z)} + {asin_a(2z * t, w*z)} + ;% +\xintdeffloatfunc atan_a(t, T) := atan_b(t, 1-T, inv(1+T));% +\xintdeffloatfunc atan(t):= (t)?? + {-atan_a(-t, sqr(t))} + {0} + {atan_a(t, sqr(t))} + ;% % \end{macrocode} % \lverb|& % degrees % | % \begin{macrocode} -\xintdeffloatefunc atand_b(t, w, z) := - 0.5 * if(w< 0, 180 - asind_a(2z * t, -w*z), asind_a(2z * t, w*z));% -\xintdeffloatefunc atand_a(t, T) := atand_b(t, 1-T, inv(1+T));% -\xintdeffloatefunc atand(t):= ifsgn(t,-atand_a(-t, sqr(t)), 0, atand_a(t, sqr(t)));% +\xintdeffloatfunc atand_b(t, w, z) := 0.5 * (w< 0)? + {180 - asind_a(2z * t, -w*z)} + {asind_a(2z * t, w*z)} + ;% +\xintdeffloatfunc atand_a(t, T) := atand_b(t, 1-T, inv(1+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()}} % \lverb|& % Arg(x,y) function from -π (excluded) to +π (included) % | % \begin{macrocode} -\xintdeffloatefunc Arg(x, y):= - if(y>x, - if(y>-x, Piover2 - atan(x/y), - if(y<0, -Pi + atan(y/x), Pi + atan(y/x))), - if(y>-x, atan(y/x), -Piover2 + atan(x/-y)) - );% +\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} % \lverb|& % atan2(y,x) = Arg(x,y) ... (some people have atan2 with arguments reversed % but the convention here seems the most often encountered) % | % \begin{macrocode} -\xintdeffloatefunc atan2(y,x) := Arg(x, y);% +\xintdeffloatfunc atan2(y,x) := Arg(x, y);% % \end{macrocode} % \lverb|& % Argd(x,y) function from -180 (excluded) to +180 (included) % | % \begin{macrocode} -\xintdeffloatefunc Argd(x, y):= - if(y>x, - if(y>-x, 90 - atand(x/y), - if(y<0, -180 + atand(y/x), 180 + atand(y/x))), - if(y>-x, atand(y/x), -90 + atand(x/-y)) - );% +\xintdeffloatfunc Argd(x, y):= (y>x)? + {(y>-x)? + {90 - atand(x/y)} + {(y<0)? + {-180 + atand(y/x)} + {180 + atand(y/x)} + } + } + {(y>-x)? + {atand(y/x)} + {-90 + atand(x/-y)} + } + ;% % \end{macrocode} % \lverb|& % atan2d(y,x) = Argd(x,y) % | % \begin{macrocode} -\xintdeffloatefunc atan2d(y,x) := Argd(x, y);% +\xintdeffloatfunc atan2d(y,x) := Argd(x, y);% % \end{macrocode} % \lverb|& % pArg(x,y) function from 0 (included) to 2π (excluded) % I hesitated between pArg, Argpos, and Argplus. Opting for pArg in the end. % | % \begin{macrocode} -\xintdeffloatefunc pArg(x, y):= - if(y>x, - if(y>-x, Piover2 - atan(x/y), Pi + atan(y/x)), - if(y>-x, if(y<0, twoPi + atan(y/x), atan(y/x)), - threePiover2 + atan(x/-y)) - );% +\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} % \lverb|& % pArgd(x,y) function from 0 (included) to 360 (excluded) % | % \begin{macrocode} -\xintdeffloatefunc pArgd(x, y):= - if(y>x, - if(y>-x, 90 - atan(x/y)*oneRadian, 180 + atan(y/x)*oneRadian), - if(y>-x, if(y<0, 360 + atan(y/x)*oneRadian, atan(y/x)*oneRadian), - 270 + atan(x/-y)*oneRadian) - );% +\xintdeffloatfunc pArgd(x, y):=(y>x)? + {(y>-x)? + {90 - atan(x/y)*oneRadian} + {180 + atan(y/x)*oneRadian} + } + {(y>-x)? + {(y<0)? + {360 + atan(y/x)*oneRadian} + {atan(y/x)*oneRadian} + } + {270 + atan(x/-y)*oneRadian} + } + ;% % \end{macrocode} % \subsection{Synonyms: \cshn{tg()}, \cshn{cotg()}} % \lverb|These are my childhood notations and I am attached to them. In @@ -40539,23 +41519,23 @@ math shift catcode. \xintFor #1 in {sin, cos, tan, sec, csc, cot, asin, acos, atan}\do {% - \xintdefefunc #1(x) := \xintfloatexpr #1(sfloat(x))\relax;% - \xintdefefunc #1d(x):= \xintfloatexpr #1d(sfloat(x))\relax;% + \xintdeffunc #1(x) := \xintfloatexpr #1(sfloat(x))\relax;% + \xintdeffunc #1d(x):= \xintfloatexpr #1d(sfloat(x))\relax;% }% \xintFor #1 in {Arg, pArg, atan2}\do {% - \xintdefefunc #1(x, y) := \xintfloatexpr #1(sfloat(x), sfloat(y))\relax;% - \xintdefefunc #1d(x, y):= \xintfloatexpr #1d(sfloat(x), sfloat(y))\relax;% + \xintdeffunc #1(x, y) := \xintfloatexpr #1(sfloat(x), sfloat(y))\relax;% + \xintdeffunc #1d(x, y):= \xintfloatexpr #1d(sfloat(x), sfloat(y))\relax;% }% -\xintdefefunc tg(x) := \xintfloatexpr tg(sfloat(x))\relax;% -\xintdefefunc cotg(x):= \xintfloatexpr cotg(sfloat(x))\relax;% -\xintdefefunc sinc(x):= \xintfloatexpr sinc(sfloat(x))\relax;% +\xintdeffunc tg(x) := \xintfloatexpr tg(sfloat(x))\relax;% +\xintdeffunc cotg(x):= \xintfloatexpr cotg(sfloat(x))\relax;% +\xintdeffunc sinc(x):= \xintfloatexpr sinc(sfloat(x))\relax;% % \end{macrocode} % \lverb|Restore used dummy variables to their status prior to the package reloading. % On first loading this is not needed naturally, because this is done % immediately at end of xintexpr.sty.| % \begin{macrocode} -\xintFor* #1 in {iDTVtuwxyzX}\do{\xintrestorelettervar{#1}}% +\xintFor* #1 in {iDTVtuwxyzX}\do{\xintrestorevariable{#1}}% % \end{macrocode} % \StoreCodelineNo {xinttrig} % \cleardoublepage\let\xinttrignameUp\undefined @@ -40649,7 +41629,7 @@ math shift catcode. \xintexprSafeCatcodes\catcode`_ 11 \XINT_providespackage \ProvidesPackage{xintlog}% -[2019/09/10 v1.3f Logarithms and exponentials for xintexpr (JFB)]% +[2020/01/31 v1.4 Logarithms and exponentials for xintexpr (JFB)]% % \end{macrocode} % \subsection{Loading of \cshn{poormanlog} package} % \lverb|Attention to catcode regime when loading poormanlog. It matters less @@ -40678,15 +41658,17 @@ math shift catcode. % \begin{macrocode} \expandafter\def\csname XINT_expr_func_log10\endcsname#1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:one\PoorManLogBaseTen{\XINT_expr_unlock #3}\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:one + {\romannumeral`&&@\PoorManLogBaseTen#3}}% }% \expandafter\let\csname XINT_flexpr_func_log10\expandafter\endcsname \csname XINT_expr_func_log10\endcsname \expandafter\def\csname XINT_expr_func_pow10\endcsname#1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:one\PoorManPowerOfTen{\XINT_expr_unlock #3}\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:one + {\romannumeral`&&@\PoorManPowerOfTen#3}}% }% \expandafter\let\csname XINT_flexpr_func_pow10\expandafter\endcsname \csname XINT_expr_func_pow10\endcsname @@ -40698,94 +41680,139 @@ math shift catcode. % \begin{macrocode} \def\XINT_expr_func_log #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:one\xintLog{\XINT_expr_unlock #3}\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:one + {\romannumeral`&&@\xintLog#3}}% }% \def\XINT_flexpr_func_log #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:one\XINTinFloatLog{\XINT_expr_unlock #3}\endcsname + \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\csname.=% - \XINT:NEhook:one\xintExp{\XINT_expr_unlock #3}\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:one + {\romannumeral`&&@\xintExp#3}}% }% \def\XINT_flexpr_func_exp #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \XINT:NEhook:one\XINTinFloatExp{\XINT_expr_unlock #3}\endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:one + {\romannumeral`&&@\XINTinFloatExp#3}}% }% % \end{macrocode} % \lverb|Attention that the ! is of catcode 11 here.| % \begin{macrocode} \def\XINT_expr_func_pow #1#2#3% {% - \expandafter #1\expandafter #2\csname.=% - \expandafter\XINT:NEhook:twosp - \romannumeral`&&@\XINT_expr_unlock #3,!\PoorManPower - \endcsname + \expandafter #1\expandafter #2\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:two + {\romannumeral`&&@\PoorManPower#3}}% }% \let\XINT_flexpr_func_pow\XINT_expr_func_pow % \end{macrocode} % \subsection{\csh{poormanloghack}} % \lverb|With \poormanloghack{**}, the ** operator will use pow10(y*log10(x)). -% Same for ^.| +% Same for ^. Sync'd with xintexpr 1.4.| % \begin{macrocode} \catcode`\* 11 -\def\poormanloghack**{% -\def\XINT_expr_op_** ##1% -{% - \expandafter \XINT_expr_until_**_a - \expandafter ##1\romannumeral`&&@\expandafter\XINT_expr_getnext -}% -\def\XINT_expr_until_**_a ##1{% -\def\XINT_expr_until_**_a ####1####2% +\def\poormanloghack** {% + \def\XINT_tmpa ##1##2##3##4##5##6% + {% + \def ##3####1% \XINT_expr_op_<op> + {% + \expanded{\unexpanded{##4{####1}}\expandafter}% + \romannumeral`&&@\expandafter##2\romannumeral`&&@\XINT_expr_getnext + }% + \def##2####1% \XINT_expr_check-_<op> + {% \xint_UDsignfork - ####2{\expandafter \XINT_expr_until_**_a \expandafter ##1% - \romannumeral`&&@##1}% - -{\XINT_expr_until_**_b ####1####2}% + ####1{\expandafter##2\romannumeral`&&@##1}% + -{##5####1}% \krof -}}\expandafter\XINT_expr_until_**_a\csname XINT_expr_op_-ix\endcsname -\def\XINT_expr_until_**_b ##1##2##3##4% -{% - \ifnum ##2>\XINT_expr_precedence_** - \xint_afterfi - {\expandafter \XINT_expr_until_**_a \expandafter ##1% - \romannumeral`&&@\csname XINT_expr_op_##3\endcsname{##4}}% - \else - \xint_afterfi - {\expandafter ##2\expandafter ##3% - \csname .=\XINT:NEhook:two - \PoorManPower{\XINT_expr_unlock ##1}{\XINT_expr_unlock ##4}\endcsname - }% - \fi -}% -\let\XINT_flexpr_op_** \XINT_expr_op_** -\let\XINT_flexpr_until_**_a\XINT_expr_until_**_a -\let\XINT_flexpr_until_**_b\XINT_expr_until_**_b + }% + \def##5####1####2% \XINT_expr_checkp_<op> + {% + \ifnum ####1>\XINT_expr_precedence_** + \expandafter##5% + \romannumeral`&&@\csname XINT_##6_op_####2\expandafter\endcsname + \else + \expandafter ####1\expandafter ####2% + \fi + }% + }% + \expandafter\XINT_tmpa + \csname XINT_expr_op_-ix\expandafter\endcsname + \csname XINT_expr_check-_**\endcsname + \XINT_expr_op_** + \XINT_expr_exec_** + \XINT_expr_checkp_** {expr}% + \expandafter\XINT_tmpa + \csname XINT_flexpr_op_-ix\expandafter\endcsname + \csname XINT_flexpr_check-_**\endcsname + \XINT_flexpr_op_** + \XINT_flexpr_exec_** + \XINT_flexpr_checkp_** {flexpr}% + \def\XINT_expr_exec_** ##1##2##3##4% \XINT_expr_exec_<op> + {% + \expandafter##2\expandafter##3\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:two + {\romannumeral`&&@\PoorManPower##1##4}}% + }% + \let\XINT_flexpr_exec_**\XINT_expr_exec_** }% -\def\poormanloghack^{% -\def\XINT_expr_until_^_b ##1##2##3##4% +\def\poormanloghack^ {% - \ifnum ##2>\XINT_expr_precedence_^ - \xint_afterfi - {\expandafter \XINT_expr_until_^_a \expandafter ##1% - \romannumeral`&&@\csname XINT_expr_op_##3\endcsname {##4}}% - \else - \xint_afterfi - {\expandafter ##2\expandafter ##3% - \csname .=\XINT:NEhook:two - \PoorManPower{\XINT_expr_unlock ##1}{\XINT_expr_unlock ##4}\endcsname - }% - \fi -}% -\let\XINT_flexpr_until_^_b\XINT_expr_until_^_b + \def\XINT_tmpa ##1##2##3##4##5##6% + {% + \def ##3####1% \XINT_expr_op_<op> + {% + \expanded{\unexpanded{##4{####1}}\expandafter}% + \romannumeral`&&@\expandafter##2\romannumeral`&&@\XINT_expr_getnext + }% + \def##2####1% \XINT_expr_check-_<op> + {% + \xint_UDsignfork + ####1{\expandafter##2\romannumeral`&&@##1}% + -{##5####1}% + \krof + }% + \def##5####1####2% \XINT_expr_checkp_<op> + {% + \ifnum ####1>\XINT_expr_precedence_^ + \expandafter##5% + \romannumeral`&&@\csname XINT_##6_op_####2\expandafter\endcsname + \else + \expandafter ####1\expandafter ####2% + \fi + }% + }% + \expandafter\XINT_tmpa + \csname XINT_expr_op_-ix\expandafter\endcsname + \csname XINT_expr_check-_^\endcsname + \XINT_expr_op_^ + \XINT_expr_exec_^ + \XINT_expr_checkp_^ {expr}% + \expandafter\XINT_tmpa + \csname XINT_flexpr_op_-ix\expandafter\endcsname + \csname XINT_flexpr_check-_^\endcsname + \XINT_flexpr_op_^ + \XINT_flexpr_exec_^ + \XINT_flexpr_checkp_^ {flexpr}% + \def\XINT_expr_exec_^ ##1##2##3##4% \XINT_expr_exec_<op> + {% + \expandafter##2\expandafter##3\expandafter{% + \romannumeral`&&@\XINT:NEhook:f:one:from:two + {\romannumeral`&&@\PoorManPower##1##4}}% + }% + \let\XINT_flexpr_exec_^\XINT_expr_exec_^ }% \def\poormanloghack#1{\csname poormanloghack#1\endcsname}% % \end{macrocode} -% \lverb|We don't worry about resetting catcodes now as this file is +% \lverb|IMPORTANT: We don't worry about resetting catcodes now as this file is % theoretically only loadable from xintexpr.sty itself which will take care of % the needed restore.| % \StoreCodelineNo {xintlog} @@ -40795,38 +41822,38 @@ math shift catcode. %<*dtx>----------------------------------------------------------- \iffalse % grep -c -e "^{%" xint*sty -xint.sty:190 +xint.sty:205 xintbinhex.sty:53 xintcfrac.sty:183 xintcore.sty:271 -xintexpr.sty:287 -xintfrac.sty:473 -xintgcd.sty:48 -xintkernel.sty:15 -xintlog.sty:11 +xintexpr.sty:412 +xintfrac.sty:492 +xintgcd.sty:41 +xintkernel.sty:17 +xintlog.sty:9 xintseries.sty:48 -xinttools.sty:140 +xinttools.sty:153 xinttrig.sty:31 \fi % grep -o "^{%" xint*sty | wc -l -\def\totala{ 1750} +\def\totala{ 1915} \iffalse % grep -c -e "^}%" xint*sty -xint.sty:189 +xint.sty:204 xintbinhex.sty:52 xintcfrac.sty:183 xintcore.sty:268 -xintexpr.sty:314 -xintfrac.sty:476 -xintgcd.sty:50 -xintkernel.sty:16 -xintlog.sty:12 +xintexpr.sty:400 +xintfrac.sty:495 +xintgcd.sty:43 +xintkernel.sty:18 +xintlog.sty:9 xintseries.sty:48 -xinttools.sty:139 +xinttools.sty:152 xinttrig.sty:32 \fi % grep -o "^}%" xint*sty | wc -l -\def\totalb{ 1779} +\def\totalb{ 1904} \cleardoublepage \section{Cumulative line count} @@ -40850,7 +41877,7 @@ xinttrig.sty:32 \TeX\strut. Version {\xintbndlversion} of {\xintbndldate}.\par } -\CheckSum {33497}% 1.3f +\CheckSum {34575}% 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, diff --git a/macros/generic/xint/xint.pdf b/macros/generic/xint/xint.pdf Binary files differindex d81acf490b..2ba88c84fe 100644 --- a/macros/generic/xint/xint.pdf +++ b/macros/generic/xint/xint.pdf |