summaryrefslogtreecommitdiff
path: root/Master/texmf-dist
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2013-11-22 00:05:28 +0000
committerKarl Berry <karl@freefriends.org>2013-11-22 00:05:28 +0000
commit4efb0e288e61307337a1593f83dead03178acc61 (patch)
tree1de51740df3962c81edef97135bac249b41d3fe1 /Master/texmf-dist
parent9dd6af228b319f176777f85b0b551eda0df6cfbe (diff)
l3 (19nov13)
git-svn-id: svn://tug.org/texlive/trunk@32204 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist')
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/l3dt/l3dt.pdfbin550367 -> 550355 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/l3sort/l3sort.pdfbin557262 -> 557250 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/l3str/l3flag.pdfbin390095 -> 390079 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/l3str/l3regex.pdfbin982431 -> 982419 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-convert.pdfbin781932 -> 781920 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-format.pdfbin568869 -> 569053 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/l3str/l3str.pdfbin622988 -> 622976 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-analysis.pdfbin521023 -> 521010 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-build.pdfbin468386 -> 468371 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins.pdfbin490253 -> 490241 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/xgalley/l3galley.pdfbin681136 -> 681124 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/xgalley/xgalley.pdfbin575678 -> 575666 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3kernel/expl3.pdfbin675078 -> 675005 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3kernel/interface3.pdfbin1280497 -> 1288070 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3kernel/l3docstrip.pdfbin449468 -> 449457 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3kernel/l3styleguide.pdfbin273218 -> 273207 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.pdfbin220216 -> 220205 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3kernel/source3.pdfbin3823187 -> 3954716 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3packages/l3keys2e/l3keys2e.pdfbin473658 -> 473902 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3packages/xfrac/xfrac.pdfbin633950 -> 633938 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3packages/xparse/xparse.pdfbin450342 -> 450406 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3packages/xtemplate/xtemplate.pdfbin401066 -> 401376 bytes
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx2
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/expl3.dtx4
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx14
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx19
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx23
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx111
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx38
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx54
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx35
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx872
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx60
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx2895
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx7
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx1569
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp.dtx225
-rw-r--r--Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx6
-rw-r--r--Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx6
-rw-r--r--Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx6
-rw-r--r--Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-format.sty2
-rw-r--r--Master/texmf-dist/tex/latex/l3kernel/expl3.sty4
-rw-r--r--Master/texmf-dist/tex/latex/l3kernel/l3candidates.sty10
-rw-r--r--Master/texmf-dist/tex/latex/l3kernel/l3dvipdfmx.def13
-rw-r--r--Master/texmf-dist/tex/latex/l3kernel/l3dvips.def7
-rw-r--r--Master/texmf-dist/tex/latex/l3kernel/l3fp.sty2298
-rw-r--r--Master/texmf-dist/tex/latex/l3kernel/l3pdfmode.def13
-rw-r--r--Master/texmf-dist/tex/latex/l3kernel/l3xdvipdfmx.def13
-rw-r--r--Master/texmf-dist/tex/latex/l3packages/l3keys2e/l3keys2e.sty6
-rw-r--r--Master/texmf-dist/tex/latex/l3packages/xparse/xparse.sty6
-rw-r--r--Master/texmf-dist/tex/latex/l3packages/xtemplate/xtemplate.sty6
51 files changed, 5267 insertions, 3057 deletions
diff --git a/Master/texmf-dist/doc/latex/l3experimental/l3dt/l3dt.pdf b/Master/texmf-dist/doc/latex/l3experimental/l3dt/l3dt.pdf
index 44e03f543a1..782bdba1bbf 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/l3dt/l3dt.pdf
+++ b/Master/texmf-dist/doc/latex/l3experimental/l3dt/l3dt.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/l3sort/l3sort.pdf b/Master/texmf-dist/doc/latex/l3experimental/l3sort/l3sort.pdf
index f3abd6807c4..10922c7f0ac 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/l3sort/l3sort.pdf
+++ b/Master/texmf-dist/doc/latex/l3experimental/l3sort/l3sort.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3flag.pdf b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3flag.pdf
index 15169cc7a30..3f9d7598f43 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3flag.pdf
+++ b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3flag.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3regex.pdf b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3regex.pdf
index e83139e48e8..94248639218 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3regex.pdf
+++ b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3regex.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-convert.pdf b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-convert.pdf
index 0d6aa751bd3..91d31870f09 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-convert.pdf
+++ b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-convert.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-format.pdf b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-format.pdf
index 2207ec1c978..fdd21b84082 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-format.pdf
+++ b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str-format.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str.pdf b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str.pdf
index 870c368f0aa..9a11edbd578 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str.pdf
+++ b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-analysis.pdf b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-analysis.pdf
index c5a4504d080..7d0ac5032da 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-analysis.pdf
+++ b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-analysis.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-build.pdf b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-build.pdf
index ed6d05fda8e..264b93f1d66 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-build.pdf
+++ b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3tl-build.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins.pdf b/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins.pdf
index dbd907a1694..638104e473b 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins.pdf
+++ b/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/xgalley/l3galley.pdf b/Master/texmf-dist/doc/latex/l3experimental/xgalley/l3galley.pdf
index 8dd00b79b0f..a1a273834b5 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/xgalley/l3galley.pdf
+++ b/Master/texmf-dist/doc/latex/l3experimental/xgalley/l3galley.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/xgalley/xgalley.pdf b/Master/texmf-dist/doc/latex/l3experimental/xgalley/xgalley.pdf
index 320c2f32e1d..6ebaabc14c3 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/xgalley/xgalley.pdf
+++ b/Master/texmf-dist/doc/latex/l3experimental/xgalley/xgalley.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3kernel/expl3.pdf b/Master/texmf-dist/doc/latex/l3kernel/expl3.pdf
index 544981c2b49..c4bb6e4dce7 100644
--- a/Master/texmf-dist/doc/latex/l3kernel/expl3.pdf
+++ b/Master/texmf-dist/doc/latex/l3kernel/expl3.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3kernel/interface3.pdf b/Master/texmf-dist/doc/latex/l3kernel/interface3.pdf
index 8955aea5fac..23e3b3384f0 100644
--- a/Master/texmf-dist/doc/latex/l3kernel/interface3.pdf
+++ b/Master/texmf-dist/doc/latex/l3kernel/interface3.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3kernel/l3docstrip.pdf b/Master/texmf-dist/doc/latex/l3kernel/l3docstrip.pdf
index 6228471ad90..04db83af2c9 100644
--- a/Master/texmf-dist/doc/latex/l3kernel/l3docstrip.pdf
+++ b/Master/texmf-dist/doc/latex/l3kernel/l3docstrip.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.pdf b/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.pdf
index a5120d37c59..735c3e5bab1 100644
--- a/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.pdf
+++ b/Master/texmf-dist/doc/latex/l3kernel/l3styleguide.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.pdf b/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.pdf
index bb1a53ccc77..af68866492e 100644
--- a/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.pdf
+++ b/Master/texmf-dist/doc/latex/l3kernel/l3syntax-changes.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3kernel/source3.pdf b/Master/texmf-dist/doc/latex/l3kernel/source3.pdf
index cd2eb01f1e6..aabf972adaa 100644
--- a/Master/texmf-dist/doc/latex/l3kernel/source3.pdf
+++ b/Master/texmf-dist/doc/latex/l3kernel/source3.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3packages/l3keys2e/l3keys2e.pdf b/Master/texmf-dist/doc/latex/l3packages/l3keys2e/l3keys2e.pdf
index 0c7306629f2..da9c5a642e8 100644
--- a/Master/texmf-dist/doc/latex/l3packages/l3keys2e/l3keys2e.pdf
+++ b/Master/texmf-dist/doc/latex/l3packages/l3keys2e/l3keys2e.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3packages/xfrac/xfrac.pdf b/Master/texmf-dist/doc/latex/l3packages/xfrac/xfrac.pdf
index b1a819d7ba6..c5cb8b68361 100644
--- a/Master/texmf-dist/doc/latex/l3packages/xfrac/xfrac.pdf
+++ b/Master/texmf-dist/doc/latex/l3packages/xfrac/xfrac.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3packages/xparse/xparse.pdf b/Master/texmf-dist/doc/latex/l3packages/xparse/xparse.pdf
index f7de0add4d8..42666aede14 100644
--- a/Master/texmf-dist/doc/latex/l3packages/xparse/xparse.pdf
+++ b/Master/texmf-dist/doc/latex/l3packages/xparse/xparse.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3packages/xtemplate/xtemplate.pdf b/Master/texmf-dist/doc/latex/l3packages/xtemplate/xtemplate.pdf
index 13041235b89..3be8a01e21f 100644
--- a/Master/texmf-dist/doc/latex/l3packages/xtemplate/xtemplate.pdf
+++ b/Master/texmf-dist/doc/latex/l3packages/xtemplate/xtemplate.pdf
Binary files differ
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx
index 10eea3278f4..92b3e1eebef 100644
--- a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx
+++ b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx
@@ -940,7 +940,7 @@
{ \fp_to_scientific:n }
{ \fp_to_decimal:n }
}
- { \__fp_abs_o:w #1; \prg_do_nothing: }
+ { \__fp_set_sign_o:w 0 #1; @ \prg_do_nothing: }
}
% \end{macrocode}
% \end{macro}
diff --git a/Master/texmf-dist/source/latex/l3kernel/expl3.dtx b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx
index 674e4bd6a23..96631cf3ed0 100644
--- a/Master/texmf-dist/source/latex/l3kernel/expl3.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx
@@ -49,8 +49,8 @@
%<*driver|package>
\def\ExplFileName{expl3}
\def\ExplFileDescription{L3 Experimental code bundle wrapper}
-\def\ExplFileDate{2013/10/13}
-\def\ExplFileVersion{4597}
+\def\ExplFileDate{2013/11/19}
+\def\ExplFileVersion{4610}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
index f9faeada808..c31a0e478de 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
@@ -36,7 +36,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3candidates.dtx 4576 2013-07-24 21:40:24Z joseph $
+\GetIdInfo$Id: l3candidates.dtx 4602 2013-11-18 23:19:01Z bruno $
{L3 Experimental additions to l3kernel}
%</driver|package>
%<*driver>
@@ -895,8 +895,8 @@
{
\group_begin:
\fp_set:Nn \l_@@_angle_fp {#2}
- \fp_set:Nn \l_@@_sin_fp { sin ( \l_@@_angle_fp * deg ) }
- \fp_set:Nn \l_@@_cos_fp { cos ( \l_@@_angle_fp * deg ) }
+ \fp_set:Nn \l_@@_sin_fp { sind ( \l_@@_angle_fp ) }
+ \fp_set:Nn \l_@@_cos_fp { cosd ( \l_@@_angle_fp ) }
\@@_rotate:N #1
\group_end:
}
@@ -1656,15 +1656,15 @@
%
% \begin{macro}{\coffin_rotate:Nn, \coffin_rotate:cn}
% Rotating a coffin requires several steps which can be conveniently
-% run together. The first step is to convert the angle given in degrees
-% to one in radians. This is then used to set \cs{l_@@_sin_fp} and
+% run together. The sine and cosine of the angle in degrees are
+% computed. This is then used to set \cs{l_@@_sin_fp} and
% \cs{l_@@_cos_fp}, which are carried through unchanged for the rest
% of the procedure.
% \begin{macrocode}
\cs_new_protected:Npn \coffin_rotate:Nn #1#2
{
- \fp_set:Nn \l_@@_sin_fp { sin ( ( #2 ) * deg ) }
- \fp_set:Nn \l_@@_cos_fp { cos ( ( #2 ) * deg ) }
+ \fp_set:Nn \l_@@_sin_fp { sind ( #2 ) }
+ \fp_set:Nn \l_@@_cos_fp { cosd ( #2 ) }
% \end{macrocode}
% The corners and poles of the coffin can now be rotated around the
% origin. This is best achieved using mapping functions.
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx b/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx
index 4fded9b0079..46426e18186 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3drivers.dtx Copyright(C) 2011-2012 The LaTeX3 Project
+%% File: l3drivers.dtx Copyright(C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -36,7 +36,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3drivers.dtx 4505 2013-06-28 22:06:04Z joseph $
+\GetIdInfo$Id: l3drivers.dtx 4602 2013-11-18 23:19:01Z bruno $
{L3 Experimental drivers}
%</driver|package>
%<*driver>
@@ -403,31 +403,30 @@
% case where the sine and cosine are used, we store the rounded values to
% avoid rounding twice. There are also a couple of comparisons to ensure
% that |-0| is not written to the output, as this avoids any issues with
-% problematic display programs.
+% problematic display programs. Note that numbers are compared to~$0$
+% after rounding.
% \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_box_rotate_begin:
{
\@@_graphic_state_save:
%<*dvips>
+ \fp_set:Nn \l__box_angle_fp { round ( \l__box_angle_fp , 5 ) }
\@@_ps_literal:n
{
currentpoint~
currentpoint~translate~
\fp_compare:nNnTF \l__box_angle_fp = \c_zero_fp
{ 0 }
- { \fp_eval:n { round ( - \l__box_angle_fp , 5 ) } }
+ { \fp_eval:n { - \l__box_angle_fp } }
\c_space_tl rotate~
neg~exch~neg~exch~translate
}
%</dvips>
%<*!dvips>
\box_set_wd:Nn \l__box_internal_box \c_zero_dim
- \fp_set:Nn \l__box_cos_fp
- {
- \fp_compare:nNnTF \l__box_cos_fp = \c_zero_fp
- { 0 }
- { round ( \l__box_cos_fp , 5 ) }
- }
+ \fp_set:Nn \l__box_cos_fp { round ( \l__box_cos_fp , 5 ) }
+ \fp_compare:nNnT \l__box_cos_fp = \c_zero_fp
+ { \fp_zero:N \l__box_cos_fp }
\fp_set:Nn \l__box_sin_fp { round ( \l__box_sin_fp , 5 ) }
\@@_pdf_matrix:n
{
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx
index c207d30abf5..c7c07218480 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-assign.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%%
-%% File: l3fp-assign.dtx Copyright (C) 2011-2012 The LaTeX3 project
+%% File: l3fp-assign.dtx Copyright (C) 2011-2013 The LaTeX3 project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -36,7 +36,7 @@
%
%<*driver>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3fp-assign.dtx 4212 2012-09-09 12:24:04Z bruno $
+\GetIdInfo$Id: l3fp-assign.dtx 4605 2013-11-19 03:05:27Z bruno $
{L3 Floating-point assignments}
\documentclass[full]{l3doc}
\begin{document}
@@ -93,15 +93,15 @@
% \fp_gset:Nn, \fp_gset:cn,
% \fp_const:Nn, \fp_const:cn
% }
-% Simply use \cs{@@_parse:n} within various \texttt{x}-expanding
+% Simply use \cs{@@_parse:n} within various \texttt{f}-expanding
% assignments.
% \begin{macrocode}
\cs_new_protected:Npn \fp_set:Nn #1#2
- { \tl_set:Nx #1 { \@@_parse:n {#2} } }
+ { \tl_set:Nx #1 { \exp_not:f { \@@_parse:n {#2} } } }
\cs_new_protected:Npn \fp_gset:Nn #1#2
- { \tl_gset:Nx #1 { \@@_parse:n {#2} } }
+ { \tl_gset:Nx #1 { \exp_not:f { \@@_parse:n {#2} } } }
\cs_new_protected:Npn \fp_const:Nn #1#2
- { \tl_const:Nx #1 { \@@_parse:n {#2} } }
+ { \tl_const:Nx #1 { \exp_not:f { \@@_parse:n {#2} } } }
\cs_generate_variant:Nn \fp_set:Nn {c}
\cs_generate_variant:Nn \fp_gset:Nn {c}
\cs_generate_variant:Nn \fp_const:Nn {c}
@@ -212,16 +212,9 @@
% \end{variable}
%
% \begin{variable}{\c_pi_fp, \c_one_degree_fp}
-% We do not round $\pi$ to the closest multiple of $10^{-15}$, which
-% would underestimate it by roughly $2.4\cdot 10^{-16}$, but instead
-% round it up to the next nearest multiple, which is an overestimate
-% by roughly $7.7\cdot 10^{-16}$. This particular choice of rounding
-% has very nice properties: it is exactly divisible by $4$ and by
-% $180$ as a $16$-digit precision floating point number, hence
-% ensuring that $\sin(180\mathrm{deg}) = \sin(\pi) = 0$ exactly, with
-% no rounding artifact.
+% We simply round $\pi$ to the closest multiple of $10^{-15}$.
% \begin{macrocode}
-\fp_const:Nn \c_pi_fp { 3.141 5926 5358 9794 }
+\fp_const:Nn \c_pi_fp { 3.141 5926 5358 9793 }
\fp_const:Nn \c_one_degree_fp { 0.0 1745 3292 5199 4330 }
% \end{macrocode}
% \end{variable}
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx
index bacb6065b5a..ee40577fbe8 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3fp-aux.dtx Copyright(C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-aux.dtx Copyright(C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -36,7 +36,7 @@
%
%<*driver>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3fp-aux.dtx 4339 2012-11-24 19:16:43Z joseph $
+\GetIdInfo$Id: l3fp-aux.dtx 4601 2013-11-18 23:13:28Z bruno $
{L3 Floating-point support functions}
\documentclass[full]{l3doc}
\begin{document}
@@ -83,6 +83,93 @@
% ^^A todo: make sanitize and pack more homogeneous between modules.
%
% ^^A begin[todo]: move
+% \section{Internal representation}
+%
+% Internally, a floating point number \meta{X} is a
+% token list containing
+% \begin{quote}
+% \cs{s_@@} \cs{@@_chk:w} \meta{case} \meta{sign} \meta{body} |;|
+% \end{quote}
+% Let us explain each piece separately.
+%
+% Internal floating point numbers will be used in expressions,
+% and in this context will be subject to f-expansion. They must
+% leave a recognizable mark after \texttt{f}-expansion, to prevent the
+% floating point number from being re-parsed. Thus, \cs{s_@@}
+% is simply another name for \tn{relax}.
+%
+% Since floating point numbers are always accessed by the various
+% operations using f-expansion, we can safely let them be protected:
+% \texttt{x}-expansion will then leave them untouched. However, when
+% used directly without an accessor function, floating points should
+% produce an error. \cs{s_@@} will do nothing, and \cs{@@_chk:w}
+% produces an error.
+%
+% The (decimal part of the) IEEE-754-2008 standard requires the
+% format to be able to represent special floating point numbers
+% besides the usual positive and negative cases. The various
+% possibilities will be distinguished by their \meta{case}, which
+% is a single digit:\footnote{Bruno: I need to implement subnormal
+% numbers. Also, quiet and signalling \texttt{nan} must be better
+% distinguished.}
+% \begin{itemize}
+% \item[0] zeros: |+0| and |-0|,
+% \item[1] \enquote{normal} numbers (positive and negative),
+% \item[2] infinities: |+inf| and |-inf|,
+% \item[3] quiet and signalling \texttt{nan}.
+% \end{itemize}
+% The \meta{sign} is |0| (positive) or |2| (negative),
+% except in the case of \texttt{nan}, which have $\meta{sign} = 1$.
+% This ensures that changing the \meta{sign} digit to $2-\meta{sign}$
+% is exactly equivalent to changing the sign of the number.
+%
+% Special floating point numbers have the form
+% \begin{quote}
+% \cs{s_@@} \cs{@@_chk:w} \meta{case} \meta{sign} \cs{s_@@_...} |;|
+% \end{quote}
+% where \cs{s_@@_...} is a scan mark carrying information about how the
+% number was formed (useful for debugging).
+%
+% Normal floating point numbers ($\meta{case} = 1$) have the form
+% \begin{quote}
+% \cs{s_@@} \cs{@@_chk:w} 1 \meta{sign} \Arg{exponent}
+% \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} |;|
+% \end{quote}
+% Here, the \meta{exponent} is an integer, at most
+% $\cs{c_@@_max_exponent_int} =
+% \the\csname\detokenize{c__fp_max_exponent_int}\endcsname$
+% in absolute value. The body consists in four
+% blocks of exactly $4$ digits, $ 0000 \leq \meta{X_i} \leq 9999$,
+% such that
+% \[
+% \meta{X}
+% = (-1)^{\meta{sign}} 10^{-\meta{exponent}}
+% \sum_{i=1}^{4} \meta{X_i} 10^{-4i}
+% \]
+% and such that the \meta{exponent} is minimal. This implies
+% $ 1000 \leq \meta{X_1} \leq 9999 $.
+%
+% \begin{table}\centering
+% \caption{Internal representation of floating point numbers.}
+% \label{tab:fp-convert-special}
+% \begin{tabular}{ll}
+% \toprule
+% \multicolumn{1}{c}{Representation} & Meaning \\
+% \midrule
+% 0 0 \cs{s_@@_...} \texttt{;} & Positive zero. \\
+% 0 2 \cs{s_@@_...} \texttt{;} & Negative zero. \\
+% 1 0 \Arg{exponent} \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} \texttt{;}
+% & Positive floating point. \\
+% 1 2 \Arg{exponent} \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} \texttt{;}
+% & Negative floating point. \\
+% 2 0 \cs{s_@@_...} \texttt{;} & Positive infinity. \\
+% 2 2 \cs{s_@@_...} \texttt{;} & Negative infinity. \\
+% 3 1 \cs{s_@@_...} \texttt{;} & Quiet \texttt{nan}. \\
+% 3 1 \cs{s_@@_...} \texttt{;} & Signalling \texttt{nan}. \\
+% \bottomrule
+% \end{tabular}
+% \end{table}
+%
% \section{Internal storage of floating points numbers}
%
% A floating point number \meta{X} is stored as
@@ -124,6 +211,7 @@
% (typically digits).
% \begin{macrocode}
\cs_new:Npn \@@_use_s:n #1 { #1; }
+\cs_new:Npn \@@_use_braced_s:n #1 { {#1} ; }
\cs_new:Npn \@@_use_s:nn #1#2 { #1#2; }
% \end{macrocode}
% \end{macro}
@@ -139,6 +227,7 @@
% \end{macrocode}
% \end{macro}
%
+% ^^A todo: rename to \@@_args_swap:Nww
% \begin{macro}[int, EXP]{\@@_reverse_args:Nww}
% Many internal functions take arguments delimited by semicolons, and
% it is occasionally useful to swap two such arguments.
@@ -147,6 +236,22 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}[int, EXP]{\@@_rrot:www}
+% Rotate three arguments delimited by semicolons. This is the inverse
+% (or the square) of the Forth primitive |ROT|.
+% \begin{macrocode}
+\cs_new:Npn \@@_rrot:www #1; #2; #3; { #2; #3; #1; }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int, EXP]{\@@_use_i:ww}
+% Many internal functions take arguments delimited by semicolons, and
+% it is occasionally useful to remove one such argument.
+% \begin{macrocode}
+\cs_new:Npn \@@_use_i:ww #1; #2; { #1; }
+% \end{macrocode}
+% \end{macro}
+%
% \subsection{Constants, and structure of floating points}
%
% \begin{macro}[int]{\s_@@, \@@_chk:w}
@@ -314,6 +419,7 @@
%
% \subsection{Expanding after a floating point number}
%
+% ^^A todo: maybe delete \cs{@@_exp_after_o:nw}?
% \begin{macro}[int, EXP]{\@@_exp_after_o:w}
% \begin{macro}[int, EXP]{\@@_exp_after_o:nw, \@@_exp_after_f:nw}
% \begin{syntax}
@@ -532,6 +638,7 @@
% \end{variable}
% \end{macro}
%
+% ^^A \@@_pack_Bigg:NNNNNNw = \@@_pack_big:NNNNNNw ?
% \begin{macro}[int, EXP]{\@@_pack_Bigg:NNNNNNw}
% \begin{variable}[int]
% {
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx
index cdc2e983983..104a118ca3b 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-basics.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3fp-basics.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-basics.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -36,7 +36,7 @@
%
%<*driver>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3fp-basics.dtx 4482 2013-04-24 21:05:12Z joseph $
+\GetIdInfo$Id: l3fp-basics.dtx 4601 2013-11-18 23:13:28Z bruno $
{L3 Floating-point arithmetic}
\documentclass[full]{l3doc}
\begin{document}
@@ -1601,35 +1601,23 @@
%
% \subsection{Unary operations}
%
-% \begin{macro}[int, EXP]{\@@_-_o:w}
-% This function flips the sign of the \meta{floating point} and
-% expands after it in the input stream, just like \cs{@@_+_o:ww}
-% \emph{etc.} We add a hook used by \pkg{l3fp-expo}: anything before
-% \cs{s_@@} is ignored.
+% \begin{macro}[int, EXP]{\@@_set_sign_o:w}
+% This function is used for the unary minus and for \texttt{abs}. It
+% leaves the sign of \texttt{nan} invariant, turns negative numbers
+% (sign~$2$) to positive numbers (sign~$0$) and positive numbers
+% (sign~$0$) to positive or negative numbers depending on~|#1|. It
+% also expands after itself in the input stream, just like
+% \cs{@@_+_o:ww}.
% \begin{macrocode}
-\cs_new:cpn { @@_-_o:w } #1 \s_@@ \@@_chk:w #2 #3
+\cs_new:Npn \@@_set_sign_o:w #1 \s_@@ \@@_chk:w #2#3#4; @
{
\exp_after:wN \@@_exp_after_o:w
\exp_after:wN \s_@@
\exp_after:wN \@@_chk:w
\exp_after:wN #2
- \int_use:N \__int_eval:w \c_two - #3 \__int_eval_end:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[int, EXP]{\@@_abs_o:w}
-% This function sets the sign of the \meta{floating point} to be
-% positive, and expands after itself in the input stream, just like
-% \cs{@@_-_o:w}. We must leave the sign of \texttt{nan} invariant.
-% \begin{macrocode}
-\cs_new:Npn \@@_abs_o:w \s_@@ \@@_chk:w #1 #2
- {
- \exp_after:wN \@@_exp_after_o:w
- \exp_after:wN \s_@@
- \exp_after:wN \@@_chk:w
- \exp_after:wN #1
- \__int_value:w \if_meaning:w 1 #2 1 \else: 0 \fi: \exp_stop_f:
+ \__int_value:w
+ \if_case:w #3 \exp_stop_f: #1 \or: 1 \or: 0 \fi: \exp_stop_f:
+ #4;
}
% \end{macrocode}
% \end{macro}
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx
index 10cf4d2d03b..7b7e11bd20f 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3fp-convert.dtx Copyright(C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-convert.dtx Copyright(C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -36,7 +36,7 @@
%
%<*driver>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3fp-convert.dtx 4339 2012-11-24 19:16:43Z joseph $
+\GetIdInfo$Id: l3fp-convert.dtx 4601 2013-11-18 23:13:28Z bruno $
{L3 Floating-point conversion}
\documentclass[full]{l3doc}
\begin{document}
@@ -402,10 +402,10 @@
% \begin{macro}[EXP]{\dim_to_fp:n}
% \begin{macro}[aux, EXP]
% {
-% \@@_from_dim_test:N,
-% \@@_from_dim:Nw,
+% \@@_from_dim_test:ww,
+% \@@_from_dim:wNw,
% \@@_from_dim:wNNnnnnnn,
-% \@@_from_dim:wnnnnwN,
+% \@@_from_dim:wnnnnwNw,
% }
% The dimension expression (which can in fact be a glue expression) is
% evaluated, converted to a number (\emph{i.e.}, expressed in scaled
@@ -413,40 +413,48 @@
% value expressed in points. The auxiliary \cs{@@_mul_npos_o:Nww}
% expects the desired \meta{final sign} and two floating point
% operands (of the form \cs{s_@@} \ldots{} |;|) as arguments.
+% This set of functions is also used to convert dimension registers to
+% floating points while parsing expressions: in this context there is
+% an additional exponent, which is the first argument of
+% \cs{@@_from_dim_test:ww}, and is combined with the exponent $-4$
+% of $2^{-16}$. There is also a need to expand afterwards: this is
+% performed by \cs{@@_mul_npos_o:Nww}, and cancelled by
+% \cs{prg_do_nothing:} in \cs{dim_to_fp:n}.
% \begin{macrocode}
\cs_new:Npn \dim_to_fp:n #1
{
- \exp_after:wN \@@_from_dim_test:N
+ \exp_after:wN \@@_from_dim_test:ww
+ \exp_after:wN 0
+ \exp_after:wN ,
\__int_value:w \etex_glueexpr:D #1 ;
}
-\cs_new:Npn \@@_from_dim_test:N #1
+\cs_new:Npn \@@_from_dim_test:ww #1, #2
{
- \if_meaning:w 0 #1
- \@@_case_return:nw \c_zero_fp
+ \if_meaning:w 0 #2
+ \@@_case_return:nw { \exp_after:wN \c_zero_fp }
\else:
- \if_meaning:w - #1
- \exp_after:wN \@@_from_dim:Nw
- \exp_after:wN 2
- \__int_value:w
- \else:
- \exp_after:wN \@@_from_dim:Nw
- \exp_after:wN 0
- \__int_value:w #1
- \fi:
+ \exp_after:wN \@@_from_dim:wNw
+ \int_use:N \__int_eval:w #1 - \c_four
+ \if_meaning:w - #2
+ \exp_after:wN , \exp_after:wN 2 \__int_value:w
+ \else:
+ \exp_after:wN , \exp_after:wN 0 \__int_value:w #2
+ \fi:
\fi:
}
-\cs_new:Npn \@@_from_dim:Nw #1 #2;
+\cs_new:Npn \@@_from_dim:wNw #1,#2#3;
{
\@@_pack_twice_four:wNNNNNNNN \@@_from_dim:wNNnnnnnn ;
- #2 000 0000 00 {10}987654321; #1
+ #3 000 0000 00 {10}987654321; #2 {#1}
}
\cs_new:Npn \@@_from_dim:wNNnnnnnn #1; #2#3#4#5#6#7#8#9
- { \@@_from_dim:wnnnnwN #1 {#2#300} {0000} ; }
-\cs_new:Npn \@@_from_dim:wnnnnwN #1; #2#3#4#5#6; #7
+ { \@@_from_dim:wnnnnwNn #1 {#2#300} {0000} ; }
+\cs_new:Npn \@@_from_dim:wnnnnwNn #1; #2#3#4#5#6; #7#8
{
\@@_mul_npos_o:Nww #7
\s_@@ \@@_chk:w 1 #7 {#5} #1 ;
- \s_@@ \@@_chk:w 1 0 {-4} {1525} {8789} {0625} {0000} ;
+ \s_@@ \@@_chk:w 1 0 {#8} {1525} {8789} {0625} {0000} ;
+ \prg_do_nothing:
}
% \end{macrocode}
% \end{macro}
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx
index f0782a2eed4..47dfff937ad 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-expo.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3fp-expo.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-expo.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -36,7 +36,7 @@
%
%<*driver>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3fp-expo.dtx 4482 2013-04-24 21:05:12Z joseph $
+\GetIdInfo$Id: l3fp-expo.dtx 4601 2013-11-18 23:13:28Z bruno $
{L3 Floating-point exponential-related functions}
\documentclass[full]{l3doc}
\begin{document}
@@ -153,19 +153,19 @@
% $+\infty$ or a \texttt{nan} is itself. Positive normal numbers call
% \cs{@@_ln_npos_o:w}.
% \begin{macrocode}
-\cs_new:Npn \@@_ln_o:w \s_@@ \@@_chk:w #1 #2
+\cs_new:Npn \@@_ln_o:w #1 \s_@@ \@@_chk:w #2#3#4; @
{
- \if_meaning:w 2 #2
+ \if_meaning:w 2 #3
\@@_case_use:nw { \@@_invalid_operation_o:nw { ln } }
\fi:
- \if_case:w #1 \exp_stop_f:
+ \if_case:w #2 \exp_stop_f:
\@@_case_use:nw
{ \@@_division_by_zero_o:Nnw \c_minus_inf_fp { ln } }
\or:
\else:
\@@_case_return_same_o:w
\fi:
- \@@_ln_npos_o:w \s_@@ \@@_chk:w #1#2
+ \@@_ln_npos_o:w \s_@@ \@@_chk:w #2#3#4;
}
% \end{macrocode}
% \end{macro}
@@ -608,14 +608,14 @@
%
% \begin{macro}[int, EXP]{\@@_exp_o:w}
% \begin{macrocode}
-\cs_new:Npn \@@_exp_o:w \s_@@ \@@_chk:w #1#2
+\cs_new:Npn \@@_exp_o:w #1 \s_@@ \@@_chk:w #2#3#4; @
{
- \if_case:w #1 \exp_stop_f:
+ \if_case:w #2 \exp_stop_f:
\@@_case_return_o:Nw \c_one_fp
\or:
\exp_after:wN \@@_exp_normal:w
\or:
- \if_meaning:w 0 #2
+ \if_meaning:w 0 #3
\exp_after:wN \@@_case_return_o:Nw
\exp_after:wN \c_inf_fp
\else:
@@ -625,7 +625,7 @@
\or:
\@@_case_return_same_o:w
\fi:
- \s_@@ \@@_chk:w #1#2
+ \s_@@ \@@_chk:w #2#3#4;
}
% \end{macrocode}
% \end{macro}
@@ -1146,11 +1146,11 @@
% \end{macro}
%^^A end[todo]
%
-% \begin{macro}[aux, EXP]{\@@_pow_neg:www}
+% \begin{macro}[aux, EXP]{\@@_pow_neg:www, \@@_pow_neg_aux:wNN}
% This function is followed by three floating point numbers: $|a|^b$,
% $a\in[-\infty,-0]$, and $b$. If $b$ is an even integer (case $-1$),
% $a^b=|a|^b$. If $b$ is an odd integer (case $0$), $a^b=-|a|^b$,
-% obtained by a call to \cs{@@_-_o:w}. Otherwise, the sign is
+% obtained by a call to \cs{@@_pow_neg_aux:wNN}. Otherwise, the sign is
% undefined. This is invalid, unless $|a|^b$ turns out to be $+0$ or
% \texttt{nan}, in which case we return that as $a^b$. In particular,
% since the underflow detection occurs before \cs{@@_pow_neg:www} is
@@ -1160,7 +1160,7 @@
\cs_new:Npn \@@_pow_neg:www \s_@@ \@@_chk:w #1#2; #3; #4;
{
\if_case:w \@@_pow_neg_case:w #4 ;
- \cs:w @@_-_o:w \exp_after:wN \cs_end:
+ \exp_after:wN \@@_pow_neg_aux:wNN
\or:
\if_int_compare:w \__int_eval:w #1 / \c_two = \c_one
\@@_invalid_operation_o:Nww ^ #3; #4;
@@ -1172,9 +1172,16 @@
\@@_exp_after_o:w
\s_@@ \@@_chk:w #1#2;
}
+\cs_new:Npn \@@_pow_neg_aux:wNN #1 \s_@@ \@@_chk:w #2#3
+ {
+ \exp_after:wN \@@_exp_after_o:w
+ \exp_after:wN \s_@@
+ \exp_after:wN \@@_chk:w
+ \exp_after:wN #2
+ \int_use:N \__int_eval:w \c_two - #3 \__int_eval_end:
+ }
% \end{macrocode}
% ^^A todo: is this \@@_exp_after_o:w necessary? Appropriate?
-% ^^A todo: improve upon the run-time \cs:w ... \cs_end: construction.
% \end{macro}
%
% \begin{macro}[aux, rEXP]
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx
index 79e96d7715c..9bb7145d635 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-extended.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3fp-extended.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-extended.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -36,8 +36,8 @@
%
%<*driver>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3fp-extended.dtx 4482 2013-04-24 21:05:12Z joseph $
- {L3 Floating-point extended precision fixed-points}
+\GetIdInfo$Id: l3fp-extended.dtx 4601 2013-11-18 23:13:28Z bruno $
+ {L3 Floating-points with extended precision}
\documentclass[full]{l3doc}
\begin{document}
\DocInput{\jobname.dtx}
@@ -48,7 +48,7 @@
% \title{The \textsf{l3fp-extended} package\thanks{This file
% has version number \ExplFileVersion, last
% revised \ExplFileDate.}\\
-% Fixed points with extended precision for internal use}
+% Manipulating numbers with extended precision, for internal use}
% \author{^^A
% The \LaTeX3 Project\thanks
% {^^A
@@ -77,10 +77,12 @@
%<@@=fp>
% \end{macrocode}
%
-% \subsection{Description of extended fixed points}
+% \subsection{Description of fixed point numbers}
%
-% In this module, we work on (almost) fixed-point numbers with
-% extended ($24$ digits) precision. This is used in the computation of
+% This module provides a few functions to manipulate positive floating
+% point numbers with extended precision ($24$ digits), but mostly
+% provides functions for fixed-point numbers with this precision ($24$
+% digits). Those are used in the computation of
% Taylor series for the logarithm, exponential, and trigonometric
% functions. Since we eventually only care about the $16$ first digits
% of the final result, some of the calculations are not performed with
@@ -93,7 +95,7 @@
% \end{quote}
% where each \meta{a_i} is exactly $4$ digits (ranging from |0000| to
% |9999|), except \meta{a_1}, which may be any \enquote{not-too-large}
-% non-negative integer, with or without trailing zeros. Here,
+% non-negative integer, with or without leading zeros. Here,
% \enquote{not-too-large} depends on the specific function (see the
% corresponding comments for details). Checking for overflow is the
% responsibility of the code calling those functions. The fixed point
@@ -118,15 +120,16 @@
% appropriate for computing continued fractions and Taylor series.
%
% At the end of the calculation, the result is turned back to a floating
-% point number using \cs{@@_fixed_to_float:Nw}. This function has to
+% point number using \cs{@@_fixed_to_float:wN}. This function has to
% change the exponent of the floating point number: it must be used
% after starting an integer expression for the overall exponent of the
% result.
%
-% \subsection{Helpers for extended fixed points}
+% \subsection{Helpers for numbers with extended precision}
%
+% ^^A todo: put trailing semicolon here?
% \begin{variable}[int]{\c_@@_one_fixed_tl}
-% The extended fixed-point number~$1$, used in \pkg{l3fp-expo}.
+% The fixed-point number~$1$, used in \pkg{l3fp-expo}.
% \begin{macrocode}
\tl_const:Nn \c_@@_one_fixed_tl
{ {10000} {0000} {0000} {0000} {0000} {0000} }
@@ -157,6 +160,28 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}[int, EXP]{\@@_fixed_div_myriad:wn}
+% Divide a fixed point number by $10000$. This is a little bit more
+% subtle than just removing the last group and adding a leading group
+% of zeros: the first group~|#1| may have any number of digits, and we
+% must split~|#1| into the new first group and a second group of
+% exactly $4$~digits. The choice of shifts allows~|#1| to be in the
+% range $[0, 5\cdot 10^{8}-1]$.
+% \begin{macrocode}
+\cs_new:Npn \@@_fixed_div_myriad:wn #1#2#3#4#5#6; #7
+ {
+ \exp_after:wN \@@_fixed_mul_after:wn
+ \int_use:N \__int_eval:w \c_@@_leading_shift_int
+ \exp_after:wN \@@_pack:NNNNNwn
+ \int_use:N \__int_eval:w \c_@@_trailing_shift_int
+ + #1 ; {#7} {#2}{#3}{#4}{#5};
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% ^^A todo:\cs_new:Npn \@@_fixed_mul_after:wn #1; #2; #3 { #3 {#1} #2; }
+% ^^A and do not bring the continuation up while packing.
+% ^^A possibly delete use_braced_s function afterwards.
% \begin{macro}[aux, EXP]{\@@_fixed_mul_after:wn}
% The fixed point operations which involve multiplication end by
% calling this auxiliary. It braces the last block of digits, and
@@ -168,6 +193,51 @@
% \end{macrocode}
% \end{macro}
%
+% \subsection{Multiplying a fixed point number by a short one}
+%
+% \begin{macro}[int, EXP]{\@@_fixed_mul_short:wwn}
+% \begin{syntax}
+% \cs{@@_fixed_mul_short:wwn}
+% \ \ \Arg{a_1} \Arg{a_2} \Arg{a_3} \Arg{a_4} \Arg{a_5} \Arg{a_6} |;|
+% \ \ \Arg{b_0} \Arg{b_1} \Arg{b_2} |;| \Arg{continuation}
+% \end{syntax}
+% Computes the product $c=ab$ of $a=\sum_i \meta{a_i} 10^{-4i}$ and
+% $b=\sum_i \meta{b_i} 10^{-4i}$, rounds it to the closest multiple of
+% $10^{-24}$, and leaves \meta{continuation} \Arg{c_1} \ldots{}
+% \Arg{c_6} |;| in the input stream, where each of the \meta{c_i} are
+% blocks of $4$~digits, except \meta{c_1}, which is any \TeX{}
+% integer. Note that indices for \meta{b} start at~$0$: a second
+% operand of |{0001}{0000}{0000}| will leave the first operand
+% unchanged (rather than dividing it by $10^{4}$, as
+% \cs{@@_fixed_mul:wwn} would).
+% \begin{macrocode}
+\cs_new:Npn \@@_fixed_mul_short:wwn #1#2#3#4#5#6; #7#8#9;
+ {
+ \exp_after:wN \@@_fixed_mul_after:wn
+ \int_use:N \__int_eval:w \c_@@_leading_shift_int
+ + #1*#7
+ \exp_after:wN \@@_pack:NNNNNwn
+ \int_use:N \__int_eval:w \c_@@_middle_shift_int
+ + #1*#8 + #2*#7
+ \exp_after:wN \@@_pack:NNNNNwn
+ \int_use:N \__int_eval:w \c_@@_middle_shift_int
+ + #1*#9 + #2*#8 + #3*#7
+ \exp_after:wN \@@_pack:NNNNNwn
+ \int_use:N \__int_eval:w \c_@@_middle_shift_int
+ + #2*#9 + #3*#8 + #4*#7
+ \exp_after:wN \@@_pack:NNNNNwn
+ \int_use:N \__int_eval:w \c_@@_middle_shift_int
+ + #3*#9 + #4*#8 + #5*#7
+ \exp_after:wN \@@_pack:NNNNNwn
+ \int_use:N \__int_eval:w \c_@@_trailing_shift_int
+ + #4*#9 + #5*#8 + #6*#7
+ + ( #5*#9 + #6*#8 + #6*#9 / \c_ten_thousand )
+ / \c_ten_thousand
+ \exp_after:wN ; \@@_use_braced_s:n
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \subsection{Dividing a fixed point number by a small integer}
%
% \begin{macro}[int, EXP]{\@@_fixed_div_int:wwN}
@@ -270,12 +340,13 @@
% \cs{@@_fixed_add:wwn} \meta{a} |;| \meta{b} |;| \Arg{continuation}
% \end{syntax}
% Computes $a+b$ (resp.\ $a-b$) and feeds the result to the
-% \meta{continuation}. This function requires $0\leq
-% a_{1},b_{1}<50000$, and requires the result to be positive (this
-% happens automatically for addition). The two functions only differ
+% \meta{continuation}. This function requires $0\leq a_{1},b_{1}\leq
+% 114748$, its result must be positive (this happens automatically for
+% addition) and its first group must have at most~$5$ digits: $(a\pm
+% b)_{1}<100000$. The two functions only differ by
% a sign, hence use a common auxiliary. It would be nice to grab the
% $12$ brace groups in one go; only $9$ parameters are allowed. Start
-% by grabbing the two signs, $a_{1}, \ldots, a_{4}$, the rest of $a$,
+% by grabbing the sign, $a_{1}, \ldots, a_{4}$, the rest of $a$,
% and $b_{1}$ and $b_{2}$. The second auxiliary receives the rest of
% $a$, the sign multiplying $b$, the rest of $b$, and the
% \meta{continuation} as arguments. After going down through the
@@ -309,6 +380,7 @@
%
% \subsection{Multiplying fixed points}
%
+% ^^A todo: may a_1 or b_1 be = 10000? Used in ediv_epsi later.
% \begin{macro}[int, EXP]{\@@_fixed_mul:wwn}
% \begin{macro}[aux, EXP]{\@@_fixed_mul:nnnnnnnwn}
% \begin{syntax}
@@ -564,8 +636,576 @@
% \end{macrocode}
% \end{macro}
%
+% \subsection{Extended-precision floating point numbers}
+%
+% In this section we manipulate floating point numbers with roughly $24$
+% significant figures (``extended-precision'' numbers, in short,
+% ``ep''), which take the form of an integer exponent, followed by a
+% comma, then six groups of digits, ending with a semicolon. The first
+% group of digit may be any non-negative integer, while other groups of
+% digits have $4$~digits. In other words, an extended-precision number
+% is an exponent ending in a comma, then a fixed point number.
+%
+% \begin{macro}[int, EXP]{\@@_ep_to_fixed:wwn}
+% \begin{macro}[aux, EXP]
+% {\@@_ep_to_fixed_auxi:www, \@@_ep_to_fixed_auxii:nnnnnnnwn}
+% Converts an extended-precision number with an exponent at most~$4$
+% to a fixed point number whose first block will have $12$~digits,
+% most often starting with many zeros.
+% \begin{macrocode}
+\cs_new:Npn \@@_ep_to_fixed:wwn #1,#2
+ {
+ \exp_after:wN \@@_ep_to_fixed_auxi:www
+ \int_use:N \__int_eval:w 1 0000 0000 + #2 \exp_after:wN ;
+ \tex_romannumeral:D -`0
+ \prg_replicate:nn { \c_four - \int_max:nn {#1} { -32 } } { 0 } ;
+ }
+\cs_new:Npn \@@_ep_to_fixed_auxi:www 1#1; #2; #3#4#5#6#7;
+ {
+ \@@_pack_eight:wNNNNNNNN
+ \@@_pack_twice_four:wNNNNNNNN
+ \@@_pack_twice_four:wNNNNNNNN
+ \@@_pack_twice_four:wNNNNNNNN
+ \@@_ep_to_fixed_auxii:nnnnnnnwn ;
+ #2 #1#3#4#5#6#7 0000 !
+ }
+\cs_new:Npn \@@_ep_to_fixed_auxii:nnnnnnnwn #1#2#3#4#5#6#7; #8! #9
+ { #9 {#1#2}{#3}{#4}{#5}{#6}{#7}; }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% ^^A todo: make it work when the arg is zero.
+% ^^A todo: remove the unused(?) 'n' arg.
+% \begin{macro}[aux, EXP]{\@@_ep_to_ep:wwN}
+% \begin{macro}[aux, rEXP]{\@@_ep_to_ep_loop:N, \@@_ep_to_ep_end:www}
+% \begin{macro}[aux, EXP]{\@@_ep_to_ep_zero:ww}
+% Normalize an extended-precision number. More precisely, leading
+% zeros are removed from the mantissa of the argument, decreasing its
+% exponent as appropriate. Then the digits are packed into $6$~groups
+% of~$4$ (discarding any remaining digit, not rounding). Finally, the
+% continuation~|#8| is placed before the resulting exponent--mantissa
+% pair. The input exponent may in fact be given as an integer
+% expression. The \texttt{loop} auxiliary grabs a digit: if it
+% is~$0$, decrement the exponent and continue looping, and otherwise
+% call the \texttt{end} auxiliary, which places all digits in the
+% right order (the digit that was not~$0$, and any remaining digits),
+% followed by some~$0$, then packs them up neatly in $3\times2=6$
+% blocks of four. At the end of the day, remove with \cs{@@_use_i:ww}
+% any digit that did not make it in the final mantissa (typically only
+% zeros, unless the original first block has more than~$4$ digits).
+% \begin{macrocode}
+\cs_new:Npn \@@_ep_to_ep:wwN #1,#2#3#4#5#6#7; #8
+ {
+ \exp_after:wN #8
+ \int_use:N \__int_eval:w #1 + \c_four
+ \exp_after:wN \use_i:nn
+ \exp_after:wN \@@_ep_to_ep_loop:N
+ \int_use:N \__int_eval:w 1 0000 0000 + #2 \__int_eval_end:
+ #3#4#5#6#7 ; ; !
+ }
+\cs_new:Npn \@@_ep_to_ep_loop:N #1
+ {
+ \if_meaning:w 0 #1
+ - \c_one
+ \else:
+ \@@_ep_to_ep_end:www #1
+ \fi:
+ \@@_ep_to_ep_loop:N
+ }
+\cs_new:Npn \@@_ep_to_ep_end:www
+ #1 \fi: \@@_ep_to_ep_loop:N #2; #3!
+ {
+ \fi:
+ \if_meaning:w ; #1
+ - \c_two * \c_@@_max_exponent_int
+ \@@_ep_to_ep_zero:ww
+ \fi:
+ \@@_pack_twice_four:wNNNNNNNN
+ \@@_pack_twice_four:wNNNNNNNN
+ \@@_pack_twice_four:wNNNNNNNN
+ \@@_use_i:ww , ;
+ #1 #2 0000 0000 0000 0000 0000 0000 ;
+ }
+\cs_new:Npn \@@_ep_to_ep_zero:ww \fi: #1; #2; #3;
+ { \fi: , {1000}{0000}{0000}{0000}{0000}{0000} ; }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int, EXP]{\@@_ep_compare:wwww}
+% \begin{macro}[aux, EXP]{\@@_ep_compare_aux:wwww}
+% In \pkg{l3fp-trig} we need to compare two extended-precision
+% numbers. This is based on the same function for positive floating
+% point numbers, with an extra test if comparing only $16$ decimals is
+% not enough to distinguish the numbers. Note that this function only
+% works if the numbers are normalized so that their first block is
+% in~$[1000,9999]$.
+% \begin{macrocode}
+\cs_new:Npn \@@_ep_compare:wwww #1,#2#3#4#5#6#7;
+ { \@@_ep_compare_aux:wwww {#1}{#2}{#3}{#4}{#5}; #6#7; }
+\cs_new:Npn \@@_ep_compare_aux:wwww #1;#2;#3,#4#5#6#7#8#9;
+ {
+ \if_case:w
+ \@@_compare_npos:nwnw #1; {#3}{#4}{#5}{#6}{#7}; \exp_stop_f:
+ \if_int_compare:w #2 = #8#9 \exp_stop_f:
+ 0
+ \else:
+ \if_int_compare:w #2 < #8#9 - \fi: 1
+ \fi:
+ \or: 1
+ \else: -1
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% ^^A todo: doc that neither operand may be zero (or fix ep_to_ep above)
+% \begin{macro}[int, EXP]{\@@_ep_mul:wwwwn, \@@_ep_mul_raw:wwwwN}
+% Multiply two extended-precision numbers: first normalize them to
+% avoid losing too much precision, then multiply the mantissas |#2|
+% and~|#4| as fixed point numbers, and sum the exponents |#1|
+% and~|#3|. The result's first block is in $[100,9999]$.
+% \begin{macrocode}
+\cs_new:Npn \@@_ep_mul:wwwwn #1,#2; #3,#4;
+ {
+ \@@_ep_to_ep:wwN #3,#4;
+ \@@_fixed_continue:wn
+ {
+ \@@_ep_to_ep:wwN #1,#2;
+ \@@_ep_mul_raw:wwwwN
+ }
+ \@@_fixed_continue:wn
+ }
+\cs_new:Npn \@@_ep_mul_raw:wwwwN #1,#2; #3,#4; #5
+ {
+ \@@_fixed_mul:wwn #2; #4;
+ { \exp_after:wN #5 \int_use:N \__int_eval:w #1 + #3 , }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Dividing extended-precision numbers}
+%
+% \newcommand{\eTeXfrac}[2]{\left[\frac{#1}{#2}\right]}
+%
+% Divisions of extended-precision numbers are difficult to perform with
+% exact rounding: the technique used in \pkg{l3fp-basics} for $16$-digit
+% floating point numbers does not generalize easily to $24$-digit
+% numbers. Thankfully, there is no need for exact rounding.
+%
+% Let us call \meta{n} the numerator and \meta{d} the denominator.
+% After a simple normalization step, we can assume that
+% $\meta{n}\in[0.1,1)$ and $\meta{d}\in[0.1,1)$, and compute
+% $\meta{n}/(10\meta{d})\in(0.01,1)$. In terms of the $6$~blocks of
+% digits $\meta{n_1}\cdots\meta{n_6}$ and the $6$~blocks
+% $\meta{d_1}\cdots\meta{d_6}$, the condition translates to
+% $\meta{n_1},\meta{d_1}\in[1000,9999]$.
+%
+% We will first find an integer estimate $a \simeq 10^{8} / \meta{d}$ by
+% computing
+% \begin{align*}
+% \alpha &= \eTeXfrac{10^{9}}{\meta{d_1}+1} \\
+% \beta &= \eTeXfrac{10^{9}}{\meta{d_1}} \\
+% a &= 10^{3} \alpha + (\beta-\alpha) \cdot
+% \left(10^{3}-\eTeXfrac{\meta{d_2}}{10}\right) - 1250,
+% \end{align*}
+% where $\eTeXfrac{\bullet}{\bullet}$ denotes \eTeX{}'s rounding
+% division, which rounds ties away from zero. The idea is to
+% interpolate between $10^{3}\alpha$ and $10^{3}\beta$ with a parameter
+% $\meta{d_2}/10^{4}$, so that when $\meta{d_2}=0$ one gets $a =
+% 10^{3}\beta-1250 \simeq 10^{12} / \meta{d_1} \simeq 10^{8} /
+% \meta{d}$, while when $\meta{d_2}=9999$ one gets $a =
+% 10^{3}\alpha-1250 \simeq 10^{12} / (\meta{d_1} + 1) \simeq 10^{8} /
+% \meta{d}$. The shift by $1250$ helps to ensure that $a$ is an
+% underestimate of the correct value. We will prove that
+% \[
+% 1 - 1.755\cdot 10^{-5} < \frac{\meta{d}a}{10^{8}} < 1 .
+% \]
+% We can then compute the inverse of $\meta{d}a/10^{8} = 1 - \epsilon$
+% using the relation $1/(1-\epsilon) \simeq (1+\epsilon)(1+\epsilon^{2})
+% + \epsilon^{4}$, which is correct up to a relative error of
+% $\epsilon^5 < 1.6\cdot 10^{-24}$. This allows us to find the desired
+% ratio as
+% \[
+% \frac{\meta{n}}{\meta{d}}
+% = \frac{\meta{n}a}{10^{8}}
+% \bigl( (1+\epsilon)(1+\epsilon^{2}) + \epsilon^{4}\bigr) .
+% \]
+%
+% Let us prove the upper bound first (multiplied by $10^{15}$). Note
+% that $10^{7} \meta{d} < 10^{3} \meta{d_1} + 10^{-1} (\meta{d_2} + 1)$,
+% and that \eTeX{}'s division $\eTeXfrac{\meta{d_2}}{10}$ will at most
+% underestimate $10^{-1}(\meta{d_2} + 1)$ by $0.5$, as can be checked
+% for each possible last digit of \meta{d_2}. Then,
+% \begin{align}
+% 10^{7} \meta{d}a
+% & <
+% \left(10^{3}\meta{d_1}
+% + \eTeXfrac{\meta{d_2}}{10} + \frac{1}{2}\right)
+% \left(\left(10^{3}-\eTeXfrac{\meta{d_2}}{10}\right) \beta
+% + \eTeXfrac{\meta{d_2}}{10} \alpha - 1250\right)
+% \\
+% & <
+% \left(10^{3}\meta{d_1}
+% + \eTeXfrac{\meta{d_2}}{10} + \frac{1}{2}\right)
+% \left(
+% \left(10^{3}-\eTeXfrac{\meta{d_2}}{10}\right)
+% \left(\frac{10^{9}}{\meta{d_1}} + \frac{1}{2} \right)
+% + \eTeXfrac{\meta{d_2}}{10}
+% \left(\frac{10^{9}}{\meta{d_1}+1} + \frac{1}{2} \right)
+% - 1250
+% \right)
+% \\
+% & <
+% \left(10^{3} \meta{d_1}
+% + \eTeXfrac{\meta{d_2}}{10} + \frac{1}{2}\right)
+% \left(\frac{10^{12}}{\meta{d_1}}
+% - \eTeXfrac{\meta{d_2}}{10}
+% \frac{10^{9}}{\meta{d_1}(\meta{d_1}+1)}
+% - 750\right)
+% \end{align}
+% We recognize a quadratic polynomial in $[\meta{d_2}/10]$ with a
+% negative leading coefficient: this polynomial is bounded above,
+% according to $([\meta{d_2}/10]+a)(b-c[\meta{d_2}/10]) \leq
+% (b+ca)^2/(4c)$. Hence,
+% \[
+% 10^{7} \meta{d}a
+% < \frac{10^{15}}{\meta{d_1}(\meta{d_1}+1)} \left(
+% \meta{d_1} + \frac{1}{2} + \frac{1}{4} 10^{-3}
+% - \frac{3}{8} \cdot 10^{-9} \meta{d_1}(\meta{d_1}+1) \right)^2
+% \]
+% Since \meta{d_1} takes integer values within $[1000,9999]$, it is a
+% simple programming exercise to check that the squared expression is
+% always less than $\meta{d_1}(\meta{d_1}+1)$, hence $10^{7} \meta{d} a
+% < 10^{15}$. The upper bound is proven. We also find that
+% $\frac{3}{8}$ can be replaced by slightly smaller numbers, but nothing
+% less than $0.374563\ldots$, and going back through the derivation of
+% the upper bound, we find that $1250$ is as small a shift as we can
+% obtain without breaking the bound.
+%
+% Now, the lower bound. The same computation as for the upper bound
+% implies
+% \[
+% 10^{7} \meta{d}a
+% > \left(10^{3} \meta{d_1} + \eTeXfrac{\meta{d_2}}{10}
+% - \frac{1}{2}\right)
+% \left(\frac{10^{12}}{\meta{d_1}}
+% - \eTeXfrac{\meta{d_2}}{10} \frac{10^{9}}{\meta{d_1}(\meta{d_1}+1)}
+% - 1750\right)
+% \]
+% This time, we want to find the minimum of this quadratic polynomial.
+% Since the leading coefficient is still negative, the minimum is
+% reached for one of the extreme values $[y/10]=0$ or $[y/10]=100$, and
+% we easily check the bound for those values.
+%
+% We have proven that the algorithm will give us a precise enough
+% answer. Incidentally, the upper bound that we derived tells us that
+% $a < 10^{8}/\meta{d} \leq 10^{9}$, hence we can compute $a$ safely as
+% a \TeX{} integer, and even add $10^{9}$ to it to ease grabbing of all
+% the digits. The lower bound implies $10^{8} - 1755 < a$, which we do
+% not care about.
+%
+% ^^A todo: provide ep_inv, not ep_div?
+% ^^A todo: make extra sure that the result's first block cannot be 99
+% ^^A todo: doc that neither operand may be zero (or fix ep_to_ep)
+% \begin{macro}[int, EXP]{\@@_ep_div:wwwwn}
+% Compute the ratio of two extended-precision numbers. The result is
+% an extended-precision number whose first block lies in the range
+% $[100,9999]$, and is placed after the \meta{continuation} once we
+% are done. First normalize the inputs so that both first block lie
+% in $[1000,9999]$, then call \cs{@@_ep_div_esti:wwwwn}
+% \meta{denominator} \meta{numerator}, responsible for estimating the
+% inverse of the denominator.
+% \begin{macrocode}
+\cs_new:Npn \@@_ep_div:wwwwn #1,#2; #3,#4;
+ {
+ \@@_ep_to_ep:wwN #1,#2;
+ \@@_fixed_continue:wn
+ {
+ \@@_ep_to_ep:wwN #3,#4;
+ \@@_ep_div_esti:wwwwn
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]
+% {
+% \@@_ep_div_esti:wwwwn,
+% \@@_ep_div_estii:wwnnwwn,
+% \@@_ep_div_estiii:NNNNNwwwn
+% }
+% The \texttt{esti} function evaluates $\alpha=10^{9} / (\meta{d_1} +
+% 1)$, which is used twice in the expression for $a$, and combines the
+% exponents |#1| and~|#4| (with a shift by~$1$ because we will compute
+% $\meta{n}/(10\meta{d})$. Then the \texttt{estii} function evaluates
+% $10^{9} + a$, and puts the exponent~|#2| after the
+% continuation~|#7|: from there on we can forget exponents and focus
+% on the mantissa. The \texttt{estiii} function multiplies the
+% denominator~|#7| by $10^{-8}a$ (obtained as $a$ split into the
+% single digit~|#1| and two blocks of $4$~digits, |#2#3#4#5|
+% and~|#6|). The result $10^{-8}a\meta{d}=(1-\epsilon)$, and a
+% partially packed $10^{-9}a$ (as a block of four digits, and five
+% individual digits, not packed by lack of available macro parameters
+% here) are passed to \cs{@@_ep_div_epsi:wnNNNNn}, which computes
+% $10^{-9}a/(1-\epsilon)$, that is, $1/(10\meta{d})$ and we finally
+% multiply this by the numerator~|#8|.
+% \begin{macrocode}
+\cs_new:Npn \@@_ep_div_esti:wwwwn #1,#2#3; #4,
+ {
+ \exp_after:wN \@@_ep_div_estii:wwnnwwn
+ \int_use:N \__int_eval:w 10 0000 0000 / ( #2 + \c_one )
+ \exp_after:wN ;
+ \int_use:N \__int_eval:w #4 - #1 + \c_one ,
+ {#2} #3;
+ }
+\cs_new:Npn \@@_ep_div_estii:wwnnwwn #1; #2,#3#4#5; #6; #7
+ {
+ \exp_after:wN \@@_ep_div_estiii:NNNNNwwwn
+ \int_use:N \__int_eval:w 10 0000 0000 - 1750
+ + #1 000 + (10 0000 0000 / #3 - #1) * (1000 - #4 / 10) ;
+ {#3}{#4}#5; #6; { #7 #2, }
+ }
+\cs_new:Npn \@@_ep_div_estiii:NNNNNwwwn 1#1#2#3#4#5#6; #7;
+ {
+ \@@_fixed_mul_short:wwn #7; {#1}{#2#3#4#5}{#6};
+ \@@_ep_div_epsi:wnNNNNNn {#1#2#3#4}#5#6
+ \@@_fixed_mul:wwn
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]
+% {
+% \@@_ep_div_epsi:wnNNNNNn,
+% \@@_ep_div_eps_pack:NNNNNw,
+% \@@_ep_div_epsii:wwnNNNNNn,
+% }
+% The bounds shown above imply that the \texttt{epsi} function's first
+% operand is $(1-\epsilon)$ with $\epsilon\in[0,1.755\cdot 10^{-5}]$.
+% The \texttt{epsi} function computes $\epsilon$ as $1-(1-\epsilon)$.
+% Since $\epsilon<10^{-4}$, its first block vanishes and there is no
+% need to explicitly use~|#1| (which is $9999$). Then \texttt{epsii}
+% evaluates $10^{-9}a/(1-\epsilon)$ as
+% $(1+\epsilon^2)(1+\epsilon)(10^{-9}a \epsilon) + 10^{-9}a$.
+% Importantly, we compute $10^{-9}a \epsilon$ before multiplying it
+% with the rest, rather than multiplying by $\epsilon$ and then
+% $10^{-9}a$, as this second option loses more precision. Also, the
+% combination of \texttt{short_mul} and \texttt{div_myriad} is both
+% faster and more precise than a simple \texttt{mul}.
+% \begin{macrocode}
+\cs_new:Npn \@@_ep_div_epsi:wnNNNNNn #1#2#3#4#5#6;
+ {
+ \exp_after:wN \@@_ep_div_epsii:wwnNNNNNn
+ \int_use:N \__int_eval:w 1 9998 - #2
+ \exp_after:wN \@@_ep_div_eps_pack:NNNNNw
+ \int_use:N \__int_eval:w 1 9999 9998 - #3#4
+ \exp_after:wN \@@_ep_div_eps_pack:NNNNNw
+ \int_use:N \__int_eval:w 2 0000 0000 - #5#6 ; ;
+ }
+\cs_new:Npn \@@_ep_div_eps_pack:NNNNNw #1#2#3#4#5#6;
+ { + #1 ; {#2#3#4#5} {#6} }
+\cs_new:Npn \@@_ep_div_epsii:wwnNNNNNn 1#1; #2; #3#4#5#6#7#8
+ {
+ \@@_fixed_mul:wwn {0000}{#1}#2; {0000}{#1}#2;
+ \@@_fixed_add_one:wN
+ \@@_fixed_mul:wwn {10000} {#1} #2 ;
+ {
+ \@@_fixed_mul_short:wwn {0000}{#1}#2; {#3}{#4#5#6#7}{#8000};
+ \@@_fixed_div_myriad:wn
+ \@@_fixed_mul:wwn
+ }
+ \@@_fixed_add:wwn {#3}{#4#5#6#7}{#8000}{0000}{0000}{0000};
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Inverse square root of extended precision numbers}
+%
+% The idea here is similar to division. Normalize the input,
+% multiplying by powers of $100$ until we have $x\in[0.01,1)$. Then
+% find an integer approximation $r \in [101, 1003]$ of
+% $10^{2}/\sqrt{x}$, as the fixed point of iterations of the Newton
+% method: essentially $r \mapsto (r + 10^{8} / (x_{1} r)) / 2$, starting
+% from a guess that optimizes the number of steps before convergence.
+% In fact, just as there is a slight shift when computing divisions to
+% ensure that some inequalities hold, we will replace $10^{8}$ by a
+% slightly larger number which will ensure that $r^2 x \geq 10^{4}$.
+% This also causes $r \in [101, 1003]$. Another correction to the above
+% is that the input is actually normalized to $[0.1,1)$, and we use
+% either $10^{8}$ or $10^{9}$ in the Newton method, depending on the
+% parity of the exponent. Skipping those technical hurdles, once we
+% have the approximation~$r$, we set $y = 10^{-4} r^{2} x$ (or rather,
+% the correct power of~$10$ to get $y\simeq 1$) and compute $y^{-1/2}$
+% through another application of Newton's method. This time, the
+% starting value is $z=1$, each step maps $z \mapsto z(1.5-0.5yz^2)$,
+% and we perform a fixed number of steps. Our final result combines~$r$
+% with $y^{-1/2}$ as $x^{-1/2} = 10^{-2} r y^{-1/2}$.
+%
+% ^^A todo: doc that the operand may not be zero (or fix ep_to_ep above)
+% \begin{macro}[int, EXP]{\@@_ep_isqrt:wwn}
+% \begin{macro}[aux, EXP]
+% {\@@_ep_isqrt_aux:wwn, \@@_ep_isqrt_auxii:wwnnnwn}
+% First normalize the input, then check the parity of the
+% exponent~|#1|. If it is even, the result's exponent will be
+% $-|#1|/2$, otherwise it will be $(|#1|-1)/2$ (except in the case
+% where the input was an exact power of $100$). The \texttt{auxii}
+% function receives as~|#1| the result's exponent just computed, as
+% |#2| the starting value for the iteration giving~$r$ (the
+% values~$168$ and~$535$ lead to the least number of iterations before
+% convergence, on average), as |#3| and~|#4| one empty argument and
+% one~|0|, depending on the parity of the original exponent, as |#5|
+% and~|#6| the normalized mantissa ($|#5|\in[1000,9999]$), and as |#7|
+% the continuation. It sets up the iteration giving~$r$: the
+% \texttt{esti} function thus receives the initial two guesses |#2|
+% and~$0$, an approximation~|#5| of~$10^{4}x$ (its first block of
+% digits), and the empty/zero arguments |#3| and~|#4|, followed by the
+% mantissa and an altered continuation where we have stored the
+% result's exponent.
+% \begin{macrocode}
+\cs_new:Npn \@@_ep_isqrt:wwn #1,#2;
+ {
+ \@@_ep_to_ep:wwN #1,#2;
+ \@@_ep_isqrt_auxi:wwn
+ }
+\cs_new:Npn \@@_ep_isqrt_auxi:wwn #1,
+ {
+ \exp_after:wN \@@_ep_isqrt_auxii:wwnnnwn
+ \int_use:N \__int_eval:w
+ \int_if_odd:nTF {#1}
+ { (\c_one - #1) / \c_two , 535 , { 0 } { } }
+ { \c_one - #1 / \c_two , 168 , { } { 0 } }
+ }
+\cs_new:Npn \@@_ep_isqrt_auxii:wwnnnwn #1, #2, #3#4 #5#6; #7
+ {
+ \@@_ep_isqrt_esti:wwwnnwn #2, 0, #5, {#3} {#4}
+ {#5} #6 ; { #7 #1 , }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]
+% {
+% \@@_ep_isqrt_esti:wwwnnwn,
+% \@@_ep_isqrt_estii:wwwnnwn,
+% \@@_ep_isqrt_estiii:NNNNNwwwn
+% }
+% If the last two approximations gave the same result, we are done:
+% call the \texttt{estii} function to clean up. Otherwise, evaluate
+% $(\meta{prev} + 1.005 \cdot 10^{\text{$8$ or $9$}} / (\meta{prev}
+% \cdot x)) / 2$, as the next approximation: omitting the $1.005$
+% factor, this would be Newton's method. We can check by brute force
+% that if |#4| is empty (the original exponent was even), the process
+% computes an integer slightly larger than $100 / \sqrt{x}$, while if
+% |#4| is~$0$ (the original exponent was odd), the result is an
+% integer slightly larger than $100 / \sqrt{x/10}$. Once we are done,
+% we evaluate $100 r^2 / 2$ or $10 r^2 / 2$ (when the exponent is even
+% or odd, respectively) and feed that to \texttt{estiii}. This third
+% auxiliary finds $y_{\text{even}} / 2 = 10^{-4} r^2 x / 2$ or
+% $y_{\text{odd}} / 2 = 10^{-5} r^2 x / 2$ (again, depending on
+% earlier parity). A simple program shows that $y\in [1, 1.0201]$.
+% The number $y/2$ is fed to \cs{@@_ep_isqrt_epsi:wN}, which computes
+% $1/\sqrt{y}$, and we finally multiply the result by~$r$.
+% \begin{macrocode}
+\cs_new:Npn \@@_ep_isqrt_esti:wwwnnwn #1, #2, #3, #4
+ {
+ \if_int_compare:w #1 = #2 \exp_stop_f:
+ \exp_after:wN \@@_ep_isqrt_estii:wwwnnwn
+ \fi:
+ \exp_after:wN \@@_ep_isqrt_esti:wwwnnwn
+ \int_use:N \__int_eval:w
+ (#1 + 1 0050 0000 #4 / (#1 * #3)) / \c_two ,
+ #1, #3, {#4}
+ }
+\cs_new:Npn \@@_ep_isqrt_estii:wwwnnwn #1, #2, #3, #4#5
+ {
+ \exp_after:wN \@@_ep_isqrt_estiii:NNNNNwwwn
+ \int_use:N \__int_eval:w 1000 0000 + #2 * #2 #5 * \c_five
+ \exp_after:wN , \int_use:N \__int_eval:w 10000 + #2 ;
+ }
+\cs_new:Npn \@@_ep_isqrt_estiii:NNNNNwwwn 1#1#2#3#4#5#6, 1#7#8; #9;
+ {
+ \@@_fixed_mul_short:wwn #9; {#1} {#2#3#4#5} {#600} ;
+ \@@_ep_isqrt_epsi:wN
+ \@@_fixed_mul_short:wwn {#7} {#80} {0000} ;
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_ep_isqrt_epsi:wN, \@@_ep_isqrt_epsii:wwN}
+% Here, we receive a fixed point number $y/2$ with $y\in[1,1.0201]$.
+% Starting from $z = 1$ we iterate $z \mapsto z(3/2 - z^2 y/2)$. In
+% fact, we start from the first iteration $z=3/2-y/2$ to avoid useless
+% multiplications. The \texttt{epsii} auxiliary receives $z$ as~|#1|
+% and $y$ as~|#2|.
+% \begin{macrocode}
+\cs_new:Npn \@@_ep_isqrt_epsi:wN #1;
+ {
+ \@@_fixed_sub:wwn {15000}{0000}{0000}{0000}{0000}{0000}; #1;
+ \@@_ep_isqrt_epsii:wwN #1;
+ \@@_ep_isqrt_epsii:wwN #1;
+ \@@_ep_isqrt_epsii:wwN #1;
+ }
+\cs_new:Npn \@@_ep_isqrt_epsii:wwN #1; #2;
+ {
+ \@@_fixed_mul:wwn #1; #1;
+ \@@_fixed_mul_sub_back:wwwn #2;
+ {15000}{0000}{0000}{0000}{0000}{0000};
+ \@@_fixed_mul:wwn #1;
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \subsection{Converting from fixed point to floating point}
+% ^^A todo: doc and turn ..._to_float:... -> ..._to_float_o:...
+%
+% After computing Taylor series, we wish to convert the result from
+% extended precision (with or without an exponent) to the public
+% floating point format. The functions here should be called within an
+% integer expression for the overall exponent of the floating point.
%
+% \begin{macro}[int, rEXP]{\@@_ep_to_float:wwN, \@@_ep_inv_to_float:wwN}
+% An extended-precision number is simply a comma-delimited exponent
+% followed by a fixed point number. Leave the exponent in the current
+% integer expression then convert the fixed point number.
+% \begin{macrocode}
+\cs_new:Npn \@@_ep_to_float:wwN #1,
+ { + \__int_eval:w #1 \@@_fixed_to_float:wN }
+\cs_new:Npn \@@_ep_inv_to_float:wwN #1,#2;
+ {
+ \@@_ep_div:wwwwn 1,{1000}{0000}{0000}{0000}{0000}{0000}; #1,#2;
+ \@@_ep_to_float:wwN
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[rEXP, int]{\@@_fixed_inv_to_float:wN}
+% Another function which reduces to converting an extended precision
+% number to a float.
+% \begin{macrocode}
+\cs_new:Npn \@@_fixed_inv_to_float:wN
+ { \@@_ep_inv_to_float:wwN 0, }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[rEXP, int]{\@@_fixed_to_float_rad:wN}
+% Converts the fixed point number~|#1| from degrees to radians then to
+% a floating point number. This could perhaps remain in
+% \pkg{l3fp-trig}.
+% \begin{macrocode}
+\cs_new:Npn \@@_fixed_to_float_rad:wN #1;
+ {
+ \@@_fixed_mul:wwn #1; {5729}{5779}{5130}{8232}{0876}{7981};
+ { \@@_ep_to_float:wwN 2, }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% ^^A todo: make exponents end in ',' consistently throughout l3fp
% \begin{macro}[int, rEXP]
% {\@@_fixed_to_float:wN, \@@_fixed_to_float:Nw}
% \begin{syntax}
@@ -586,7 +1226,7 @@
\cs_new:Npn \@@_fixed_to_float:Nw #1#2; { \@@_fixed_to_float:wN #2; #1 }
\cs_new:Npn \@@_fixed_to_float:wN #1#2#3#4#5#6; #7
{
- + \c_four % for the 8-digit-at-the-start thing.
+ + \__int_eval:w \c_four % for the 8-digit-at-the-start thing.
\exp_after:wN \exp_after:wN
\exp_after:wN \@@_fixed_to_loop:N
\exp_after:wN \use_none:n
@@ -642,206 +1282,6 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[rEXP, int]{\@@_fixed_inv_to_float:wN, \@@_fixed_div_to_float:ww}
-% Starting from \texttt{fixed_dtf} $A$ |;| $B$ |;| we want to compute
-% $A/B$, and express it as a floating point number. Normalize both
-% numbers by removing leading brace groups of zeros and leaving the
-% appropriate exponent shift in the input stream.
-% \begin{macrocode}
-\cs_new:Npn \@@_fixed_inv_to_float:wN #1#2; #3
- {
- + \__int_eval:w % ^^A todo: remove the +?
- \if_int_compare:w #1 < \c_one_thousand
- \@@_fixed_dtf_zeros:wNnnnnnn
- \fi:
- \@@_fixed_dtf_no_zero:Nwn + {#1} #2 \s_@@
- \@@_fixed_dtf_approx:n
- {10000} {0000} {0000} {0000} {0000} {0000} ;
- }
-\cs_new:Npn \@@_fixed_div_to_float:ww #1#2; #3#4;
- {
- \if_int_compare:w #1 < \c_one_thousand
- \@@_fixed_dtf_zeros:wNnnnnnn
- \fi:
- \@@_fixed_dtf_no_zero:Nwn - {#1} #2 \s_@@
- {
- \if_int_compare:w #3 < \c_one_thousand
- \@@_fixed_dtf_zeros:wNnnnnnn
- \fi:
- \@@_fixed_dtf_no_zero:Nwn + {#3} #4 \s_@@
- \@@_fixed_dtf_approx:n
- }
- }
-\cs_new:Npn \@@_fixed_dtf_no_zero:Nwn #1#2 \s_@@ #3 { #3 #2; }
-\cs_new:Npn \@@_fixed_dtf_zeros:wNnnnnnn
- \fi: \@@_fixed_dtf_no_zero:Nwn #1#2#3#4#5#6#7
- {
- \fi:
- #1 \c_minus_one
- \exp_after:wN \use_i_ii:nnn
- \exp_after:wN \@@_fixed_dtf_zeros:NN
- \exp_after:wN #1
- \int_use:N \__int_eval:w 10 0000 + #2 \__int_eval_end: #3#4#5#6#7
- ; 1 ;
- }
-\cs_new:Npn \@@_fixed_dtf_zeros:NN #1#2
- {
- \if_meaning:w 0 #2
- #1 \c_one
- \else:
- \@@_fixed_dtf_zeros_end:wNww #2
- \fi:
- \@@_fixed_dtf_zeros:NN #1
- }
-\cs_new:Npn \@@_fixed_dtf_zeros_end:wNww
- #1 \fi: \@@_fixed_dtf_zeros:NN #2 #3; #4 \s_@@
- {
- \fi:
- \if_meaning:w ; #1
- #2 \c_two * \c_@@_max_exponent_int
- \use_i_ii:nnn
- \fi:
- \@@_fixed_dtf_zeros_auxi:ww
- #1#3 0000 0000 0000 0000 0000 0000 ;
- }
-\cs_new:Npn \@@_fixed_dtf_zeros_auxi:ww
- {
- \@@_pack_twice_four:wNNNNNNNN
- \@@_pack_twice_four:wNNNNNNNN
- \@@_pack_twice_four:wNNNNNNNN
- \@@_fixed_dtf_zeros_auxii:ww
- ;
- }
-\cs_new:Npn \@@_fixed_dtf_zeros_auxii:ww #1; #2; #3 { #3 #1; }
-% \end{macrocode}
-% \newcommand{\eTeXfrac}[2]{\left[\frac{#1}{#2}\right]}
-% We get
-% \begin{quote}
-% \cs{@@_fixed_dtf_approx:n} \meta{B'} |;| \meta{A'} |;|
-% \end{quote}
-% where \meta{B'} and \meta{A'} are each $6$ brace groups,
-% representing fixed point numbers in the range $[0.1,1)$. Denote by
-% $x\in[1000,9999]$ and $y\in[0,9999]$ the first two groups of
-% \meta{B'}. We first find an estimate $a$ for the inverse of $B'$ by
-% computing
-% \begin{align*}
-% \alpha &= \eTeXfrac{10^{9}}{x+1} \\
-% \beta &= \eTeXfrac{10^{9}}{x} \\
-% a &= 10^{3} \alpha + (\beta-\alpha) \cdot
-% \left(10^{3}-\eTeXfrac{y}{10}\right) - 1750,
-% \end{align*}
-% where $\eTeXfrac{\bullet}{\bullet}$ denotes \eTeX{}'s rounding
-% division. The idea is to interpolate between $\alpha$ and $\beta$
-% with a parameter $y/10^{4}$. The shift by $1750$ helps to ensure
-% that $a$ is an underestimate of the correct value. We will prove
-% that
-% \[
-% 1 - 2.255\cdot 10^{-5} < \frac{B'a}{10^{8}} < 1 .
-% \]
-% We can then compute the inverse $B'a/10^{8}$ using $1/(1-\epsilon)
-% \simeq (1+\epsilon)(1+\epsilon^{2})$, which is correct up to a
-% relative error of $\epsilon^4 < 2.6\cdot 10^{-19}$. Since we target
-% a $16$-digit value, this is small enough.
-%
-% Let us prove the upper bound first.
-% \begin{align}\label{l3fp-fixed-eTeXfrac}
-% 10^{7} B'a
-% & < \left(10^{3} x + \eTeXfrac{y}{10} + \frac{3}{2}\right)
-% \left(\left(10^{3}-\eTeXfrac{y}{10}\right) \beta
-% + \eTeXfrac{y}{10} \alpha - 1750\right)
-% \\& < \left(10^{3} x + \eTeXfrac{y}{10} + \frac{3}{2}\right)
-% \left(\left(10^{3}-\eTeXfrac{y}{10}\right)
-% \left(\frac{10^{9}}{x} + \frac{1}{2} \right)
-% + \eTeXfrac{y}{10} \left(\frac{10^{9}}{x+1} + \frac{1}{2} \right)
-% - 1750\right)
-% \\& < \left(10^{3} x + \eTeXfrac{y}{10} + \frac{3}{2}\right)
-% \left(\frac{10^{12}}{x}
-% - \eTeXfrac{y}{10} \frac{10^{9}}{x(x+1)}
-% - 1250\right)
-% \end{align}
-% We recognize a quadratic polynomial in $[y/10]$ with a negative
-% leading coefficient, $([y/10]+a)(b-c[y/10]) \leq (b+ca)^2/(4c)$.
-% Hence,
-% \[
-% 10^{7} B'a
-% < \frac{10^{15}}{x(x+1)} \left(
-% x + \frac{1}{2} + \frac{3}{4} 10^{-3}
-% - 6.25\cdot 10^{-10} x(x+1) \right)^2
-% \]
-% We want to prove that the squared expression is less than $x(x+1)$,
-% which we do by simplifying the difference, and checking its sign,
-% \[
-% x(x+1) - \left(x + \frac{1}{2} + \frac{3}{4} 10^{-3}
-% - 6.25\cdot 10^{-10} x(x+1) \right)^2
-% > - \frac{1}{4} (1+1.5\cdot 10^{-3})^2 - 10^{-3} x
-% + 1.25\cdot 10^{-9} x(x+1)(x+0.5)
-% > 0.
-% \]
-%
-% Now, the lower bound. The same computation as
-% \eqref{l3fp-fixed-eTeXfrac} imply
-% \[
-% 10^{7} B'a
-% > \left(10^{3} x + \eTeXfrac{y}{10} - \frac{1}{2}\right)
-% \left(\frac{10^{12}}{x} - \eTeXfrac{y}{10} \frac{10^{9}}{x(x+1)}
-% - 2250\right)
-% \]
-% This time, we want to find the minimum of this quadratic polynomial.
-% Since the leading coefficient is still negative, the minimum is
-% reached for one of the extreme values $y=0$ or $y=9999$, and we
-% easily check the bound for those values.
-%
-% We have proven that the algorithm will give us a precise enough
-% answer. Incidentally, the upper bound that we derived tells us that
-% $a < 10^{8}/B \leq 10^{9}$, hence we can compute $a$ safely as a
-% \TeX{} integer, and even add $10^{9}$ to it to ease grabbing of all
-% the digits.
-% \begin{macrocode}
-\cs_new:Npn \@@_fixed_dtf_approx:n #1
- {
- \exp_after:wN \@@_fixed_dtf_approx:wnn
- \int_use:N \__int_eval:w 10 0000 0000 / ( #1 + \c_one ) ;
- {#1}
- }
-\cs_new:Npn \@@_fixed_dtf_approx:wnn #1; #2#3
- {
-%<assert> \assert:n { \tl_count:n {#1} = 6 }
- \exp_after:wN \@@_fixed_dtf_approx:NNNNNw
- \int_use:N \__int_eval:w 10 0000 0000 - 1750
- + #1000 + (10 0000 0000/#2-#1) * (1000-#3/10) ;
- {#2}{#3}
- }
-\cs_new:Npn \@@_fixed_dtf_approx:NNNNNw 1#1#2#3#4#5#6; #7; #8;
- {
- + \c_four % because of the line below "dtf_epsilon" here.
- \@@_fixed_mul:wwn {000#1}{#2#3#4#5}{#6}{0000}{0000}{0000} ; #7;
- \@@_fixed_dtf_epsilon:wN
- \@@_fixed_mul:wwn {000#1}{#2#3#4#5}{#6}{0000}{0000}{0000} ;
- \@@_fixed_mul:wwn #8;
- \@@_fixed_to_float:wN ?
- }
-\cs_new:Npn \@@_fixed_dtf_epsilon:wN #1#2#3#4#5#6;
- {
-%<assert> \assert:n { #1 = 0000 }
-%<assert> \assert:n { #2 = 9999 }
- \exp_after:wN \@@_fixed_dtf_epsilon:NNNNNww
- \int_use:N \__int_eval:w 1 9999 9998 - #3#4 +
- \exp_after:wN \@@_fixed_dtf_epsilon_pack:NNNNNw
- \int_use:N \__int_eval:w 2 0000 0000 - #5#6 ; {0000} ;
- }
-\cs_new:Npn \@@_fixed_dtf_epsilon_pack:NNNNNw #1#2#3#4#5#6;
- { #1 ; {#2#3#4#5} {#6} }
-\cs_new:Npn \@@_fixed_dtf_epsilon:NNNNNww #1#2#3#4#5#6; #7;
- {
- \@@_fixed_mul:wwn %^^A todo: optimize to use \@@_mul_significand.
- {0000} {#2#3#4#5} {#6} #7 ;
- {0000} {#2#3#4#5} {#6} #7 ;
- \@@_fixed_add_one:wN
- \@@_fixed_mul:wwn {10000} {#2#3#4#5} {#6} #7 ;
- }
-% \end{macrocode}
-% \end{macro}
-%
% \begin{macrocode}
%</initex|package>
% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
index 6c7991c4027..49f9630c5f3 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3fp-logic.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-logic.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -82,9 +82,8 @@
% \begin{itemize}
% \item \cs{@@_compare_npos:nwnw} \Arg{expo_1} \meta{body_1} |;|
% \Arg{expo_2} \meta{body_2} |;|
-% \item \cs{@@_max_o:w} \meta{floating point array}
-% \item \cs{@@_min_o:w} \meta{floating point array}
-% \item \cs{@@_!_o:w} \meta{floating point}
+% \item \cs{@@_minmax_o:Nw} \meta{sign} \meta{floating point array}
+% \item \cs{@@_not_o:w} |?| \meta{floating point array} (with one floating point number only)
% \item \cs{@@_\string&_o:ww} \meta{floating point} \meta{floating point}
% \item \cs{@@_\string|_o:ww} \meta{floating point} \meta{floating point}
% \item \cs{@@_ternary:NwwN}, \cs{@@_ternary_auxi:NwwN},
@@ -320,28 +319,26 @@
%
% \subsection{Extrema}
%
-% \begin{macro}[int, EXP]{\@@_max_o:w, \@@_min_o:w}
-% The maximum (minimum) of an array of floating point numbers is
-% computed by reading them sequentially, keeping track of the largest
-% (smallest) number found so far. We start with $-\infty$ ($\infty$)
-% since every number is larger (smaller) than that. The weird fp-like
-% trailing marker breaks the loop correctly: see the precise
+% \begin{macro}[int, EXP]{\@@_minmax_o:Nw}
+% The argument~|#1| is $2$~to find the maximum of an array~|#2| of
+% floating point numbers, and $0$~to find the minimum. We read
+% numbers sequentially, keeping track of the largest (smallest) number
+% found so far. If numbers are equal (for instance~$\pm0$), the first
+% is kept. We append $-\infty$ ($\infty$), for the case of an empty
+% array, currently impossible. Since no number is smaller (larger)
+% than that, it will never alter the maximum (minimum). The weird
+% fp-like trailing marker breaks the loop correctly: see the precise
% definition of \cs{@@_minmax_loop:Nww}.
% \begin{macrocode}
-\cs_new:Npn \@@_max_o:w #1 @
+\cs_new:Npn \@@_minmax_o:Nw #1#2 @
{
- \exp_after:wN \@@_minmax_loop:Nww
- \exp_after:wN \c_minus_one
- \c_minus_inf_fp
- #1
- \s_@@ \@@_chk:w { 3 \@@_minmax_break_o:w } ;
- }
-\cs_new:Npn \@@_min_o:w #1 @
- {
- \exp_after:wN \@@_minmax_loop:Nww
- \exp_after:wN \c_one
- \c_inf_fp
- #1
+ \if_meaning:w 0 #1
+ \exp_after:wN \@@_minmax_loop:Nww \exp_after:wN \c_one
+ \else:
+ \exp_after:wN \@@_minmax_loop:Nww \exp_after:wN \c_minus_one
+ \fi:
+ #2
+ \s_@@ \@@_chk:w 2 #1 \s_@@_exact ;
\s_@@ \@@_chk:w { 3 \@@_minmax_break_o:w } ;
}
% \end{macrocode}
@@ -407,13 +404,14 @@
%
% \subsection{Boolean operations}
%
-% \begin{macro}[int, EXP]{\@@_!_o:w}
+% \begin{macro}[int, EXP]{\@@_not_o:w}
% Return \texttt{true} or \texttt{false}, with two expansions, one to
-% exit the conditional, and one to please \pkg{l3fp-parse}.
+% exit the conditional, and one to please \pkg{l3fp-parse}. The first
+% argument is provided by \pkg{l3fp-parse} and is ignored.
% \begin{macrocode}
-\cs_new:cpn { @@_!_o:w } \s_@@ \@@_chk:w #1#2;
+\cs_new:cpn { @@_not_o:w } #1 \s_@@ \@@_chk:w #2#3; @
{
- \if_meaning:w 0 #1
+ \if_meaning:w 0 #2
\exp_after:wN \exp_after:wN \exp_after:wN \c_one_fp
\else:
\exp_after:wN \exp_after:wN \exp_after:wN \c_zero_fp
@@ -480,12 +478,12 @@
\@@_exp_after_array_f:w #3 \s_@@_stop
\exp_after:wN @
\tex_romannumeral:D
- \@@_parse_until:Nw \c_two
+ \@@_parse_operand:Nw \c_two
\@@_parse_expand:w
\else:
\__msg_kernel_expandable_error:nnnn
{ kernel } { fp-missing } { : } { ~for~?: }
- \exp_after:wN \@@_parse_until_test:NwN
+ \exp_after:wN \@@_parse_continue:NwN
\exp_after:wN #1
\tex_romannumeral:D -`0
\@@_exp_after_array_f:w #3 \s_@@_stop
@@ -508,7 +506,7 @@
\cs_new:Npn \@@_ternary_map_break: #1 \@@_ternary_break_point:n #2 {#2}
\cs_new:Npn \@@_ternary_auxi:NwwN #1#2@#3@#4
{
- \exp_after:wN \@@_parse_until_test:NwN
+ \exp_after:wN \@@_parse_continue:NwN
\exp_after:wN #1
\tex_romannumeral:D -`0
\@@_exp_after_array_f:w #2 \s_@@_stop
@@ -516,7 +514,7 @@
}
\cs_new:Npn \@@_ternary_auxii:NwwN #1#2@#3@#4
{
- \exp_after:wN \@@_parse_until_test:NwN
+ \exp_after:wN \@@_parse_continue:NwN
\exp_after:wN #1
\tex_romannumeral:D -`0
\@@_exp_after_array_f:w #3 \s_@@_stop
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx
index a9e926bcaeb..3923238e387 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-parse.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3fp-parse.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-parse.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -36,7 +36,7 @@
%
%<*driver>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3fp-parse.dtx 4482 2013-04-24 21:05:12Z joseph $
+\GetIdInfo$Id: l3fp-parse.dtx 4604 2013-11-19 03:03:47Z bruno $
{L3 Floating-point expression parsing}
\documentclass[full]{l3doc}
\begin{document}
@@ -61,26 +61,6 @@
%
% \maketitle
%
-% ^^A begin[todo]
-%
-% ^^A To typeset the examples of expansion control, I'm using a hand-made
-% ^^A environment.
-% \newcommand{\fpOperation}[1]
-% {\textcolor[rgb]{.6,.2,.2}{\ttfamily#1}}
-% \newcommand{\fpPrecedence}[1]
-% {\textcolor[rgb]{.2,.2,.6}{\ttfamily#1}}
-% \newcommand{\fpExpand}[2]
-% {\underline{\textcolor{red}{#1{#2}}}}
-% \newenvironment{l3fp-code-example}
-% {\begin{quote}^^A
-% \edef\^{\string^}^^A
-% \let\*\fpExpand
-% \let\o\fpOperation
-% \let\p\fpPrecedence
-% \def\!{\begingroup\def\!{\endgroup\par}\color[gray]{0.5}}^^A
-% \ttfamily\frenchspacing
-% }{\end{quote}}
-%
% \begin{documentation}
%
% \end{documentation}
@@ -97,661 +77,526 @@
%<@@=fp>
% \end{macrocode}
%
-% \section{Precedences}
-%
-% In order of evaluation (some distinctions are irrelevant for the order
-% of evaluation, but serve as signals).
-% \begin{itemize}
-% \item[32] Juxtaposition for implicit multiplication.
-% \item[16] Function calls with multiple arguments.
-% \item[15] Function calls expecting exactly one argument.
-% \item[14] Binary |**| and |^| (right to left).
-% \item[12] Unary |+|, |-|, |!| (right to left).
-% \item[10] Binary |*|, |/| and |%|.
-% \item[9] Binary |+| and |-|.
-% \item[7] Comparisons.
-% \item[5] Logical \texttt{and}, denoted by |&&|.
-% \item[4] Logical \texttt{or}, denoted by \verb*+||+.
-% \item[3] Ternary operator |?:|, piece |?|.
-% \item[2] Ternary operator |?:|, piece |:|.
-% \item[1] Commas, and parentheses accepting commas.
-% \item[0] Parentheses expecting exactly one argument.
-% \item[-1] Start and end of the expression.
-% \end{itemize}
-%
-% ^^A todo: ask SO when sNaN can arise.
+% \subsection{Work plan}
%
-% \section{Evaluating an expression}
+% The task at hand is non-trivial, and some previous failed attempts
+% show that the code leads to unreadable logs, so we had better get it
+% (almost) right the first time. Let us first describe our goal, then
+% discuss the design precisely before writing any code.
%
% \begin{macro}[EXP, int]{\@@_parse:n}
% \begin{syntax}
-% \cs{@@_parse:n} \Arg{floating point expression}
+% \cs{@@_parse:n} \Arg{fpexpr}
% \end{syntax}
-% This \texttt{f}-expands to the internal floating point number
-% obtained by evaluating the \meta{floating point expression}. During
-% this evaluation, each token is fully \texttt{f}-expanded.
+% Evaluates the \meta{floating point expression} and leaves the result
+% in the input stream as an internal floating point number. This
+% function forms the basis of almost all public \pkg{l3fp} functions.
+% During evaluation, each token is fully \texttt{f}-expanded.
% \begin{texnote}
% Registers (integers, toks, etc.) are automatically unpacked,
-% without requiring a function such as \cs{int_use:N}. Invalid
+% without requiring a function such as \cs{int_use:N}. Invalid
% tokens remaining after \texttt{f}-expansion will lead to
-% unrecoverable low-level TeX errors.\footnote{Bruno: describe what
-% happens in cases like $2\cs{c_three} = 6$.}
+% unrecoverable low-level \TeX{} errors.
% \end{texnote}
% \end{macro}
%
-% \section{Work plan}\label{subsec:fp-parse-workplan}
-%
-% The task at hand is non-trivial, and some previous failed attempts have
-% shown me that the code ends up giving unreadable logs, so we'd better get
-% it (almost) right the first time. Let us thus first discuss precisely
-% the design before starting to write the code. To simplify matters,
-% we first consider expressions with integers only.
-%
-% \subsection{Storing results}
-%
-% The main issue in parsing expressions expandably is: \enquote{where
-% in the input stream should the result be put?}
-%
-% One option is to place the result at the end of the expression,
-% but this has several drawbacks:
+% Floating point expressions are composed of numbers, given in various
+% forms, infix operators, such as |+|, |**|, or~|,| (which joins two
+% numbers into a list), and prefix operators, such as the unary~|-|,
+% functions, or opening parentheses. Here is a list of precedences
+% which control the order of evaluation (some distinctions are
+% irrelevant for the order of evaluation, but serve as signals), from
+% the tightest binding to the loosest binding.
% \begin{itemize}
-% \item firstly it means that for long expressions we would be reaching
-% all the way to the end of the expression at every step of the
-% calculation, which can be rather expensive;
-% \item secondly, when parsing parenthesized sub-expressions, we would
-% naturally place the result after the corresponding closing parenthesis.
-% But since \cs{@@_parse:n} does not assume that its argument is expanded,
-% this closing parenthesis may be hidden in a macro, and not present yet,
-% causing havoc.
+% \item[32] Juxtaposition for implicit multiplication.
+% \item[16] Function calls with multiple arguments.
+% \item[15] Function calls expecting exactly one argument.
+% \item[14] Binary |**| and~|^| (right to left).
+% \item[12] Unary |+|, |-|, |!| (right to left).
+% \item[10] Binary |*|, |/| and~|%|.
+% \item[9] Binary |+| and~|-|.
+% \item[7] Comparisons.
+% \item[5] Logical \texttt{and}, denoted by~|&&|.
+% \item[4] Logical \texttt{or}, denoted by~\verb*+||+.
+% \item[3] Ternary operator |?:|, piece~|?|.
+% \item[2] Ternary operator |?:|, piece~|:|.
+% \item[1] Commas, and parentheses accepting commas.
+% \item[0] Parentheses expecting exactly one argument.
+% \item[-1] Start and end of the expression.
% \end{itemize}
%
-% The other natural option is to store the result at the start of the
-% expression, and carry it as an argument of each macro. This does not
-% really work either: in order to expand what follows on the input stream,
-% we need to skip at each step over all the tokens in the result using
-% \cs{exp_after:wN}. But this requires adding many \cs{exp_after:wN} to
-% the result at each step, also an expensive process.
+% \subsubsection{Storing results}
+%
+% The main question in parsing expressions expandably is to decide where
+% to put the intermediate results computed for various subexpressions.
+%
+% One option is to store the values at the start of the expression, and
+% carry them together as the first argument of each macro. However, we
+% want to \texttt{f}-expand tokens one by one in the expression (as
+% \cs{int_eval:n} does), and with this approach, expanding the next
+% unread token forces us to jump with \cs{exp_after:wN} over every value
+% computed earlier in the expression. With this approach, the run-time
+% will grow at least quadratically in the length of the expression, if
+% not as its cube (inserting the \cs{exp_after:wN} is tricky and slow).
+%
+% A second option is to place those values at the end of the expression.
+% Then expanding the next unread token is straightforward, but this
+% still hits a performance issue: for long expressions we would be
+% reaching all the way to the end of the expression at every step of the
+% calculation. The run-time is again quadratic.
+%
+% A variation of the above attempts to place the intermediate results
+% which appear when computing a parenthesized expression near the
+% closing parenthesis. This still lets us expand tokens as we go, and
+% avoids performance problems as long as there are enough parentheses.
+% However, it would be much better to avoid requiring the closing
+% parenthesis to be present as soon as the corresponding opening
+% parenthesis is read: the closing parenthesis may still be hidden in a
+% macro yet to be expanded.
%
% Hence, we need to go for some fine expansion control: the result is
-% stored \emph{before} the start\ldots{} A toy model that illustrates this
-% idea is to try and add some positive integers which may be hidden
-% within macros, or registers. Assume that one number has already been
-% found, and that we want to parse the next number. The current status
-% of the code may look as follows.
+% stored \emph{before} the start!
+%
+% Let us illustrate this idea in a simple model: adding positive
+% integers which may be resulting from the expansion of macros, or may
+% be values of registers. Assume that one number, say, $12345$, has
+% already been found, and that we want to parse the next number. The
+% current status of the code may look as follows.
% \begin{quote}\ttfamily
% \cs{exp_after:wN} \cs{add:ww}
% \cs{__int_value:w} 12345 \cs{exp_after:wN} ; \newline
-% \cs{tex_romannumeral:D} -`0 \cs{clean:w} \meta{stuff}
+% \cs{tex_romannumeral:D} |\operand:w| \meta{stuff}
% \end{quote}
-% Hitting this construction by one step of expansion expands
-% \cs{exp_after:wN}, which triggers the primitive \cs{__int_value:w},
-% which reads an integer, \texttt{12345}. This integer is unfinished,
-% causing the second \cs{exp_after:wN} to expand, and trigger
-% the construction \cs{tex_romannumeral:D} |-`0|, which f-expands
-% \cs{clean:w} (see \pkg{l3expan.dtx} for an explanation). Assume
-% then that \cs{clean:w} is such that it expands \meta{stuff} to
-% \emph{e.g.}, |333444;|. Once \cs{clean:w} is done expanding, we
-% will obtain essentially
+% One step of expansion expands \cs{exp_after:wN}, which triggers the
+% primitive \cs{__int_value:w}, which reads the five digits we have
+% already found, |12345|. This integer is unfinished, causing the
+% second \cs{exp_after:wN} to expand, and to trigger the construction
+% \cs{tex_romannumeral:D}, which expands |\operand:w|, defined to read
+% what follows and make a number out of it, then leave \cs{c_zero}, the
+% number, and a semicolon in the input stream. Once |\operand:w| is
+% done expanding, we obtain essentially
% \begin{quote}\ttfamily
-% \cs{exp_after:wN} \cs{add:ww} \cs{__int_value:w} 12345 ; 333444 ;
+% \cs{exp_after:wN} \cs{add:ww} \cs{__int_value:w} 12345 ; \newline
+% \cs{tex_romannumeral:D} \cs{c_zero} 333444 ;
% \end{quote}
-% where in fact \cs{exp_after:wN} has already been expanded, and
-% \cs{__int_value:w} has already seen \texttt{12345}. Now,
-% \cs{__int_value:w} sees the \texttt{;}, and stops expanding, and
-% we are left with
+% where in fact \cs{exp_after:wN} has already been expanded,
+% \cs{__int_value:w} has already seen |12345|, and
+% \cs{tex_romannumeral:D} is still looking for a number. It finds
+% \cs{c_zero}, hence expands to nothing. Now, \cs{__int_value:w} sees
+% the \texttt{;}, which cannot be part of a number. The expansion
+% stops, and we are left with
% \begin{quote}\ttfamily
% \cs{add:ww} 12345 ; 333444 ;
% \end{quote}
% which can safely perform the addition by grabbing two arguments
-% delimited by \texttt{;}.
-%
-% On this toy example, we could note that if we were to continue
-% parsing the expression, then the following number should also
-% be cleaned up before the next use of a binary operation such as
-% \cs{add:ww}. Just like \cs{__int_value:w} \texttt{12345}
-% \cs{exp_after:wN} \texttt{;} expanded what follows once, we need
-% \cs{add:ww} to do the calculation, and in the process to expand
-% the following once. This is also true in our real application:
-% all the functions of the form \cs{@@_..._o:ww} expand what
-% follows once. This comes at the cost of leaving tokens in the
-% input stack, and we will need to be careful to waste as little
-% as possible of this precious memory.
-%
-% \subsection{Precedence}
-%
-% A major point to keep in mind when parsing expressions is that
-% different operators have different precedence. The true analog
-% of our toy \cs{clean:w} macro must thus take care of that. For
-% definiteness, let us assume that the operation which prompted
-% \cs{clean:w} was a multiplication. Then \cs{clean:w} (expand
-% and) read digits until the number is ended by some operation.
-% If this is \texttt{+} or~\texttt{-}, then the multiplication
-% should be calculated next, so \cs{clean:w} can simply decide
-% that its job is done. However, if the operator we find is |^|,
-% then this operation must be performed before returning control
-% to the multiplication. This means that we need to \cs{clean:w}
-% the number following |^|, and perform the calculation, then just
-% end our job.
-%
-% Hence, each time a number is cleaned, the precedence of the
-% following operation must be compared to that of the previous
-% operation. The process of course has to happen recursively.
-% For instance, |1+2^3*4| would involve the following steps.
+% delimited by~|;|.
+%
+% If we were to continue parsing the expression, then the following
+% number should also be cleaned up before the next use of a binary
+% operation such as \cs{add:ww}. Just like \cs{__int_value:w} |12345|
+% \cs{exp_after:wN}~|;| expanded what follows once, we need \cs{add:ww}
+% to do the calculation, and in the process to expand the following
+% once. This is also true in our real application: all the functions of
+% the form \cs{@@_..._o:ww} expand what follows once. This comes at the
+% cost of leaving tokens in the input stack, and we will need to be
+% careful not to waste this memory. All of our discussion above is nice
+% but simplistic, as operations should not simply be performed in the
+% order they appear.
+%
+% \subsubsection{Precedence and infix operators}
+%
+% The various operators we will encounter have different precedences,
+% which influence the order of calculations: $1+2\times 3 = 1+(2\times
+% 3)$ because $\times$~has a higher precedence than~$+$. The true
+% analog of our macro |\operand:w| must thus take care of that. When
+% looking for an operand, it needs to perform calculations until
+% reaching an operator which has lower precedence than the one which
+% called |\operand:w|. This means that |\operand:w| must know what the
+% previous binary operator is, or rather, its precedence: we thus rename
+% it |\operand:Nw|. Let us describe as an example how the calculation
+% |41-2^3*4+5| will be done. Here, we abuse notations: the first
+% argument of |\operand:Nw| should be an integer constant (\cs{c_three},
+% \cs{c_nine}, \ldots{}) equal to the precedence of the given operator,
+% not directly the operator itself.
% \begin{itemize}
-% \item |1| is cleaned up.
-% \item |2| is cleaned up.
-% \item The precedences of |+| and |^| are compared. Since the
-% latter is higher, the second operand of |^| should be cleaned.
-% \item |3| is cleaned up.
-% \item The precedences of |^| and |*| are compared. Since the
-% former is higher, the cleaning step stops.
-% \item Compute |2^3 = 8|.
-% \item We now have |1+8*4|, and the operation |+| is still
-% looking for a second operand. Clean |8|.
-% \item The precedences of |+| and |*| are compared. Since the
-% latter is higher, the second operand of |*| should be cleaned.
-% \item |4| is cleaned up, and the end of the expression is reached.
-% \item Compute |8*4 = 32|.
-% \item We now have |1+8*4|, and the operation |+| is still
-% looking for a second operand. Clean |32|, and reach the end
-% of the expression.
-% \item Compute |1+32 = 33|.
+% \item Clean up~|41| and find~|-|. We call |\operand:Nw|~|-| to find
+% the second operand.
+% \item Clean up~|2| and find~|^|.
+% \item Compare the precedences of |-| and~|^|. Since the latter is
+% higher, we need to compute the exponentiation. For this, find the
+% second operand with a nested call to |\operand:Nw|~|^|.
+% \item Clean up~|3| and find~|*|.
+% \item Compare the precedences of |^| and~|*|. Since the former is
+% higher, |\operand:Nw|~|^| has found the second operand of the
+% exponentiation, which is computed: $2^{3} = 8$.
+% \item We now have |41+8*4+5|, and |\operand:Nw|~|-| is still
+% looking for a second operand for the subtraction. Is it~$8$?
+% \item Compare the precedences of |-| and~|*|. Since the latter is
+% higher, we are not done with~$8$. Call |\operand:Nw|~|*| to find
+% the second operand of the multiplication.
+% \item Clean up~|4|, and find~|-|.
+% \item Compare the precedences of |*| and~|-|. Since the former is
+% higher, |\operand:Nw|~|*| has found the second operand of the
+% multiplication, which is computed: $8*4 = 32$.
+% \item We now have |41+32+5|, and |\operand:Nw|~|-| is still looking
+% for a second operand for the subtraction. Is it~$32$?
+% \item Compare the precedences of |-| and~|+|. Since they are equal,
+% |\operand:Nw|~|-| has found the second operand for the
+% subtraction, which is computed: $41-32=9$.
+% \item We now have |9+5|.
% \end{itemize}
-% Here, there is some (expensive) redundant work: the results of
-% computations should not need to be cleaned again. Thus the true definition
-% is slightly more elaborate.
-%
-% The precedence of |(| and |)| are defined to be equal, and smaller than
-% the precedence of |+| and |-|, itself smaller than |*| and |/|, smaller,
-% finally, then the power operator |**| (or |^|).
-%
-%
-% \subsection{Infix operators}
-%
-% The implementation that was chosen is slightly wasteful: it causes
-% more nesting than necessary. ^^A todo: clarify.
-% However, it is simpler to implement and to explain than a slightly
-% optimized variant. ^^A todo: implement optimized version; compare.
-%
-% The cornerstone of that method is a pair of functions,
-% \cs{until} and \cs{one}, which both take as their first
-% argument the precedence (an integer) of the last operation.
-% The f-expansion of
+% The procedure above stops short of performing all computations, but
+% adding a surrounding call to |\operand:Nw| with a very low precedence
+% ensures that all computations will be performed before |\operand:Nw|
+% is done. Adding a trailing marker with the same very low precedence
+% prevents the surrounding |\operand:Nw| from going beyond the marker.
+%
+% The pattern above to find an operand for a given operator, is to find
+% one number and the next operator, then compare precedences to know if
+% the next computation should be done. If it should, then perform it
+% after finding its second operand, and look at the next operator, then
+% compare precedences to know if the next computation should be done.
+% This continues until we find that the next computation should not be
+% done. Then, we stop.
+%
+% We are now ready to get a bit more technical and describe which of the
+% \pkg{l3fp-parse} functions correspond to each step above.
+%
+% First, \cs{@@_parse_operand:Nw} is the |\operand:Nw| function above,
+% with small modifications due to expansion issues discussed later. We
+% denote by \meta{precedence} the argument of \cs{@@_parse_operand:Nw},
+% that is, the precedence of the binary operator whose operand we are
+% trying to find. The basic action is to read numbers from the input
+% stream. This is done by \cs{@@_parse_one:Nw}. A first approximation
+% of this function is that it reads one \meta{number}, performing no
+% computation, and finds the following binary \meta{operator}. Then it
+% expands to
% \begin{quote}
-% \cs{until} \meta{prec} \cs{one} \meta{prec} \meta{stuff}
+% \meta{number} \newline
+% ~~|\__fp_parse_infix_|\meta{operator}|:N| \meta{precedence}
% \end{quote}
-% is the internal floating point obtained by \enquote{cleaning}
-% numbers which follow in the input stream, and performing
-% computations until reaching an operation with a precedence
-% less than or equal to \meta{prec}. This is followed by a control
-% sequence of the form \cs{infix_?}, namely,
+% expanding the \texttt{infix} auxiliary before leaving the above in the
+% input stream.
+%
+% We now explain the \texttt{infix} auxiliaries. We need some
+% flexibility in how we treat the case of equal precedences: most often,
+% the first operation encountered should be performed, such as |1-2-3|
+% being computed as |(1-2)-3|, but |2^3^4| should be evaluated as
+% |2^(3^4)| instead. For this reason, and to support the equivalence
+% between |**| and~|^| more easily, each binary operator is converted to
+% a control sequence |\__fp_parse_infix_|\meta{operator}|:N| when it is
+% encountered for the first time. Instead of passing both precedences
+% to a test function to do the comparison steps above, we pass the
+% \meta{precedence} (of the earlier operator) to the \texttt{infix}
+% auxiliary for the following \meta{operator}, to know whether to
+% perform the computation of the \meta{operator}. If it should not be
+% performed, the \texttt{infix} auxiliary expands to
% \begin{quote}
-% \meta{floating point} \cs{infix_?}
+% |@| \cs{use_none:n} |\__fp_parse_infix_|\meta{operator}|:N|
% \end{quote}
-% where |?| is the operation following that number in the input
-% stream (we thus know that this operation has at most the
-% precedence \meta{prec}, otherwise it would have been performed
-% already).
-%
-% How is that expansion achieved? First, \cs{one} \meta{prec}
-% reads one \meta{floating point} number, and converts it to an
-% internal form, then the following operation, say |*|, is
-% packed in the form \cs{infix_*}, which is fed the \meta{prec}.
-% This function (one per infix operator) compares \meta{prec}
-% with the precedence of the operator we just read (here |*|).
-% If \meta{prec} is higher, our job is finished, and \cs{one}
-% leaves \cs{@@_parse_stop_until:N} so that \cs{until} knows to stop.
-% Otherwise, \cs{infix_*} triggers a new pair
-% \cs{until} \meta{prec(*)} \cs{one} \meta{prec(*)},
-% which produces the second operand \meta{floating point_2}
-% for the multiplication:
+% and otherwise it calls \cs{@@_parse_operand:Nw} with the precedence of
+% the \meta{operator} to find its second operand \meta{number_2} and the
+% next \meta{operator_2}, and expands to
% \begin{quote}
-% \cs{until} \meta{prec} \meta{floating point} \newline
-% \texttt{...} \meta{floating point_2} |;| \cs{infix_?}
+% |@| \cs{@@_parse_apply_binary:NwNwN} \newline
+% ~~~~\meta{operator} \meta{number_2} \newline
+% |@| |\__fp_parse_infix_|\meta{operator_2}|:N|
% \end{quote}
-% The dots are \cs{@@_parse_apply_binary:NwNwN} |*|. The boolean
-% tells \cs{until} that it is not done, and it expands
-% (essentially) to
+% The \texttt{infix} function is responsible for comparing precedences,
+% but cannot directly call the computation functions, because the first
+% operand \meta{number} is before the \texttt{infix} function in the
+% input stream. This is why we stop the expansion here and give control
+% to another function to close the loop.
+%
+% A definition of \cs{@@_parse_operand:Nw} \meta{precedence} with some
+% of the expansion control removed is
% \begin{quote}
-% \cs{until} \meta{prec}
-% \cs{@@_*_o:ww} \meta{floating point} \meta{floating point_2}
-% \cs{tex_romannumeral:D} \texttt{-`0} \cs{infix_?} \meta{prec}
+% \cs{exp_after:wN} \cs{@@_parse_continue:NwN} \newline
+% \cs{exp_after:wN} \meta{precedence} \newline
+% \cs{tex_romannumeral:D} |-`0| \newline
+% ~~\cs{@@_parse_one:Nw} \meta{precedence}
% \end{quote}
-% making \TeX{} expand \cs{@@_*_o:ww} before \cs{until}. As
-% implemented in \pkg{l3fp-basics}, this operation expands what follows
-% its result exactly once. This triggers \cs{tex_romannumeral:D},
-% which fully expands \cs{infix_?} \meta{prec}. This compares
-% the precedence of the next operation, |?|, and \meta{prec},
-% and leaves a boolean (and possibly more things), which is then
-% checked by \cs{until} \meta{prec} to know if the result
-% of the multiplication is the end of the story, or if |?|
-% should be computed as well before \cs{until} \meta{prec} ends.
-%
-% This should be easier to see on an example. To each infix
-% operator, for instance, |*|, is associated the following data:
-% \begin{itemize}
-% \item a test function, \cs{infix_*}, which conditionally continues
-% the calculation or waits to be hit again by expansion;
-% \item a function \fpOperation{*} (notation for \cs{@@_*_o:ww})
-% which performs the actual calculation;
-% \item an integer, \fpPrecedence{*}, which encodes the precedence of
-% the operator.
-% \end{itemize}
-% The token that is currently being expanded is underlined,
-% and in red. Tokens that have not yet been read (and could
-% still be hidden in macros) are in gray.
-%
-% In a first reading, the distinction between the \meta{precedence}
-% \fpPrecedence{+}, the operation \fpOperation{+}, and the character
-% token |+| should not matter. It is only required to accommodate for
-% multi-token infix operators such as |**|: indeed, when controlling
-% expansion, we need to skip over those tokens using \cs{exp_after:wN},
-% and this only skips one token. Thus |**| needs to be replaced by a
-% single token (either its precedence or its calculating function,
-% depending on the place).
-%
-% To end the computation cleanly, we add a trailing right
-% parenthesis, and give |(| and |)| the lowest precedence,
-% so that \cs{until}\fpPrecedence{(} \cs{one}\fpPrecedence{(}
-% reads numbers and performs operations until meeting a right
-% parenthesis. This is discussed more precisely in the next section.
-%
-% \begin{l3fp-code-example}
-% \cs{until}\p( \*\cs{one}\p( \! 11 + 2**3 * 5 - 9 )\!
-% \cs{until}\p( 1 \*\cs{one}\p( \! 1 + 2**3 * 5 - 9 )\!
-% \cs{until}\p( 11 \*\cs{one}\p( \! + 2**3 * 5 - 9 )\!
-% \cs{until}\p( 11; \*\cs{infix_+}\p( \! 2**3 * 5 - 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ \*\cs{one}\p+ \! 2**3 * 5 - 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ 2 \*\cs{one}\p+ \! **3 * 5 - 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ 2; \*\cs{infix_**}\p+ \! 3 * 5 - 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ 2;
-% F \o{**} \cs{until}\p{**} \*\cs{one}\p{**} \! 3 * 5 - 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ 2;
-% F \o{**} \cs{until}\p{**} 3 \*\cs{one}\p{**} \! * 5 - 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ 2;
-% F \o{**} \cs{until}\p{**} 3; \*\cs{infix_*}\p{**} \! 5 - 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ 2;
-% F \o{**} \*\cs{until}\p{**} 3; T \cs{infix_*} \! 5 - 9 )\!
-% \cs{until}\p( 11; F \o+ \*\cs{until}\p+ 2;
-% F \o{**} 3; \cs{infix_*} \! 5 - 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ \*\o{**} 2; 3;
-% \cs{infix_*}\p+ \! 5 - 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ 8; \*\cs{infix_*}\p+ \! 5 - 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ 8;
-% F \o* \cs{until}\p* \*\cs{one}\p* \! 5 - 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ 8;
-% F \o* \cs{until}\p* 5 \*\cs{one}\p* \! - 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ 8;
-% F \o* \cs{until}\p* 5; \*\cs{infix_-}\p* \! 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ 8;
-% F \o* \*\cs{until}\p* 5; T \cs{infix_-} \! 9 )\!
-% \cs{until}\p( 11; F \o+ \*\cs{until}\p+ 8; F \o* 5; \cs{infix_-} \! 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ \*\o{*} 8; 5; \cs{infix_-}\p+ \! 9 )\!
-% \cs{until}\p( 11; F \o+ \cs{until}\p+ 40; \*\cs{infix_-}\p+ \! 9 )\!
-% \cs{until}\p( 11; F \o+ \*\cs{until}\p+ 40; T \cs{infix_-} \! 9 )\!
-% \*\cs{until}\p( 11; F \o+ 40; \cs{infix_-} \! 9 )\!
-% \cs{until}\p( \*\o{+} 11; 40; \cs{infix_-}\p( \! 9 )\!
-% \cs{until}\p( 51; \*\cs{infix_-}\p( \! 9 )\!
-% \cs{until}\p( 51; F \o- \cs{until}\p- \*\cs{one}\p- \! 9 )\!
-% \cs{until}\p( 51; F \o- \cs{until}\p- 9 \*\cs{one}\p- \! )\!
-% \cs{until}\p( 51; F \o- \cs{until}\p- 9; \*\cs{infix_)}\p- \!\!
-% \cs{until}\p( 51; F \o- \*\cs{until}\p- 9; T \cs{infix_)} \!\!
-% \*\cs{until}\p( 51; F \o- 9; \cs{infix_)} \!\!
-% \cs{until}\p( \*\o{-} 51; 9; \cs{infix_)}\p( \!\!
-% \cs{until}\p( 42; \*\cs{infix_)}\p( \!\!
-% \*\cs{until}\p( 42; T \cs{infix_)} \!\!
-% 42; \cs{infix_)} \!\!
-% \end{l3fp-code-example}
-%
-% The only missing step is to clean the output by removing \cs{infix_)},
-% and possibly checking that nothing else remains.
-%
-% \subsection{Prefix operators, parentheses, and functions}
-%
-% Prefix operators (typically the unary |-|) and parentheses are
-% taken care of by the same mechanism, and functions (\texttt{sin},
-% \texttt{exp}, etc.) as well. Finding the argument of the unary
-% |-|, for instance, is very similar to grabbing the second operand
-% of a binary infix operator, with a small subtlety on precedence
-% explained below. Once that argument is found, its sign can be
-% flipped. A left parenthesis is just a prefix operator which
-% removes the closing parenthesis (with some extra checks).
-%
-% Detecting prefix operators is done by \cs{one}. Before looking
-% for a number, it tests the first character. If it is a digit, a
-% dot, or a register, then we have a number. Otherwise, it is put
-% in a function, \cs{prefix_?} (where |?| is roughly that first
-% character), which is expanded. For instance, with a left
-% parenthesis we would have the following.
-% \begin{l3fp-code-example}
-% \*\cs{one}\p* \! ( 2 + 3 ) \!
-% \*\cs{prefix_(}\p* \! 2 + 3 ) \!
-% \o(\p* \cs{until}\p( \*\cs{one}\p( \! 2 + 3 ) \!
-% ... \!\!
-% \o(\p* 5; \cs{infix_)} \! \!
-% \end{l3fp-code-example}
-% As usual, the \cs{until}--\cs{one} pair reads and compute
-% until reaching an operator of precedence at most \fpPrecedence{(}.
-% Then \fpOperation{(} removes \cs{infix_)} and looks ahead for
-% the next operation, comparing its precedence with the precedence
-% \fpPrecedence{*} of the previous operation (in fact, this comparison
-% is done by the relevant \cs{infix_?} built from the next operation).
-%
-% To support multi-character function (and constant) names, we
-% may need to put more than one character in the \cs{prefix_?}
-% construction. See implementation for details.
-%
-% Note that contrarily to \cs{infix_?} functions, the \cs{prefix_?}
-% functions perform no test on their argument (which is once more
-% the previous precedence), since we know that we need a number,
-% and must never stop there.
-%
-% Functions are implemented as prefix operators with infinitely high
+% This expands \cs{@@_parse_one:Nw} \meta{precedence} completely, which
+% finds a number, wraps the next \meta{operator} into an \texttt{infix}
+% function, feeds this function the \meta{precedence}, and expands it,
+% yielding either
+% \begin{quote}
+% \cs{@@_parse_continue:NwN} \meta{precedence} \newline
+% \meta{number} |@| \newline
+% \cs{use_none:n} |\__fp_parse_infix_|\meta{operator}|:N|
+% \end{quote}
+% or
+% \begin{quote}
+% \cs{@@_parse_continue:NwN} \meta{precedence} \newline
+% \meta{number} |@| \newline
+% \cs{@@_parse_apply_binary:NwNwN} \newline
+% ~~\meta{operator} \meta{number_2} \newline
+% |@| |\__fp_parse_infix_|\meta{operator_2}|:N|
+% \end{quote}
+% The definition of \cs{@@_parse_continue:NwN} is then very simple:
+% \begin{verbatim}
+% \cs_new:Npn \__fp_parse_continue:NwN #1#2@#3 { #3 #1 #2 @ }
+% \end{verbatim}
+% In the first case, |#3|~is \cs{use_none:n}, yielding
+% \begin{quote}
+% \cs{use_none:n} \meta{precedence} \meta{number} |@| \newline
+% |\__fp_parse_infix_|\meta{operator}|:N|
+% \end{quote}
+% then \meta{number} |@| |\__fp_parse_infix_|\meta{operator}|:N|. In
+% the second case, |#3|~is \cs{@@_parse_apply_binary:NwNwN}, whose role
+% is to compute \meta{number} \meta{operator} \meta{number_2} and to
+% prepare for the next comparison of precedences: first we get
+% \begin{quote}
+% \cs{@@_parse_apply_binary:NwNwN} \newline
+% ~~\meta{precedence} \meta{number} |@| \newline
+% ~~\meta{operator} \meta{number_2} \newline
+% |@| |\__fp_parse_infix_|\meta{operator_2}|:N|
+% \end{quote}
+% then
+% \begin{quote}
+% \cs{exp_after:wN} \cs{@@_parse_continue:NwN} \newline
+% \cs{exp_after:wN} \meta{precedence} \newline
+% \cs{tex_romannumeral:D} |-`0| \newline
+% |\__fp_|\meta{operator}|_o:ww| \meta{number} \meta{number_2} \newline
+% \cs{tex_romannumeral:D} |-`0| \newline
+% |\__fp_parse_infix_|\meta{operator_2}|:N| \meta{precedence}
+% \end{quote}
+% where |\__fp_|\meta{operator}|_o:ww| computes \meta{number}
+% \meta{operator} \meta{number_2} and expands after the result, thus
+% triggers the comparison of the precedence of the \meta{operator_2} and
+% the \meta{precedence}, continuing the loop.
+%
+% We have introduced the most important functions here, and the next few
+% paragraphs will describe various subtleties.
+%
+% \subsubsection{Prefix operators, parentheses, and functions}
+%
+% Prefix operators (unary |-|, |+|,~|!|) and parentheses are taken care
+% of by the same mechanism, and functions (\texttt{sin}, \texttt{exp},
+% etc.) as well. Finding the argument of the unary~|-|, for instance,
+% is very similar to grabbing the second operand of a binary infix
+% operator, with a subtle precedence explained below. Once that operand
+% is found, the operator can be applied to it (for the unary~|-|, this
+% simply flips the sign). A left parenthesis is just a prefix operator
+% with a very low precedence equal to that of the closing parenthesis
+% (which is treated as an infix operator, since it normally appears just
+% after numbers), so that all computations are performed until the
+% closing parenthesis. The prefix operator associated to the left
+% parenthesis does not alter its argument, but it removes the closing
+% parenthesis (with some checks).
+%
+% Prefix operators are the reason why we only summarily described the
+% function \cs{@@_parse_one:Nw} earlier. This function is responsible
+% for reading in the input stream the first possible \meta{number} and
+% the next infix \meta{operator}. If what follows \cs{@@_parse_one:Nw}
+% \meta{precedence} is a prefix operator, then we must find the operand
+% of this prefix operator through a nested call to
+% \cs{@@_parse_operand:Nw} with the appropriate precedence, then apply
+% the operator to the operand found to yield the result of
+% \cs{@@_parse_one:Nw}. So far, all is simple.
+%
+% The unary operators |+|, |-|,~|!| complicate things a little bit:
+% |-3**2| should be $-(3^2)=-9$, and not $(-3)^2=9$. This would easily
+% be done by giving~|-| a lower precedence, equal to that of the infix
+% |+| and~|-|. Unfortunately, this fails in cases such as |3**-2*4|,
+% yielding $3^{-2\times 4}$ instead of the correct $3^{-2}\times 4$. A
+% second attempt would be to call \cs{@@_parse_operand:Nw} with the
+% \meta{precedence} of the previous operator, but |0>-2+3| is then
+% parsed as |0>-(2+3)|: the addition is performed because it binds more
+% tightly than the comparision which precedes~|-|. The correct approach
+% is for a unary~|-| to perform operations whose precedence is greater
+% than both that of the previous operation, and that of the unary~|-|
+% itself. The unary~|-| is given a precedence higher than
+% multiplication and division. This does not lead to any surprising
+% result, since $-(x/y) = (-x)/y$ and similarly for multiplication, and
+% it reduces the number of nested calls to \cs{@@_parse_operand:Nw}.
+%
+% Functions are implemented as prefix operators with very high
% precedence, so that their argument is the first number that can
-% possibly be built. For instance, something like the following could
-% happen in a computation
-% \begin{l3fp-code-example}
-% \*\cs{one}\p* \! sqrt 4 + 3 ) \!
-% \*\cs{prefix_sqrt}\p* \! 4 + 3 ) \!
-% \o{sqrt}\p* \cs{until}\p{$\infty$} \*\cs{one}\p{$\infty$} \! 4 + 3 ) \!
-% ... \!\!
-% \o{sqrt}\p* 4; \cs{infix_+} \! 3 ) \!
-% 2; \*\cs{infix_+}\p* \! 3 ) \!
-% \end{l3fp-code-example}
-%
-% Lonely example, to be put somewhere: |2+sin 1 * 3| is $2+(\sin(1)\times 3)$.
-%
-% A further complication arises in the case of the unary |-| sign:
-% |-3**2| should be $-(3^2)=-9$, and not $(-3)^2=9$. Easy, just give
-% |-| a lower precedence, equal to that of the infix |+| and |-|.
-% Unfortunately, this fails in subtle cases such as |3**-2*4|,
-% yielding $3^{-2\times 4}$ instead of the correct $3^{-2}\times 4$.
-% In fact, a unary |-| should only perform operations whose precedence
-% is greater than that of the last operation, as well as
-% |-|.\footnote{Taking into account the precedence of \texttt{-} itself
-% only matters when it follows a left parenthesis:
-% \texttt{(-2*4+3)} should give \texttt{((-8)+3)}, not \texttt{(-(8+3))}.}
-% Thus, \cs{prefix_-} \meta{prec} expands to something like
-% \begin{l3fp-code-example}
-% \o- \meta{prec} \cs{until}\p? \*\cs{one} \p?
-% \end{l3fp-code-example}
-% where \fpPrecedence{?} is the maximum of \meta{prec} and the
-% precedence of |-|. Once the argument of |-| is found, \fpOperation{-}
-% gets its opposite, and leaves it for the previous operation to use.
-%
-% An example with parentheses.
-%
-% \begin{l3fp-code-example}
-% \cs{until}\p( \*\cs{one}\p( \! 11 * ( 2 + 3 ) - 9 )\!
-% \cs{until}\p( 1 \*\cs{one}\p( \! 1 * ( 2 + 3 ) - 9 )\!
-% \cs{until}\p( 11 \*\cs{one}\p( \! * ( 2 + 3 ) - 9 )\!
-% \cs{until}\p( 11; \*\cs{infix_*}\p( \! ( 2 + 3 ) - 9 )\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \*\cs{one}\p* \! ( 2 + 3 ) - 9 )\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \*\cs{prefix_(}\p* \! 2 + 3 ) - 9 )\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( \*\cs{one}\p( \! 2 + 3 ) - 9 )\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 2 \*\cs{one}\p( \! + 3 ) - 9 )\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 2; \*\cs{infix_+}\p( \! 3 ) - 9 )\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 2; F \o+ \cs{until}\p+ \*\cs{one}\p+ \! 3)-9)\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 2; F \o+ \cs{until}\p+ 3 \*\cs{one}\p+ \! )-9)\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 2; F \o+ \cs{until}\p+ 3; \*\cs{infix_)}\p+ \! -9)\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 2; F \o+ \*\cs{until}\p+ 3; T \cs{infix_)} \! -9)\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \*\cs{until}\p( 2; F \o+ 3; \cs{infix_)} \! - 9 )\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( \*\o+ 2; 3; \cs{infix_)}\p( \! - 9 )\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \cs{until}\p( 5; \*\cs{infix_)}\p( \! - 9 )\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \o(\p* \*\cs{until}\p( 5; T \cs{infix_)} \! - 9 )\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* \*\o(\p* 5; \cs{infix_)} \! - 9 )\!
-% \cs{until}\p( 11; F \o* \cs{until}\p* 5; \*\cs{infix_-}\p* \! 9 )\!
-% \cs{until}\p( 11; F \o* \*\cs{until}\p* 5; T \cs{infix_-} \! 9 )\!
-% \*\cs{until}\p( 11; F \o* 5; \cs{infix_-} \! 9 )\!
-% \cs{until}\p( \*\o* 11; 5; \cs{infix_-}\p( \! 9 )\!
-% \cs{until}\p( 55; \* \cs{infix_-}\p( \! 9 )\!
-% \cs{until}\p( 55; F \o- \cs{until}\p- \*\cs{one}\p- \! 9 )\!
-% \cs{until}\p( 55; F \o- \cs{until}\p- 9 \*\cs{one}\p- \! )\!
-% \cs{until}\p( 55; F \o- \cs{until}\p- 9; \*\cs{infix_)}\p- \!\!
-% \cs{until}\p( 55; F \o- \*\cs{until}\p- 9; T \cs{infix_)} \!\!
-% \*\cs{until}\p( 55; F \o- 9; \cs{infix_)} \!\!
-% \cs{until}\p( \*\o- 55; 9; \cs{infix_)}\p( \!\!
-% \cs{until}\p( 47; \*\cs{infix_)}\p( \!\!
-% \*\cs{until}\p( 47; T \cs{infix_)} \!\!
-% 47; \cs{infix_)} \!\!
-% \end{l3fp-code-example}
-%
-% The end of this (sub)section was not revised yet
-%
+% possibly be built, except for juxtaposition.
+%
+% Note that contrarily to the \texttt{infix} functions discussed
+% earlier, the \texttt{prefix} functions do perform tests on the
+% previous \meta{precedence} to decide whether to find an argument or
+% not, since we know that we need a number, and must never stop there.
+%
+% \subsubsection{Numbers and reading tokens one by one}
+%
+% So far, we have glossed over one important point: what is a
+% \enquote{number}? A number is typically given in the form
+% \meta{significand}|e|\meta{exponent}, where the \meta{significand} is
+% any non-empty string composed of decimal digits and at most one
+% decimal separator (a period), the exponent
+% \enquote{\texttt{e}\meta{exponent}} is optional and is composed of an
+% exponent mark~|e| followed by a possibly empty string of signs
+% |+| or~|-| and a non-empty string of decimal digits. The
+% \meta{significand} can also be an integer, dimension, skip, or muskip
+% variable, in which case dimensions are converted from points (or mu
+% units) to floating points, and the \meta{exponent} can also be an
+% integer variable. Numbers can also be given as floating point
+% variables, or as named constants such as |nan|, |inf| or~|pi|. We may
+% add more types in the future.
+%
+% When \cs{@@_parse_one:Nw} is looking for a \enquote{number}, here is
+% what happens.
% \begin{itemize}
-% \item If it is a sign (|-| or |+|), then any following sign will be
-% combined with this initial sign, forming \cs{prefix_+} or \cs{prefix_-}.
-% \item If it is a letter, then any following letter is grabbed, forming
-% for instance \cs{prefix_sin} or \cs{prefix_sinh}.
-% \item Otherwise, only one token\footnote{Some support for multi-character
-% prefix operator may be added in the future, but right now, I don't
-% see a use for it. Perhaps, for including comments inside
-% the computation itself??} is grabbed, for instance \cs{prefix_(}.
+% \item If the next token is a control sequence with the meaning of
+% \cs{scan_stop:}, it can be: \cs{s_@@}, in which case our job is
+% done, as what follows is an internal floating point number, or
+% \cs{s_@@_mark}, in which case the expression has come to an early
+% end, as we are still looking for a number here, or something else,
+% in which case we consider the control sequence to be a bad
+% variable resulting from \texttt{c}-expansion.
+% \item If the next token is a control sequence with a different
+% meaning, we assume that it is a register, unpack it with
+% \cs{tex_the:D}, and use its value (in \texttt{pt} for dimensions
+% and skips, \texttt{mu} for muskips) as the \meta{significand} of a
+% number: we look for an exponent.
+% \item If the next token is a digit, we remove any leading zeros,
+% then read a significand larger than~$1$ if the next character is a
+% digit, read a significand smaller than~$1$ if the next character
+% is a period, or we have found a significand equal to~$0$
+% otherwise, and look for an exponent.
+% \item If the next token is a letter, we collect more letters until
+% the first non-letter: the resulting word may denote a function
+% such as |asin|, a constant such as |pi| or be unknown. In the
+% first case, we call \cs{@@_parse_operand:Nw} to find the argument
+% of the function, then apply the function, before declaring that we
+% are done. Otherwise, we are done, either with the value of the
+% constant, or with the value |nan| for unknown words.
+% \item If the next token is anything else, we check whether it is a
+% known prefix operator, in which case \cs{@@_parse_operand:Nw}
+% finds its operand. If it is not known, then either a number is
+% missing (if the token is a known infix operator) or the token is
+% simply invalid in floating point expressions.
% \end{itemize}
-%
-%^^A todo: make sure that's correct??
-%
-% Functions may take several arguments, possibly an unknown
-% number\footnote{Keyword argument support may be added later.},
-% for instance \texttt{round(1.23456,2)}.
+% Once a number is found, \cs{@@_parse_one:Nw} also finds an infix
+% operator. This goes as follows.
% \begin{itemize}
-% \item \texttt{round} is made into \cs{prefix_round}, which tries to
-% grab one number using \cs{one}.
-% \item This builds \cs{prefix_(}, which uses \cs{one} to grab one
-% number, calculating as necessary. The comma is given the same
-% precedence as parentheses, and thus ends the calculation of the
-% argument of \texttt{round}.
-% \item \texttt{round} now has its first argument. It can check whether
-% the argument was closed by |,| or |)|, and branch accordingly.
-% \item If it was a comma, then the first argument is skipped over,
-% through an expensive set of \cs{exp_after:wN}, and the second
-% argument can be grabbed. Here it is simply an integer, easier
-% to parse by building upon \cs{etex_numexpr:D}.
-% \item The closing parenthesis (or another comma) is seen, and the
-% control is given back to \cs{prefix_round}.
+% \item
+% \item If the next token is a control sequence, it could be the
+% end-marker \cs{s_@@_mark}, which has the lowest precedence, and
+% otherwise it is a case of juxtaposing numbers, such as
+% |2\c_three|, with an implied multiplication.
+% \item If the next token is a letter, it is also a case of
+% juxtaposition, as letters cannot be proper infix operators.
+% \item Otherwise (including in the case of digits), if the token is a
+% known infix operator, the appropriate
+% |\__fp_infix_|\meta{operator}|:N| function is built, and if it
+% does not exist, we complain. In particular, the juxtaposition
+% |\c_three 2| is disallowed.
% \end{itemize}
%
-% \subsection{Type detection}
-%
-% The type of data should be detected by reading the first few tokens,
-% before calling a type-specific function to parse it. Or
-% should the type be obtained after the semicolon which indicates the
-% end of the thing? And placed there?
-%
-% ^^A todo: what did I mean in this paragraph?
-% Also to grab exponents correctly, build \cs{@@_<abc>:w} when seeing
-% some non-numeric |abc| while still looking to complete a number (or
-% other data). Then, if \cs{@@_postfix_<type>_<abc>:w} exists, use it.
-%
-% The internal representation of floating point numbers is quite
-% untypable, and we provide here the tools to convert from a more
-% user-friendly representation to internal floating point numbers,
-% and for various other conversions. Every floating point operation
-% calls those functions to normalize the input, so they must be
-% optimized.
+% In the above, we need to test whether a character token~|#1| is a
+% digit:
+% \begin{verbatim}
+% \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f:
+% is a digit
+% \else:
+% not a digit
+% \fi:
+% \end{verbatim}
+% To exclude |0|, replace \cs{c_nine} by \cs{c_ten}. The use of
+% \cs{token_to_str:N} ensures that a digit with any catcode is detected.
+% To test if a character token is a letter, we need to work with its
+% character code, testing if |`#1| lies in $[65,90]$ (uppercase letters)
+% or $[97,112]$ (lowercase letters)
+% \begin{verbatim}
+% \if_int_compare:w \__int_eval:w
+% ( `#1 \if_int_compare:w `#1 > `Z - 32 \fi: ) / 26 = \c_three
+% is a letter
+% \else:
+% not a letter
+% \fi:
+% \end{verbatim}
+% At all steps, we try to accept all category codes: when |#1|~is kept
+% to be used later, it is almost always converted to category code other
+% through \cs{token_to_str:N}. More precisely, catcodes $\{3, 6, 7, 8,
+% 11, 12\}$ should work without trouble, but $\{1, 2, 4, 10, 13\}$ will
+% not work, and of course $\{0, 5, 9\}$ cannot become tokens.
%
-% \section{Internal representation}
+% Floating point expressions should behave as much as possible like
+% \eTeX{}-based integer expressions and dimension expressions. In
+% particular, \texttt{f}-expansion should be performed as the expression
+% is read, token by token, forcing the expansion of protected macros,
+% and ignoring spaces. One advantage of expanding at every step is that
+% restricted expandable functions can then be used in floating point
+% expressions just as they can be in other kinds of expressions.
+% Problematically, spaces stop \texttt{f}-expansion: for instance, the
+% macro~|\X| below will not be expanded if we simply perform
+% \texttt{f}-expansion.
+% \begin{verbatim}
+% \DeclareDocumentCommand {\test} {m} { \fp_eval:n {#1} }
+% \ExplSyntaxOff
+% \test { 1 + \X }
+% \end{verbatim}
+% Of course, spaces will not appear in a code setting, but may very
+% easily come in document-level input, from which some expressions may
+% come. To avoid this problem, at every step, we do essentially what
+% \cs{use:f} would do: take an argument, put it back in the input
+% stream, then \texttt{f}-expand it. This is not a complete solution,
+% since a macro's expansion could contain leading spaces which will stop
+% the \texttt{f}-expansion before further macro calls are performed.
+% However, in practice it should be enough: in particular, floating
+% point numbers will correctly be expanded to the underlying \cs{s_@@}
+% \ldots{} structure. The \texttt{f}-expansion is performed by
+% \cs{@@_parse_expand:w}.
%
-% Internally, a floating point number \meta{X} is a
-% token list containing
-% \begin{quote}
-% \cs{s_@@} \cs{@@_chk:w} \meta{case} \meta{sign} \meta{body} |;|
-% \end{quote}
-% Let us explain each piece separately.
-%
-% Internal floating point numbers will be used in expressions,
-% and in this context will be subject to f-expansion. They must
-% leave a recognizable mark after \texttt{f}-expansion, to prevent the
-% floating point number from being re-parsed. Thus, \cs{s_@@}
-% is simply another name for \tn{relax}.
-%
-% Since floating point numbers are always accessed by the various
-% operations using f-expansion, we can safely let them be protected:
-% \texttt{x}-expansion will then leave them untouched. However, when
-% used directly without an accessor function, floating points should
-% produce an error. \cs{s_@@} will do nothing, and \cs{@@_chk:w}
-% produces an error.
-%
-% The (decimal part of the) IEEE-754-2008 standard requires the
-% format to be able to represent special floating point numbers
-% besides the usual positive and negative cases. The various
-% possibilities will be distinguished by their \meta{case}, which
-% is a single digit:\footnote{Bruno: I need to implement subnormal
-% numbers. Also, quiet and signalling \texttt{nan} must be better
-% distinguished.}
-% \begin{itemize}
-% \item[0] zeros: |+0| and |-0|,
-% \item[1] \enquote{normal} numbers (positive and negative),
-% \item[2] infinities: |+inf| and |-inf|,
-% \item[3] quiet and signalling \texttt{nan}.
-% \end{itemize}
-% The \meta{sign} is |0| (positive) or |2| (negative),
-% except in the case of \texttt{nan}, which have $\meta{sign} = 1$.
-% This ensures that changing the \meta{sign} digit to $2-\meta{sign}$
-% is exactly equivalent to changing the sign of the number.
+% ^^A begin[todo]
%
-% Special floating point numbers have the form
-% \begin{quote}
-% \cs{s_@@} \cs{@@_chk:w} \meta{case} \meta{sign} \cs{s_@@_...} |;|
-% \end{quote}
-% where \cs{s_@@_...} is a scan mark carrying information about how the
-% number was formed (useful for debugging).
+% \subsection{Main auxiliary functions}
%
-% Normal floating point numbers ($\meta{case} = 1$) have the form
-% \begin{quote}
-% \cs{s_@@} \cs{@@_chk:w} 1 \meta{sign} \Arg{exponent}
-% \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} |;|
-% \end{quote}
-% Here, the \meta{exponent} is an integer, at most
-% $\cs{c_@@_max_exponent_int} =
-% \the\csname\detokenize{c__fp_max_exponent_int}\endcsname$
-% in absolute value. The body consists in four
-% blocks of exactly $4$ digits, $ 0000 \leq \meta{X_i} \leq 9999$,
-% such that
-% \[
-% \meta{X}
-% = (-1)^{\meta{sign}} 10^{-\meta{exponent}}
-% \sum_{i=1}^{4} \meta{X_i} 10^{-4i}
-% \]
-% and such that the \meta{exponent} is minimal. This implies
-% $ 1000 \leq \meta{X_1} \leq 9999 $.
-%
-% \begin{table}\centering
-% \caption{Internal representation of floating point numbers.}
-% \label{tab:fp-convert-special}
-% \begin{tabular}{ll}
-% \toprule
-% \multicolumn{1}{c}{Representation} & Meaning \\
-% \midrule
-% 0 0 \cs{s_@@_...} \texttt{;} & Positive zero. \\
-% 0 2 \cs{s_@@_...} \texttt{;} & Negative zero. \\
-% 1 0 \Arg{exponent} \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} \texttt{;}
-% & Positive floating point. \\
-% 1 2 \Arg{exponent} \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} \texttt{;}
-% & Negative floating point. \\
-% 2 0 \cs{s_@@_...} \texttt{;} & Positive infinity. \\
-% 2 2 \cs{s_@@_...} \texttt{;} & Negative infinity. \\
-% 3 1 \cs{s_@@_...} \texttt{;} & Quiet \texttt{nan}. \\
-% 3 1 \cs{s_@@_...} \texttt{;} & Signalling \texttt{nan}. \\
-% \bottomrule
-% \end{tabular}
-% \end{table}
-%
-% \section{Internal parsing functions}
-%
-% \begin{macro}[EXP, int]{\@@_parse_until:Nw}
+% \begin{macro}[rEXP, aux]{\@@_parse_operand:Nw}
% \begin{syntax}
-% \cs{tex_romannumeral:D} \cs{@@_parse_until:Nw} \meta{precedence} \cs{@@_parse_expand:w} \meta{tokens}
+% \cs{tex_romannumeral:D} \cs{@@_parse_operand:Nw} \meta{precedence} \cs{@@_parse_expand:w}
% \end{syntax}
-% Reads the \meta{tokens}, performing every computation with a
-% precedence higher than \meta{precedence}, then expands to
+% Reads the \enquote{\ttfamily\ldots{}}, performing every computation
+% with a precedence higher than \meta{precedence}, then expands to
% \begin{syntax}
-% \meta{objects} |@| \cs{@@_parse_infix_\meta{operation}:N} \ldots{}
+% \meta{result} |@| |\__fp_parse_infix_|\meta{operation}|:N| \ldots{}
% \end{syntax}
-% where the \meta{op} is the first operation with a lower precedence,
-% possibly \texttt{end}.
+% where the \meta{operation} is the first operation with a lower
+% precedence, possibly \texttt{end}, and the
+% \enquote{\ttfamily\ldots{}} start just after the \meta{operation}.
% \end{macro}
%
-% \begin{macro}[EXP, int]{\@@_parse_operand:Nw}
+% \begin{macro}[EXP, aux]{\@@_parse_infix_+:N}
% \begin{syntax}
-% \cs{@@_parse_operand:Nw} \meta{precedence} \ldots{}
+% \cs{@@_parse_infix_+:N} \meta{precedence} \ldots{}
% \end{syntax}
-% If the following \meta{operation} has a precedence higher than
-% \meta{precedence}, expands to
+% If |+|~has a precedence higher than the \meta{precedence}, cleans up
+% a second \meta{operand} and finds the \meta{operation_2} which
+% follows, and expands to
% \begin{syntax}
-% \meta{object_1} |@| \cs{@@_parse_apply_binary:NwNwN} \meta{operation} \meta{object_2} |@| \cs{@@_parse_infix_\meta{operation_2}:N} \ldots{}
+% |@| \cs{@@_parse_apply_binary:NwNwN} |+| \meta{operand} |@| \cs{@@_parse_infix_\meta{operation_2}:N} \ldots{}
% \end{syntax}
-% and otherwise expands to
+% Otherwise expands to
% \begin{syntax}
-% \meta{object} |@| \cs{@@_parse_stop_until:N} \cs{@@_parse_infix_\meta{operation}:N} \ldots{}
+% |@| \cs{use_none:n} \cs{@@_parse_infix_+:N} \ldots{}
% \end{syntax}
+% A similar function exists for each infix operator.
% \end{macro}
%
-% \begin{macro}[EXP, int]{\@@_parse_infix_\meta{operation}:N}
+% \begin{macro}[EXP, aux]{\@@_parse_one:Nw}
% \begin{syntax}
-% \cs{@@_parse_infix_\meta{operation}:N} \meta{precedence}
+% \cs{@@_parse_one:Nw} \meta{precedence} \ldots{}
% \end{syntax}
-% If the \meta{op} has a precedence higher than \meta{precedence}, expands to
+% Cleans up one or two operands depending on how the precedence of the
+% next operation compares to the \meta{precedence}. If the following
+% \meta{operation} has a precedence higher than \meta{precedence},
+% expands to
% \begin{syntax}
-% |@| \cs{@@_parse_apply_binary:NwNwN} \meta{operation} \meta{object} |@| \cs{@@_parse_infix_\meta{operation_2}:N}
+% \meta{operand_1} |@| \cs{@@_parse_apply_binary:NwNwN} \meta{operation} \meta{operand_2} |@| |\__fp_parse_infix_|\meta{operation_2}|:N| \ldots{}
% \end{syntax}
-% Otherwise expands to
+% and otherwise expands to
% \begin{syntax}
-% |@| \cs{@@_parse_stop_until:N} \cs{@@_parse_infix_\meta{operation}:N}
+% \meta{operand} |@| \cs{use_none:n} |\__fp_parse_infix_|\meta{operation}|:N| \ldots{}
% \end{syntax}
% \end{macro}
%
% ^^A end[todo]
%
-% \subsection{Expansion control}
-%
-% At each step in reading a floating point expression, we wish to
-% perform \texttt{f}-expansion. Normally, spaces stop this
-% \texttt{f}-expansion. This can be problematic: for instance, the
-% macro |\X| below will not be expanded if we simply do
-% \texttt{f}-expansion.
-% \begin{verbatim}
-% \DeclareDocumentCommand {\test} {m} { \fp_eval:n {#1} }
-% \ExplSyntaxOff
-% \test { 1 + \X }
-% \end{verbatim}
-% To avoid this problem, at every step, we do essentially what
-% \cs{use:f} would do: take an argument, put it back in the input
-% stream, then \texttt{f}-expand it. This is not a complete solution,
-% since a macro's expansion could contain leading spaces which will stop
-% the \texttt{f}-expansion before further macro calls are performed.
-% However, in practice it should be enough: in particular, floating
-% point numbers will correctly be expanded to the underlying \cs{s_@@}
-% \ldots{} structure.
-%
-%^^A begin[todo]
-% Floating point expressions should behave as much as possible like
-% \eTeX{}-based integer expressions and dimension expressions. In
-% particular, full-expansion should be performed as the expression is
-% read, token by token, forcing the expansion of protected macros, and
-% ignoring spaces.
-%
-% Full expansion can be done with \cs{tex_romannumeral:D} |-`0|.
-% Unfortunately, this expansion is stopped by spaces. Thus using simply
-% this will fail on |\fp_eval:n { 1 + ~ \l_tmpa_fp }| since the floating
-% point variable will not be expanded. Of course, spaces will not
-% appear in a code setting, but may very easily come in document-level
-% input, from which some expressions may come. We can avoid being
-% stopped by such explicit space characters (and by some braces) if we
-% add \cs{use:n} after~|-`0|.
-%
-% Testing if a character token |#1| is a digit can be done using
-% \begin{verbatim}
-% \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f:
-% true code
-% \else:
-% false code
-% \fi:
-% \end{verbatim}
-% To exclude |0|, replace \cs{c_nine} by \cs{c_ten}. The use of
-% \cs{token_to_str:N} ensures that a digit with any catcode is detected.
-%
-%^^A end[todo]
+% \subsection{Helpers}
%
% \begin{macro}[aux, rEXP]{\@@_parse_expand:w}
% \begin{syntax}
@@ -776,8 +621,6 @@
% \end{macrocode}
% \end{macro}
%
-% \subsection{Fp object type}
-%
% \begin{macro}[aux, EXP]{\@@_type_from_scan:N, \@@_type_from_scan:w}
% \begin{syntax}
% \cs{@@_type_from_scan:N} \meta{token}
@@ -804,8 +647,6 @@
% \end{macrocode}
% \end{macro}
%
-% \subsection{Reading digits}
-%
% \begin{macro}[rEXP, aux]
% {
% \@@_parse_digits_vii:N ,
@@ -817,11 +658,11 @@
% \@@_parse_digits_i:N
% }
% These functions must be called within an \cs{__int_value:w} or
-% \cs{__int_eval:w} construction. The first token which follows must be
-% \texttt{f}-expanded prior to calling those functions. The functions
-% read tokens one by one, and output digits into the input stream,
-% until meeting a non-digit, or up to a number of digits equal to
-% their index. The full expansion is
+% \cs{__int_eval:w} construction. The first token which follows must
+% be \texttt{f}-expanded prior to calling those functions. The
+% functions read tokens one by one, and output digits into the input
+% stream, until meeting a non-digit, or up to a number of digits equal
+% to their index. The full expansion is
% \begin{quote}
% \meta{digits} |;| \meta{filling 0} |;| \meta{length}
% \end{quote}
@@ -856,64 +697,37 @@
% \end{macrocode}
% \end{macro}
%
-% \subsection{Parsing one operand}
-%
-% At the start of an expression, or just following a binary operation or
-% a function call, we are looking for an operand. This can be an
-% explicit floating point number, a floating point variable, a \TeX{}
-% register, a function call such as \texttt{sin(3)}, a parenthesized
-% expression, \emph{etc.} We distinguish the various cases by their
-% first token after \texttt{f}-expansion:
-% \begin{itemize}
-% \item \cs{tex_relax:D} in some form. That can be an internal
-% floating point, a premature end, or an uninitialized register.
-% \item A register. We interpret this as the significand of a floating
-% point number. This is subtly different from unpacking it, for
-% instance, \texttt{\cs{c_minus_one}**2} gives $1$, while
-% \texttt{-1**2} gives $-1$.
-% \item A digit, or a dot. That marks the start of the significand for
-% a floating point number.
-% \item A letter (lower or upper-case), which starts an identifier,
-% either a constant or a function (possibly unknown).
-% \item |+|, |-|, or |!|, unary operators, which resume looking for a
-% floating point number before acting on it.
-% \item |(|, which makes us parse a subexpression until the
-% matching~|)|.
-% \item Other characters such as |'| or |"| may be given a meaning
-% later. Characters such as |*| or |/| have a meaning as infix
-% operators but are not valid when we are looking for an operand: for
-% instance, |3+*4| is not valid.
-% \end{itemize}
-% A category code test separates the first two cases from the others,
-% and they are further distinguished with a meaning test. We then
-% single out digits. Letters are detected using their character code.
-% All other characters are taken care of by building a csname from that
-% character and using it to continue parsing. Unknown characters lead
-% to an error.
-%
-% \begin{macro}[int, EXP]{\@@_parse_operand:Nw}
-% Function called \cs{one} at other places. It grabs one operand, and
-% packs the symbol that follows in an \cs{infix_} csname. |#1| is the
-% previous \meta{precedence}, and |#2| the first character of the
-% operand (already \texttt{f}-expanded).
+% \subsection{Parsing one number}
+%
+% \begin{macro}[aux, EXP]{\@@_parse_one:Nw}
+% This function finds one number, and packs the symbol which follows
+% in an \cs{infix_} csname. |#1|~is the previous \meta{precedence},
+% and |#2|~the first token of the operand. We distinguish four cases:
+% |#2|~is equal to \cs{scan_stop:} in meaning, |#2|~is a different
+% control sequence, |#2|~is a digit, and |#2|~is something else (this
+% last case will be split further. Despite the earlier
+% \texttt{f}-expansion, |#2|~may still be expandable if it was
+% protected by \cs{exp_not:N}, as happens with the \LaTeXe{} command
+% \tn{protect}. Testing if |#2|~is a control sequence thus includes
+% \cs{exp_not:N}.
% \begin{macrocode}
-\cs_new:Npn \@@_parse_operand:Nw #1 #2
+\cs_new:Npn \@@_parse_one:Nw #1 #2
{
- \if_catcode:w \tex_relax:D #2
- \if_meaning:w \tex_relax:D #2
+ \if_catcode:w \scan_stop: \exp_not:N #2
+ \if_meaning:w \scan_stop: #2
\exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_operand_relax:NN
+ \exp_after:wN \@@_parse_one_fp:NN
\else:
\exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_operand_register:NN
+ \exp_after:wN \@@_parse_one_register:NN
\fi:
\else:
\if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f:
\exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_operand_digit:NN
+ \exp_after:wN \@@_parse_one_digit:NN
\else:
\exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_operand_other:NN
+ \exp_after:wN \@@_parse_one_other:NN
\fi:
\fi:
#1 #2
@@ -921,111 +735,163 @@
% \end{macrocode}
% \end{macro}
%
-% ^^A todo: rounding of negative dimensions is probably wrong.
-% \begin{macro}[aux, EXP]
-% {\@@_parse_operand_register:NN, \@@_parse_operand_register_aux:www}
-% Find the exponent following the register |#2|, then combine the
-% value of |#2| (mapping |1pt| to $1$) with the exponent to produce a
-% floating point number.
-% \begin{macrocode}
-\group_begin:
-\char_set_catcode_other:N \P
-\char_set_catcode_other:N \T
-\tl_to_lowercase:n
- {
- \group_end:
- \cs_new:Npn \@@_parse_operand_register:NN #1#2
- {
- \exp_after:wN \@@_parse_infix_after_operand:NwN
- \exp_after:wN #1
- \tex_romannumeral:D -`0
- \exp_after:wN \@@_parse_operand_register_aux:www
- \tex_the:D
- \exp_after:wN #2
- \exp_after:wN P
- \exp_after:wN T
- \exp_after:wN \q_stop
- \__int_value:w \@@_parse_exponent:N
- }
- \cs_new:Npn \@@_parse_operand_register_aux:www #1 PT #2 \q_stop #3 ;
- { \@@_parse:n { #1 e #3 } }
- }
-% \end{macrocode}
-% \end{macro}
-%
% \begin{macro}[aux, EXP]
% {
-% \@@_parse_operand_relax:NN,
-% \@@_parse_exp_after_f:nw,
-% \@@_parse_exp_after_mark_f:nw,
-% \@@_parse_exp_after_?_f:nw
+% \@@_parse_one_fp:NN,
+% \@@_exp_after_mark_f:nw,
+% \@@_exp_after_?_f:nw
% }
-% The second argument is a control sequence equal to \cs{tex_relax:D}.
-% There are three cases, dispatched using \cs{@@_type_from_scan:N}.
+% This function receives a \meta{precedence} and a control sequence
+% equal to \cs{scan_stop:} in meaning. There are three cases,
+% dispatched using \cs{@@_type_from_scan:N}.
% \begin{itemize}
% \item \cs{s_@@} starts a floating point number, and we call
-% \cs{@@_parse_exp_after_f:nw}, which |f|-expands after the
-% floating point.
+% \cs{@@_exp_after_f:nw}, which |f|-expands after the floating
+% point.
% \item \cs{s_@@_mark} is a premature end, we call
-% \cs{@@_parse_exp_after_mark_f:nw}, which triggers the
-% appropriate error.
+% \cs{@@_exp_after_mark_f:nw}, which triggers an |fp-early-end|
+% error.
% \item For a control sequence not containing |\s__fp|, we call
-% \cs{@@_parse_exp_after_?_f:nw}, causing a |bad-variable| error.
+% \cs{@@_exp_after_?_f:nw}, causing a |bad-variable| error.
% \end{itemize}
% This scheme is extensible: additional types can be added by starting
% the variables with a scan mark of the form |\s__fp_|\meta{type} and
-% defining |\__fp_parse_exp_after_|\meta{type}|_f:nw|. In all cases, we
-% make sure that the last argument of \cs{@@_parse_infix:NN} is
+% defining |\__fp_exp_after_|\meta{type}|_f:nw|. In all cases, we
+% make sure that the second argument of \cs{@@_parse_infix:NN} is
% correctly expanded.
% \begin{macrocode}
-\cs_new:Npn \@@_parse_operand_relax:NN #1#2
+\cs_new:Npn \@@_parse_one_fp:NN #1#2
{
- \cs:w @@_parse_exp_after \@@_type_from_scan:N #2 _f:nw \cs_end:
+ \cs:w @@_exp_after \@@_type_from_scan:N #2 _f:nw \cs_end:
{
\exp_after:wN \@@_parse_infix:NN
\exp_after:wN #1 \tex_romannumeral:D \@@_parse_expand:w
}
#2
}
-\cs_new_eq:NN \@@_parse_exp_after_f:nw \@@_exp_after_f:nw
-\cs_new:Npn \@@_parse_exp_after_mark_f:nw #1
+\cs_new:Npn \@@_exp_after_mark_f:nw #1
{
\__msg_kernel_expandable_error:nn { kernel } { fp-early-end }
- \exp_after:wN \c_nan_fp
- \tex_romannumeral:D -`0 #1
+ \exp_after:wN \c_nan_fp \tex_romannumeral:D -`0 #1
}
-\cs_new:cpn { @@_parse_exp_after_?_f:nw } #1#2
+\cs_new:cpn { @@_exp_after_?_f:nw } #1#2
{
- \__msg_kernel_expandable_error:nnn
- { kernel } { bad-variable } {#2}
- \exp_after:wN \c_nan_fp
- \tex_romannumeral:D -`0 #1
+ \__msg_kernel_expandable_error:nnn { kernel } { bad-variable } {#2}
+ \exp_after:wN \c_nan_fp \tex_romannumeral:D -`0 #1
}
% \end{macrocode}
% \end{macro}
%
-% ^^A begin[todo]
+% \begin{macro}[aux, EXP]
+% {
+% \@@_parse_one_register:NN,
+% \@@_parse_one_register_aux:Nw,
+% \@@_parse_one_register_auxii:wwwNw,
+% \@@_parse_one_register_int:www,
+% \@@_parse_one_register_mu:www,
+% \@@_parse_one_register_dim:ww
+% }
+% This is called whenever~|#2| is a control sequence other than
+% \cs{scan_stop:} in meaning. We assume that it is a register, but
+% carefully unpacking it with \cs{tex_the:D} within braces. First, we
+% find the exponent following~|#2|. Then we unpack~|#2| with
+% \cs{tex_the:D}, and the \texttt{auxii} auxiliary distinguishes
+% integer registers from dimensions/skips from muskips, according to
+% the presence of a period and/or of |pt|. For integers, simply
+% convert \meta{value}|e|\meta{exponent} to a floating point number
+% with \cs{fp_parse:n} (this is somewhat wasteful). For other
+% registers, the decimal rounding provided by \TeX{} does not
+% accurately represent the binary value that it manipulates, so we
+% extract this binary value as a number of scaled points with
+% \cs{__int_value:w} \cs{__dim_eval:w} \meta{decimal value} |pt|, and
+% use an auxiliary of \cs{dim_to_fp:n}, which performs the
+% multiplication by $2^{-16}$, correctly rounded.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_one_register:NN #1#2
+ {
+ \exp_after:wN \@@_parse_infix_after_operand:NwN
+ \exp_after:wN #1
+ \tex_romannumeral:D -`0
+ \exp_after:wN \@@_parse_one_register_aux:Nw
+ \exp_after:wN #2
+ \__int_value:w
+ \exp_after:wN \@@_parse_exponent:N
+ \tex_romannumeral:D \@@_parse_expand:w
+ }
+\group_begin:
+\char_set_catcode_other:N \P
+\char_set_catcode_other:N \T
+\char_set_catcode_other:N \M
+\char_set_catcode_other:N \U
+\tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new:Npn \@@_parse_one_register_aux:Nw #1
+ {
+ \exp_after:wN \use:nn
+ \exp_after:wN \@@_parse_one_register_auxii:wwwNw
+ \exp_after:wN { \tex_the:D \exp_not:N #1 }
+ ; \@@_parse_one_register_dim:ww
+ PT ; \@@_parse_one_register_mu:www
+ . PT ; \@@_parse_one_register_int:www
+ \q_stop
+ }
+ \cs_new:Npn \@@_parse_one_register_auxii:wwwNw
+ #1 . #2 PT #3 ; #4#5 \q_stop { #4 #1.#2; }
+ \cs_new:Npn \@@_parse_one_register_mu:www #1 MU; #2;
+ { \@@_parse_one_register_dim:ww #1; }
+ }
+\cs_new:Npn \@@_parse_one_register_int:www #1; #2.; #3;
+ { \@@_parse:n { #1 e #3 } }
+\cs_new:Npn \@@_parse_one_register_dim:ww #1; #2;
+ {
+ \exp_after:wN \@@_from_dim_test:ww
+ \__int_value:w #2 \exp_after:wN ,
+ \__int_value:w \__dim_eval:w #1 pt ;
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_parse_one_digit:NN}
+% A digit marks the beginning of an explicit floating point number.
+% Once the number is found, we will catch the case of overflow and
+% underflow with \cs{@@_sanitize:wN}, then
+% \cs{@@_parse_infix_after_operand:NwN} expands \cs{@@_parse_infix:NN}
+% after the number we find, to wrap the following infix operator as
+% required. Finding the number itself begins by removing leading
+% zeros: further steps are described later.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_one_digit:NN #1
+ {
+ \exp_after:wN \@@_parse_infix_after_operand:NwN
+ \exp_after:wN #1
+ \tex_romannumeral:D -`0
+ \exp_after:wN \@@_sanitize:wN
+ \int_use:N \__int_eval:w \c_zero \@@_parse_trim_zeros:N
+ }
+% \end{macrocode}
+% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_parse_operand_other:NN}
-% The interesting bit is \cs{@@_parse_operand_other:NN}. It separates
-% letters from non-letters and builds the appropriate \cs{prefix}
-% function. If it is not defined (is \cs{tex_relax:D}), make it
-% a signalling \texttt{nan}. We don't look for an argument, as the
-% unknown \enquote{prefix} can also be a (mistyped) constant such
-% as \texttt{Inf}.
+% \begin{macro}[aux, EXP]{\@@_parse_one_other:NN}
+% For this function, |#2|~is a character token which is not a digit.
+% If it is a letter, \cs{@@_parse_letters:N} beyond this one and give
+% the result to \cs{@@_parse_word:Nw}. Otherwise, the character is
+% assumed to be a prefix operator, and we build
+% |\__fp_parse_prefix_|\meta{operator}|:Nw|.
% \begin{macrocode}
-\cs_new:Npn \@@_parse_operand_other:NN #1 #2
+\cs_new:Npn \@@_parse_one_other:NN #1 #2
{
\if_int_compare:w
- \__int_eval:w \tex_uccode:D `#2 / 26 = \c_three
- \exp_after:wN \@@_parse_operand_other_word_aux:Nw
+ \__int_eval:w
+ ( `#2 \if_int_compare:w `#2 > `Z - \c_thirty_two \fi: ) / 26
+ = \c_three
+ \exp_after:wN \@@_parse_word:Nw
\exp_after:wN #1
+ \exp_after:wN #2
+ \tex_romannumeral:D \exp_after:wN \@@_parse_letters:N
\tex_romannumeral:D
- \exp_after:wN \@@_parse_letters:NN
- \exp_after:wN #2
- \tex_romannumeral:D
\else:
- \exp_after:wN \@@_parse_operand_other_prefix_aux:NNN
+ \exp_after:wN \@@_parse_prefix:NNN
\exp_after:wN #1
\exp_after:wN #2
\cs:w @@_parse_prefix_#2:Nw \exp_after:wN \cs_end:
@@ -1033,161 +899,119 @@
\fi:
\@@_parse_expand:w
}
-
-\cs_new:Npn \@@_parse_letters:NN #1#2
- {
- \exp_after:wN \c_zero
- \exp_after:wN #1
- \tex_romannumeral:D
- \if_int_compare:w
- \if_catcode:w \tex_relax:D #2
- \c_zero
- \else:
- \__int_eval:w \tex_uccode:D `#2 / 26
- \fi:
- = \c_three
- \exp_after:wN \@@_parse_letters:NN
- \exp_after:wN #2
- \tex_romannumeral:D
- \exp_after:wN \@@_parse_expand:w
- \else:
- \exp_after:wN \c_zero
- \exp_after:wN ;
- \exp_after:wN #2
- \fi:
- }
-\cs_new:Npn \@@_parse_operand_other_word_aux:Nw #1 #2;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_parse_word:Nw}
+% \begin{macro}[aux, rEXP]{\@@_parse_letters:N}
+% Finding letters is a simple recursion. Once \cs{@@_parse_letters:N}
+% has done its job, we try to build a control sequence from the
+% word~|#2|. If it is a known word, then the corresponding action is
+% taken, and otherwise, we complain about an unknown word, yield
+% \cs{c_nan_fp}, and look for the following infix operator. Note that
+% the unknown word could be a mistyped function as well as a mistyped
+% constant, so there is no way to tell whether to look for arguments;
+% we do not.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_word:Nw #1#2;
{
\cs_if_exist_use:cF { @@_parse_word_#2:N }
{
\__msg_kernel_expandable_error:nnn
{ kernel } { unknown-fp-word } {#2}
- \exp_after:wN \c_nan_fp
- \tex_romannumeral:D -`0
- \@@_parse_infix:NN
+ \exp_after:wN \c_nan_fp \tex_romannumeral:D -`0
+ \@@_parse_infix:NN
}
#1
}
-\cs_new_eq:NN \s_@@_unknown \tex_relax:D
-\cs_new:Npn \@@_parse_operand_other_prefix_aux:NNN #1#2#3
+\cs_new:Npn \@@_parse_letters:N #1
+ {
+ -`0
+ \if_int_compare:w
+ \if_catcode:w \scan_stop: \exp_not:N #1
+ \c_zero
+ \else:
+ \__int_eval:w
+ ( `#1 \if_int_compare:w `#1 > `Z - \c_thirty_two \fi: )
+ / 26
+ \fi:
+ = \c_three
+ \exp_after:wN #1
+ \tex_romannumeral:D \exp_after:wN \@@_parse_letters:N
+ \tex_romannumeral:D
+ \else:
+ \@@_parse_return_semicolon:w #1
+ \fi:
+ \@@_parse_expand:w
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]
+% {\@@_parse_prefix:NNN, \@@_parse_prefix_unknown:NNN}
+% For this function, |#1|~is the previous \meta{precedence}, |#2|~is
+% the operator just seen, and |#3|~is a control sequence which
+% implements the operator if it is a known operator. If this control
+% sequence is \cs{scan_stop:}, then the operator is in fact unknown.
+% Either the expression is missing a number there (if the operator is
+% valid as an infix operator), and we put \texttt{nan}, wrapping the
+% infix operator in a csname as appropriate, or the character is
+% simply invalid in floating point expressions, and we continue
+% looking for a number, starting again from \cs{@@_parse_one:Nw}.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_prefix:NNN #1#2#3
{
- \if_meaning:w \tex_relax:D #3
- \exp_after:wN \@@_parse_operand_other_prefix_unknown:NNN
+ \if_meaning:w \scan_stop: #3
+ \exp_after:wN \@@_parse_prefix_unknown:NNN
\exp_after:wN #2
\fi:
#3 #1
}
-\cs_new:Npn \@@_parse_operand_other_prefix_unknown:NNN #1#2#3
+\cs_new:Npn \@@_parse_prefix_unknown:NNN #1#2#3
{
\cs_if_exist:cTF { @@_parse_infix_#1:N }
{
\__msg_kernel_expandable_error:nnn
{ kernel } { fp-missing-number } {#1}
- \exp_after:wN \c_nan_fp
- \tex_romannumeral:D -`0
- \@@_parse_infix:NN #3 #1
+ \exp_after:wN \c_nan_fp \tex_romannumeral:D -`0
+ \@@_parse_infix:NN #3 #1
}
{
\__msg_kernel_expandable_error:nnn
{ kernel } { fp-unknown-symbol } {#1}
- \@@_parse_operand:Nw #3
+ \@@_parse_one:Nw #3
}
}
% \end{macrocode}
% \end{macro}
%
-% The following forms are accepted:
-% \begin{itemize}
-% \item
-% \item \meta{floating point}
-% \item \meta{integer} |.| \meta{decimal} |e| \meta{exponent}
-% \end{itemize}
-% In both cases, \meta{signs} is a (possibly empty) string of
-% |+| and |-| (with any category code\footnote{Bruno: except
-% 1, 2, 4, 10, 13, and those which cannot be tokens (0, 5, 9),
-% so really, just 3, 6, 7, 8, 11, 12.}).\footnote{Bruno:
-% test (and implement) non-other digits.}
-%
-% In the second form, the \meta{integer} is a sequence of digits,
-% whose length is not limited by constraints \TeX{}'s integer
-% registers. It stops at the first non-digit character. The
-% \meta{decimal} part is formed by all digits from the dot
-% (if it exists) until the first non-digit character. The
-% \meta{exponent} part has the form \meta{exponent sign}
-% \meta{exponent body}, where \meta{exponent sign} is any string
-% of |+| or |-|, and \meta{exponent body} is a string of digits,
-% stopping, as usual, at the first non-digit.
-%
-% Any missing part will take the appropriate default value.
-% \begin{itemize}
-% \item A missing \meta{exponent} is considered to be zero.
-% \item A number with no dot has zero decimal part.
-% \item An empty \meta{integer} part or decimal part is zero.
-% \end{itemize}
-%
-% Border cases:
-% \begin{itemize}
-% \item \texttt{e1} is considered as invalid input, and gives
-% \texttt{qnan}.\footnote{Bruno: now just gives an error.}
-% This will be important once parsing expressions is
-% implemented, since \texttt{e-1} would be ambiguous otherwise.
-% \item \texttt{.e3} and \texttt{.} are zero.
-% \end{itemize}
-%
-% Bruno: expansion, not yet. Only f-expansion at the start, and
-% unpacking of registers after signs.
-%
-%
-% Work-plan.
-% \begin{itemize}
-% \item Remove any leading sign and build the \meta{sign} as we go.
-% If the next character is a letter, go to the \enquote{special}
-% branch, discussed later.
-% \item Drop leading zeros.
-% \item If the next character is a dot, drop some more zeros,
-% keeping track of how many were dropped after the dot.
-% Counting those gives $\meta{exp_1}<0$. Then read the decimal part
-% with the \cs{@@_from_str_small} functions.
-% \item Otherwise, $\meta{exp_1}=0$, and first read the integer part,
-% then the decimal part. This is implemented through the more
-% elaborate \cs{@@_from_str_large} functions.
-% \item Continuing in the same line of expansion, read the exponent
-% \meta{exp_2}.
-% \item Finally check that nothing is left.\footnote{Bruno: not done yet.}
-% \end{itemize}
-%
-% \begin{macro}[aux, EXP]{\@@_parse_operand_digit:NN}
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_operand_digit:NN #1
- {
- \exp_after:wN \@@_parse_infix_after_operand:NwN
- \exp_after:wN #1
- \tex_romannumeral:D -`0
- \exp_after:wN \@@_sanitize:wN
- \int_use:N \__int_eval:w \c_zero \@@_parse_trim_zeros:N
- }
-% \end{macrocode}
-% \end{macro}
-%
-% ^^A end[todo]
+% \subsubsection{Numbers: trimming leading zeros}
%
-% \subsubsection{Trimming leading zeros}
+% Numbers will be parsed as follows: first we trim leading zeros, then
+% if the next character is a digit, start reading a significand $\geq 1$
+% with the set of functions |\__fp_parse_large|\ldots{}; if it is a
+% period, the significand is~$<1$; and otherwise it is zero. In the
+% second case, trim additional zeros after the period, counting them for
+% an exponent shift $\meta{exp_1}<0$, then read the significand with the
+% set of functions |\__fp_parse_small|\ldots{} Once the significand is
+% read, read the exponent if |e|~is present.
%
% \begin{macro}[aux, rEXP]{\@@_parse_trim_zeros:N, \@@_parse_trim_end:w}
% This function expects an already expanded token. It removes any
-% leading zero, then distinguished three cases: if the first non-zero
-% token is a digit, then call \cs{@@_parse_large:N} (the significand is
-% $\geq 1$); if it is |.|, then continue trimming zeros with
+% leading zero, then distinguishes three cases: if the first non-zero
+% token is a digit, then call \cs{@@_parse_large:N} (the significand
+% is $\geq 1$); if it is |.|, then continue trimming zeros with
% \cs{@@_parse_strim_zeros:N}; otherwise, our number is exactly zero,
% and we call \cs{@@_parse_zero:} to take care of that case.
% \begin{macrocode}
\cs_new:Npn \@@_parse_trim_zeros:N #1
{
- \if:w 0 #1
+ \if:w 0 \exp_not:N #1
\exp_after:wN \@@_parse_trim_zeros:N
\tex_romannumeral:D
\else:
- \if:w . #1
+ \if:w . \exp_not:N #1
\exp_after:wN \@@_parse_strim_zeros:N
\tex_romannumeral:D
\else:
@@ -1210,20 +1034,21 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, rEXP]{\@@_parse_strim_zeros:N, \@@_parse_strim_end:w}
+% \begin{macro}[aux, rEXP]
+% {\@@_parse_strim_zeros:N, \@@_parse_strim_end:w}
% If we have removed all digits until a period (or if the body started
% with a period), then enter the \enquote{\texttt{small_trim}} loop
-% which outputs $-1$ for each removed $0$. Those $-1$ are added to an
+% which outputs $-1$ for each removed~$0$. Those $-1$ are added to an
% integer expression waiting for the exponent. If the first non-zero
% token is a digit, call \cs{@@_parse_small:N} (our significand is
-% smaller than~$1$), and otherwise, the number is an exact zero.
+% smaller than~$1$), and otherwise, the number is an exact zero. The
+% name \texttt{strim} stands for \enquote{small trim}.
% \begin{macrocode}
\cs_new:Npn \@@_parse_strim_zeros:N #1
{
- \if:w 0 #1
+ \if:w 0 \exp_not:N #1
- \c_one
- \exp_after:wN \@@_parse_strim_zeros:N
- \tex_romannumeral:D
+ \exp_after:wN \@@_parse_strim_zeros:N \tex_romannumeral:D
\else:
\@@_parse_strim_end:w #1
\fi:
@@ -1242,12 +1067,10 @@
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{Exact zero}
-%
% \begin{macro}[aux, EXP]{\@@_parse_zero:}
-% After reading a significand of $0$, we need to remove any exponent,
-% then put a sign of |1| for \cs{@@_sanitize:wN}, denoting an
-% exact zero.
+% After reading a significand of~$0$, we need to remove any exponent,
+% then put a sign of~|1| for \cs{@@_sanitize:wN}, small hack to denote
+% an exact zero (rather than an underflow).
% \begin{macrocode}
\cs_new:Npn \@@_parse_zero:
{
@@ -1257,7 +1080,7 @@
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{Small significand}
+% \subsubsection{Number: small significand}
%
% \begin{macro}[aux, rEXP]{\@@_parse_small:N}
% This function is called after we have passed the decimal separator
@@ -1268,8 +1091,8 @@
% expanding) can only go up to $9$ digits. Hence we grab digits in
% two steps of $8$ digits. Since |#1| is a digit, read seven more
% digits using \cs{@@_parse_digits_vii:N}. The \texttt{small_leading}
-% auxiliary will leave those digits in the \cs{__int_value:w}, and grab
-% some more, or stop if there are no more digits. Then the
+% auxiliary will leave those digits in the \cs{__int_value:w}, and
+% grab some more, or stop if there are no more digits. Then the
% \texttt{pack_leading} auxiliary puts the various parts in the
% appropriate order for the processing further up.
% \begin{macrocode}
@@ -1291,12 +1114,12 @@
% \end{syntax}
% We leave \meta{digits} \meta{zeros} in the input stream: the
% functions used to grab digits are such that this constitutes digits
-% $1$ through $8$ of the significand. Then prepare to pack $8$ more
+% $1$ through~$8$ of the significand. Then prepare to pack $8$~more
% digits, with an exponent shift of \cs{c_zero} (this shift is used in
-% the case of a large significand). If |#4| is a digit, leave it
-% behind for the packing function, and read $6$ more digits to reach a
-% total of $15$ digits: further digits are involved in the rounding.
-% Otherwise put $8$ zeros in to complete the significand, then look
+% the case of a large significand). If |#4|~is a digit, leave it
+% behind for the packing function, and read $6$~more digits to reach a
+% total of $15$~digits: further digits are involved in the rounding.
+% Otherwise put $8$~zeros in to complete the significand, then look
% for an exponent.
% \begin{macrocode}
\cs_new:Npn \@@_parse_small_leading:wwNN 1 #1 ; #2; #3 #4
@@ -1323,12 +1146,13 @@
% \begin{syntax}
% \cs{@@_parse_small_trailing:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} \meta{next~token}
% \end{syntax}
-% Leave digits $10$ to $15$ (arguments |#1| and |#2|) in the input
+% Leave digits $10$ to~$15$ (arguments |#1| and |#2|) in the input
% stream. If the \meta{next~token} is a digit, it is the $16$th
% digit, we keep it, then the \texttt{small_round} auxiliary considers
% this digit and all further digits to perform the rounding: the
-% function expands to nothing or to |+1|. Otherwise, there is no
-% $16$-th digit, so we put a $0$, and look for an exponent.
+% function expands to nothing, to |+\c_zero| or to |+\c_one|.
+% Otherwise, there is no $16$-th digit, so we put a~$0$, and look for
+% an exponent.
% \begin{macrocode}
\cs_new:Npn \@@_parse_small_trailing:wwNN 1 #1 ; #2; #3 #4
{
@@ -1354,18 +1178,18 @@
% }
% Those functions are expanded after all the digits are found, we took
% care of the rounding, as well as the exponent. The last argument is
-% the exponent. The previous five arguments are $8$ digits which we
-% pack in groups of $4$, and the argument before that is $1$, except
+% the exponent. The previous five arguments are $8$~digits which we
+% pack in groups of~$4$, and the argument before that is~$1$, except
% in the rare case where rounding lead to a carry, in which case the
-% argument is $2$. The \texttt{trailing} function has an exponent
+% argument is~$2$. The \texttt{trailing} function has an exponent
% shift as its first argument, which we add to the exponent found in
% the |e...| syntax. If the trailing digits cause a carry, the
% integer expression for the leading digits is incremented (|+ \c_one|
% in the code below). If the leading digits propagate this carry all
% the way up, the function \cs{@@_parse_pack_carry:w} increments the
-% exponent, and changes the significand from |0000...| to |1000...|: this
-% is simple because such a carry can only occur to give rise to a
-% power of $10$.
+% exponent, and changes the significand from |0000...| to |1000...|:
+% this is simple because such a carry can only occur to give rise to a
+% power of~$10$.
% \begin{macrocode}
\cs_new:Npn \@@_parse_pack_trailing:NNNNNNww #1 #2 #3#4#5#6 #7; #8 ;
{
@@ -1383,9 +1207,9 @@
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{Large significand}
+% \subsubsection{Number: large significand}
%
-% Parsing a significand larger than $1$ is a little bit more difficult
+% Parsing a significand larger than~$1$ is a little bit more difficult
% than parsing small significands. We need to count the number of
% digits before the decimal separator, and add that to the final
% exponent. We also need to test for the presence of a dot each time we
@@ -1395,8 +1219,8 @@
% \begin{macro}[aux, EXP]{\@@_parse_large:N}
% This function is followed by the first non-zero digit of a
% \enquote{large} significand ($\geq 1$). It is called within an
-% integer expression for the exponent. Grab up to $7$ more digits,
-% for a total of $8$ digits.
+% integer expression for the exponent. Grab up to $7$~more digits,
+% for a total of $8$~digits.
% \begin{macrocode}
\cs_new:Npn \@@_parse_large:N #1
{
@@ -1412,15 +1236,15 @@
% \begin{syntax}
% \cs{@@_parse_large_leading:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} \meta{next~token}
% \end{syntax}
-% We shift the exponent by the number of digits in |#1|, namely the
+% We shift the exponent by the number of digits in~|#1|, namely the
% target number, $8$, minus the \meta{number of zeros} (number of
-% digits missing). Then prepare to pack the $8$ first digits. If the
-% \meta{next token} is a digit, read up to $6$ more digits (digits
-% $10$ to $15$). If it is a period, try to grab the end of our $8$
-% first digits, branching to the \texttt{small} functions since the
-% number of digit does not affect the exponent anymore. Finally, if
-% this is the end of the significand, insert the \meta{zeros} to
-% complete the $8$ first digits, insert $8$ more, and look for an
+% digits missing). Then prepare to pack the $8$~first digits. If the
+% \meta{next token} is a digit, read up to $6$~more digits (digits
+% $10$ to~$15$). If it is a period, try to grab the end of our
+% $8$~first digits, branching to the \texttt{small} functions since
+% the number of digit does not affect the exponent anymore. Finally,
+% if this is the end of the significand, insert the \meta{zeros} to
+% complete the $8$~first digits, insert $8$~more, and look for an
% exponent.
% \begin{macrocode}
\cs_new:Npn \@@_parse_large_leading:wwNN 1 #1 ; #2; #3 #4
@@ -1434,7 +1258,7 @@
\exp_after:wN \@@_parse_digits_vi:N
\tex_romannumeral:D
\else:
- \if:w . #4
+ \if:w . \exp_not:N #4
\exp_after:wN \@@_parse_small_leading:wwNN
\__int_value:w 1
\cs:w
@@ -1460,19 +1284,19 @@
% \begin{syntax}
% \cs{@@_parse_large_trailing:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} \meta{next~token}
% \end{syntax}
-% We have just read $15$ digits. If the \meta{next token} is a digit,
-% then the exponent shift caused by this block of $8$ digits is $8$,
+% We have just read $15$~digits. If the \meta{next token} is a digit,
+% then the exponent shift caused by this block of $8$~digits is~$8$,
% first argument to the \texttt{pack_trailing} function. We keep the
% \meta{digits} and this $16$-th digit, and find how this should be
% rounded using \cs{@@_parse_large_round:NN}. Otherwise, the exponent
-% shift is the number of \meta{digits}, $7$ minus the \meta{number of
+% shift is the number of \meta{digits}, $7$~minus the \meta{number of
% zeros}, and we test for a decimal point. This case happens in
% |123451234512345.67| with exactly $15$ digits before the decimal
% separator. Then branch to the appropriate \texttt{small} auxiliary,
% grabbing a few more digits to complement the digits we already
% grabbed. Finally, if this is truly the end of the significand, look
% for an exponent after using the \meta{zeros} and providing a $16$-th
-% digit of $0$.
+% digit of~$0$.
% \begin{macrocode}
\cs_new:Npn \@@_parse_large_trailing:wwNN 1 #1 ; #2; #3 #4
{
@@ -1487,7 +1311,7 @@
\exp_after:wN \@@_parse_pack_trailing:NNNNNNww
\int_use:N \__int_eval:w \c_seven - #3 \exp_stop_f:
\int_use:N \__int_eval:w 1 #1
- \if:w . #4
+ \if:w . \exp_not:N #4
\exp_after:wN \@@_parse_small_trailing:wwNN
\__int_value:w 1
\cs:w
@@ -1505,7 +1329,167 @@
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{Finding the exponent}
+% \subsubsection{Number: beyond 16 digits, rounding}
+%
+% \begin{macro}[aux, rEXP]{\@@_parse_round_loop:N, \@@_parse_round_up:N}
+% This loop is called when rounding a number (whether the mantissa is
+% small or large). It should appear in an integer expression. This
+% function reads digits one by one, until reaching a non-digit, and
+% adds~$1$ to the integer expression for each digit. If all digits
+% found are~$0$, the function ends the expression by |;\c_zero|,
+% otherwise by |;\c_one|. This is done by switching the loop to
+% |round_up| at the first non-zero digit, thus we avoid to test
+% whether digits are~$0$ or not once we see a first non-zero digit.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_round_loop:N #1
+ {
+ \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f:
+ + \c_one
+ \if:w 0 \token_to_str:N #1
+ \exp_after:wN \@@_parse_round_loop:N
+ \tex_romannumeral:D
+ \else:
+ \exp_after:wN \@@_parse_round_up:N
+ \tex_romannumeral:D
+ \fi:
+ \else:
+ \@@_parse_return_semicolon:w \c_zero #1
+ \fi:
+ \@@_parse_expand:w
+ }
+\cs_new:Npn \@@_parse_round_up:N #1
+ {
+ \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f:
+ + \c_one
+ \exp_after:wN \@@_parse_round_up:N
+ \tex_romannumeral:D
+ \else:
+ \@@_parse_return_semicolon:w \c_one #1
+ \fi:
+ \@@_parse_expand:w
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, rEXP]{\@@_parse_round_after:wN}
+% After the loop \cs{@@_parse_round_loop:N}, this function fetches an
+% exponent with \cs{@@_parse_exponent:N}, and combines it with the
+% number of digits counted by \cs{@@_parse_round_loop:N}. At the same
+% time, the result \cs{c_zero} or \cs{c_one} is added to the
+% surrounding integer expression.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_round_after:wN #1; #2
+ {
+ + #2 \exp_after:wN ;
+ \int_use:N \__int_eval:w #1 + \@@_parse_exponent:N
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, rEXP]
+% {\@@_parse_small_round:NN, \@@_parse_round_after:wN}
+% Here, |#1|~is the digit that we are currently rounding (we only care
+% whether it is even or odd). If |#2|~is not a digit, then fetch an
+% exponent and expand to |;|\meta{exponent} only. Otherwise, we will
+% expand to |+\c_zero| or |+\c_one|, then |;|\meta{exponent}. To
+% decide which, call \cs{@@_round_s:NNNw} to know whether to round up,
+% giving it as arguments a sign~$0$ (all explicit numbers are
+% positive), the digit |#1|~to round, the first following digit~|#2|,
+% and either |+\c_zero| or |+\c_one| depending on whether the
+% following digits are all zero or not. This last argument is
+% obtained by \cs{@@_parse_round_loop:N}, whose number of digits we
+% discard by multiplying it by~$0$. The exponent which follows the
+% number is also fetched by \cs{@@_parse_round_after:wN}.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_small_round:NN #1#2
+ {
+ \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f:
+ +
+ \exp_after:wN \@@_round_s:NNNw
+ \exp_after:wN 0
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \int_use:N \__int_eval:w
+ \exp_after:wN \@@_parse_round_after:wN
+ \int_use:N \__int_eval:w \c_zero * \__int_eval:w \c_zero
+ \exp_after:wN \@@_parse_round_loop:N
+ \tex_romannumeral:D
+ \else:
+ \@@_parse_exponent:Nw #2
+ \fi:
+ \@@_parse_expand:w
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}[aux, rEXP]
+% {
+% \@@_parse_large_round:NN,
+% \@@_parse_large_round_test:NN,
+% \@@_parse_large_round_aux:wNN,
+% }
+% Large numbers are harder to round, as there may be a period in the
+% way. Again, |#1|~is the digit that we are currently rounding (we
+% only care whether it is even or odd). If there are no more digits
+% (|#2|~is not a digit), then we must test for a period: if there is
+% one, then switch to the rounding function for small significands,
+% otherwise fetch an exponent. If there are more digits (|#2|~is a
+% digit), then round, checking with \cs{@@_parse_round_loop:N} if all
+% further digits vanish, or some are non-zero. This loop is not
+% enough, as it is stopped by a period. After the loop, the
+% \texttt{aux} function tests for a period: if it is present, then we
+% must continue looking for digits, this time discarding the number of
+% digits we find.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_large_round:NN #1#2
+ {
+ \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f:
+ +
+ \exp_after:wN \@@_round_s:NNNw
+ \exp_after:wN 0
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \int_use:N \__int_eval:w
+ \exp_after:wN \@@_parse_large_round_aux:wNN
+ \int_use:N \__int_eval:w \c_one
+ \exp_after:wN \@@_parse_round_loop:N
+ \else: %^^A could be dot, or e, or other
+ \exp_after:wN \@@_parse_large_round_test:NN
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \fi:
+ }
+\cs_new:Npn \@@_parse_large_round_test:NN #1#2
+ {
+ \if:w . \exp_not:N #2
+ \exp_after:wN \@@_parse_small_round:NN
+ \exp_after:wN #1
+ \tex_romannumeral:D
+ \else:
+ \@@_parse_exponent:Nw #2
+ \fi:
+ \@@_parse_expand:w
+ }
+\cs_new:Npn \@@_parse_large_round_aux:wNN #1 ; #2 #3
+ {
+ + #2
+ \exp_after:wN \@@_parse_round_after:wN
+ \int_use:N \__int_eval:w #1
+ \if:w . \exp_not:N #3
+ + \c_zero * \__int_eval:w \c_zero
+ \exp_after:wN \@@_parse_round_loop:N
+ \tex_romannumeral:D \exp_after:wN \@@_parse_expand:w
+ \else:
+ \exp_after:wN ;
+ \exp_after:wN \c_zero
+ \exp_after:wN #3
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Number: finding the exponent}
%
% Expansion is a little bit tricky here, in part because we accept input
% where multiplication is implicit.
@@ -1532,12 +1516,12 @@
% just as \TeX{} does, we should read ahead as little as possible.
% Here, the only case where there may be an exponent is if the first
% token ahead is |e|. Then we expand (and possibly unpack) the second
-% token --- and hopefully that is safe.
+% token.
%
% \begin{macro}[aux, rEXP]{\@@_parse_exponent:Nw}
% This auxiliary is convenient to smuggle some material through
% \cs{fi:} ending conditional processing. We place those \cs{fi:}
-% (argument |#2|) at a very odd place because this allows us to insert
+% (argument~|#2|) at a very odd place because this allows us to insert
% \cs{__int_eval:w} \ldots{} there if needed.
% \begin{macrocode}
\cs_new:Npn \@@_parse_exponent:Nw #1 #2 \@@_parse_expand:w
@@ -1548,20 +1532,21 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, rEXP]{\@@_parse_exponent:N, \@@_parse_exponent_aux:N}
-% This function should be called within an \cs{__int_value:w} expansion
-% (or within an integer expression. It leaves digits of the exponent
-% behind it in the input stream, and terminates the expansion with a
-% semicolon. If there is no \texttt{e}, leave an exponent of $0$. If
-% there is an \texttt{e}, expand the next token to run some tests on
-% it. Namely, if the character code of |#1| is greater than that of
-% |9| (largest code valid for an exponent, less than any code valid
-% for an identifier), there was in fact no exponent; otherwise, we
-% search for the sign of the exponent.
+% \begin{macro}[aux, rEXP]
+% {\@@_parse_exponent:N, \@@_parse_exponent_aux:N}
+% This function should be called within an \cs{__int_value:w}
+% expansion (or within an integer expression. It leaves digits of the
+% exponent behind it in the input stream, and terminates the expansion
+% with a semicolon. If there is no~|e|, leave an exponent of~$0$. If
+% there is an~|e|, expand the next token to run some tests on it. The
+% first rough test is that if the character code of~|#1| is greater
+% than that of~|9| (largest code valid for an exponent, less than any
+% code valid for an identifier), there was in fact no exponent;
+% otherwise, we search for the sign of the exponent.
% \begin{macrocode}
\cs_new:Npn \@@_parse_exponent:N #1
{
- \if:w e #1
+ \if:w e \exp_not:N #1
\exp_after:wN \@@_parse_exponent_aux:N
\tex_romannumeral:D
\else:
@@ -1571,7 +1556,7 @@
}
\cs_new:Npn \@@_parse_exponent_aux:N #1
{
- \if_int_compare:w \if_catcode:w \tex_relax:D #1
+ \if_int_compare:w \if_catcode:w \scan_stop: \exp_not:N #1
\c_zero \else: `#1 \fi: > `9 \exp_stop_f:
0 \exp_after:wN ; \exp_after:wN e
\else:
@@ -1587,7 +1572,7 @@
% \begin{macrocode}
\cs_new:Npn \@@_parse_exponent_sign:N #1
{
- \if:w + \if:w - #1 + \fi: \token_to_str:N #1
+ \if:w + \if:w - \exp_not:N #1 + \fi: \token_to_str:N #1
\exp_after:wN \@@_parse_exponent_sign:N
\tex_romannumeral:D \exp_after:wN \@@_parse_expand:w
\else:
@@ -1624,8 +1609,8 @@
% \begin{macro}[aux, rEXP]{\@@_parse_exponent_digits:N}
% Read digits one by one, and leave them behind in the input stream.
% When finding a non-digit, stop, and insert a semicolon. Note that
-% we don't check for overflow of the exponent, hence there can be a
-% TeX error. It is mostly harmless, except when parsing
+% we do not check for overflow of the exponent, hence there can be a
+% \TeX{} error. It is mostly harmless, except when parsing
% |0e9876543210|, which should be a valid representation of $0$, but
% is not.
% \begin{macrocode}
@@ -1644,9 +1629,9 @@
% \end{macro}
%
% \begin{macro}[aux, rEXP]{\@@_parse_exponent_keep:NTF}
-% This is the last building block for parsing exponents. The argument
-% |#1| is already fully expanded, and neither |+| nor |-| nor a digit.
-% It can be:
+% This is the last building block for parsing exponents. The
+% argument~|#1| is already fully expanded, and neither |+| nor~|-| nor
+% a digit. It can be:
% \begin{itemize}
% \item \cs{s_@@}, marking the start of an internal floating point,
% invalid here;
@@ -1659,9 +1644,10 @@
% \begin{macrocode}
\prg_new_conditional:Npnn \@@_parse_exponent_keep:N #1 { TF }
{
- \if_catcode:w \tex_relax:D #1
- \if_meaning:w \tex_relax:D #1
- \if_int_compare:w \pdftex_strcmp:D { \s_@@ } { #1 } = \c_zero
+ \if_catcode:w \scan_stop: \exp_not:N #1
+ \if_meaning:w \scan_stop: #1
+ \if_int_compare:w
+ \pdftex_strcmp:D { \s_@@ } { \exp_not:N #1 } = \c_zero
0
\__msg_kernel_expandable_error:nnn
{ kernel } { fp-after-e } { floating~point~ }
@@ -1694,363 +1680,138 @@
% \end{macrocode}
% \end{macro}
%
-% ^^A begin[todo]
-% ^^A todo: word 'e' == 'invalid syntax', word 'E' == "use 'e' instead"
-%
-% \subsubsection{Beyond 16 digits: rounding}
+% \subsection{Constants, functions and prefix operators}
%
-% \begin{macro}[int]{\@@_cfs_round_loop:N}
-% Used both for \cs{@@_parse_small_round:NN} and
-% \cs{@@_parse_large_round:NN}.
-% Should appear after a \cs{__int_eval:w} |0|. Reads digits one by one,
-% until reaching a non-digit. Adds |+1| for each digit. If all digits
-% found are |0|, ends the \cs{__int_eval:w} by |;\c_zero|, otherwise
-% by |;\c_one|. This is done by switching the loop to |round_up|
-% at the first non-zero digit.
+% \subsubsection{Prefix operators}
%
+% \begin{macro}[EXP, aux]{\@@_parse_prefix_+:Nw}
+% A unary~|+| does nothing: we should continue looking for a number.
% \begin{macrocode}
-\cs_new:Npn \@@_cfs_round_loop:N #1
- {
- \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f:
- + \c_one
- \if:w 0 #1
- \exp_after:wN \@@_cfs_round_loop:N
- \tex_romannumeral:D
- \else:
- \exp_after:wN \@@_cfs_round_up:N
- \tex_romannumeral:D
- \fi:
- \else:
- \@@_parse_return_semicolon:w \c_zero #1
- \fi:
- \@@_parse_expand:w
- }
-\cs_new:Npn \@@_cfs_round_up:N #1
- {
- \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f:
- + 1
- \exp_after:wN \@@_cfs_round_up:N
- \tex_romannumeral:D
- \else:
- \@@_parse_return_semicolon:w \c_one #1
- \fi:
- \@@_parse_expand:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-%
-% \begin{macro}[int]{\@@_parse_large_round:NN}
-% \begin{syntax}
-% \cs{@@_parse_large_round:NN} \meta{digit} \meta{more digits}
-% \end{syntax}
-% \meta{digit} is the digit that we are currently rounding (we only
-% care whether it is even or odd).
-%
-% The goal is to get \cs{c_zero} or \cs{c_one}, check for an exponent
-% afterwards, and combine it to the number of digits before the decimal
-% point (which we thus need to keep track of).
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_large_round:NN #1#2
- {
- \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f:
- +
- \exp_after:wN \@@_round_s:NNNw
- \exp_after:wN 0
- \exp_after:wN #1
- \exp_after:wN #2
- \int_use:N \__int_eval:w
- \exp_after:wN \@@_parse_large_round_after:wNN
- \int_use:N \__int_eval:w \c_one
- \exp_after:wN \@@_cfs_round_loop:N
- \else: %^^A could be dot, or e, or other
- \exp_after:wN \@@_parse_large_round_dot_test:NNw
- \exp_after:wN #1
- \exp_after:wN #2
- \fi:
- }
-\cs_new:Npn \@@_parse_large_round_dot_test:NNw #1#2
- {
- \if:w . #2
- \exp_after:wN \@@_parse_small_round:NN
- \exp_after:wN #1
- \tex_romannumeral:D
- \else:
- \@@_parse_exponent:Nw #2
- \fi:
- \@@_parse_expand:w
- }
-% \end{macrocode}
-% \begin{syntax}
-% \cs{@@_parse_large_round_after:wNN} \meta{exp} |;|
-% ~~\meta{0 or 1} \meta{next~token}
-% \end{syntax}
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_large_round_after:wNN #1 ; #2 #3
- {
- \if:w . #3
- \exp_after:wN \@@_parse_large_round_after_aux:wN
- \int_use:N \__int_eval:w #1 +
- \c_zero * \__int_eval:w \c_zero
- \exp_after:wN \@@_cfs_round_loop:N
- \tex_romannumeral:D \exp_after:wN \@@_parse_expand:w
- \else:
- + #2
- \exp_after:wN ;
- \int_use:N \__int_eval:w #1 +
- \exp_after:wN \@@_parse_exponent:N
- \exp_after:wN #3
- \fi:
- }
-\cs_new:Npn \@@_parse_large_round_after_aux:wN #1 ; #2
- {
- + #2
- \exp_after:wN ;
- \int_use:N \__int_eval:w #1 +
- \@@_parse_exponent:N
- }
+\cs_new_eq:cN { @@_parse_prefix_+:Nw } \@@_parse_one:Nw
% \end{macrocode}
% \end{macro}
%
-%
-%
-% \begin{macro}[int]{\@@_parse_small_round:NN}
-% \begin{syntax}
-% \cs{@@_parse_small_round:NN} \meta{digit} \meta{more digits}
-% \end{syntax}
-% \meta{digit} is the digit that we are currently rounding (we only
-% care whether it is even or odd).
-%
-% The goal is to get \cs{c_zero} or \cs{c_one}
+% \begin{macro}[aux, EXP]{\@@_parse_apply_unary:NNNwN}
+% Here, |#1| is a precedence, |#2| is some extra data used by some
+% functions, |#3| is \emph{e.g.}, \cs{@@_sin_o:w}, and expands once
+% after the calculation, |#4| is the operand, and |#5| is a
+% |\__fp_parse_infix_...:N| function. We feed the data~|#2|, and the
+% argument~|#4|, to the function~|#3|, which expands
+% \cs{tex_romannumeral:D} thus the \texttt{infix} function~|#5|.
% \begin{macrocode}
-\cs_new:Npn \@@_parse_small_round:NN #1#2
+\cs_new:Npn \@@_parse_apply_unary:NNNwN #1#2#3#4@#5
{
- \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f:
- +
- \exp_after:wN \@@_round_s:NNNw
- \exp_after:wN 0
- \exp_after:wN #1
- \exp_after:wN #2
- \int_use:N \__int_eval:w
- \exp_after:wN \@@_parse_small_round_after:wN
- \int_use:N \__int_eval:w \c_zero
- \exp_after:wN \@@_cfs_round_loop:N
- \tex_romannumeral:D
- \else:
- \@@_parse_exponent:Nw #2
- \fi:
- \@@_parse_expand:w
- }
-\cs_new:Npn \@@_parse_small_round_after:wN #1; #2
- {
- + #2 \exp_after:wN ;
- \__int_value:w \@@_parse_exponent:N
+ #3 #2 #4 @
+ \tex_romannumeral:D -`0 #5 #1
}
% \end{macrocode}
% \end{macro}
%
-%
-% \subsection{Main functions}
-%
-% \begin{macro}[int, EXP]{\@@_parse:n}
-% \begin{macro}[aux, EXP]{\@@_parse_after:ww}
-% Start a \tn{romannumeral} expansion so that \cs{@@_parse:n} expands
-% in two steps. The \cs{@@_parse_until:Nw} function will perform
-% computations until reaching an operation with precedence
-% \cs{c_minus_one} or less. Then check that there was indeed nothing
-% left (this cannot happen), and stop the initial expansion with
-% \cs{c_zero}.%^^A todo: simplify a bit.
+% \begin{macro}[EXP, aux]{\@@_parse_prefix_-:Nw, \@@_parse_prefix_!:Nw}
+% The unary~|-| and boolean not are harder: we parse the operand using
+% a precedence equal to the maximum of the previous precedence~|##1|
+% and the precedence \cs{c_twelve} of the unary operator, then call
+% the appropriate |\__fp_|\meta{operation}|_o:w| function,
+% where the \meta{operation} is |set_sign| or |not|.
% \begin{macrocode}
-\cs_new:Npn \@@_parse:n #1
- {
- \tex_romannumeral:D
- \exp_after:wN \@@_parse_after:ww
- \tex_romannumeral:D
- \@@_parse_until:Nw \c_minus_one
- \@@_parse_expand:w #1 \s_@@_mark
- \s_@@_stop
- }
-\cs_new:Npn \@@_parse_after:ww #1@ #2 \s_@@_stop
+\cs_set_protected:Npn \@@_tmp:w #1#2#3#4
{
-%<assert> \assert_str_eq:nn { #2 } { \@@_parse_infix_end:N \s_@@_mark }
- \c_zero #1
+ \cs_new:cpn { @@_parse_prefix_ #1 :Nw } ##1
+ {
+ \exp_after:wN \@@_parse_apply_unary:NNNwN
+ \exp_after:wN ##1
+ \exp_after:wN #4
+ \cs:w @@_#3_o:w \exp_after:wN \cs_end:
+ \tex_romannumeral:D
+ \if_int_compare:w #2 < ##1
+ \@@_parse_operand:Nw ##1
+ \else:
+ \@@_parse_operand:Nw #2
+ \fi:
+ \@@_parse_expand:w
+ }
}
+\@@_tmp:w - \c_twelve { set_sign } 2
+\@@_tmp:w ! \c_twelve { not } ?
% \end{macrocode}
% \end{macro}
-% \end{macro}
%
-% \begin{macro}[int, EXP]{\@@_parse_until:Nw}
-% \begin{macro}[aux, EXP]{\@@_parse_until_test:NwN}
-% The \cs{@@_parse_until}
-% This is just a shorthand which sets up both \cs{@@_parse_until_test}
-% and \cs{@@_parse_operand} with the same precedence. Note the
-% trailing \cs{tex_romannumeral:D}. This function should be
-% used with much care.
+% \begin{macro}[EXP, aux]{\@@_parse_prefix_.:Nw}
+% Numbers which start with a decimal separator (a~period) end up here.
+% Of course, we do not look for an operand, but for the rest of the
+% number. This function is very similar to \cs{@@_parse_one_digit:NN}
+% but calls \cs{@@_parse_strim_zeros:N} to trim zeros after the
+% decimal point, rather than the \texttt{trim_zeros} function for
+% zeros before the decimal point.
% \begin{macrocode}
-\cs_new:Npn \@@_parse_until:Nw #1
+\cs_new:cpn { @@_parse_prefix_.:Nw } #1
{
- -`0
- \exp_after:wN \@@_parse_until_test:NwN
+ \exp_after:wN \@@_parse_infix_after_operand:NwN
\exp_after:wN #1
\tex_romannumeral:D -`0
- \exp_after:wN \@@_parse_operand:Nw
- \exp_after:wN #1
- \tex_romannumeral:D
+ \exp_after:wN \@@_sanitize:wN
+ \int_use:N \__int_eval:w \c_zero \@@_parse_strim_zeros:N
}
-\cs_new:Npn \@@_parse_until_test:NwN #1 #2 @ #3 { #3 #1 #2 @ }
-\cs_new_eq:NN \@@_parse_stop_until:N \use_none:n
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_parse_until_test:NwN}
-% \begin{syntax}
-% \cs{@@_parse_until_test:NwN} \meta{prec} \meta{fp} \meta{bool}
-% \end{syntax}
-% If \meta{bool} is true, then \meta{fp} is the floating
-% point number that we are looking for (it ends with |;|),
-% and this expands to \meta{fp}. If \meta{bool} is false,
-% then the input stream actually looks like
-% \begin{quote}
-% \cs{@@_parse_until_test:NwN} \meta{prec} \meta{fp_1} \meta{false}
-% \meta{oper} \meta{fp_2} \cs{infix_?}
-% \end{quote}
-% and we must feed \meta{prec} to \cs{infix_?}, and perform
-% \meta{oper} on \meta{fp_1} and \meta{fp_2}: this
-% triggers the expansion of \cs{infix_?} \meta{prec}, continuing
-% the computation (or stopping). In that case, the function \cs{until}
-% yields
-% \begin{quote}
-% \cs{@@_parse_until_test:NwN} \meta{prec}
-% \meta{oper} \meta{fp_1} \meta{fp_2}
-% \cs{tex_romannumeral:D} |-`0| \cs{infix_?} \meta{prec}
-% \end{quote}
-% expanding \meta{oper} next.
-% \begin{macrocode}
% \end{macrocode}
% \end{macro}
%
-% ^^A 3.5\mydim e4**2
-% ^^A todo: add tests that catcode changes don't mess things up.
-%
-% \subsection{Main functions}
-%
-% \begin{macro}[aux, EXP]{\@@_parse_infix_after_operand:NwN}
+% \begin{macro}[aux, EXP]
+% {\@@_parse_prefix_(:Nw, \@@_parse_lparen_after:NwN}
+% The left parenthesis is treated as a unary prefix operator because
+% it appears in exactly the same settings. Commas will be allowed if
+% the previous precedence is $16$ (function with multiple arguments)
+% or $13$ (unary boolean \enquote{not}). In this case, find an
+% operand using the precedence~$1$; otherwise the precedence~$0$.
+% Once the operand is found, the \texttt{lparen_after} auxiliary makes
+% sure that there was a closing parenthesis (otherwise it complains),
+% and leaves in the input stream the array it found as an operand,
+% fetching the following infix operator.
% \begin{macrocode}
-\cs_new:Npn \@@_parse_infix_after_operand:NwN #1 #2;
- {
- \@@_exp_after_f:nw { \@@_parse_infix:NN #1 }
- #2;
- }
\group_begin:
- \char_set_catcode_letter:N \*
- \cs_new:Npn \@@_parse_infix:NN #1 #2
+ \char_set_catcode_letter:N (
+ \char_set_catcode_letter:N )
+ \cs_new:Npn \@@_parse_prefix_(:Nw #1
{
- \if_catcode:w \tex_relax:D #2
- \if_int_compare:w
- \pdftex_strcmp:D { \s_@@_mark } { #2 }
- = \c_zero
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_infix_end:N
- \else:
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_infix_juxtapose:N
- \fi:
+ \exp_after:wN \@@_parse_lparen_after:NwN
+ \exp_after:wN #1
+ \tex_romannumeral:D
+ \if_int_compare:w #1 = \c_sixteen
+ \@@_parse_operand:Nw \c_one
\else:
- \if_int_compare:w
- \__int_eval:w \tex_uccode:D `#2 / 26
- = \c_three
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_parse_infix_juxtapose:N
- \else:
- \exp_after:wN \@@_parse_infix_check:NNN
- \cs:w
- @@_parse_infix_#2:N
- \exp_after:wN \exp_after:wN \exp_after:wN
- \cs_end:
- \fi:
+ \@@_parse_operand:Nw \c_zero
\fi:
- #1
- #2
+ \@@_parse_expand:w
}
- \cs_new:Npn \@@_parse_infix_check:NNN #1#2#3
+ \cs_new:Npn \@@_parse_lparen_after:NwN #1#2 @ #3
{
- \if_meaning:w \tex_relax:D #1
- \__msg_kernel_expandable_error:nnn { kernel } { fp-missing } { * }
- \exp_after:wN \@@_parse_infix_*:N
- \exp_after:wN #2
- \exp_after:wN #3
- \else:
- \exp_after:wN #1
- \exp_after:wN #2
- \tex_romannumeral:D \exp_after:wN \@@_parse_expand:w
- \fi:
+ \token_if_eq_meaning:NNTF #3 \@@_parse_infix_):N
+ {
+ \@@_exp_after_array_f:w #2 \s_@@_stop
+ \exp_after:wN \@@_parse_infix:NN
+ \exp_after:wN #1
+ \tex_romannumeral:D \@@_parse_expand:w
+ }
+ {
+ \__msg_kernel_expandable_error:nnn
+ { kernel } { fp-missing } { ) }
+ #2 @ \use_none:n #3
+ }
}
\group_end:
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int, EXP]{\@@_parse_apply_binary:NwNwN}
-% Receives \meta{precedence} \meta{operand_1} |@| \meta{operation}
-% \meta{operand_2} |@| \meta{infix command}. Builds the appropriate
-% call to the \meta{operation} |#4|, given the types of the two
-% \meta{operands}.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_apply_binary:NwNwN #1 #2#3@ #4 #5#6@ #7
- {
- \exp_after:wN \@@_parse_until_test:NwN
- \exp_after:wN #1
- \tex_romannumeral:D -`0
- \cs:w
- @@
- \@@_type_from_scan:N #2
- _ #4
- \@@_type_from_scan:N #5
- _o:ww
- \cs_end:
- #2#3 #5#6
- \tex_romannumeral:D -`0 #7 #1
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[int, EXP]
-% {\@@_parse_apply_unary_array:NNwN, \@@_parse_apply_unary:NNwN}
-% Here, |#2| is \emph{e.g.}, \cs{@@_sin_o:w}, and expands once after the
-% calculation.\footnote{Bruno: explain.} The argument |#3| may be an
-% array, so either we map through all its items, or we feed all items
-% at once to the custom function.
-% \begin{macrocode}
-\cs_new:Npn \@@_parse_apply_unary_array:NNwN #1#2#3@#4
- {
- #2 #3 @
- \tex_romannumeral:D -`0 #4 #1
- }
-\cs_new:Npn \@@_parse_apply_unary:NNwN #1#2#3@#4
- {
- #2 #3
- \tex_romannumeral:D -`0 #4 #1
- }
-\cs_new:Npn \@@_parse_unary_type:N #1
- { \@@_type_from_scan:N #1 _o:w \cs_end: #1 }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsection{Prefix operators}
-%
-% \subsubsection{Identifiers}
+% \subsubsection{Constants}
%
% \begin{macro}[aux, EXP]
% {
-% \@@_parse_word_inf:N, \@@_parse_word_nan:N, \@@_parse_word_pi:N ,
-% \@@_parse_word_deg:N, \@@_parse_word_em:N ,
-% \@@_parse_word_ex:N , \@@_parse_word_in:N , \@@_parse_word_pt:N ,
-% \@@_parse_word_pc:N , \@@_parse_word_cm:N , \@@_parse_word_mm:N ,
-% \@@_parse_word_dd:N , \@@_parse_word_cc:N , \@@_parse_word_nd:N ,
-% \@@_parse_word_nc:N , \@@_parse_word_bp:N , \@@_parse_word_sp:N ,
+% \@@_parse_word_inf:N , \@@_parse_word_nan:N ,
+% \@@_parse_word_pi:N , \@@_parse_word_deg:N ,
% \@@_parse_word_true:N , \@@_parse_word_false:N ,
% }
-% A whole bunch of floating point numbers.
+% Some words correspond to constant floating points. The floating
+% point constant is left as a result of \cs{@@_parse_one:Nw} after
+% expanding \cs{@@_parse_infix:NN}.
% \begin{macrocode}
\cs_set_protected:Npn \@@_tmp:w #1 #2
{
@@ -2063,7 +1824,20 @@
\@@_tmp:w { deg } \c_one_degree_fp
\@@_tmp:w { true } \c_one_fp
\@@_tmp:w { false } \c_zero_fp
-\@@_tmp:w { pt } \c_one_fp
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]
+% {
+% \@@_parse_word_pt:N , \@@_parse_word_in:N ,
+% \@@_parse_word_pc:N , \@@_parse_word_cm:N , \@@_parse_word_mm:N ,
+% \@@_parse_word_dd:N , \@@_parse_word_cc:N , \@@_parse_word_nd:N ,
+% \@@_parse_word_nc:N , \@@_parse_word_bp:N , \@@_parse_word_sp:N ,
+% }
+% Dimension units are also floating point constants but their value is
+% not stored as a floating point constant. We give the values
+% explicitly here.
+% \begin{macrocode}
\cs_set_protected:Npn \@@_tmp:w #1 #2
{
\cs_new_nopar:cpn { @@_parse_word_#1:N }
@@ -2072,6 +1846,7 @@
\s_@@ \@@_chk:w 10 #2 ;
}
}
+\@@_tmp:w {pt} { {1} {1000} {0000} {0000} {0000} }
\@@_tmp:w {in} { {2} {7227} {0000} {0000} {0000} }
\@@_tmp:w {pc} { {2} {1200} {0000} {0000} {0000} }
\@@_tmp:w {cm} { {2} {2845} {2755} {9055} {1181} }
@@ -2082,73 +1857,140 @@
\@@_tmp:w {nc} { {2} {1280} {3740} {1574} {8031} }
\@@_tmp:w {bp} { {1} {1003} {7500} {0000} {0000} }
\@@_tmp:w {sp} { {-4} {1525} {8789} {0625} {0000} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_parse_word_em:N, \@@_parse_word_ex:N}
+% The font-dependent units |em| and |ex| must be evaluated on the fly.
+% We reuse an auxiliary of \cs{dim_to_fp:n}.
+% \begin{macrocode}
\tl_map_inline:nn { {em} {ex} }
{
\cs_new_nopar:cpn { @@_parse_word_#1:N }
{
- \exp_after:wN \dim_to_fp:n \exp_after:wN
- { \dim_use:N \__dim_eval:w 1 #1 \exp_after:wN }
+ \exp_after:wN \@@_from_dim_test:ww
+ \exp_after:wN 0 \exp_after:wN ,
+ \__int_value:w \__dim_eval:w 1 #1 \exp_after:wN ;
\tex_romannumeral:D -`0 \@@_parse_infix:NN
}
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int, EXP]
+% \subsubsection{Functions}
+%
+% ^^A begin[todo]
+%
+% ^^A todo: test <15 digits>1500000000.1
+% ^^A todo: test <15 digits>1517263572.000
+%
+% ^^A todo: word 'e' == 'invalid syntax', word 'E' == "use 'e' instead"
+%
+% \begin{macro}[aux, EXP]
+% {\@@_parse_unary_function:nNN, \@@_parse_function:NNN}
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_unary_function:nNN #1#2#3
+ {
+ \exp_after:wN \@@_parse_apply_unary:NNNwN
+ \exp_after:wN #3
+ \exp_after:wN #2
+ \cs:w @@_#1_o:w \exp_after:wN \cs_end:
+ \tex_romannumeral:D
+ \@@_parse_operand:Nw \c_fifteen \@@_parse_expand:w
+ }
+\cs_new:Npn \@@_parse_function:NNN #1#2#3
+ {
+ \exp_after:wN \@@_parse_apply_unary:NNNwN
+ \exp_after:wN #3
+ \exp_after:wN #2
+ \exp_after:wN #1
+ \tex_romannumeral:D
+ \@@_parse_operand:Nw \c_sixteen \@@_parse_expand:w
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]
+% {
+% \@@_parse_word_acot:N , \@@_parse_word_acotd:N,
+% \@@_parse_word_atan:N , \@@_parse_word_atand:N,
+% \@@_parse_word_max:N , \@@_parse_word_min:N ,
+% }
+% Those functions are also unary (not binary), but may receive a
+% variable number of arguments.
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_parse_word_acot:N
+ { \@@_parse_function:NNN \@@_acot_o:Nw \use_i:nn }
+\cs_new_nopar:Npn \@@_parse_word_acotd:N
+ { \@@_parse_function:NNN \@@_acot_o:Nw \use_ii:nn }
+\cs_new_nopar:Npn \@@_parse_word_atan:N
+ { \@@_parse_function:NNN \@@_atan_o:Nw \use_i:nn }
+\cs_new_nopar:Npn \@@_parse_word_atand:N
+ { \@@_parse_function:NNN \@@_atan_o:Nw \use_ii:nn }
+\cs_new_nopar:Npn \@@_parse_word_max:N
+ { \@@_parse_function:NNN \@@_minmax_o:Nw 2 }
+\cs_new_nopar:Npn \@@_parse_word_min:N
+ { \@@_parse_function:NNN \@@_minmax_o:Nw 0 }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]
% {
% \@@_parse_word_abs:N ,
+% \@@_parse_word_exp:N ,
+% \@@_parse_word_ln:N ,
+% }
+% Unary functions.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_word_abs:N
+ { \@@_parse_unary_function:nNN { set_sign } 0 }
+\cs_new_nopar:Npn \@@_parse_word_exp:N
+ { \@@_parse_unary_function:nNN {exp} ? }
+\cs_new_nopar:Npn \@@_parse_word_ln:N
+ { \@@_parse_unary_function:nNN {ln} ? }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]
+% {
+% \@@_parse_word_acos:N ,
+% \@@_parse_word_acosd:N ,
+% \@@_parse_word_acsc:N ,
+% \@@_parse_word_acscd:N ,
+% \@@_parse_word_asec:N ,
+% \@@_parse_word_asecd:N ,
+% \@@_parse_word_asin:N ,
+% \@@_parse_word_asind:N ,
% \@@_parse_word_cos:N ,
+% \@@_parse_word_cosd:N ,
% \@@_parse_word_cot:N ,
+% \@@_parse_word_cotd:N ,
% \@@_parse_word_csc:N ,
-% \@@_parse_word_exp:N ,
-% \@@_parse_word_ln:N ,
+% \@@_parse_word_cscd:N ,
% \@@_parse_word_sec:N ,
+% \@@_parse_word_secd:N ,
% \@@_parse_word_sin:N ,
+% \@@_parse_word_sind:N ,
% \@@_parse_word_tan:N ,
+% \@@_parse_word_tand:N ,
% }
-% Unary functions, which are applied to all of their arguments when
-% receiving an array.
+% Unary functions.
% \begin{macrocode}
\tl_map_inline:nn
- { {abs} {cos} {cot} {csc} {exp} {ln} {sec} {sin} {tan} }
{
- \cs_new:cpn { @@_parse_word_#1:N } ##1
- {
- \exp_after:wN \@@_parse_apply_unary:NNwN
- \exp_after:wN ##1
- \cs:w @@_ #1 \exp_after:wN \@@_parse_unary_type:N
- \tex_romannumeral:D
- \@@_parse_until:Nw \c_fifteen
- \@@_parse_expand:w
- }
+ {acos} {acsc} {asec} {asin}
+ {cos} {cot} {csc} {sec} {sin} {tan}
}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[int, EXP]
-% {
-% \@@_parse_word_max:N , \@@_parse_word_min:N ,
-% }
-% Those functions are also unary, but need to mix all of their
-% arguments together.
-% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1#2
{
- \cs_new:Npn #1 ##1
- {
- \exp_after:wN \@@_parse_apply_unary_array:NNwN
- \exp_after:wN ##1
- \exp_after:wN #2
- \tex_romannumeral:D
- \@@_parse_until:Nw \c_sixteen \@@_parse_expand:w
- }
+ \cs_new_nopar:cpn { @@_parse_word_#1:N }
+ { \@@_parse_unary_function:nNN {#1} \use_i:nn }
+ \cs_new_nopar:cpn { @@_parse_word_#1d:N }
+ { \@@_parse_unary_function:nNN {#1} \use_ii:nn }
}
-\@@_tmp:w \@@_parse_word_max:N \@@_max_o:w
-\@@_tmp:w \@@_parse_word_min:N \@@_min_o:w
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int, EXP]{\@@_parse_word_round:N}
+% \begin{macro}[aux, EXP]{\@@_parse_word_round:N}
% This function expects one or two arguments.
% \begin{macrocode}
\cs_new:Npn \@@_parse_word_round:N #1#2
@@ -2168,7 +2010,7 @@
\exp_after:wN #1
\exp_after:wN \@@_round_to_nearest:NNN
\tex_romannumeral:D
- \@@_parse_until:Nw \c_sixteen \@@_parse_expand:w #2
+ \@@_parse_operand:Nw \c_sixteen \@@_parse_expand:w #2
}
\cs_new:Npn \@@_parse_round:Nw
#1 #2 \@@_round_to_nearest:NNN #3 \@@_parse_expand:w #4
@@ -2188,151 +2030,308 @@
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{Unary minus, plus, not}
+% \subsection{Main functions}
%
-% \begin{macro}[EXP, aux]{\@@_parse_prefix_+:Nw}
-% A unary |+| does nothing.
+% \begin{macro}[int, EXP]{\@@_parse:n}
+% \begin{macro}[aux, EXP]{\@@_parse_after:ww}
+% Start a \tn{romannumeral} expansion so that \cs{@@_parse:n} expands
+% in two steps. The \cs{@@_parse_operand:Nw} function will perform
+% computations until reaching an operation with precedence
+% \cs{c_minus_one} or less. Then stop the initial expansion with
+% \cs{c_zero}.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse:n #1
+ {
+ \tex_romannumeral:D
+ \exp_after:wN \@@_parse_after:ww
+ \tex_romannumeral:D
+ \@@_parse_operand:Nw \c_minus_one
+ \@@_parse_expand:w #1 \s_@@_mark
+ \s_@@_stop
+ }
+\cs_new:Npn \@@_parse_after:ww
+ #1@ \@@_parse_infix_end:N \s_@@_mark \s_@@_stop
+ { \c_zero #1 }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_parse_operand:Nw}
+% \begin{macro}[aux, EXP]{\@@_parse_continue:NwN}
+% The \cs{@@_parse_operand}
+% This is just a shorthand which sets up both \cs{@@_parse_continue}
+% and \cs{@@_parse_one} with the same precedence. Note the
+% trailing \cs{tex_romannumeral:D}. This function should be
+% used with much care.
% \begin{macrocode}
-\cs_new_eq:cN { @@_parse_prefix_+:Nw } \@@_parse_operand:Nw
+\cs_new:Npn \@@_parse_operand:Nw #1
+ {
+ -`0
+ \exp_after:wN \@@_parse_continue:NwN
+ \exp_after:wN #1
+ \tex_romannumeral:D -`0
+ \exp_after:wN \@@_parse_one:Nw
+ \exp_after:wN #1
+ \tex_romannumeral:D
+ }
+\cs_new:Npn \@@_parse_continue:NwN #1 #2 @ #3 { #3 #1 #2 @ }
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
-% \begin{macro}[EXP, aux]{\@@_parse_prefix_-:Nw, \@@_parse_prefix_!:Nw}
-% Unary |-| is harder.
-% Boolean not.
+% \begin{macro}[aux, EXP]{\@@_parse_apply_binary:NwNwN}
+% Receives \meta{precedence} \meta{operand_1} |@| \meta{operation}
+% \meta{operand_2} |@| \meta{infix command}. Builds the appropriate
+% call to the \meta{operation}~|#3|.
% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1#2
+\cs_new:Npn \@@_parse_apply_binary:NwNwN #1 #2@ #3 #4@ #5
{
- \cs_new:cpn { @@_parse_prefix_#1:Nw } ##1
- {
- \exp_after:wN \@@_parse_apply_unary:NNwN
- \exp_after:wN ##1
- \cs:w @@_ #2 \exp_after:wN \@@_parse_unary_type:N
- \tex_romannumeral:D
- \if_int_compare:w \c_twelve < ##1
- \@@_parse_until:Nw ##1
- \else:
- \@@_parse_until:Nw \c_twelve
- \fi:
- \@@_parse_expand:w
- }
+ \exp_after:wN \@@_parse_continue:NwN
+ \exp_after:wN #1
+ \tex_romannumeral:D -`0 \cs:w @@_#3_o:ww \cs_end: #2 #4
+ \tex_romannumeral:D -`0 #5 #1
}
-\@@_tmp:w - { - }
-\@@_tmp:w ! { ! }
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{Other prefixes}
+% \subsection{Infix operators}
%
-% \begin{macro}[int]{\@@_parse_prefix_(:Nw}
+% \begin{macro}[aux, EXP]{\@@_parse_infix_after_operand:NwN}
% \begin{macrocode}
+\cs_new:Npn \@@_parse_infix_after_operand:NwN #1 #2;
+ {
+ \@@_exp_after_f:nw { \@@_parse_infix:NN #1 }
+ #2;
+ }
\group_begin:
- \char_set_catcode_letter:N \)
- \cs_new:cpn { @@_parse_prefix_(:Nw } #1
+ \char_set_catcode_letter:N \*
+ \cs_new:Npn \@@_parse_infix:NN #1 #2
{
- \exp_after:wN \@@_parse_lparen_after:NwN
- \exp_after:wN #1
- \tex_romannumeral:D
- \if_int_compare:w #1 = \c_sixteen
- \@@_parse_until:Nw \c_one
+ \if_catcode:w \scan_stop: \exp_not:N #2
+ \if_int_compare:w
+ \pdftex_strcmp:D { \s_@@_mark } { \exp_not:N #2 }
+ = \c_zero
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \@@_parse_infix_end:N
+ \else:
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \@@_parse_infix_juxtapose:N
+ \fi:
\else:
- \@@_parse_until:Nw \c_zero
+ \if_int_compare:w
+ \__int_eval:w
+ ( `#2 \if_int_compare:w `#2 > `Z - \c_thirty_two \fi: )
+ / 26
+ = \c_three
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \@@_parse_infix_juxtapose:N
+ \else:
+ \exp_after:wN \@@_parse_infix_check:NNN
+ \cs:w
+ @@_parse_infix_#2:N
+ \exp_after:wN \exp_after:wN \exp_after:wN
+ \cs_end:
+ \fi:
\fi:
- \@@_parse_expand:w
+ #1
+ #2
}
- \cs_new:Npn \@@_parse_lparen_after:NwN #1#2@#3
+ \cs_new:Npn \@@_parse_infix_check:NNN #1#2#3
{
- \token_if_eq_meaning:NNTF #3 \@@_parse_infix_):N
- {
- \@@_exp_after_array_f:w #2 \s_@@_stop
- \exp_after:wN \@@_parse_infix:NN
- \exp_after:wN #1
- \tex_romannumeral:D \@@_parse_expand:w
- }
- {
- \__msg_kernel_expandable_error:nnn { kernel } { fp-missing } { ) }
- #2 @ \@@_parse_stop_until:N #3
- }
+ \if_meaning:w \scan_stop: #1
+ \__msg_kernel_expandable_error:nnn
+ { kernel } { fp-missing } { * }
+ \exp_after:wN \@@_parse_infix_*:N
+ \exp_after:wN #2
+ \exp_after:wN #3
+ \else:
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \tex_romannumeral:D \exp_after:wN \@@_parse_expand:w
+ \fi:
}
\group_end:
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int]{\@@_parse_prefix_.:Nw}
-% This function is called when a number starts with a dot.
+% \subsubsection{Closing parentheses and commas}
+%
+% \begin{macro}[aux, EXP]{\@@_parse_infix_end:N}
+% This one is a little bit odd: force every previous operator to end,
+% regardless of the precedence.
% \begin{macrocode}
-\cs_new:cpn {@@_parse_prefix_.:Nw} #1
- {
- \exp_after:wN \@@_parse_infix_after_operand:NwN
- \exp_after:wN #1
- \tex_romannumeral:D -`0
- \exp_after:wN \@@_sanitize:wN
- \int_use:N \__int_eval:w \c_zero \@@_parse_strim_zeros:N
- }
+\cs_new:Npn \@@_parse_infix_end:N #1
+ { @ \use_none:n \@@_parse_infix_end:N }
% \end{macrocode}
% \end{macro}
%
-% \subsection{Infix operators}
+% \begin{macro}[aux, EXP]+\@@_parse_infix_):N+
+% This is very similar to \cs{@@_parse_infix_end:N}, complaining about
+% an extra closing parenthesis if the previous operator was the
+% beginning of the expression.
+% \begin{macrocode}
+\group_begin:
+ \char_set_catcode_letter:N \)
+ \cs_new:Npn \@@_parse_infix_):N #1
+ {
+ \if_int_compare:w #1 < \c_zero
+ \__msg_kernel_expandable_error:nnn { kernel } { fp-extra } { ) }
+ \exp_after:wN \@@_parse_infix:NN
+ \exp_after:wN #1
+ \tex_romannumeral:D \exp_after:wN \@@_parse_expand:w
+ \else:
+ \exp_after:wN @
+ \exp_after:wN \use_none:n
+ \exp_after:wN \@@_parse_infix_):N
+ \fi:
+ }
+\group_end:
+% \end{macrocode}
+% \end{macro}
%
-% As described in the \enquote{work plan}, each infix operator has an
-% associated \cs{infix} function, a computing function, and
-% precedence, given as arguments to \cs{@@_tmp:w}. The
-% latter two are only needed when defining the \cs{infix} function.
+% \begin{macro}[aux, EXP]+\@@_parse_infix_,:N+
% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1#2#3#4
- {
- \cs_new:Npn #1 ##1
- {
- \if_int_compare:w ##1 < #3
- \exp_after:wN @
- \exp_after:wN \@@_parse_apply_binary:NwNwN
- \exp_after:wN #2
+\group_begin:
+ \char_set_catcode_letter:N \,
+ \cs_new:Npn \@@_parse_infix_,:N #1
+ {
+ \if_int_compare:w #1 > \c_one
+ \exp_after:wN @
+ \exp_after:wN \use_none:n
+ \exp_after:wN \@@_parse_infix_,:N
+ \else:
+ \if_int_compare:w #1 = \c_one
+ \exp_after:wN \@@_parse_infix_comma:w
\tex_romannumeral:D
- \@@_parse_until:Nw #4
- \exp_after:wN \@@_parse_expand:w
\else:
- \exp_after:wN @
- \exp_after:wN \@@_parse_stop_until:N
- \exp_after:wN #1
+ \exp_after:wN \@@_parse_infix_comma_gobble:w
+ \tex_romannumeral:D
\fi:
- }
- }
+ \@@_parse_operand:Nw \c_one
+ \exp_after:wN \@@_parse_expand:w
+ \fi:
+ }
+ \cs_new:Npn \@@_parse_infix_comma:w #1 @
+ { #1 @ \use_none:n }
+ \cs_new:Npn \@@_parse_infix_comma_gobble:w #1 @
+ {
+ \__msg_kernel_expandable_error:nn { kernel } { fp-extra-comma }
+ @ \use_none:n
+ }
+\group_end:
% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Usual infix operators}
%
-% \begin{macro}[int, EXP]
+% \begin{macro}[aux, EXP]
% {
% \@@_parse_infix_+:N, \@@_parse_infix_-:N,
% \@@_parse_infix_/:N, \@@_parse_infix_mul:N,
% \@@_parse_infix_and:N, \@@_parse_infix_or:N,
% }
-% Using the general mechanism for arithmetic operations.
+% \begin{macro}[aux, EXP]+\@@_parse_infix_^:N+ As described in the
+% \enquote{work plan}, each infix operator has an associated
+% \cs{infix} function, a computing function, and precedence, given as
+% arguments to \cs{@@_tmp:w}. Using the general mechanism for
+% arithmetic operations. The power operation must be associative in
+% the opposite order from all others. For this, we use two distinct
+% precedences.
% \begin{macrocode}
\group_begin:
\char_set_catcode_other:N \&
- \@@_tmp:w \@@_parse_infix_juxtapose:N * \c_thirty_two \c_thirty_two
- \exp_args:Nc \@@_tmp:w { @@_parse_infix_ / :N } / \c_ten \c_ten
- \exp_args:Nc \@@_tmp:w { @@_parse_infix_mul:N } * \c_ten \c_ten
- \exp_args:Nc \@@_tmp:w { @@_parse_infix_ - :N } - \c_nine \c_nine
- \exp_args:Nc \@@_tmp:w { @@_parse_infix_ + :N } + \c_nine \c_nine
- \exp_args:Nc \@@_tmp:w { @@_parse_infix_and:N } & \c_five \c_five
- \exp_args:Nc \@@_tmp:w { @@_parse_infix_ or:N } | \c_four \c_four
+ \char_set_catcode_letter:N \^
+ \char_set_catcode_letter:N \/
+ \char_set_catcode_letter:N \-
+ \char_set_catcode_letter:N \+
+ \cs_set_protected:Npn \@@_tmp:w #1#2#3#4
+ {
+ \cs_new:Npn #1 ##1
+ {
+ \if_int_compare:w ##1 < #3
+ \exp_after:wN @
+ \exp_after:wN \@@_parse_apply_binary:NwNwN
+ \exp_after:wN #2
+ \tex_romannumeral:D
+ \@@_parse_operand:Nw #4
+ \exp_after:wN \@@_parse_expand:w
+ \else:
+ \exp_after:wN @
+ \exp_after:wN \use_none:n
+ \exp_after:wN #1
+ \fi:
+ }
+ }
+ \@@_tmp:w \@@_parse_infix_^:N ^ \c_fifteen \c_fourteen
+ \@@_tmp:w \@@_parse_infix_/:N / \c_ten \c_ten
+ \@@_tmp:w \@@_parse_infix_mul:N * \c_ten \c_ten
+ \@@_tmp:w \@@_parse_infix_-:N - \c_nine \c_nine
+ \@@_tmp:w \@@_parse_infix_+:N + \c_nine \c_nine
+ \@@_tmp:w \@@_parse_infix_and:N & \c_five \c_five
+ \@@_tmp:w \@@_parse_infix_or:N | \c_four \c_four
\group_end:
% \end{macrocode}
% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Juxtaposition}
+%
+% \begin{macro}[aux, EXP]+\@@_parse_infix_(:N+
+% When an opening parenthesis appears where we expect an infix
+% operator, we compute the product of the previous operand and the
+% contents of the parentheses using \cs{@@_parse_infix_juxtapose:N}.
+% \begin{macrocode}
+\cs_new:cpn { @@_parse_infix_(:N } #1
+ { \@@_parse_infix_juxtapose:N #1 ( }
+% \end{macrocode}
+% \end{macro}
%
-% \begin{macro}[int, EXP]{\@@_parse_infix_*:N}
-% \begin{macro}[int, EXP]+\@@_parse_infix_^:N+
-% The power operation must be associative in the opposite order from
-% all others. For this, we reverse the test, hence treating a
-% \enquote{previous precedence} of \cs{c_fourteen} as less binding
-% than |^|.
+% \begin{macro}[aux, EXP]
+% {\@@_parse_infix_juxtapose:N, \@@_parse_apply_juxtapose:NwwN}
+% Juxtaposition follows the same scheme as other binary operations,
+% but calls \cs{@@_parse_apply_juxtapose:NwwN} rather than directly
+% calling \cs{@@_parse_apply_binary:NwNwN}. This lets us catch errors
+% such as |max(1,2,3)pt| where one operand of the juxtaposition is not
+% a single number: both |#3| and~|#5| of the \texttt{apply} auxiliary
+% must be empty.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_infix_juxtapose:N #1
+ {
+ \if_int_compare:w #1 < \c_thirty_two
+ \exp_after:wN @
+ \exp_after:wN \@@_parse_apply_juxtapose:NwwN
+ \tex_romannumeral:D
+ \@@_parse_operand:Nw \c_thirty_two
+ \exp_after:wN \@@_parse_expand:w
+ \else:
+ \exp_after:wN @
+ \exp_after:wN \use_none:n
+ \exp_after:wN \@@_parse_infix_juxtapose:N
+ \fi:
+ }
+\cs_new:Npn \@@_parse_apply_juxtapose:NwwN #1 #2;#3@ #4;#5@
+ {
+ \if_catcode:w ^ \tl_to_str:n { #3 #5 } ^
+ \else:
+ \@@_error:nffn { invalid-ii }
+ { \@@_array_to_clist:n { #2; #3 } }
+ { \@@_array_to_clist:n { #4; #5 } }
+ { }
+ \fi:
+ \@@_parse_apply_binary:NwNwN #1 #2;@ * #4;@
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Multi-character cases}
+%
+% \begin{macro}[aux, EXP]{\@@_parse_infix_*:N}
% \begin{macrocode}
\group_begin:
\char_set_catcode_letter:N ^
- \@@_tmp:w \@@_parse_infix_^:N ^ \c_fifteen \c_fourteen
\cs_new:cpn { @@_parse_infix_*:N } #1#2
{
- \if:w * #2
+ \if:w * \exp_not:N #2
\exp_after:wN \@@_parse_infix_^:N
\exp_after:wN #1
\else:
@@ -2344,17 +2343,16 @@
\group_end:
% \end{macrocode}
% \end{macro}
-% \end{macro}
%
-% \begin{macro}[int, EXP]+\@@_parse_infix_|:Nw+
-% \begin{macro}[int, EXP]+\@@_parse_infix_&:Nw+
+% \begin{macro}[aux, EXP]+\@@_parse_infix_|:Nw+
+% \begin{macro}[aux, EXP]+\@@_parse_infix_&:Nw+
% \begin{macrocode}
\group_begin:
\char_set_catcode_letter:N \|
\char_set_catcode_letter:N \&
\cs_new:Npn \@@_parse_infix_|:N #1#2
{
- \if:w | #2
+ \if:w | \exp_not:N #2
\exp_after:wN \@@_parse_infix_|:N
\exp_after:wN #1
\tex_romannumeral:D \exp_after:wN \@@_parse_expand:w
@@ -2366,7 +2364,7 @@
}
\cs_new:Npn \@@_parse_infix_&:N #1#2
{
- \if:w & #2
+ \if:w & \exp_not:N #2
\exp_after:wN \@@_parse_infix_&:N
\exp_after:wN #1
\tex_romannumeral:D \exp_after:wN \@@_parse_expand:w
@@ -2381,7 +2379,49 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}[int, EXP]
+% \subsubsection{Ternary operator}
+%
+% \begin{macro}[aux, EXP]{\@@_parse_infix_?:N, \@@_parse_infix_::N}
+% \begin{macrocode}
+\group_begin:
+ \char_set_catcode_letter:N \?
+ \cs_new:Npn \@@_parse_infix_?:N #1
+ {
+ \if_int_compare:w #1 < \c_three
+ \exp_after:wN @
+ \exp_after:wN \@@_ternary:NwwN
+ \tex_romannumeral:D
+ \@@_parse_operand:Nw \c_three
+ \exp_after:wN \@@_parse_expand:w
+ \else:
+ \exp_after:wN @
+ \exp_after:wN \use_none:n
+ \exp_after:wN \@@_parse_infix_?:N
+ \fi:
+ }
+ \cs_new:Npn \@@_parse_infix_::N #1
+ {
+ \if_int_compare:w #1 < \c_three
+ \__msg_kernel_expandable_error:nnnn
+ { kernel } { fp-missing } { ? } { ~for~?: }
+ \exp_after:wN @
+ \exp_after:wN \@@_ternary_auxii:NwwN
+ \tex_romannumeral:D
+ \@@_parse_operand:Nw \c_two
+ \exp_after:wN \@@_parse_expand:w
+ \else:
+ \exp_after:wN @
+ \exp_after:wN \use_none:n
+ \exp_after:wN \@@_parse_infix_::N
+ \fi:
+ }
+\group_end:
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Comparisons}
+%
+% \begin{macro}[aux, EXP]
% {
% \@@_parse_infix_<:N, \@@_parse_infix_=:N,
% \@@_parse_infix_>:N, \@@_parse_infix_!:N
@@ -2434,14 +2474,14 @@
\exp_after:wN \@@_parse_infix_excl_error:
\else:
\exp_after:wN @
- \exp_after:wN \@@_parse_stop_until:N
+ \exp_after:wN \use_none:n
\exp_after:wN \@@_infix_compare:N
\fi:
}
\cs_new:Npn \@@_parse_compare:NNNNNNw #1#2#3#4#5#6#7
{
\if_case:w
- \if_catcode:w \tex_relax:D #7
+ \if_catcode:w \scan_stop: #7
\c_minus_one
\else:
\__int_eval:w `#7 - `< \__int_eval_end:
@@ -2474,11 +2514,11 @@
\exp_after:wN #3
\exp_after:wN #4
\tex_romannumeral:D
- \@@_parse_until:Nw \c_seven \@@_parse_expand:w #5
+ \@@_parse_operand:Nw \c_seven \@@_parse_expand:w #5
}
\cs_new:Npn \@@_parse_apply_compare:NwNNNNwN #1 #2@ #3#4#5#6 #7@ #8
{
- \exp_after:wN \@@_parse_until_test:NwN
+ \exp_after:wN \@@_parse_continue:NwN
\exp_after:wN #1
\tex_romannumeral:D -`0
\exp_after:wN \exp_after:wN
@@ -2496,104 +2536,9 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_parse_infix_?:N, \@@_parse_infix_::N}
-% \begin{macrocode}
-\group_begin:
- \char_set_catcode_letter:N \?
- \cs_new:Npn \@@_parse_infix_?:N #1
- {
- \if_int_compare:w #1 < \c_three
- \exp_after:wN @
- \exp_after:wN \@@_ternary:NwwN
- \tex_romannumeral:D
- \@@_parse_until:Nw \c_three
- \exp_after:wN \@@_parse_expand:w
- \else:
- \exp_after:wN @
- \exp_after:wN \@@_parse_stop_until:N
- \exp_after:wN \@@_parse_infix_?:N
- \fi:
- }
- \cs_new:Npn \@@_parse_infix_::N #1
- {
- \if_int_compare:w #1 < \c_three
- \__msg_kernel_expandable_error:nnnn
- { kernel } { fp-missing } { ? } { ~for~?: }
- \exp_after:wN @
- \exp_after:wN \@@_ternary_auxii:NwwN
- \tex_romannumeral:D
- \@@_parse_until:Nw \c_two
- \exp_after:wN \@@_parse_expand:w
- \else:
- \exp_after:wN @
- \exp_after:wN \@@_parse_stop_until:N
- \exp_after:wN \@@_parse_infix_::N
- \fi:
- }
-\group_end:
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[int, EXP]+\@@_parse_infix_):N+
-% This one is a little bit odd: force every previous operator to end,
-% regardless of the precedence. This is very similar to
-% \cs{@@_parse_infix_end:N}.
-% \begin{macrocode}
-\group_begin:
- \char_set_catcode_letter:N \)
- \cs_new:Npn \@@_parse_infix_):N #1
- {
- \if_int_compare:w #1 < \c_zero
- \__msg_kernel_expandable_error:nnn { kernel } { fp-extra } { ) }
- \exp_after:wN \@@_parse_infix:NN
- \exp_after:wN #1
- \tex_romannumeral:D \exp_after:wN \@@_parse_expand:w
- \else:
- \exp_after:wN @
- \exp_after:wN \@@_parse_stop_until:N
- \exp_after:wN \@@_parse_infix_):N
- \fi:
- }
-\group_end:
-\cs_new:Npn \@@_parse_infix_end:N #1
- { @ \@@_parse_stop_until:N \@@_parse_infix_end:N }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[int, EXP]+\@@_parse_infix_,:N+
-% \begin{macrocode}
-\group_begin:
- \char_set_catcode_letter:N \,
- \cs_new:Npn \@@_parse_infix_,:N #1
- {
- \if_int_compare:w #1 > \c_one
- \exp_after:wN @
- \exp_after:wN \@@_parse_stop_until:N
- \exp_after:wN \@@_parse_infix_,:N
- \else:
- \if_int_compare:w #1 = \c_one
- \exp_after:wN \@@_parse_infix_comma:w
- \tex_romannumeral:D
- \else:
- \exp_after:wN \@@_parse_infix_comma_gobble:w
- \tex_romannumeral:D
- \fi:
- \@@_parse_until:Nw \c_one
- \exp_after:wN \@@_parse_expand:w
- \fi:
- }
- \cs_new:Npn \@@_parse_infix_comma:w #1 @
- { #1 @ \@@_parse_stop_until:N }
- \cs_new:Npn \@@_parse_infix_comma_gobble:w #1 @
- {
- \__msg_kernel_expandable_error:nn { kernel } { fp-extra-comma }
- @ \@@_parse_stop_until:N
- }
-\group_end:
-% \end{macrocode}
-% \end{macro}
+% ^^A end[todo]
%
-% \section{Messages}
+% \subsection{Messages}
%
% \begin{macrocode}
\__msg_kernel_new:nnn { kernel } { unknown-fp-word }
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx
index 1e00baa38da..2a989ffcdf8 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%%
-%% File: l3fp-traps.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-traps.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -36,7 +36,7 @@
%
%<*driver>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3fp-traps.dtx 4428 2013-01-10 13:23:29Z bruno $
+\GetIdInfo$Id: l3fp-traps.dtx 4598 2013-11-02 14:26:32Z bruno $
{L3 Floating-point exception trapping}
\documentclass[full]{l3doc}
\begin{document}
@@ -369,12 +369,13 @@
% \end{macro}
%
% \begin{macro}[int, EXP]
-% {\@@_invalid_operation_o:nw}
+% {\@@_invalid_operation_o:nw, \@@_invalid_operation_o:fw}
% Convenient short-hands for returning \cs{c_nan_fp} for a unary or
% binary operation, and expanding after.
% \begin{macrocode}
\cs_new_nopar:Npn \@@_invalid_operation_o:nw
{ \@@_invalid_operation:nnw { \exp_after:wN \c_nan_fp } }
+\cs_generate_variant:Nn \@@_invalid_operation_o:nw { f }
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx
index 34f0a220acd..0fea2b00541 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3fp-trig.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-trig.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -36,7 +36,7 @@
%
%<*driver>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3fp-trig.dtx 4593 2013-10-07 13:32:35Z bruno $
+\GetIdInfo$Id: l3fp-trig.dtx 4607 2013-11-19 08:35:08Z joseph $
{L3 Floating-point trigonometric functions}
\documentclass[full]{l3doc}
\begin{document}
@@ -67,7 +67,7 @@
%
% \begin{implementation}
%
-% \section{Implementation}
+% \section{\pkg{l3fp-trig} Implementation}
%
% \begin{macrocode}
%<*initex|package>
@@ -82,51 +82,58 @@
% \subsection{Direct trigonometric functions}
%
% The approach for all trigonometric functions (sine, cosine, tangent,
-% cotangent, cosecant, and secant) is the same.
+% cotangent, cosecant, and secant), with arguments given in radians or
+% in degrees, is the same.
% \begin{itemize}
% \item Filter out special cases ($\pm 0$, $\pm\inf$ and \nan{}).
% \item Keep the sign for later, and work with the absolute value
-% $|x|$ of the argument.
-% \item For numbers less than $1$, shift the significand to convert them
-% to fixed point numbers. Very small numbers take a slightly
-% different route.
-% \item For numbers $\geq 1$, subtract a multiple of $\pi/2$ to bring
-% them to the range to $[0, \pi/2]$. (This is called argument
-% reduction.)
-% \item Reduce further to $[0, \pi/4]$ using $\sin x = \cos
-% (\pi/2-x)$.
+% $\lvert x\rvert$ of the argument.
+% \item Small numbers ($\lvert x\rvert<1$ in radians, $\lvert
+% x\rvert<10$ in degrees) are converted to fixed point numbers (and
+% to radians if $\lvert x\rvert$ is in degrees).
+% \item For larger numbers, we need argument reduction. Subtract a
+% multiple of $\pi/2$ (in degrees,~$90$) to bring the number to the
+% range to $[0, \pi/2)$ (in degrees, $[0,90)$).
+% \item Reduce further to $[0, \pi/4]$ (in degrees, $[0,45]$) using
+% $\sin x = \cos (\pi/2-x)$, and when working in degrees, convert to
+% radians.
% \item Use the appropriate power series depending on the octant
-% $\lfloor\frac{|x|}{\pi/4}\rfloor \mod 8$, the sign, and the
-% function to compute.
+% $\lfloor\frac{|x|}{\pi/4}\rfloor \mod 8$ (in degrees, the same
+% formula with $\pi/4\to 45$), the sign, and the function to
+% compute.
% \end{itemize}
%
-% \subsubsection{Sign and special numbers}
+% \subsubsection{Filtering special cases}
%
% \begin{macro}[int, EXP]{\@@_sin_o:w}
-% The sine of $\pm 0$ or \nan{} is the same floating point number.
-% The sine of $\pm\infty$ raises an invalid operation exception.
-% Otherwise, \cs{@@_trig_exponent:NNNNNwn} checks the exponent: if the
-% number is tiny, use \cs{@@_trig_epsilon_o:w} which returns
-% $\sin\epsilon = \epsilon$. For larger inputs, use the series
-% \cs{@@_sin_series:NNwww} after argument reduction. In this second
-% case, we will use a sign~|#2|, an initial octant of~$0$, and convert
-% the result of the series to a floating point directly, since
-% $\sin(x) = \#2 \sin\lvert x\rvert$.
-% \begin{macrocode}
-\cs_new:Npn \@@_sin_o:w \s_@@ \@@_chk:w #1#2
- {
- \if_case:w #1 \exp_stop_f:
+% This function, and its analogs for \texttt{cos}, \texttt{csc},
+% \texttt{sec}, \texttt{tan}, and \texttt{cot} instead of
+% \texttt{sin}, are followed either by \cs{use_i:nn} and a float in
+% radians or by \cs{use_ii:nn} and a float in degrees. The sine of
+% $\pm 0$ or \nan{} is the same float. The sine of $\pm\infty$ raises
+% an invalid operation exception with the appropriate function name.
+% Otherwise, call the \texttt{trig} function to perform argument
+% reduction and if necessary convert the reduced argument to radians.
+% Then, \cs{@@_sin_series_o:NNwwww} will be called to compute the
+% Taylor series: this function receives a sign~|#3|, an initial octant
+% of~$0$, and the function \cs{@@_ep_to_float:wwN} which converts the
+% result of the series to a floating point directly rather than taking
+% its inverse, since $\sin(x) = \#3 \sin\lvert x\rvert$.
+% \begin{macrocode}
+\cs_new:Npn \@@_sin_o:w #1 \s_@@ \@@_chk:w #2#3#4; @
+ {
+ \if_case:w #2 \exp_stop_f:
\@@_case_return_same_o:w
- \or:
- \@@_case_use:nw
- {
- \@@_trig_exponent:NNNNNwn \@@_trig_epsilon_o:w
- \@@_sin_series:NNwww \@@_fixed_to_float:wN #2 \c_zero
- }
- \or: \@@_case_use:nw { \@@_invalid_operation_o:nw { sin } }
+ \or: \@@_case_use:nw
+ {
+ \@@_trig:NNNNNwn #1 \@@_sin_series_o:NNwwww
+ \@@_ep_to_float:wwN #3 \c_zero
+ }
+ \or: \@@_case_use:nw
+ { \@@_invalid_operation_o:fw { #1 { sin } { sind } } }
\else: \@@_case_return_same_o:w
\fi:
- \s_@@ \@@_chk:w #1#2
+ \s_@@ \@@_chk:w #2 #3 #4;
}
% \end{macrocode}
% \end{macro}
@@ -134,56 +141,56 @@
% \begin{macro}[int, EXP]{\@@_cos_o:w}
% The cosine of $\pm 0$ is $1$. The cosine of $\pm\infty$ raises an
% invalid operation exception. The cosine of \nan{} is itself.
-% Otherwise, \cs{@@_trig_exponent:NNNNNwn} checks the exponent: if the
-% number is tiny, use \cs{@@_trig_epsilon_one_o:w} which returns
-% $\cos\epsilon = 1$. For larger inputs, use the same series as for
-% sine, but using a positive sign~|0| and with an initial octant
+% Otherwise, the \texttt{trig} function reduces the argument to at
+% most half a right-angle and converts if necessary to radians. We
+% will then call the same series as for sine, but using a positive
+% sign~|0| regardless of the sign of~$x$, and with an initial octant
% of~$2$, because $\cos(x) = + \sin(\pi/2 + \lvert x\rvert)$.
% \begin{macrocode}
-\cs_new:Npn \@@_cos_o:w \s_@@ \@@_chk:w #1#2
+\cs_new:Npn \@@_cos_o:w #1 \s_@@ \@@_chk:w #2#3; @
{
- \if_case:w #1 \exp_stop_f:
+ \if_case:w #2 \exp_stop_f:
\@@_case_return_o:Nw \c_one_fp
- \or:
- \@@_case_use:nw
- {
- \@@_trig_exponent:NNNNNwn \@@_trig_epsilon_one_o:w
- \@@_sin_series:NNwww \@@_fixed_to_float:wN 0 \c_two
- }
- \or: \@@_case_use:nw { \@@_invalid_operation_o:nw { cos } }
+ \or: \@@_case_use:nw
+ {
+ \@@_trig:NNNNNwn #1 \@@_sin_series_o:NNwwww
+ \@@_ep_to_float:wwN 0 \c_two
+ }
+ \or: \@@_case_use:nw
+ { \@@_invalid_operation_o:fw { #1 { cos } { cosd } } }
\else: \@@_case_return_same_o:w
\fi:
- \s_@@ \@@_chk:w #1#2
+ \s_@@ \@@_chk:w #2 #3;
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[int, EXP]{\@@_csc_o:w}
% The cosecant of $\pm 0$ is $\pm \infty$ with the same sign, with a
-% division by zero exception (see \cs{@@_cot_zero_o:Nnw} defined
-% below). The cosecant of $\pm\infty$ raises an invalid operation
-% exception. The cosecant of \nan{} is itself. Otherwise,
-% \cs{@@_trig_exponent:NNNNNwn} checks the exponent: if the number is
-% tiny, use \cs{@@_trig_epsilon_inv_o:w} which returns $\csc\epsilon =
-% 1/\epsilon$. For larger inputs, use the same series as for sine,
-% using the sign~|#2|, a starting octant of~$0$, and inverting during
-% the conversion from the fixed point sine to the floating point
-% result, because $\csc(x) = \#2 \big( \sin\lvert x\rvert\big)^{-1}$.
-% \begin{macrocode}
-\cs_new:Npn \@@_csc_o:w \s_@@ \@@_chk:w #1#2
- {
- \if_case:w #1 \exp_stop_f:
- \@@_cot_zero_o:Nnw #2 { csc }
- \or:
- \@@_case_use:nw
- {
- \@@_trig_exponent:NNNNNwn \@@_trig_epsilon_inv_o:w
- \@@_sin_series:NNwww \@@_fixed_inv_to_float:wN #2 \c_zero
- }
- \or: \@@_case_use:nw { \@@_invalid_operation_o:nw { csc } }
+% division by zero exception (see \cs{@@_cot_zero_o:Nfw} defined
+% below), which requires the function name. The cosecant of
+% $\pm\infty$ raises an invalid operation exception. The cosecant of
+% \nan{} is itself. Otherwise, the \texttt{trig} function performs
+% the argument reduction, and converts if necessary to radians before
+% calling the same series as for sine, using the sign~|#3|, a starting
+% octant of~$0$, and inverting during the conversion from the fixed
+% point sine to the floating point result, because $\csc(x) = \#3
+% \big( \sin\lvert x\rvert\big)^{-1}$.
+% \begin{macrocode}
+\cs_new:Npn \@@_csc_o:w #1 \s_@@ \@@_chk:w #2#3#4; @
+ {
+ \if_case:w #2 \exp_stop_f:
+ \@@_cot_zero_o:Nfw #3 { #1 { csc } { cscd } }
+ \or: \@@_case_use:nw
+ {
+ \@@_trig:NNNNNwn #1 \@@_sin_series_o:NNwwww
+ \@@_ep_inv_to_float:wwN #3 \c_zero
+ }
+ \or: \@@_case_use:nw
+ { \@@_invalid_operation_o:fw { #1 { csc } { cscd } } }
\else: \@@_case_return_same_o:w
\fi:
- \s_@@ \@@_chk:w #1#2
+ \s_@@ \@@_chk:w #2 #3 #4;
}
% \end{macrocode}
% \end{macro}
@@ -191,27 +198,25 @@
% \begin{macro}[int, EXP]{\@@_sec_o:w}
% The secant of $\pm 0$ is $1$. The secant of $\pm \infty$ raises an
% invalid operation exception. The secant of \nan{} is itself.
-% Otherwise, \cs{@@_trig_exponent:NNNNNwn} checks the exponent: if the
-% number is tiny, use \cs{@@_trig_epsilon_one_o:w} which returns
-% $\sec\epsilon = 1$. For larger inputs, use the same series as for
-% sine, using a positive sign~$0$, a starting octant of~$2$, and
-% inverting upon conversion, because $\sec(x) = + 1 / \sin(\pi/2 +
-% \lvert x\rvert)$.
+% Otherwise, the \texttt{trig} function reduces the argument and turns
+% it to radians before calling the same series as for sine, using a
+% positive sign~$0$, a starting octant of~$2$, and inverting upon
+% conversion, because $\sec(x) = + 1 / \sin(\pi/2 + \lvert x\rvert)$.
% \begin{macrocode}
-\cs_new:Npn \@@_sec_o:w \s_@@ \@@_chk:w #1#2
+\cs_new:Npn \@@_sec_o:w #1 \s_@@ \@@_chk:w #2#3; @
{
- \if_case:w #1 \exp_stop_f:
+ \if_case:w #2 \exp_stop_f:
\@@_case_return_o:Nw \c_one_fp
- \or:
- \@@_case_use:nw
- {
- \@@_trig_exponent:NNNNNwn \@@_trig_epsilon_one_o:w
- \@@_sin_series:NNwww \@@_fixed_inv_to_float:wN 0 \c_two
- }
- \or: \@@_case_use:nw { \@@_invalid_operation_o:nw { sec } }
+ \or: \@@_case_use:nw
+ {
+ \@@_trig:NNNNNwn #1 \@@_sin_series_o:NNwwww
+ \@@_ep_inv_to_float:wwN 0 \c_two
+ }
+ \or: \@@_case_use:nw
+ { \@@_invalid_operation_o:fw { #1 { sec } { secd } } }
\else: \@@_case_return_same_o:w
\fi:
- \s_@@ \@@_chk:w #1#2
+ \s_@@ \@@_chk:w #2 #3;
}
% \end{macrocode}
% \end{macro}
@@ -219,263 +224,606 @@
% \begin{macro}[int, EXP]{\@@_tan_o:w}
% The tangent of $\pm 0$ or \nan{} is the same floating point number.
% The tangent of $\pm\infty$ raises an invalid operation exception.
-% Otherwise, \cs{@@_trig_exponent:NNNNNwn} checks the exponent: if the
-% number is tiny, use \cs{@@_trig_epsilon_o:w} which returns
-% $\tan\epsilon = \epsilon$. For larger inputs, use
-% \cs{@@_tan_series_o:NNwww} for the calculation after argument
-% reduction, with a sign~|#2| and an initial octant of~$1$ (this shift
-% is somewhat arbitrary). See \cs{@@_cot_o:w} for an explanation of
-% the $0$~argument.
+% Once more, the \texttt{trig} function does the argument reduction
+% step and conversion to radians before calling
+% \cs{@@_tan_series_o:NNwwww}, with a sign~|#3| and an initial octant
+% of~$1$ (this shift is somewhat arbitrary). See \cs{@@_cot_o:w} for
+% an explanation of the $0$~argument.
% \begin{macrocode}
-\cs_new:Npn \@@_tan_o:w \s_@@ \@@_chk:w #1#2
+\cs_new:Npn \@@_tan_o:w #1 \s_@@ \@@_chk:w #2#3#4; @
{
- \if_case:w #1 \exp_stop_f:
+ \if_case:w #2 \exp_stop_f:
\@@_case_return_same_o:w
- \or:
- \@@_case_use:nw
- {
- \@@_trig_exponent:NNNNNwn \@@_trig_epsilon_o:w
- \@@_tan_series_o:NNwww 0 #2 \c_one
- }
- \or: \@@_case_use:nw { \@@_invalid_operation_o:nw { tan } }
+ \or: \@@_case_use:nw
+ {
+ \@@_trig:NNNNNwn #1
+ \@@_tan_series_o:NNwwww 0 #3 \c_one
+ }
+ \or: \@@_case_use:nw
+ { \@@_invalid_operation_o:fw { #1 { tan } { tand } } }
\else: \@@_case_return_same_o:w
\fi:
- \s_@@ \@@_chk:w #1#2
+ \s_@@ \@@_chk:w #2 #3 #4;
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[int, EXP]{\@@_cot_o:w}
-% \begin{macro}[aux, EXP]{\@@_cot_zero_o:Nnw}
+% \begin{macro}[aux, EXP]{\@@_cot_zero_o:Nfw}
% The cotangent of $\pm 0$ is $\pm \infty$ with the same sign, with a
-% division by zero exception (see \cs{@@_cot_zero_o:Nnw}. The
+% division by zero exception (see \cs{@@_cot_zero_o:Nfw}. The
% cotangent of $\pm\infty$ raises an invalid operation exception. The
% cotangent of \nan{} is itself. We use $\cot x = - \tan (\pi/2 +
% x)$, and the initial octant for the tangent was chosen to be $1$, so
% the octant here starts at $3$. The change in sign is obtained by
-% feeding \cs{@@_tan_series_o:NNwww} two signs rather than just the sign
-% of the argument: the first of those indicates whether we compute
-% tangent or cotangent. Those signs are eventually combined.
+% feeding \cs{@@_tan_series_o:NNwwww} two signs rather than just the
+% sign of the argument: the first of those indicates whether we
+% compute tangent or cotangent. Those signs are eventually combined.
% \begin{macrocode}
-\cs_new:Npn \@@_cot_o:w \s_@@ \@@_chk:w #1#2
+\cs_new:Npn \@@_cot_o:w #1 \s_@@ \@@_chk:w #2#3#4; @
{
- \if_case:w #1 \exp_stop_f:
- \@@_cot_zero_o:Nnw #2 { cot }
- \or:
- \@@_case_use:nw
- {
- \@@_trig_exponent:NNNNNwn \@@_trig_epsilon_inv_o:w
- \@@_tan_series_o:NNwww 2 #2 \c_three
- }
- \or: \@@_case_use:nw { \@@_invalid_operation_o:nw { cot } }
+ \if_case:w #2 \exp_stop_f:
+ \@@_cot_zero_o:Nfw #3 { #1 { cot } { cotd } }
+ \or: \@@_case_use:nw
+ {
+ \@@_trig:NNNNNwn #1
+ \@@_tan_series_o:NNwwww 2 #3 \c_three
+ }
+ \or: \@@_case_use:nw
+ { \@@_invalid_operation_o:fw { #1 { cot } { cotd } } }
\else: \@@_case_return_same_o:w
\fi:
- \s_@@ \@@_chk:w #1#2
+ \s_@@ \@@_chk:w #2 #3 #4;
}
-\cs_new:Npn \@@_cot_zero_o:Nnw #1 #2 #3 \fi:
+\cs_new:Npn \@@_cot_zero_o:Nfw #1#2#3 \fi:
{
\fi:
- \if_meaning:w 0 #1
- \exp_after:wN \@@_division_by_zero_o:Nnw \exp_after:wN \c_inf_fp
- \else:
- \exp_after:wN \@@_division_by_zero_o:Nnw \exp_after:wN \c_minus_inf_fp
- \fi:
+ \token_if_eq_meaning:NNTF 0 #1
+ { \exp_args:NNf \@@_division_by_zero_o:Nnw \c_inf_fp }
+ { \exp_args:NNf \@@_division_by_zero_o:Nnw \c_minus_inf_fp }
{#2}
}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \subsubsection{Small and tiny arguments}
+% \subsubsection{Distinguishing small and large arguments}
%
-% \begin{macro}[aux, EXP]{\@@_trig_exponent:NNNNNwn}
-% The first five arguments control what trigonometric function we
-% compute, then follows a normal floating point number. If the
-% floating point is smaller than $10^{-8}$, then call the
-% \texttt{_epsilon} auxiliary~|#1|. Otherwise, call the function
-% |#2|, with arguments |#3|; |#4|; the octant, computed in an integer
-% expression starting with |#5| and stopped by a period; and a fixed
-% point number obtained from the floating point number by argument
-% reduction. Argument reduction leaves a shift into the integer
-% expression for the octant. Numbers less than~$1$ are converted
-% using \cs{@@_trig_small:w} which simply shifts the significand, while
-% large numbers need argument reduction.
+% \begin{macro}[aux, EXP]{\@@_trig:NNNNNwn}
+% The first argument is \cs{use_i:nn} if the operand is in radians and
+% \cs{use_ii:nn} if it is in degrees. Arguments |#2| to~|#5| control
+% what trigonometric function we compute, and |#6| to~|#8| are pieces
+% of a normal floating point number. Call the \texttt{_series}
+% function~|#2|, with arguments |#3|, either a conversion function
+% (\cs{@@_ep_to_float:wN} or \cs{@@_ep_inv_to_float:wN}) or a sign $0$
+% or~$2$ when computing tangent or cotangent; |#4|, a sign $0$ or~$2$;
+% the octant, computed in an integer expression starting with~|#5| and
+% stopped by a period; and a fixed point number obtained from the
+% floating point number by argument reduction (if necessary) and
+% conversion to radians (if necessary). Any argument reduction
+% adjusts the octant accordingly by leaving a (positive) shift into
+% its integer expression. Let us explain the integer comparison. Two
+% of the four \cs{exp_after:wN} are expanded, the expansion hits the
+% test, which is true if the float is at least~$1$ when working in
+% radians, and at least $10$ when working in degrees. Then one of the
+% remaining \cs{exp_after:wN} hits |#1|, which picks the \texttt{trig}
+% or \texttt{trigd} function in whichever branch of the conditional
+% was taken. The final \cs{exp_after:wN} closes the conditional. At
+% the end of the day, a number is \texttt{large} if it is $\geq 1$ in
+% radians or $\geq 10$ in degrees, and \texttt{small} otherwise. All
+% four \texttt{trig}/\texttt{trigd} auxiliaries receive the operand as
+% an extended-precision number.
% \begin{macrocode}
-\cs_new:Npn \@@_trig_exponent:NNNNNwn #1#2#3#4#5 \s_@@ \@@_chk:w 1#6#7
+\cs_new:Npn \@@_trig:NNNNNwn #1#2#3#4#5 \s_@@ \@@_chk:w 1#6#7#8;
{
- \if_int_compare:w #7 > - \c_eight
- \exp_after:wN #2
- \exp_after:wN #3
- \exp_after:wN #4
- \int_use:N \__int_eval:w #5
- \if_int_compare:w #7 > \c_zero
- \exp_after:wN \@@_trig_large:ww \__int_value:w
- \else:
- \exp_after:wN \@@_trig_small:ww \__int_value:w
- \fi:
- \else:
- \exp_after:wN #1
- \exp_after:wN #6
- \fi:
- #7 ;
+ \exp_after:wN #2
+ \exp_after:wN #3
+ \exp_after:wN #4
+ \int_use:N \__int_eval:w #5
+ \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN
+ \if_int_compare:w #7 > #1 \c_zero \c_one
+ #1 \@@_trig_large:ww \@@_trigd_large:ww
+ \else:
+ #1 \@@_trig_small:ww \@@_trigd_small:ww
+ \fi:
+ #7,#8{0000}{0000};
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]
-% {\@@_trig_epsilon_o:w, \@@_trig_epsilon_one_o:w, \@@_trig_epsilon_inv_o:w}
-% Sine and tangent of tiny numbers give the number itself: the
-% relative error is less than $5 \cdot 10^{-17}$, which is
-% appropriate. Cosine and secant simply give~$1$. Cotangent and
-% cosecant compute $1/\epsilon$. This is actually slightly wrong
-% because further terms in the power series could affect the rounding
-% for cotangent.
-% \begin{macrocode}
-\cs_new:Npn \@@_trig_epsilon_o:w #1 #2 ;
- { \@@_exp_after_o:w \s_@@ \@@_chk:w 1 #1 {#2} }
-\cs_new:Npn \@@_trig_epsilon_one_o:w #1 ; #2 ;
- { \exp_after:wN \c_one_fp }
-\group_begin:
- \char_set_catcode_letter:N /
- \cs_new:Npn \@@_trig_epsilon_inv_o:w #1 #2 ;
- {
- \exp_after:wN \@@_/_o:ww
- \c_one_fp
- \s_@@ \@@_chk:w 1 #1 {#2}
- }
-\group_end:
+% \subsubsection{Small arguments}
+%
+% \begin{macro}[aux, EXP]{\@@_trig_small:ww}
+% This receives a small extended-precision number in radians and
+% converts it to a fixed point number. Some trailing digits may be
+% lost in the conversion, so we keep the original floating point
+% number around: when computing sine or tangent (or their inverses),
+% the last step will be to multiply by the floating point number (as
+% an extended-precision number) rather than the fixed point number.
+% The period serves to end the integer expression for the octant.
+% \begin{macrocode}
+\cs_new:Npn \@@_trig_small:ww #1,#2;
+ { \@@_ep_to_fixed:wwn #1,#2; . #1,#2; }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_trig_small:ww}
-% Floating point numbers less than $1$ are converted to fixed point
-% numbers by prepending a number of zeroes to the significand. Since we
-% have already filtered out numbers less than $10^{-8}$, we add at
-% most $7$ zeroes, hence no digit is lost in converting to a fixed
-% point number.
+% \begin{macro}[aux, EXP]{\@@_trigd_small:ww}
+% Convert the extended-precision number to radians, then call
+% \cs{@@_trig_small:ww} to massage it in the form appropriate for the
+% \texttt{_series} auxiliary.
% \begin{macrocode}
-\cs_new:Npn \@@_trig_small:ww #1; #2#3#4#5;
+\cs_new:Npn \@@_trigd_small:ww #1,#2;
{
+ \@@_ep_mul_raw:wwwwN
+ -1,{1745}{3292}{5199}{4329}{5769}{2369}; #1,#2;
+ \@@_trig_small:ww
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Argument reduction in degrees}
+%
+% \begin{macro}[aux, rEXP]
+% {
+% \@@_trigd_large:ww, \@@_trigd_large_auxi:nnnnwNNNN,
+% \@@_trigd_large_auxii:wNw, \@@_trigd_large_auxiii:www
+% }
+% Note that $25\times 360 = 9000$, so $10^{k+1} \equiv 10^{k}
+% \pmod{360}$ for $k\geq 3$. When the exponent~|#1| is very large, we
+% can thus safely replace it by~$22$ (or even~$19$). We turn the
+% floating point number into a fixed point number with two blocks of
+% $8$~digits followed by five blocks of $4$~digits. The original
+% float is $100\times\meta{block_1}\cdots\meta{block_3}.
+% \meta{block_4}\cdots\meta{block_7}$, or is equal to it modulo~$360$
+% if the exponent~|#1| is very large. The first auxiliary finds
+% $\meta{block_1} + \meta{block_2} \pmod{9}$, a single digit, and
+% prepends it to the $4$~digits of \meta{block_3}. It also unpacks
+% \meta{block_4} and grabs the $4$~digits of \meta{block_7}. The
+% second auxiliary grabs the \meta{block_3} plus any contribution from
+% the first two blocks as~|#1|, the first digit of \meta{block_4}
+% (just after the decimal point in hundreds of degrees) as~|#2|, and
+% the three other digits as~|#3|. It finds the quotient and remainder
+% of |#1#2| modulo~$9$, adds twice the quotient to the integer
+% expression for the octant, and places the remainder (between $0$
+% and~$8$) before |#3| to form a new \meta{block_4}. The resulting
+% fixed point number is $x\in [0, 0.9]$. If $x\geq 0.45$, we add~$1$
+% to the octant and feed $0.9-x$ with an exponent of~$2$ (to
+% compensate the fact that we are working in units of hundreds of
+% degrees rather than degrees) to \cs{@@_trigd_small:ww}. Otherwise,
+% we feed it~$x$ with an exponent of~$2$. The third auxiliary also
+% discards digits which were not packed into the various
+% \meta{blocks}. Since the original exponent~|#1| is at least~$2$,
+% those are all~$0$ and no precision is lost (|#6| and~|#7| are
+% four~$0$ each).
+% \begin{macrocode}
+\cs_new:Npn \@@_trigd_large:ww #1, #2#3#4#5#6#7;
+ {
+ \exp_after:wN \@@_pack_eight:wNNNNNNNN
+ \exp_after:wN \@@_pack_eight:wNNNNNNNN
\exp_after:wN \@@_pack_twice_four:wNNNNNNNN
\exp_after:wN \@@_pack_twice_four:wNNNNNNNN
- \exp_after:wN \@@_pack_twice_four:wNNNNNNNN
- \exp_after:wN .
+ \exp_after:wN \@@_trigd_large_auxi:nnnnwNNNN
\exp_after:wN ;
\tex_romannumeral:D -`0
- \prg_replicate:nn { - #1 } { 0 } #2#3#4#5 0000 0000 ;
+ \prg_replicate:nn { \int_max:nn { 22 - #1 } { 0 } } { 0 }
+ #2#3#4#5#6#7 0000 0000 0000 !
+ }
+\cs_new:Npn \@@_trigd_large_auxi:nnnnwNNNN #1#2#3#4#5; #6#7#8#9
+ {
+ \exp_after:wN \@@_trigd_large_auxii:wNw
+ \int_use:N \__int_eval:w #1 + #2
+ - (#1 + #2 - \c_four) / \c_nine * \c_nine \__int_eval_end:
+ #3;
+ #4; #5{#6#7#8#9};
+ }
+\cs_new:Npn \@@_trigd_large_auxii:wNw #1; #2#3;
+ {
+ + (#1#2 - \c_four) / \c_nine * \c_two
+ \exp_after:wN \@@_trigd_large_auxiii:www
+ \int_use:N \__int_eval:w #1#2
+ - (#1#2 - \c_four) / \c_nine * \c_nine \__int_eval_end: #3 ;
+ }
+\cs_new:Npn \@@_trigd_large_auxiii:www #1; #2; #3!
+ {
+ \if_int_compare:w #1 < 4500 \exp_stop_f:
+ \exp_after:wN \@@_use_i_until_s:nw
+ \exp_after:wN \@@_fixed_continue:wn
+ \else:
+ + \c_one
+ \fi:
+ \@@_fixed_sub:wwn {9000}{0000}{0000}{0000}{0000}{0000};
+ {#1}#2{0000}{0000};
+ { \@@_trigd_small:ww 2, }
}
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{Reduction of large arguments}
+% \subsubsection{Argument reduction in radians}
%
-% In the case of a floating point argument greater or equal to $1$, we
-% need to perform argument reduction.
+% Arguments greater or equal to~$1$ need to be reduced to a range where
+% we only need a few terms of the Taylor series. We reduce to the range
+% $[0,2\pi]$ by subtracting multiples of~$2\pi$, then to the smaller
+% range $[0,\pi/2]$ by subtracting multiples of~$\pi/2$ (keeping track
+% of how many times~$\pi/2$ is subtracted), then to $[0,\pi/4]$ by
+% mapping $x\to \pi/2 - x$ if appropriate. When the argument is very
+% large, say, $10^{100}$, an equally large multiple of~$2\pi$ must be
+% subtracted, hence we must work with a very good approximation
+% of~$2\pi$ in order to get a sensible remainder modulo~$2\pi$.
+%
+% Specifically, we multiply the argument by an approximation
+% of~$1/(2\pi)$ with $\ExplSyntaxOn\int_eval:n { \c__fp_max_exponent_int
+% + 48 }\ExplSyntaxOff$~digits, then discard the integer part of the
+% result, keeping $52$~digits of the fractional part. From the
+% fractional part of $x/(2\pi)$ we deduce the octant (quotient of the
+% first three digits by~$125$). We then multiply by $8$ or~$-8$ (the
+% latter when the octant is odd), ignore any integer part (related to
+% the octant), and convert the fractional part to an extended precision
+% number, before multiplying by~$\pi/4$ to convert back to a value in
+% radians in $[0,\pi/4]$.
+%
+% It is possible to prove that given the precision of floating points
+% and their range of exponents, the $52$~digits may start at most with
+% $24$~zeros. The $5$~last digits are affected by carries from
+% computations which are not done, hence we are left with at least $52 -
+% 24 - 5 = 23$ significant digits, enough to round correctly up to
+% $0.6\cdot\text{ulp}$ in all cases.
+%
+% ^^A todo: if the exponent range is reduced, store 1/2pi as a simple tl
+% \begin{macro}[aux, EXP]{\@@_trig_inverse_two_pi:}
+% This macro expands to |,,!| or~|,!| followed by $10112$~decimals of
+% $10^{-16}/(2\pi)$. The number of decimals we really need is the
+% maximum exponent plus the number of digits we will need later,~$52$,
+% plus~$12$ ($4-1$~groups of $4$~digits). We store the decimals as a
+% control sequence name, and convert it to a token list when required:
+% strings take up less memory than their token list representation.
+% \begin{macrocode}
+\cs_new_nopar:Npx \@@_trig_inverse_two_pi:
+ {
+ \exp_not:n { \exp_after:wN \use_none:n \token_to_str:N }
+ \cs:w , , !
+ 0000000000000000159154943091895335768883763372514362034459645740 ~
+ 4564487476673440588967976342265350901138027662530859560728427267 ~
+ 5795803689291184611457865287796741073169983922923996693740907757 ~
+ 3077746396925307688717392896217397661693362390241723629011832380 ~
+ 1142226997557159404618900869026739561204894109369378440855287230 ~
+ 9994644340024867234773945961089832309678307490616698646280469944 ~
+ 8652187881574786566964241038995874139348609983868099199962442875 ~
+ 5851711788584311175187671605465475369880097394603647593337680593 ~
+ 0249449663530532715677550322032477781639716602294674811959816584 ~
+ 0606016803035998133911987498832786654435279755070016240677564388 ~
+ 8495713108801221993761476813777647378906330680464579784817613124 ~
+ 2731406996077502450029775985708905690279678513152521001631774602 ~
+ 0924811606240561456203146484089248459191435211575407556200871526 ~
+ 6068022171591407574745827225977462853998751553293908139817724093 ~
+ 5825479707332871904069997590765770784934703935898280871734256403 ~
+ 6689511662545705943327631268650026122717971153211259950438667945 ~
+ 0376255608363171169525975812822494162333431451061235368785631136 ~
+ 3669216714206974696012925057833605311960859450983955671870995474 ~
+ 6510431623815517580839442979970999505254387566129445883306846050 ~
+ 7852915151410404892988506388160776196993073410389995786918905980 ~
+ 9373777206187543222718930136625526123878038753888110681406765434 ~
+ 0828278526933426799556070790386060352738996245125995749276297023 ~
+ 5940955843011648296411855777124057544494570217897697924094903272 ~
+ 9477021664960356531815354400384068987471769158876319096650696440 ~
+ 4776970687683656778104779795450353395758301881838687937766124814 ~
+ 9530599655802190835987510351271290432315804987196868777594656634 ~
+ 6221034204440855497850379273869429353661937782928735937843470323 ~
+ 0237145837923557118636341929460183182291964165008783079331353497 ~
+ 7909974586492902674506098936890945883050337030538054731232158094 ~
+ 3197676032283131418980974982243833517435698984750103950068388003 ~
+ 9786723599608024002739010874954854787923568261139948903268997427 ~
+ 0834961149208289037767847430355045684560836714793084567233270354 ~
+ 8539255620208683932409956221175331839402097079357077496549880868 ~
+ 6066360968661967037474542102831219251846224834991161149566556037 ~
+ 9696761399312829960776082779901007830360023382729879085402387615 ~
+ 5744543092601191005433799838904654921248295160707285300522721023 ~
+ 6017523313173179759311050328155109373913639645305792607180083617 ~
+ 9548767246459804739772924481092009371257869183328958862839904358 ~
+ 6866663975673445140950363732719174311388066383072592302759734506 ~
+ 0548212778037065337783032170987734966568490800326988506741791464 ~
+ 6835082816168533143361607309951498531198197337584442098416559541 ~
+ 5225064339431286444038388356150879771645017064706751877456059160 ~
+ 8716857857939226234756331711132998655941596890719850688744230057 ~
+ 5191977056900382183925622033874235362568083541565172971088117217 ~
+ 9593683256488518749974870855311659830610139214454460161488452770 ~
+ 2511411070248521739745103866736403872860099674893173561812071174 ~
+ 0478899368886556923078485023057057144063638632023685201074100574 ~
+ 8592281115721968003978247595300166958522123034641877365043546764 ~
+ 6456565971901123084767099309708591283646669191776938791433315566 ~
+ 5066981321641521008957117286238426070678451760111345080069947684 ~
+ 2235698962488051577598095339708085475059753626564903439445420581 ~
+ 7886435683042000315095594743439252544850674914290864751442303321 ~
+ 3324569511634945677539394240360905438335528292434220349484366151 ~
+ 4663228602477666660495314065734357553014090827988091478669343492 ~
+ 2737602634997829957018161964321233140475762897484082891174097478 ~
+ 2637899181699939487497715198981872666294601830539583275209236350 ~
+ 6853889228468247259972528300766856937583659722919824429747406163 ~
+ 8183113958306744348516928597383237392662402434501997809940402189 ~
+ 6134834273613676449913827154166063424829363741850612261086132119 ~
+ 9863346284709941839942742955915628333990480382117501161211667205 ~
+ 1912579303552929241134403116134112495318385926958490443846807849 ~
+ 0973982808855297045153053991400988698840883654836652224668624087 ~
+ 2540140400911787421220452307533473972538149403884190586842311594 ~
+ 6322744339066125162393106283195323883392131534556381511752035108 ~
+ 7459558201123754359768155340187407394340363397803881721004531691 ~
+ 8295194879591767395417787924352761740724605939160273228287946819 ~
+ 3649128949714953432552723591659298072479985806126900733218844526 ~
+ 7943350455801952492566306204876616134365339920287545208555344144 ~
+ 0990512982727454659118132223284051166615650709837557433729548631 ~
+ 2041121716380915606161165732000083306114606181280326258695951602 ~
+ 4632166138576614804719932707771316441201594960110632830520759583 ~
+ 4850305079095584982982186740289838551383239570208076397550429225 ~
+ 9847647071016426974384504309165864528360324933604354657237557916 ~
+ 1366324120457809969715663402215880545794313282780055246132088901 ~
+ 8742121092448910410052154968097113720754005710963406643135745439 ~
+ 9159769435788920793425617783022237011486424925239248728713132021 ~
+ 7667360756645598272609574156602343787436291321097485897150713073 ~
+ 9104072643541417970572226547980381512759579124002534468048220261 ~
+ 7342299001020483062463033796474678190501811830375153802879523433 ~
+ 4195502135689770912905614317878792086205744999257897569018492103 ~
+ 2420647138519113881475640209760554895793785141404145305151583964 ~
+ 2823265406020603311891586570272086250269916393751527887360608114 ~
+ 5569484210322407772727421651364234366992716340309405307480652685 ~
+ 0930165892136921414312937134106157153714062039784761842650297807 ~
+ 8606266969960809184223476335047746719017450451446166382846208240 ~
+ 8673595102371302904443779408535034454426334130626307459513830310 ~
+ 2293146934466832851766328241515210179422644395718121717021756492 ~
+ 1964449396532222187658488244511909401340504432139858628621083179 ~
+ 3939608443898019147873897723310286310131486955212620518278063494 ~
+ 5711866277825659883100535155231665984394090221806314454521212978 ~
+ 9734471488741258268223860236027109981191520568823472398358013366 ~
+ 0683786328867928619732367253606685216856320119489780733958419190 ~
+ 6659583867852941241871821727987506103946064819585745620060892122 ~
+ 8416394373846549589932028481236433466119707324309545859073361878 ~
+ 6290631850165106267576851216357588696307451999220010776676830946 ~
+ 9814975622682434793671310841210219520899481912444048751171059184 ~
+ 4139907889455775184621619041530934543802808938628073237578615267 ~
+ 7971143323241969857805637630180884386640607175368321362629671224 ~
+ 2609428540110963218262765120117022552929289655594608204938409069 ~
+ 0760692003954646191640021567336017909631872891998634341086903200 ~
+ 5796637103128612356988817640364252540837098108148351903121318624 ~
+ 7228181050845123690190646632235938872454630737272808789830041018 ~
+ 9485913673742589418124056729191238003306344998219631580386381054 ~
+ 2457893450084553280313511884341007373060595654437362488771292628 ~
+ 9807423539074061786905784443105274262641767830058221486462289361 ~
+ 9296692992033046693328438158053564864073184440599549689353773183 ~
+ 6726613130108623588021288043289344562140479789454233736058506327 ~
+ 0439981932635916687341943656783901281912202816229500333012236091 ~
+ 8587559201959081224153679499095448881099758919890811581163538891 ~
+ 6339402923722049848375224236209100834097566791710084167957022331 ~
+ 7897107102928884897013099533995424415335060625843921452433864640 ~
+ 3432440657317477553405404481006177612569084746461432976543900008 ~
+ 3826521145210162366431119798731902751191441213616962045693602633 ~
+ 6102355962140467029012156796418735746835873172331004745963339773 ~
+ 2477044918885134415363760091537564267438450166221393719306748706 ~
+ 2881595464819775192207710236743289062690709117919412776212245117 ~
+ 2354677115640433357720616661564674474627305622913332030953340551 ~
+ 3841718194605321501426328000879551813296754972846701883657425342 ~
+ 5016994231069156343106626043412205213831587971115075454063290657 ~
+ 0248488648697402872037259869281149360627403842332874942332178578 ~
+ 7750735571857043787379693402336902911446961448649769719434527467 ~
+ 4429603089437192540526658890710662062575509930379976658367936112 ~
+ 8137451104971506153783743579555867972129358764463093757203221320 ~
+ 2460565661129971310275869112846043251843432691552928458573495971 ~
+ 5042565399302112184947232132380516549802909919676815118022483192 ~
+ 5127372199792134331067642187484426215985121676396779352982985195 ~
+ 8545392106957880586853123277545433229161989053189053725391582222 ~
+ 9232597278133427818256064882333760719681014481453198336237910767 ~
+ 1255017528826351836492103572587410356573894694875444694018175923 ~
+ 0609370828146501857425324969212764624247832210765473750568198834 ~
+ 5641035458027261252285503154325039591848918982630498759115406321 ~
+ 0354263890012837426155187877318375862355175378506956599570028011 ~
+ 5841258870150030170259167463020842412449128392380525772514737141 ~
+ 2310230172563968305553583262840383638157686828464330456805994018 ~
+ 7001071952092970177990583216417579868116586547147748964716547948 ~
+ 8312140431836079844314055731179349677763739898930227765607058530 ~
+ 4083747752640947435070395214524701683884070908706147194437225650 ~
+ 2823145872995869738316897126851939042297110721350756978037262545 ~
+ 8141095038270388987364516284820180468288205829135339013835649144 ~
+ 3004015706509887926715417450706686888783438055583501196745862340 ~
+ 8059532724727843829259395771584036885940989939255241688378793572 ~
+ 7967951654076673927031256418760962190243046993485989199060012977 ~
+ 7469214532970421677817261517850653008552559997940209969455431545 ~
+ 2745856704403686680428648404512881182309793496962721836492935516 ~
+ 2029872469583299481932978335803459023227052612542114437084359584 ~
+ 9443383638388317751841160881711251279233374577219339820819005406 ~
+ 3292937775306906607415304997682647124407768817248673421685881509 ~
+ 9133422075930947173855159340808957124410634720893194912880783576 ~
+ 3115829400549708918023366596077070927599010527028150868897828549 ~
+ 4340372642729262103487013992868853550062061514343078665396085995 ~
+ 0058714939141652065302070085265624074703660736605333805263766757 ~
+ 2018839497277047222153633851135483463624619855425993871933367482 ~
+ 0422097449956672702505446423243957506869591330193746919142980999 ~
+ 3424230550172665212092414559625960554427590951996824313084279693 ~
+ 7113207021049823238195747175985519501864630940297594363194450091 ~
+ 9150616049228764323192129703446093584259267276386814363309856853 ~
+ 2786024332141052330760658841495858718197071242995959226781172796 ~
+ 4438853796763139274314227953114500064922126500133268623021550837
+ \cs_end:
+ }
+% \end{macrocode}
+% \end{macro}
%
% \begin{macro}[aux, rEXP]
% {
-% \@@_trig_large:ww, \@@_trig_large:www,
-% \@@_trig_large_o:wnnnn, \@@_trig_large_break:w
+% \@@_trig_large:ww,
+% \@@_trig_large_auxi:wwwwww,
+% \@@_trig_large_auxii:ww,
+% \@@_trig_large_auxiii:wNNNNNNNN,
+% \@@_trig_large_auxiv:wN
% }
-% We shift the significand by one digit at a time, subtracting a multiple
-% of $2\pi$ at each step. We use a value of $2\pi$ rounded up,
-% consistent with the choice of \cs{c_pi_fp}. This is not quite
-% correct from an accuracy perspective, but has the nice property that
-% $\sin(180\mathrm{deg}) = 0$ exactly. The arguments of
-% \cs{@@_trig_large:www} are a leading block of up to $5$ digits,
-% three brace groups of $4$ digits each, and the exponent, decremented
-% at each step. The multiple of $2\pi$ to subtract is estimated as
-% $\lfloor |#1| / 6283.3\rfloor$ (the formula chosen always gives a
-% non-negative integer, strictly less than the actual ratio by $2\pi$).
-% The subtraction has a form similar to our
-% usual multiplications (see \pkg{l3fp-basics} or
-% \pkg{l3fp-extended}). Once the exponent reaches $0$, we are done
-% subtracting $2\pi$, and we call \cs{@@_trig_octant_loop:nnnnnw} to do
-% the reduction by $\pi/2$.
-% \begin{macrocode}
-\cs_new:Npn \@@_trig_large:ww #1; #2#3;
- { \@@_trig_large:www #2; #3 ; #1; }
-\cs_new:Npn \@@_trig_large:www #1; #2; #3;
- {
- \if_meaning:w 0 #3 \@@_trig_large_break:w \fi:
- \exp_after:wN \@@_trig_large_o:wnnnn
- \int_use:N \__int_eval:w ( #10 - 31416 ) / 62833 ;
- {#1} #2
- \exp_after:wN ;
- \int_use:N \__int_eval:w \c_minus_one + #3;
- }
-\cs_new:Npn \@@_trig_large_o:wnnnn #1; #2#3#4#5
- {
- \exp_after:wN \@@_trig_large:www
- \int_use:N \__int_eval:w \c_@@_leading_shift_int + #20 - #1*62831
- \exp_after:wN \@@_pack:NNNNNw
- \int_use:N \__int_eval:w \c_@@_middle_shift_int + #30 - #1*8530
- \exp_after:wN \@@_pack:NNNNNw
- \int_use:N \__int_eval:w \c_@@_middle_shift_int + #40 - #1*7179
- \exp_after:wN \@@_pack:NNNNNw
- \int_use:N \__int_eval:w \c_@@_trailing_shift_int + #50 - #1*5880
- \exp_after:wN ;
+% The exponent~|#1| is between $1$ and~$\ExplSyntaxOn \int_use:N
+% \c__fp_max_exponent_int$. We discard the integer part of
+% $10^{\text{\texttt{\#1}}-16}/(2\pi)$, that is, the first |#1|~digits
+% of $10^{-16}/(2\pi)$, because it yields an integer contribution to
+% $x/(2\pi)$. The \texttt{auxii} auxiliary discards~$64$ digits at a
+% time thanks to spaces inserted in the result of
+% \cs{@@_trig_inverse_two_pi:}, while \texttt{auxiii} discards~$8$
+% digits at a time, and \texttt{auxiv} discards digits one at a time.
+% Then $64$~digits are packed into groups of~$4$ and the \texttt{auxv}
+% auxiliary is called.
+% \begin{macrocode}
+\cs_new:Npn \@@_trig_large:ww #1, #2#3#4#5#6;
+ {
+ \exp_after:wN \@@_trig_large_auxi:wwwwww
+ \int_use:N \__int_eval:w (#1 - 32) / 64 \exp_after:wN ,
+ \int_use:N \__int_eval:w (#1 - 4) / 8 \exp_after:wN ,
+ \__int_value:w #1 \@@_trig_inverse_two_pi: ;
+ {#2}{#3}{#4}{#5} ;
+ }
+\cs_new:Npn \@@_trig_large_auxi:wwwwww #1, #2, #3, #4!
+ {
+ \prg_replicate:nn {#1} { \@@_trig_large_auxii:ww }
+ \prg_replicate:nn { #2 - #1 * \c_eight }
+ { \@@_trig_large_auxiii:wNNNNNNNN }
+ \prg_replicate:nn { #3 - #2 * \c_eight }
+ { \@@_trig_large_auxiv:wN }
+ \prg_replicate:nn { \c_eight } { \@@_pack_twice_four:wNNNNNNNN }
+ \@@_trig_large_auxv:www
+ ;
}
-\cs_new:Npn \@@_trig_large_break:w \fi: #1; #2;
- { \fi: \@@_trig_octant_loop:nnnnnw #2 {0000} {0000} ; }
+\cs_new:Npn \@@_trig_large_auxii:ww #1; #2 ~ { #1; }
+\cs_new:Npn \@@_trig_large_auxiii:wNNNNNNNN
+ #1; #2#3#4#5#6#7#8#9 { #1; }
+\cs_new:Npn \@@_trig_large_auxiv:wN #1; #2 { #1; }
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux, rEXP]
-% {\@@_trig_octant_loop:nnnnnw, \@@_trig_octant_break:w}
-% We receive a fixed point number as argument. As long as it is
-% greater than half of \cs{c_pi_fp}, namely $1.5707963267948970$,
-% subtract that fixed-point approximation of $\pi/2$, and leave |+|
-% |\c_two| in the integer expression for the octant. Once the argument
-% becomes smaller, break the initial loop. If the number is greater
-% than $0.7854$ (overestimate of $\pi/4$), then compute $\pi/2 - x$
-% and increment the octant. The result is in all cases in the range
-% $[0, 0.7854]$, appropriate for the series expansions.
-% \begin{macrocode}
-\cs_new:Npn \@@_trig_octant_loop:nnnnnw #1#2#3#4#5#6;
- {
- \if_int_compare:w #1#2 < 157079633 \exp_stop_f:
- \if_int_compare:w #1#2 = 157079632 \exp_stop_f:
- \if_int_compare:w #3#4 > 67948969 \exp_stop_f:
- \use_i_ii:nnn
- \fi:
- \fi:
- \@@_trig_octant_break:w
- \fi:
- + \c_two
- \@@_fixed_sub:wwn
- {#1} {#2} {#3} {#4} {0000} {0000} ;
- {15707} {9632} {6794} {8970} {0000} {0000} ;
- \@@_trig_octant_loop:nnnnnw
+% {
+% \@@_trig_large_auxv:www,
+% \@@_trig_large_auxvi:wnnnnnnnn,
+% \@@_trig_large_pack:NNNNNw
+% }
+% First come the first $64$~digits of the fractional part of
+% $10^{\text{\texttt{\#1}}-16}/(2\pi)$, arranged in $16$~blocks
+% of~$4$, and ending with a semicolon. Then some more digits of the
+% same fractional part, ending with a semicolon, then $4$~blocks of
+% $4$~digits holding the significand of the original argument.
+% Multiply the $16$-digit significand with the $64$-digit fractional
+% part: the \texttt{auxvi} auxiliary receives the significand
+% as~|#2#3#4#5| and $16$~digits of the fractional part as~|#6#7#8#9|,
+% and computes one step of the usual ladder of \texttt{pack} functions
+% we use for multiplication (see \emph{e.g.,} \cs{@@_fixed_mul:wwn}),
+% then discards one block of the fractional part to set things up for
+% the next step of the ladder. We perform $13$~such steps, replacing
+% the last \texttt{middle} shift by the appropriate \texttt{trailing}
+% shift, then discard the significand and remaining $3$~blocks from
+% the fractional part, as there are not enough digits to compute any
+% more step in the ladder. The last semicolon closes the ladder, and
+% we return control to the \texttt{auxvii} auxiliary.
+% \begin{macrocode}
+\cs_new:Npn \@@_trig_large_auxv:www #1; #2; #3;
+ {
+ \exp_after:wN \@@_use_i_until_s:nw
+ \exp_after:wN \@@_trig_large_auxvii:w
+ \int_use:N \__int_eval:w \c_@@_leading_shift_int
+ \prg_replicate:nn { \c_thirteen }
+ { \@@_trig_large_auxvi:wnnnnnnnn }
+ + \c_@@_trailing_shift_int - \c_@@_middle_shift_int
+ \@@_use_i_until_s:nw
+ ; #3 #1 ; ;
}
-\cs_new:Npn \@@_trig_octant_break:w #1 \fi: + #2#3 #4#5; #6; #7;
+\cs_new:Npn \@@_trig_large_auxvi:wnnnnnnnn #1; #2#3#4#5#6#7#8#9
{
+ \exp_after:wN \@@_trig_large_pack:NNNNNw
+ \int_use:N \__int_eval:w \c_@@_middle_shift_int
+ + #2*#9 + #3*#8 + #4*#7 + #5*#6
+ #1; {#2}{#3}{#4}{#5} {#7}{#8}{#9}
+ }
+\cs_new:Npn \@@_trig_large_pack:NNNNNw #1#2#3#4#5#6;
+ { + #1#2#3#4#5 ; #6 }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, rEXP]
+% {
+% \@@_trig_large_auxvii:w,
+% \@@_trig_large_auxviii:w,
+% }
+% \begin{macro}[aux, EXP]
+% {
+% \@@_trig_large_auxix:Nw,
+% \@@_trig_large_auxx:wNNNNN,
+% \@@_trig_large_auxxi:w
+% }
+% The \texttt{auxvii} auxiliary is followed by $52$~digits and a
+% semicolon. We find the octant as the integer part of $8$~times what
+% follows, or equivalently as the integer part of $|#1#2#3|/125$, and
+% add it to the surrounding integer expression for the octant. We
+% then compute $8$~times the $52$-digit number, with a minus sign if
+% the octant is odd. Again, the last \texttt{middle} shift is
+% converted to a \texttt{trailing} shift. Any integer part (including
+% negative values which come up when the octant is odd) is discarded
+% by \cs{@@_use_i_until_s:nw}. The resulting fractional part should
+% then be converted to radians by multiplying by~$2\pi/8$, but first,
+% build an extended precision number by abusing
+% \cs{@@_ep_to_ep_loop:N} with the appropriate trailing markers.
+% Finally, \cs{@@_trig_small:ww} sets up the argument for the
+% functions which compute the Taylor series.
+% \begin{macrocode}
+\cs_new:Npn \@@_trig_large_auxvii:w #1#2#3
+ {
+ \exp_after:wN \@@_trig_large_auxviii:ww
+ \int_use:N \__int_eval:w (#1#2#3 - 62) / 125 ;
+ #1#2#3
+ }
+\cs_new:Npn \@@_trig_large_auxviii:ww #1;
+ {
+ + #1
+ \if_int_odd:w #1 \exp_stop_f:
+ \exp_after:wN \@@_trig_large_auxix:Nw
+ \exp_after:wN -
+ \else:
+ \exp_after:wN \@@_trig_large_auxix:Nw
+ \exp_after:wN +
\fi:
- \if_int_compare:w #4 < 7854 \exp_stop_f:
- \exp_after:wN \@@_use_i_until_s:nw
- \exp_after:wN .
- \fi:
- + \c_one
- \@@_fixed_sub:wwn #6 ; {#4} #5 ; . ;
+ }
+\cs_new_nopar:Npn \@@_trig_large_auxix:Nw
+ {
+ \exp_after:wN \@@_use_i_until_s:nw
+ \exp_after:wN \@@_trig_large_auxxi:w
+ \int_use:N \__int_eval:w \c_@@_leading_shift_int
+ \prg_replicate:nn { \c_thirteen }
+ { \@@_trig_large_auxx:wNNNNN }
+ + \c_@@_trailing_shift_int - \c_@@_middle_shift_int
+ ;
+ }
+\cs_new:Npn \@@_trig_large_auxx:wNNNNN #1; #2 #3#4#5#6
+ {
+ \exp_after:wN \@@_trig_large_pack:NNNNNw
+ \int_use:N \__int_eval:w \c_@@_middle_shift_int
+ #2 \c_eight * #3#4#5#6
+ #1; #2
+ }
+\cs_new:Npn \@@_trig_large_auxxi:w #1;
+ {
+ \exp_after:wN \@@_ep_mul_raw:wwwwN
+ \int_use:N \__int_eval:w \c_zero \@@_ep_to_ep_loop:N #1 ; ; !
+ 0,{7853}{9816}{3397}{4483}{0961}{5661};
+ \@@_trig_small:ww
}
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
-% \subsection{Computing the power series}
+% \subsubsection{Computing the power series}
%
-% \begin{macro}[aux, EXP]{\@@_sin_series:NNwww, \@@_sin_series_aux:NNnww}
-% Here we receive a conversion function \cs{@@_fixed_to_float:wN} or
-% \cs{@@_fixed_inv_to_float:wN}, a \meta{sign} ($0$ or $2$), a
+% \begin{macro}[aux, EXP]
+% {\@@_sin_series_o:NNwwww, \@@_sin_series_aux_o:NNnwww}
+% Here we receive a conversion function \cs{@@_ep_to_float:wwN} or
+% \cs{@@_ep_inv_to_float:wwN}, a \meta{sign} ($0$ or~$2$), a
% (non-negative) \meta{octant} delimited by a dot, a \meta{fixed
-% point} number, and junk delimited by a semicolon. The auxiliary
-% receives:
+% point} number delimited by a semicolon, and an extended-precision
+% number. The auxiliary receives:
% \begin{itemize}
-% \item The final sign, which depends on the octant |#3| and the
-% original sign |#2|,
-% \item The octant |#3|, which will control the series we use.
-% \item The square |#4 * #4| of the argument, computed with
-% \cs{@@_fixed_mul:wwn}.
-% \item The number itself.
+% \item the conversion function~|#1|;
+% \item the final sign, which depends on the octant~|#3| and the
+% sign~|#2|;
+% \item the octant~|#3|, which will control the series we use;
+% \item the square |#4 * #4| of the argument as a fixed point number,
+% computed with \cs{@@_fixed_mul:wwn};
+% \item the number itself as an extended-precision number.
% \end{itemize}
% If the octant is in $\{1,2,5,6,\ldots{}\}$, we are near an extremum
% of the function and we use the series
@@ -488,15 +836,15 @@
% \sin(x) = x \bigg( 1 - x^2 \bigg( \frac{1}{3!} - x^2 \bigg(
% \frac{1}{5!} - x^2 \bigg( \cdots \bigg) \bigg) \bigg) \bigg)
% \]
-% is used. Finally, the fixed point number is converted to a floating
-% point number with the given sign, and \cs{@@_sanitize:Nw} checks for
-% overflow and underflow.
+% is used. Finally, the extended-precision number is converted to a
+% floating point number with the given sign, and \cs{@@_sanitize:Nw}
+% checks for overflow and underflow.
% \begin{macrocode}
-\cs_new:Npn \@@_sin_series:NNwww #1#2#3 . #4; #5;
+\cs_new:Npn \@@_sin_series_o:NNwwww #1#2#3. #4;
{
\@@_fixed_mul:wwn #4; #4;
{
- \exp_after:wN \@@_sin_series_aux:NNnww
+ \exp_after:wN \@@_sin_series_aux_o:NNnwww
\exp_after:wN #1
\__int_value:w
\if_int_odd:w \__int_eval:w ( #3 + \c_two ) / \c_four \__int_eval_end:
@@ -506,9 +854,8 @@
\fi:
{#3}
}
- #4 ;
}
-\cs_new:Npn \@@_sin_series_aux:NNnww #1#2#3 #4; #5;
+\cs_new:Npn \@@_sin_series_aux_o:NNnwww #1#2#3 #4; #5,#6;
{
\if_int_odd:w \__int_eval:w #3 / \c_two \__int_eval_end:
\exp_after:wN \use_i:nn
@@ -526,6 +873,7 @@
\@@_fixed_mul_sub_back:wwwn #4; {0416}{6666}{6666}{6666}{6666}{6667};
\@@_fixed_mul_sub_back:wwwn #4; {5000}{0000}{0000}{0000}{0000}{0000};
\@@_fixed_mul_sub_back:wwwn #4;{10000}{0000}{0000}{0000}{0000}{0000};
+ { \@@_fixed_continue:wn 0, }
}
{ % 1/17!
\@@_fixed_mul_sub_back:wwwn {0000}{0000}{0000}{0028}{1145}{7254};
@@ -537,7 +885,7 @@
\@@_fixed_mul_sub_back:wwwn #4; {0083}{3333}{3333}{3333}{3333}{3333};
\@@_fixed_mul_sub_back:wwwn #4; {1666}{6666}{6666}{6666}{6666}{6667};
\@@_fixed_mul_sub_back:wwwn #4;{10000}{0000}{0000}{0000}{0000}{0000};
- \@@_fixed_mul:wwn #5;
+ { \@@_ep_mul:wwwwn 0, } #5,#6;
}
{
\exp_after:wN \@@_sanitize:Nw
@@ -549,9 +897,11 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_tan_series_o:NNwww, \@@_tan_series_aux_o:Nnww}
-% Contrarily to \cs{@@_sin_series:NNwww} which received the conversion
-% auxiliary as |#1|, here |#1| is $0$ for tangent, and $2$ for
+% \begin{macro}[aux, EXP]
+% {\@@_tan_series_o:NNwwww, \@@_tan_series_aux_o:Nnwww}
+% Contrarily to \cs{@@_sin_series_o:NNwwww} which received a
+% conversion auxiliary as~|#1|, here, |#1| is $0$ for tangent
+% and $2$ for
% cotangent. Consider first the case of the tangent. The octant |#3|
% starts at $1$, which means that it is $1$ or $2$ for $\lvert
% x\rvert\in[0,\pi/2]$, it is $3$ or $4$ for $\lvert
@@ -564,25 +914,26 @@
% similar story holds for $\cot(x)$.
%
% The auxiliary receives the sign, the octant, the square of the
-% (reduced) input, and the (reduced) input as arguments. It then
+% (reduced) input, and the (reduced) input (an extended-precision
+% number) as arguments. It then
% computes the numerator and denominator of
% \[
% \tan(x) \simeq
% \frac{x (1 - x^2 (a_1 - x^2 (a_2 - x^2 (a_3 - x^2 (a_4 - x^2 a_5)))))}
% {1 - x^2 (b_1 - x^2 (b_2 - x^2 (b_3 - x^2 (b_4 - x^2 b_5))))} .
% \]
-% The ratio itself is computed by \cs{@@_fixed_div_to_float:ww}, which
-% converts it directly to a floating point number to avoid rounding
-% issues. For octants~|#2| (really, quadrants) next to a pole of the
+% The ratio is computed by \cs{@@_ep_div:wwwwn}, then converted to a
+% floating point number. For octants~|#3| (really, quadrants) next to
+% a pole of the
% functions, the fixed point numerator and denominator are exchanged
% before computing the ratio. Note that this \cs{if_int_odd:w} test
% relies on the fact that the octant is at least~$1$.
% \begin{macrocode}
-\cs_new:Npn \@@_tan_series_o:NNwww #1#2#3. #4; #5;
+\cs_new:Npn \@@_tan_series_o:NNwwww #1#2#3. #4;
{
\@@_fixed_mul:wwn #4; #4;
{
- \exp_after:wN \@@_tan_series_aux_o:Nnww
+ \exp_after:wN \@@_tan_series_aux_o:Nnwww
\__int_value:w
\if_int_odd:w \__int_eval:w #3 / \c_two \__int_eval_end:
\exp_after:wN \reverse_if:N
@@ -590,9 +941,8 @@
\if_meaning:w #1#2 2 \else: 0 \fi:
{#3}
}
- #4 ;
}
-\cs_new:Npn \@@_tan_series_aux_o:Nnww #1 #2 #3; #4;
+\cs_new:Npn \@@_tan_series_aux_o:Nnwww #1 #2 #3; #4,#5;
{
\@@_fixed_mul_sub_back:wwwn {0000}{0000}{1527}{3493}{0856}{7059};
#3; {0000}{0159}{6080}{0274}{5257}{6472};
@@ -600,24 +950,615 @@
\@@_fixed_mul_sub_back:wwwn #3; {0115}{5830}{7533}{5397}{3168}{2147};
\@@_fixed_mul_sub_back:wwwn #3; {1929}{8245}{6140}{3508}{7719}{2982};
\@@_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000};
- \@@_fixed_mul:wwn #4;
+ { \@@_ep_mul:wwwwn 0, } #4,#5;
+ {
+ \@@_fixed_mul_sub_back:wwwn {0000}{0007}{0258}{0681}{9408}{4706};
+ #3; {0000}{2343}{7175}{1399}{6151}{7670};
+ \@@_fixed_mul_sub_back:wwwn #3; {0019}{2638}{4588}{9232}{8861}{3691};
+ \@@_fixed_mul_sub_back:wwwn #3; {0536}{6357}{0691}{4344}{6852}{4252};
+ \@@_fixed_mul_sub_back:wwwn #3; {5263}{1578}{9473}{6842}{1052}{6315};
+ \@@_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000};
+ {
+ \reverse_if:N \if_int_odd:w
+ \__int_eval:w (#2 - \c_one) / \c_two \__int_eval_end:
+ \exp_after:wN \@@_reverse_args:Nww
+ \fi:
+ \@@_ep_div:wwwwn 0,
+ }
+ }
+ {
+ \exp_after:wN \@@_sanitize:Nw
+ \exp_after:wN #1
+ \int_use:N \__int_eval:w \@@_ep_to_float:wwN
+ }
+ #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Inverse trigonometric functions}
+%
+% \providecommand*{\atan}{\operatorname{atan}}
+%
+% All inverse trigonometric functions (arcsine, arccosine, arctangent,
+% arccotangent, arccosecant, and arcsecant) are based on a function
+% often denoted \texttt{atan2}. This function is accessed directly by
+% feeding two arguments to arctangent, and is defined by \(\atan(y, x) =
+% \atan(y/x)\) for generic \(y\) and~\(x\). Its advantages over the
+% conventional arctangent is that it takes values in $[-\pi,\pi]$ rather
+% than $[-\pi/2,\pi/2]$, and that it is better behaved in boundary
+% cases. Other inverse trigonometric functions are expressed in terms
+% of \(\atan\) as
+% \begin{align}
+% \operatorname{acos} x & = \atan(\sqrt{1-x^2}, x) \\
+% \operatorname{asin} x & = \atan(x, \sqrt{1-x^2}) \\
+% \operatorname{asec} x & = \atan(\sqrt{x^2-1}, 1) \\
+% \operatorname{acsc} x & = \atan(1, \sqrt{x^2-1}) \\
+% \operatorname{atan} x & = \atan(x, 1) \\
+% \operatorname{acot} x & = \atan(1, x) .
+% \end{align}
+% Rather than introducing a new function, \texttt{atan2}, the arctangent
+% function \texttt{atan} is overloaded: it can take one or two
+% arguments. In the comments below, following many texts, we call the
+% first argument~$y$ and the second~$x$, because $\atan(y, x) = \atan(y
+% / x)$ is the angular coordinate of the point $(x, y)$.
+%
+% As for direct trigonometric functions, the first step in computing
+% $\atan(y, x)$ is argument reduction. The sign of~$y$ will give that
+% of the result. We distinguish eight regions where the point $(x,
+% \lvert y\rvert)$ can lie, of angular size roughly $\pi/8$,
+% characterized by their ``octant'', between $0$ and~$7$ included. In
+% each region, we compute an arctangent as a Taylor series, then shift
+% this arctangent by the appropriate multiple of $\pi/4$ and sign to get
+% the result. Here is a list of octants, and how we compute the
+% arctangent (we assume $y>0$: otherwise replace $y$ by~$-y$ below):
+% \begin{itemize}
+% \item[0] $0 < \lvert y\rvert < 0.41421 x$, then
+% $\atan\frac{\lvert y\rvert}{x}$
+% is given by a nicely convergent Taylor series;
+% \item[1] $0 < 0.41421 x < \lvert y\rvert < x$, then
+% $\atan\frac{\lvert y\rvert}{x}
+% = \frac{\pi}{4}-\atan\frac{x-\lvert y\rvert}{x+\lvert y\rvert}$;
+% \item[2] $0 < 0.41421 \lvert y\rvert < x < \lvert y\rvert$, then
+% $\atan\frac{\lvert y\rvert}{x}
+% = \frac{\pi}{4}+\atan\frac{-x+\lvert y\rvert}{x+\lvert y\rvert}$;
+% \item[3] $0 < x < 0.41421 \lvert y\rvert$, then
+% $\atan\frac{\lvert y\rvert}{x}
+% = \frac{\pi}{2}-\atan\frac{x}{\lvert y\rvert}$;
+% \item[4] $0 < -x < 0.41421 \lvert y\rvert$, then
+% $\atan\frac{\lvert y\rvert}{x}
+% = \frac{\pi}{2}+\atan\frac{-x}{\lvert y\rvert}$;
+% \item[5] $0 < 0.41421 \lvert y\rvert < -x < \lvert y\rvert$, then
+% $\atan\frac{\lvert y\rvert}{x}
+% =\frac{3\pi}{4}-\atan\frac{x+\lvert y\rvert}{-x+\lvert y\rvert}$;
+% \item[6] $0 < -0.41421 x < \lvert y\rvert < -x$, then
+% $\atan\frac{\lvert y\rvert}{x}
+% =\frac{3\pi}{4}+\atan\frac{-x-\lvert y\rvert}{-x+\lvert y\rvert}$;
+% \item[7] $0 < \lvert y\rvert < -0.41421 x$, then
+% $\atan\frac{\lvert y\rvert}{x}
+% = \pi-\atan\frac{\lvert y\rvert}{-x}$.
+% \end{itemize}
+% In the following, we will denote by~$z$ the ratio among
+% $\lvert\frac{y}{x}\rvert$, $\lvert\frac{x}{y}\rvert$,
+% $\lvert\frac{x+y}{x-y}\rvert$, $\lvert\frac{x-y}{x+y}\rvert$ which
+% appears in the right-hand side above.
+%
+% \subsubsection{Arctangent and arccotangent}
+%
+% \begin{macro}[int, EXP]{\@@_atan_o:Nw, \@@_acot_o:Nw}
+% \begin{macro}[aux, EXP]{\@@_atan_dispatch_o:NNnNw}
+% The parsing step manipulates \texttt{atan} and \texttt{acot} like
+% \texttt{min} and \texttt{max}, reading in an array of operands, but
+% also leaves \cs{use_i:nn} or \cs{use_ii:nn} depending on whether the
+% result should be given in radians or in degrees. Here, we dispatch
+% according to the number of arguments. The one-argument versions of
+% arctangent and arccotangent are special cases of the two-argument
+% ones: $\atan(y) = \atan(y, 1) = \operatorname{acot}(1, y)$ and
+% $\operatorname{acot}(x) = \atan(1, x) = \operatorname{acot}(x, 1)$.
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_atan_o:Nw
+ {
+ \@@_atan_dispatch_o:NNnNw
+ \@@_acotii_o:Nww \@@_atanii_o:Nww { atan }
+ }
+\cs_new_nopar:Npn \@@_acot_o:Nw
+ {
+ \@@_atan_dispatch_o:NNnNw
+ \@@_atanii_o:Nww \@@_acotii_o:Nww { acot }
+ }
+\cs_new:Npn \@@_atan_dispatch_o:NNnNw #1#2#3#4#5@
+ {
+ \if_case:w
+ \__int_eval:w \@@_array_count:n {#5} - \c_one \__int_eval_end:
+ \exp_after:wN #1 \exp_after:wN #4 \c_one_fp #5
+ \tex_romannumeral:D
+ \or: #2 #4 #5 \tex_romannumeral:D
+ \else:
+ \__msg_kernel_expandable_error:nnnnn
+ { kernel } { fp-num-args } { #3() } { 1 } { 2 }
+ \exp_after:wN \c_nan_fp \tex_romannumeral:D
+ \fi:
+ \exp_after:wN \c_zero
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int, EXP]{\@@_atanii_o:Nww, \@@_acotii_o:Nww}
+% If either operand is \texttt{nan}, we return it. If both are
+% normal, we call \cs{@@_atan_normal_o:NNnwNnw}. If both are zero or
+% both infinity, we call \cs{@@_atan_inf_o:NNNw} with argument~$2$,
+% leading to a result among $\{\pm\pi/4, \pm 3\pi/4\}$ (in degrees,
+% $\{\pm 45, \pm 135\}$). Otherwise, one is much bigger than the
+% other, and we call \cs{@@_atan_inf_o:NNNw} with either an argument
+% of~$4$, leading to the values $\pm\pi/2$ (in degrees,~$\pm 90$),
+% or~$0$, leading to $\{\pm 0, \pm\pi\}$ (in degrees, $\{\pm 0,\pm
+% 180\}$). Since $\operatorname{acot}(x, y) = \atan(y, x)$,
+% \cs{@@_acotii_o:ww} simply reverses its two arguments.
+% \begin{macrocode}
+\cs_new:Npn \@@_atanii_o:Nww
+ #1 \s_@@ \@@_chk:w #2#3#4; \s_@@ \@@_chk:w #5
+ {
+ \if_meaning:w 3 #2 \@@_case_return_i_o:ww \fi:
+ \if_meaning:w 3 #5 \@@_case_return_ii_o:ww \fi:
+ \if_case:w
+ \if_meaning:w #2 #5
+ \if_meaning:w 1 #2 \c_ten \else: \c_zero \fi:
+ \else:
+ \if_int_compare:w #2 > #5 \c_one \else: \c_two \fi:
+ \fi:
+ \@@_case_return:nw { \@@_atan_inf_o:NNNw #1 #3 \c_two }
+ \or: \@@_case_return:nw { \@@_atan_inf_o:NNNw #1 #3 \c_four }
+ \or: \@@_case_return:nw { \@@_atan_inf_o:NNNw #1 #3 \c_zero }
+ \fi:
+ \@@_atan_normal_o:NNnwNnw #1
+ \s_@@ \@@_chk:w #2#3#4;
+ \s_@@ \@@_chk:w #5
+ }
+\cs_new:Npn \@@_acotii_o:Nww #1#2; #3;
+ { \@@_atanii_o:Nww #1#3; #2; }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_atan_inf_o:NNNw}
+% This auxiliary is called whenever one number is $\pm 0$ or
+% $\pm\infty$ (and neither is \nan{}). Then the result only depends
+% on the signs, and its value is a multiple of $\pi/4$. We use the
+% same auxiliary as for normal numbers,
+% \cs{@@_atan_combine_o:NwwwwwN}, with arguments the final sign~|#2|;
+% the octant~|#3|; $\atan z/z=1$ as a fixed point number; $z=0$~as a
+% fixed point number; and $z=0$~as an extended-precision number.
+% Given the values we provide, $\atan z$ will be computed to be~$0$,
+% and the result will be $[|#3|/2]\cdot\pi/4$ if the sign~|#5| of~$x$
+% is positive, and $[(7-|#3|)/2]\cdot\pi/4$ for negative~$x$, where
+% the divisions are rounded up.
+% \begin{macrocode}
+\cs_new:Npn \@@_atan_inf_o:NNNw #1#2#3 \s_@@ \@@_chk:w #4#5#6;
+ {
+ \exp_after:wN \@@_atan_combine_o:NwwwwwN
+ \exp_after:wN #2
+ \int_use:N \__int_eval:w
+ \if_meaning:w 2 #5 \c_seven - \fi: #3 \exp_after:wN ;
+ \c_@@_one_fixed_tl ;
+ {0000}{0000}{0000}{0000}{0000}{0000};
+ 0,{0000}{0000}{0000}{0000}{0000}{0000}; #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_atan_normal_o:NNnwNnw}
+% Here we simply reorder the floating point data into a pair of signed
+% extended-precision numbers, that is, a sign, an exponent ending with
+% a comma, and a six-block mantissa ending with a semi-colon. This
+% extended precision is required by other inverse trigonometric
+% functions, to compute things like $\atan(x,\sqrt{1-x^2})$ without
+% intermediate rounding errors.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_atan_normal_o:NNnwNnw
+ #1 \s_@@ \@@_chk:w 1#2#3#4; \s_@@ \@@_chk:w 1#5#6#7;
+ {
+ \@@_atan_test_o:NwwNwwN
+ #2 #3, #4{0000}{0000};
+ #5 #6, #7{0000}{0000}; #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_atan_test_o:NwwNwwN}
+% This receives: the sign~|#1| of~$y$, its exponent~|#2|, its $24$
+% digits~|#3| in groups of~$4$, and similarly for~$x$. We prepare to
+% call \cs{@@_atan_combine_o:NwwwwwN} which expects the sign~|#1|, the
+% octant, the ratio $(\atan z)/z = 1 - \cdots$, and the value of~$z$,
+% both as a fixed point number and as an extended-precision floating
+% point number with a mantissa in $[0.01,1)$. For now, we place |#1|
+% as a first argument, and start an integer expression for the octant.
+% The sign of $x$ does not affect what~$z$ will be, so we simply leave
+% a contribution to the octant: $\meta{octant} \to 7 - \meta{octant}$
+% for negative~$x$. Then we order $\lvert y\rvert$ and $\lvert
+% x\rvert$ in a non-decreasing order: if $\lvert y\rvert > \lvert
+% x\rvert$, insert $3-$ in the expression for the octant, and swap the
+% two numbers. The finer test with $0.41421$ is done by
+% \cs{@@_atan_div:wnwwnw} after the operands have been ordered.
+% \begin{macrocode}
+\cs_new:Npn \@@_atan_test_o:NwwNwwN #1#2,#3; #4#5,#6;
+ {
+ \exp_after:wN \@@_atan_combine_o:NwwwwwN
+ \exp_after:wN #1
+ \int_use:N \__int_eval:w
+ \if_meaning:w 2 #4
+ \c_seven - \__int_eval:w
+ \fi:
+ \if_int_compare:w
+ \@@_ep_compare:wwww #2,#3; #5,#6; > \c_zero
+ \c_three -
+ \exp_after:wN \@@_reverse_args:Nww
+ \fi:
+ \@@_atan_div:wnwwnw #2,#3; #5,#6;
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, rEXP]{\@@_atan_div:wnwwnw, \@@_atan_near:wwwn}
+% \begin{macro}[aux, EXP]{\@@_atan_near_aux:wwn}
+% This receives two positive numbers $a$ and~$b$ (equal to $\lvert
+% x\rvert$ and~$\lvert y\rvert$ in some order), each as an exponent
+% and $6$~blocks of $4$~digits, such that $0<a<b$. If $0.41421b<a$,
+% the two numbers are ``near'', hence the point $(y,x)$ that we
+% started with is closer to the diagonals $\{\lvert y\rvert = \lvert
+% x\rvert\}$ than to the axes $\{xy = 0\}$. In that case, the octant
+% is~$1$ (possibly combined with the $7-$ and $3-$ inserted earlier)
+% and we wish to compute $\atan\frac{b-a}{a+b}$. Otherwise, the
+% octant is~$0$ (again, combined with earlier terms) and we wish to
+% compute $\atan\frac{a}{b}$. In any case, call \cs{@@_atan_auxi:ww}
+% followed by~$z$, as a comma-delimited exponent and a fixed point
+% number.
+% \begin{macrocode}
+\cs_new:Npn \@@_atan_div:wnwwnw #1,#2#3; #4,#5#6;
+ {
+ \if_int_compare:w
+ \__int_eval:w 41421 * #5 < #2 000
+ \if_case:w \__int_eval:w #4 - #1 \__int_eval_end: 00 \or: 0 \fi:
+ \exp_stop_f:
+ \exp_after:wN \@@_atan_near:wwwn
+ \fi:
+ \c_zero
+ \@@_ep_div:wwwwn #1,{#2}#3; #4,{#5}#6;
+ \@@_atan_auxi:ww
+ }
+\cs_new:Npn \@@_atan_near:wwwn
+ \c_zero \@@_ep_div:wwwwn #1,#2; #3,
+ {
+ \c_one
+ \@@_ep_to_fixed:wwn #1 - #3, #2;
+ \@@_atan_near_aux:wwn
+ }
+\cs_new:Npn \@@_atan_near_aux:wwn #1; #2;
+ {
+ \@@_fixed_add:wwn #1; #2;
+ { \@@_fixed_sub:wwn #2; #1; { \@@_ep_div:wwwwn 0, } 0, }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_atan_auxi:ww, \@@_atan_auxii:w}
+% Convert~$z$ from a representation as an exponent and a fixed point
+% number in $[0.01,1)$ to a fixed point number only, then set up the
+% call to \cs{@@_atan_Taylor_loop:www}, followed by the fixed point
+% representation of~$z$ and the old representation.
+% \begin{macrocode}
+\cs_new:Npn \@@_atan_auxi:ww #1,#2;
+ { \@@_ep_to_fixed:wwn #1,#2; \@@_atan_auxii:w #1,#2; }
+\cs_new:Npn \@@_atan_auxii:w #1;
+ {
+ \@@_fixed_mul:wwn #1; #1;
+ {
+ \@@_atan_Taylor_loop:www 39 ;
+ {0000}{0000}{0000}{0000}{0000}{0000} ;
+ }
+ ! #1;
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]
+% {\@@_atan_Taylor_loop:www, \@@_atan_Taylor_break:w}
+% We compute the series of $(\atan z)/z$. A typical intermediate
+% stage has $|#1|=2k-1$, $|#2| =
+% \frac{1}{2k+1}-z^2(\frac{1}{2k+3}-z^2(\cdots-z^2\frac{1}{39}))$, and
+% $|#3|=z^2$. To go to the next step $k\to k-1$, we compute
+% $\frac{1}{2k-1}$, then subtract from it $z^2$ times |#2|. The loop
+% stops when $k=0$: then |#2| is $(\atan z)/z$, and there is a need to
+% clean up all the unnecessary data, end the integer expression
+% computing the octant with a semicolon, and leave the result~|#2|
+% afterwards.
+% \begin{macrocode}
+\cs_new:Npn \@@_atan_Taylor_loop:www #1; #2; #3;
+ {
+ \if_int_compare:w #1 = \c_minus_one
+ \@@_atan_Taylor_break:w
+ \fi:
+ \exp_after:wN \@@_fixed_div_int:wwN \c_@@_one_fixed_tl ; #1;
+ \@@_rrot:www \@@_fixed_mul_sub_back:wwwn #2; #3;
+ {
+ \exp_after:wN \@@_atan_Taylor_loop:www
+ \int_use:N \__int_eval:w #1 - \c_two ;
+ }
+ #3;
+ }
+\cs_new:Npn \@@_atan_Taylor_break:w
+ \fi: #1 \@@_fixed_mul_sub_back:wwwn #2; #3 !
+ { \fi: ; #2 ; }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]
+% {\@@_atan_combine_o:NwwwwwN, \@@_atan_combine_aux:ww}
+% This receives a \meta{sign}, an \meta{octant}, a fixed point value
+% of $(\atan z)/z$, a fixed point number~$z$, and another
+% representation of~$z$, as an \meta{exponent} and the fixed point
+% number $10^{-\meta{exponent}} z$, followed by either \cs{use_i:nn}
+% (when working in radians) or \cs{use_ii:nn} (when working in
+% degrees). The function computes the floating point result
+% \begin{equation}
+% \meta{sign} \left(
+% \left\lceil\frac{\meta{octant}}{2}\right\rceil
+% \frac{\pi}{4}
+% + (-1)^{\meta{octant}} \frac{\atan z}{z} \cdot z\right) \,,
+% \end{equation}
+% multiplied by $180/\pi$ if working in degrees, and using in any case
+% the most appropriate representation of~$z$. The floating point
+% result is passed to \cs{@@_sanitize:Nw}, which checks for overflow
+% or underflow. If the octant is~$0$, leave the exponent~|#5| for
+% \cs{@@_sanitize:Nw}, and multiply $|#3|=\frac{\atan z}{z}$
+% with~|#6|, the adjusted~$z$. Otherwise, multiply $|#3|=\frac{\atan
+% z}{z}$ with $|#4|=z$, then compute the appropriate multiple of
+% $\frac{\pi}{4}$ and add or subtract the product $|#3|\cdot|#4|$. In
+% both cases, convert to a floating point with
+% \cs{@@_fixed_to_float:wN}.
+% \begin{macrocode}
+\cs_new:Npn \@@_atan_combine_o:NwwwwwN #1 #2; #3; #4; #5,#6; #7
+ {
+ \exp_after:wN \@@_sanitize:Nw
+ \exp_after:wN #1
+ \int_use:N \__int_eval:w
+ \if_meaning:w 0 #2
+ \exp_after:wN \use_i:nn
+ \else:
+ \exp_after:wN \use_ii:nn
+ \fi:
+ { #5 \@@_fixed_mul:wwn #3; #6; }
+ {
+ \@@_fixed_mul:wwn #3; #4;
+ {
+ \exp_after:wN \@@_atan_combine_aux:ww
+ \int_use:N \__int_eval:w #2 / \c_two ; #2;
+ }
+ }
+ { #7 \@@_fixed_to_float:wN \@@_fixed_to_float_rad:wN }
+ #1
+ }
+\cs_new:Npn \@@_atan_combine_aux:ww #1; #2;
+ {
+ \@@_fixed_mul_short:wwn
+ {7853}{9816}{3397}{4483}{0961}{5661};
+ {#1}{0000}{0000};
+ {
+ \if_int_odd:w #2 \exp_stop_f:
+ \exp_after:wN \@@_fixed_sub:wwn
+ \else:
+ \exp_after:wN \@@_fixed_add:wwn
+ \fi:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Arcsine and arccosine}
+%
+% \begin{macro}[int, EXP]{\@@_asin_o:w}
+% Again, the first argument provided by \pkg{l3fp-parse} is
+% \cs{use_i:nn} if we are to work in radians and \cs{use_ii:nn} for
+% degrees. Then comes a floating point number. The arcsine of $\pm
+% 0$ or \nan{} is the same floating point number. The arcsine of
+% $\pm\infty$ raises an invalid operation exception. Otherwise, call
+% an auxiliary common with \cs{@@_acos_o:w}, feeding it information
+% about what function is being performed (for ``invalid operation''
+% exceptions).
+% \begin{macrocode}
+\cs_new:Npn \@@_asin_o:w #1 \s_@@ \@@_chk:w #2#3; @
+ {
+ \if_case:w #2 \exp_stop_f:
+ \@@_case_return_same_o:w
+ \or:
+ \@@_case_use:nw
+ { \@@_asin_normal_o:NfwNnnnnw #1 { #1 { asin } { asind } } }
+ \or:
+ \@@_case_use:nw
+ { \@@_invalid_operation_o:fw { #1 { asin } { asind } } }
+ \else:
+ \@@_case_return_same_o:w
+ \fi:
+ \s_@@ \@@_chk:w #2 #3;
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int, EXP]{\@@_acos_o:w}
+% The arccosine of $\pm 0$ is $\pi / 2$ (in degrees,~$90$). The
+% arccosine of $\pm\infty$ raises an invalid operation exception. The
+% arccosine of \nan{} is itself. Otherwise, call an auxiliary common
+% with \cs{@@_sin_o:w}, informing it that it was called by
+% \texttt{acos} or \texttt{acosd}, and preparing to swap some
+% arguments down the line.
+% \begin{macrocode}
+\cs_new:Npn \@@_acos_o:w #1 \s_@@ \@@_chk:w #2#3; @
+ {
+ \if_case:w #2 \exp_stop_f:
+ \@@_case_use:nw { \@@_atan_inf_o:NNNw #1 0 \c_four }
+ \or:
+ \@@_case_use:nw
+ {
+ \@@_asin_normal_o:NfwNnnnnw #1 { #1 { acos } { acosd } }
+ \@@_reverse_args:Nww
+ }
+ \or:
+ \@@_case_use:nw
+ { \@@_invalid_operation_o:fw { #1 { acos } { acosd } } }
+ \else:
+ \@@_case_return_same_o:w
+ \fi:
+ \s_@@ \@@_chk:w #2 #3;
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_asin_normal_o:NfwNnnnnw}
+% If the exponent~|#5| is strictly less than~$1$, the operand lies
+% within $(-1,1)$ and the operation is permitted: call
+% \cs{@@_asin_auxi_o:nNww} with the appropriate arguments. If the
+% number is exactly~$\pm 1$ (the test works because we know that
+% $|#5|\geq 1$, $|#6#7|\geq 10000000$, $|#8#9|\geq 0$, with equality
+% only for $\pm 1$), we also call \cs{@@_asin_auxi_o:nNww}.
+% Otherwise, \cs{@@_use_i:ww} gets rid of the \texttt{asin} auxiliary,
+% and raises instead an invalid operation, because the operand is
+% outside the domain of arcsine or arccosine.
+% \begin{macrocode}
+\cs_new:Npn \@@_asin_normal_o:NfwNnnnnw
+ #1#2#3 \s_@@ \@@_chk:w 1#4#5#6#7#8#9;
+ {
+ \if_int_compare:w #5 < \c_one
+ \exp_after:wN \@@_use_none_until_s:w
+ \fi:
+ \if_int_compare:w \__int_eval:w #5 + #6#7 + #8#9 = 1000 0001 ~
+ \exp_after:wN \@@_use_none_until_s:w
+ \fi:
+ \@@_use_i:ww
+ \@@_invalid_operation_o:fw {#2}
+ \s_@@ \@@_chk:w 1#4{#5}{#6}{#7}{#8}{#9};
+ \@@_asin_auxi_o:NnNww
+ #1 {#3} #4 #5,{#6}{#7}{#8}{#9}{0000}{0000};
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_asin_auxi_o:NnNww, \@@_asin_isqrt:wn}
+% We compute $x/\sqrt{1-x^2}$. This function is used by \texttt{asin}
+% and \texttt{acos}, but also by \texttt{acsc} and \texttt{asec} after
+% inverting the operand, thus it must manipulate extended-precision
+% numbers. First evaluate $1-x^2$ as $(1+x)(1-x)$: this behaves
+% better near~$x=1$. We do the addition/subtraction with fixed point
+% numbers (they are not implemented for extended-precision floats),
+% but go back to extended-precision floats to multiply and compute the
+% inverse square root $1/\sqrt{1-x^2}$. Finally, multiply by the
+% (positive) extended-precision float $\lvert x\rvert$, and feed the
+% (signed) result, and the number~$+1$, as arguments to the arctangent
+% function. When computing the arccosine, the arguments
+% $x/\sqrt{1-x^2}$ and~$+1$ are swapped by~|#2|
+% (\cs{@@_reverse_args:Nww} in that case) before
+% \cs{@@_atan_test_o:NwwNwwN} is evaluated. Note that the arctangent
+% function requires normalized arguments, hence the need for
+% \texttt{ep_to_ep} and \texttt{continue} after \texttt{ep_mul}.
+% \begin{macrocode}
+\cs_new:Npn \@@_asin_auxi_o:NnNww #1#2#3#4,#5;
+ {
+ \@@_ep_to_fixed:wwn #4,#5;
+ \@@_asin_isqrt:wn
+ \@@_ep_mul:wwwwn #4,#5;
+ \@@_ep_to_ep:wwN
+ \@@_fixed_continue:wn
+ { #2 \@@_atan_test_o:NwwNwwN #3 }
+ 0 1,{1000}{0000}{0000}{0000}{0000}{0000}; #1
+ }
+\cs_new:Npn \@@_asin_isqrt:wn #1;
+ {
+ \exp_after:wN \@@_fixed_sub:wwn \c_@@_one_fixed_tl ; #1;
+ {
+ \@@_fixed_add_one:wN #1;
+ \@@_fixed_continue:wn { \@@_ep_mul:wwwwn 0, } 0,
+ }
+ \@@_ep_isqrt:wwn
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Arccosecant and arcsecant}
+%
+% \begin{macro}[int, EXP]{\@@_acsc_o:w}
+% Cases are mostly labelled by~|#2|, except when |#2| is~$2$: then we
+% use |#3#2|, which is $02=2$ when the number is $+\infty$ and
+% $22$~when the number is $-\infty$. The arccosecant of $\pm 0$
+% raises an invalid operation exception. The arccosecant of
+% $\pm\infty$ is $\pm 0$ with the same sign. The arcosecant of \nan{}
+% is itself. Otherwise, \cs{@@_acsc_normal_o:NfwNnw} does some more
+% tests, keeping the function name (\texttt{acsc} or \texttt{acscd})
+% as an argument for invalid operation exceptions.
+% \begin{macrocode}
+\cs_new:Npn \@@_acsc_o:w #1 \s_@@ \@@_chk:w #2#3#4; @
+ {
+ \if_case:w \if_meaning:w 2 #2 #3 \fi: #2 \exp_stop_f:
+ \@@_case_use:nw
+ { \@@_invalid_operation_o:fw { #1 { acsc } { acscd } } }
+ \or: \@@_case_use:nw
+ { \@@_acsc_normal_o:NfwNnw #1 { #1 { acsc } { acscd } } }
+ \or: \@@_case_return_o:Nw \c_zero_fp
+ \or: \@@_case_return_same_o:w
+ \else: \@@_case_return_o:Nw \c_minus_zero_fp
+ \fi:
+ \s_@@ \@@_chk:w #2 #3 #4;
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int, EXP]{\@@_asec_o:w}
+% The arcsecant of $\pm 0$ raises an invalid operation exception. The
+% arcsecant of $\pm\infty$ is $\pi / 2$ (in degrees,~$90$). The
+% arcosecant of \nan{} is itself. Otherwise, do some more tests,
+% keeping the function name \texttt{asec} (or \texttt{asecd}) as an
+% argument for invalid operation exceptions, and a
+% \cs{@@_reverse_args:Nww} following precisely that appearing in
+% \cs{@@_acos_o:w}.
+% \begin{macrocode}
+\cs_new:Npn \@@_asec_o:w #1 \s_@@ \@@_chk:w #2#3; @
+ {
+ \if_case:w #2 \exp_stop_f:
+ \@@_case_use:nw
+ { \@@_invalid_operation_o:fw { #1 { asec } { asecd } } }
+ \or:
+ \@@_case_use:nw
+ {
+ \@@_acsc_normal_o:NfwNnw #1 { #1 { asec } { asecd } }
+ \@@_reverse_args:Nww
+ }
+ \or: \@@_case_use:nw { \@@_atan_inf_o:NNNw #1 0 \c_four }
+ \else: \@@_case_return_same_o:w
+ \fi:
+ \s_@@ \@@_chk:w #2 #3;
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_acsc_normal_o:NfwNnw}
+% If the exponent is non-positive, the operand is less than~$1$ in
+% absolute value, which is always an invalid operation: complain.
+% Otherwise, compute the inverse of the operand, and feed it to
+% \cs{@@_asin_auxi_o:nNww} (with all the appropriate arguments). This
+% computes what we want thanks to
+% $\operatorname{acsc}(x)=\operatorname{asin}(1/x)$ and
+% $\operatorname{asec}(x)=\operatorname{acos}(1/x)$.
+% \begin{macrocode}
+\cs_new:Npn \@@_acsc_normal_o:NfwNnw #1#2#3 \s_@@ \@@_chk:w 1#4#5#6;
+ {
+ \int_compare:nNnTF {#5} < \c_one
+ {
+ \@@_invalid_operation_o:fw {#2}
+ \s_@@ \@@_chk:w 1#4{#5}#6;
+ }
{
- \@@_fixed_mul_sub_back:wwwn {0000}{0007}{0258}{0681}{9408}{4706};
- #3; {0000}{2343}{7175}{1399}{6151}{7670};
- \@@_fixed_mul_sub_back:wwwn #3; {0019}{2638}{4588}{9232}{8861}{3691};
- \@@_fixed_mul_sub_back:wwwn #3; {0536}{6357}{0691}{4344}{6852}{4252};
- \@@_fixed_mul_sub_back:wwwn #3; {5263}{1578}{9473}{6842}{1052}{6315};
- \@@_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000};
- {
- \exp_after:wN \@@_sanitize:Nw
- \exp_after:wN #1
- \int_use:N \__int_eval:w
- \reverse_if:N \if_int_odd:w
- \__int_eval:w (#2 - \c_one) / \c_two \__int_eval_end:
- \exp_after:wN \@@_reverse_args:Nww
- \fi:
- \@@_fixed_div_to_float:ww
- }
+ \@@_ep_div:wwwwn
+ 1,{1000}{0000}{0000}{0000}{0000}{0000};
+ #5,#6{0000}{0000};
+ { \@@_asin_auxi_o:NnNww #1 {#3} #4 }
}
}
% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
index d4f0a435ec9..dc000923765 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3fp.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -36,7 +36,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3fp.dtx 4521 2013-07-09 11:45:31Z joseph $
+\GetIdInfo$Id: l3fp.dtx 4601 2013-11-18 23:13:28Z bruno $
{L3 Floating points}
%</driver|package>
%<*driver>
@@ -91,11 +91,19 @@
% operator $x\mathop{?}y\mathop{:}z$.
% \item Exponentials: $\exp x$, $\ln x$, $x^y$.
% \item Trigonometry: $\sin x$, $\cos x$, $\tan x$, $\cot x$, $\sec
-% x$, $\csc x$.
-% \item [\emph{(not yet)}] Inverse trigonometric functions:
-% $\operatorname{asin} x$, $\operatorname{acos} x$,
-% $\operatorname{atan} x$, $\operatorname{acot} x$,
-% $\operatorname{asec} x$, $\operatorname{acsc} x$.
+% x$, $\csc x$ expecting their arguments in radians, and
+% $\operatorname{sind} x$, $\operatorname{cosd} x$,
+% $\operatorname{tand} x$, $\operatorname{cotd} x$,
+% $\operatorname{secd} x$, $\operatorname{cscd} x$ expecting their
+% arguments in degrees.
+% \item Inverse trigonometric functions: $\operatorname{asin} x$,
+% $\operatorname{acos} x$, $\operatorname{atan} x$,
+% $\operatorname{acot} x$, $\operatorname{asec} x$,
+% $\operatorname{acsc} x$ giving a result in radians, and
+% $\operatorname{asind} x$, $\operatorname{acosd} x$,
+% $\operatorname{atand} x$, $\operatorname{acotd} x$,
+% $\operatorname{asecd} x$, $\operatorname{acscd} x$ giving a result
+% in degrees.
% \item [\emph{(not yet)}] Hyperbolic functions and their inverse
% functions: $\sinh x$, $\cosh x$, $\tanh x$, $\coth x$,
% $\operatorname{sech} x$, $\operatorname{csch}$, and
@@ -490,7 +498,7 @@
% \begin{variable}[added = 2012-05-08]{\c_zero_fp, \c_minus_zero_fp}
% Zero, with either sign.
% \end{variable}
-%
+%
% \begin{variable}[added = 2012-05-08]{\c_one_fp}
% One as an \texttt{fp}: useful for comparisons in some places.
% \end{variable}
@@ -504,18 +512,18 @@
% The value of the base of the natural logarithm, $\mathrm{e} = \exp(1)$.
% \end{variable}
%
-% \begin{variable}[updated = 2012-05-08]{\c_pi_fp}
+% \begin{variable}[updated = 2012-05-08, updated = 2013-11-17]{\c_pi_fp}
% The value of $\pi$. This can be input directly in a floating point
-% expression as \texttt{pi}. The value is rounded in a slightly odd
-% way, to ensure for instance that \texttt{sin(pi)} yields an exact $0$.
+% expression as \texttt{pi}.
% \end{variable}
%
-% \begin{variable}[added = 2012-05-08]{\c_one_degree_fp}
+% \begin{variable}[added = 2012-05-08, updated = 2013-11-17]
+% {\c_one_degree_fp}
% The value of $1^{\circ}$ in radians. Multiply an angle given in
-% degrees by this value to obtain a result in radians, suitable to be
-% used for trigonometric functions. Within floating point
-% expressions, this can be accessed as \texttt{deg}. Note that
-% \texttt{180 deg = pi} exactly.
+% degrees by this value to obtain a result in radians. Note that
+% trigonometric functions expecting an argument in radians or in
+% degrees are both available. Within floating point expressions, this
+% can be accessed as \texttt{deg}.
% \end{variable}
%
% \begin{variable}{\l_tmpa_fp, \l_tmpb_fp}
@@ -711,7 +719,8 @@
% expressions, in order of decreasing precedence: operations listed
% earlier bind more tightly than operations listed below them.
% \begin{itemize}
-% \item Implicit multiplication by juxtaposition (\texttt{2pi}, \emph{etc}).
+% \item Implicit multiplication by juxtaposition (\texttt{2pi},
+% \texttt{3(4+5)}, \emph{etc}).
% \item Function calls (\texttt{sin}, \texttt{ln}, \emph{etc}).
% \item Binary |**| and |^| (right associative).
% \item Unary |+|, |-|, |!|.
@@ -907,7 +916,8 @@
% (this cannot happen unless $\meta{fpexpr_2}\string<-9984$).
% \end{function}
%
-% \begin{function}[tested = m3fp-trig001]{sin, cos, tan, cot, csc, sec}
+% \begin{function}[updated = 2013-11-17, tested = m3fp-trig001]
+% {sin, cos, tan, cot, csc, sec}
% \begin{syntax}
% \cs{fp_eval:n} \{ |sin(| \meta{fpexpr} |)| \}
% \cs{fp_eval:n} \{ |cos(| \meta{fpexpr} |)| \}
@@ -917,7 +927,34 @@
% \cs{fp_eval:n} \{ |sec(| \meta{fpexpr} |)| \}
% \end{syntax}
% Computes the sine, cosine, tangent, cotangent, cosecant, or secant
-% of the \meta{fpexpr}. The trigonometric functions are undefined for
+% of the \meta{fpexpr} given in radians. For arguments given in
+% degrees, see \texttt{sind}, \texttt{cosd}, \emph{etc.} Note that
+% since $\pi$~is irrational, $\operatorname{sin}(8pi)$ is not quite
+% zero, while its analog $\operatorname{sind}(8\times 180)$ is exactly
+% zero. The trigonometric functions are undefined for
+% an argument of $\pm\infty$, leading to the \enquote{invalid
+% operation} exception. Additionally, evaluating tangent,
+% cotangent, cosecant, or secant at one of their poles leads to a
+% \enquote{division by zero} exception. \enquote{Underflow} and
+% \enquote{overflow} occur when appropriate.
+% \end{function}
+%
+% \begin{function}[added = 2013-11-02, tested = m3fp-trig003]
+% {sind, cosd, tand, cotd, cscd, secd}
+% \begin{syntax}
+% \cs{fp_eval:n} \{ |sind(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |cosd(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |tand(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |cotd(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |cscd(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |secd(| \meta{fpexpr} |)| \}
+% \end{syntax}
+% Computes the sine, cosine, tangent, cotangent, cosecant, or secant
+% of the \meta{fpexpr} given in degrees. For arguments given in
+% radians, see \texttt{sin}, \texttt{cos}, \emph{etc.} Note that
+% since $\pi$~is irrational, $\operatorname{sin}(8pi)$ is not quite
+% zero, while its analog $\operatorname{sind}(8\times 180)$ is exactly
+% zero. The trigonometric functions are undefined for
% an argument of $\pm\infty$, leading to the \enquote{invalid
% operation} exception. Additionally, evaluating tangent,
% cotangent, cosecant, or secant at one of their poles leads to a
@@ -925,6 +962,102 @@
% \enquote{overflow} occur when appropriate.
% \end{function}
%
+% \begin{function}[added = 2013-11-02, tested = m3fp-trig002]
+% {asin, acos, acsc, asec}
+% \begin{syntax}
+% \cs{fp_eval:n} \{ |asin(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |acos(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |acsc(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |asec(| \meta{fpexpr} |)| \}
+% \end{syntax}
+% Computes the arcsine, arccosine, arccosecant, or arcsecant of the
+% \meta{fpexpr} and returns the result in radians, in the range
+% $[-\pi/2,\pi/2]$ for \texttt{asin} and \texttt{acsc} and $[0,\pi]$
+% for \texttt{acos} and \texttt{asec}. For a result in degrees, use
+% \texttt{asind}, \emph{etc.} If the argument of |asin| or |acos|
+% lies outside the range $[-1,1]$, or the argument of |acsc| or |asec|
+% inside the range $(-1,1)$, an \enquote{invalid operation} exception
+% is raised. \enquote{Underflow} and \enquote{overflow} occur when
+% appropriate.
+% \end{function}
+%
+% \begin{function}[added = 2013-11-02, tested = m3fp-trig004]
+% {asind, acosd, acscd, asecd}
+% \begin{syntax}
+% \cs{fp_eval:n} \{ |asind(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |acosd(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |acscd(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |asecd(| \meta{fpexpr} |)| \}
+% \end{syntax}
+% Computes the arcsine, arccosine, arccosecant, or arcsecant of the
+% \meta{fpexpr} and returns the result in degrees, in the range
+% $[-90,90]$ for \texttt{asin} and \texttt{acsc} and $[0,180]$ for
+% \texttt{acos} and \texttt{asec}. For a result in radians, use
+% \texttt{asin}, \emph{etc.} If the argument of |asin| or |acos| lies
+% outside the range $[-1,1]$, or the argument of |acsc| or |asec|
+% inside the range $(-1,1)$, an \enquote{invalid operation} exception
+% is raised. \enquote{Underflow} and \enquote{overflow} occur when
+% appropriate.
+% \end{function}
+%
+% \begin{function}[added = 2013-11-02, tested = m3fp-trig002]
+% {atan, acot}
+% \begin{syntax}
+% \cs{fp_eval:n} \{ |atan(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |atan(| \meta{fpexpr_1} , \meta{fpexpr_2} |)| \}
+% \cs{fp_eval:n} \{ |acot(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |acot(| \meta{fpexpr_1} , \meta{fpexpr_2} |)| \}
+% \end{syntax}
+% Those functions yield an angle in radians: \texttt{atand} and
+% \texttt{acotd} are their analogs in degrees. The one-argument
+% versions compute the arctangent or arccotangent of the
+% \meta{fpexpr}: arctangent takes values in the range
+% $[-\pi/2,\pi/2]$, and arccotangent in the range $[0,\pi]$. The
+% two-argument arctangent computes the angle in polar coordinates of
+% the point with Cartesian coordinates $(\meta{fpexpr_2},
+% \meta{fpexpr_1})$: this is the arctangent of
+% $\meta{fpexpr_1}/\meta{fpexpr_2}$, possibly shifted by~$\pi$
+% depending on the signs of \meta{fpexpr_1} and \meta{fpexpr_2}. The
+% two-argument arccotangent computes the angle in polar coordinates of
+% the point $(\meta{fpexpr_1}, \meta{fpexpr_2})$, equal to the
+% arccotangent of $\meta{fpexpr_1}/\meta{fpexpr_2}$, possibly shifted
+% by~$\pi$. Both two-argument functions take values in the wider
+% range $[-\pi,\pi]$. The ratio $\meta{fpexpr_1}/\meta{fpexpr_2}$
+% need not be defined for the two-argument arctangent: when both
+% expressions yield~$\pm 0$, or when both yield~$\pm\infty$, the
+% resulting angle is one of $\{\pm\pi/4,\pm 3\pi/4\}$ depending on
+% signs. Only the \enquote{underflow} exception can occur.
+% \end{function}
+%
+% \begin{function}[added = 2013-11-02, tested = m3fp-trig004]
+% {atand, acotd}
+% \begin{syntax}
+% \cs{fp_eval:n} \{ |atand(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |atand(| \meta{fpexpr_1} , \meta{fpexpr_2} |)| \}
+% \cs{fp_eval:n} \{ |acotd(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |acotd(| \meta{fpexpr_1} , \meta{fpexpr_2} |)| \}
+% \end{syntax}
+% Those functions yield an angle in degrees: \texttt{atand} and
+% \texttt{acotd} are their analogs in radians. The one-argument
+% versions compute the arctangent or arccotangent of the
+% \meta{fpexpr}: arctangent takes values in the range $[-90,90]$, and
+% arccotangent in the range $[0,180]$. The two-argument arctangent
+% computes the angle in polar coordinates of the point with Cartesian
+% coordinates $(\meta{fpexpr_2}, \meta{fpexpr_1})$: this is the
+% arctangent of $\meta{fpexpr_1}/\meta{fpexpr_2}$, possibly shifted
+% by~$180$ depending on the signs of \meta{fpexpr_1} and
+% \meta{fpexpr_2}. The two-argument arccotangent computes the angle
+% in polar coordinates of the point $(\meta{fpexpr_1},
+% \meta{fpexpr_2})$, equal to the arccotangent of
+% $\meta{fpexpr_1}/\meta{fpexpr_2}$, possibly shifted by~$180$. Both
+% two-argument functions take values in the wider range $[-180,180]$.
+% The ratio $\meta{fpexpr_1}/\meta{fpexpr_2}$ need not be defined for
+% the two-argument arctangent: when both expressions yield~$\pm 0$, or
+% when both yield~$\pm\infty$, the resulting angle is one of $\{\pm
+% 45,\pm 135\}$ depending on signs. Only the \enquote{underflow}
+% exception can occur.
+% \end{function}
+%
% \begin{variable}[tested = m3fp-parse001]{inf, nan}
% The special values $+\infty$, $-\infty$, and \nan{} are represented
% as \texttt{inf}, \texttt{-inf} and \texttt{nan} (see \cs{c_inf_fp},
@@ -1004,22 +1137,16 @@
%
% \section{Disclaimer and roadmap}
%
-% The package may break down if:
-% \begin{itemize}
-% \item the escape character is either a digit, or an underscore,
-% \item the \tn{uccodes} are changed: the test for whether a character
-% is a letter actually tests if the upper-case code of the character
-% is between A and Z.
-% \end{itemize}
+% The package may break down if the escape character is among
+% |0123456789_+|; if it receives a \TeX{} primitive conditional affected
+% by \cs{exp_not:N}.
%
% The following need to be done. I'll try to time-order the items.
% \begin{itemize}
+% \item Rename |round0| to |trunc|, |round+| to |ceil|, and |round-|
+% to |floor|.
% \item Decide what exponent range to consider.
-% \item Change the internal representation of fp, by replacing braced
-% groups of $4$ digits by delimited arguments. Also consider
-% changing the fp structure a bit to allow using
-% \cs{pdftex_strcmp:D} to compare (not in \LuaTeX{}: it is too
-% slow)?
+% \item Improve the treatment of signalling versus quiet \texttt{nan}.
% \item Modulo and remainder, and rounding functions |quantize|,
% |quantize0|, |quantize+|, |quantize-|, |quantize=|, |round=|.
% Should the modulo also be provided as (catcode 12) |%|?
@@ -1027,14 +1154,9 @@
% \meta{format} be? More general pretty printing?
% \item Add |and|, |or|, |xor|? Perhaps under the names \texttt{all},
% \texttt{any}, and \texttt{xor}?
-% \item Add \texttt{csc} and \texttt{sec}.
% \item Add $\log(x,b)$ for logarithm of $x$ in base $b$.
-% \item \texttt{hypot} (Euclidean length) and
-% $\operatorname{atan}(x,y) = \operatorname{atan}(x/y)$,
-% also called \texttt{atan2} in other math packages.
-% Cartesian-to-polar transform. Other inverse trigonometric functions
-% \texttt{acos}, \texttt{asin}, \texttt{atan} (one and two arguments).
-% Also \texttt{asec}, \texttt{acsc}?
+% \item \texttt{hypot} (Euclidean length).
+% Cartesian-to-polar transform.
% \item Hyperbolic functions \texttt{cosh}, \texttt{sinh}, \texttt{tanh}.
% \item Inverse hyperbolics.
% \item Base conversion, input such as \texttt{0xAB.CDEF}.
@@ -1045,42 +1167,37 @@
% series.
% \item Treat upper and lower case letters identically in
% identifiers, and ignore underscores.
-% \item Parse $-3<-2<-1$ as it should, not $(-3<-2)<-1$.
% \item Add an |array(1,2,3)| and |i=complex(0,1)|.
% \item Provide an experimental |map| function? Perhaps easier to
% implement if it is a single character, |@sin(1,2)|?
% \item Provide \cs{fp_if_nan:nTF}, and an |isnan| function?
+% \item Support keyword arguments?
% \end{itemize}
% \pkg{Pgfmath} also provides box-measurements (depth, height, width), but
% boxes are not possible expandably.
%
% Bugs. (Exclamation points mark important bugs.)
% \begin{itemize}
-% \item[!] Some functions are not monotonic when they should. For
-% instance, $\sin(1-10^{-16})$ is wrongly greater than $\sin(1)$.
+% \item[!] $-3<-2<-1$ is wrongly parsed as $(-3<-2)<-1$.
+% \item Check that functions are monotonic when they should.
% \item Add exceptions to |?:|, |!<=>?|, |&&|, \verb"||", and |!|.
% \item |round| should accept any integer as its second argument.
% \item Logarithms of numbers very close to $1$ are inaccurate.
-% \item \texttt{tan} and \texttt{cot} give very slightly wrong results
-% for arguments near $10^{-8}$.
% \item When rounding towards $-\infty$, |\dim_to_fp:n {0pt}| should
% return $-0$, not $+0$.
% \item The result of $(\pm0)+(\pm0)$ should depend on the rounding
% mode.
% \item \texttt{0e9999999999} gives a \TeX{} \enquote{number too
% large} error.
-% \item Conversion to integers with \cs{fp_to_int:n} does not check
-% for overflow.
% \item Subnormals are not implemented.
-% \item |max(-inf)| will lose any information attached to this |-inf|.
% \item The overflow trap receives the wrong argument in
% \pkg{l3fp-expo} (see |exp(1e5678)| in \file{m3fp-traps001}).
% \end{itemize}
%
% Possible optimizations/improvements.
% \begin{itemize}
-% \item Optimize argument reduction for trigonometric functions: we
-% don't need $6\times 4$ digits here, only $4\times 4$.
+% \item Document that \pkg{l3trial/l3fp-types} introduces tools for
+% adding new types.
% \item In subsection~\ref{sec:l3fp:fp-floats}, write a grammar.
% \item Fix the |TWO BARS| business with the index.
% \item It would be nice if the \texttt{parse} auxiliaries for each
@@ -1096,8 +1213,7 @@
% could be made to use a $5$ terms Taylor series instead of $10$
% terms by taking $c = 2000/(\lfloor 200x\rfloor +1) \in [10,95]$
% instead of $c\in [1,10]$. Also, it would then be possible to
-% simplify the computation of $t$, using methods similar to
-% \cs{__fp_fixed_div_to_float:ww}. However, we would then have to
+% simplify the computation of $t$. However, we would then have to
% hard-code the logarithms of $44$ small integers instead of $9$.
% \item Improve notations in the explanations of the division
% algorithm (\pkg{l3fp-basics}).
@@ -1110,6 +1226,15 @@
% \item Add bibliography. Some of Kahan's articles, some previous
% \TeX{} fp packages, the international standards,\ldots{}
% \item Also take into account the \enquote{inexact} exception?
+% \item (Likely not.)
+% Change the internal representation of fp, by replacing braced
+% groups of $4$ digits by delimited arguments. Also consider
+% changing the fp structure a bit to allow using
+% \cs{pdftex_strcmp:D} to compare (not in \LuaTeX{}: it is too
+% slow)?
+% \item Support multi-character prefix operators (\emph{e.g.}, |@/| or
+% whatever)? Perhaps for including comments inside the computation
+% itself??
% \end{itemize}
%
% \end{documentation}
diff --git a/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx b/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx
index 4aec4ad1aa8..fbc01946956 100644
--- a/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx
+++ b/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx
@@ -37,8 +37,8 @@
%<*driver|package>
% The version of expl3 required is tested as early as possible, as
% some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2013/10/13]
-%<package>\@ifpackagelater{expl3}{2013/10/13}
+\RequirePackage{expl3}[2013/11/19]
+%<package>\@ifpackagelater{expl3}{2013/11/19}
%<package> {}
%<package> {%
%<package> \PackageError{l3keys2e}{Support package l3kernel too old}
@@ -50,7 +50,7 @@
%<package> }%
%<package> \endinput
%<package> }
-\GetIdInfo$Id: l3keys2e.dtx 4597 2013-10-13 21:44:53Z joseph $
+\GetIdInfo$Id: l3keys2e.dtx 4608 2013-11-19 15:52:24Z joseph $
{LaTeX2e option processing using LaTeX3 keys}
%</driver|package>
%<*driver>
diff --git a/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx b/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx
index 17472c2b273..8c088950b7e 100644
--- a/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx
+++ b/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx
@@ -41,8 +41,8 @@
%<*driver|package>
% The version of expl3 required is tested as early as possible, as
% some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2013/10/13]
-%<package>\@ifpackagelater{expl3}{2013/10/13}
+\RequirePackage{expl3}[2013/11/19]
+%<package>\@ifpackagelater{expl3}{2013/11/19}
%<package> {}
%<package> {%
%<package> \PackageError{xparse}{Support package l3kernel too old}
@@ -54,7 +54,7 @@
%<package> }%
%<package> \endinput
%<package> }
-\GetIdInfo$Id: xparse.dtx 4597 2013-10-13 21:44:53Z joseph $
+\GetIdInfo$Id: xparse.dtx 4609 2013-11-19 16:01:54Z joseph $
{L3 Experimental document command parser}
%</driver|package>
%<*driver>
diff --git a/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx b/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx
index b7062236d8b..7a90562f543 100644
--- a/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx
+++ b/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx
@@ -41,8 +41,8 @@
%<*driver|package>
% The version of expl3 required is tested as early as possible, as
% some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2013/10/13]
-%<package>\@ifpackagelater{expl3}{2013/10/13}
+\RequirePackage{expl3}[2013/11/19]
+%<package>\@ifpackagelater{expl3}{2013/11/19}
%<package> {}
%<package> {%
%<package> \PackageError{xtemplate}{Support package l3kernel too old}
@@ -54,7 +54,7 @@
%<package> }%
%<package> \endinput
%<package> }
-\GetIdInfo$Id: xtemplate.dtx 4597 2013-10-13 21:44:53Z joseph $
+\GetIdInfo$Id: xtemplate.dtx 4608 2013-11-19 15:52:24Z joseph $
{L3 Experimental prototype document functions}
%</driver|package>
%<*driver>
diff --git a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-format.sty b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-format.sty
index 0cdd5c2bbcf..868fef6ab5f 100644
--- a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-format.sty
+++ b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str-format.sty
@@ -454,7 +454,7 @@
{ \fp_to_scientific:n }
{ \fp_to_decimal:n }
}
- { \__fp_abs_o:w #1; \prg_do_nothing: }
+ { \__fp_set_sign_o:w 0 #1; @ \prg_do_nothing: }
}
\__msg_kernel_new:nnn { str } { invalid-format }
{ Invalid~format~'#1'. }
diff --git a/Master/texmf-dist/tex/latex/l3kernel/expl3.sty b/Master/texmf-dist/tex/latex/l3kernel/expl3.sty
index 54e7db0da47..3ac782837f7 100644
--- a/Master/texmf-dist/tex/latex/l3kernel/expl3.sty
+++ b/Master/texmf-dist/tex/latex/l3kernel/expl3.sty
@@ -60,8 +60,8 @@
}
\def\ExplFileName{expl3}
\def\ExplFileDescription{L3 Experimental code bundle wrapper}
-\def\ExplFileDate{2013/10/13}
-\def\ExplFileVersion{4597}
+\def\ExplFileDate{2013/11/19}
+\def\ExplFileVersion{4610}
\RequirePackage{etex}
\relax
\reserveinserts{32}
diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3candidates.sty b/Master/texmf-dist/tex/latex/l3kernel/l3candidates.sty
index 4288b0d5288..fce554e38d6 100644
--- a/Master/texmf-dist/tex/latex/l3kernel/l3candidates.sty
+++ b/Master/texmf-dist/tex/latex/l3kernel/l3candidates.sty
@@ -47,7 +47,7 @@
%% -----------------------------------------------------------------------
%%
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3candidates.dtx 4576 2013-07-24 21:40:24Z joseph $
+\GetIdInfo$Id: l3candidates.dtx 4602 2013-11-18 23:19:01Z bruno $
{L3 Experimental additions to l3kernel}
\ProvidesExplPackage
{\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
@@ -70,8 +70,8 @@
{
\group_begin:
\fp_set:Nn \l__box_angle_fp {#2}
- \fp_set:Nn \l__box_sin_fp { sin ( \l__box_angle_fp * deg ) }
- \fp_set:Nn \l__box_cos_fp { cos ( \l__box_angle_fp * deg ) }
+ \fp_set:Nn \l__box_sin_fp { sind ( \l__box_angle_fp ) }
+ \fp_set:Nn \l__box_cos_fp { cosd ( \l__box_angle_fp ) }
\__box_rotate:N #1
\group_end:
}
@@ -501,8 +501,8 @@
\dim_new:N \l__coffin_top_corner_dim
\cs_new_protected:Npn \coffin_rotate:Nn #1#2
{
- \fp_set:Nn \l__coffin_sin_fp { sin ( ( #2 ) * deg ) }
- \fp_set:Nn \l__coffin_cos_fp { cos ( ( #2 ) * deg ) }
+ \fp_set:Nn \l__coffin_sin_fp { sind ( #2 ) }
+ \fp_set:Nn \l__coffin_cos_fp { cosd ( #2 ) }
\prop_map_inline:cn { l__coffin_corners_ \__int_value:w #1 _prop }
{ \__coffin_rotate_corner:Nnnn #1 {##1} ##2 }
\prop_map_inline:cn { l__coffin_poles_ \__int_value:w #1 _prop }
diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3dvipdfmx.def b/Master/texmf-dist/tex/latex/l3kernel/l3dvipdfmx.def
index bf00bdedecb..7fae4b147c9 100644
--- a/Master/texmf-dist/tex/latex/l3kernel/l3dvipdfmx.def
+++ b/Master/texmf-dist/tex/latex/l3kernel/l3dvipdfmx.def
@@ -13,7 +13,7 @@
%%
%% Do not distribute a modified version of this file.
%%
-%% File: l3drivers.dtx Copyright(C) 2011-2012 The LaTeX3 Project
+%% File: l3drivers.dtx Copyright(C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -47,7 +47,7 @@
%% -----------------------------------------------------------------------
%%
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3drivers.dtx 4505 2013-06-28 22:06:04Z joseph $
+\GetIdInfo$Id: l3drivers.dtx 4602 2013-11-18 23:19:01Z bruno $
{L3 Experimental drivers}
\ProvidesExplFile
{l3dvidpfmx.def}{\ExplFileDate}{\ExplFileVersion}
@@ -84,12 +84,9 @@
{
\__driver_graphic_state_save:
\box_set_wd:Nn \l__box_internal_box \c_zero_dim
- \fp_set:Nn \l__box_cos_fp
- {
- \fp_compare:nNnTF \l__box_cos_fp = \c_zero_fp
- { 0 }
- { round ( \l__box_cos_fp , 5 ) }
- }
+ \fp_set:Nn \l__box_cos_fp { round ( \l__box_cos_fp , 5 ) }
+ \fp_compare:nNnT \l__box_cos_fp = \c_zero_fp
+ { \fp_zero:N \l__box_cos_fp }
\fp_set:Nn \l__box_sin_fp { round ( \l__box_sin_fp , 5 ) }
\__driver_pdf_matrix:n
{
diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3dvips.def b/Master/texmf-dist/tex/latex/l3kernel/l3dvips.def
index 355f52bd4ad..991fe9b59c4 100644
--- a/Master/texmf-dist/tex/latex/l3kernel/l3dvips.def
+++ b/Master/texmf-dist/tex/latex/l3kernel/l3dvips.def
@@ -13,7 +13,7 @@
%%
%% Do not distribute a modified version of this file.
%%
-%% File: l3drivers.dtx Copyright(C) 2011-2012 The LaTeX3 Project
+%% File: l3drivers.dtx Copyright(C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -47,7 +47,7 @@
%% -----------------------------------------------------------------------
%%
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3drivers.dtx 4505 2013-06-28 22:06:04Z joseph $
+\GetIdInfo$Id: l3drivers.dtx 4602 2013-11-18 23:19:01Z bruno $
{L3 Experimental drivers}
\ProvidesExplFile
{l3dvips.def}{\ExplFileDate}{\ExplFileVersion}
@@ -84,13 +84,14 @@
\cs_new_protected_nopar:Npn \__driver_box_rotate_begin:
{
\__driver_graphic_state_save:
+ \fp_set:Nn \l__box_angle_fp { round ( \l__box_angle_fp , 5 ) }
\__driver_ps_literal:n
{
currentpoint~
currentpoint~translate~
\fp_compare:nNnTF \l__box_angle_fp = \c_zero_fp
{ 0 }
- { \fp_eval:n { round ( - \l__box_angle_fp , 5 ) } }
+ { \fp_eval:n { - \l__box_angle_fp } }
\c_space_tl rotate~
neg~exch~neg~exch~translate
}
diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3fp.sty b/Master/texmf-dist/tex/latex/l3kernel/l3fp.sty
index 48e8d757bfe..679f97c2519 100644
--- a/Master/texmf-dist/tex/latex/l3kernel/l3fp.sty
+++ b/Master/texmf-dist/tex/latex/l3kernel/l3fp.sty
@@ -25,7 +25,7 @@
%%
%% Do not distribute a modified version of this file.
%%
-%% File: l3fp.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -59,12 +59,12 @@
%% -----------------------------------------------------------------------
%%
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3fp.dtx 4521 2013-07-09 11:45:31Z joseph $
+\GetIdInfo$Id: l3fp.dtx 4601 2013-11-18 23:13:28Z bruno $
{L3 Floating points}
\ProvidesExplPackage
{\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
\__expl_package_check:
-%% File: l3fp-aux.dtx Copyright(C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-aux.dtx Copyright(C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -99,11 +99,14 @@
%%
\cs_new:Npn \__fp_use_none_stop_f:n #1 { \exp_stop_f: }
\cs_new:Npn \__fp_use_s:n #1 { #1; }
+\cs_new:Npn \__fp_use_braced_s:n #1 { {#1} ; }
\cs_new:Npn \__fp_use_s:nn #1#2 { #1#2; }
\cs_new:Npn \__fp_use_none_until_s:w #1; { }
\cs_new:Npn \__fp_use_i_until_s:nw #1#2; {#1}
\cs_new:Npn \__fp_use_ii_until_s:nnw #1#2#3; {#2}
\cs_new:Npn \__fp_reverse_args:Nww #1 #2; #3; { #1 #3; #2; }
+\cs_new:Npn \__fp_rrot:www #1; #2; #3; { #2; #3; #1; }
+\cs_new:Npn \__fp_use_i:ww #1; #2; { #1; }
\__scan_new:N \s__fp
\cs_new_protected:Npn \__fp_chk:w #1 ;
{
@@ -366,7 +369,7 @@
conversion~functions.
}
%%
-%% File: l3fp-traps.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-traps.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -533,6 +536,7 @@
\fp_trap:nn { underflow } { flag }
\cs_new_nopar:Npn \__fp_invalid_operation_o:nw
{ \__fp_invalid_operation:nnw { \exp_after:wN \c_nan_fp } }
+\cs_generate_variant:Nn \__fp_invalid_operation_o:nw { f }
\cs_new:Npn \__fp_error:nnnn #1
{ \__msg_kernel_expandable_error:nnnnn { kernel } { fp - #1 } }
\cs_generate_variant:Nn \__fp_error:nnnn { nnf, nff }
@@ -773,7 +777,7 @@
\exp_after:wN \__fp_exp_after_o:w \tex_romannumeral:D -`0
\__fp_sanitize:Nw #1#2; {1000}{0000}{0000}{0000};
}
-%% File: l3fp-parse.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-parse.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -844,84 +848,109 @@
\__fp_tmp:w {ii} \__fp_parse_digits_i:N { 00 ; 2 }
\__fp_tmp:w {i} \__fp_parse_digits_:N { 0 ; 1 }
\cs_new_nopar:Npn \__fp_parse_digits_:N { ; ; 0 }
-\cs_new:Npn \__fp_parse_operand:Nw #1 #2
+\cs_new:Npn \__fp_parse_one:Nw #1 #2
{
- \if_catcode:w \tex_relax:D #2
- \if_meaning:w \tex_relax:D #2
+ \if_catcode:w \scan_stop: \exp_not:N #2
+ \if_meaning:w \scan_stop: #2
\exp_after:wN \exp_after:wN
- \exp_after:wN \__fp_parse_operand_relax:NN
+ \exp_after:wN \__fp_parse_one_fp:NN
\else:
\exp_after:wN \exp_after:wN
- \exp_after:wN \__fp_parse_operand_register:NN
+ \exp_after:wN \__fp_parse_one_register:NN
\fi:
\else:
\if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f:
\exp_after:wN \exp_after:wN
- \exp_after:wN \__fp_parse_operand_digit:NN
+ \exp_after:wN \__fp_parse_one_digit:NN
\else:
\exp_after:wN \exp_after:wN
- \exp_after:wN \__fp_parse_operand_other:NN
+ \exp_after:wN \__fp_parse_one_other:NN
\fi:
\fi:
#1 #2
}
+\cs_new:Npn \__fp_parse_one_fp:NN #1#2
+ {
+ \cs:w __fp_exp_after \__fp_type_from_scan:N #2 _f:nw \cs_end:
+ {
+ \exp_after:wN \__fp_parse_infix:NN
+ \exp_after:wN #1 \tex_romannumeral:D \__fp_parse_expand:w
+ }
+ #2
+ }
+\cs_new:Npn \__fp_exp_after_mark_f:nw #1
+ {
+ \__msg_kernel_expandable_error:nn { kernel } { fp-early-end }
+ \exp_after:wN \c_nan_fp \tex_romannumeral:D -`0 #1
+ }
+\cs_new:cpn { __fp_exp_after_?_f:nw } #1#2
+ {
+ \__msg_kernel_expandable_error:nnn { kernel } { bad-variable } {#2}
+ \exp_after:wN \c_nan_fp \tex_romannumeral:D -`0 #1
+ }
+\cs_new:Npn \__fp_parse_one_register:NN #1#2
+ {
+ \exp_after:wN \__fp_parse_infix_after_operand:NwN
+ \exp_after:wN #1
+ \tex_romannumeral:D -`0
+ \exp_after:wN \__fp_parse_one_register_aux:Nw
+ \exp_after:wN #2
+ \__int_value:w
+ \exp_after:wN \__fp_parse_exponent:N
+ \tex_romannumeral:D \__fp_parse_expand:w
+ }
\group_begin:
\char_set_catcode_other:N \P
\char_set_catcode_other:N \T
+\char_set_catcode_other:N \M
+\char_set_catcode_other:N \U
\tl_to_lowercase:n
{
\group_end:
- \cs_new:Npn \__fp_parse_operand_register:NN #1#2
+ \cs_new:Npn \__fp_parse_one_register_aux:Nw #1
{
- \exp_after:wN \__fp_parse_infix_after_operand:NwN
- \exp_after:wN #1
- \tex_romannumeral:D -`0
- \exp_after:wN \__fp_parse_operand_register_aux:www
- \tex_the:D
- \exp_after:wN #2
- \exp_after:wN P
- \exp_after:wN T
- \exp_after:wN \q_stop
- \__int_value:w \__fp_parse_exponent:N
+ \exp_after:wN \use:nn
+ \exp_after:wN \__fp_parse_one_register_auxii:wwwNw
+ \exp_after:wN { \tex_the:D \exp_not:N #1 }
+ ; \__fp_parse_one_register_dim:ww
+ PT ; \__fp_parse_one_register_mu:www
+ . PT ; \__fp_parse_one_register_int:www
+ \q_stop
}
- \cs_new:Npn \__fp_parse_operand_register_aux:www #1 PT #2 \q_stop #3 ;
- { \__fp_parse:n { #1 e #3 } }
- }
-\cs_new:Npn \__fp_parse_operand_relax:NN #1#2
- {
- \cs:w __fp_parse_exp_after \__fp_type_from_scan:N #2 _f:nw \cs_end:
- {
- \exp_after:wN \__fp_parse_infix:NN
- \exp_after:wN #1 \tex_romannumeral:D \__fp_parse_expand:w
- }
- #2
+ \cs_new:Npn \__fp_parse_one_register_auxii:wwwNw
+ #1 . #2 PT #3 ; #4#5 \q_stop { #4 #1.#2; }
+ \cs_new:Npn \__fp_parse_one_register_mu:www #1 MU; #2;
+ { \__fp_parse_one_register_dim:ww #1; }
}
-\cs_new_eq:NN \__fp_parse_exp_after_f:nw \__fp_exp_after_f:nw
-\cs_new:Npn \__fp_parse_exp_after_mark_f:nw #1
+\cs_new:Npn \__fp_parse_one_register_int:www #1; #2.; #3;
+ { \__fp_parse:n { #1 e #3 } }
+\cs_new:Npn \__fp_parse_one_register_dim:ww #1; #2;
{
- \__msg_kernel_expandable_error:nn { kernel } { fp-early-end }
- \exp_after:wN \c_nan_fp
- \tex_romannumeral:D -`0 #1
+ \exp_after:wN \__fp_from_dim_test:ww
+ \__int_value:w #2 \exp_after:wN ,
+ \__int_value:w \__dim_eval:w #1 pt ;
}
-\cs_new:cpn { __fp_parse_exp_after_?_f:nw } #1#2
+\cs_new:Npn \__fp_parse_one_digit:NN #1
{
- \__msg_kernel_expandable_error:nnn
- { kernel } { bad-variable } {#2}
- \exp_after:wN \c_nan_fp
- \tex_romannumeral:D -`0 #1
+ \exp_after:wN \__fp_parse_infix_after_operand:NwN
+ \exp_after:wN #1
+ \tex_romannumeral:D -`0
+ \exp_after:wN \__fp_sanitize:wN
+ \int_use:N \__int_eval:w \c_zero \__fp_parse_trim_zeros:N
}
-\cs_new:Npn \__fp_parse_operand_other:NN #1 #2
+\cs_new:Npn \__fp_parse_one_other:NN #1 #2
{
\if_int_compare:w
- \__int_eval:w \tex_uccode:D `#2 / 26 = \c_three
- \exp_after:wN \__fp_parse_operand_other_word_aux:Nw
+ \__int_eval:w
+ ( `#2 \if_int_compare:w `#2 > `Z - \c_thirty_two \fi: ) / 26
+ = \c_three
+ \exp_after:wN \__fp_parse_word:Nw
\exp_after:wN #1
+ \exp_after:wN #2
+ \tex_romannumeral:D \exp_after:wN \__fp_parse_letters:N
\tex_romannumeral:D
- \exp_after:wN \__fp_parse_letters:NN
- \exp_after:wN #2
- \tex_romannumeral:D
\else:
- \exp_after:wN \__fp_parse_operand_other_prefix_aux:NNN
+ \exp_after:wN \__fp_parse_prefix:NNN
\exp_after:wN #1
\exp_after:wN #2
\cs:w __fp_parse_prefix_#2:Nw \exp_after:wN \cs_end:
@@ -929,81 +958,67 @@
\fi:
\__fp_parse_expand:w
}
-
-\cs_new:Npn \__fp_parse_letters:NN #1#2
- {
- \exp_after:wN \c_zero
- \exp_after:wN #1
- \tex_romannumeral:D
- \if_int_compare:w
- \if_catcode:w \tex_relax:D #2
- \c_zero
- \else:
- \__int_eval:w \tex_uccode:D `#2 / 26
- \fi:
- = \c_three
- \exp_after:wN \__fp_parse_letters:NN
- \exp_after:wN #2
- \tex_romannumeral:D
- \exp_after:wN \__fp_parse_expand:w
- \else:
- \exp_after:wN \c_zero
- \exp_after:wN ;
- \exp_after:wN #2
- \fi:
- }
-\cs_new:Npn \__fp_parse_operand_other_word_aux:Nw #1 #2;
+\cs_new:Npn \__fp_parse_word:Nw #1#2;
{
\cs_if_exist_use:cF { __fp_parse_word_#2:N }
{
\__msg_kernel_expandable_error:nnn
{ kernel } { unknown-fp-word } {#2}
- \exp_after:wN \c_nan_fp
- \tex_romannumeral:D -`0
- \__fp_parse_infix:NN
+ \exp_after:wN \c_nan_fp \tex_romannumeral:D -`0
+ \__fp_parse_infix:NN
}
#1
}
-\cs_new_eq:NN \s__fp_unknown \tex_relax:D
-\cs_new:Npn \__fp_parse_operand_other_prefix_aux:NNN #1#2#3
+\cs_new:Npn \__fp_parse_letters:N #1
+ {
+ -`0
+ \if_int_compare:w
+ \if_catcode:w \scan_stop: \exp_not:N #1
+ \c_zero
+ \else:
+ \__int_eval:w
+ ( `#1 \if_int_compare:w `#1 > `Z - \c_thirty_two \fi: )
+ / 26
+ \fi:
+ = \c_three
+ \exp_after:wN #1
+ \tex_romannumeral:D \exp_after:wN \__fp_parse_letters:N
+ \tex_romannumeral:D
+ \else:
+ \__fp_parse_return_semicolon:w #1
+ \fi:
+ \__fp_parse_expand:w
+ }
+\cs_new:Npn \__fp_parse_prefix:NNN #1#2#3
{
- \if_meaning:w \tex_relax:D #3
- \exp_after:wN \__fp_parse_operand_other_prefix_unknown:NNN
+ \if_meaning:w \scan_stop: #3
+ \exp_after:wN \__fp_parse_prefix_unknown:NNN
\exp_after:wN #2
\fi:
#3 #1
}
-\cs_new:Npn \__fp_parse_operand_other_prefix_unknown:NNN #1#2#3
+\cs_new:Npn \__fp_parse_prefix_unknown:NNN #1#2#3
{
\cs_if_exist:cTF { __fp_parse_infix_#1:N }
{
\__msg_kernel_expandable_error:nnn
{ kernel } { fp-missing-number } {#1}
- \exp_after:wN \c_nan_fp
- \tex_romannumeral:D -`0
- \__fp_parse_infix:NN #3 #1
+ \exp_after:wN \c_nan_fp \tex_romannumeral:D -`0
+ \__fp_parse_infix:NN #3 #1
}
{
\__msg_kernel_expandable_error:nnn
{ kernel } { fp-unknown-symbol } {#1}
- \__fp_parse_operand:Nw #3
+ \__fp_parse_one:Nw #3
}
}
-\cs_new:Npn \__fp_parse_operand_digit:NN #1
- {
- \exp_after:wN \__fp_parse_infix_after_operand:NwN
- \exp_after:wN #1
- \tex_romannumeral:D -`0
- \exp_after:wN \__fp_sanitize:wN
- \int_use:N \__int_eval:w \c_zero \__fp_parse_trim_zeros:N
- }
\cs_new:Npn \__fp_parse_trim_zeros:N #1
{
- \if:w 0 #1
+ \if:w 0 \exp_not:N #1
\exp_after:wN \__fp_parse_trim_zeros:N
\tex_romannumeral:D
\else:
- \if:w . #1
+ \if:w . \exp_not:N #1
\exp_after:wN \__fp_parse_strim_zeros:N
\tex_romannumeral:D
\else:
@@ -1025,10 +1040,9 @@
}
\cs_new:Npn \__fp_parse_strim_zeros:N #1
{
- \if:w 0 #1
+ \if:w 0 \exp_not:N #1
- \c_one
- \exp_after:wN \__fp_parse_strim_zeros:N
- \tex_romannumeral:D
+ \exp_after:wN \__fp_parse_strim_zeros:N \tex_romannumeral:D
\else:
\__fp_parse_strim_end:w #1
\fi:
@@ -1119,7 +1133,7 @@
\exp_after:wN \__fp_parse_digits_vi:N
\tex_romannumeral:D
\else:
- \if:w . #4
+ \if:w . \exp_not:N #4
\exp_after:wN \__fp_parse_small_leading:wwNN
\__int_value:w 1
\cs:w
@@ -1151,7 +1165,7 @@
\exp_after:wN \__fp_parse_pack_trailing:NNNNNNww
\int_use:N \__int_eval:w \c_seven - #3 \exp_stop_f:
\int_use:N \__int_eval:w 1 #1
- \if:w . #4
+ \if:w . \exp_not:N #4
\exp_after:wN \__fp_parse_small_trailing:wwNN
\__int_value:w 1
\cs:w
@@ -1166,6 +1180,100 @@
\fi:
\__fp_parse_expand:w
}
+\cs_new:Npn \__fp_parse_round_loop:N #1
+ {
+ \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f:
+ + \c_one
+ \if:w 0 \token_to_str:N #1
+ \exp_after:wN \__fp_parse_round_loop:N
+ \tex_romannumeral:D
+ \else:
+ \exp_after:wN \__fp_parse_round_up:N
+ \tex_romannumeral:D
+ \fi:
+ \else:
+ \__fp_parse_return_semicolon:w \c_zero #1
+ \fi:
+ \__fp_parse_expand:w
+ }
+\cs_new:Npn \__fp_parse_round_up:N #1
+ {
+ \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f:
+ + \c_one
+ \exp_after:wN \__fp_parse_round_up:N
+ \tex_romannumeral:D
+ \else:
+ \__fp_parse_return_semicolon:w \c_one #1
+ \fi:
+ \__fp_parse_expand:w
+ }
+\cs_new:Npn \__fp_parse_round_after:wN #1; #2
+ {
+ + #2 \exp_after:wN ;
+ \int_use:N \__int_eval:w #1 + \__fp_parse_exponent:N
+ }
+\cs_new:Npn \__fp_parse_small_round:NN #1#2
+ {
+ \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f:
+ +
+ \exp_after:wN \__fp_round_s:NNNw
+ \exp_after:wN 0
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \int_use:N \__int_eval:w
+ \exp_after:wN \__fp_parse_round_after:wN
+ \int_use:N \__int_eval:w \c_zero * \__int_eval:w \c_zero
+ \exp_after:wN \__fp_parse_round_loop:N
+ \tex_romannumeral:D
+ \else:
+ \__fp_parse_exponent:Nw #2
+ \fi:
+ \__fp_parse_expand:w
+ }
+\cs_new:Npn \__fp_parse_large_round:NN #1#2
+ {
+ \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f:
+ +
+ \exp_after:wN \__fp_round_s:NNNw
+ \exp_after:wN 0
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \int_use:N \__int_eval:w
+ \exp_after:wN \__fp_parse_large_round_aux:wNN
+ \int_use:N \__int_eval:w \c_one
+ \exp_after:wN \__fp_parse_round_loop:N
+ \else: %^^A could be dot, or e, or other
+ \exp_after:wN \__fp_parse_large_round_test:NN
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \fi:
+ }
+\cs_new:Npn \__fp_parse_large_round_test:NN #1#2
+ {
+ \if:w . \exp_not:N #2
+ \exp_after:wN \__fp_parse_small_round:NN
+ \exp_after:wN #1
+ \tex_romannumeral:D
+ \else:
+ \__fp_parse_exponent:Nw #2
+ \fi:
+ \__fp_parse_expand:w
+ }
+\cs_new:Npn \__fp_parse_large_round_aux:wNN #1 ; #2 #3
+ {
+ + #2
+ \exp_after:wN \__fp_parse_round_after:wN
+ \int_use:N \__int_eval:w #1
+ \if:w . \exp_not:N #3
+ + \c_zero * \__int_eval:w \c_zero
+ \exp_after:wN \__fp_parse_round_loop:N
+ \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w
+ \else:
+ \exp_after:wN ;
+ \exp_after:wN \c_zero
+ \exp_after:wN #3
+ \fi:
+ }
\cs_new:Npn \__fp_parse_exponent:Nw #1 #2 \__fp_parse_expand:w
{
\exp_after:wN ;
@@ -1173,7 +1281,7 @@
}
\cs_new:Npn \__fp_parse_exponent:N #1
{
- \if:w e #1
+ \if:w e \exp_not:N #1
\exp_after:wN \__fp_parse_exponent_aux:N
\tex_romannumeral:D
\else:
@@ -1183,7 +1291,7 @@
}
\cs_new:Npn \__fp_parse_exponent_aux:N #1
{
- \if_int_compare:w \if_catcode:w \tex_relax:D #1
+ \if_int_compare:w \if_catcode:w \scan_stop: \exp_not:N #1
\c_zero \else: `#1 \fi: > `9 \exp_stop_f:
0 \exp_after:wN ; \exp_after:wN e
\else:
@@ -1193,7 +1301,7 @@
}
\cs_new:Npn \__fp_parse_exponent_sign:N #1
{
- \if:w + \if:w - #1 + \fi: \token_to_str:N #1
+ \if:w + \if:w - \exp_not:N #1 + \fi: \token_to_str:N #1
\exp_after:wN \__fp_parse_exponent_sign:N
\tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w
\else:
@@ -1230,9 +1338,10 @@
}
\prg_new_conditional:Npnn \__fp_parse_exponent_keep:N #1 { TF }
{
- \if_catcode:w \tex_relax:D #1
- \if_meaning:w \tex_relax:D #1
- \if_int_compare:w \pdftex_strcmp:D { \s__fp } { #1 } = \c_zero
+ \if_catcode:w \scan_stop: \exp_not:N #1
+ \if_meaning:w \scan_stop: #1
+ \if_int_compare:w
+ \pdftex_strcmp:D { \s__fp } { \exp_not:N #1 } = \c_zero
0
\__msg_kernel_expandable_error:nnn
{ kernel } { fp-after-e } { floating~point~ }
@@ -1262,210 +1371,70 @@
\prg_return_true:
\fi:
}
-\cs_new:Npn \__fp_cfs_round_loop:N #1
- {
- \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f:
- + \c_one
- \if:w 0 #1
- \exp_after:wN \__fp_cfs_round_loop:N
- \tex_romannumeral:D
- \else:
- \exp_after:wN \__fp_cfs_round_up:N
- \tex_romannumeral:D
- \fi:
- \else:
- \__fp_parse_return_semicolon:w \c_zero #1
- \fi:
- \__fp_parse_expand:w
- }
-\cs_new:Npn \__fp_cfs_round_up:N #1
- {
- \if_int_compare:w \c_nine < 1 \token_to_str:N #1 \exp_stop_f:
- + 1
- \exp_after:wN \__fp_cfs_round_up:N
- \tex_romannumeral:D
- \else:
- \__fp_parse_return_semicolon:w \c_one #1
- \fi:
- \__fp_parse_expand:w
- }
-\cs_new:Npn \__fp_parse_large_round:NN #1#2
- {
- \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f:
- +
- \exp_after:wN \__fp_round_s:NNNw
- \exp_after:wN 0
- \exp_after:wN #1
- \exp_after:wN #2
- \int_use:N \__int_eval:w
- \exp_after:wN \__fp_parse_large_round_after:wNN
- \int_use:N \__int_eval:w \c_one
- \exp_after:wN \__fp_cfs_round_loop:N
- \else: %^^A could be dot, or e, or other
- \exp_after:wN \__fp_parse_large_round_dot_test:NNw
- \exp_after:wN #1
- \exp_after:wN #2
- \fi:
- }
-\cs_new:Npn \__fp_parse_large_round_dot_test:NNw #1#2
- {
- \if:w . #2
- \exp_after:wN \__fp_parse_small_round:NN
- \exp_after:wN #1
- \tex_romannumeral:D
- \else:
- \__fp_parse_exponent:Nw #2
- \fi:
- \__fp_parse_expand:w
- }
-\cs_new:Npn \__fp_parse_large_round_after:wNN #1 ; #2 #3
- {
- \if:w . #3
- \exp_after:wN \__fp_parse_large_round_after_aux:wN
- \int_use:N \__int_eval:w #1 +
- \c_zero * \__int_eval:w \c_zero
- \exp_after:wN \__fp_cfs_round_loop:N
- \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w
- \else:
- + #2
- \exp_after:wN ;
- \int_use:N \__int_eval:w #1 +
- \exp_after:wN \__fp_parse_exponent:N
- \exp_after:wN #3
- \fi:
- }
-\cs_new:Npn \__fp_parse_large_round_after_aux:wN #1 ; #2
- {
- + #2
- \exp_after:wN ;
- \int_use:N \__int_eval:w #1 +
- \__fp_parse_exponent:N
- }
-\cs_new:Npn \__fp_parse_small_round:NN #1#2
- {
- \if_int_compare:w \c_nine < 1 \token_to_str:N #2 \exp_stop_f:
- +
- \exp_after:wN \__fp_round_s:NNNw
- \exp_after:wN 0
- \exp_after:wN #1
- \exp_after:wN #2
- \int_use:N \__int_eval:w
- \exp_after:wN \__fp_parse_small_round_after:wN
- \int_use:N \__int_eval:w \c_zero
- \exp_after:wN \__fp_cfs_round_loop:N
- \tex_romannumeral:D
- \else:
- \__fp_parse_exponent:Nw #2
- \fi:
- \__fp_parse_expand:w
- }
-\cs_new:Npn \__fp_parse_small_round_after:wN #1; #2
+\cs_new_eq:cN { __fp_parse_prefix_+:Nw } \__fp_parse_one:Nw
+\cs_new:Npn \__fp_parse_apply_unary:NNNwN #1#2#3#4@#5
{
- + #2 \exp_after:wN ;
- \__int_value:w \__fp_parse_exponent:N
+ #3 #2 #4 @
+ \tex_romannumeral:D -`0 #5 #1
}
-\cs_new:Npn \__fp_parse:n #1
- {
- \tex_romannumeral:D
- \exp_after:wN \__fp_parse_after:ww
- \tex_romannumeral:D
- \__fp_parse_until:Nw \c_minus_one
- \__fp_parse_expand:w #1 \s__fp_mark
- \s__fp_stop
- }
-\cs_new:Npn \__fp_parse_after:ww #1@ #2 \s__fp_stop
+\cs_set_protected:Npn \__fp_tmp:w #1#2#3#4
{
- \c_zero #1
+ \cs_new:cpn { __fp_parse_prefix_ #1 :Nw } ##1
+ {
+ \exp_after:wN \__fp_parse_apply_unary:NNNwN
+ \exp_after:wN ##1
+ \exp_after:wN #4
+ \cs:w __fp_#3_o:w \exp_after:wN \cs_end:
+ \tex_romannumeral:D
+ \if_int_compare:w #2 < ##1
+ \__fp_parse_operand:Nw ##1
+ \else:
+ \__fp_parse_operand:Nw #2
+ \fi:
+ \__fp_parse_expand:w
+ }
}
-\cs_new:Npn \__fp_parse_until:Nw #1
+\__fp_tmp:w - \c_twelve { set_sign } 2
+\__fp_tmp:w ! \c_twelve { not } ?
+\cs_new:cpn { __fp_parse_prefix_.:Nw } #1
{
- -`0
- \exp_after:wN \__fp_parse_until_test:NwN
+ \exp_after:wN \__fp_parse_infix_after_operand:NwN
\exp_after:wN #1
\tex_romannumeral:D -`0
- \exp_after:wN \__fp_parse_operand:Nw
- \exp_after:wN #1
- \tex_romannumeral:D
- }
-\cs_new:Npn \__fp_parse_until_test:NwN #1 #2 @ #3 { #3 #1 #2 @ }
-\cs_new_eq:NN \__fp_parse_stop_until:N \use_none:n
-\cs_new:Npn \__fp_parse_infix_after_operand:NwN #1 #2;
- {
- \__fp_exp_after_f:nw { \__fp_parse_infix:NN #1 }
- #2;
+ \exp_after:wN \__fp_sanitize:wN
+ \int_use:N \__int_eval:w \c_zero \__fp_parse_strim_zeros:N
}
\group_begin:
- \char_set_catcode_letter:N \*
- \cs_new:Npn \__fp_parse_infix:NN #1 #2
+ \char_set_catcode_letter:N (
+ \char_set_catcode_letter:N )
+ \cs_new:Npn \__fp_parse_prefix_(:Nw #1
{
- \if_catcode:w \tex_relax:D #2
- \if_int_compare:w
- \pdftex_strcmp:D { \s__fp_mark } { #2 }
- = \c_zero
- \exp_after:wN \exp_after:wN
- \exp_after:wN \__fp_parse_infix_end:N
- \else:
- \exp_after:wN \exp_after:wN
- \exp_after:wN \__fp_parse_infix_juxtapose:N
- \fi:
+ \exp_after:wN \__fp_parse_lparen_after:NwN
+ \exp_after:wN #1
+ \tex_romannumeral:D
+ \if_int_compare:w #1 = \c_sixteen
+ \__fp_parse_operand:Nw \c_one
\else:
- \if_int_compare:w
- \__int_eval:w \tex_uccode:D `#2 / 26
- = \c_three
- \exp_after:wN \exp_after:wN
- \exp_after:wN \__fp_parse_infix_juxtapose:N
- \else:
- \exp_after:wN \__fp_parse_infix_check:NNN
- \cs:w
- __fp_parse_infix_#2:N
- \exp_after:wN \exp_after:wN \exp_after:wN
- \cs_end:
- \fi:
+ \__fp_parse_operand:Nw \c_zero
\fi:
- #1
- #2
+ \__fp_parse_expand:w
}
- \cs_new:Npn \__fp_parse_infix_check:NNN #1#2#3
+ \cs_new:Npn \__fp_parse_lparen_after:NwN #1#2 @ #3
{
- \if_meaning:w \tex_relax:D #1
- \__msg_kernel_expandable_error:nnn { kernel } { fp-missing } { * }
- \exp_after:wN \__fp_parse_infix_*:N
- \exp_after:wN #2
- \exp_after:wN #3
- \else:
- \exp_after:wN #1
- \exp_after:wN #2
- \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w
- \fi:
+ \token_if_eq_meaning:NNTF #3 \__fp_parse_infix_):N
+ {
+ \__fp_exp_after_array_f:w #2 \s__fp_stop
+ \exp_after:wN \__fp_parse_infix:NN
+ \exp_after:wN #1
+ \tex_romannumeral:D \__fp_parse_expand:w
+ }
+ {
+ \__msg_kernel_expandable_error:nnn
+ { kernel } { fp-missing } { ) }
+ #2 @ \use_none:n #3
+ }
}
\group_end:
-\cs_new:Npn \__fp_parse_apply_binary:NwNwN #1 #2#3@ #4 #5#6@ #7
- {
- \exp_after:wN \__fp_parse_until_test:NwN
- \exp_after:wN #1
- \tex_romannumeral:D -`0
- \cs:w
- __fp
- \__fp_type_from_scan:N #2
- _ #4
- \__fp_type_from_scan:N #5
- _o:ww
- \cs_end:
- #2#3 #5#6
- \tex_romannumeral:D -`0 #7 #1
- }
-\cs_new:Npn \__fp_parse_apply_unary_array:NNwN #1#2#3@#4
- {
- #2 #3 @
- \tex_romannumeral:D -`0 #4 #1
- }
-\cs_new:Npn \__fp_parse_apply_unary:NNwN #1#2#3@#4
- {
- #2 #3
- \tex_romannumeral:D -`0 #4 #1
- }
-\cs_new:Npn \__fp_parse_unary_type:N #1
- { \__fp_type_from_scan:N #1 _o:w \cs_end: #1 }
\cs_set_protected:Npn \__fp_tmp:w #1 #2
{
\cs_new_nopar:cpn { __fp_parse_word_#1:N }
@@ -1477,7 +1446,6 @@
\__fp_tmp:w { deg } \c_one_degree_fp
\__fp_tmp:w { true } \c_one_fp
\__fp_tmp:w { false } \c_zero_fp
-\__fp_tmp:w { pt } \c_one_fp
\cs_set_protected:Npn \__fp_tmp:w #1 #2
{
\cs_new_nopar:cpn { __fp_parse_word_#1:N }
@@ -1486,6 +1454,7 @@
\s__fp \__fp_chk:w 10 #2 ;
}
}
+\__fp_tmp:w {pt} { {1} {1000} {0000} {0000} {0000} }
\__fp_tmp:w {in} { {2} {7227} {0000} {0000} {0000} }
\__fp_tmp:w {pc} { {2} {1200} {0000} {0000} {0000} }
\__fp_tmp:w {cm} { {2} {2845} {2755} {9055} {1181} }
@@ -1500,37 +1469,59 @@
{
\cs_new_nopar:cpn { __fp_parse_word_#1:N }
{
- \exp_after:wN \dim_to_fp:n \exp_after:wN
- { \dim_use:N \__dim_eval:w 1 #1 \exp_after:wN }
+ \exp_after:wN \__fp_from_dim_test:ww
+ \exp_after:wN 0 \exp_after:wN ,
+ \__int_value:w \__dim_eval:w 1 #1 \exp_after:wN ;
\tex_romannumeral:D -`0 \__fp_parse_infix:NN
}
}
+\cs_new:Npn \__fp_parse_unary_function:nNN #1#2#3
+ {
+ \exp_after:wN \__fp_parse_apply_unary:NNNwN
+ \exp_after:wN #3
+ \exp_after:wN #2
+ \cs:w __fp_#1_o:w \exp_after:wN \cs_end:
+ \tex_romannumeral:D
+ \__fp_parse_operand:Nw \c_fifteen \__fp_parse_expand:w
+ }
+\cs_new:Npn \__fp_parse_function:NNN #1#2#3
+ {
+ \exp_after:wN \__fp_parse_apply_unary:NNNwN
+ \exp_after:wN #3
+ \exp_after:wN #2
+ \exp_after:wN #1
+ \tex_romannumeral:D
+ \__fp_parse_operand:Nw \c_sixteen \__fp_parse_expand:w
+ }
+\cs_new_nopar:Npn \__fp_parse_word_acot:N
+ { \__fp_parse_function:NNN \__fp_acot_o:Nw \use_i:nn }
+\cs_new_nopar:Npn \__fp_parse_word_acotd:N
+ { \__fp_parse_function:NNN \__fp_acot_o:Nw \use_ii:nn }
+\cs_new_nopar:Npn \__fp_parse_word_atan:N
+ { \__fp_parse_function:NNN \__fp_atan_o:Nw \use_i:nn }
+\cs_new_nopar:Npn \__fp_parse_word_atand:N
+ { \__fp_parse_function:NNN \__fp_atan_o:Nw \use_ii:nn }
+\cs_new_nopar:Npn \__fp_parse_word_max:N
+ { \__fp_parse_function:NNN \__fp_minmax_o:Nw 2 }
+\cs_new_nopar:Npn \__fp_parse_word_min:N
+ { \__fp_parse_function:NNN \__fp_minmax_o:Nw 0 }
+\cs_new:Npn \__fp_parse_word_abs:N
+ { \__fp_parse_unary_function:nNN { set_sign } 0 }
+\cs_new_nopar:Npn \__fp_parse_word_exp:N
+ { \__fp_parse_unary_function:nNN {exp} ? }
+\cs_new_nopar:Npn \__fp_parse_word_ln:N
+ { \__fp_parse_unary_function:nNN {ln} ? }
\tl_map_inline:nn
- { {abs} {cos} {cot} {csc} {exp} {ln} {sec} {sin} {tan} }
{
- \cs_new:cpn { __fp_parse_word_#1:N } ##1
- {
- \exp_after:wN \__fp_parse_apply_unary:NNwN
- \exp_after:wN ##1
- \cs:w __fp_ #1 \exp_after:wN \__fp_parse_unary_type:N
- \tex_romannumeral:D
- \__fp_parse_until:Nw \c_fifteen
- \__fp_parse_expand:w
- }
+ {acos} {acsc} {asec} {asin}
+ {cos} {cot} {csc} {sec} {sin} {tan}
}
-\cs_set_protected:Npn \__fp_tmp:w #1#2
{
- \cs_new:Npn #1 ##1
- {
- \exp_after:wN \__fp_parse_apply_unary_array:NNwN
- \exp_after:wN ##1
- \exp_after:wN #2
- \tex_romannumeral:D
- \__fp_parse_until:Nw \c_sixteen \__fp_parse_expand:w
- }
+ \cs_new_nopar:cpn { __fp_parse_word_#1:N }
+ { \__fp_parse_unary_function:nNN {#1} \use_i:nn }
+ \cs_new_nopar:cpn { __fp_parse_word_#1d:N }
+ { \__fp_parse_unary_function:nNN {#1} \use_ii:nn }
}
-\__fp_tmp:w \__fp_parse_word_max:N \__fp_max_o:w
-\__fp_tmp:w \__fp_parse_word_min:N \__fp_min_o:w
\cs_new:Npn \__fp_parse_word_round:N #1#2
{
\if_meaning:w + #2
@@ -1548,7 +1539,7 @@
\exp_after:wN #1
\exp_after:wN \__fp_round_to_nearest:NNN
\tex_romannumeral:D
- \__fp_parse_until:Nw \c_sixteen \__fp_parse_expand:w #2
+ \__fp_parse_operand:Nw \c_sixteen \__fp_parse_expand:w #2
}
\cs_new:Npn \__fp_parse_round:Nw
#1 #2 \__fp_round_to_nearest:NNN #3 \__fp_parse_expand:w #4
@@ -1565,96 +1556,199 @@
\fi:
-`0 #4 #1
}
-\cs_new_eq:cN { __fp_parse_prefix_+:Nw } \__fp_parse_operand:Nw
-\cs_set_protected:Npn \__fp_tmp:w #1#2
+\cs_new:Npn \__fp_parse:n #1
{
- \cs_new:cpn { __fp_parse_prefix_#1:Nw } ##1
- {
- \exp_after:wN \__fp_parse_apply_unary:NNwN
- \exp_after:wN ##1
- \cs:w __fp_ #2 \exp_after:wN \__fp_parse_unary_type:N
- \tex_romannumeral:D
- \if_int_compare:w \c_twelve < ##1
- \__fp_parse_until:Nw ##1
+ \tex_romannumeral:D
+ \exp_after:wN \__fp_parse_after:ww
+ \tex_romannumeral:D
+ \__fp_parse_operand:Nw \c_minus_one
+ \__fp_parse_expand:w #1 \s__fp_mark
+ \s__fp_stop
+ }
+\cs_new:Npn \__fp_parse_after:ww
+ #1@ \__fp_parse_infix_end:N \s__fp_mark \s__fp_stop
+ { \c_zero #1 }
+\cs_new:Npn \__fp_parse_operand:Nw #1
+ {
+ -`0
+ \exp_after:wN \__fp_parse_continue:NwN
+ \exp_after:wN #1
+ \tex_romannumeral:D -`0
+ \exp_after:wN \__fp_parse_one:Nw
+ \exp_after:wN #1
+ \tex_romannumeral:D
+ }
+\cs_new:Npn \__fp_parse_continue:NwN #1 #2 @ #3 { #3 #1 #2 @ }
+\cs_new:Npn \__fp_parse_apply_binary:NwNwN #1 #2@ #3 #4@ #5
+ {
+ \exp_after:wN \__fp_parse_continue:NwN
+ \exp_after:wN #1
+ \tex_romannumeral:D -`0 \cs:w __fp_#3_o:ww \cs_end: #2 #4
+ \tex_romannumeral:D -`0 #5 #1
+ }
+\cs_new:Npn \__fp_parse_infix_after_operand:NwN #1 #2;
+ {
+ \__fp_exp_after_f:nw { \__fp_parse_infix:NN #1 }
+ #2;
+ }
+\group_begin:
+ \char_set_catcode_letter:N \*
+ \cs_new:Npn \__fp_parse_infix:NN #1 #2
+ {
+ \if_catcode:w \scan_stop: \exp_not:N #2
+ \if_int_compare:w
+ \pdftex_strcmp:D { \s__fp_mark } { \exp_not:N #2 }
+ = \c_zero
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \__fp_parse_infix_end:N
\else:
- \__fp_parse_until:Nw \c_twelve
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \__fp_parse_infix_juxtapose:N
\fi:
- \__fp_parse_expand:w
- }
- }
-\__fp_tmp:w - { - }
-\__fp_tmp:w ! { ! }
+ \else:
+ \if_int_compare:w
+ \__int_eval:w
+ ( `#2 \if_int_compare:w `#2 > `Z - \c_thirty_two \fi: )
+ / 26
+ = \c_three
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \__fp_parse_infix_juxtapose:N
+ \else:
+ \exp_after:wN \__fp_parse_infix_check:NNN
+ \cs:w
+ __fp_parse_infix_#2:N
+ \exp_after:wN \exp_after:wN \exp_after:wN
+ \cs_end:
+ \fi:
+ \fi:
+ #1
+ #2
+ }
+ \cs_new:Npn \__fp_parse_infix_check:NNN #1#2#3
+ {
+ \if_meaning:w \scan_stop: #1
+ \__msg_kernel_expandable_error:nnn
+ { kernel } { fp-missing } { * }
+ \exp_after:wN \__fp_parse_infix_*:N
+ \exp_after:wN #2
+ \exp_after:wN #3
+ \else:
+ \exp_after:wN #1
+ \exp_after:wN #2
+ \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w
+ \fi:
+ }
+\group_end:
+\cs_new:Npn \__fp_parse_infix_end:N #1
+ { @ \use_none:n \__fp_parse_infix_end:N }
\group_begin:
\char_set_catcode_letter:N \)
- \cs_new:cpn { __fp_parse_prefix_(:Nw } #1
+ \cs_new:Npn \__fp_parse_infix_):N #1
{
- \exp_after:wN \__fp_parse_lparen_after:NwN
- \exp_after:wN #1
- \tex_romannumeral:D
- \if_int_compare:w #1 = \c_sixteen
- \__fp_parse_until:Nw \c_one
+ \if_int_compare:w #1 < \c_zero
+ \__msg_kernel_expandable_error:nnn { kernel } { fp-extra } { ) }
+ \exp_after:wN \__fp_parse_infix:NN
+ \exp_after:wN #1
+ \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w
\else:
- \__fp_parse_until:Nw \c_zero
+ \exp_after:wN @
+ \exp_after:wN \use_none:n
+ \exp_after:wN \__fp_parse_infix_):N
\fi:
- \__fp_parse_expand:w
}
- \cs_new:Npn \__fp_parse_lparen_after:NwN #1#2@#3
+\group_end:
+\group_begin:
+ \char_set_catcode_letter:N \,
+ \cs_new:Npn \__fp_parse_infix_,:N #1
{
- \token_if_eq_meaning:NNTF #3 \__fp_parse_infix_):N
- {
- \__fp_exp_after_array_f:w #2 \s__fp_stop
- \exp_after:wN \__fp_parse_infix:NN
- \exp_after:wN #1
- \tex_romannumeral:D \__fp_parse_expand:w
- }
+ \if_int_compare:w #1 > \c_one
+ \exp_after:wN @
+ \exp_after:wN \use_none:n
+ \exp_after:wN \__fp_parse_infix_,:N
+ \else:
+ \if_int_compare:w #1 = \c_one
+ \exp_after:wN \__fp_parse_infix_comma:w
+ \tex_romannumeral:D
+ \else:
+ \exp_after:wN \__fp_parse_infix_comma_gobble:w
+ \tex_romannumeral:D
+ \fi:
+ \__fp_parse_operand:Nw \c_one
+ \exp_after:wN \__fp_parse_expand:w
+ \fi:
+ }
+ \cs_new:Npn \__fp_parse_infix_comma:w #1 @
+ { #1 @ \use_none:n }
+ \cs_new:Npn \__fp_parse_infix_comma_gobble:w #1 @
+ {
+ \__msg_kernel_expandable_error:nn { kernel } { fp-extra-comma }
+ @ \use_none:n
+ }
+\group_end:
+\group_begin:
+ \char_set_catcode_other:N \&
+ \char_set_catcode_letter:N \^
+ \char_set_catcode_letter:N \/
+ \char_set_catcode_letter:N \-
+ \char_set_catcode_letter:N \+
+ \cs_set_protected:Npn \__fp_tmp:w #1#2#3#4
+ {
+ \cs_new:Npn #1 ##1
{
- \__msg_kernel_expandable_error:nnn { kernel } { fp-missing } { ) }
- #2 @ \__fp_parse_stop_until:N #3
+ \if_int_compare:w ##1 < #3
+ \exp_after:wN @
+ \exp_after:wN \__fp_parse_apply_binary:NwNwN
+ \exp_after:wN #2
+ \tex_romannumeral:D
+ \__fp_parse_operand:Nw #4
+ \exp_after:wN \__fp_parse_expand:w
+ \else:
+ \exp_after:wN @
+ \exp_after:wN \use_none:n
+ \exp_after:wN #1
+ \fi:
}
}
+ \__fp_tmp:w \__fp_parse_infix_^:N ^ \c_fifteen \c_fourteen
+ \__fp_tmp:w \__fp_parse_infix_/:N / \c_ten \c_ten
+ \__fp_tmp:w \__fp_parse_infix_mul:N * \c_ten \c_ten
+ \__fp_tmp:w \__fp_parse_infix_-:N - \c_nine \c_nine
+ \__fp_tmp:w \__fp_parse_infix_+:N + \c_nine \c_nine
+ \__fp_tmp:w \__fp_parse_infix_and:N & \c_five \c_five
+ \__fp_tmp:w \__fp_parse_infix_or:N | \c_four \c_four
\group_end:
-\cs_new:cpn {__fp_parse_prefix_.:Nw} #1
+\cs_new:cpn { __fp_parse_infix_(:N } #1
+ { \__fp_parse_infix_juxtapose:N #1 ( }
+\cs_new:Npn \__fp_parse_infix_juxtapose:N #1
{
- \exp_after:wN \__fp_parse_infix_after_operand:NwN
- \exp_after:wN #1
- \tex_romannumeral:D -`0
- \exp_after:wN \__fp_sanitize:wN
- \int_use:N \__int_eval:w \c_zero \__fp_parse_strim_zeros:N
+ \if_int_compare:w #1 < \c_thirty_two
+ \exp_after:wN @
+ \exp_after:wN \__fp_parse_apply_juxtapose:NwwN
+ \tex_romannumeral:D
+ \__fp_parse_operand:Nw \c_thirty_two
+ \exp_after:wN \__fp_parse_expand:w
+ \else:
+ \exp_after:wN @
+ \exp_after:wN \use_none:n
+ \exp_after:wN \__fp_parse_infix_juxtapose:N
+ \fi:
}
-\cs_set_protected:Npn \__fp_tmp:w #1#2#3#4
+\cs_new:Npn \__fp_parse_apply_juxtapose:NwwN #1 #2;#3@ #4;#5@
{
- \cs_new:Npn #1 ##1
- {
- \if_int_compare:w ##1 < #3
- \exp_after:wN @
- \exp_after:wN \__fp_parse_apply_binary:NwNwN
- \exp_after:wN #2
- \tex_romannumeral:D
- \__fp_parse_until:Nw #4
- \exp_after:wN \__fp_parse_expand:w
- \else:
- \exp_after:wN @
- \exp_after:wN \__fp_parse_stop_until:N
- \exp_after:wN #1
- \fi:
- }
+ \if_catcode:w ^ \tl_to_str:n { #3 #5 } ^
+ \else:
+ \__fp_error:nffn { invalid-ii }
+ { \__fp_array_to_clist:n { #2; #3 } }
+ { \__fp_array_to_clist:n { #4; #5 } }
+ { }
+ \fi:
+ \__fp_parse_apply_binary:NwNwN #1 #2;@ * #4;@
}
\group_begin:
- \char_set_catcode_other:N \&
- \__fp_tmp:w \__fp_parse_infix_juxtapose:N * \c_thirty_two \c_thirty_two
- \exp_args:Nc \__fp_tmp:w { __fp_parse_infix_ / :N } / \c_ten \c_ten
- \exp_args:Nc \__fp_tmp:w { __fp_parse_infix_mul:N } * \c_ten \c_ten
- \exp_args:Nc \__fp_tmp:w { __fp_parse_infix_ - :N } - \c_nine \c_nine
- \exp_args:Nc \__fp_tmp:w { __fp_parse_infix_ + :N } + \c_nine \c_nine
- \exp_args:Nc \__fp_tmp:w { __fp_parse_infix_and:N } & \c_five \c_five
- \exp_args:Nc \__fp_tmp:w { __fp_parse_infix_ or:N } | \c_four \c_four
-\group_end:
-\group_begin:
\char_set_catcode_letter:N ^
- \__fp_tmp:w \__fp_parse_infix_^:N ^ \c_fifteen \c_fourteen
\cs_new:cpn { __fp_parse_infix_*:N } #1#2
{
- \if:w * #2
+ \if:w * \exp_not:N #2
\exp_after:wN \__fp_parse_infix_^:N
\exp_after:wN #1
\else:
@@ -1669,7 +1763,7 @@
\char_set_catcode_letter:N \&
\cs_new:Npn \__fp_parse_infix_|:N #1#2
{
- \if:w | #2
+ \if:w | \exp_not:N #2
\exp_after:wN \__fp_parse_infix_|:N
\exp_after:wN #1
\tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w
@@ -1681,7 +1775,7 @@
}
\cs_new:Npn \__fp_parse_infix_&:N #1#2
{
- \if:w & #2
+ \if:w & \exp_not:N #2
\exp_after:wN \__fp_parse_infix_&:N
\exp_after:wN #1
\tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w
@@ -1692,6 +1786,39 @@
\fi:
}
\group_end:
+\group_begin:
+ \char_set_catcode_letter:N \?
+ \cs_new:Npn \__fp_parse_infix_?:N #1
+ {
+ \if_int_compare:w #1 < \c_three
+ \exp_after:wN @
+ \exp_after:wN \__fp_ternary:NwwN
+ \tex_romannumeral:D
+ \__fp_parse_operand:Nw \c_three
+ \exp_after:wN \__fp_parse_expand:w
+ \else:
+ \exp_after:wN @
+ \exp_after:wN \use_none:n
+ \exp_after:wN \__fp_parse_infix_?:N
+ \fi:
+ }
+ \cs_new:Npn \__fp_parse_infix_::N #1
+ {
+ \if_int_compare:w #1 < \c_three
+ \__msg_kernel_expandable_error:nnnn
+ { kernel } { fp-missing } { ? } { ~for~?: }
+ \exp_after:wN @
+ \exp_after:wN \__fp_ternary_auxii:NwwN
+ \tex_romannumeral:D
+ \__fp_parse_operand:Nw \c_two
+ \exp_after:wN \__fp_parse_expand:w
+ \else:
+ \exp_after:wN @
+ \exp_after:wN \use_none:n
+ \exp_after:wN \__fp_parse_infix_::N
+ \fi:
+ }
+\group_end:
\cs_new:cpn { __fp_parse_infix_<:N } #1
{
\__fp_infix_compare:N #1 \c_one_fp
@@ -1729,14 +1856,14 @@
\exp_after:wN \__fp_parse_infix_excl_error:
\else:
\exp_after:wN @
- \exp_after:wN \__fp_parse_stop_until:N
+ \exp_after:wN \use_none:n
\exp_after:wN \__fp_infix_compare:N
\fi:
}
\cs_new:Npn \__fp_parse_compare:NNNNNNw #1#2#3#4#5#6#7
{
\if_case:w
- \if_catcode:w \tex_relax:D #7
+ \if_catcode:w \scan_stop: #7
\c_minus_one
\else:
\__int_eval:w `#7 - `< \__int_eval_end:
@@ -1769,11 +1896,11 @@
\exp_after:wN #3
\exp_after:wN #4
\tex_romannumeral:D
- \__fp_parse_until:Nw \c_seven \__fp_parse_expand:w #5
+ \__fp_parse_operand:Nw \c_seven \__fp_parse_expand:w #5
}
\cs_new:Npn \__fp_parse_apply_compare:NwNNNNwN #1 #2@ #3#4#5#6 #7@ #8
{
- \exp_after:wN \__fp_parse_until_test:NwN
+ \exp_after:wN \__fp_parse_continue:NwN
\exp_after:wN #1
\tex_romannumeral:D -`0
\exp_after:wN \exp_after:wN
@@ -1787,85 +1914,6 @@
\fi:
\tex_romannumeral:D -`0 #8 #1
}
-\group_begin:
- \char_set_catcode_letter:N \?
- \cs_new:Npn \__fp_parse_infix_?:N #1
- {
- \if_int_compare:w #1 < \c_three
- \exp_after:wN @
- \exp_after:wN \__fp_ternary:NwwN
- \tex_romannumeral:D
- \__fp_parse_until:Nw \c_three
- \exp_after:wN \__fp_parse_expand:w
- \else:
- \exp_after:wN @
- \exp_after:wN \__fp_parse_stop_until:N
- \exp_after:wN \__fp_parse_infix_?:N
- \fi:
- }
- \cs_new:Npn \__fp_parse_infix_::N #1
- {
- \if_int_compare:w #1 < \c_three
- \__msg_kernel_expandable_error:nnnn
- { kernel } { fp-missing } { ? } { ~for~?: }
- \exp_after:wN @
- \exp_after:wN \__fp_ternary_auxii:NwwN
- \tex_romannumeral:D
- \__fp_parse_until:Nw \c_two
- \exp_after:wN \__fp_parse_expand:w
- \else:
- \exp_after:wN @
- \exp_after:wN \__fp_parse_stop_until:N
- \exp_after:wN \__fp_parse_infix_::N
- \fi:
- }
-\group_end:
-\group_begin:
- \char_set_catcode_letter:N \)
- \cs_new:Npn \__fp_parse_infix_):N #1
- {
- \if_int_compare:w #1 < \c_zero
- \__msg_kernel_expandable_error:nnn { kernel } { fp-extra } { ) }
- \exp_after:wN \__fp_parse_infix:NN
- \exp_after:wN #1
- \tex_romannumeral:D \exp_after:wN \__fp_parse_expand:w
- \else:
- \exp_after:wN @
- \exp_after:wN \__fp_parse_stop_until:N
- \exp_after:wN \__fp_parse_infix_):N
- \fi:
- }
-\group_end:
-\cs_new:Npn \__fp_parse_infix_end:N #1
- { @ \__fp_parse_stop_until:N \__fp_parse_infix_end:N }
-\group_begin:
- \char_set_catcode_letter:N \,
- \cs_new:Npn \__fp_parse_infix_,:N #1
- {
- \if_int_compare:w #1 > \c_one
- \exp_after:wN @
- \exp_after:wN \__fp_parse_stop_until:N
- \exp_after:wN \__fp_parse_infix_,:N
- \else:
- \if_int_compare:w #1 = \c_one
- \exp_after:wN \__fp_parse_infix_comma:w
- \tex_romannumeral:D
- \else:
- \exp_after:wN \__fp_parse_infix_comma_gobble:w
- \tex_romannumeral:D
- \fi:
- \__fp_parse_until:Nw \c_one
- \exp_after:wN \__fp_parse_expand:w
- \fi:
- }
- \cs_new:Npn \__fp_parse_infix_comma:w #1 @
- { #1 @ \__fp_parse_stop_until:N }
- \cs_new:Npn \__fp_parse_infix_comma_gobble:w #1 @
- {
- \__msg_kernel_expandable_error:nn { kernel } { fp-extra-comma }
- @ \__fp_parse_stop_until:N
- }
-\group_end:
\__msg_kernel_new:nnn { kernel } { unknown-fp-word }
{ Unknown~fp~word~#1. }
\__msg_kernel_new:nnn { kernel } { fp-missing }
@@ -1884,7 +1932,7 @@
{ Unexpected~comma:~extra~arguments~ignored. }
\__msg_kernel_new:nnn { kernel } { fp-num-args }
{ #1~expects~between~#2~and~#3~arguments. }
-%% File: l3fp-logic.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-logic.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -2052,20 +2100,15 @@
\fp_while_do:nNnn {#1} #2 {#3} {#4}
}
}
-\cs_new:Npn \__fp_max_o:w #1 @
+\cs_new:Npn \__fp_minmax_o:Nw #1#2 @
{
- \exp_after:wN \__fp_minmax_loop:Nww
- \exp_after:wN \c_minus_one
- \c_minus_inf_fp
- #1
- \s__fp \__fp_chk:w { 3 \__fp_minmax_break_o:w } ;
- }
-\cs_new:Npn \__fp_min_o:w #1 @
- {
- \exp_after:wN \__fp_minmax_loop:Nww
- \exp_after:wN \c_one
- \c_inf_fp
- #1
+ \if_meaning:w 0 #1
+ \exp_after:wN \__fp_minmax_loop:Nww \exp_after:wN \c_one
+ \else:
+ \exp_after:wN \__fp_minmax_loop:Nww \exp_after:wN \c_minus_one
+ \fi:
+ #2
+ \s__fp \__fp_chk:w 2 #1 \s__fp_exact ;
\s__fp \__fp_chk:w { 3 \__fp_minmax_break_o:w } ;
}
\cs_new:Npn \__fp_minmax_loop:Nww
@@ -2098,9 +2141,9 @@
{ \fi: \fi: #2 }
\cs_new:Npn \__fp_minmax_break_o:w #1 \fi: \fi: #2 \s__fp #3; #4;
{ \fi: \__fp_exp_after_o:w \s__fp #3; }
-\cs_new:cpn { __fp_!_o:w } \s__fp \__fp_chk:w #1#2;
+\cs_new:cpn { __fp_not_o:w } #1 \s__fp \__fp_chk:w #2#3; @
{
- \if_meaning:w 0 #1
+ \if_meaning:w 0 #2
\exp_after:wN \exp_after:wN \exp_after:wN \c_one_fp
\else:
\exp_after:wN \exp_after:wN \exp_after:wN \c_zero_fp
@@ -2131,12 +2174,12 @@
\__fp_exp_after_array_f:w #3 \s__fp_stop
\exp_after:wN @
\tex_romannumeral:D
- \__fp_parse_until:Nw \c_two
+ \__fp_parse_operand:Nw \c_two
\__fp_parse_expand:w
\else:
\__msg_kernel_expandable_error:nnnn
{ kernel } { fp-missing } { : } { ~for~?: }
- \exp_after:wN \__fp_parse_until_test:NwN
+ \exp_after:wN \__fp_parse_continue:NwN
\exp_after:wN #1
\tex_romannumeral:D -`0
\__fp_exp_after_array_f:w #3 \s__fp_stop
@@ -2159,7 +2202,7 @@
\cs_new:Npn \__fp_ternary_map_break: #1 \__fp_ternary_break_point:n #2 {#2}
\cs_new:Npn \__fp_ternary_auxi:NwwN #1#2@#3@#4
{
- \exp_after:wN \__fp_parse_until_test:NwN
+ \exp_after:wN \__fp_parse_continue:NwN
\exp_after:wN #1
\tex_romannumeral:D -`0
\__fp_exp_after_array_f:w #2 \s__fp_stop
@@ -2167,13 +2210,13 @@
}
\cs_new:Npn \__fp_ternary_auxii:NwwN #1#2@#3@#4
{
- \exp_after:wN \__fp_parse_until_test:NwN
+ \exp_after:wN \__fp_parse_continue:NwN
\exp_after:wN #1
\tex_romannumeral:D -`0
\__fp_exp_after_array_f:w #3 \s__fp_stop
#4 #1
}
-%% File: l3fp-basics.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-basics.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -2781,23 +2824,17 @@
\__int_value:w \__fp_round_digit:Nw #7 #8 ;
\exp_after:wN ;
}
-\cs_new:cpn { __fp_-_o:w } #1 \s__fp \__fp_chk:w #2 #3
+\cs_new:Npn \__fp_set_sign_o:w #1 \s__fp \__fp_chk:w #2#3#4; @
{
\exp_after:wN \__fp_exp_after_o:w
\exp_after:wN \s__fp
\exp_after:wN \__fp_chk:w
\exp_after:wN #2
- \int_use:N \__int_eval:w \c_two - #3 \__int_eval_end:
- }
-\cs_new:Npn \__fp_abs_o:w \s__fp \__fp_chk:w #1 #2
- {
- \exp_after:wN \__fp_exp_after_o:w
- \exp_after:wN \s__fp
- \exp_after:wN \__fp_chk:w
- \exp_after:wN #1
- \__int_value:w \if_meaning:w 1 #2 1 \else: 0 \fi: \exp_stop_f:
+ \__int_value:w
+ \if_case:w #3 \exp_stop_f: #1 \or: 1 \or: 0 \fi: \exp_stop_f:
+ #4;
}
-%% File: l3fp-extended.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-extended.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -2838,7 +2875,39 @@
\exp_after:wN #3 \exp_after:wN
{ \int_use:N \__int_eval:w \c_ten_thousand + #1 } #2 ;
}
+\cs_new:Npn \__fp_fixed_div_myriad:wn #1#2#3#4#5#6; #7
+ {
+ \exp_after:wN \__fp_fixed_mul_after:wn
+ \int_use:N \__int_eval:w \c__fp_leading_shift_int
+ \exp_after:wN \__fp_pack:NNNNNwn
+ \int_use:N \__int_eval:w \c__fp_trailing_shift_int
+ + #1 ; {#7} {#2}{#3}{#4}{#5};
+ }
\cs_new:Npn \__fp_fixed_mul_after:wn #1; #2 { #2 {#1} }
+\cs_new:Npn \__fp_fixed_mul_short:wwn #1#2#3#4#5#6; #7#8#9;
+ {
+ \exp_after:wN \__fp_fixed_mul_after:wn
+ \int_use:N \__int_eval:w \c__fp_leading_shift_int
+ + #1*#7
+ \exp_after:wN \__fp_pack:NNNNNwn
+ \int_use:N \__int_eval:w \c__fp_middle_shift_int
+ + #1*#8 + #2*#7
+ \exp_after:wN \__fp_pack:NNNNNwn
+ \int_use:N \__int_eval:w \c__fp_middle_shift_int
+ + #1*#9 + #2*#8 + #3*#7
+ \exp_after:wN \__fp_pack:NNNNNwn
+ \int_use:N \__int_eval:w \c__fp_middle_shift_int
+ + #2*#9 + #3*#8 + #4*#7
+ \exp_after:wN \__fp_pack:NNNNNwn
+ \int_use:N \__int_eval:w \c__fp_middle_shift_int
+ + #3*#9 + #4*#8 + #5*#7
+ \exp_after:wN \__fp_pack:NNNNNwn
+ \int_use:N \__int_eval:w \c__fp_trailing_shift_int
+ + #4*#9 + #5*#8 + #6*#7
+ + ( #5*#9 + #6*#8 + #6*#9 / \c_ten_thousand )
+ / \c_ten_thousand
+ \exp_after:wN ; \__fp_use_braced_s:n
+ }
\cs_new:Npn \__fp_fixed_div_int:wwN #1#2#3#4#5#6 ; #7 ; #8
{
\exp_after:wN \__fp_fixed_div_int_after:Nw
@@ -2977,10 +3046,213 @@
#9 (#4* #1 *#7)
#9 (#5*#6+#4* #2 *#7+#3*#8) / \c_ten_thousand
}
+\cs_new:Npn \__fp_ep_to_fixed:wwn #1,#2
+ {
+ \exp_after:wN \__fp_ep_to_fixed_auxi:www
+ \int_use:N \__int_eval:w 1 0000 0000 + #2 \exp_after:wN ;
+ \tex_romannumeral:D -`0
+ \prg_replicate:nn { \c_four - \int_max:nn {#1} { -32 } } { 0 } ;
+ }
+\cs_new:Npn \__fp_ep_to_fixed_auxi:www 1#1; #2; #3#4#5#6#7;
+ {
+ \__fp_pack_eight:wNNNNNNNN
+ \__fp_pack_twice_four:wNNNNNNNN
+ \__fp_pack_twice_four:wNNNNNNNN
+ \__fp_pack_twice_four:wNNNNNNNN
+ \__fp_ep_to_fixed_auxii:nnnnnnnwn ;
+ #2 #1#3#4#5#6#7 0000 !
+ }
+\cs_new:Npn \__fp_ep_to_fixed_auxii:nnnnnnnwn #1#2#3#4#5#6#7; #8! #9
+ { #9 {#1#2}{#3}{#4}{#5}{#6}{#7}; }
+\cs_new:Npn \__fp_ep_to_ep:wwN #1,#2#3#4#5#6#7; #8
+ {
+ \exp_after:wN #8
+ \int_use:N \__int_eval:w #1 + \c_four
+ \exp_after:wN \use_i:nn
+ \exp_after:wN \__fp_ep_to_ep_loop:N
+ \int_use:N \__int_eval:w 1 0000 0000 + #2 \__int_eval_end:
+ #3#4#5#6#7 ; ; !
+ }
+\cs_new:Npn \__fp_ep_to_ep_loop:N #1
+ {
+ \if_meaning:w 0 #1
+ - \c_one
+ \else:
+ \__fp_ep_to_ep_end:www #1
+ \fi:
+ \__fp_ep_to_ep_loop:N
+ }
+\cs_new:Npn \__fp_ep_to_ep_end:www
+ #1 \fi: \__fp_ep_to_ep_loop:N #2; #3!
+ {
+ \fi:
+ \if_meaning:w ; #1
+ - \c_two * \c__fp_max_exponent_int
+ \__fp_ep_to_ep_zero:ww
+ \fi:
+ \__fp_pack_twice_four:wNNNNNNNN
+ \__fp_pack_twice_four:wNNNNNNNN
+ \__fp_pack_twice_four:wNNNNNNNN
+ \__fp_use_i:ww , ;
+ #1 #2 0000 0000 0000 0000 0000 0000 ;
+ }
+\cs_new:Npn \__fp_ep_to_ep_zero:ww \fi: #1; #2; #3;
+ { \fi: , {1000}{0000}{0000}{0000}{0000}{0000} ; }
+\cs_new:Npn \__fp_ep_compare:wwww #1,#2#3#4#5#6#7;
+ { \__fp_ep_compare_aux:wwww {#1}{#2}{#3}{#4}{#5}; #6#7; }
+\cs_new:Npn \__fp_ep_compare_aux:wwww #1;#2;#3,#4#5#6#7#8#9;
+ {
+ \if_case:w
+ \__fp_compare_npos:nwnw #1; {#3}{#4}{#5}{#6}{#7}; \exp_stop_f:
+ \if_int_compare:w #2 = #8#9 \exp_stop_f:
+ 0
+ \else:
+ \if_int_compare:w #2 < #8#9 - \fi: 1
+ \fi:
+ \or: 1
+ \else: -1
+ \fi:
+ }
+\cs_new:Npn \__fp_ep_mul:wwwwn #1,#2; #3,#4;
+ {
+ \__fp_ep_to_ep:wwN #3,#4;
+ \__fp_fixed_continue:wn
+ {
+ \__fp_ep_to_ep:wwN #1,#2;
+ \__fp_ep_mul_raw:wwwwN
+ }
+ \__fp_fixed_continue:wn
+ }
+\cs_new:Npn \__fp_ep_mul_raw:wwwwN #1,#2; #3,#4; #5
+ {
+ \__fp_fixed_mul:wwn #2; #4;
+ { \exp_after:wN #5 \int_use:N \__int_eval:w #1 + #3 , }
+ }
+\cs_new:Npn \__fp_ep_div:wwwwn #1,#2; #3,#4;
+ {
+ \__fp_ep_to_ep:wwN #1,#2;
+ \__fp_fixed_continue:wn
+ {
+ \__fp_ep_to_ep:wwN #3,#4;
+ \__fp_ep_div_esti:wwwwn
+ }
+ }
+\cs_new:Npn \__fp_ep_div_esti:wwwwn #1,#2#3; #4,
+ {
+ \exp_after:wN \__fp_ep_div_estii:wwnnwwn
+ \int_use:N \__int_eval:w 10 0000 0000 / ( #2 + \c_one )
+ \exp_after:wN ;
+ \int_use:N \__int_eval:w #4 - #1 + \c_one ,
+ {#2} #3;
+ }
+\cs_new:Npn \__fp_ep_div_estii:wwnnwwn #1; #2,#3#4#5; #6; #7
+ {
+ \exp_after:wN \__fp_ep_div_estiii:NNNNNwwwn
+ \int_use:N \__int_eval:w 10 0000 0000 - 1750
+ + #1 000 + (10 0000 0000 / #3 - #1) * (1000 - #4 / 10) ;
+ {#3}{#4}#5; #6; { #7 #2, }
+ }
+\cs_new:Npn \__fp_ep_div_estiii:NNNNNwwwn 1#1#2#3#4#5#6; #7;
+ {
+ \__fp_fixed_mul_short:wwn #7; {#1}{#2#3#4#5}{#6};
+ \__fp_ep_div_epsi:wnNNNNNn {#1#2#3#4}#5#6
+ \__fp_fixed_mul:wwn
+ }
+\cs_new:Npn \__fp_ep_div_epsi:wnNNNNNn #1#2#3#4#5#6;
+ {
+ \exp_after:wN \__fp_ep_div_epsii:wwnNNNNNn
+ \int_use:N \__int_eval:w 1 9998 - #2
+ \exp_after:wN \__fp_ep_div_eps_pack:NNNNNw
+ \int_use:N \__int_eval:w 1 9999 9998 - #3#4
+ \exp_after:wN \__fp_ep_div_eps_pack:NNNNNw
+ \int_use:N \__int_eval:w 2 0000 0000 - #5#6 ; ;
+ }
+\cs_new:Npn \__fp_ep_div_eps_pack:NNNNNw #1#2#3#4#5#6;
+ { + #1 ; {#2#3#4#5} {#6} }
+\cs_new:Npn \__fp_ep_div_epsii:wwnNNNNNn 1#1; #2; #3#4#5#6#7#8
+ {
+ \__fp_fixed_mul:wwn {0000}{#1}#2; {0000}{#1}#2;
+ \__fp_fixed_add_one:wN
+ \__fp_fixed_mul:wwn {10000} {#1} #2 ;
+ {
+ \__fp_fixed_mul_short:wwn {0000}{#1}#2; {#3}{#4#5#6#7}{#8000};
+ \__fp_fixed_div_myriad:wn
+ \__fp_fixed_mul:wwn
+ }
+ \__fp_fixed_add:wwn {#3}{#4#5#6#7}{#8000}{0000}{0000}{0000};
+ }
+\cs_new:Npn \__fp_ep_isqrt:wwn #1,#2;
+ {
+ \__fp_ep_to_ep:wwN #1,#2;
+ \__fp_ep_isqrt_auxi:wwn
+ }
+\cs_new:Npn \__fp_ep_isqrt_auxi:wwn #1,
+ {
+ \exp_after:wN \__fp_ep_isqrt_auxii:wwnnnwn
+ \int_use:N \__int_eval:w
+ \int_if_odd:nTF {#1}
+ { (\c_one - #1) / \c_two , 535 , { 0 } { } }
+ { \c_one - #1 / \c_two , 168 , { } { 0 } }
+ }
+\cs_new:Npn \__fp_ep_isqrt_auxii:wwnnnwn #1, #2, #3#4 #5#6; #7
+ {
+ \__fp_ep_isqrt_esti:wwwnnwn #2, 0, #5, {#3} {#4}
+ {#5} #6 ; { #7 #1 , }
+ }
+\cs_new:Npn \__fp_ep_isqrt_esti:wwwnnwn #1, #2, #3, #4
+ {
+ \if_int_compare:w #1 = #2 \exp_stop_f:
+ \exp_after:wN \__fp_ep_isqrt_estii:wwwnnwn
+ \fi:
+ \exp_after:wN \__fp_ep_isqrt_esti:wwwnnwn
+ \int_use:N \__int_eval:w
+ (#1 + 1 0050 0000 #4 / (#1 * #3)) / \c_two ,
+ #1, #3, {#4}
+ }
+\cs_new:Npn \__fp_ep_isqrt_estii:wwwnnwn #1, #2, #3, #4#5
+ {
+ \exp_after:wN \__fp_ep_isqrt_estiii:NNNNNwwwn
+ \int_use:N \__int_eval:w 1000 0000 + #2 * #2 #5 * \c_five
+ \exp_after:wN , \int_use:N \__int_eval:w 10000 + #2 ;
+ }
+\cs_new:Npn \__fp_ep_isqrt_estiii:NNNNNwwwn 1#1#2#3#4#5#6, 1#7#8; #9;
+ {
+ \__fp_fixed_mul_short:wwn #9; {#1} {#2#3#4#5} {#600} ;
+ \__fp_ep_isqrt_epsi:wN
+ \__fp_fixed_mul_short:wwn {#7} {#80} {0000} ;
+ }
+\cs_new:Npn \__fp_ep_isqrt_epsi:wN #1;
+ {
+ \__fp_fixed_sub:wwn {15000}{0000}{0000}{0000}{0000}{0000}; #1;
+ \__fp_ep_isqrt_epsii:wwN #1;
+ \__fp_ep_isqrt_epsii:wwN #1;
+ \__fp_ep_isqrt_epsii:wwN #1;
+ }
+\cs_new:Npn \__fp_ep_isqrt_epsii:wwN #1; #2;
+ {
+ \__fp_fixed_mul:wwn #1; #1;
+ \__fp_fixed_mul_sub_back:wwwn #2;
+ {15000}{0000}{0000}{0000}{0000}{0000};
+ \__fp_fixed_mul:wwn #1;
+ }
+\cs_new:Npn \__fp_ep_to_float:wwN #1,
+ { + \__int_eval:w #1 \__fp_fixed_to_float:wN }
+\cs_new:Npn \__fp_ep_inv_to_float:wwN #1,#2;
+ {
+ \__fp_ep_div:wwwwn 1,{1000}{0000}{0000}{0000}{0000}{0000}; #1,#2;
+ \__fp_ep_to_float:wwN
+ }
+\cs_new:Npn \__fp_fixed_inv_to_float:wN
+ { \__fp_ep_inv_to_float:wwN 0, }
+\cs_new:Npn \__fp_fixed_to_float_rad:wN #1;
+ {
+ \__fp_fixed_mul:wwn #1; {5729}{5779}{5130}{8232}{0876}{7981};
+ { \__fp_ep_to_float:wwN 2, }
+ }
\cs_new:Npn \__fp_fixed_to_float:Nw #1#2; { \__fp_fixed_to_float:wN #2; #1 }
\cs_new:Npn \__fp_fixed_to_float:wN #1#2#3#4#5#6; #7
{
- + \c_four % for the 8-digit-at-the-start thing.
+ + \__int_eval:w \c_four % for the 8-digit-at-the-start thing.
\exp_after:wN \exp_after:wN
\exp_after:wN \__fp_fixed_to_loop:N
\exp_after:wN \use_none:n
@@ -3033,111 +3305,7 @@
\exp_after:wN \__fp_basics_pack_low:NNNNNw
\int_use:N \__int_eval:w 1 #3#4 + \c_one ;
}
-\cs_new:Npn \__fp_fixed_inv_to_float:wN #1#2; #3
- {
- + \__int_eval:w % ^^A todo: remove the +?
- \if_int_compare:w #1 < \c_one_thousand
- \__fp_fixed_dtf_zeros:wNnnnnnn
- \fi:
- \__fp_fixed_dtf_no_zero:Nwn + {#1} #2 \s__fp
- \__fp_fixed_dtf_approx:n
- {10000} {0000} {0000} {0000} {0000} {0000} ;
- }
-\cs_new:Npn \__fp_fixed_div_to_float:ww #1#2; #3#4;
- {
- \if_int_compare:w #1 < \c_one_thousand
- \__fp_fixed_dtf_zeros:wNnnnnnn
- \fi:
- \__fp_fixed_dtf_no_zero:Nwn - {#1} #2 \s__fp
- {
- \if_int_compare:w #3 < \c_one_thousand
- \__fp_fixed_dtf_zeros:wNnnnnnn
- \fi:
- \__fp_fixed_dtf_no_zero:Nwn + {#3} #4 \s__fp
- \__fp_fixed_dtf_approx:n
- }
- }
-\cs_new:Npn \__fp_fixed_dtf_no_zero:Nwn #1#2 \s__fp #3 { #3 #2; }
-\cs_new:Npn \__fp_fixed_dtf_zeros:wNnnnnnn
- \fi: \__fp_fixed_dtf_no_zero:Nwn #1#2#3#4#5#6#7
- {
- \fi:
- #1 \c_minus_one
- \exp_after:wN \use_i_ii:nnn
- \exp_after:wN \__fp_fixed_dtf_zeros:NN
- \exp_after:wN #1
- \int_use:N \__int_eval:w 10 0000 + #2 \__int_eval_end: #3#4#5#6#7
- ; 1 ;
- }
-\cs_new:Npn \__fp_fixed_dtf_zeros:NN #1#2
- {
- \if_meaning:w 0 #2
- #1 \c_one
- \else:
- \__fp_fixed_dtf_zeros_end:wNww #2
- \fi:
- \__fp_fixed_dtf_zeros:NN #1
- }
-\cs_new:Npn \__fp_fixed_dtf_zeros_end:wNww
- #1 \fi: \__fp_fixed_dtf_zeros:NN #2 #3; #4 \s__fp
- {
- \fi:
- \if_meaning:w ; #1
- #2 \c_two * \c__fp_max_exponent_int
- \use_i_ii:nnn
- \fi:
- \__fp_fixed_dtf_zeros_auxi:ww
- #1#3 0000 0000 0000 0000 0000 0000 ;
- }
-\cs_new:Npn \__fp_fixed_dtf_zeros_auxi:ww
- {
- \__fp_pack_twice_four:wNNNNNNNN
- \__fp_pack_twice_four:wNNNNNNNN
- \__fp_pack_twice_four:wNNNNNNNN
- \__fp_fixed_dtf_zeros_auxii:ww
- ;
- }
-\cs_new:Npn \__fp_fixed_dtf_zeros_auxii:ww #1; #2; #3 { #3 #1; }
-\cs_new:Npn \__fp_fixed_dtf_approx:n #1
- {
- \exp_after:wN \__fp_fixed_dtf_approx:wnn
- \int_use:N \__int_eval:w 10 0000 0000 / ( #1 + \c_one ) ;
- {#1}
- }
-\cs_new:Npn \__fp_fixed_dtf_approx:wnn #1; #2#3
- {
- \exp_after:wN \__fp_fixed_dtf_approx:NNNNNw
- \int_use:N \__int_eval:w 10 0000 0000 - 1750
- + #1000 + (10 0000 0000/#2-#1) * (1000-#3/10) ;
- {#2}{#3}
- }
-\cs_new:Npn \__fp_fixed_dtf_approx:NNNNNw 1#1#2#3#4#5#6; #7; #8;
- {
- + \c_four % because of the line below "dtf_epsilon" here.
- \__fp_fixed_mul:wwn {000#1}{#2#3#4#5}{#6}{0000}{0000}{0000} ; #7;
- \__fp_fixed_dtf_epsilon:wN
- \__fp_fixed_mul:wwn {000#1}{#2#3#4#5}{#6}{0000}{0000}{0000} ;
- \__fp_fixed_mul:wwn #8;
- \__fp_fixed_to_float:wN ?
- }
-\cs_new:Npn \__fp_fixed_dtf_epsilon:wN #1#2#3#4#5#6;
- {
- \exp_after:wN \__fp_fixed_dtf_epsilon:NNNNNww
- \int_use:N \__int_eval:w 1 9999 9998 - #3#4 +
- \exp_after:wN \__fp_fixed_dtf_epsilon_pack:NNNNNw
- \int_use:N \__int_eval:w 2 0000 0000 - #5#6 ; {0000} ;
- }
-\cs_new:Npn \__fp_fixed_dtf_epsilon_pack:NNNNNw #1#2#3#4#5#6;
- { #1 ; {#2#3#4#5} {#6} }
-\cs_new:Npn \__fp_fixed_dtf_epsilon:NNNNNww #1#2#3#4#5#6; #7;
- {
- \__fp_fixed_mul:wwn %^^A todo: optimize to use \__fp_mul_significand.
- {0000} {#2#3#4#5} {#6} #7 ;
- {0000} {#2#3#4#5} {#6} #7 ;
- \__fp_fixed_add_one:wN
- \__fp_fixed_mul:wwn {10000} {#2#3#4#5} {#6} #7 ;
- }
-%% File: l3fp-expo.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-expo.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -3179,19 +3347,19 @@
\tl_const:Nn \c__fp_ln_viii_fixed_tl{{20794}{4154}{1679}{8359}{2825}{1696} }
\tl_const:Nn \c__fp_ln_ix_fixed_tl {{21972}{2457}{7336}{2193}{8279}{0490} }
\tl_const:Nn \c__fp_ln_x_fixed_tl {{23025}{8509}{2994}{0456}{8401}{7991} }
-\cs_new:Npn \__fp_ln_o:w \s__fp \__fp_chk:w #1 #2
+\cs_new:Npn \__fp_ln_o:w #1 \s__fp \__fp_chk:w #2#3#4; @
{
- \if_meaning:w 2 #2
+ \if_meaning:w 2 #3
\__fp_case_use:nw { \__fp_invalid_operation_o:nw { ln } }
\fi:
- \if_case:w #1 \exp_stop_f:
+ \if_case:w #2 \exp_stop_f:
\__fp_case_use:nw
{ \__fp_division_by_zero_o:Nnw \c_minus_inf_fp { ln } }
\or:
\else:
\__fp_case_return_same_o:w
\fi:
- \__fp_ln_npos_o:w \s__fp \__fp_chk:w #1#2
+ \__fp_ln_npos_o:w \s__fp \__fp_chk:w #2#3#4;
}
\cs_new:Npn \__fp_ln_npos_o:w \s__fp \__fp_chk:w 10#1#2#3;
{ %^^A todo: ln(1) should be "exact zero", not "underflow"
@@ -3400,14 +3568,14 @@
{0000}{#4}{#5}{#6}{#7}{#8};
\__fp_fixed_to_float:wN #1
}
-\cs_new:Npn \__fp_exp_o:w \s__fp \__fp_chk:w #1#2
+\cs_new:Npn \__fp_exp_o:w #1 \s__fp \__fp_chk:w #2#3#4; @
{
- \if_case:w #1 \exp_stop_f:
+ \if_case:w #2 \exp_stop_f:
\__fp_case_return_o:Nw \c_one_fp
\or:
\exp_after:wN \__fp_exp_normal:w
\or:
- \if_meaning:w 0 #2
+ \if_meaning:w 0 #3
\exp_after:wN \__fp_case_return_o:Nw
\exp_after:wN \c_inf_fp
\else:
@@ -3417,7 +3585,7 @@
\or:
\__fp_case_return_same_o:w
\fi:
- \s__fp \__fp_chk:w #1#2
+ \s__fp \__fp_chk:w #2#3#4;
}
\cs_new:Npn \__fp_exp_normal:w \s__fp \__fp_chk:w 1#1
{
@@ -3783,7 +3951,7 @@
\cs_new:Npn \__fp_pow_neg:www \s__fp \__fp_chk:w #1#2; #3; #4;
{
\if_case:w \__fp_pow_neg_case:w #4 ;
- \cs:w __fp_-_o:w \exp_after:wN \cs_end:
+ \exp_after:wN \__fp_pow_neg_aux:wNN
\or:
\if_int_compare:w \__int_eval:w #1 / \c_two = \c_one
\__fp_invalid_operation_o:Nww ^ #3; #4;
@@ -3795,6 +3963,14 @@
\__fp_exp_after_o:w
\s__fp \__fp_chk:w #1#2;
}
+\cs_new:Npn \__fp_pow_neg_aux:wNN #1 \s__fp \__fp_chk:w #2#3
+ {
+ \exp_after:wN \__fp_exp_after_o:w
+ \exp_after:wN \s__fp
+ \exp_after:wN \__fp_chk:w
+ \exp_after:wN #2
+ \int_use:N \__int_eval:w \c_two - #3 \__int_eval_end:
+ }
\cs_new:Npn \__fp_pow_neg_case:w \s__fp \__fp_chk:w #1#2#3;
{
\if_case:w #1 \exp_stop_f:
@@ -3839,7 +4015,7 @@
\c_one
\fi:
}
-%% File: l3fp-trig.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3fp-trig.dtx Copyright (C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -3872,203 +4048,418 @@
%%
%% -----------------------------------------------------------------------
%%
-\cs_new:Npn \__fp_sin_o:w \s__fp \__fp_chk:w #1#2
+\cs_new:Npn \__fp_sin_o:w #1 \s__fp \__fp_chk:w #2#3#4; @
{
- \if_case:w #1 \exp_stop_f:
+ \if_case:w #2 \exp_stop_f:
\__fp_case_return_same_o:w
- \or:
- \__fp_case_use:nw
- {
- \__fp_trig_exponent:NNNNNwn \__fp_trig_epsilon_o:w
- \__fp_sin_series:NNwww \__fp_fixed_to_float:wN #2 \c_zero
- }
- \or: \__fp_case_use:nw { \__fp_invalid_operation_o:nw { sin } }
+ \or: \__fp_case_use:nw
+ {
+ \__fp_trig:NNNNNwn #1 \__fp_sin_series_o:NNwwww
+ \__fp_ep_to_float:wwN #3 \c_zero
+ }
+ \or: \__fp_case_use:nw
+ { \__fp_invalid_operation_o:fw { #1 { sin } { sind } } }
\else: \__fp_case_return_same_o:w
\fi:
- \s__fp \__fp_chk:w #1#2
+ \s__fp \__fp_chk:w #2 #3 #4;
}
-\cs_new:Npn \__fp_cos_o:w \s__fp \__fp_chk:w #1#2
+\cs_new:Npn \__fp_cos_o:w #1 \s__fp \__fp_chk:w #2#3; @
{
- \if_case:w #1 \exp_stop_f:
+ \if_case:w #2 \exp_stop_f:
\__fp_case_return_o:Nw \c_one_fp
- \or:
- \__fp_case_use:nw
- {
- \__fp_trig_exponent:NNNNNwn \__fp_trig_epsilon_one_o:w
- \__fp_sin_series:NNwww \__fp_fixed_to_float:wN 0 \c_two
- }
- \or: \__fp_case_use:nw { \__fp_invalid_operation_o:nw { cos } }
+ \or: \__fp_case_use:nw
+ {
+ \__fp_trig:NNNNNwn #1 \__fp_sin_series_o:NNwwww
+ \__fp_ep_to_float:wwN 0 \c_two
+ }
+ \or: \__fp_case_use:nw
+ { \__fp_invalid_operation_o:fw { #1 { cos } { cosd } } }
\else: \__fp_case_return_same_o:w
\fi:
- \s__fp \__fp_chk:w #1#2
+ \s__fp \__fp_chk:w #2 #3;
}
-\cs_new:Npn \__fp_csc_o:w \s__fp \__fp_chk:w #1#2
+\cs_new:Npn \__fp_csc_o:w #1 \s__fp \__fp_chk:w #2#3#4; @
{
- \if_case:w #1 \exp_stop_f:
- \__fp_cot_zero_o:Nnw #2 { csc }
- \or:
- \__fp_case_use:nw
- {
- \__fp_trig_exponent:NNNNNwn \__fp_trig_epsilon_inv_o:w
- \__fp_sin_series:NNwww \__fp_fixed_inv_to_float:wN #2 \c_zero
- }
- \or: \__fp_case_use:nw { \__fp_invalid_operation_o:nw { csc } }
+ \if_case:w #2 \exp_stop_f:
+ \__fp_cot_zero_o:Nfw #3 { #1 { csc } { cscd } }
+ \or: \__fp_case_use:nw
+ {
+ \__fp_trig:NNNNNwn #1 \__fp_sin_series_o:NNwwww
+ \__fp_ep_inv_to_float:wwN #3 \c_zero
+ }
+ \or: \__fp_case_use:nw
+ { \__fp_invalid_operation_o:fw { #1 { csc } { cscd } } }
\else: \__fp_case_return_same_o:w
\fi:
- \s__fp \__fp_chk:w #1#2
+ \s__fp \__fp_chk:w #2 #3 #4;
}
-\cs_new:Npn \__fp_sec_o:w \s__fp \__fp_chk:w #1#2
+\cs_new:Npn \__fp_sec_o:w #1 \s__fp \__fp_chk:w #2#3; @
{
- \if_case:w #1 \exp_stop_f:
+ \if_case:w #2 \exp_stop_f:
\__fp_case_return_o:Nw \c_one_fp
- \or:
- \__fp_case_use:nw
- {
- \__fp_trig_exponent:NNNNNwn \__fp_trig_epsilon_one_o:w
- \__fp_sin_series:NNwww \__fp_fixed_inv_to_float:wN 0 \c_two
- }
- \or: \__fp_case_use:nw { \__fp_invalid_operation_o:nw { sec } }
+ \or: \__fp_case_use:nw
+ {
+ \__fp_trig:NNNNNwn #1 \__fp_sin_series_o:NNwwww
+ \__fp_ep_inv_to_float:wwN 0 \c_two
+ }
+ \or: \__fp_case_use:nw
+ { \__fp_invalid_operation_o:fw { #1 { sec } { secd } } }
\else: \__fp_case_return_same_o:w
\fi:
- \s__fp \__fp_chk:w #1#2
+ \s__fp \__fp_chk:w #2 #3;
}
-\cs_new:Npn \__fp_tan_o:w \s__fp \__fp_chk:w #1#2
+\cs_new:Npn \__fp_tan_o:w #1 \s__fp \__fp_chk:w #2#3#4; @
{
- \if_case:w #1 \exp_stop_f:
+ \if_case:w #2 \exp_stop_f:
\__fp_case_return_same_o:w
- \or:
- \__fp_case_use:nw
- {
- \__fp_trig_exponent:NNNNNwn \__fp_trig_epsilon_o:w
- \__fp_tan_series_o:NNwww 0 #2 \c_one
- }
- \or: \__fp_case_use:nw { \__fp_invalid_operation_o:nw { tan } }
+ \or: \__fp_case_use:nw
+ {
+ \__fp_trig:NNNNNwn #1
+ \__fp_tan_series_o:NNwwww 0 #3 \c_one
+ }
+ \or: \__fp_case_use:nw
+ { \__fp_invalid_operation_o:fw { #1 { tan } { tand } } }
\else: \__fp_case_return_same_o:w
\fi:
- \s__fp \__fp_chk:w #1#2
+ \s__fp \__fp_chk:w #2 #3 #4;
}
-\cs_new:Npn \__fp_cot_o:w \s__fp \__fp_chk:w #1#2
+\cs_new:Npn \__fp_cot_o:w #1 \s__fp \__fp_chk:w #2#3#4; @
{
- \if_case:w #1 \exp_stop_f:
- \__fp_cot_zero_o:Nnw #2 { cot }
- \or:
- \__fp_case_use:nw
- {
- \__fp_trig_exponent:NNNNNwn \__fp_trig_epsilon_inv_o:w
- \__fp_tan_series_o:NNwww 2 #2 \c_three
- }
- \or: \__fp_case_use:nw { \__fp_invalid_operation_o:nw { cot } }
+ \if_case:w #2 \exp_stop_f:
+ \__fp_cot_zero_o:Nfw #3 { #1 { cot } { cotd } }
+ \or: \__fp_case_use:nw
+ {
+ \__fp_trig:NNNNNwn #1
+ \__fp_tan_series_o:NNwwww 2 #3 \c_three
+ }
+ \or: \__fp_case_use:nw
+ { \__fp_invalid_operation_o:fw { #1 { cot } { cotd } } }
\else: \__fp_case_return_same_o:w
\fi:
- \s__fp \__fp_chk:w #1#2
+ \s__fp \__fp_chk:w #2 #3 #4;
}
-\cs_new:Npn \__fp_cot_zero_o:Nnw #1 #2 #3 \fi:
+\cs_new:Npn \__fp_cot_zero_o:Nfw #1#2#3 \fi:
{
\fi:
- \if_meaning:w 0 #1
- \exp_after:wN \__fp_division_by_zero_o:Nnw \exp_after:wN \c_inf_fp
- \else:
- \exp_after:wN \__fp_division_by_zero_o:Nnw \exp_after:wN \c_minus_inf_fp
- \fi:
+ \token_if_eq_meaning:NNTF 0 #1
+ { \exp_args:NNf \__fp_division_by_zero_o:Nnw \c_inf_fp }
+ { \exp_args:NNf \__fp_division_by_zero_o:Nnw \c_minus_inf_fp }
{#2}
}
-\cs_new:Npn \__fp_trig_exponent:NNNNNwn #1#2#3#4#5 \s__fp \__fp_chk:w 1#6#7
+\cs_new:Npn \__fp_trig:NNNNNwn #1#2#3#4#5 \s__fp \__fp_chk:w 1#6#7#8;
{
- \if_int_compare:w #7 > - \c_eight
- \exp_after:wN #2
- \exp_after:wN #3
- \exp_after:wN #4
- \int_use:N \__int_eval:w #5
- \if_int_compare:w #7 > \c_zero
- \exp_after:wN \__fp_trig_large:ww \__int_value:w
- \else:
- \exp_after:wN \__fp_trig_small:ww \__int_value:w
- \fi:
- \else:
- \exp_after:wN #1
- \exp_after:wN #6
- \fi:
- #7 ;
+ \exp_after:wN #2
+ \exp_after:wN #3
+ \exp_after:wN #4
+ \int_use:N \__int_eval:w #5
+ \exp_after:wN \exp_after:wN \exp_after:wN \exp_after:wN
+ \if_int_compare:w #7 > #1 \c_zero \c_one
+ #1 \__fp_trig_large:ww \__fp_trigd_large:ww
+ \else:
+ #1 \__fp_trig_small:ww \__fp_trigd_small:ww
+ \fi:
+ #7,#8{0000}{0000};
}
-\cs_new:Npn \__fp_trig_epsilon_o:w #1 #2 ;
- { \__fp_exp_after_o:w \s__fp \__fp_chk:w 1 #1 {#2} }
-\cs_new:Npn \__fp_trig_epsilon_one_o:w #1 ; #2 ;
- { \exp_after:wN \c_one_fp }
-\group_begin:
- \char_set_catcode_letter:N /
- \cs_new:Npn \__fp_trig_epsilon_inv_o:w #1 #2 ;
- {
- \exp_after:wN \__fp_/_o:ww
- \c_one_fp
- \s__fp \__fp_chk:w 1 #1 {#2}
- }
-\group_end:
-\cs_new:Npn \__fp_trig_small:ww #1; #2#3#4#5;
+\cs_new:Npn \__fp_trig_small:ww #1,#2;
+ { \__fp_ep_to_fixed:wwn #1,#2; . #1,#2; }
+\cs_new:Npn \__fp_trigd_small:ww #1,#2;
{
+ \__fp_ep_mul_raw:wwwwN
+ -1,{1745}{3292}{5199}{4329}{5769}{2369}; #1,#2;
+ \__fp_trig_small:ww
+ }
+\cs_new:Npn \__fp_trigd_large:ww #1, #2#3#4#5#6#7;
+ {
+ \exp_after:wN \__fp_pack_eight:wNNNNNNNN
+ \exp_after:wN \__fp_pack_eight:wNNNNNNNN
\exp_after:wN \__fp_pack_twice_four:wNNNNNNNN
\exp_after:wN \__fp_pack_twice_four:wNNNNNNNN
- \exp_after:wN \__fp_pack_twice_four:wNNNNNNNN
- \exp_after:wN .
+ \exp_after:wN \__fp_trigd_large_auxi:nnnnwNNNN
\exp_after:wN ;
\tex_romannumeral:D -`0
- \prg_replicate:nn { - #1 } { 0 } #2#3#4#5 0000 0000 ;
+ \prg_replicate:nn { \int_max:nn { 22 - #1 } { 0 } } { 0 }
+ #2#3#4#5#6#7 0000 0000 0000 !
}
-\cs_new:Npn \__fp_trig_large:ww #1; #2#3;
- { \__fp_trig_large:www #2; #3 ; #1; }
-\cs_new:Npn \__fp_trig_large:www #1; #2; #3;
+\cs_new:Npn \__fp_trigd_large_auxi:nnnnwNNNN #1#2#3#4#5; #6#7#8#9
{
- \if_meaning:w 0 #3 \__fp_trig_large_break:w \fi:
- \exp_after:wN \__fp_trig_large_o:wnnnn
- \int_use:N \__int_eval:w ( #10 - 31416 ) / 62833 ;
- {#1} #2
- \exp_after:wN ;
- \int_use:N \__int_eval:w \c_minus_one + #3;
- }
-\cs_new:Npn \__fp_trig_large_o:wnnnn #1; #2#3#4#5
- {
- \exp_after:wN \__fp_trig_large:www
- \int_use:N \__int_eval:w \c__fp_leading_shift_int + #20 - #1*62831
- \exp_after:wN \__fp_pack:NNNNNw
- \int_use:N \__int_eval:w \c__fp_middle_shift_int + #30 - #1*8530
- \exp_after:wN \__fp_pack:NNNNNw
- \int_use:N \__int_eval:w \c__fp_middle_shift_int + #40 - #1*7179
- \exp_after:wN \__fp_pack:NNNNNw
- \int_use:N \__int_eval:w \c__fp_trailing_shift_int + #50 - #1*5880
- \exp_after:wN ;
+ \exp_after:wN \__fp_trigd_large_auxii:wNw
+ \int_use:N \__int_eval:w #1 + #2
+ - (#1 + #2 - \c_four) / \c_nine * \c_nine \__int_eval_end:
+ #3;
+ #4; #5{#6#7#8#9};
}
-\cs_new:Npn \__fp_trig_large_break:w \fi: #1; #2;
- { \fi: \__fp_trig_octant_loop:nnnnnw #2 {0000} {0000} ; }
-\cs_new:Npn \__fp_trig_octant_loop:nnnnnw #1#2#3#4#5#6;
+\cs_new:Npn \__fp_trigd_large_auxii:wNw #1; #2#3;
{
- \if_int_compare:w #1#2 < 157079633 \exp_stop_f:
- \if_int_compare:w #1#2 = 157079632 \exp_stop_f:
- \if_int_compare:w #3#4 > 67948969 \exp_stop_f:
- \use_i_ii:nnn
- \fi:
- \fi:
- \__fp_trig_octant_break:w
- \fi:
- + \c_two
- \__fp_fixed_sub:wwn
- {#1} {#2} {#3} {#4} {0000} {0000} ;
- {15707} {9632} {6794} {8970} {0000} {0000} ;
- \__fp_trig_octant_loop:nnnnnw
+ + (#1#2 - \c_four) / \c_nine * \c_two
+ \exp_after:wN \__fp_trigd_large_auxiii:www
+ \int_use:N \__int_eval:w #1#2
+ - (#1#2 - \c_four) / \c_nine * \c_nine \__int_eval_end: #3 ;
}
-\cs_new:Npn \__fp_trig_octant_break:w #1 \fi: + #2#3 #4#5; #6; #7;
+\cs_new:Npn \__fp_trigd_large_auxiii:www #1; #2; #3!
{
- \fi:
- \if_int_compare:w #4 < 7854 \exp_stop_f:
+ \if_int_compare:w #1 < 4500 \exp_stop_f:
\exp_after:wN \__fp_use_i_until_s:nw
- \exp_after:wN .
+ \exp_after:wN \__fp_fixed_continue:wn
+ \else:
+ + \c_one
\fi:
- + \c_one
- \__fp_fixed_sub:wwn #6 ; {#4} #5 ; . ;
+ \__fp_fixed_sub:wwn {9000}{0000}{0000}{0000}{0000}{0000};
+ {#1}#2{0000}{0000};
+ { \__fp_trigd_small:ww 2, }
+ }
+\cs_new_nopar:Npx \__fp_trig_inverse_two_pi:
+ {
+ \exp_not:n { \exp_after:wN \use_none:n \token_to_str:N }
+ \cs:w , , !
+ 0000000000000000159154943091895335768883763372514362034459645740 ~
+ 4564487476673440588967976342265350901138027662530859560728427267 ~
+ 5795803689291184611457865287796741073169983922923996693740907757 ~
+ 3077746396925307688717392896217397661693362390241723629011832380 ~
+ 1142226997557159404618900869026739561204894109369378440855287230 ~
+ 9994644340024867234773945961089832309678307490616698646280469944 ~
+ 8652187881574786566964241038995874139348609983868099199962442875 ~
+ 5851711788584311175187671605465475369880097394603647593337680593 ~
+ 0249449663530532715677550322032477781639716602294674811959816584 ~
+ 0606016803035998133911987498832786654435279755070016240677564388 ~
+ 8495713108801221993761476813777647378906330680464579784817613124 ~
+ 2731406996077502450029775985708905690279678513152521001631774602 ~
+ 0924811606240561456203146484089248459191435211575407556200871526 ~
+ 6068022171591407574745827225977462853998751553293908139817724093 ~
+ 5825479707332871904069997590765770784934703935898280871734256403 ~
+ 6689511662545705943327631268650026122717971153211259950438667945 ~
+ 0376255608363171169525975812822494162333431451061235368785631136 ~
+ 3669216714206974696012925057833605311960859450983955671870995474 ~
+ 6510431623815517580839442979970999505254387566129445883306846050 ~
+ 7852915151410404892988506388160776196993073410389995786918905980 ~
+ 9373777206187543222718930136625526123878038753888110681406765434 ~
+ 0828278526933426799556070790386060352738996245125995749276297023 ~
+ 5940955843011648296411855777124057544494570217897697924094903272 ~
+ 9477021664960356531815354400384068987471769158876319096650696440 ~
+ 4776970687683656778104779795450353395758301881838687937766124814 ~
+ 9530599655802190835987510351271290432315804987196868777594656634 ~
+ 6221034204440855497850379273869429353661937782928735937843470323 ~
+ 0237145837923557118636341929460183182291964165008783079331353497 ~
+ 7909974586492902674506098936890945883050337030538054731232158094 ~
+ 3197676032283131418980974982243833517435698984750103950068388003 ~
+ 9786723599608024002739010874954854787923568261139948903268997427 ~
+ 0834961149208289037767847430355045684560836714793084567233270354 ~
+ 8539255620208683932409956221175331839402097079357077496549880868 ~
+ 6066360968661967037474542102831219251846224834991161149566556037 ~
+ 9696761399312829960776082779901007830360023382729879085402387615 ~
+ 5744543092601191005433799838904654921248295160707285300522721023 ~
+ 6017523313173179759311050328155109373913639645305792607180083617 ~
+ 9548767246459804739772924481092009371257869183328958862839904358 ~
+ 6866663975673445140950363732719174311388066383072592302759734506 ~
+ 0548212778037065337783032170987734966568490800326988506741791464 ~
+ 6835082816168533143361607309951498531198197337584442098416559541 ~
+ 5225064339431286444038388356150879771645017064706751877456059160 ~
+ 8716857857939226234756331711132998655941596890719850688744230057 ~
+ 5191977056900382183925622033874235362568083541565172971088117217 ~
+ 9593683256488518749974870855311659830610139214454460161488452770 ~
+ 2511411070248521739745103866736403872860099674893173561812071174 ~
+ 0478899368886556923078485023057057144063638632023685201074100574 ~
+ 8592281115721968003978247595300166958522123034641877365043546764 ~
+ 6456565971901123084767099309708591283646669191776938791433315566 ~
+ 5066981321641521008957117286238426070678451760111345080069947684 ~
+ 2235698962488051577598095339708085475059753626564903439445420581 ~
+ 7886435683042000315095594743439252544850674914290864751442303321 ~
+ 3324569511634945677539394240360905438335528292434220349484366151 ~
+ 4663228602477666660495314065734357553014090827988091478669343492 ~
+ 2737602634997829957018161964321233140475762897484082891174097478 ~
+ 2637899181699939487497715198981872666294601830539583275209236350 ~
+ 6853889228468247259972528300766856937583659722919824429747406163 ~
+ 8183113958306744348516928597383237392662402434501997809940402189 ~
+ 6134834273613676449913827154166063424829363741850612261086132119 ~
+ 9863346284709941839942742955915628333990480382117501161211667205 ~
+ 1912579303552929241134403116134112495318385926958490443846807849 ~
+ 0973982808855297045153053991400988698840883654836652224668624087 ~
+ 2540140400911787421220452307533473972538149403884190586842311594 ~
+ 6322744339066125162393106283195323883392131534556381511752035108 ~
+ 7459558201123754359768155340187407394340363397803881721004531691 ~
+ 8295194879591767395417787924352761740724605939160273228287946819 ~
+ 3649128949714953432552723591659298072479985806126900733218844526 ~
+ 7943350455801952492566306204876616134365339920287545208555344144 ~
+ 0990512982727454659118132223284051166615650709837557433729548631 ~
+ 2041121716380915606161165732000083306114606181280326258695951602 ~
+ 4632166138576614804719932707771316441201594960110632830520759583 ~
+ 4850305079095584982982186740289838551383239570208076397550429225 ~
+ 9847647071016426974384504309165864528360324933604354657237557916 ~
+ 1366324120457809969715663402215880545794313282780055246132088901 ~
+ 8742121092448910410052154968097113720754005710963406643135745439 ~
+ 9159769435788920793425617783022237011486424925239248728713132021 ~
+ 7667360756645598272609574156602343787436291321097485897150713073 ~
+ 9104072643541417970572226547980381512759579124002534468048220261 ~
+ 7342299001020483062463033796474678190501811830375153802879523433 ~
+ 4195502135689770912905614317878792086205744999257897569018492103 ~
+ 2420647138519113881475640209760554895793785141404145305151583964 ~
+ 2823265406020603311891586570272086250269916393751527887360608114 ~
+ 5569484210322407772727421651364234366992716340309405307480652685 ~
+ 0930165892136921414312937134106157153714062039784761842650297807 ~
+ 8606266969960809184223476335047746719017450451446166382846208240 ~
+ 8673595102371302904443779408535034454426334130626307459513830310 ~
+ 2293146934466832851766328241515210179422644395718121717021756492 ~
+ 1964449396532222187658488244511909401340504432139858628621083179 ~
+ 3939608443898019147873897723310286310131486955212620518278063494 ~
+ 5711866277825659883100535155231665984394090221806314454521212978 ~
+ 9734471488741258268223860236027109981191520568823472398358013366 ~
+ 0683786328867928619732367253606685216856320119489780733958419190 ~
+ 6659583867852941241871821727987506103946064819585745620060892122 ~
+ 8416394373846549589932028481236433466119707324309545859073361878 ~
+ 6290631850165106267576851216357588696307451999220010776676830946 ~
+ 9814975622682434793671310841210219520899481912444048751171059184 ~
+ 4139907889455775184621619041530934543802808938628073237578615267 ~
+ 7971143323241969857805637630180884386640607175368321362629671224 ~
+ 2609428540110963218262765120117022552929289655594608204938409069 ~
+ 0760692003954646191640021567336017909631872891998634341086903200 ~
+ 5796637103128612356988817640364252540837098108148351903121318624 ~
+ 7228181050845123690190646632235938872454630737272808789830041018 ~
+ 9485913673742589418124056729191238003306344998219631580386381054 ~
+ 2457893450084553280313511884341007373060595654437362488771292628 ~
+ 9807423539074061786905784443105274262641767830058221486462289361 ~
+ 9296692992033046693328438158053564864073184440599549689353773183 ~
+ 6726613130108623588021288043289344562140479789454233736058506327 ~
+ 0439981932635916687341943656783901281912202816229500333012236091 ~
+ 8587559201959081224153679499095448881099758919890811581163538891 ~
+ 6339402923722049848375224236209100834097566791710084167957022331 ~
+ 7897107102928884897013099533995424415335060625843921452433864640 ~
+ 3432440657317477553405404481006177612569084746461432976543900008 ~
+ 3826521145210162366431119798731902751191441213616962045693602633 ~
+ 6102355962140467029012156796418735746835873172331004745963339773 ~
+ 2477044918885134415363760091537564267438450166221393719306748706 ~
+ 2881595464819775192207710236743289062690709117919412776212245117 ~
+ 2354677115640433357720616661564674474627305622913332030953340551 ~
+ 3841718194605321501426328000879551813296754972846701883657425342 ~
+ 5016994231069156343106626043412205213831587971115075454063290657 ~
+ 0248488648697402872037259869281149360627403842332874942332178578 ~
+ 7750735571857043787379693402336902911446961448649769719434527467 ~
+ 4429603089437192540526658890710662062575509930379976658367936112 ~
+ 8137451104971506153783743579555867972129358764463093757203221320 ~
+ 2460565661129971310275869112846043251843432691552928458573495971 ~
+ 5042565399302112184947232132380516549802909919676815118022483192 ~
+ 5127372199792134331067642187484426215985121676396779352982985195 ~
+ 8545392106957880586853123277545433229161989053189053725391582222 ~
+ 9232597278133427818256064882333760719681014481453198336237910767 ~
+ 1255017528826351836492103572587410356573894694875444694018175923 ~
+ 0609370828146501857425324969212764624247832210765473750568198834 ~
+ 5641035458027261252285503154325039591848918982630498759115406321 ~
+ 0354263890012837426155187877318375862355175378506956599570028011 ~
+ 5841258870150030170259167463020842412449128392380525772514737141 ~
+ 2310230172563968305553583262840383638157686828464330456805994018 ~
+ 7001071952092970177990583216417579868116586547147748964716547948 ~
+ 8312140431836079844314055731179349677763739898930227765607058530 ~
+ 4083747752640947435070395214524701683884070908706147194437225650 ~
+ 2823145872995869738316897126851939042297110721350756978037262545 ~
+ 8141095038270388987364516284820180468288205829135339013835649144 ~
+ 3004015706509887926715417450706686888783438055583501196745862340 ~
+ 8059532724727843829259395771584036885940989939255241688378793572 ~
+ 7967951654076673927031256418760962190243046993485989199060012977 ~
+ 7469214532970421677817261517850653008552559997940209969455431545 ~
+ 2745856704403686680428648404512881182309793496962721836492935516 ~
+ 2029872469583299481932978335803459023227052612542114437084359584 ~
+ 9443383638388317751841160881711251279233374577219339820819005406 ~
+ 3292937775306906607415304997682647124407768817248673421685881509 ~
+ 9133422075930947173855159340808957124410634720893194912880783576 ~
+ 3115829400549708918023366596077070927599010527028150868897828549 ~
+ 4340372642729262103487013992868853550062061514343078665396085995 ~
+ 0058714939141652065302070085265624074703660736605333805263766757 ~
+ 2018839497277047222153633851135483463624619855425993871933367482 ~
+ 0422097449956672702505446423243957506869591330193746919142980999 ~
+ 3424230550172665212092414559625960554427590951996824313084279693 ~
+ 7113207021049823238195747175985519501864630940297594363194450091 ~
+ 9150616049228764323192129703446093584259267276386814363309856853 ~
+ 2786024332141052330760658841495858718197071242995959226781172796 ~
+ 4438853796763139274314227953114500064922126500133268623021550837
+ \cs_end:
+ }
+\cs_new:Npn \__fp_trig_large:ww #1, #2#3#4#5#6;
+ {
+ \exp_after:wN \__fp_trig_large_auxi:wwwwww
+ \int_use:N \__int_eval:w (#1 - 32) / 64 \exp_after:wN ,
+ \int_use:N \__int_eval:w (#1 - 4) / 8 \exp_after:wN ,
+ \__int_value:w #1 \__fp_trig_inverse_two_pi: ;
+ {#2}{#3}{#4}{#5} ;
+ }
+\cs_new:Npn \__fp_trig_large_auxi:wwwwww #1, #2, #3, #4!
+ {
+ \prg_replicate:nn {#1} { \__fp_trig_large_auxii:ww }
+ \prg_replicate:nn { #2 - #1 * \c_eight }
+ { \__fp_trig_large_auxiii:wNNNNNNNN }
+ \prg_replicate:nn { #3 - #2 * \c_eight }
+ { \__fp_trig_large_auxiv:wN }
+ \prg_replicate:nn { \c_eight } { \__fp_pack_twice_four:wNNNNNNNN }
+ \__fp_trig_large_auxv:www
+ ;
+ }
+\cs_new:Npn \__fp_trig_large_auxii:ww #1; #2 ~ { #1; }
+\cs_new:Npn \__fp_trig_large_auxiii:wNNNNNNNN
+ #1; #2#3#4#5#6#7#8#9 { #1; }
+\cs_new:Npn \__fp_trig_large_auxiv:wN #1; #2 { #1; }
+\cs_new:Npn \__fp_trig_large_auxv:www #1; #2; #3;
+ {
+ \exp_after:wN \__fp_use_i_until_s:nw
+ \exp_after:wN \__fp_trig_large_auxvii:w
+ \int_use:N \__int_eval:w \c__fp_leading_shift_int
+ \prg_replicate:nn { \c_thirteen }
+ { \__fp_trig_large_auxvi:wnnnnnnnn }
+ + \c__fp_trailing_shift_int - \c__fp_middle_shift_int
+ \__fp_use_i_until_s:nw
+ ; #3 #1 ; ;
+ }
+\cs_new:Npn \__fp_trig_large_auxvi:wnnnnnnnn #1; #2#3#4#5#6#7#8#9
+ {
+ \exp_after:wN \__fp_trig_large_pack:NNNNNw
+ \int_use:N \__int_eval:w \c__fp_middle_shift_int
+ + #2*#9 + #3*#8 + #4*#7 + #5*#6
+ #1; {#2}{#3}{#4}{#5} {#7}{#8}{#9}
+ }
+\cs_new:Npn \__fp_trig_large_pack:NNNNNw #1#2#3#4#5#6;
+ { + #1#2#3#4#5 ; #6 }
+\cs_new:Npn \__fp_trig_large_auxvii:w #1#2#3
+ {
+ \exp_after:wN \__fp_trig_large_auxviii:ww
+ \int_use:N \__int_eval:w (#1#2#3 - 62) / 125 ;
+ #1#2#3
+ }
+\cs_new:Npn \__fp_trig_large_auxviii:ww #1;
+ {
+ + #1
+ \if_int_odd:w #1 \exp_stop_f:
+ \exp_after:wN \__fp_trig_large_auxix:Nw
+ \exp_after:wN -
+ \else:
+ \exp_after:wN \__fp_trig_large_auxix:Nw
+ \exp_after:wN +
+ \fi:
+ }
+\cs_new_nopar:Npn \__fp_trig_large_auxix:Nw
+ {
+ \exp_after:wN \__fp_use_i_until_s:nw
+ \exp_after:wN \__fp_trig_large_auxxi:w
+ \int_use:N \__int_eval:w \c__fp_leading_shift_int
+ \prg_replicate:nn { \c_thirteen }
+ { \__fp_trig_large_auxx:wNNNNN }
+ + \c__fp_trailing_shift_int - \c__fp_middle_shift_int
+ ;
+ }
+\cs_new:Npn \__fp_trig_large_auxx:wNNNNN #1; #2 #3#4#5#6
+ {
+ \exp_after:wN \__fp_trig_large_pack:NNNNNw
+ \int_use:N \__int_eval:w \c__fp_middle_shift_int
+ #2 \c_eight * #3#4#5#6
+ #1; #2
}
-\cs_new:Npn \__fp_sin_series:NNwww #1#2#3 . #4; #5;
+\cs_new:Npn \__fp_trig_large_auxxi:w #1;
+ {
+ \exp_after:wN \__fp_ep_mul_raw:wwwwN
+ \int_use:N \__int_eval:w \c_zero \__fp_ep_to_ep_loop:N #1 ; ; !
+ 0,{7853}{9816}{3397}{4483}{0961}{5661};
+ \__fp_trig_small:ww
+ }
+\cs_new:Npn \__fp_sin_series_o:NNwwww #1#2#3. #4;
{
\__fp_fixed_mul:wwn #4; #4;
{
- \exp_after:wN \__fp_sin_series_aux:NNnww
+ \exp_after:wN \__fp_sin_series_aux_o:NNnwww
\exp_after:wN #1
\__int_value:w
\if_int_odd:w \__int_eval:w ( #3 + \c_two ) / \c_four \__int_eval_end:
@@ -4078,9 +4469,8 @@
\fi:
{#3}
}
- #4 ;
}
-\cs_new:Npn \__fp_sin_series_aux:NNnww #1#2#3 #4; #5;
+\cs_new:Npn \__fp_sin_series_aux_o:NNnwww #1#2#3 #4; #5,#6;
{
\if_int_odd:w \__int_eval:w #3 / \c_two \__int_eval_end:
\exp_after:wN \use_i:nn
@@ -4098,6 +4488,7 @@
\__fp_fixed_mul_sub_back:wwwn #4; {0416}{6666}{6666}{6666}{6666}{6667};
\__fp_fixed_mul_sub_back:wwwn #4; {5000}{0000}{0000}{0000}{0000}{0000};
\__fp_fixed_mul_sub_back:wwwn #4;{10000}{0000}{0000}{0000}{0000}{0000};
+ { \__fp_fixed_continue:wn 0, }
}
{ % 1/17!
\__fp_fixed_mul_sub_back:wwwn {0000}{0000}{0000}{0028}{1145}{7254};
@@ -4109,7 +4500,7 @@
\__fp_fixed_mul_sub_back:wwwn #4; {0083}{3333}{3333}{3333}{3333}{3333};
\__fp_fixed_mul_sub_back:wwwn #4; {1666}{6666}{6666}{6666}{6666}{6667};
\__fp_fixed_mul_sub_back:wwwn #4;{10000}{0000}{0000}{0000}{0000}{0000};
- \__fp_fixed_mul:wwn #5;
+ { \__fp_ep_mul:wwwwn 0, } #5,#6;
}
{
\exp_after:wN \__fp_sanitize:Nw
@@ -4118,11 +4509,11 @@
}
#2
}
-\cs_new:Npn \__fp_tan_series_o:NNwww #1#2#3. #4; #5;
+\cs_new:Npn \__fp_tan_series_o:NNwwww #1#2#3. #4;
{
\__fp_fixed_mul:wwn #4; #4;
{
- \exp_after:wN \__fp_tan_series_aux_o:Nnww
+ \exp_after:wN \__fp_tan_series_aux_o:Nnwww
\__int_value:w
\if_int_odd:w \__int_eval:w #3 / \c_two \__int_eval_end:
\exp_after:wN \reverse_if:N
@@ -4130,9 +4521,8 @@
\if_meaning:w #1#2 2 \else: 0 \fi:
{#3}
}
- #4 ;
}
-\cs_new:Npn \__fp_tan_series_aux_o:Nnww #1 #2 #3; #4;
+\cs_new:Npn \__fp_tan_series_aux_o:Nnwww #1 #2 #3; #4,#5;
{
\__fp_fixed_mul_sub_back:wwwn {0000}{0000}{1527}{3493}{0856}{7059};
#3; {0000}{0159}{6080}{0274}{5257}{6472};
@@ -4140,27 +4530,302 @@
\__fp_fixed_mul_sub_back:wwwn #3; {0115}{5830}{7533}{5397}{3168}{2147};
\__fp_fixed_mul_sub_back:wwwn #3; {1929}{8245}{6140}{3508}{7719}{2982};
\__fp_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000};
- \__fp_fixed_mul:wwn #4;
+ { \__fp_ep_mul:wwwwn 0, } #4,#5;
+ {
+ \__fp_fixed_mul_sub_back:wwwn {0000}{0007}{0258}{0681}{9408}{4706};
+ #3; {0000}{2343}{7175}{1399}{6151}{7670};
+ \__fp_fixed_mul_sub_back:wwwn #3; {0019}{2638}{4588}{9232}{8861}{3691};
+ \__fp_fixed_mul_sub_back:wwwn #3; {0536}{6357}{0691}{4344}{6852}{4252};
+ \__fp_fixed_mul_sub_back:wwwn #3; {5263}{1578}{9473}{6842}{1052}{6315};
+ \__fp_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000};
{
- \__fp_fixed_mul_sub_back:wwwn {0000}{0007}{0258}{0681}{9408}{4706};
- #3; {0000}{2343}{7175}{1399}{6151}{7670};
- \__fp_fixed_mul_sub_back:wwwn #3; {0019}{2638}{4588}{9232}{8861}{3691};
- \__fp_fixed_mul_sub_back:wwwn #3; {0536}{6357}{0691}{4344}{6852}{4252};
- \__fp_fixed_mul_sub_back:wwwn #3; {5263}{1578}{9473}{6842}{1052}{6315};
- \__fp_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000};
- {
- \exp_after:wN \__fp_sanitize:Nw
- \exp_after:wN #1
- \int_use:N \__int_eval:w
- \reverse_if:N \if_int_odd:w
- \__int_eval:w (#2 - \c_one) / \c_two \__int_eval_end:
- \exp_after:wN \__fp_reverse_args:Nww
- \fi:
- \__fp_fixed_div_to_float:ww
- }
+ \reverse_if:N \if_int_odd:w
+ \__int_eval:w (#2 - \c_one) / \c_two \__int_eval_end:
+ \exp_after:wN \__fp_reverse_args:Nww
+ \fi:
+ \__fp_ep_div:wwwwn 0,
}
+ }
+ {
+ \exp_after:wN \__fp_sanitize:Nw
+ \exp_after:wN #1
+ \int_use:N \__int_eval:w \__fp_ep_to_float:wwN
+ }
+ #1
+ }
+\cs_new_nopar:Npn \__fp_atan_o:Nw
+ {
+ \__fp_atan_dispatch_o:NNnNw
+ \__fp_acotii_o:Nww \__fp_atanii_o:Nww { atan }
+ }
+\cs_new_nopar:Npn \__fp_acot_o:Nw
+ {
+ \__fp_atan_dispatch_o:NNnNw
+ \__fp_atanii_o:Nww \__fp_acotii_o:Nww { acot }
}
-%% File: l3fp-convert.dtx Copyright(C) 2011-2012 The LaTeX3 Project
+\cs_new:Npn \__fp_atan_dispatch_o:NNnNw #1#2#3#4#5@
+ {
+ \if_case:w
+ \__int_eval:w \__fp_array_count:n {#5} - \c_one \__int_eval_end:
+ \exp_after:wN #1 \exp_after:wN #4 \c_one_fp #5
+ \tex_romannumeral:D
+ \or: #2 #4 #5 \tex_romannumeral:D
+ \else:
+ \__msg_kernel_expandable_error:nnnnn
+ { kernel } { fp-num-args } { #3() } { 1 } { 2 }
+ \exp_after:wN \c_nan_fp \tex_romannumeral:D
+ \fi:
+ \exp_after:wN \c_zero
+ }
+\cs_new:Npn \__fp_atanii_o:Nww
+ #1 \s__fp \__fp_chk:w #2#3#4; \s__fp \__fp_chk:w #5
+ {
+ \if_meaning:w 3 #2 \__fp_case_return_i_o:ww \fi:
+ \if_meaning:w 3 #5 \__fp_case_return_ii_o:ww \fi:
+ \if_case:w
+ \if_meaning:w #2 #5
+ \if_meaning:w 1 #2 \c_ten \else: \c_zero \fi:
+ \else:
+ \if_int_compare:w #2 > #5 \c_one \else: \c_two \fi:
+ \fi:
+ \__fp_case_return:nw { \__fp_atan_inf_o:NNNw #1 #3 \c_two }
+ \or: \__fp_case_return:nw { \__fp_atan_inf_o:NNNw #1 #3 \c_four }
+ \or: \__fp_case_return:nw { \__fp_atan_inf_o:NNNw #1 #3 \c_zero }
+ \fi:
+ \__fp_atan_normal_o:NNnwNnw #1
+ \s__fp \__fp_chk:w #2#3#4;
+ \s__fp \__fp_chk:w #5
+ }
+\cs_new:Npn \__fp_acotii_o:Nww #1#2; #3;
+ { \__fp_atanii_o:Nww #1#3; #2; }
+\cs_new:Npn \__fp_atan_inf_o:NNNw #1#2#3 \s__fp \__fp_chk:w #4#5#6;
+ {
+ \exp_after:wN \__fp_atan_combine_o:NwwwwwN
+ \exp_after:wN #2
+ \int_use:N \__int_eval:w
+ \if_meaning:w 2 #5 \c_seven - \fi: #3 \exp_after:wN ;
+ \c__fp_one_fixed_tl ;
+ {0000}{0000}{0000}{0000}{0000}{0000};
+ 0,{0000}{0000}{0000}{0000}{0000}{0000}; #1
+ }
+\cs_new_protected:Npn \__fp_atan_normal_o:NNnwNnw
+ #1 \s__fp \__fp_chk:w 1#2#3#4; \s__fp \__fp_chk:w 1#5#6#7;
+ {
+ \__fp_atan_test_o:NwwNwwN
+ #2 #3, #4{0000}{0000};
+ #5 #6, #7{0000}{0000}; #1
+ }
+\cs_new:Npn \__fp_atan_test_o:NwwNwwN #1#2,#3; #4#5,#6;
+ {
+ \exp_after:wN \__fp_atan_combine_o:NwwwwwN
+ \exp_after:wN #1
+ \int_use:N \__int_eval:w
+ \if_meaning:w 2 #4
+ \c_seven - \__int_eval:w
+ \fi:
+ \if_int_compare:w
+ \__fp_ep_compare:wwww #2,#3; #5,#6; > \c_zero
+ \c_three -
+ \exp_after:wN \__fp_reverse_args:Nww
+ \fi:
+ \__fp_atan_div:wnwwnw #2,#3; #5,#6;
+ }
+\cs_new:Npn \__fp_atan_div:wnwwnw #1,#2#3; #4,#5#6;
+ {
+ \if_int_compare:w
+ \__int_eval:w 41421 * #5 < #2 000
+ \if_case:w \__int_eval:w #4 - #1 \__int_eval_end: 00 \or: 0 \fi:
+ \exp_stop_f:
+ \exp_after:wN \__fp_atan_near:wwwn
+ \fi:
+ \c_zero
+ \__fp_ep_div:wwwwn #1,{#2}#3; #4,{#5}#6;
+ \__fp_atan_auxi:ww
+ }
+\cs_new:Npn \__fp_atan_near:wwwn
+ \c_zero \__fp_ep_div:wwwwn #1,#2; #3,
+ {
+ \c_one
+ \__fp_ep_to_fixed:wwn #1 - #3, #2;
+ \__fp_atan_near_aux:wwn
+ }
+\cs_new:Npn \__fp_atan_near_aux:wwn #1; #2;
+ {
+ \__fp_fixed_add:wwn #1; #2;
+ { \__fp_fixed_sub:wwn #2; #1; { \__fp_ep_div:wwwwn 0, } 0, }
+ }
+\cs_new:Npn \__fp_atan_auxi:ww #1,#2;
+ { \__fp_ep_to_fixed:wwn #1,#2; \__fp_atan_auxii:w #1,#2; }
+\cs_new:Npn \__fp_atan_auxii:w #1;
+ {
+ \__fp_fixed_mul:wwn #1; #1;
+ {
+ \__fp_atan_Taylor_loop:www 39 ;
+ {0000}{0000}{0000}{0000}{0000}{0000} ;
+ }
+ ! #1;
+ }
+\cs_new:Npn \__fp_atan_Taylor_loop:www #1; #2; #3;
+ {
+ \if_int_compare:w #1 = \c_minus_one
+ \__fp_atan_Taylor_break:w
+ \fi:
+ \exp_after:wN \__fp_fixed_div_int:wwN \c__fp_one_fixed_tl ; #1;
+ \__fp_rrot:www \__fp_fixed_mul_sub_back:wwwn #2; #3;
+ {
+ \exp_after:wN \__fp_atan_Taylor_loop:www
+ \int_use:N \__int_eval:w #1 - \c_two ;
+ }
+ #3;
+ }
+\cs_new:Npn \__fp_atan_Taylor_break:w
+ \fi: #1 \__fp_fixed_mul_sub_back:wwwn #2; #3 !
+ { \fi: ; #2 ; }
+\cs_new:Npn \__fp_atan_combine_o:NwwwwwN #1 #2; #3; #4; #5,#6; #7
+ {
+ \exp_after:wN \__fp_sanitize:Nw
+ \exp_after:wN #1
+ \int_use:N \__int_eval:w
+ \if_meaning:w 0 #2
+ \exp_after:wN \use_i:nn
+ \else:
+ \exp_after:wN \use_ii:nn
+ \fi:
+ { #5 \__fp_fixed_mul:wwn #3; #6; }
+ {
+ \__fp_fixed_mul:wwn #3; #4;
+ {
+ \exp_after:wN \__fp_atan_combine_aux:ww
+ \int_use:N \__int_eval:w #2 / \c_two ; #2;
+ }
+ }
+ { #7 \__fp_fixed_to_float:wN \__fp_fixed_to_float_rad:wN }
+ #1
+ }
+\cs_new:Npn \__fp_atan_combine_aux:ww #1; #2;
+ {
+ \__fp_fixed_mul_short:wwn
+ {7853}{9816}{3397}{4483}{0961}{5661};
+ {#1}{0000}{0000};
+ {
+ \if_int_odd:w #2 \exp_stop_f:
+ \exp_after:wN \__fp_fixed_sub:wwn
+ \else:
+ \exp_after:wN \__fp_fixed_add:wwn
+ \fi:
+ }
+ }
+\cs_new:Npn \__fp_asin_o:w #1 \s__fp \__fp_chk:w #2#3; @
+ {
+ \if_case:w #2 \exp_stop_f:
+ \__fp_case_return_same_o:w
+ \or:
+ \__fp_case_use:nw
+ { \__fp_asin_normal_o:NfwNnnnnw #1 { #1 { asin } { asind } } }
+ \or:
+ \__fp_case_use:nw
+ { \__fp_invalid_operation_o:fw { #1 { asin } { asind } } }
+ \else:
+ \__fp_case_return_same_o:w
+ \fi:
+ \s__fp \__fp_chk:w #2 #3;
+ }
+\cs_new:Npn \__fp_acos_o:w #1 \s__fp \__fp_chk:w #2#3; @
+ {
+ \if_case:w #2 \exp_stop_f:
+ \__fp_case_use:nw { \__fp_atan_inf_o:NNNw #1 0 \c_four }
+ \or:
+ \__fp_case_use:nw
+ {
+ \__fp_asin_normal_o:NfwNnnnnw #1 { #1 { acos } { acosd } }
+ \__fp_reverse_args:Nww
+ }
+ \or:
+ \__fp_case_use:nw
+ { \__fp_invalid_operation_o:fw { #1 { acos } { acosd } } }
+ \else:
+ \__fp_case_return_same_o:w
+ \fi:
+ \s__fp \__fp_chk:w #2 #3;
+ }
+\cs_new:Npn \__fp_asin_normal_o:NfwNnnnnw
+ #1#2#3 \s__fp \__fp_chk:w 1#4#5#6#7#8#9;
+ {
+ \if_int_compare:w #5 < \c_one
+ \exp_after:wN \__fp_use_none_until_s:w
+ \fi:
+ \if_int_compare:w \__int_eval:w #5 + #6#7 + #8#9 = 1000 0001 ~
+ \exp_after:wN \__fp_use_none_until_s:w
+ \fi:
+ \__fp_use_i:ww
+ \__fp_invalid_operation_o:fw {#2}
+ \s__fp \__fp_chk:w 1#4{#5}{#6}{#7}{#8}{#9};
+ \__fp_asin_auxi_o:NnNww
+ #1 {#3} #4 #5,{#6}{#7}{#8}{#9}{0000}{0000};
+ }
+\cs_new:Npn \__fp_asin_auxi_o:NnNww #1#2#3#4,#5;
+ {
+ \__fp_ep_to_fixed:wwn #4,#5;
+ \__fp_asin_isqrt:wn
+ \__fp_ep_mul:wwwwn #4,#5;
+ \__fp_ep_to_ep:wwN
+ \__fp_fixed_continue:wn
+ { #2 \__fp_atan_test_o:NwwNwwN #3 }
+ 0 1,{1000}{0000}{0000}{0000}{0000}{0000}; #1
+ }
+\cs_new:Npn \__fp_asin_isqrt:wn #1;
+ {
+ \exp_after:wN \__fp_fixed_sub:wwn \c__fp_one_fixed_tl ; #1;
+ {
+ \__fp_fixed_add_one:wN #1;
+ \__fp_fixed_continue:wn { \__fp_ep_mul:wwwwn 0, } 0,
+ }
+ \__fp_ep_isqrt:wwn
+ }
+\cs_new:Npn \__fp_acsc_o:w #1 \s__fp \__fp_chk:w #2#3#4; @
+ {
+ \if_case:w \if_meaning:w 2 #2 #3 \fi: #2 \exp_stop_f:
+ \__fp_case_use:nw
+ { \__fp_invalid_operation_o:fw { #1 { acsc } { acscd } } }
+ \or: \__fp_case_use:nw
+ { \__fp_acsc_normal_o:NfwNnw #1 { #1 { acsc } { acscd } } }
+ \or: \__fp_case_return_o:Nw \c_zero_fp
+ \or: \__fp_case_return_same_o:w
+ \else: \__fp_case_return_o:Nw \c_minus_zero_fp
+ \fi:
+ \s__fp \__fp_chk:w #2 #3 #4;
+ }
+\cs_new:Npn \__fp_asec_o:w #1 \s__fp \__fp_chk:w #2#3; @
+ {
+ \if_case:w #2 \exp_stop_f:
+ \__fp_case_use:nw
+ { \__fp_invalid_operation_o:fw { #1 { asec } { asecd } } }
+ \or:
+ \__fp_case_use:nw
+ {
+ \__fp_acsc_normal_o:NfwNnw #1 { #1 { asec } { asecd } }
+ \__fp_reverse_args:Nww
+ }
+ \or: \__fp_case_use:nw { \__fp_atan_inf_o:NNNw #1 0 \c_four }
+ \else: \__fp_case_return_same_o:w
+ \fi:
+ \s__fp \__fp_chk:w #2 #3;
+ }
+\cs_new:Npn \__fp_acsc_normal_o:NfwNnw #1#2#3 \s__fp \__fp_chk:w 1#4#5#6;
+ {
+ \int_compare:nNnTF {#5} < \c_one
+ {
+ \__fp_invalid_operation_o:fw {#2}
+ \s__fp \__fp_chk:w 1#4{#5}#6;
+ }
+ {
+ \__fp_ep_div:wwwwn
+ 1,{1000}{0000}{0000}{0000}{0000}{0000};
+ #5,#6{0000}{0000};
+ { \__fp_asin_auxi_o:NnNww #1 {#3} #4 }
+ }
+ }
+%% File: l3fp-convert.dtx Copyright(C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -4376,37 +5041,38 @@
}
\cs_new:Npn \dim_to_fp:n #1
{
- \exp_after:wN \__fp_from_dim_test:N
+ \exp_after:wN \__fp_from_dim_test:ww
+ \exp_after:wN 0
+ \exp_after:wN ,
\__int_value:w \etex_glueexpr:D #1 ;
}
-\cs_new:Npn \__fp_from_dim_test:N #1
+\cs_new:Npn \__fp_from_dim_test:ww #1, #2
{
- \if_meaning:w 0 #1
- \__fp_case_return:nw \c_zero_fp
+ \if_meaning:w 0 #2
+ \__fp_case_return:nw { \exp_after:wN \c_zero_fp }
\else:
- \if_meaning:w - #1
- \exp_after:wN \__fp_from_dim:Nw
- \exp_after:wN 2
- \__int_value:w
- \else:
- \exp_after:wN \__fp_from_dim:Nw
- \exp_after:wN 0
- \__int_value:w #1
- \fi:
+ \exp_after:wN \__fp_from_dim:wNw
+ \int_use:N \__int_eval:w #1 - \c_four
+ \if_meaning:w - #2
+ \exp_after:wN , \exp_after:wN 2 \__int_value:w
+ \else:
+ \exp_after:wN , \exp_after:wN 0 \__int_value:w #2
+ \fi:
\fi:
}
-\cs_new:Npn \__fp_from_dim:Nw #1 #2;
+\cs_new:Npn \__fp_from_dim:wNw #1,#2#3;
{
\__fp_pack_twice_four:wNNNNNNNN \__fp_from_dim:wNNnnnnnn ;
- #2 000 0000 00 {10}987654321; #1
+ #3 000 0000 00 {10}987654321; #2 {#1}
}
\cs_new:Npn \__fp_from_dim:wNNnnnnnn #1; #2#3#4#5#6#7#8#9
- { \__fp_from_dim:wnnnnwN #1 {#2#300} {0000} ; }
-\cs_new:Npn \__fp_from_dim:wnnnnwN #1; #2#3#4#5#6; #7
+ { \__fp_from_dim:wnnnnwNn #1 {#2#300} {0000} ; }
+\cs_new:Npn \__fp_from_dim:wnnnnwNn #1; #2#3#4#5#6; #7#8
{
\__fp_mul_npos_o:Nww #7
\s__fp \__fp_chk:w 1 #7 {#5} #1 ;
- \s__fp \__fp_chk:w 1 0 {-4} {1525} {8789} {0625} {0000} ;
+ \s__fp \__fp_chk:w 1 0 {#8} {1525} {8789} {0625} {0000} ;
+ \prg_do_nothing:
}
\cs_new_eq:NN \fp_use:N \fp_to_decimal:N
\cs_generate_variant:Nn \fp_use:N { c }
@@ -4442,7 +5108,7 @@
\exp_not:N \__fp_array_to_clist_loop:Nw
}
%%
-%% File: l3fp-assign.dtx Copyright (C) 2011-2012 The LaTeX3 project
+%% File: l3fp-assign.dtx Copyright (C) 2011-2013 The LaTeX3 project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -4479,11 +5145,11 @@
{ \cs_new_eq:NN #1 \c_zero_fp }
\cs_generate_variant:Nn \fp_new:N {c}
\cs_new_protected:Npn \fp_set:Nn #1#2
- { \tl_set:Nx #1 { \__fp_parse:n {#2} } }
+ { \tl_set:Nx #1 { \exp_not:f { \__fp_parse:n {#2} } } }
\cs_new_protected:Npn \fp_gset:Nn #1#2
- { \tl_gset:Nx #1 { \__fp_parse:n {#2} } }
+ { \tl_gset:Nx #1 { \exp_not:f { \__fp_parse:n {#2} } } }
\cs_new_protected:Npn \fp_const:Nn #1#2
- { \tl_const:Nx #1 { \__fp_parse:n {#2} } }
+ { \tl_const:Nx #1 { \exp_not:f { \__fp_parse:n {#2} } } }
\cs_generate_variant:Nn \fp_set:Nn {c}
\cs_generate_variant:Nn \fp_gset:Nn {c}
\cs_generate_variant:Nn \fp_const:Nn {c}
@@ -4525,7 +5191,7 @@
\cs_generate_variant:Nn \fp_show:N { c }
\fp_const:Nn \c_e_fp { 2.718 2818 2845 9045 }
\fp_const:Nn \c_one_fp { 1 }
-\fp_const:Nn \c_pi_fp { 3.141 5926 5358 9794 }
+\fp_const:Nn \c_pi_fp { 3.141 5926 5358 9793 }
\fp_const:Nn \c_one_degree_fp { 0.0 1745 3292 5199 4330 }
\fp_new:N \l_tmpa_fp
\fp_new:N \l_tmpb_fp
diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3pdfmode.def b/Master/texmf-dist/tex/latex/l3kernel/l3pdfmode.def
index 377d6c31d84..84511dd3405 100644
--- a/Master/texmf-dist/tex/latex/l3kernel/l3pdfmode.def
+++ b/Master/texmf-dist/tex/latex/l3kernel/l3pdfmode.def
@@ -13,7 +13,7 @@
%%
%% Do not distribute a modified version of this file.
%%
-%% File: l3drivers.dtx Copyright(C) 2011-2012 The LaTeX3 Project
+%% File: l3drivers.dtx Copyright(C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -47,7 +47,7 @@
%% -----------------------------------------------------------------------
%%
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3drivers.dtx 4505 2013-06-28 22:06:04Z joseph $
+\GetIdInfo$Id: l3drivers.dtx 4602 2013-11-18 23:19:01Z bruno $
{L3 Experimental drivers}
\ProvidesExplFile
{l3pdfmode.def}{\ExplFileDate}{\ExplFileVersion}
@@ -87,12 +87,9 @@
{
\__driver_graphic_state_save:
\box_set_wd:Nn \l__box_internal_box \c_zero_dim
- \fp_set:Nn \l__box_cos_fp
- {
- \fp_compare:nNnTF \l__box_cos_fp = \c_zero_fp
- { 0 }
- { round ( \l__box_cos_fp , 5 ) }
- }
+ \fp_set:Nn \l__box_cos_fp { round ( \l__box_cos_fp , 5 ) }
+ \fp_compare:nNnT \l__box_cos_fp = \c_zero_fp
+ { \fp_zero:N \l__box_cos_fp }
\fp_set:Nn \l__box_sin_fp { round ( \l__box_sin_fp , 5 ) }
\__driver_pdf_matrix:n
{
diff --git a/Master/texmf-dist/tex/latex/l3kernel/l3xdvipdfmx.def b/Master/texmf-dist/tex/latex/l3kernel/l3xdvipdfmx.def
index 0c0ba1fb2b4..b1d14e8264a 100644
--- a/Master/texmf-dist/tex/latex/l3kernel/l3xdvipdfmx.def
+++ b/Master/texmf-dist/tex/latex/l3kernel/l3xdvipdfmx.def
@@ -13,7 +13,7 @@
%%
%% Do not distribute a modified version of this file.
%%
-%% File: l3drivers.dtx Copyright(C) 2011-2012 The LaTeX3 Project
+%% File: l3drivers.dtx Copyright(C) 2011-2013 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -47,7 +47,7 @@
%% -----------------------------------------------------------------------
%%
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3drivers.dtx 4505 2013-06-28 22:06:04Z joseph $
+\GetIdInfo$Id: l3drivers.dtx 4602 2013-11-18 23:19:01Z bruno $
{L3 Experimental drivers}
\ProvidesExplFile
{l3xdvidpfmx.def}{\ExplFileDate}{\ExplFileVersion}
@@ -84,12 +84,9 @@
{
\__driver_graphic_state_save:
\box_set_wd:Nn \l__box_internal_box \c_zero_dim
- \fp_set:Nn \l__box_cos_fp
- {
- \fp_compare:nNnTF \l__box_cos_fp = \c_zero_fp
- { 0 }
- { round ( \l__box_cos_fp , 5 ) }
- }
+ \fp_set:Nn \l__box_cos_fp { round ( \l__box_cos_fp , 5 ) }
+ \fp_compare:nNnT \l__box_cos_fp = \c_zero_fp
+ { \fp_zero:N \l__box_cos_fp }
\fp_set:Nn \l__box_sin_fp { round ( \l__box_sin_fp , 5 ) }
\__driver_pdf_matrix:n
{
diff --git a/Master/texmf-dist/tex/latex/l3packages/l3keys2e/l3keys2e.sty b/Master/texmf-dist/tex/latex/l3packages/l3keys2e/l3keys2e.sty
index 03576dedc50..2835a4a7407 100644
--- a/Master/texmf-dist/tex/latex/l3packages/l3keys2e/l3keys2e.sty
+++ b/Master/texmf-dist/tex/latex/l3packages/l3keys2e/l3keys2e.sty
@@ -46,8 +46,8 @@
%%
%% -----------------------------------------------------------------------
%%
-\RequirePackage{expl3}[2013/10/13]
-\@ifpackagelater{expl3}{2013/10/13}
+\RequirePackage{expl3}[2013/11/19]
+\@ifpackagelater{expl3}{2013/11/19}
{}
{%
\PackageError{l3keys2e}{Support package l3kernel too old}
@@ -59,7 +59,7 @@
}%
\endinput
}
-\GetIdInfo$Id: l3keys2e.dtx 4597 2013-10-13 21:44:53Z joseph $
+\GetIdInfo$Id: l3keys2e.dtx 4608 2013-11-19 15:52:24Z joseph $
{LaTeX2e option processing using LaTeX3 keys}
\ProvidesExplPackage
{\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
diff --git a/Master/texmf-dist/tex/latex/l3packages/xparse/xparse.sty b/Master/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
index 00711c48e43..d686b7b96b4 100644
--- a/Master/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
+++ b/Master/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
@@ -50,8 +50,8 @@
%%
%% -----------------------------------------------------------------------
%%
-\RequirePackage{expl3}[2013/10/13]
-\@ifpackagelater{expl3}{2013/10/13}
+\RequirePackage{expl3}[2013/11/19]
+\@ifpackagelater{expl3}{2013/11/19}
{}
{%
\PackageError{xparse}{Support package l3kernel too old}
@@ -63,7 +63,7 @@
}%
\endinput
}
-\GetIdInfo$Id: xparse.dtx 4597 2013-10-13 21:44:53Z joseph $
+\GetIdInfo$Id: xparse.dtx 4609 2013-11-19 16:01:54Z joseph $
{L3 Experimental document command parser}
\ProvidesExplPackage
{\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
diff --git a/Master/texmf-dist/tex/latex/l3packages/xtemplate/xtemplate.sty b/Master/texmf-dist/tex/latex/l3packages/xtemplate/xtemplate.sty
index 84040cd8978..ad415a959f2 100644
--- a/Master/texmf-dist/tex/latex/l3packages/xtemplate/xtemplate.sty
+++ b/Master/texmf-dist/tex/latex/l3packages/xtemplate/xtemplate.sty
@@ -50,8 +50,8 @@
%%
%% -----------------------------------------------------------------------
%%
-\RequirePackage{expl3}[2013/10/13]
-\@ifpackagelater{expl3}{2013/10/13}
+\RequirePackage{expl3}[2013/11/19]
+\@ifpackagelater{expl3}{2013/11/19}
{}
{%
\PackageError{xtemplate}{Support package l3kernel too old}
@@ -63,7 +63,7 @@
}%
\endinput
}
-\GetIdInfo$Id: xtemplate.dtx 4597 2013-10-13 21:44:53Z joseph $
+\GetIdInfo$Id: xtemplate.dtx 4608 2013-11-19 15:52:24Z joseph $
{L3 Experimental prototype document functions}
\ProvidesExplPackage
{\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}