texlive[47510] Master/texmfdist: apnum (23apr18)
commits+karl at tug.org
commits+karl at tug.org
Mon Apr 30 19:03:56 CEST 2018
Revision: 47510
http://tug.org/svn/texlive?view=revision&revision=47510
Author: karl
Date: 20180430 19:03:56 +0200 (Mon, 30 Apr 2018)
Log Message:

apnum (23apr18)
Modified Paths:

trunk/Master/texmfdist/doc/generic/apnum/README
trunk/Master/texmfdist/doc/generic/apnum/apnum.d
trunk/Master/texmfdist/doc/generic/apnum/apnum.pdf
trunk/Master/texmfdist/tex/generic/apnum/apnum.tex
Modified: trunk/Master/texmfdist/doc/generic/apnum/README
===================================================================
 trunk/Master/texmfdist/doc/generic/apnum/README 20180430 17:03:34 UTC (rev 47509)
+++ trunk/Master/texmfdist/doc/generic/apnum/README 20180430 17:03:56 UTC (rev 47510)
@@ 26,3 +26,4 @@
1.4 <Dec 2015>  \SIN, \COS, \TAN, \ASIN, \ACOS, \ATAN, \PI, \PIhalf added
1.5 <Jan 2016>  \eprint for printing evaluated expressions added.
1.6 <Feb 2016>  \evalmdef introduced, \EXP improved.
+1.7 <Apr 2018>  \eprint  round braces around an expression with unary minus
Modified: trunk/Master/texmfdist/doc/generic/apnum/apnum.d
===================================================================
 trunk/Master/texmfdist/doc/generic/apnum/apnum.d 20180430 17:03:34 UTC (rev 47509)
+++ trunk/Master/texmfdist/doc/generic/apnum/apnum.d 20180430 17:03:56 UTC (rev 47510)
@@ 1,6 +1,6 @@
% apnum.tex  Arbitrary Precision Numbers
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The documentation, Petr Olsak, 2014, 2015, 2016
+% The documentation, Petr Olsak, 2014, 2015, 2016, 2018
% You can create the pdf version of this documentation by the command
% pdfcsplain apnum.d
@@ 10,7 +10,7 @@
\input utf8off \clearmubyte % use pdfcsplain
\def\projectversion{1.6 Feb 2016}
+\def\projectversion{1.7 Apr 2018}
\def\headtitle{Arbitrary Precision Numbers}
\widowpenalty=10000
@@ 520,15 +520,16 @@
\def\vars{\def\X{x}\def\Y{y}\let\apMULop=\relax}
\def\nums{\corrnum\X \corrnum\Y}
\printresult
{(\X\SQRT{\Y^2+1}) + ((\X*\Y+1)/2) + \SIN{\X+\PIhalf} + 2*\COS{\Y}}
+{(\X\SQRT{\Y^2+1}) + ((\Y*\X+1)/2) + \SIN{\X+\PIhalf} + 2*\COS{\Y}}
\endtt
generates the result:
$$
\displaylines{
  \left(x\sqrt{y^2+1}\right) +  {xy+1\over 2}
 + \sin\left( x+{\pi\over2}\right) + 2 \cos y = \cr
 =  \left(0.25\sqrt{18.11^2+1}\right) +  {0.25\cdot18.11+1\over 2}
 + \sin\left( 0.25+{\pi\over2}\right) + 2\cdot \cos 18.11 = \cr
+  \left(x\sqrt{y^2+1}\right) + \left( {yx+1\over 2}\right)
+ + \sin\!\left( x+{\pi\over2}\right) + 2 \cos y = \cr
+ =  \left(0.25\sqrt{18.11^2+1}\right) +
+ \left( {18.11\cdot(0.25)+1\over 2}\right)
+ + \sin\!\left( 0.25+{\pi\over2}\right) + 2\cdot \cos 18.11 = \cr
= 22.5977863, \cr
x = 0.25, \quad y = 18.11
}
@@ 540,10 +541,10 @@
Note that "\eprint" macro recalculates the occurrences of round brackets but
keeps the meaning of the "<expression>".
For example "(\A+\B)/\C" is printed as "{a+b\over c}" (without brackets) and
"6*(\A+\B)" is printed as "6\cdot((a+b))" (new brackets pair is added).
Or "\SIN{\X}" is printed as "\sin x" (without brackets) but "\SIN{\X+1}"
is printed as "\sin(x+1)" (with brackets). And "\SIN{X}^2" is printed as
+For example "(a+b)/c" is printed as "{a+b\over c}" (without brackets) and
+"6*(a+b)" is printed as "6\cdot((a+b))" (new brackets pair is added).
+Or "\SIN{x}" is printed as "\sin x" (without brackets) but "\SIN{x+1}"
+is printed as "\sin(x+1)" (with brackets). And "\SIN{x}^2" is printed as
"\sin^2 x".
You can do \du{apMULop}"\let\apMULop=\," or "\let\apMULop=\relax" in the
@@ 570,14 +571,15 @@
"\noBK" prints it without brackets when using "\eprint".
\begtt
\def\BK#1{\relax \evaldef\OUT{#1}}
\let\noBK=\BK
\def\BKprint#1{\left(\eprint{#1}{}\right)}
\def\noBKprint#1{\eprint{#1}{}}
\def\setBK{\let\BK=\BKprint \let\noBK=\noBKprint}
Now $\eprint{3+\BK{\SIN{1}}^2}{\setBK}$ prints $3+(\sin 1)^2$.
+\def\BK#1{\relax \evaldef\OUT{#1}} \let\noBK=\BK
+\def\apEPj{\def\BK##1{\left(\eprint{##1}{}\right)}%
+ \def\noBK##1{\eprint{##1}{}}}
+Now $\eprint{3+\BK{\SIN{1}}^2}{}$ prints $3+(\sin 1)^2$.
\endtt
+Note that "\apEPj" macro is an initial hook of "\eprint"
+(it is run inside group before processing of the second parameter of "\eprint").
+
\subsec [tests] Experiments
The following table shows the time needed for calculation of randomly
@@ 2687,7 +2689,7 @@
in the first step like "\evaldef". This is done by "\apEVALb#1\limits".
The result is stored in the "\tmpb" macro in Polish notation.
Then the internal initialization is processed in "\apEPi" and userspace
initialization is added in "#2". Then "\tmpb" is processed. The \db apEPe can
+initialization is added in "\apEPj" and "#2". Then "\tmpb" is processed. The \db apEPe can
do something endgame play but typically it is "\relax".
\inext{eprint}{^^B\cbrace}{++}
@@ 2705,55 +2707,79 @@
\inext{apEPi}{def\nb apEPj}{++}
All parameters are processed in new group. For example we have
+All parameters are processed in new group (excepts individual constants).
+For example we have
"\apPLUS{a}{\apDIV{b}{c}}" in the "\tmpb". Then the
"{a}+{\apDIV{b}{c}}" is processed and thus "{a}+{{b}\over{c}}" is printed.
The outer group is set by "\eprint" macro itself. So, the ``printing''
meaning of "\apPLUS" prepared in \db apEPplus looks like:
+"a+{\apDIV{b}{c}}" is processed and thus "a+{b\over c}" is printed.
+As noted above, the outer group is set by "\eprint" macro itself.
\inext{apEPplus}{}{++}

When we process the "\tmpb" with the output of the "<expression>"
interpreter then the original positions of the round brackets are lost. We
must to print these brackets if it is required by usual math syntax. For
example "\apMINUS{a}{\apPLUS{b}{c}}" must be printed as "a(b+c)".
But "\apMINUS{a}{\apMUL{b}{c}}" must be printed as "abc".
+interpreter then the original positions of the round brackets are definitively
+lost. We must to print these brackets if it is required by usual math syntax.
+For example "\apPLUS{1}{2}" must be printed as "1+(2)".
+But "\apPLUS{1}{2}" must be printed as "1+2". So, we print
+all parameters using "\apEPp{<parameter>}{<a><b><c><d>}".
+This macro decides if the parameter will be surrounded by brackets or not.
+So, the ``printing'' meaning of "\apPLUS" (or "\apMINUS" respectively)
+and prepared in \db apEPplus (or \db apEPminus respectively) looks like:
The "\apEPp<parameter>\empty\end<a><b><c><d><e>" is used for this feature.
The result of "\apEPp" is the "<parameter>" enclosed or not enclosed in
round brackets. It depends on the main operator $\M$ in the "<parameter>" and
on the given parameters "<a><b><c><d><e>". If $\M$ is "\apPLUS" and "<a>" isn't
dot or $\M$ is "\apMINUS" and "<b>" isn't dot or $\M$ is (unary minus or
"\apMUL") and "<c>" isn't dot or $\M$ is "\apDIV" and "<d>" isn't dot or $\M$
is "\apPOWx" and "<e>" isn't dot then the "<parameter>" is enclosed in brackets
using "\left(<parameter>\right)".
Else the "<parameter>" is enclosed in invisible groupbraces only. If $\M$ is
nothing mentioned above (because single operand is here) then no brackets
and no invisible braces are used and the "<parameter>" is printed ``as is''.
This feature is used in the printing version of "\apMINUS", i.~e.\ in
\db apEPminus macro (and in many others macros).
The second parameter of "\apMINUS" is enclosed in brackets only if its main
operator $\M$ is "+" or "".
+\inext{apEPplus}{apEPminus}{++}
\inext{apEPminus}{}{++}
+The usage of "\apEPp{<parameter>}{<a><b><c><d>}" has the
+following meaning:
+\begitems
+\item * if "<a>" is "!" and the "<parameter>" is a negative constant or
+ a "<expression>" or
+\item * if "<b>" is "!" and main operator $\M$ of the "<parameter>" is "+" or "" or
+\item * if "<c>" is "!" and main operator $\M$ of the "<parameter>" is "*" or
+\item * if "<d>" is "!" and main operator $\M$ of the "<parameter>" is "/" or "^"
+\enditems
+\noindent then "\apEPp" prints brackets around the "<parameter>" using
+"\left(<parameter>\right)".
+Else it doesn't use brackets around the "<parameter>" (but the "<parameter>"
+itself is printed in a group unless it is single element: constant, variable).
+
+The rule for the parameter "<a>" has the exception: if "<a>" is "?" and the
+"<parameter>" is a negative constant or a "<expression>", then brackets are
+not used if and only if this is ``very first parameter'', it means that
+the "<parameter>" is first:
+\begitems
+\item * at beginning of the whole "<expression>" given as an argument
+ of "\eprint" or
+\item * immediately after an opening bracket or
+\item * at beginning of a numerator or a denominator in a fraction or
+\item * at beginning of an exponent.
+\enditems
+
+For example "1+1" is preprocessed as "\apPLUS{1}{1}" and printed as "1+1"
+because first parameter has "<a>" equal to "?" and we are at beginning of
+the expression. But "1+1" is preprocessed as
+"\apPLUS{1}{1}" and printed as "1+(1)" because second parameter has "<a>"
+equal to "!". The "2*(1+5)" is printed as "2\cdot(1+5)" because "1" is
+``very first parameter'' after opening bracket.
+Another examples: "1+1+1" is printed as "1+(1)+(1)",
+"a+b*c" is printed as "a+b\cdot c" (without brackets), The "1(2+3)" is
+printed ``as is'' but "1+(2+3)" is printed as "1+2+3".
+
+The question about to be ``very first parameter'' is controlled by the value of
+\db apEPx macro. It is started as "." and it is replaced by "!" whenever "<a>" is "!".
+It is reverted to "." when open bracket is printed.
+
The unary minus in the cases like "(a+b)" are transformed
to "\apMUL{1}{\apPLUS{a}{b}}"
by the "<expression>" interpreter. But we don't need
to print "1\cdot(a+b)". So, the printing version of "\apMUL" stored in the
macro \db apEPmul have an exception. First, we do the test, if "#1" is equal
to "1". If this is true, then we print the unary minus else we print the
whole first parameter enclosed in braces if its $\M$ is "+" or "".
The second parameter is enclosed in braces if its $\M$ is "+" or "" or "*".
This needs more explanation: The multiplying chains as "a*b*c" are processed
from left to right in the "<expression>" scanner and the result is
"\apMUL{\apMUL{a}{b}}{c}". So, no brackets are printed. But the "a*(b+c)"
is converted to "\apMUL{a}{\apMUL{1}{\apPLUS{b}{c}}}" and we need to print
this as "a\cdot((b+c))". This is the reason why the second parameter of
"\apMUL" will be in brackets when its $\M$ is "*".
+to "1". If this is true, then we print only the unary minus (no whole "1\cdot").
+Else we print the whole first parameter (enclosed in braces if its $\M$ is "+" or "").
+The first case has two subcases: if "\apEPx" is "!" (it means that it is not
+``very first parameter'' then brackets are used around "<expression>".
\inext{apEPmul}{!!!}{++}
+The second parameter is enclosed in brackets if its $\M$ is "+" or "".
+\inext{apEPmul}{^^B\cbrace}{++}
+
The \db apEPdiv macro used for printing "\apDIV" is very easy. We needn't to set
the outer group here because each parameter is enclosed in the group. We
need not to add any round brackets here because fraction generated by
@@ 2773,17 +2799,17 @@
and only "<base>" is processed (the "\apEPy" is printed inside this
processing) else "\apEPy" is empty and the "<base>" enclosed
in brackets is followed by "^{<exponent>}". Note that the "<base>" isn't
enclosed by brackets if its $\M$ is missing, i.~e.\ the "<base>" is single
operand.
+enclosed by brackets only if the "<base>" is single and positive operand.
\inext{apEPpow}{^^B\cbrace}{++}
The \db apEPpowa macro detects the special functionlike macro "\SIN", "\COS"
+The \db apEPpowa and \db apEPpowb macros detect the special
+functionlike macro "\SIN", "\COS"
etc. by performing one expansion step on the tested "<base>". If the first
"<token>" is "\apEPf" then the special functionlike macro is detected.
Note that "\SIN", "\COS" etc. are defined as "\apEPf" in the "\apEPi" macro.
\inext{}{\count=2 let\nb apEPy}{++}
+\inext{apEPpowa}{apEPy}{++}
The functions like "\SIN{<expression>}" are printed by
\db apEPf "{<name>}{<expression>}". First, the "\mathop{<name>}\nolimits" is
@@ 2793,30 +2819,57 @@
\inext{apEPf}{^^B\cbrace}{++}
The code "\expandafter"\db apEPb in the "<declaration>" part of "\eprint"
expands the following "\tmpb" (the result of the "<expression>" scanner) and
checks the first token. By default the "<expression>" will be enclosed by
brackets (see the default "\next" definition where closing brace is printed
by "\apEPe" macro used after expanded "\tmpb"). But if the first token is
"\apPPn" or "\apDIV" then no brackets are printed around the "<expression>".
+The spacecorrection macro \db apEPk is set to remove the "\thinmuskip"
+after "\mathop". This will be processed only if the "\left(" follows: we want
+to print "\sin\apEPk\left(<expression>\right)" because this gives the same result as
+"\sin(<expression>)". On the other hand we don't use "\apEPk" when simple "\sin x"
+is printed without brackets.
+
+By default the "<expression>" (this is an argument of common functionlike
+macros "\SIN", "\COS", "\EXP" etc.) will be printed in brackets
+(see the default "\next" definition
+where closing bracket is printed by "\apEPe" macro used after expanded "\tmpb").
+But if
+\begitems
+\item * the "<expression>" is single nonnegatie object
+ (a constant or a variable without unary minus) or
+\item * the "<expression>" is a fraction of the form "{<nominator>\over<denominator>}"
+\enditems
+
+\noindent then no brackets are printed around the "<expression>".
+
+This rule is implemented by the usage of
+"\expandafter"\db apEPb in the "<declaration>" part of "\eprint"
+(in the code of "\apEPf" above). It
+expands the following "\tmpb" (the result of the expression scanner) and
+checks the first token and the following parameter.
Note that the "<expression>" scanner generates "\apPPn{<operand>}" if and
only if the whole "<expression>" is a single operand.
\inext{apEPb}{^^B\cbrace}{++}
The meaning of \db apEPp "<parameter>\empty\end<a><b><c><d><e>" is
explained above, see the text where "\apEPminus" is introduced.
+The meaning of \db apEPp "{<parameter>}{<a><b><c><d>}" is
+explained above, see the text where "\apEPplus" is introduced.
Now, we focus to the implementation of this feature. The auxiliary macro
\db apEPa "<first token>{<normal>}{<bracket>}<a><b><c><d><e>" is used twice:
before processing the "<parameter>" "#1#2" and after processing. The "\apEPa"
+\db apEPa "<first token><rest>\end{<normal>}{<bracket>}<a><b><c><d>"
+is used twice:
+before processing the "<parameter>" and after processing. The "\apEPa"
inserts the "<normal>" or "<bracket>" depending on the condition described
above where $\M$ is equal to the "<first token>". Note the trick with
"\empty" which is inserted at the end of "#2" parameter. The "<parameter>"
should be in the form "\SIN{...}". If the "\empty" token isn't added then
"#2" becomes the text without braces and this is not desired.
+above where $\M$ (or unary "" when "<parameter>" is negative constant)
+is equal to the "<first token>".
\inext{apEPp}{^^B\cbrace}{++}
+If we have variables like "\def\X{17}" and the expression looks like
+"1+\X" and the constants stored in the varaibales must to be printed
+then we have "\apPLUS{1}{\X}" after expression scanner and we need
+to print "1+(17)".
+So we need to try to expand the "<paramter>" and to test if there is the
+unary "" as a "<firsttok>". This is done by
+\db apEPd "<firsttok><rest>\end{<grouptype>}{<elsepart>}{<dotorexclam>}".
+
+\inext{apEPd}{}{++}
+
The \db apMULop is used as an operation mark for multiplying.
It is "\cdot" by default but user can change this.
Modified: trunk/Master/texmfdist/doc/generic/apnum/apnum.pdf
===================================================================
(Binary files differ)
Modified: trunk/Master/texmfdist/tex/generic/apnum/apnum.tex
===================================================================
 trunk/Master/texmfdist/tex/generic/apnum/apnum.tex 20180430 17:03:34 UTC (rev 47509)
+++ trunk/Master/texmfdist/tex/generic/apnum/apnum.tex 20180430 17:03:56 UTC (rev 47510)
@@ 1,10 +1,10 @@
% Arbitrary precision numbers
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 2014, 2015, 2016 Petr Olsak
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 2014, 2015, 2016, 2018 Petr Olsak
% See the documentation apnum.pdf or apnum.d for more information
\def\apVERSION{1.6 <Feb 2016>}
+\def\apVERSION{1.7 <Apr 2018>}
\message{The Arbitrary Precision Numbers, \apVERSION}
%%%%%%%%%%%% Internal registers, sec. 2.1 in apnum.pdf
@@ 1033,7 +1033,7 @@
\advance\apFRAC by3
\do\denom=\COS\X;%
\ifnum\apSIGN=0 \apERR{\string\TAN: argument {\X} is out of range}\apRETURN\fi
 \SIN\X\message{\OUT/\denom}%
+ \SIN\X
\apDIV{\SIN\X}\denom
\apEND
}
@@ 1082,6 +1082,7 @@
}
\def\ACOS#1{\relax \apPIexec \apPLUS\apPIhalf{\ASIN{#1}}}
+
%%%%%%%%%%%% Printing expressions, sec 2.11 in apnum.pdf
\def\eprint#1#2{\bgroup \apnumA=0 \apnumE=1 \apEVALb#1\limits
@@ 1096,41 +1097,48 @@
\let\ABS=\apEPabs \let\FAC=\apEPfac \let\BINOM=\apEPbinom
\let\SGN=\apEPsgn \let\iDIV=\apEPidiv \let\iMOD=\apEPimod
\let\iFLOOR=\apEPifloor \let\iFRAC=\apEPifrac
+ \let\apEPk=\empty \let\apEPy=\empty \def\apEPx{.}%
\let\apEPi=\relax \apEPj
}
\def\apEPj{}
\def\apEPplus#1#2{{#1}+{#2}}
\def\apEPminus#1#2{{#1}\apEPp#2\empty\end!!...}
+\def\apEPplus#1#2{\apEPp{#1}{?...}+\apEPp{#2}{!...}}
+\def\apEPminus#1#2{\apEPp{#1}{?...}\apEPp{#2}{!!..}}
\def\apEPmul#1#2{\def\tmpa{#1}\def\tmpb{1}%
 \ifx\tmpa\tmpb \else \apEPp#1\empty\end!!...\apMULop\fi
 \apEPp#2\empty\end!!!..}
\def\apEPdiv#1#2{{#1}\over{#2}}
+ \ifx\tmpa\tmpb \if\apEPx!\left(\apEPp{#2}{!!..}\right)\else
+ \apEPp{#2}{!!..}\fi
+ \else \apEPp{#1}{?!..}\apMULop \apEPp{#2}{!!..}\fi
+}
+\def\apEPdiv#1#2{{\def\apEPx{.}#1}\over{\def\apEPx{.}#2}}
\def\apEPpow#1#2{%
\let\apEPy=\empty \apEPpowa{#1}\end{#2}%
 \ifx\apEPy\empty \apEPp#1\empty\end!!!!!^{#2}\else#1\fi
+ \ifx\apEPy\empty \apEPp{#1}{!!!!}^{\def\apEPx{.}#2}\else#1\fi
}
\def\apEPpowa#1{\expandafter\apEPpowb#1;}
\def\apEPpowb#1#2;\end#3{\ifx#1\apEPf \def\apEPy{\let\apEPy=\empty #3}\fi}
\let\apEPy=\empty
\def\apEPf#1#2{\mathop{\rm#1}\nolimits
+\def\apEPpowb#1#2;\end#3{\ifx#1\apEPf \def\apEPy{\let\apEPy=\empty\def\apEPx{.}#3}\fi}
+\def\apEPf#1#2{\begingroup
+ \mathop{\rm#1}\nolimits
\ifx\apEPy\empty \else ^{\apEPy}\let\apEPy=\empty \fi
 \eprint{#2}{\expandafter\apEPb}%
+ \def\apEPk{\mskip\thinmuskip}%
+ \def\apEPx{.}%
+ \eprint{#2}{\expandafter\apEPb}\endgroup
}
\def\apEPb#1{\def\next{\left(\def\apEPe{\right)}}%
 \ifx\apPPn#1\let\next=\relax \fi
+\def\apEPb#1#2{\def\next{\apEPk\left(\def\apEPe{\right)}}%
+ \ifx\apPPn#1\expandafter\apEPd#2.\end{}{\let\next=\relax}.\fi
\ifx\apDIV#1\let\next=\relax \fi
 \next#1%
+ \next\let\apEPk=\empty #1{#2}%
}
\def\apEPp#1#2\end#3#4#5#6#7{%
 \apEPa#1\bgroup{\left(}#3#4#5#6#7#1#2\apEPa#1\egroup{\right)}#3#4#5#6#7}
\def\apEPa#1#2#3#4#5#6#7#8{%
 \ifx#1\apEPplus \ifx#4.#2\else#3\fi\fi
 \ifx#1\apEPminus \ifx#5.#2\else#3\fi\fi
 \ifx#1\apEPmul \ifx#6.#2\else#3\fi\fi
 \ifx#1\apEPdiv \ifx#7.#2\else#3\fi\fi
 \ifx#1\apEPpow \ifx#8.#2\else#3\fi\fi
 \ifx#1\empty \ifx#6.#2\else#3\fi\fi
+\def\apEPp#1#2{\apEPq#1\end\bgroup{\left(\def\apEPx{.}}#2#1\apEPq#1\end\egroup{\right)}#2}
+\def\apEPq#1#2\end#3#4#5#6#7#8{
+ \ifx#5!\def\apEPx{!}\fi
+ \ifx#1\apEPplus \ifx#6!#4\else#3\fi\else
+ \ifx#1\apEPminus \ifx#6!#4\else#3\fi\else
+ \ifx#1\apEPmul \ifx#7!#4\else#3\fi\else
+ \ifx#1\apEPdiv \ifx#8!#4\else#3\fi\else
+ \ifx#1\apEPpow \ifx#8!#4\else#3\fi\else
+ \expandafter\apEPd#1.\end#3{}\apEPx\fi\fi\fi\fi\fi
}
+\def\apEPd#1#2\end#3#4#5{\ifx#1\if#5!\ifx#3\bgroup\left(\else\right)\fi\fi\else#4\fi}
+
\let\apMULop=\cdot
\def\apEPabs#1{\left\eprint{#1}{}\right}
\def\apEPfac#1{\eprint{#1}{\expandafter\apEPb}\,!}
@@ 1191,3 +1199,5 @@
1.6 <Feb 2016>
 \evalmdef introduced
 \EXP for arg>=4 rewritten, \apEX register introduced
+1.7 <Apr 2018>
+  \eprint: bug removed (round brackets around negative constants)
More information about the texlivecommits
mailing list