diff options
Diffstat (limited to 'Master/texmf-dist/source')
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/expl3.dtx | 6 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3basics.dtx | 4 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3box.dtx | 52 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3clist.dtx | 126 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3doc.dtx | 6 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3expan.dtx | 4 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3fp.dtx | 3916 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3prg.dtx | 147 |
8 files changed, 3006 insertions, 1255 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/expl3.dtx b/Master/texmf-dist/source/latex/expl3/expl3.dtx index 0251c705b42..9657e07811e 100644 --- a/Master/texmf-dist/source/latex/expl3/expl3.dtx +++ b/Master/texmf-dist/source/latex/expl3/expl3.dtx @@ -37,7 +37,7 @@ \RequirePackage{l3names} %</driver|package> %\fi -\GetIdInfo$Id: expl3.dtx 1987 2010-07-25 14:55:46Z joseph $ +\GetIdInfo$Id: expl3.dtx 2020 2010-09-14 10:37:46Z joseph $ {L3 Experimental code bundle wrapper}% %\iffalse %<*driver> @@ -907,7 +907,7 @@ l3prop, l3msg, l3io, - l3skip, + l3skip } % \end{macrocode} % All the rest: @@ -921,7 +921,7 @@ l3xref, l3file, l3fp, - l3luatex, + l3luatex } \RequirePackage{calc} % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/expl3/l3basics.dtx b/Master/texmf-dist/source/latex/expl3/l3basics.dtx index 99712ddc497..4bfc83ec33b 100644 --- a/Master/texmf-dist/source/latex/expl3/l3basics.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3basics.dtx @@ -35,7 +35,7 @@ \RequirePackage{l3names} %</driver|package> %\fi -\GetIdInfo$Id: l3basics.dtx 1942 2010-06-07 17:06:11Z will $ +\GetIdInfo$Id: l3basics.dtx 1992 2010-08-04 20:41:40Z joseph $ {L3 Experimental basic definitions} %\iffalse %<*driver> @@ -2521,7 +2521,7 @@ % string between the two arguments. % \begin{macrocode} \cs_set:Npn \cs_tmp:w #1#2{ - \cs_new_nopar:Npn #1 { \exp_args:Nc #2 } + \cs_new_protected_nopar:Npn #1 { \exp_args:Nc #2 } } \cs_tmp:w \cs_set_nopar:cpn \cs_set_nopar:Npn \cs_tmp:w \cs_set_nopar:cpx \cs_set_nopar:Npx diff --git a/Master/texmf-dist/source/latex/expl3/l3box.dtx b/Master/texmf-dist/source/latex/expl3/l3box.dtx index 6f3c0b21c1b..8da3021541b 100644 --- a/Master/texmf-dist/source/latex/expl3/l3box.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3box.dtx @@ -36,7 +36,7 @@ \RequirePackage{l3names} %</driver|package> %\fi -\GetIdInfo$Id: l3box.dtx 1919 2010-05-22 05:56:38Z will $ +\GetIdInfo$Id: l3box.dtx 2015 2010-09-03 17:45:09Z mittelba $ {L3 Experimental Box module} %\iffalse %<*driver> @@ -400,7 +400,18 @@ % "\vbox:n" \Arg{contents} % \end{syntax} % Places a "vbox" of natural size with baseline equal to the baseline -% of the last line in the box. +% of the last object in the box, i.e., if the last object is a line of text +% the box has the same depth as that line; otherwise the depth will be zero. +% \end{function} +% +% \begin{function}{% +% \vbox_top:n | +% } +% \begin{syntax} +% "\vbox_top:n" \Arg{contents} +% \end{syntax} +% Same as "\vbox:n" except that the reference point will be at the baseline +% of the first object in the box not the last. % \end{function} % % \begin{function}{% @@ -413,7 +424,24 @@ % "\vbox_set:Nn" <box> \Arg{contents} % \end{syntax} % Sets <box> to be a vertical mode box containing \m{contents}. It has -% its natural size. "\vbox_gset:Nn" does it globally. +% its natural size and the reference point will be at the baseline of the +% last object in the box. "\vbox_gset:Nn" does it globally. +% \end{function} +% +% +% \begin{function}{% +% \vbox_set_top:Nn | +% \vbox_set_top:cn | +% \vbox_gset_top:Nn | +% \vbox_gset_top:cn | +% } +% \begin{syntax} +% "\vbox_set_top:Nn" <box> \Arg{contents} +% \end{syntax} +% Sets <box> to be a vertical mode box containing \m{contents}. It has +% its natural size (usually a small height and a larger depth) +% and the reference point will be at the baseline of the +% first object in the box. "\vbox_gset_top:Nn" does it globally. % \end{function} % % @@ -736,10 +764,12 @@ % \subsection{Vertical boxes} % % -% \begin{macro}{\vbox:n} +% \begin{macro}{\vbox:n, +% \vbox_top:n} % Put a vertical box directly into the input stream. % \begin{macrocode} \cs_new_protected_nopar:Npn \vbox:n {\tex_vbox:D \scan_stop:} +\cs_new_protected_nopar:Npn \vbox_top:n {\tex_vtop:D \scan_stop:} % \end{macrocode} % \end{macro} % @@ -755,6 +785,20 @@ % \end{macro} % \end{macro} % +% +% \begin{macro}{\vbox_set_top:Nn,\vbox_set_top:cn} +% \begin{macro}{\vbox_gset_top:Nn,\vbox_gset_top:cn} +% Storing material in a vertical box with a natural height and reference +% point at the baseline of the first object in the box. +% \begin{macrocode} +\cs_new_protected:Npn \vbox_set_top:Nn #1#2 {\tex_setbox:D #1 \tex_vtop:D {#2}} +\cs_generate_variant:Nn \vbox_set_top:Nn {cn} +\cs_new_protected_nopar:Npn \vbox_gset_top:Nn {\pref_global:D \vbox_set_top:Nn} +\cs_generate_variant:Nn \vbox_gset_top:Nn {cn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \begin{macro}{\vbox_set_to_ht:Nnn,\vbox_set_to_ht:cnn} % \begin{macro}{\vbox_gset_to_ht:Nnn,\vbox_gset_to_ht:cnn,\vbox_gset_to_ht:ccn} % Storing material in a vertical box with a specified height. diff --git a/Master/texmf-dist/source/latex/expl3/l3clist.dtx b/Master/texmf-dist/source/latex/expl3/l3clist.dtx index 4ae2d84d587..c3167477819 100644 --- a/Master/texmf-dist/source/latex/expl3/l3clist.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3clist.dtx @@ -36,7 +36,7 @@ \RequirePackage{l3names} %</driver|package> %\fi -\GetIdInfo$Id: l3clist.dtx 1878 2010-03-29 07:15:02Z joseph $ +\GetIdInfo$Id: l3clist.dtx 1992 2010-08-04 20:41:40Z joseph $ {L3 Experimental comma separated lists} %\iffalse %<*driver> @@ -875,103 +875,35 @@ % % \subsection{Mapping} % -% \begin{macro}{\clist_map_function:NN} -% \begin{macro}{\clist_map_function:cN} -% \begin{macro}{\clist_map_function:nN} -% |\clist_map_function:NN| \meta{comma-list} \meta{cmd} applies \meta{cmd} to each -% element of \meta{comma-list}, from left to right. +%\begin{macro}{\clist_map_function:NN} +%\begin{macro}{\clist_map_function:Nc} +%\begin{macro}{\clist_map_function:cN} +%\begin{macro}{\clist_map_function:cc} +%\begin{macro}{\clist_map_function:nN} +%\begin{macro}{\clist_map_function:nc} +%\begin{macro}{\clist_map_inline:Nn} +%\begin{macro}{\clist_map_inline:cn} +%\begin{macro}{\clist_map_inline:nn} +%\begin{macro}{\clist_map_break:} +% Using the above creating the comma mappings is easy.. % \begin{macrocode} -\cs_new_nopar:Npn \clist_map_function:NN #1#2 { - \clist_if_empty:NF #1 { - \exp_after:wN \clist_map_function_aux:Nw - \exp_after:wN #2 #1 , \q_recursion_tail , \q_recursion_stop - } -} -\cs_generate_variant:Nn \clist_map_function:NN {cN} -% \end{macrocode} -% \begin{macrocode} -\cs_new:Npn \clist_map_function:nN #1#2 { - \tl_if_blank:nF {#1} { - \clist_map_function_aux:Nw #2 #1 , \q_recursion_tail , \q_recursion_stop - } -} -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}[aux]{\clist_map_function_aux:Nw} -% The general loop. Tests if we hit the first stop marker and exits if -% we did. If we didn't, place the function "#1" in front of the -% element "#2", which is surrounded by braces. -% \begin{macrocode} -\cs_new:Npn \clist_map_function_aux:Nw #1#2,{ - \quark_if_recursion_tail_stop:n{#2} - #1{#2} - \clist_map_function_aux:Nw #1 -} -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\clist_map_break:} -% The break statement is easy. Same as in other modules, gobble -% everything up to the special recursion stop marker. -% \begin{macrocode} -\cs_new_eq:NN \clist_map_break: \use_none_delimit_by_q_recursion_stop:w -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\clist_map_inline:Nn} -% \begin{macro}{\clist_map_inline:cn} -% \begin{macro}{\clist_map_inline:nn} -% The inline type is faster but not expandable. In order to make it -% nestable, we use a counter to keep track of the nesting level so -% that all of the functions called have distict names. A simpler -% approach would of course be to use grouping and thus the save -% stack but then you lose the ability to do things locally. -% -% A funny little thing occured in one document: The command setting -% up the first call of |\clist_map_inline:Nn| was used in a tabular -% cell and the inline code used |\\| so the loop broke as soon as -% this happened. Lesson to be learned from this: If you wish to have -% group like structure but not using the groupings of \TeX, then do -% every operation globally. -% \begin{macrocode} -\int_new:N \g_clist_inline_level_int -\cs_new_protected:Npn \clist_map_inline:Nn #1#2 { - \clist_if_empty:NF #1 { - \int_gincr:N \g_clist_inline_level_int - \cs_gset:cpn {clist_map_inline_ \int_use:N \g_clist_inline_level_int :n} - ##1{#2} -% \end{macrocode} -% It is a lot more efficient to carry over -% the special function rather than constructing the same csname over -% and over again, so we just do it once. We reuse -% |\clist_map_function_aux:Nw| for the actual loop. -% \begin{macrocode} - \exp_last_unbraced:NcV \clist_map_function_aux:Nw - {clist_map_inline_ \int_use:N \g_clist_inline_level_int :n} - #1 , \q_recursion_tail , \q_recursion_stop - \int_gdecr:N \g_clist_inline_level_int - } -} -\cs_generate_variant:Nn \clist_map_inline:Nn {c} -\cs_new_protected:Npn \clist_map_inline:nn #1#2 { - \tl_if_empty:nF {#1} { - \int_gincr:N \g_clist_inline_level_int - \cs_gset:cpn {clist_map_inline_ \int_use:N \g_clist_inline_level_int :n} - ##1{#2} - \exp_args:Nc \clist_map_function_aux:Nw - {clist_map_inline_ \int_use:N \g_clist_inline_level_int :n} - #1 , \q_recursion_tail , \q_recursion_stop - \int_gdecr:N \g_clist_inline_level_int - } -} -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% +\prg_new_map_functions:Nn , { clist } +\cs_generate_variant:Nn \clist_map_function:NN { Nc } +\cs_generate_variant:Nn \clist_map_function:NN { c } +\cs_generate_variant:Nn \clist_map_function:NN { cc } +\cs_generate_variant:Nn \clist_map_inline:Nn { c } +\cs_generate_variant:Nn \clist_map_inline:Nn { nc } +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} % % \begin{macro}{\clist_map_variable:nNn} % \begin{macro}{\clist_map_variable:NNn} diff --git a/Master/texmf-dist/source/latex/expl3/l3doc.dtx b/Master/texmf-dist/source/latex/expl3/l3doc.dtx index df4cdf0ab5f..87bc748fb72 100644 --- a/Master/texmf-dist/source/latex/expl3/l3doc.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3doc.dtx @@ -77,7 +77,7 @@ Do not distribute a modified version of this file. % \end{macrocode} % %<*driver|class> -\GetIdInfo$Id: l3doc.dtx 1987 2010-07-25 14:55:46Z joseph $ +\GetIdInfo$Id: l3doc.dtx 2004 2010-08-18 19:39:24Z joseph $ {L3 Experimental documentation class} %</driver|class> % @@ -468,7 +468,7 @@ Do not distribute a modified version of this file. % \begin{macrocode} \LoadClass{article} \RequirePackage{doc} -\RequirePackage{array,alphalph,color,fixltx2e,enumitem,textcomp,trace,underscore} +\RequirePackage{array,alphalph,booktabs,color,fixltx2e,enumitem,textcomp,trace,underscore} % \end{macrocode} % % \begin{macrocode} @@ -486,7 +486,7 @@ Do not distribute a modified version of this file. \let\doc@verbatim\verbatim \let\enddoc@verbatim\endverbatim \let\doc@@verbatim\@verbatim -\usepackage{verbatim} +\RequirePackage{verbatim} \AtBeginDocument{% \let\verbatim\doc@verbatim \let\endverbatim\enddoc@verbatim diff --git a/Master/texmf-dist/source/latex/expl3/l3expan.dtx b/Master/texmf-dist/source/latex/expl3/l3expan.dtx index e28b81baa32..270c9758238 100644 --- a/Master/texmf-dist/source/latex/expl3/l3expan.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3expan.dtx @@ -36,7 +36,7 @@ \RequirePackage{l3names} %</driver|package> %\fi -\GetIdInfo$Id: l3expan.dtx 1948 2010-06-10 18:53:09Z joseph $ +\GetIdInfo$Id: l3expan.dtx 1991 2010-08-04 19:49:35Z joseph $ {L3 Experimental Argument Expansion module} %\iffalse %<*driver> @@ -140,7 +140,7 @@ % same way. \cs{cs_generate_variant:Nn} can only be applied if the % \meta{parent control sequence} is already defined. If the % \meta{parent control sequence} is protected then the new sequence -% will also be protected. +% will also be protected. The variants are generated globally. %\end{function} % % \paragraph{Internal functions} \mbox{} diff --git a/Master/texmf-dist/source/latex/expl3/l3fp.dtx b/Master/texmf-dist/source/latex/expl3/l3fp.dtx index bb64842ee90..54013130760 100644 --- a/Master/texmf-dist/source/latex/expl3/l3fp.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3fp.dtx @@ -35,7 +35,7 @@ \RequirePackage{l3names} %</driver|package> %\fi -\GetIdInfo$Id: l3fp.dtx 1985 2010-07-18 09:05:56Z joseph $ +\GetIdInfo$Id: l3fp.dtx 2021 2010-09-14 15:59:54Z joseph $ {L3 Experimental floating-point operations} %\iffalse %<*driver> @@ -53,20 +53,29 @@ % \title{The \textsf{l3fp} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ -% Fixed-point arithmetic} +% Floating point arithmetic} % \author{\Team} % \date{\filedate} % \maketitle % %\begin{documentation} % -%\section{Fixed-point numbers} -% -% This module implements a fixed-point data type and arithmetic support. -% Fixed-point numbers are real numbers with a fixed range of decimal -% places available, in this case nine before and nine after the -% decimal point. As this is a low-level module, error-checking is -% minimal. +%\section{Floating point numbers} +% +% A floating point number is one which is stored as a mantissa and +% a separate exponent. This module implements arithmetic using radix +% \( 10 \) floating point numbers. This means that the mantissa should +% be a real number in the range \( 1 \le \string| x \string| < 10 \), +% with the +% exponent given as an integer between \( -99 \) and \( 99 \). In the +% input, the exponent part is represented starting with an \texttt{e}. +% As this is a low-level module, error-checking is minimal. Numbers +% which are too large for the floating point unit to handle will result +% in errors, either from \TeX\ or from \LaTeX. The \LaTeX\ code does not +% check that the input will not overflow, hence the possibility of a +% \TeX\ error. On the other hand, numbers which are too small will be +% dropped, which will mean that extra decimal digits will simply be +% lost. % % When parsing numbers, any missing parts will be interpreted as % zero. So for example @@ -77,38 +86,48 @@ %\end{verbatim} % will all be interpreted as zero values without raising an error. % -% Number which are too large for the fixed-point unit to handle will -% result in errors, either from \TeX\ or from \LaTeX. The \LaTeX\ code -% does not check that the input will not overflow, hence the -% possibility of a \TeX\ error. On the other hand, numbers which are too -% small will be dropped, which will mean that extra decimal digits will -% simply be lost. -% % Operations which give an undefined result (such as division by -% \( 0 \)) or those which result in \( \pm \infty \) will not lead -% to errors. Instead special marker values are returned, which -% can be tested for using \cs{fp_if_undefined:N(TF)} and -% \cs{fp_if_infinity:N(TF)}. In this way it is possible to work with -% asymptopic functions without first checking the input. If these +% \( 0 \)) will not lead to errors. Instead special marker values are +% returned, which can be tested for using fr example +% \cs{fp_if_undefined:N(TF)}. In this way it is possible to work with +% asymptotic functions without first checking the input. If these % special values are carried forward in calculations they will be % treated as \( 0 \). % -% Fixed-point numbers are stored in the \texttt{fp} fixed-point +% Floating point numbers are stored in the \texttt{fp} floating point % variable type. This has a standard range of functions for % variable management. % -%\subsection{Fixed-point variables} +%\subsection{Constants} +% +%\begin{variable}{ \c_infinity_fp } +% A marker value for an infinite result from a calculation, such as +% \( \tan ( \pi / 2 ) \). +%\end{variable} +% +%\begin{variable}{ \c_undefined_fp } +% A special marker floating point variable representing the result of +% an operation which does not give a defined result (such as division +% by \( 0 \)). +%\end{variable} +% +%\begin{variable}{ \c_zero_fp } +% A permanently zero floating point variable. +%\end{variable} +% +%\subsection{Floating-point variables} % %\begin{function}{ % \fp_new:N | % \fp_new:c | %} % \begin{syntax} -% \cs{fp_new:N} \meta{fixed-point} +% \cs{fp_new:N} \meta{floating point variable} % \end{syntax} -% Creates a new \meta{fixed-point} or raises an error if the -% name is already taken. The declaration global. The -% \meta{fixed-point} will initially be set to "+0.000000000". +% Creates a new \meta{floating point variable} or raises an error if +% the name is already taken. The declaration global. The +% \meta{floating point} will initially be set to "+0.000000000e0" +% (the zero floating point). %\end{function} % %\begin{function}{ @@ -118,10 +137,10 @@ % \fp_set_eq:cc | %} % \begin{syntax} -% \cs{fp_set_eq:NN} \meta{fp1} \meta{fp2} +% \cs{fp_set_eq:NN} \meta{fp var1} \meta{fp var2} % \end{syntax} -% Sets the value of \meta{fixed-point1} equal to that of -% \meta{fixed-point2}. This assignment is restricted to the +% Sets the value of \meta{floating point variable1} equal to that of +% \meta{floating point variable2}. This assignment is restricted to the % current \TeX\ group level. %\end{function} % @@ -132,10 +151,10 @@ % \fp_gset_eq:cc | %} % \begin{syntax} -% \cs{tl_gset_eq:NN} \meta{tl var1} \meta{tl var2} +% \cs{fp_gset_eq:NN} \meta{fp var1} \meta{fp var2} % \end{syntax} -% Sets the value of \meta{fixed-point1} equal to that of -% \meta{fixed-point2}. This assignment is global and so is +% Sets the value of \meta{floating point variable1} equal to that of +% \meta{floating point variable2}. This assignment is global and so is % not limited by the current \TeX\ group level. %\end{function} % @@ -144,10 +163,10 @@ % \fp_zero:c | %} % \begin{syntax} -% \cs{fp_zero:N} \meta{fixed-point} +% \cs{fp_zero:N} \meta{floating point variable} % \end{syntax} -% Sets the \meta{fixed-point} to "+0.000000000" within the current -% scope. +% Sets the \meta{floating point variable} to "+0.000000000e0" within +% the current scope. %\end{function} % %\begin{function}{ @@ -155,9 +174,9 @@ % \fp_gzero:c | %} % \begin{syntax} -% \cs{fp_gzero:N} \meta{fixed-point} +% \cs{fp_gzero:N} \meta{floating point variable} % \end{syntax} -% Sets the \meta{fixed-point} to "+0.000000000" globally. +% Sets the \meta{floating point variable} to "+0.000000000e0" globally. %\end{function} % %\begin{function}{ @@ -165,10 +184,10 @@ % \fp_set:cn | %} % \begin{syntax} -% \cs{fp_set:Nn} \meta{fixed-point} \Arg{value} +% \cs{fp_set:Nn} \meta{floating point variable} \Arg{value} % \end{syntax} -% Sets the \meta{fixed-point} variable to \meta{value} within -% the scope of the current \TeX\ group. +% Sets the \meta{floating point variable} variable to \meta{value} +% within the scope of the current \TeX\ group. %\end{function} % %\begin{function}{ @@ -176,9 +195,10 @@ % \fp_gset:cn | %} % \begin{syntax} -% \cs{fp_gset:Nn} \meta{fixed-point} \Arg{value} +% \cs{fp_gset:Nn} \meta{floating point variable} \Arg{value} % \end{syntax} -% Sets the \meta{fixed-point} variable to \meta{value} globally. +% Sets the \meta{floating point variable} variable to \meta{value} +% globally. %\end{function} % %\begin{function}{ @@ -186,13 +206,13 @@ % \fp_set_from_dim:cn | %} % \begin{syntax} -% \cs{fp_set_from_dim:Nn} \meta{fixed-point} \Arg{dimexpr} +% \cs{fp_set_from_dim:Nn} \meta{floating point variable} \Arg{dimexpr} % \end{syntax} -% Sets the \meta{fixed-point} variable to the distance represented +% Sets the \meta{floating point variable} to the distance represented % by the \meta{dimension expression} in the units points. This means % that distances given in other units are first converted to points -% before being assigned to the \meta{fixed-point}. The assignment -% is local. +% before being assigned to the \meta{floating point variable}. The +% assignment is local. %\end{function} % %\begin{function}{ @@ -200,13 +220,34 @@ % \fp_gset_from_dim:cn | %} % \begin{syntax} -% \cs{fp_gset_from_dim:Nn} \meta{fixed-point} \Arg{dimexpr} +% \cs{fp_gset_from_dim:Nn} \meta{floating point variable} \Arg{dimexpr} % \end{syntax} -% Sets the \meta{fixed-point} variable to the distance represented +% Sets the \meta{floating point variable} to the distance represented % by the \meta{dimension expression} in the units points. This means % that distances given in other units are first converted to points -% before being assigned to the \meta{fixed-point}. The assignment -% is global. +% before being assigned to the \meta{floating point variable}. The +% assignment is global. +%\end{function} +% +%\begin{function}{ +% \fp_use:N / (EXP) | +% \fp_use:c / (EXP) | +%} +% \begin{syntax} +% \cs{fp_use:N} \meta{floating point variable} +% \end{syntax} +% Inserts the value of the \meta{floating point variable} into the +% input stream. The value will be given as a real number without any +% exponent part, and will always include a decimal point. For example, +% \begin{verbatim} +% \fp_new:Nn \test +% \fp_set:Nn \test { 1.234 e 5 } +% \fp_use:N \test +% \end{verbatim} +% will insert `\texttt{12345.00000}' into the input stream. +% As illustrated, a floating point will always be inserted with ten +% significant digits given. Very large and very small values will +% include additional zeros for place value. %\end{function} % %\begin{function}{ @@ -214,265 +255,131 @@ % \fp_show:c | %} % \begin{syntax} -% \cs{fp_show:N} \meta{fixed-point} +% \cs{fp_show:N} \meta{floating point variable} % \end{syntax} -% Displays the content of the \meta{fixed-point} on the +% Displays the content of the \meta{floating point variable} on the % terminal. %\end{function} % -%\subsection{Unary operations} +%\subsection{Conversion to other formats} % -% The unary operations alter the value stored within an \texttt{fp} -% variable. +% It is useful to be able to convert floating point variables to +% other forms. These functions are expandable, so that the material +% can be used in a variety of contexts. The \cs{fp_use:N} function +% should also be consulted in this context, as it will insert the +% value of the floating point variable as a real number. % %\begin{function}{ -% \fp_abs:N | -% \fp_abs:c | +% \fp_to_int:N / (EXP) | +% \fp_to_int:c / (EXP) | %} % \begin{syntax} -% \cs{fp_abs:N} \meta{fixed-point} +% \cs{fp_to_int:N} \meta{floating point variable} % \end{syntax} -% Converts the \meta{fixed-point} to its absolute value, assigning -% the result within the current \TeX\ group. +% Inserts the integer value of the \meta{floating point variable} +% into the input stream. The decimal part of the number will not be +% included, but will be used to round the integer. %\end{function} % %\begin{function}{ -% \fp_gabs:N | -% \fp_gabs:c | +% \fp_to_tl:N / (EXP) | +% \fp_to_tl:c / (EXP) | %} % \begin{syntax} -% \cs{fp_gabs:N} \meta{fixed-point} +% \cs{fp_to_tl:N} \meta{floating point variable} % \end{syntax} -% Converts the \meta{fixed-point} to its absolute value, assigning -% the result globally. +% Inserts a representation of the \meta{floating point variable} into +% the input stream as a token list. The representation follows the +% conventions of a pocket calculator: +% \begin{center} +% \ttfamily +% \begin{tabular}{r@{.}lr@{.}l} +% \toprule +% \multicolumn{2}{l}{\rmfamily{Floating point value}} & +% \multicolumn{2}{l}{\rmfamily{Representation}} \\ +% \midrule +% 1 & 234000000000e0 & 1 & 234 \\ +% -1 & 234000000000e0 & -1 & 234 \\ +% 1 & 234000000000e3 & \multicolumn{2}{l}{1234} \\ +% 1 & 234000000000e13 & \multicolumn{2}{l}{1234e13} \\ +% 1 & 234000000000e-1 & 0 & 1234 \\ +% 1 & 234000000000e-2 & 0 & 01234 \\ +% 1 & 234000000000e-3 & 1 & 234e-3 \\ +% \bottomrule +% \end{tabular} +% \end{center} +% Notice that trailing zeros are removed in this process, and that +% numbers which do not require a decimal part do \emph{not} include +% a decimal marker. %\end{function} % +%\subsection{Rounding floating point values} +% +% The module can round floating point values to either decimal places +% or significant figures using the usual method in which exact halves +% are rounded up. +% %\begin{function}{ -% \fp_neg:N | -% \fp_neg:c | +% \fp_round_figures:Nn | +% \fp_round_figures:cn | %} % \begin{syntax} -% \cs{fp_neg:N} \meta{fixed-point} +% \cs{fp_round_figures:Nn} \meta{floating point variable} \Arg{target} % \end{syntax} -% Reverse the sign of the \meta{fixed-point}, assigning the result -% within the current \TeX\ group. +% Rounds the \meta{floating point variable} to the \meta{target} number +% of significant figures (an integer expression). The rounding is +% carried out locally. %\end{function} % %\begin{function}{ -% \fp_gneg:N | -% \fp_gneg:c | +% \fp_ground_figures:Nn | +% \fp_ground_figures:cn | %} % \begin{syntax} -% \cs{fp_gneg:N} \meta{fixed-point} +% \cs{fp_ground_figures:Nn} \meta{floating point variable} \Arg{target} % \end{syntax} -% Reverse the sign of the \meta{fixed-point}, assigning the result -% globally. +% Rounds the \meta{floating point variable} to the \meta{target} number +% of significant figures (an integer expression). The rounding is +% carried out globally. %\end{function} % -%\subsection{Transferring \texttt{fp} to \texttt{tl} data} -% -% The highly-structured internal format used for \texttt{fp} data -% will not generally be desirable for use in user output. As a result, -% the module provides a set of intermediate level functions to convert -% \texttt{fp} into \texttt{tl} material. This process is governed by -% a number of settings, which determine how the output is rounded and -% how trailing zeros are handled. -% %\begin{function}{ -% \fp_to_tl:NN | -% \fp_to_tl:Nc | -% \fp_to_tl:cN | -% \fp_to_tl:cc | +% \fp_round_places:Nn | +% \fp_round_places:cn | %} % \begin{syntax} -% \cs{fp_to_tl:NN} \meta{fixed-point} \meta{token list variable} +% \cs{fp_round_places:Nn} \meta{floating point variable} \Arg{target} % \end{syntax} -% Transfers the content of the \meta{fixed-point} into the -% \meta{token list variable}, formatting according to the currently -% prevailing formatting settings. The \meta{token list variable} is -% set within the current \TeX\ group. +% Rounds the \meta{floating point variable} to the \meta{target} number +% of decimal places (an integer expression). The rounding is +% carried out locally. %\end{function} % %\begin{function}{ -% \fp_gto_tl:NN | -% \fp_gto_tl:Nc | -% \fp_gto_tl:cN | -% \fp_gto_tl:cc | +% \fp_ground_places:Nn | +% \fp_ground_places:cn | %} % \begin{syntax} -% \cs{fp_gto_tl:NN} \meta{fixed-point} \meta{token list variable} +% \cs{fp_ground_places:Nn} \meta{floating point variable} \Arg{target} % \end{syntax} -% Transfers the content of the \meta{fixed-point} into the -% \meta{token list variable}, formatting according to the currently -% prevailing formatting settings. The \meta{token list variable} is -% set globally. +% Rounds the \meta{floating point variable} to the \meta{target} number +% of decimal places (an integer expression). The rounding is +% carried out globally. %\end{function} % -% The exact behaviour of the transfer process is governed by a small -% family of key--value settings. These are accessible using the -% \cs{keys_set:nn} function in the \texttt{fp} path: -%\begin{verbatim} -% \keys_set:nn { fp } { -% % Settings here -% } -%\end{verbatim} -% -%\DescribeOption{remove-trailing-zeros} -% The Boolean setting \texttt{remove-trailing-zeros} is used to govern -% whether trailing zeros in the decimal part of the \texttt{fp} are -% removed. -%\begin{verbatim} -% \fp_new:N \l_test_fp -% \tl_new:N \l_test_tl -% \fp_set:Nn \l_test_fp { 1.234 } -% \keys_set:nn { fp } { remove-trailing-zeros = false } -% \fp_to_tl \l_test_fp \l_test_tl % => '1.234000000' -% \keys_set:nn { fp } { remove-trailing-zeros = true } -% \fp_to_tl \l_test_fp \l_test_tl % => '1.234' -%\end{verbatim} -% Removing trailing zeros will always leave the result as a real number: -%\begin{verbatim} -% \fp_set:Nn \l_test_fp { 1.0 } -% \keys_set:nn { fp } { remove-trailing-zeros = true } -% \fp_to_tl \l_test_fp \l_test_tl % => '1.0' -%\end{verbatim} -% -%\DescribeOption{round-mode} -%\DescribeOption{precision} -% The two options \texttt{round-mode} and \texttt{precision} determine -% whether any rounding takes place for the decimal part of the output, -% and if so how many significant output digits are retained. The -% \texttt{precision} option indicates how many decimal digits should -% be retained in the output, and therefore takes numerical values -% only. The \texttt{round-mode} option takes one of the values -% \texttt{none}, \texttt{truncate}, \texttt{half-from-zero} and -% \texttt{half-even}. The \texttt{none} setting completely disables any -% rounding, and therefore does not interact at all with -% \texttt{precision}. The number of digits in the \texttt{tl} will -% therefore depend only on the values in the \texttt{fp}, and whether -% \texttt{remove-trailing-zeros} is active -%\begin{verbatim} -% \fp_set:Nn \l_test_fp { 1.234 } -% \keys_set:nn { fp } { -% round-mode = none , -% remove-trailing-zeros = false , -% } -% \fp_to_tl \l_test_fp \l_test_tl % => '1.234000000' -% \keys_set:nn { fp } { -% round-mode = none , -% remove-trailing-zeros = true , -% } -% \fp_to_tl \l_test_fp \l_test_tl % => '1.234' -%\end{verbatim} -% In all other cases (\texttt{truncate}, \texttt{half-from-zero} -% and \texttt{half-even}) modification of the \texttt{fp} value will -% always provide the number of decimal digits specified by -% \texttt{precision}. This includes trailing zeros if they fall within -% the \texttt{precision} requested. The \texttt{truncate} setting will -% cause the transfer to simply discard excess decimal digits. -%\begin{verbatim} -% \keys_set:nn { fp } { -% precision = 3 , -% remove-trailing-zeros = true , -% round-mode = truncate , -% } -% \fp_set:Nn \l_test_fp { 1.23556 } -% \fp_to_tl \l_test_fp \l_test_tl % => 1.235 -% \fp_set:Nn \l_test_fp { 1.2 } -% \fp_to_tl \l_test_fp \l_test_tl % => 1.200 -%\end{verbatim} -% The \texttt{half-from-zero} setting will round the number such that -% if the digit to be rounded is \( 5 \) then rounding will occur -% away from zero (increasing the absolute value). -%\begin{verbatim} -% \keys_set:nn { fp } { -% precision = 3 , -% remove-trailing-zeros = true , -% round-mode = half-from-zero , -% } -% \fp_set:Nn \l_test_fp { 1.23556 } -% \fp_to_tl \l_test_fp \l_test_tl % => 1.236 -% \fp_set:Nn \l_test_fp { 1.2358 } -% \fp_to_tl \l_test_fp \l_test_tl % => 1.236 -% \fp_set:Nn \l_test_fp { 1.23505 } -% \fp_to_tl \l_test_fp \l_test_tl % => 1.235 -% \fp_set:Nn \l_test_fp { -1.23556 } -% \fp_to_tl \l_test_fp \l_test_tl % => -1.236 -% \fp_set:Nn \l_test_fp { -1.23 } -% \fp_to_tl \l_test_fp \l_test_tl % => -1.230 -%\end{verbatim} -% The alternative \texttt{half-even} setting behaves indentically to -% \texttt{half-from-zero} apart from the case where the discarded number -% is exctly half. In this special case the result is rounded to the -% nearest even number in the final digit. This form of rounding is -% sometimes used as it is does not add any bias to the final result. -%\begin{verbatim} -% \keys_set:nn { fp } { -% precision = 3 , -% remove-trailing-zeros = true , -% round-mode = half-even , -% } -% \fp_set:Nn \l_test_fp { 1.23556 } -% \fp_to_tl \l_test_fp \l_test_tl % => 1.236 -% \fp_set:Nn \l_test_fp { 1.23550 } -% \fp_to_tl \l_test_fp \l_test_tl % => 1.236 -% \fp_set:Nn \l_test_fp { 1.23450 } -% \fp_to_tl \l_test_fp \l_test_tl % => 1.234 -% \fp_set:Nn \l_test_fp { 1.234500001 } -% \fp_to_tl \l_test_fp \l_test_tl % => 1.235 -%\end{verbatim} -% -%\subsection{Constants} -% -%\begin{variable}{ \c_zero_fp } -% A permanently zero fixed-point variable. -%\end{variable} -% -%\begin{variable}{ \c_undefined_fp } -% A special marker fixed-point variable representing the result of -% an operation which does not give a defined result (such as division -% by \( 0 \)). -%\end{variable} -% -%\begin{variable}{ \c_infinity_fp } -% A special marker fixed-point variable representing \( \infty \). -%\end{variable} -% -%\begin{variable}{ \c_minus_infinity_fp } -% A special marker fixed-point variable representing \( -\infty \). -%\end{variable} -% -%\subsection{Tests on fixed-point values} +%\subsection{Tests on floating-point values} % %\begin{function}{ -% \fp_if_infinite_p:N / (EXP) | -% \fp_if_infinite:N / (EXP) (TF) | +% \fp_if_infinity_p:N / (EXP) | +% \fp_if_infinity:N / (EXP) (TF) | %} % \begin{syntax} -% \cs{fp_if_infinite_p:N} \meta{fixed-point} -% \cs{fp_if_infinite:NTF} \meta{fixed-point} +% \cs{fp_if_infinity_p:N} \meta{fixed-point} +% \cs{fp_if_infinity:NTF} \meta{fixed-point} % ~~\Arg{true code} \Arg{false code} % \end{syntax} -% Tests if \meta{fixed-point} is infinite (\emph{i.e}.~equal to the -% either of the special marker variables \cs{c_infinity_fp} or -% \cs{c_minus_infinity_fp}). The branching versions then leave either -% \meta{true code} or \meta{false code} in the input stream, as -% appropriate to the truth of the test and the variant of the -% function chosen. The logical truth of the test is left in the input -% stream by the predicate version. -%\end{function} -% -%\begin{function}{ -% \fp_if_plus_infinity_p:N / (EXP) | -% \fp_if_plus_infinity:N / (EXP) (TF) | -%} -% \begin{syntax} -% \cs{fp_if_plus_infinity_p:N} \meta{fixed-point} -% \cs{fp_if_plus_infinity:NTF} \meta{fixed-point} -% ~~\Arg{true code} \Arg{false code} -% \end{syntax} -% Tests if \meta{fixed-point} is \( +\infty \) (\emph{i.e}.~equal to -% the special \cs{c_infinity_fp} variable). The branching versions then +% Tests if \meta{floating point} is infinite (\emph{i.e}.~equal to the +% special \cs{c_infinity_fp} variable). The branching versions then % leave either \meta{true code} or \meta{false code} in the input % stream, as appropriate to the truth of the test and the variant of % the function chosen. The logical truth of the test is left in the @@ -480,23 +387,6 @@ %\end{function} % %\begin{function}{ -% \fp_if_minus_infinity_p:N / (EXP) | -% \fp_if_minus_infinity:N / (EXP) (TF) | -%} -% \begin{syntax} -% \cs{fp_if_minus_infinity_p:N} \meta{fixed-point} -% \cs{fp_if_minus_infinity:NTF} \meta{fixed-point} -% ~~\Arg{true code} \Arg{false code} -% \end{syntax} -% Tests if \meta{fixed-point} is \( +\infty \) (\emph{i.e}.~equal to -% the special \cs{c_minus_infinity_fp} variable). The branching -% versions then leave either \meta{true code} or \meta{false code} in -% the input stream, as appropriate to the truth of the test and the -% variant of the function chosen. The logical truth of the test is left -% in the input stream by the predicate version. -%\end{function} -% -%\begin{function}{ % \fp_if_undefined_p:N / (EXP) | % \fp_if_undefined:N / (EXP) (TF) | %} @@ -505,7 +395,7 @@ % \cs{fp_if_undefined:NTF} \meta{fixed-point} % ~~\Arg{true code} \Arg{false code} % \end{syntax} -% Tests if \meta{fixed-point} is undefined (\emph{i.e}.~equal to the +% Tests if \meta{floating point} is undefined (\emph{i.e}.~equal to the % special \cs{c_undefined_fp} variable). The branching versions then % leave either \meta{true code} or \meta{false code} in the input % stream, as appropriate to the truth of the test and the variant of @@ -521,7 +411,7 @@ % \cs{fp_if_zero_p:N} \meta{fixed-point} % \cs{fp_if_zero:NTF} \meta{fixed-point} \Arg{true code} \Arg{false code} % \end{syntax} -% Tests if \meta{fixed-point} is equal to zero (\emph{i.e}.~equal to +% Tests if \meta{floating point} is equal to zero (\emph{i.e}.~equal to % the special \cs{c_zero_fp} variable). The branching versions then % leave either \meta{true code} or \meta{false code} in the input % stream, as appropriate to the truth of the test and the variant of @@ -539,12 +429,61 @@ % \cs{fp_compare:NNNTF} \Arg{fp1} \meta{relation} \Arg{fp2} % ~~\Arg{true code} \Arg{false code} % \end{syntax} -% Compares the two \meta{values} or \meta{fixed-points} based on the +% Compares the two \meta{values} or \meta{floating points} based on the % \meta{relation} (\texttt{=}, \verb"<" or \verb">"), and leaves % either the \meta{true code} or \meta{false code} in the input stream, % as appropriate to the truth of the test and the variant of the -% function chosen. The tests treat undefined fixed-points -% as zero, as the comparison is intended for real numbers only. +% function chosen. The tests treat undefined floating points as zero, +% as the comparison is intended for real numbers only. +%\end{function} +% +%\subsection{Unary operations} +% +% The unary operations alter the value stored within an \texttt{fp} +% variable. +% +%\begin{function}{ +% \fp_abs:N | +% \fp_abs:c | +%} +% \begin{syntax} +% \cs{fp_abs:N} \meta{floating point variable} +% \end{syntax} +% Converts the \meta{floating point variable} to its absolute value, +% assigning the result within the current \TeX\ group. +%\end{function} +% +%\begin{function}{ +% \fp_gabs:N | +% \fp_gabs:c | +%} +% \begin{syntax} +% \cs{fp_gabs:N} \meta{floating point variable} +% \end{syntax} +% Converts the \meta{floating point variable} to its absolute value, +% assigning the result globally. +%\end{function} +% +%\begin{function}{ +% \fp_neg:N | +% \fp_neg:c | +%} +% \begin{syntax} +% \cs{fp_neg:N} \meta{floating point variable} +% \end{syntax} +% Reverse the sign of the \meta{floating point variable}, assigning the +% result within the current \TeX\ group. +%\end{function} +% +%\begin{function}{ +% \fp_gneg:N | +% \fp_gneg:c | +%} +% \begin{syntax} +% \cs{fp_gneg:N} \meta{floating point variable} +% \end{syntax} +% Reverse the sign of the \meta{floating point variable}, assigning the +% result globally. %\end{function} % %\subsection{Arithmetic operations} @@ -563,9 +502,9 @@ % \fp_add:cn | %} % \begin{syntax} -% \cs{fp_add:Nn} \meta{fixed-point} \Arg{value} +% \cs{fp_add:Nn} \meta{floating point} \Arg{value} % \end{syntax} -% Adds the \meta{value} to the \meta{fixed-point}, making the +% Adds the \meta{value} to the \meta{floating point}, making the % assignment within the current \TeX\ group level. %\end{function} % @@ -574,9 +513,9 @@ % \fp_gadd:cn | %} % \begin{syntax} -% \cs{fp_gadd:Nn} \meta{fixed-point} \Arg{value} +% \cs{fp_gadd:Nn} \meta{floating point} \Arg{value} % \end{syntax} -% Adds the \meta{value} to the \meta{fixed-point}, making the +% Adds the \meta{value} to the \meta{floating point}, making the % assignment globally. %\end{function} % @@ -585,9 +524,9 @@ % \fp_sub:cn | %} % \begin{syntax} -% \cs{fp_sub:Nn} \meta{fixed-point} \Arg{value} +% \cs{fp_sub:Nn} \meta{floating point} \Arg{value} % \end{syntax} -% Subtracts the \meta{value} from the \meta{fixed-point}, making the +% Subtracts the \meta{value} from the \meta{floating point}, making the % assignment within the current \TeX\ group level. %\end{function} % @@ -596,9 +535,9 @@ % \fp_gsub:cn | %} % \begin{syntax} -% \cs{fp_gsub:Nn} \meta{fixed-point} \Arg{value} +% \cs{fp_gsub:Nn} \meta{floating point} \Arg{value} % \end{syntax} -% Subtracts the \meta{value} from the \meta{fixed-point}, making the +% Subtracts the \meta{value} from the \meta{floating point}, making the % assignment globally. %\end{function} % @@ -607,9 +546,9 @@ % \fp_mul:cn | %} % \begin{syntax} -% \cs{fp_mul:Nn} \meta{fixed-point} \Arg{value} +% \cs{fp_mul:Nn} \meta{floating point} \Arg{value} % \end{syntax} -% Multiples the \meta{fixed-point} by the \meta{value}, making the +% Multiples the \meta{floating point} by the \meta{value}, making the % assignment within the current \TeX\ group level. %\end{function} % @@ -618,9 +557,9 @@ % \fp_gmul:cn | %} % \begin{syntax} -% \cs{fp_gmul:Nn} \meta{fixed-point} \Arg{value} +% \cs{fp_gmul:Nn} \meta{floating point} \Arg{value} % \end{syntax} -% Multiples the \meta{fixed-point} by the \meta{value}, making the +% Multiples the \meta{floating point} by the \meta{value}, making the % assignment globally. %\end{function} % @@ -629,11 +568,12 @@ % \fp_div:cn | %} % \begin{syntax} -% \cs{fp_div:Nn} \meta{fixed-point} \Arg{value} +% \cs{fp_div:Nn} \meta{floating point} \Arg{value} % \end{syntax} -% Divides the \meta{fixed-point} by the \meta{value}, making the +% Divides the \meta{floating point} by the \meta{value}, making the % assignment within the current \TeX\ group level. If the \meta{value} -% is zero, the \meta{fixed-point} will be set to \cs{c_undefined_fp}. +% is zero, the \meta{floating point} will be set to +% \cs{c_undefined_fp}. %\end{function} % %\begin{function}{ @@ -641,20 +581,120 @@ % \fp_gdiv:cn | %} % \begin{syntax} -% \cs{fp_gdiv:Nn} \meta{fixed-point} \Arg{value} +% \cs{fp_gdiv:Nn} \meta{floating point} \Arg{value} % \end{syntax} -% Divides the \meta{fixed-point} by the \meta{value}, making the +% Divides the \meta{floating point} by the \meta{value}, making the % assignment globally. If the \meta{value} is zero, the -% \meta{fixed-point} will be set to \cs{c_undefined_fp}. +% \meta{floating point} will be set to \cs{c_undefined_fp}. +%\end{function} +% +%\subsection{Trigonometric functions} +% +% The trigonometric functions all work in radians. They accept a maximum +% input value of \( 1 000 000 000\), as there are issues with range +% reduction and very large input values. +% +%\begin{function}{ +% \fp_sin:Nn | +% \fp_sin:cn | +%} +% \begin{syntax} +% \cs{fp_sin:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Assigns the sine of the \meta{value} to the \meta{floating point}. +% The \meta{value} should be given in radians. The assignment is +% local. +%\end{function} +% +%\begin{function}{ +% \fp_gsin:Nn | +% \fp_gsin:cn | +%} +% \begin{syntax} +% \cs{fp_gsin:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Assigns the sine of the \meta{value} to the \meta{floating point}. +% The \meta{value} should be given in radians. The assignment is +% global. +%\end{function} +% +%\begin{function}{ +% \fp_cos:Nn | +% \fp_cos:cn | +%} +% \begin{syntax} +% \cs{fp_cos:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Assigns the cosine of the \meta{value} to the \meta{floating point}. +% The \meta{value} should be given in radians. The assignment is +% local. +%\end{function} +% +%\begin{function}{ +% \fp_gcos:Nn | +% \fp_gcos:cn | +%} +% \begin{syntax} +% \cs{fp_gcos:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Assigns the cosine of the \meta{value} to the \meta{floating point}. +% The \meta{value} should be given in radians. The assignment is +% global. +%\end{function} +% +%\begin{function}{ +% \fp_tan:Nn | +% \fp_tan:cn | +%} +% \begin{syntax} +% \cs{fp_tan:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Assigns the tangent of the \meta{value} to the \meta{floating point}. +% The \meta{value} should be given in radians. The assignment is +% local. +%\end{function} +% +%\begin{function}{ +% \fp_gtan:Nn | +% \fp_gtan:cn | +%} +% \begin{syntax} +% \cs{fp_gtan:Nn} \meta{floating point} \Arg{value} +% \end{syntax} +% Assigns the tangent of the \meta{value} to the \meta{floating point}. +% The \meta{value} should be given in radians. The assignment is +% global. %\end{function} % +%\subsection{Notes on the floating point unit} +% +% Anyone with experience of programming floating point calculations will +% know that this is a complex area. The aim of the unit is to be +% accurate enough for the likely applications in a typesetting context. +% The arithmetic operations are therefore intended to provide ten digit +% accuracy with the last digit accurate to \( \pm 1 \). The elemental +% transcendental functions may not provide such high accuracy in every +% case, although the design aim has been to provide \( 10 \) digit +% accuracy for cases likely to be relevant in typesetting situations. +% A good overview of the challenges in this area can be found in +% J.-M.~Muller, \emph{Elementary functions: algorithms and +% implementation}, 2nd edition, Birkh{\"a}uer Boston, New York, USA, +% 2006. +% +% The internal representation of numbers is tuned to the needs of the +% underlying \TeX\ system. This means that the format is somewhat +% different from that used in, for example, computer floating point +% units. Programming in \TeX\ makes it most convenient to use a +% radix \( 10 \) system, using \TeX\ \texttt{count} registers for +% storage and taking advantage where possible of delimited arguments. +% %\end{documentation} % %\begin{implementation} % %\section{Implementation} % -% Announce and ensure that the required packages are loaded. +% We start by ensuring that the required packages are loaded. % \begin{macrocode} %<*package> \ProvidesExplPackage @@ -664,50 +704,157 @@ %<*initex|package> % \end{macrocode} % -% Internally, a fixed-point number is a token list variable of the -% correct format. The first token in the variable is the sign: normally -% this will be "+" or "-", but this token can also be used to indicate -% a special state (for exampe if a calculation would give infinity as -% a result). The main part of the number is then stored as a decimal: -% there are always nine digits in the decimal part. This ensures that -% two numbers which are equal to one another will always be stored in -% the same way. For the same reason, zero is stored as "+0.000000000". -% -%\subsection{General variables} -% +%\subsection{Constants} +% +%\begin{macro}{\c_forty_four} +%\begin{macro}{\c_one_hundred} +%\begin{macro}{\c_one_thousand} +%\begin{macro}{\c_one_million} +%\begin{macro}{\c_one_hundred_million} +%\begin{macro}{\c_five_hundred_million} +%\begin{macro}{\c_one_thousand_million} +% There is some speed to gain by moving numbers into fixed positions. +% \begin{macrocode} +\int_new:N \c_forty_four +\int_set:Nn \c_forty_four { 44 } +\int_new:N \c_one_hundred +\int_set:Nn \c_one_hundred { 100 } +\int_new:N \c_one_thousand +\int_set:Nn \c_one_thousand { 1000 } +\int_new:N \c_one_million +\int_set:Nn \c_one_million { 1 000 000 } +\int_new:N \c_one_hundred_million +\int_set:Nn \c_one_hundred_million { 100 000 000 } +\int_new:N \c_five_hundred_million +\int_set:Nn \c_five_hundred_million { 500 000 000 } +\int_new:N \c_one_thousand_million +\int_set:Nn \c_one_thousand_million { 1 000 000 000 } +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\c_fp_pi_by_four_decimal_int} +%\begin{macro}{\c_fp_pi_by_four_extended_int} +%\begin{macro}{\c_fp_pi_decimal_int} +%\begin{macro}{\c_fp_pi_extended_int} +%\begin{macro}{\c_fp_two_pi_decimal_int} +%\begin{macro}{\c_fp_two_pi_extended_int} +% Parts of \( \pi \) for trigonometric range reduction. +% \begin{macrocode} +\int_new:N \c_fp_pi_by_four_decimal_int +\int_set:Nn \c_fp_pi_by_four_decimal_int { 785 398 158 } +\int_new:N \c_fp_pi_by_four_extended_int +\int_set:Nn \c_fp_pi_by_four_extended_int { 897 448 310 } +\int_new:N \c_fp_pi_decimal_int +\int_set:Nn \c_fp_pi_decimal_int { 141 592 653 } +\int_new:N \c_fp_pi_extended_int +\int_set:Nn \c_fp_pi_extended_int { 589 793 238 } +\int_new:N \c_fp_two_pi_decimal_int +\int_set:Nn \c_fp_two_pi_decimal_int { 283 185 307 } +\int_new:N \c_fp_two_pi_extended_int +\int_set:Nn \c_fp_two_pi_extended_int { 179 586 477 } +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\c_infinity_fp} +% Infinity is the biggest number that can be represented by \TeX's +% \texttt{count} data type. +% \begin{macrocode} +\tl_new:N \c_infinity_fp +\tl_set:Nn \c_infinity_fp { + 2147483647 . 2147483647 e 2147483647 } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\c_pi_fp} +% The value \( \pi \), as a `machine number'. +% \begin{macrocode} +\tl_new:N \c_pi_fp +\tl_set:Nn \c_pi_fp { + 3.141592654 e 0 } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\c_undefined_fp} +% A marker for undefined values. +% \begin{macrocode} +\tl_new:N \c_undefined_fp +\tl_set:Nn \c_undefined_fp { X 0.000000000 e 0 } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\c_zero_fp} +% The constant zero value. +% \begin{macrocode} +\tl_new:N \c_zero_fp +\tl_set:Nn \c_zero_fp { + 0.000000000 e 0 } +% \end{macrocode} +%\end{macro} +% +%\subsection{Variables} +% +%\begin{macro}{\l_fp_count_int} +% A counter for things like the number of divisions possible. +% \begin{macrocode} +\int_new:N \l_fp_count_int +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_fp_div_offset_int} +% When carrying out division, an offset is used for the results to +% get the decimal part correct. +% \begin{macrocode} +\int_new:N \l_fp_div_offset_int +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_fp_input_a_sign_int} %\begin{macro}{\l_fp_input_a_integer_int} %\begin{macro}{\l_fp_input_a_decimal_int} +%\begin{macro}{\l_fp_input_a_exponent_int} +%\begin{macro}{\l_fp_input_b_sign_int} %\begin{macro}{\l_fp_input_b_integer_int} %\begin{macro}{\l_fp_input_b_decimal_int} -% Storage for the input, divided into integer and decimal parts. +%\begin{macro}{\l_fp_input_b_exponent_int} +% Storage for the input: two storage areas as there are at most two +% inputs. % \begin{macrocode} +\int_new:N \l_fp_input_a_sign_int \int_new:N \l_fp_input_a_integer_int \int_new:N \l_fp_input_a_decimal_int +\int_new:N \l_fp_input_a_exponent_int +\int_new:N \l_fp_input_b_sign_int \int_new:N \l_fp_input_b_integer_int \int_new:N \l_fp_input_b_decimal_int +\int_new:N \l_fp_input_b_exponent_int % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} %\end{macro} -% -%\begin{macro}{\l_fp_input_a_sign_int} -%\begin{macro}{\l_fp_input_b_sign_int} -% The sign of each item in the input is stored as an \texttt{int} as -% this allows some faster manipulation than would otherwise be possible. -% \begin{macrocode} -\int_new:N \l_fp_input_a_sign_int -\int_new:N \l_fp_input_b_sign_int -% \end{macrocode} +%\end{macro} +%\end{macro} %\end{macro} %\end{macro} % -%\begin{macro}{\l_fp_split_sign_int} -% Used to speed up the sign-finding system. +%\begin{macro}{\l_fp_input_a_extended_int} +%\begin{macro}{\l_fp_input_b_extended_int} +% For internal use, `extended' floating point numbers are +% needed. % \begin{macrocode} -\int_new:N \l_fp_split_sign_int +\int_new:N \l_fp_input_a_extended_int +\int_new:N \l_fp_input_b_extended_int % \end{macrocode} %\end{macro} +%\end{macro} % %\begin{macro}{\l_fp_mul_a_i_int} %\begin{macro}{\l_fp_mul_a_ii_int} @@ -721,10 +868,8 @@ %\begin{macro}{\l_fp_mul_b_iv_int} %\begin{macro}{\l_fp_mul_b_v_int} %\begin{macro}{\l_fp_mul_b_vi_int} -% For multiplication, each number is split into six parts (three for the -% decimal, three for the integer). So that they are a bt easier to keep -% a track of these are simply numbered: i--iii are the integer and iv-vi -% the decimal part. +% Multiplication requires that the decimal part is split into parts +% so that there are no overflows. % \begin{macrocode} \int_new:N \l_fp_mul_a_i_int \int_new:N \l_fp_mul_a_ii_int @@ -762,49 +907,60 @@ %\end{macro} %\end{macro} % -%\begin{macro}{\l_fp_div_count_int} -%\begin{macro}{\l_fp_div_offset_int} -% Values used during division: an offset for small denominators and -% a count for the actual division. -% \begin{macrocode} -\int_new:N \l_fp_div_count_int -\int_new:N \l_fp_div_offset_int -% \end{macrocode} -%\end{macro} -%\end{macro} -% %\begin{macro}{\l_fp_output_sign_int} %\begin{macro}{\l_fp_output_integer_int} %\begin{macro}{\l_fp_output_decimal_int} +%\begin{macro}{\l_fp_output_exponent_int} % Output is stored in the same way as input. % \begin{macrocode} \int_new:N \l_fp_output_sign_int \int_new:N \l_fp_output_integer_int \int_new:N \l_fp_output_decimal_int +\int_new:N \l_fp_output_exponent_int % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} +%\end{macro} +% +%\begin{macro}{\l_fp_output_extended_int} +% Again, for calculations an extended part. +% \begin{macrocode} +\int_new:N \l_fp_output_extended_int +% \end{macrocode} +%\end{macro} % %\begin{macro}{\l_fp_round_carry_bool} -%\begin{macro}{\l_fp_round_decimal_tl} -%\begin{macro}{\l_fp_round_discard_int} -%\begin{macro}{\l_fp_round_position_int} -% The rounding system needs space to track carrying forward and also -% to hold onto dicarded material (which may be relevant when rounding -% to an even last digit). The current position in the decimal part also -% needs to be tracked. For speed reasons, the decimal part of the number -% is build back up in a token list when rounding, as this avoids -% worrying about place value. +% To indicate that a digit needs to be carried forward. % \begin{macrocode} \bool_new:N \l_fp_round_carry_bool +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_fp_round_decimal_tl} +% A temporary store when rounding, to build up the decimal part without +% needing to do any maths. +% \begin{macrocode} \tl_new:N \l_fp_round_decimal_tl -\int_new:N \l_fp_round_discard_int -\int_new:N \l_fp_round_position_int % \end{macrocode} %\end{macro} +% +%\begin{macro}{\l_fp_round_position_int} +%\begin{macro}{\l_fp_round_target_int} +% Used to check the position for rounding. +% \begin{macrocode} +\int_new:N \l_fp_round_position_int +\int_new:N \l_fp_round_target_int +% \end{macrocode} %\end{macro} %\end{macro} +% +%\begin{macro}{\l_fp_split_sign_int} +% When splitting the input it is fastest to use a fixed name for the +% sign part, and to transfer it after the split is complete. +% \begin{macrocode} +\int_new:N \l_fp_split_sign_int +% \end{macrocode} %\end{macro} % %\begin{macro}{\l_fp_tmp_int} @@ -814,90 +970,154 @@ \int_new:N \l_fp_tmp_int % \end{macrocode} %\end{macro} -% +% %\begin{macro}{\l_fp_tmp_tl} -% The usual scratch token list. +% A scratch token list variable for expanding material. % \begin{macrocode} \tl_new:N \l_fp_tmp_tl % \end{macrocode} %\end{macro} % -%\subsection{Constants} -% -%\begin{macro}{\c_zero_fp} -% The constanct zero value. +%\begin{macro}{\l_fp_trig_arg_tl} +% A token list to store the formalised representation of the input +% for trigonometry. % \begin{macrocode} -\tl_new:N \c_zero_fp -\tl_set:Nn \c_zero_fp { + 0.000000000 } +\tl_new:N \l_fp_trig_arg_tl % \end{macrocode} %\end{macro} % -%\begin{macro}{\c_undefined_fp} -%\begin{macro}{\c_infinity_fp} -%\begin{macro}{\c_minus_infinity_fp} -% Special marker values for various mathematically-valid results which -% are not fixed-point numbers. +%\begin{macro}{\l_fp_trig_octant_int} +% To track which octant the trigonometric input is in. % \begin{macrocode} -\tl_new:N \c_undefined_fp -\tl_set:Nn \c_undefined_fp { X 0.000000000 } -\tl_new:N \c_infinity_fp -\tl_set:Nn \c_infinity_fp { +2147483647.2147483647 } -\tl_new:N \c_minus_infinity_fp -\tl_set:Nn \c_minus_infinity_fp { -2147483647.2147483647 } +\int_new:N \l_fp_trig_octant_int % \end{macrocode} %\end{macro} -%\end{macro} -%\end{macro} % -%\begin{macro}{\c_one_hundred_million} -%\begin{macro}{\c_one_thousand_million} -% There is some speed to gain by moving numbers into fixed positions. +%\begin{macro}{\l_fp_trig_sign_int} +%\begin{macro}{\l_fp_trig_decimal_int} +%\begin{macro}{\l_fp_trig_extended_int} +% Used for the calculation of trigonometric values. % \begin{macrocode} -\int_new:N \c_one_hundred_million -\int_set:Nn \c_one_hundred_million { 100000000 } -\int_new:N \c_one_thousand_million -\int_set:Nn \c_one_thousand_million { 1000000000 } +\int_new:N \l_fp_trig_sign_int +\int_new:N \l_fp_trig_decimal_int +\int_new:N \l_fp_trig_extended_int % \end{macrocode} %\end{macro} %\end{macro} +%\end{macro} % -%\subsection{Tests for special values} +%\subsection{Parsing numbers} % -%\begin{macro}{\fp_if_infinite_p:N} -%\begin{macro}[TF]{\fp_if_infinite:N} -%\begin{macro}{\fp_if_plus_infinity_p:N} -%\begin{macro}[TF]{\fp_if_plus_infinity:N} -%\begin{macro}{\fp_if_minus_infinity_p:N} -%\begin{macro}[TF]{\fp_if_minus_infinity:N} -% Testing for infinite values is complicated by the sign of infinity. -% There are therefore three tests, one which will match \( +\infty \) -% or \( -\infty \) and one test each for the two individual cases. -% \begin{macrocode} -\prg_new_conditional:Npnn \fp_if_infinite:N #1 { p , T , F , TF } { - \tex_ifx:D #1 \c_infinity_fp - \prg_return_true: - \tex_else:D - \tex_ifx:D #1 \c_minus_infinity_fp - \prg_return_true: - \tex_else:D - \prg_return_false: - \tex_fi:D - \tex_fi:D +%\begin{macro}{\fp_read:N} +%\begin{macro}[aux]{\fp_read_aux:w} +% Reading a stored value is made easier as the format is designed to +% match the delimited function. This is always used to read the first +% value (register "a"). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_read:N #1 { + \exp_after:wN \fp_read_aux:w #1 \q_stop } -\prg_new_conditional:Npnn \fp_if_plus_infinity:N #1 { p , T , F , TF } { - \tex_ifx:D #1 \c_infinity_fp - \prg_return_true: +\cs_new_protected_nopar:Npn \fp_read_aux:w #1#2 . #3 e #4 \q_stop { + \tex_if:D #1 - + \l_fp_input_a_sign_int \c_minus_one \tex_else:D - \prg_return_false: + \l_fp_input_a_sign_int \c_one \tex_fi:D + \l_fp_input_a_integer_int #2 \scan_stop: + \l_fp_input_a_decimal_int #3 \scan_stop: + \l_fp_input_a_exponent_int #4 \scan_stop: } -\prg_new_conditional:Npnn \fp_if_minus_infinity:N #1 { p , T , F , TF } - { - \tex_ifx:D #1 \c_minus_infinity_fp - \prg_return_true: +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_split:Nn} +%\begin{macro}[aux]{\fp_split_sign:} +%\begin{macro}[aux]{\fp_split_exponent:} +%\begin{macro}[aux]{\fp_split_aux_i:w} +%\begin{macro}[aux]{\fp_split_aux_ii:w} +%\begin{macro}[aux]{\fp_split_aux_iii:w} +%\begin{macro}[aux]{\fp_split_decimal:w} +%\begin{macro}[aux]{\fp_split_decimal_aux:w} +% The aim here is to use as much of \TeX's mechanism as possible to pick +% up the numerical input without any mistakes. In particular, negative +% numbers have to be filtered out first in case the integer part is +% \( 0 \) (in which case \TeX\ would drop the "-" sign). That process +% has to be done in a loop for cases where the sign is repeated. +% Finding an exponent is relatively easy, after which the next phase is +% to find the integer part, which will terminate with a ".", and trigger +% the decimal-finding code. The later will allow the decimal to be too +% long, truncating the result. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_split:Nn #1#2 { + \tl_set:Nx \l_fp_tmp_tl {#2} + \l_fp_split_sign_int \c_one + \fp_split_sign: + \use:c { l_fp_input_ #1 _sign_int } \l_fp_split_sign_int + \exp_after:wN \fp_split_exponent:w \l_fp_tmp_tl e e \q_stop #1 +} +\cs_new_protected_nopar:Npn \fp_split_sign: { + \tex_ifnum:D \pdf_strcmp:D + { \exp_after:wN \tl_head:w \l_fp_tmp_tl ? \q_nil } { - } + = \c_zero + \tl_set:Nx \l_fp_tmp_tl + { + \exp_after:wN + \tl_tail:w \l_fp_tmp_tl \prg_do_nothing: \q_nil + } + \l_fp_split_sign_int -\l_fp_split_sign_int + \exp_after:wN \fp_split_sign: + \tex_else:D + \tex_ifnum:D \pdf_strcmp:D + { \exp_after:wN \tl_head:w \l_fp_tmp_tl ? \q_nil } { + } + = \c_zero + \tl_set:Nx \l_fp_tmp_tl + { + \exp_after:wN + \tl_tail:w \l_fp_tmp_tl \prg_do_nothing: \q_nil + } + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_split_sign: + \tex_fi:D + \tex_fi:D +} +\cs_new_protected_nopar:Npn + \fp_split_exponent:w #1 e #2 e #3 \q_stop #4 { + \use:c { l_fp_input_ #4 _exponent_int } + \etex_numexpr:D 0 #2 \scan_stop: + \tex_afterassignment:D \fp_split_aux_i:w + \use:c { l_fp_input_ #4 _integer_int } + \etex_numexpr:D 0 #1 . . \q_stop #4 +} +\cs_new_protected_nopar:Npn \fp_split_aux_i:w #1 . #2 . #3 \q_stop { + \fp_split_aux_ii:w #2 000000000 \q_stop +} +\cs_new_protected_nopar:Npn \fp_split_aux_ii:w #1#2#3#4#5#6#7#8#9 { + \fp_split_aux_iii:w {#1#2#3#4#5#6#7#8#9} +} +\cs_new_protected_nopar:Npn \fp_split_aux_iii:w #1#2 \q_stop { + \l_fp_tmp_int 1 #1 \scan_stop: + \exp_after:wN \fp_split_decimal:w + \int_use:N \l_fp_tmp_int 000000000 \q_stop +} +\cs_new_protected_nopar:Npn \fp_split_decimal:w #1#2#3#4#5#6#7#8#9 { + \fp_split_decimal_aux:w {#2#3#4#5#6#7#8#9} +} +\cs_new_protected_nopar:Npn \fp_split_decimal_aux:w #1#2#3 \q_stop #4 { + \use:c { l_fp_input_ #4 _decimal_int } #1#2 \scan_stop: + \tex_ifnum:D + \etex_numexpr:D + \use:c { l_fp_input_ #4 _integer_int } + + \use:c { l_fp_input_ #4 _decimal_int } + \scan_stop: + = \c_zero + \use:c { l_fp_input_ #4 _sign_int } \c_one + \tex_fi:D + \tex_ifnum:D + \use:c { l_fp_input_ #4 _integer_int } < \c_one_thousand_million \tex_else:D - \prg_return_false: - \tex_fi:D + \exp_after:wN \fp_overflow_msg: + \tex_fi:D } % \end{macrocode} %\end{macro} @@ -906,39 +1126,178 @@ %\end{macro} %\end{macro} %\end{macro} +%\end{macro} +%\end{macro} % -%\begin{macro}{\fp_if_undefined_p:N} -%\begin{macro}[TF]{\fp_if_undefined:N} -% Testing for an undefined value is easy. +%\begin{macro}{\fp_standardise:NNNN} +%\begin{macro}[aux]{\fp_standardise_aux:NNNN} +%\begin{macro}[aux]{\fp_standardise_aux:} +%\begin{macro}[aux]{\fp_standardise_aux:w} +% The idea here is to shift the input into a known exponent range. This +% is done using \TeX\ tokens where possible, as this is faster than +% arithmetic. % \begin{macrocode} -\prg_new_conditional:Npnn \fp_if_undefined:N #1 { p , T , F , TF } { - \tex_ifx:D #1 \c_undefined_fp - \prg_return_true: +\cs_new_protected_nopar:Npn \fp_standardise:NNNN #1#2#3#4 { + \tex_ifnum:D + \etex_numexpr:D #2 + #3 = \c_zero + #1 \c_one + #4 \c_zero + \exp_after:wN \use_none:nnnn \tex_else:D - \prg_return_false: + \exp_after:wN \fp_standardise_aux:NNNN \tex_fi:D + #1#2#3#4 } +\cs_new_protected_nopar:Npn \fp_standardise_aux:NNNN #1#2#3#4 { + \cs_set_protected_nopar:Npn \fp_standardise_aux: + { + \tex_ifnum:D #2 = \c_zero + \tex_advance:D #3 \c_one_thousand_million + \exp_after:wN \fp_standardise_aux:w + \int_use:N #3 \q_stop + \exp_after:wN \fp_standardise_aux: + \tex_fi:D + } + \cs_set_protected_nopar:Npn + \fp_standardise_aux:w ##1##2##3##4##5##6##7##8##9 \q_stop + { + #2 ##2 \scan_stop: + #3 ##3##4##5##6##7##8##9 0 \scan_stop: + \tex_advance:D #4 \c_minus_one + } + \fp_standardise_aux: + \cs_set_protected_nopar:Npn \fp_standardise_aux: + { + \tex_ifnum:D #2 > \c_nine + \tex_advance:D #2 \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_standardise_aux:w \int_use:N #2 + \exp_after:wN \fp_standardise_aux: + \tex_fi:D + } + \cs_set_protected_nopar:Npn + \fp_standardise_aux:w ##1##2##3##4##5##6##7##8##9 + { + #2 ##1##2##3##4##5##6##7##8 \scan_stop: + \tex_advance:D #3 \c_one_thousand_million + \tex_divide:D #3 \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + ##9 + \exp_after:wN \use_none:n \int_use:N #3 + } + #3 \l_fp_tmp_tl \scan_stop: + \tex_advance:D #4 \c_one + } + \fp_standardise_aux: + \tex_ifnum:D #4 < \c_one_hundred + \tex_ifnum:D #4 > -\c_one_hundred + \tex_else:D + #1 \c_one + #2 \c_zero + #3 \c_zero + #4 \c_zero + \tex_fi:D + \tex_else:D + \exp_after:wN \fp_overflow_msg: + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_standardise_aux: { } +\cs_new_protected_nopar:Npn \fp_standardise_aux:w { } % \end{macrocode} %\end{macro} %\end{macro} +%\end{macro} +%\end{macro} % -%\begin{macro}{\fp_if_zero_p:N} -%\begin{macro}[TF]{\fp_if_zero:N} -% Testing for a zero fixed-point is also easy. +%\subsection{Internal utilities} +% +%\begin{macro}{\fp_level_input_exponents:} +%\begin{macro}[aux]{\fp_level_input_exponents_a:} +%\begin{macro}[aux]{\fp_level_input_exponents_a:NNNNNNNNN} +%\begin{macro}[aux]{\fp_level_input_exponents_b:} +%\begin{macro}[aux]{\fp_level_input_exponents_b:NNNNNNNNN} +% The routines here are similar to those used to standardise the +% exponent. However, the aim here is different: the two exponents need +% to end up the same. % \begin{macrocode} -\prg_new_conditional:Npnn \fp_if_zero:N #1 { p , T , F , TF } { - \tex_ifx:D #1 \c_zero_fp - \prg_return_true: +\cs_new_protected_nopar:Npn \fp_level_input_exponents: { + \tex_ifnum:D \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int + \exp_after:wN \fp_level_input_exponents_a: \tex_else:D - \prg_return_false: + \exp_after:wN \fp_level_input_exponents_b: \tex_fi:D } +\cs_new_protected_nopar:Npn \fp_level_input_exponents_a: { + \tex_ifnum:D \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int + \tex_advance:D \l_fp_input_b_integer_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_level_input_exponents_a:NNNNNNNNN + \int_use:N \l_fp_input_b_integer_int + \exp_after:wN \fp_level_input_exponents_a: + \tex_fi:D +} +\cs_new_protected_nopar:Npn + \fp_level_input_exponents_a:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { + \l_fp_input_b_integer_int #1#2#3#4#5#6#7#8 \scan_stop: + \tex_advance:D \l_fp_input_b_decimal_int \c_one_thousand_million + \tex_divide:D \l_fp_input_b_decimal_int \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + #9 + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_b_decimal_int + } + \l_fp_input_b_decimal_int \l_fp_tmp_tl \scan_stop: + \tex_advance:D \l_fp_input_b_exponent_int \c_one +} +\cs_new_protected_nopar:Npn \fp_level_input_exponents_b: { + \tex_ifnum:D \l_fp_input_b_exponent_int > \l_fp_input_a_exponent_int + \tex_advance:D \l_fp_input_a_integer_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_level_input_exponents_b:NNNNNNNNN + \int_use:N \l_fp_input_a_integer_int + \exp_after:wN \fp_level_input_exponents_b: + \tex_fi:D +} +\cs_new_protected_nopar:Npn + \fp_level_input_exponents_b:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { + \l_fp_input_a_integer_int #1#2#3#4#5#6#7#8 \scan_stop: + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \tex_divide:D \l_fp_input_a_decimal_int \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + #9 + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + } + \l_fp_input_a_decimal_int \l_fp_tmp_tl \scan_stop: + \tex_advance:D \l_fp_input_a_exponent_int \c_one +} % \end{macrocode} %\end{macro} %\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_tmp:w} +% Used for output of results, cutting down on \cs{exp_after:wN}. +% This is just a place holder definition. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_tmp:w #1#2 { } +% \end{macrocode} +%\end{macro} % %\subsection{Operations for \texttt{fp} variables} % +% The format of \texttt{fp} variables is tightly defined, so that +% they can be read quickly by the internal code. The format is a single +% sign token, a single number, the decimal point, nine decimal numbers, +% an "e" and finally the exponent. This final part may vary in length. +% When stored, floating points will always be stored with a value in +% the integer position unless the number is zero. +% %\begin{macro}{\fp_new:N} %\begin{macro}{\fp_new:c} % Fixed-points always have a value, and of course this has to be @@ -992,21 +1351,31 @@ \cs_new_protected_nopar:Npn \fp_set_aux:NNn #1#2#3 { \group_begin: \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \tl_set:Nx \l_fp_tmp_tl + \cs_set_protected_nopar:Npx \fp_tmp:w { - \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero - - - \tex_else:D - + - \tex_fi:D - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_use:N \l_fp_input_a_decimal_int + \group_end: + #1 \exp_not:N #2 + { + \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero + - + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } } - \exp_after:wN \group_end: \exp_after:wN - #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } + \fp_tmp:w } \cs_generate_variant:Nn \fp_set:Nn { c } \cs_generate_variant:Nn \fp_gset:Nn { c } @@ -1024,11 +1393,13 @@ %\begin{macro}[aux]{\fp_set_from_dim_aux:NNn} %\begin{macro}[aux]{\fp_set_from_dim_aux:w} %\begin{macro}{\l_fp_tmp_dim} +%\begin{macro}{\l_fp_tmp_skip} % Here, dimensions are converted to fixed-points \emph{via} a % temporary variable. This ensures that they always convert as points. % The code is then essentially the same as for \cs{fp_set:Nn}, but with % the dimension passed so that it will be striped of the "pt" on the -% way through. +% way through. The passage through a skip is used to remove any rubber +% part. % \begin{macrocode} \cs_new_protected_nopar:Npn \fp_set_from_dim:Nn { \fp_set_from_dim_aux:NNn \tl_set:Nx @@ -1038,27 +1409,38 @@ } \cs_new_protected_nopar:Npn \fp_set_from_dim_aux:NNn #1#2#3 { \group_begin: - \l_fp_tmp_dim \etex_dimexpr:D #3 \scan_stop: + \l_fp_tmp_skip \etex_glueexpr:D #3 \scan_stop: + \l_fp_tmp_dim \l_fp_tmp_skip \fp_split:Nn a { \exp_after:wN \fp_set_from_dim_aux:w \dim_use:N \l_fp_tmp_dim } + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \tl_set:Nx \l_fp_tmp_tl + \cs_set_protected_nopar:Npx \fp_tmp:w { - \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero - - - \tex_else:D - + - \tex_fi:D - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_use:N \l_fp_input_a_decimal_int + \group_end: + #1 \exp_not:N #2 + { + \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero + - + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } } - \exp_after:wN \group_end: \exp_after:wN - #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } + \fp_tmp:w } \cs_set_protected_nopar:Npx \fp_set_from_dim_aux:w { \cs_set_nopar:Npn \exp_not:N \fp_set_from_dim_aux:w @@ -1068,6 +1450,7 @@ \cs_generate_variant:Nn \fp_set_from_dim:Nn { c } \cs_generate_variant:Nn \fp_gset_from_dim:Nn { c } \dim_new:N \l_fp_tmp_dim +\skip_new:N \l_fp_tmp_skip % \end{macrocode} %\end{macro} %\end{macro} @@ -1076,6 +1459,7 @@ %\end{macro} %\end{macro} %\end{macro} +%\end{macro} % %\begin{macro}{\fp_set_eq:NN} %\begin{macro}{\fp_set_eq:cN} @@ -1117,114 +1501,539 @@ % %\begin{macro}{\fp_use:N} %\begin{macro}{\fp_use:c} -% These are token lists, so this is easy. +%\begin{macro}[aux]{\fp_use_aux:w} +%\begin{macro}[aux]{\fp_use_none:w} +%\begin{macro}[aux]{\fp_use_small:w} +%\begin{macro}[aux]{\fp_use_large:w} +%\begin{macro}[aux]{\fp_use_large_aux_i:w} +%\begin{macro}[aux]{\fp_use_large_aux_1:w} +%\begin{macro}[aux]{\fp_use_large_aux_2:w} +%\begin{macro}[aux]{\fp_use_large_aux_3:w} +%\begin{macro}[aux]{\fp_use_large_aux_4:w} +%\begin{macro}[aux]{\fp_use_large_aux_5:w} +%\begin{macro}[aux]{\fp_use_large_aux_6:w} +%\begin{macro}[aux]{\fp_use_large_aux_7:w} +%\begin{macro}[aux]{\fp_use_large_aux_8:w} +%\begin{macro}[aux]{\fp_use_large_aux_i:w} +%\begin{macro}[aux]{\fp_use_large_aux_ii:w} +% The idea of the \cs{fp_use:N} function to convert the stored +% value into something suitable for \TeX\ to use as a number in an +% expandable manner. The first step is to deal with the sign, then +% work out how big the input is. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_use:N #1 { + \exp_after:wN \fp_use_aux:w #1 \q_stop +} +\cs_generate_variant:Nn \fp_use:N { c } +\cs_new_nopar:Npn \fp_use_aux:w #1#2 e #3 \q_stop { + \tex_if:D #1 - + - + \tex_fi:D + \tex_ifnum:D #3 > \c_zero + \exp_after:wN \fp_use_large:w + \tex_else:D + \tex_ifnum:D #3 < \c_zero + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_use_small:w + \tex_else:D + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_use_none:w + \tex_fi:D + \tex_fi:D + #2 e #3 \q_stop +} +% \end{macrocode} +% When the exponent is zero, the input is simply returned as output. % \begin{macrocode} -\cs_new_eq:NN \fp_use:N \tl_use:N -\cs_new_eq:NN \fp_use:c \tl_use:c +\cs_new_nopar:Npn \fp_use_none:w #1 e #2 \q_stop {#1} +% \end{macrocode} +% For small numbers (less than \( 1 \)) the correct number of zeros +% have to be inserted, but the decimal point is easy. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_use_small:w #1 . #2 e #3 \q_stop { + 0 . + \prg_replicate:nn { -#3 - 1 } { 0 } + #1#2 +} +% \end{macrocode} +% Life is more complex for large numbers. The decimal point needs to +% be shuffled, with potentially some zero-filling for very large values. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_use_large:w #1 . #2 e #3 \q_stop { + \tex_ifnum:D #3 < \c_ten + \exp_after:wN \fp_use_large_aux_i:w + \tex_else:D + \exp_after:wN \fp_use_large_aux_ii:w + \tex_fi:D + #1#2 e #3 \q_stop +} +\cs_new_nopar:Npn \fp_use_large_aux_i:w #1#2 e #3 \q_stop { + #1 + \use:c { fp_use_large_aux_ #3 :w } #2 \q_stop +} +\cs_new_nopar:cpn { fp_use_large_aux_1:w } #1#2 \q_stop { #1 . #2 } +\cs_new_nopar:cpn { fp_use_large_aux_2:w } #1#2#3 \q_stop { + #1#2 . #3 +} +\cs_new_nopar:cpn { fp_use_large_aux_3:w } #1#2#3#4 \q_stop { + #1#2#3 . #4 +} +\cs_new_nopar:cpn { fp_use_large_aux_4:w } #1#2#3#4#5 \q_stop { + #1#2#3#4 . #5 +} +\cs_new_nopar:cpn { fp_use_large_aux_5:w } #1#2#3#4#5#6 \q_stop { + #1#2#3#4#5 . #6 +} +\cs_new_nopar:cpn { fp_use_large_aux_6:w } #1#2#3#4#5#6#7 \q_stop { + #1#2#3#4#5#6 . #7 +} +\cs_new_nopar:cpn { fp_use_large_aux_7:w } #1#2#3#4#5#6#7#8 \q_stop { + #1#2#3#4#6#7 . #8 +} +\cs_new_nopar:cpn { fp_use_large_aux_8:w } #1#2#3#4#5#6#7#8#9 \q_stop { + #1#2#3#4#5#6#7#8 . #9 +} +\cs_new_nopar:cpn { fp_use_large_aux_9:w } #1 \q_stop { #1 . } +\cs_new_nopar:Npn \fp_use_large_aux_ii:w #1 e #2 \q_stop { + #1 + \prg_replicate:nn { #2 - 9 } { 0 } + . +} % \end{macrocode} %\end{macro} %\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} % -%\subsection{Internal utilities} +%\subsection{Transferring to other types} % -%\begin{macro}{\fp_read:N} -%\begin{macro}[aux]{\fp_read_aux:w} -% Reading a stored value is made easier as the format is designed to -% match the delimited function. This is always used to read the first -% value (register "a"). +% The \cs{fp_use:N} function converts a floating point variable to +% a form that can be used by \TeX. Here, the functions are slightly +% different, as some information may be discarded. +% +%\begin{macro}{\fp_to_int:N} +%\begin{macro}{\fp_to_int:c} +%\begin{macro}[aux]{\fp_to_int_aux:w} +%\begin{macro}[aux]{\fp_to_int_none:w} +%\begin{macro}[aux]{\fp_to_int_small:w} +%\begin{macro}[aux]{\fp_to_int_large:w} +%\begin{macro}[aux]{\fp_to_int_large_aux_i:w} +%\begin{macro}[aux]{\fp_to_int_large_aux_1:w} +%\begin{macro}[aux]{\fp_to_int_large_aux_2:w} +%\begin{macro}[aux]{\fp_to_int_large_aux_3:w} +%\begin{macro}[aux]{\fp_to_int_large_aux_4:w} +%\begin{macro}[aux]{\fp_to_int_large_aux_5:w} +%\begin{macro}[aux]{\fp_to_int_large_aux_6:w} +%\begin{macro}[aux]{\fp_to_int_large_aux_7:w} +%\begin{macro}[aux]{\fp_to_int_large_aux_8:w} +%\begin{macro}[aux]{\fp_to_int_large_aux_i:w} +%\begin{macro}[aux]{\fp_to_int_large_aux:nnn} +%\begin{macro}[aux]{\fp_to_int_large_aux_ii:w} +% Converting to integers in an expandable manner is very similar to +% simply using floating point variables, particularly in the lead-off. % \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_read:N #1 { - \exp_after:wN \fp_read_aux:w #1 \q_stop +\cs_new_nopar:Npn \fp_to_int:N #1 { + \exp_after:wN \fp_to_int_aux:w #1 \q_stop } -\cs_new_protected_nopar:Npn \fp_read_aux:w #1#2 . #3 \q_stop { +\cs_generate_variant:Nn \fp_to_int:N { c } +\cs_new_nopar:Npn \fp_to_int_aux:w #1#2 e #3 \q_stop { \tex_if:D #1 - - \l_fp_input_a_sign_int \c_minus_one + - + \tex_fi:D + \tex_ifnum:D #3 < \c_zero + \exp_after:wN \fp_to_int_small:w \tex_else:D - \l_fp_input_a_sign_int \c_one + \exp_after:wN \fp_to_int_large:w + \tex_fi:D + #2 e #3 \q_stop +} +% \end{macrocode} +% For small numbers, if the decimal part is greater than a half then +% there is rounding up to do. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_to_int_small:w #1 . #2 e #3 \q_stop { + \tex_ifnum:D #3 > \c_one + \tex_else:D + \tex_ifnum:D #1 < \c_five + 0 + \tex_else:D + 1 + \tex_fi:D + \tex_fi:D +} +% \end{macrocode} +% For large numbers, the idea is to split off the part for rounding, +% do the rounding and fill if needed. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_to_int_large:w #1 . #2 e #3 \q_stop { + \tex_ifnum:D #3 < \c_ten + \exp_after:wN \fp_to_int_large_aux_i:w + \tex_else:D + \exp_after:wN \fp_to_int_large_aux_ii:w \tex_fi:D - \l_fp_input_a_integer_int #2 \scan_stop: - \l_fp_input_a_decimal_int #3 \scan_stop: + #1#2 e #3 \q_stop +} +\cs_new_nopar:Npn \fp_to_int_large_aux_i:w #1#2 e #3 \q_stop { + \use:c { fp_to_int_large_aux_ #3 :w } #2 \q_stop {#1} +} +\cs_new_nopar:cpn { fp_to_int_large_aux_1:w } #1#2 \q_stop { + \fp_to_int_large_aux:nnn { #2 0 } {#1} +} +\cs_new_nopar:cpn { fp_to_int_large_aux_2:w } #1#2#3 \q_stop { + \fp_to_int_large_aux:nnn { #3 00 } {#1#2} +} +\cs_new_nopar:cpn { fp_to_int_large_aux_3:w } #1#2#3#4 \q_stop { + \fp_to_int_large_aux:nnn { #4 000 } {#1#2#3} +} +\cs_new_nopar:cpn { fp_to_int_large_aux_4:w } #1#2#3#4#5 \q_stop { + \fp_to_int_large_aux:nnn { #5 0000 } {#1#2#3#4} +} +\cs_new_nopar:cpn { fp_to_int_large_aux_5:w } #1#2#3#4#5#6 \q_stop { + \fp_to_int_large_aux:nnn { #6 00000 } {#1#2#3#4#5} +} +\cs_new_nopar:cpn { fp_to_int_large_aux_6:w } #1#2#3#4#5#6#7 \q_stop { + \fp_to_int_large_aux:nnn { #7 000000 } {#1#2#3#4#5#6} +} +\cs_new_nopar:cpn + { fp_to_int_large_aux_7:w } #1#2#3#4#5#6#7#8 \q_stop { + \fp_to_int_large_aux:nnn { #8 0000000 } {#1#2#3#4#5#6#7} +} +\cs_new_nopar:cpn + { fp_to_int_large_aux_8:w } #1#2#3#4#5#6#7#8#9 \q_stop { + \fp_to_int_large_aux:nnn { #9 00000000 } {#1#2#3#4#5#6#7#8} +} +\cs_new_nopar:cpn { fp_to_int_large_aux_9:w } #1 \q_stop {#1} +\cs_new_nopar:Npn \fp_to_int_large_aux:nnn #1#2#3 { + \tex_ifnum:D #1 < \c_five_hundred_million + #3#2 + \tex_else:D + \tex_number:D \etex_numexpr:D #3#2 + 1 \scan_stop: + \tex_fi:D +} +\cs_new_nopar:Npn \fp_to_int_large_aux_ii:w #1 e #2 \q_stop { + #1 + \prg_replicate:nn { #2 - 9 } { 0 } } % \end{macrocode} %\end{macro} %\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} % -%\begin{macro}{\fp_split:Nn} -%\begin{macro}[aux]{\fp_split_sign:} -%\begin{macro}[aux]{\fp_split_aux_i:w} -%\begin{macro}[aux]{\fp_split_aux_ii:w} -%\begin{macro}[aux]{\fp_split_aux_iii:w} -%\begin{macro}[aux]{\fp_split_decimal:w} -%\begin{macro}[aux]{\fp_split_decimal_aux:w} -% The aim here is to use as much of \TeX's mechanism as possible to pick -% up the numerical input without any mistakes. In particular, negative -% numbers have to be filtered out first in case the integer part is -% \( 0 \) (in which case \TeX\ would drop the "-" sign). That process -% has to be done in a loop for cases where the sign is repeated. The -% next phase is to find the integer part, which will terminate -% with a ".", and trigger the decimal-finding code. The later will -% allow the decimal to be too long, truncating the result. +%\begin{macro}{\fp_to_tl:N} +%\begin{macro}{\fp_to_tl:c} +%\begin{macro}[aux]{\fp_to_tl_aux:w} +%\begin{macro}[aux]{\fp_to_tl_large:w} +%\begin{macro}[aux]{\fp_to_tl_large_aux_i:w} +%\begin{macro}[aux]{\fp_to_tl_large_aux_ii:w} +%\begin{macro}[aux]{\fp_to_tl_large_0:w} +%\begin{macro}[aux]{\fp_to_tl_large_1:w} +%\begin{macro}[aux]{\fp_to_tl_large_2:w} +%\begin{macro}[aux]{\fp_to_tl_large_3:w} +%\begin{macro}[aux]{\fp_to_tl_large_4:w} +%\begin{macro}[aux]{\fp_to_tl_large_5:w} +%\begin{macro}[aux]{\fp_to_tl_large_6:w} +%\begin{macro}[aux]{\fp_to_tl_large_7:w} +%\begin{macro}[aux]{\fp_to_tl_large_8:w} +%\begin{macro}[aux]{\fp_to_tl_large_8_aux:w} +%\begin{macro}[aux]{\fp_to_tl_large_9:w} +%\begin{macro}[aux]{\fp_to_tl_small:w} +%\begin{macro}[aux]{\fp_to_tl_small_one:w} +%\begin{macro}[aux]{\fp_to_tl_small_two:w} +%\begin{macro}[aux]{\fp_to_tl_small_aux:w} +%\begin{macro}[aux]{\fp_to_tl_large_zeros:NNNNNNNNN} +%\begin{macro}[aux]{\fp_to_tl_small_zeros:NNNNNNNNN} +%\begin{macro}[aux]{\fp_use_iix_ix:NNNNNNNNN} +%\begin{macro}[aux]{\fp_use_ix:NNNNNNNNN} +%\begin{macro}[aux]{\fp_use_i_to_vii:NNNNNNNNN} +%\begin{macro}[aux]{\fp_use_i_to_iix:NNNNNNNNN} +% Converting to integers in an expandable manner is very similar to +% simply using floating point variables, particularly in the lead-off. % \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_split:Nn #1#2 { - \tl_set:Nx \l_fp_tmp_tl {#2} - \l_fp_split_sign_int \c_one - \fp_split_sign: - \use:c { l_fp_input_ #1 _sign_int } \l_fp_split_sign_int - \tex_afterassignment:D \fp_split_aux_i:w - \use:c { l_fp_input_ #1 _integer_int } - \etex_numexpr:D 0 \l_fp_tmp_tl . . \q_stop #1 +\cs_new_nopar:Npn \fp_to_tl:N #1 { + \exp_after:wN \fp_to_tl_aux:w #1 \q_stop } -\cs_new_protected_nopar:Npn \fp_split_sign: { - \tex_ifnum:D \pdf_strcmp:D - { \exp_after:wN \tl_head:w \l_fp_tmp_tl ? \q_nil } { - } - = \c_zero - \tl_set:Nx \l_fp_tmp_tl - { - \exp_after:wN - \tl_tail:w \l_fp_tmp_tl \prg_do_nothing: \q_nil - } - \l_fp_split_sign_int -\l_fp_split_sign_int - \exp_after:wN \fp_split_sign: - \tex_else:D - \tex_ifnum:D \pdf_strcmp:D - { \exp_after:wN \tl_head:w \l_fp_tmp_tl ? \q_nil } { + } - = \c_zero - \tl_set:Nx \l_fp_tmp_tl - { - \exp_after:wN - \tl_tail:w \l_fp_tmp_tl \prg_do_nothing: \q_nil - } +\cs_generate_variant:Nn \fp_to_tl:N { c } +\cs_new_nopar:Npn \fp_to_tl_aux:w #1#2 e #3 \q_stop { + \tex_if:D #1 - + - + \tex_fi:D + \tex_ifnum:D #3 < \c_zero + \exp_after:wN \fp_to_tl_small:w + \tex_else:D + \exp_after:wN \fp_to_tl_large:w + \tex_fi:D + #2 e #3 \q_stop +} +% \end{macrocode} +% For `large' numbers (exponent \( \ge 0 \)) there are two +% cases. For very large exponents (\( \ge 10 \)) life is easy: apart +% from dropping extra zeros there is no work to do. On the other hand, +% for intermediate exponent values the decimal needs to be moved, then +% zeros can be dropped. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_to_tl_large:w #1 e #2 \q_stop { + \tex_ifnum:D #2 < \c_ten + \exp_after:wN \fp_to_tl_large_aux_i:w + \tex_else:D + \exp_after:wN \fp_to_tl_large_aux_ii:w + \tex_fi:D + #1 e #2 \q_stop +} +\cs_new_nopar:Npn \fp_to_tl_large_aux_i:w #1 e #2 \q_stop { + \use:c { fp_to_tl_large_ #2 :w } #1 \q_stop +} +\cs_new_nopar:Npn \fp_to_tl_large_aux_ii:w #1 . #2 e #3 \q_stop { + #1 + \fp_to_tl_large_zeros:NNNNNNNNN #2 + e #3 +} +\cs_new_nopar:cpn { fp_to_tl_large_0:w } #1 . #2 \q_stop { + #1 + \fp_to_tl_large_zeros:NNNNNNNNN #2 +} +\cs_new_nopar:cpn { fp_to_tl_large_1:w } #1 . #2#3 \q_stop { + #1#2 + \fp_to_tl_large_zeros:NNNNNNNNN #3 0 +} +\cs_new_nopar:cpn { fp_to_tl_large_2:w } #1 . #2#3#4 \q_stop { + #1#2#3 + \fp_to_tl_large_zeros:NNNNNNNNN #4 00 +} +\cs_new_nopar:cpn { fp_to_tl_large_3:w } #1 . #2#3#4#5 \q_stop { + #1#2#3#4 + \fp_to_tl_large_zeros:NNNNNNNNN #5 000 +} +\cs_new_nopar:cpn { fp_to_tl_large_4:w } #1 . #2#3#4#5#6 \q_stop { + #1#2#3#4#5 + \fp_to_tl_large_zeros:NNNNNNNNN #6 0000 +} +\cs_new_nopar:cpn { fp_to_tl_large_5:w } #1 . #2#3#4#5#6#7 \q_stop { + #1#2#3#4#5#6 + \fp_to_tl_large_zeros:NNNNNNNNN #7 00000 +} +\cs_new_nopar:cpn { fp_to_tl_large_6:w } #1 . #2#3#4#5#6#7#8 \q_stop { + #1#2#3#4#5#6#7 + \fp_to_tl_large_zeros:NNNNNNNNN #8 000000 +} +\cs_new_nopar:cpn { fp_to_tl_large_7:w } #1 . #2#3#4#5#6#7#8#9 \q_stop { + #1#2#3#4#5#6#7#8 + \fp_to_tl_large_zeros:NNNNNNNNN #9 0000000 +} +\cs_new_nopar:cpn { fp_to_tl_large_8:w } #1 . { + #1 + \use:c { fp_to_tl_large_8_aux:w } +} +\cs_new_nopar:cpn + { fp_to_tl_large_8_aux:w } #1#2#3#4#5#6#7#8#9 \q_stop { + #1#2#3#4#5#6#7#8 + \fp_to_tl_large_zeros:NNNNNNNNN #9 00000000 +} +\cs_new_nopar:cpn { fp_to_tl_large_9:w } #1 . #2 \q_stop {#1#2} +% \end{macrocode} +% Dealing with small numbers is a bit more complex as there has to be +% rounding. This makes life rather awkward, as there need to be a series +% of tests and calculations, as things cannot be stored in an +% expandable system. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_to_tl_small:w #1 e #2 \q_stop { + \tex_ifnum:D #2 = \c_minus_one + \exp_after:wN \fp_to_tl_small_one:w + \tex_else:D + \tex_ifnum:D #2 = -\c_two \exp_after:wN \exp_after:wN \exp_after:wN - \fp_split_sign: - \tex_fi:D - \tex_fi:D + \fp_to_tl_small_two:w + \tex_else:D + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_to_tl_small_aux:w + \tex_fi:D + \tex_fi:D + #1 e #2 \q_stop } -\cs_new_protected_nopar:Npn \fp_split_aux_i:w #1 . #2 . #3 \q_stop { - \fp_split_aux_ii:w #2 000000000 \q_stop +\cs_new_nopar:Npn \fp_to_tl_small_one:w #1 . #2 e #3 \q_stop { + \tex_ifnum:D \fp_use_ix:NNNNNNNNN #2 > \c_four + \tex_ifnum:D + \etex_numexpr:D #1 \fp_use_i_to_iix:NNNNNNNNN #2 + 1 + < \c_one_thousand_million + 0. + \exp_after:wN \fp_to_tl_small_zeros:NNNNNNNNN + \tex_number:D + \etex_numexpr:D + #1 \fp_use_i_to_iix:NNNNNNNNN #2 + 1 + \scan_stop: + \tex_else:D + 1 + \tex_fi:D + \tex_else:D + 0. #1 + \fp_to_tl_small_zeros:NNNNNNNNN #2 + \tex_fi:D } -\cs_new_protected_nopar:Npn \fp_split_aux_ii:w #1#2#3#4#5#6#7#8#9 { - \fp_split_aux_iii:w {#1#2#3#4#5#6#7#8#9} +\cs_new_nopar:Npn \fp_to_tl_small_two:w #1 . #2 e #3 \q_stop { + \tex_ifnum:D \fp_use_iix_ix:NNNNNNNNN #2 > \c_forty_four + \tex_ifnum:D + \etex_numexpr:D #1 \fp_use_i_to_vii:NNNNNNNNN #2 0 + \c_ten + < \c_one_thousand_million + 0.0 + \exp_after:wN \fp_to_tl_small_zeros:NNNNNNNNN + \tex_number:D + \etex_numexpr:D + #1 \fp_use_i_to_vii:NNNNNNNNN #2 0 + \c_ten + \scan_stop: + \tex_else:D + 0.1 + \tex_fi:D + \tex_else:D + 0.0 + #1 + \fp_to_tl_small_zeros:NNNNNNNNN #2 + \tex_fi:D } -\cs_new_protected_nopar:Npn \fp_split_aux_iii:w #1#2 \q_stop { - \l_fp_tmp_int 1 #1 \scan_stop: - \exp_after:wN \fp_split_decimal:w - \int_use:N \l_fp_tmp_int 000000000 \q_stop +\cs_new_nopar:Npn \fp_to_tl_small_aux:w #1 . #2 e #3 \q_stop { + #1 + \fp_to_tl_large_zeros:NNNNNNNNN #2 + e #3 } -\cs_new_protected_nopar:Npn \fp_split_decimal:w #1#2#3#4#5#6#7#8#9 { - \fp_split_decimal_aux:w {#2#3#4#5#6#7#8#9} +% \end{macrocode} +% Rather than a complex recursion, the tests for finding trailing zeros +% are written out long-hand. The difference between the two is only the +% need for a decimal marker. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_to_tl_large_zeros:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { + \tex_ifnum:D #9 = \c_zero + \tex_ifnum:D #8 = \c_zero + \tex_ifnum:D #7 = \c_zero + \tex_ifnum:D #6 = \c_zero + \tex_ifnum:D #5 = \c_zero + \tex_ifnum:D #4 = \c_zero + \tex_ifnum:D #3 = \c_zero + \tex_ifnum:D #2 = \c_zero + \tex_ifnum:D #1 = \c_zero + \tex_else:D + . #1 + \tex_fi:D + \tex_else:D + . #1#2 + \tex_fi:D + \tex_else:D + . #1#2#3 + \tex_fi:D + \tex_else:D + . #1#2#3#4 + \tex_fi:D + \tex_else:D + . #1#2#3#4#5 + \tex_fi:D + \tex_else:D + . #1#2#3#4#5#6 + \tex_fi:D + \tex_else:D + . #1#2#3#4#5#6#7 + \tex_fi:D + \tex_else:D + . #1#2#3#4#5#6#7#8 + \tex_fi:D + \tex_else:D + . #1#2#3#4#5#6#7#8#9 + \tex_fi:D } -\cs_new_protected_nopar:Npn \fp_split_decimal_aux:w #1#2#3 \q_stop #4 { - \use:c { l_fp_input_ #4 _decimal_int } #1#2 \scan_stop: - \tex_ifnum:D - \etex_numexpr:D - \use:c { l_fp_input_ #4 _integer_int } + - \use:c { l_fp_input_ #4 _decimal_int } - \scan_stop: - = \c_zero - \use:c { l_fp_input_ #4 _sign_int } \c_one - \tex_fi:D +\cs_new_nopar:Npn \fp_to_tl_small_zeros:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { + \tex_ifnum:D #9 = \c_zero + \tex_ifnum:D #8 = \c_zero + \tex_ifnum:D #7 = \c_zero + \tex_ifnum:D #6 = \c_zero + \tex_ifnum:D #5 = \c_zero + \tex_ifnum:D #4 = \c_zero + \tex_ifnum:D #3 = \c_zero + \tex_ifnum:D #2 = \c_zero + \tex_ifnum:D #1 = \c_zero + \tex_else:D + #1 + \tex_fi:D + \tex_else:D + #1#2 + \tex_fi:D + \tex_else:D + #1#2#3 + \tex_fi:D + \tex_else:D + #1#2#3#4 + \tex_fi:D + \tex_else:D + #1#2#3#4#5 + \tex_fi:D + \tex_else:D + #1#2#3#4#5#6 + \tex_fi:D + \tex_else:D + #1#2#3#4#5#6#7 + \tex_fi:D + \tex_else:D + #1#2#3#4#5#6#7#8 + \tex_fi:D + \tex_else:D + #1#2#3#4#5#6#7#8#9 + \tex_fi:D } % \end{macrocode} +% Some quick `return a few' functions. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_use_iix_ix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 {#8#9} +\cs_new_nopar:Npn \fp_use_ix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 {#9} +\cs_new_nopar:Npn \fp_use_i_to_vii:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { + #1#2#3#4#5#6#7 +} +\cs_new_nopar:Npn \fp_use_i_to_iix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { + #1#2#3#4#5#6#7#8 +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} %\end{macro} %\end{macro} %\end{macro} @@ -1233,6 +2042,174 @@ %\end{macro} %\end{macro} % +%\subsection{Rounding numbers} +% +% The results may well need to be rounded. A couple of related functions +% to do this for a stored value. +% +%\begin{macro}{\fp_round_figures:Nn} +%\begin{macro}{\fp_round_figures:cn} +%\begin{macro}{\fp_ground_figures:Nn} +%\begin{macro}{\fp_ground_figures:cn} +%\begin{macro}[aux]{\fp_round_figures_aux:NNn} +% Rounding to figures needs only an adjustment to the target by one +% (as the target is in decimal places). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_round_figures:Nn { + \fp_round_figures_aux:NNn \tl_set:Nn +} +\cs_generate_variant:Nn \fp_round_figures:Nn { c } +\cs_new_protected_nopar:Npn \fp_ground_figures:Nn { + \fp_round_figures_aux:NNn \tl_gset:Nn +} +\cs_generate_variant:Nn \fp_ground_figures:Nn { c } +\cs_new_protected_nopar:Npn \fp_round_figures_aux:NNn #1#2#3 { + \group_begin: + \fp_read:N #2 + \int_set:Nn \l_fp_round_target_int { #3 - 1 } + \tex_ifnum:D \l_fp_round_target_int < \c_ten + \exp_after:wN \fp_round: + \tex_fi:D + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero + - + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + } + \fp_tmp:w +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_round_places:Nn} +%\begin{macro}{\fp_round_places:cn} +%\begin{macro}{\fp_ground_places:Nn} +%\begin{macro}{\fp_ground_places:cn} +%\begin{macro}[aux]{\fp_round_places_aux:NNn} +% Rounding to places needs an adjustment for the exponent value, which +% will mean that everything should be correct. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_round_places:Nn { + \fp_round_places_aux:NNn \tl_set:Nn +} +\cs_generate_variant:Nn \fp_round_places:Nn { c } +\cs_new_protected_nopar:Npn \fp_ground_places:Nn { + \fp_round_places_aux:NNn \tl_gset:Nn +} +\cs_generate_variant:Nn \fp_ground_places:Nn { c } +\cs_new_protected_nopar:Npn \fp_round_places_aux:NNn #1#2#3 { + \group_begin: + \fp_read:N #2 + \int_set:Nn \l_fp_round_target_int + { #3 + \l_fp_input_a_exponent_int } + \tex_ifnum:D \l_fp_round_target_int < \c_ten + \exp_after:wN \fp_round: + \tex_fi:D + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { + \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero + - + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } + } + \fp_tmp:w +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_round:} +%\begin{macro}{\fp_round_aux:NNNNNNNNN} +%\begin{macro}{\fp_round_loop:N} +% The rounding approach is the same for decimal places and significant +% figures. There are always nine decimal digits to round, so the code +% can be written to account for this. The basic logic is simply to +% find the rounding, track any carry digit and move along. At the end +% of the loop there is a possible shuffle if the integer part has +% become \( 10 \). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_round: { + \bool_set_false:N \l_fp_round_carry_bool + \l_fp_round_position_int \c_eight + \tl_clear:N \l_fp_round_decimal_tl + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_round_aux:NNNNNNNNN \int_use:N \l_fp_input_a_decimal_int +} +\cs_new_protected_nopar:Npn \fp_round_aux:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { + \fp_round_loop:N #9#8#7#6#5#4#3#2#1 + \bool_if:NT \l_fp_round_carry_bool + { \tex_advance:D \l_fp_input_a_integer_int \c_one } + \l_fp_input_a_decimal_int \l_fp_round_decimal_tl \scan_stop: + \tex_ifnum:D \l_fp_input_a_integer_int < \c_ten + \tex_else:D + \l_fp_input_a_integer_int \c_one + \tex_divide:D \l_fp_input_a_decimal_int \c_ten + \tex_advance:D \l_fp_input_a_exponent_int \c_one + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_round_loop:N #1 { + \tex_ifnum:D \l_fp_round_position_int < \l_fp_round_target_int + \bool_if:NTF \l_fp_round_carry_bool + { \l_fp_tmp_int \etex_numexpr:D #1 + \c_one \scan_stop: } + { \l_fp_tmp_int \etex_numexpr:D #1 \scan_stop: } + \tex_ifnum:D \l_fp_tmp_int = \c_ten + \l_fp_tmp_int \c_zero + \tex_else:D + \bool_set_false:N \l_fp_round_carry_bool + \tex_fi:D + \tl_set:Nx \l_fp_round_decimal_tl + { \int_use:N \l_fp_tmp_int \l_fp_round_decimal_tl } + \tex_else:D + \tl_set:Nx \l_fp_round_decimal_tl { 0 \l_fp_round_decimal_tl } + \tex_ifnum:D \l_fp_round_position_int = \l_fp_round_target_int + \tex_ifnum:D #1 > \c_four + \bool_set_true:N \l_fp_round_carry_bool + \tex_fi:D + \tex_fi:D + \tex_fi:D + \tex_advance:D \l_fp_round_position_int \c_minus_one + \tex_ifnum:D \l_fp_round_position_int > \c_minus_one + \exp_after:wN \fp_round_loop:N + \tex_fi:D +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% %\subsection{Unary functions} % %\begin{macro}{\fp_abs:N} @@ -1244,27 +2221,32 @@ % return the result. % \begin{macrocode} \cs_new_protected_nopar:Npn \fp_abs:N { - \fp_abs:NN \tl_set:Nn + \fp_abs_aux:NN \tl_set:Nn } \cs_new_protected_nopar:Npn \fp_gabs:N { - \fp_abs:NN \tl_gset:Nn + \fp_abs_aux:NN \tl_gset:Nn } \cs_generate_variant:Nn \fp_abs:N { c } \cs_generate_variant:Nn \fp_gabs:N { c } -\cs_new_protected_nopar:Npn \fp_abs:NN #1#2 { +\cs_new_protected_nopar:Npn \fp_abs_aux:NN #1#2 { \group_begin: \fp_read:N #2 \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \tl_set:Nx \l_fp_tmp_tl + \cs_set_protected_nopar:Npx \fp_tmp:w { - + - \int_use:N \l_fp_input_a_integer_int - . - \exp_after:wN \use_none:n - \int_use:N \l_fp_input_a_decimal_int + \group_end: + #1 \exp_not:N #2 + { + + + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int + } } - \exp_after:wN \group_end: \exp_after:wN - #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } + \fp_tmp:w } % \end{macrocode} %\end{macro} @@ -1304,6 +2286,8 @@ . \exp_after:wN \use_none:n \int_use:N \l_fp_input_a_decimal_int + e + \int_use:N \l_fp_input_a_exponent_int } \exp_after:wN \group_end: \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } @@ -1323,6 +2307,8 @@ %\begin{macro}{\fp_gadd:cn} %\begin{macro}[aux]{\fp_add_aux:NNn} %\begin{macro}[aux]{\fp_add_core:} +%\begin{macro}[aux]{\fp_add_sum:} +%\begin{macro}[aux]{\fp_add_difference:} % The various addition functions are simply different ways to call the % single master function below. This pattern is repeated for the % other arithmetic functions. @@ -1345,11 +2331,16 @@ \group_begin: \fp_read:N #2 \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int \fp_add_core: - \exp_after:wN \group_end: \exp_after:wN - #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } + \fp_tmp:w #1#2 } -\cs_new_protected_nopar:Npn \fp_add_core: { +\cs_new_protected_nopar:Npn \fp_add_core: { + \fp_level_input_exponents: \tex_ifnum:D \etex_numexpr:D \l_fp_input_a_sign_int * \l_fp_input_b_sign_int @@ -1358,18 +2349,31 @@ \exp_after:wN \fp_add_sum: \tex_else:D \exp_after:wN \fp_add_difference: - \tex_fi:D - \tl_set:Nx \l_fp_tmp_tl + \tex_fi:D + \l_fp_output_exponent_int \l_fp_input_a_exponent_int + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 { - \tex_ifnum:D \l_fp_output_sign_int < \c_zero - - - \tex_else:D - + - \tex_fi:D - \int_use:N \l_fp_output_integer_int - . - \exp_after:wN \use_none:n - \int_use:N \l_fp_output_decimal_int + \group_end: + ##1 ##2 + { + \tex_ifnum:D \l_fp_output_sign_int < \c_zero + - + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \tex_number:D \etex_numexpr:D + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } } } % \end{macrocode} @@ -1386,16 +2390,16 @@ \l_fp_input_a_decimal_int + \l_fp_input_b_decimal_int \scan_stop: \tex_ifnum:D \l_fp_output_decimal_int < \c_one_thousand_million - \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million \tex_else:D \tex_advance:D \l_fp_output_integer_int \c_one + \tex_advance:D \l_fp_output_decimal_int -\c_one_thousand_million \tex_fi:D } % \end{macrocode} % When the signs of the two parts of the input are different, the -% absolute difference is worked out first. There is then a caculation to -% see which way around everything has worked out, so that the final -% sign is correct. The differnce might also give a zero resul with +% absolute difference is worked out first. There is then a calculation +% to see which way around everything has worked out, so that the final +% sign is correct. The difference might also give a zero result with % a negative sign, which is reversed as zero is regarded as positive. % \begin{macrocode} \cs_new_protected_nopar:Npn \fp_add_difference: { @@ -1427,15 +2431,7 @@ \tex_fi:D \tex_else:D \l_fp_output_sign_int \l_fp_input_a_sign_int - \tex_fi:D - \tex_ifnum:D - \etex_numexpr:D - \l_fp_output_integer_int + \l_fp_output_decimal_int - \scan_stop: - = \c_zero - \l_fp_output_sign_int \c_one - \tex_fi:D - \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million + \tex_fi:D } % \end{macrocode} %\end{macro} @@ -1444,6 +2440,8 @@ %\end{macro} %\end{macro} %\end{macro} +%\end{macro} +%\end{macro} % %\begin{macro}{\fp_sub:Nn} %\begin{macro}{\fp_sub:cn} @@ -1466,27 +2464,32 @@ \group_begin: \fp_read:N #2 \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int \tex_multiply:D \l_fp_input_b_sign_int \c_minus_one \fp_add_core: - \exp_after:wN \group_end: \exp_after:wN - #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } + \fp_tmp:w #1#2 } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} %\end{macro} -%\end{macro} +%\end{macro} % %\begin{macro}{\fp_mul:Nn} %\begin{macro}{\fp_mul:cn} %\begin{macro}{\fp_gmul:Nn} %\begin{macro}{\fp_gmul:cn} %\begin{macro}[aux]{\fp_mul_aux:NNn} +%\begin{macro}[aux]{\fp_mul_int:} %\begin{macro}[aux]{\fp_mul_split:NNNN} %\begin{macro}[aux]{\fp_mul_split:w} %\begin{macro}[aux]{\fp_mul_end_level:} -%\begin{macro}[aux]{\fp_mul_end_level:w} +%\begin{macro}[aux]{\fp_mul_end_level:NNNNNNNNN} % The pattern is much the same for multiplication. % \begin{macrocode} \cs_new_protected_nopar:Npn \fp_mul:Nn { @@ -1509,93 +2512,83 @@ \group_begin: \fp_read:N #2 \fp_split:Nn b {#3} - \fp_mul_split:NNNN \l_fp_input_a_integer_int - \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int - \fp_mul_split:NNNN \l_fp_input_a_decimal_int - \l_fp_mul_a_iv_int \l_fp_mul_a_v_int \l_fp_mul_a_vi_int - \fp_mul_split:NNNN \l_fp_input_b_integer_int - \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int - \fp_mul_split:NNNN \l_fp_input_b_decimal_int - \l_fp_mul_b_iv_int \l_fp_mul_b_v_int \l_fp_mul_b_vi_int - \l_fp_mul_output_int \c_zero - \tl_clear:N \l_fp_mul_output_tl - \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_vi_int - \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_v_int - \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_iv_int - \tex_divide:D \l_fp_mul_output_int \c_thousand - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_vi_int - \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_v_int - \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_iv_int - \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_iii_int - \fp_mul_end_level: - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_vi_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_v_int - \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_iv_int - \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_ii_int - \fp_mul_end_level: - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_vi_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_v_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iv_int - \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_i_int - \fp_mul_end_level: - \l_fp_output_decimal_int 0 \l_fp_mul_output_tl \scan_stop: - \tl_clear:N \l_fp_mul_output_tl - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_v_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iv_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_i_int - \fp_mul_end_level: - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iv_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_i_int - \fp_mul_end_level: - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iii_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_i_int - \fp_mul_end_level: - \l_fp_output_integer_int 0 \l_fp_mul_output_tl \scan_stop: - \tl_clear:N \l_fp_mul_output_tl - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_ii_int - \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_i_int - \fp_mul_end_level: - \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_i_int - \fp_mul_end_level: - \tex_ifnum:D \l_fp_mul_output_tl = \c_zero - \tex_else:D - \exp_after:wN \fp_msg_overflow: - \tex_fi:D - \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million - \tl_set:Nx \l_fp_tmp_tl + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \fp_mul_int: + \l_fp_output_exponent_int + \etex_numexpr:D + \l_fp_input_a_exponent_int + \l_fp_input_b_exponent_int + \scan_stop: + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \cs_set_protected_nopar:Npx \fp_tmp:w { - \tex_ifnum:D - \etex_numexpr:D - \l_fp_input_a_sign_int * \l_fp_input_b_sign_int - \scan_stop: - < \c_zero - \tex_ifnum:D - \etex_numexpr:D - \l_fp_output_integer_int + \l_fp_output_decimal_int - \scan_stop: - = \c_one_thousand_million - + - \tex_else:D - - - \tex_fi:D - \tex_else:D - + - \tex_fi:D - \int_use:N \l_fp_output_integer_int - . - \exp_after:wN \use_none:n - \int_use:N \l_fp_output_decimal_int + \group_end: + #1 \exp_not:N #2 + { + \tex_ifnum:D + \etex_numexpr:D + \l_fp_input_a_sign_int * \l_fp_input_b_sign_int + < \c_zero + \tex_ifnum:D + \etex_numexpr:D + \l_fp_output_integer_int + \l_fp_output_decimal_int + = \c_zero + + + \tex_else:D + - + \tex_fi:D + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \tex_number:D \etex_numexpr:D + \l_fp_output_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_output_exponent_int + } } - \exp_after:wN \group_end: \exp_after:wN - #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } + \fp_tmp:w +} +% \end{macrocode} +% Done separately so that the internal use is a bit easier. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_mul_int: { + \fp_mul_split:NNNN \l_fp_input_a_decimal_int + \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int + \fp_mul_split:NNNN \l_fp_input_b_decimal_int + \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int + \l_fp_mul_output_int \c_zero + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_i_int + \tex_divide:D \l_fp_mul_output_int \c_one_thousand + \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_input_b_integer_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_input_b_integer_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_mul_b_i_int + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_input_b_integer_int + \fp_mul_end_level: + \l_fp_output_decimal_int 0 \l_fp_mul_output_tl \scan_stop: + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_input_a_integer_int \l_fp_input_b_integer_int + \fp_mul_end_level: + \l_fp_output_integer_int 0 \l_fp_mul_output_tl \scan_stop: } % \end{macrocode} % The split works by making a \( 10 \) digit number, from which @@ -1613,6 +2606,7 @@ #4 ##8##9 \scan_stop: } \exp_after:wN \fp_mul_split_aux:w \int_use:N #1 \q_stop + \tex_advance:D #1 -\c_one_thousand_million } \cs_new_protected_nopar:Npn \fp_mul_product:NN #1#2 { \l_fp_mul_output_int @@ -1625,18 +2619,19 @@ % \begin{macrocode} \cs_new_protected_nopar:Npn \fp_mul_end_level: { \tex_advance:D \l_fp_mul_output_int \c_one_thousand_million - \exp_after:wN \fp_mul_end_level:w - \int_use:N \l_fp_mul_output_int \q_stop + \exp_after:wN \use_i:nn \exp_after:wN + \fp_mul_end_level:NNNNNNNNN \int_use:N \l_fp_mul_output_int } -\cs_new_protected_nopar:Npn \fp_mul_end_level:w - #1#2#3#4#5#6#7#8#9 \q_stop { - \tl_set:Nx \l_fp_mul_output_tl { #8#9 \l_fp_mul_output_tl } - \l_fp_mul_output_int #5#6#7 \scan_stop: +\cs_new_protected_nopar:Npn \fp_mul_end_level:NNNNNNNNN + #1#2#3#4#5#6#7#8#9 { + \tl_set:Nx \l_fp_mul_output_tl { #7#8#9 \l_fp_mul_output_tl } + \l_fp_mul_output_int #1#2#3#4#5#6 \scan_stop: } % \end{macrocode} %\end{macro} %\end{macro} -%\end{macro} +%\end{macro} +%\end{macro} %\end{macro} %\end{macro} %\end{macro} @@ -1650,11 +2645,7 @@ %\begin{macro}{\fp_gdiv:cn} %\begin{macro}[aux]{\fp_div_aux:NNn} %\begin{macro}[aux]{\fp_div_aux:} -%\begin{macro}[aux]{\fp_div_offset_create:} -%\begin{macro}[aux]{\fp_div_offset_create_aux:w} %\begin{macro}[aux]{\fp_div_loop:} -%\begin{macro}[aux]{\fp_div_loop_aux_i:w} -%\begin{macro}[aux]{\fp_div_loop_aux_ii:w} %\begin{macro}[aux]{\fp_div_divide:} %\begin{macro}[aux]{\fp_div_divide_aux:} %\begin{macro}[aux]{\fp_div_store:} @@ -1681,120 +2672,113 @@ \group_begin: \fp_read:N #2 \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int \tex_ifnum:D \etex_numexpr:D \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int - \scan_stop: = \c_zero - \tl_set_eq:NN \l_fp_tmp_tl \c_undefined_fp + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + #1 \exp_not:N #2 { \c_undefined_fp } + } \tex_else:D \tex_ifnum:D \etex_numexpr:D \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int - \scan_stop: = \c_zero - \tl_set_eq:NN \l_fp_tmp_tl \c_zero_fp + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 + { + \group_end: + #1 \exp_not:N #2 { \c_zero_fp } + } \tex_else:D \exp_after:wN \exp_after:wN \exp_after:wN \fp_div_aux: \tex_fi:D \tex_fi:D - \exp_after:wN \group_end: \exp_after:wN - #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } -} -% \end{macrocode} -% The main division algorithm has to avoid overflows for awkward -% cases (division of large numbers by small ones). That requires that -% the denominator has an integer part if the numerator does: an offset -% is only created if it is needed. The idea then is find how many -% times the denominator can be removed from the numerator. This -% is stored in the result, the denominator is divided by ten and -% the process is repeated with the remainder of the numerator. Cycling -% through this sequence eventually removes all of the digits of the -% denominator, if the numerator does not reach zero first. + \fp_tmp:w #1#2 +} +% \end{macrocode} +% The main division algorithm works by finding how many times "b" can +% be removed from "a", storing the result and doing the subtraction. +% Input "a" is then multiplied by \( 10 \), and the process is repeated. +% The looping ends either when there is nothing left of "a" +% (\emph{i.e.}~an exact result) or when the code reaches the ninth +% decimal place. Most of the process takes place in the loop function +% below. % \begin{macrocode} \cs_new_protected_nopar:Npn \fp_div_aux: { - \l_fp_div_offset_int \c_one - \tex_ifnum:D \l_fp_input_a_integer_int > \c_zero - \exp_after:wN \fp_div_offset_create: - \tex_fi:D \l_fp_output_integer_int \c_zero - \l_fp_output_decimal_int \c_one_thousand_million + \l_fp_output_decimal_int \c_zero \cs_set_eq:NN \fp_div_store: \fp_div_store_integer: + \l_fp_div_offset_int \c_one_hundred_million \fp_div_loop: - \tl_set:Nx \l_fp_tmp_tl + \l_fp_output_exponent_int + \etex_numexpr:D + \l_fp_input_a_exponent_int - \l_fp_input_b_exponent_int + \scan_stop: + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \cs_set_protected_nopar:Npx \fp_tmp:w ##1##2 { - \tex_ifnum:D - \etex_numexpr:D - \l_fp_input_a_sign_int * \l_fp_input_b_sign_int - \scan_stop: - < \c_zero - \tex_ifnum:D - \etex_numexpr:D - \l_fp_output_integer_int + \l_fp_output_decimal_int - \scan_stop: - = \c_one_thousand_million - + - \tex_else:D - - - \tex_fi:D - \tex_else:D - + - \tex_fi:D - \int_use:N \l_fp_output_integer_int - . - \exp_after:wN \use_none:n - \int_use:N \l_fp_output_decimal_int + \group_end: + ##1 ##2 + { + \tex_ifnum:D + \etex_numexpr:D + \l_fp_input_a_sign_int * \l_fp_input_b_sign_int + < \c_zero + \tex_ifnum:D + \etex_numexpr:D + \l_fp_output_integer_int + \l_fp_output_decimal_int + = \c_zero + + + \tex_else:D + - + \tex_fi:D + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \tex_number:D \etex_numexpr:D + \l_fp_output_decimal_int + \c_one_thousand_million + \scan_stop: + e + \int_use:N \l_fp_output_exponent_int + } } } % \end{macrocode} -% The offset is created such that it will automatically be accounted -% for in the rest of the process. Rather than doing any integer division -% a delimited function is used to transfer the digit from the -% integer to the decimal parts. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_div_offset_create: { - \tex_ifnum:D \l_fp_input_b_integer_int = \c_zero - \tex_advance:D \l_fp_input_b_decimal_int \c_one_thousand_million - \exp_after:wN \fp_div_offset_create_aux:w - \int_use:N \l_fp_input_b_decimal_int \q_stop - \exp_after:wN \fp_div_offset_create: - \tex_fi:D -} -\cs_new_protected_nopar:Npn \fp_div_offset_create_aux:w - #1#2#3#4#5#6#7#8#9 \q_stop { - \l_fp_input_b_integer_int #2 \scan_stop: - \l_fp_input_b_decimal_int #3#4#5#6#7#8#9 0 \scan_stop: - \tex_multiply:D \l_fp_div_offset_int \c_ten -} -% \end{macrocode} -% The main division loop must start with both numerator and -% denominator above zero, so the test is at the tail of the loop. -% Once again, division by ten for the denominator is avoided, with -% a delimited function doing the job. The test at the end of the -% function means that the loop terminates as soon as one part of the -% input reaches zero: this saves dead loops if the division is -% exact. +% The main loop implements the approach described above. The storing +% function is done as a function so that the integer and decimal parts +% can be done separately but rapidly. % \begin{macrocode} \cs_new_protected_nopar:Npn \fp_div_loop: { - \l_fp_div_count_int \c_zero + \l_fp_count_int \c_zero \fp_div_divide: - \tex_divide:D \l_fp_input_b_decimal_int \c_ten - \tex_advance:D \l_fp_input_b_integer_int \c_one_thousand_million - \exp_after:wN \fp_div_loop_aux_i:w - \int_use:N \l_fp_input_b_integer_int \fp_div_store: + \tex_multiply:D \l_fp_input_a_integer_int \c_ten + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \fp_div_loop_step:w + \int_use:N \l_fp_input_a_decimal_int \q_stop \tex_ifnum:D \etex_numexpr:D \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int > \c_zero - \tex_ifnum:D - \etex_numexpr:D - \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int - > \c_zero - \exp_after:wN \exp_after:wN \exp_after:wN - \fp_div_loop: - \tex_fi:D + \tex_ifnum:D \l_fp_div_offset_int > \c_zero + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_div_loop: + \tex_fi:D \tex_fi:D } % \end{macrocode} @@ -1820,18 +2804,8 @@ \tex_fi:D \tex_fi:D } -\cs_new_protected_nopar:Npn \fp_div_loop_aux_i:w #1#2#3#4#5#6#7#8#9 { - \fp_div_loop_aux_ii:w #2#3#4#5#6#7#8#9 -} -\cs_new_protected_nopar:Npn \fp_div_loop_aux_ii:w #1#2#3#4#5#6#7#8#9 { - \l_fp_input_b_integer_int #1#2#3#4#5#6#7#8 \scan_stop: - \l_fp_input_b_decimal_int - \etex_numexpr:D - \l_fp_input_b_decimal_int + \c_one_hundred_million * #9 - \scan_stop: -} \cs_new_protected_nopar:Npn \fp_div_divide_aux: { - \tex_advance:D \l_fp_div_count_int \c_one + \tex_advance:D \l_fp_count_int \c_one \tex_advance:D \l_fp_input_a_integer_int -\l_fp_input_b_integer_int \tex_advance:D \l_fp_input_a_decimal_int -\l_fp_input_b_decimal_int \tex_ifnum:D \l_fp_input_a_decimal_int < \c_zero @@ -1841,52 +2815,964 @@ \fp_div_divide: } % \end{macrocode} -% The final stage of each loop is to store the result. This is done -% separately for the integer and decimal parts. The offset is used to -% get the digits in the correct place, and so also indicates when the -% switch from the integer to the decimal. +% Storing the number of each division is done differently for the +% integer and decimal. The integer is easy and a one-off, while the +% decimal also needs to account for the position of the digit to store. % \begin{macrocode} \cs_new_protected_nopar:Npn \fp_div_store: { } \cs_new_protected_nopar:Npn \fp_div_store_integer: { - \l_fp_output_integer_int - \etex_numexpr:D - \l_fp_output_integer_int + - \l_fp_div_count_int * \l_fp_div_offset_int - \scan_stop: - \tex_ifnum:D \l_fp_div_offset_int > \c_one - \tex_divide:D \l_fp_div_offset_int \c_ten - \tex_else:D - \cs_set_eq:NN \fp_div_store: \fp_div_store_decimal: - \l_fp_div_offset_int \c_one_hundred_million - \tex_fi:D + \l_fp_output_integer_int \l_fp_count_int + \cs_set_eq:NN \fp_div_store: \fp_div_store_decimal: } \cs_new_protected_nopar:Npn \fp_div_store_decimal: { \l_fp_output_decimal_int \etex_numexpr:D \l_fp_output_decimal_int + - \l_fp_div_count_int * \l_fp_div_offset_int + \l_fp_count_int * \l_fp_div_offset_int \scan_stop: \tex_divide:D \l_fp_div_offset_int \c_ten } +\cs_new_protected_nopar:Npn + \fp_div_loop_step:w #1#2#3#4#5#6#7#8#9 \q_stop { + \l_fp_input_a_integer_int + \etex_numexpr:D + #2 + \l_fp_input_a_integer_int + \scan_stop: + \l_fp_input_a_decimal_int #3#4#5#6#7#8#9 0 \scan_stop: +} % \end{macrocode} %\end{macro} +%\end{macro} %\end{macro} %\end{macro} %\end{macro} +%\end{macro} +%\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} +%\end{macro} +% +%\subsection{Arithmetic for internal use} +% +% For the more complex functions, it is only possible to deliver +% reliable \( 10 \) digit accuracy if the internal calculations are +% carried out to a higher degree of precision. This is done using a +% second set of functions so that the `user' versions are not +% slowed down. These versions are also focussed on the needs of internal +% calculations. No error checking, sign checking or exponent levelling +% is done. For addition and subtraction, the arguments are: +% \begin{itemize} +% \item Integer part of input "a". +% \item Decimal part of input "a". +% \item Additional decimal part of input "a". +% \item Integer part of input "b". +% \item Decimal part of input "b". +% \item Additional decimal part of input "b". +% \item Integer part of output. +% \item Decimal part of output. +% \item Additional decimal part of output. +% \end{itemize} +% The situation for multiplication and division is a little different as +% they only deal with the decimal part. +% +%\begin{macro}{\fp_add:NNNNNNNNN} +% The internal sum is always exactly that: it is always a sum and there +% is no sign check. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_add:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { + #7 \etex_numexpr:D #1 + #4 \scan_stop: + #8 \etex_numexpr:D #2 + #5 \scan_stop: + #9 \etex_numexpr:D #3 + #6 \scan_stop: + \tex_ifnum:D #9 < \c_one_thousand_million + \tex_else:D + \tex_advance:D #8 \c_one + \tex_advance:D #9 -\c_one_thousand_million + \tex_fi:D + \tex_ifnum:D #8 < \c_one_thousand_million + \tex_else:D + \tex_advance:D #7 \c_one + \tex_advance:D #8 -\c_one_thousand_million + \tex_fi:D +} +% \end{macrocode} %\end{macro} +% +%\begin{macro}{\fp_sub:NNNNNNNNNN} +% Internal subtraction is needed only when the first number is bigger +% than the second, so there is no need to worry about the sign. This is +% a good job as there are no arguments left. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_sub:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { + #7 \etex_numexpr:D #1 - #4 \scan_stop: + #8 \etex_numexpr:D #2 - #5 \scan_stop: + #9 \etex_numexpr:D #3 - #6 \scan_stop: + \tex_ifnum:D #9 < \c_zero + \tex_advance:D #8 \c_minus_one + \tex_advance:D #9 \c_one_thousand_million + \tex_fi:D + \tex_ifnum:D #8 < \c_zero + \tex_advance:D #7 \c_minus_one + \tex_advance:D #8 \c_one_thousand_million + \tex_fi:D + \tex_ifnum:D #7 < \c_zero + \tex_ifnum:D \etex_numexpr:D #8 + #9 = \c_zero + #7 -#7 + \tex_else:D + \tex_advance:D #7 \c_one + #8 \etex_numexpr:D \c_one_thousand_million - #8 \scan_stop: + #9 \etex_numexpr:D \c_one_thousand_million - #9 \scan_stop: + \tex_fi:D + \tex_fi:D +} +% \end{macrocode} %\end{macro} +% +%\begin{macro}{\fp_mul:NNNNNN} +% Decimal-part only multiplication but with higher accuracy than the +% user version. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_mul:NNNNNN #1#2#3#4#5#6 { + \fp_mul_split:NNNN #1 + \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int + \fp_mul_split:NNNN #2 + \l_fp_mul_a_iv_int \l_fp_mul_a_v_int \l_fp_mul_a_vi_int + \fp_mul_split:NNNN #3 + \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int + \fp_mul_split:NNNN #4 + \l_fp_mul_b_iv_int \l_fp_mul_b_v_int \l_fp_mul_b_vi_int + \l_fp_mul_output_int \c_zero + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_vi_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_i_int + \tex_divide:D \l_fp_mul_output_int \c_one_thousand + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_ii_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_i_int + \fp_mul_end_level: + #6 0 \l_fp_mul_output_tl \scan_stop: + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_end_level: + #5 0 \l_fp_mul_output_tl \scan_stop: +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\fp_div_integer:NNNNN} +% Here, division is always by an integer, and so it is possible to +% use \TeX's native calculations rather than doing it in macros. +% The idea here is to divide the decimal part, find any remainder, +% then do the real division of the two parts before adding in what +% is needed for the remainder. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_div_integer:NNNNN #1#2#3#4#5 { + \l_fp_tmp_int #1 + \tex_divide:D \l_fp_tmp_int #3 + \l_fp_tmp_int \etex_numexpr:D #1 - \l_fp_tmp_int * #3 \scan_stop: + #4 #1 + \tex_divide:D #4 #3 + #5 #2 + \tex_divide:D #5 #3 + \tex_multiply:D \l_fp_tmp_int \c_one_thousand + \tex_divide:D \l_fp_tmp_int #3 + #5 \etex_numexpr:D #5 + \l_fp_tmp_int * \c_one_million \scan_stop: + \tex_ifnum:D #5 > \c_one_thousand_million + \tex_advance:D #4 \c_one + \tex_advancd:D #5 -\c_one_thousand_million + \tex_fi:D +} +% \end{macrocode} +%\end{macro} +% +%\subsection{Trigonometric functions} +% +%\begin{macro}{\fp_trig_normalise:} +%\begin{macro}[aux]{\fp_trig_normalise_aux_i:} +%\begin{macro}[aux]{\fp_trig_normalise_aux:w} +%\begin{macro}[aux]{\fp_trig_normalise_aux_ii:} +%\begin{macro}[aux]{\fp_trig_normalise_aux:NNNNNNNNN} +%\begin{macro}[aux]{\fp_trig_normalise_aux_iii:} +% For normalisation, the code essentially switches to fixed-point +% arithmetic. There is a shift of the exponent, then repeated +% subtractions. The end result is a number in the range +% \( -\pi < x \le \pi \). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_trig_normalise: { + \tex_ifnum:D \l_fp_input_a_exponent_int < \c_ten + \l_fp_input_a_extended_int \c_zero + \fp_trig_normalise_aux_i: + \fp_trig_normalise_aux_ii: + \fp_trig_normalise_aux_iii: + \tex_ifnum:D \l_fp_input_a_integer_int < \c_zero + \l_fp_input_a_sign_int -\l_fp_input_a_sign_int + \l_fp_input_a_integer_int -\l_fp_input_a_integer_int + \tex_fi:D + \exp_after:wN \fp_trig_octant: + \tex_else:D + \l_fp_input_a_sign_int \c_one + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_zero + \l_fp_output_exponent_int \c_zero + \exp_after:wN \fp_trig_overflow_msg: + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_trig_normalise_aux_i: { + \tex_ifnum:D \l_fp_input_a_exponent_int > \c_zero + \tex_multiply:D \l_fp_input_a_integer_int \c_ten + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \fp_trig_normalise_aux:w + \int_use:N \l_fp_input_a_decimal_int \q_stop + \exp_after:wN \fp_trig_normalise_aux_i: + \tex_fi:D +} +\cs_new_protected_nopar:Npn + \fp_trig_normalise_aux:w #1#2#3#4#5#6#7#8#9 \q_stop { + \l_fp_input_a_integer_int + \etex_numexpr:D \l_fp_input_a_integer_int + #2 \scan_stop: + \l_fp_input_a_decimal_int #3#4#5#6#7#8#9 0 \scan_stop: + \tex_advance:D \l_fp_input_a_exponent_int \c_minus_one +} +\cs_new_protected_nopar:Npn \fp_trig_normalise_aux_ii: { + \tex_ifnum:D \l_fp_input_a_exponent_int < \c_zero + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_trig_normalise_aux:NNNNNNNNN + \int_use:N \l_fp_input_a_decimal_int + \exp_after:wN \fp_trig_normalise_aux_ii: + \tex_fi:D +} +\cs_new_protected_nopar:Npn + \fp_trig_normalise_aux:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { + \tex_ifnum:D \l_fp_input_a_integer_int = \c_zero + \l_fp_input_a_decimal_int #1#2#3#4#5#6#7#8 \scan_stop: + \tex_else:D + \tl_set:Nx \l_fp_tmp_tl + { + \int_use:N \l_fp_input_a_integer_int + #1#2#3#4#5#6#7#8 + } + \l_fp_input_a_integer_int \c_zero + \l_fp_input_a_decimal_int \l_fp_tmp_tl \scan_stop: + \tex_fi:D + \tex_divide:D \l_fp_input_a_extended_int \c_ten + \tl_set:Nx \l_fp_tmp_tl + { + #9 + \int_use:N \l_fp_input_a_extended_int + } + \l_fp_input_a_extended_int \l_fp_tmp_tl \scan_stop: + \tex_advance:D \l_fp_input_a_exponent_int \c_one +} +\cs_new_protected_nopar:Npn \fp_trig_normalise_aux_iii: { + \tex_ifnum:D \l_fp_input_a_integer_int > \c_three + \fp_sub:NNNNNNNNN + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \c_six \c_fp_two_pi_decimal_int \c_fp_two_pi_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \exp_after:wN \fp_trig_normalise_aux_iii: + \tex_else:D + \tex_ifnum:D \l_fp_input_a_integer_int > \c_two + \tex_ifnum:D \l_fp_input_a_decimal_int > \c_fp_pi_decimal_int + \fp_sub:NNNNNNNNN + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \c_six \c_fp_two_pi_decimal_int \c_fp_two_pi_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \fp_trig_normalise_aux_iii: + \tex_fi:D + \tex_fi:D + \tex_fi:D +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_trig_octant:} +%\begin{macro}[aux]{\fp_trig_octant_aux:} +% Here, the input is further reduced into the range +% \( 0 \le x < \pi / 4 \). This is pretty simple: check if +% \( \pi / 4 \) can be taken off and if it can do it and loop. The +% check at the end is to `mop up' values which are so close to +% \( \pi / 4 \) that they should be treated as such. The test for +% an even octant is needed as the `remainder' needed is from +% the nearest \( \pi / 2 \). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_trig_octant: { + \l_fp_trig_octant_int \c_one + \fp_trig_octant_aux: + \tex_ifnum:D \l_fp_input_a_decimal_int < \c_ten + \l_fp_input_a_decimal_int \c_zero + \l_fp_input_a_extended_int \c_zero + \tex_fi:D + \tex_ifodd:D \l_fp_trig_octant_int + \tex_else:D + \fp_sub:NNNNNNNNN + \c_zero \c_fp_pi_by_four_decimal_int \c_fp_pi_by_four_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_trig_octant_aux: { + \tex_ifnum:D \l_fp_input_a_integer_int > \c_zero + \fp_sub:NNNNNNNNN + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \c_zero \c_fp_pi_by_four_decimal_int \c_fp_pi_by_four_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \tex_advance:D \l_fp_trig_octant_int \c_one + \exp_after:wN \fp_trig_octant_aux: + \tex_else:D + \tex_ifnum:D + \l_fp_input_a_decimal_int > \c_fp_pi_by_four_decimal_int + \fp_sub:NNNNNNNNN + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \c_zero \c_fp_pi_by_four_decimal_int + \c_fp_pi_by_four_extended_int + \l_fp_input_a_integer_int \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int + \tex_advance:D \l_fp_trig_octant_int \c_one + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_trig_octant_aux: + \tex_fi:D + \tex_fi:D +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_sin:Nn} +%\begin{macro}{\fp_sin:cn} +%\begin{macro}{\fp_gsin:Nn} +%\begin{macro}{\fp_gsin:cn} +%\begin{macro}[aux]{\fp_sin_aux:NNn} +%\begin{macro}[aux]{\fp_sin_aux_i:} +%\begin{macro}[aux]{\fp_sin_aux_ii:} +% Calculating the sine starts off in the usual way. There is a check +% to see if the value has already been worked out before proceeding +% further. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_sin:Nn { + \fp_sin_aux:NNn \tl_set:Nn +} +\cs_new_protected_nopar:Npn \fp_gsin:Nn { + \fp_sin_aux:NNn \tl_gset:Nn +} +\cs_generate_variant:Nn \fp_sin:Nn { c } +\cs_generate_variant:Nn \fp_gsin:Nn { c } +% \end{macrocode} +% The internal routine for sines does a check to see if the value is +% already known. This saves a lot of repetition when doing rotations. +% For very small values it is best to simply return the input as the +% sine: the cut-off is \( 1 \times 10^{-5} \). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_sin_aux:NNn #1#2#3 { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tl_set:Nx \l_fp_trig_arg_tl + { + \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero + - + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \tex_number:D \etex_numexpr:D + \l_fp_input_a_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_input_a_exponent_int + } + \tex_ifnum:D \l_fp_input_a_exponent_int < -\c_five + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 { \l_fp_trig_arg_tl } + } + \tex_else:D + \etex_ifcsname:D + c_fp_sin ( \l_fp_trig_arg_tl ) _tl + \tex_endcsname:D + \tex_else:D + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_sin_aux_i: + \tex_fi:D + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { \use:c { c_fp_sin ( \l_fp_trig_arg_tl ) _tl } } + } + \tex_fi:D + \fp_tmp:w +} +% \end{macrocode} +% The internals for sine first normalise the input into an octant, then +% choose the correct set up for the Taylor series. The sign for the sine +% function is easy, so there is no worry about it. So the only thing to +% do is to get the output standardised. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_sin_aux_i: { + \fp_trig_normalise: + \fp_sin_aux_ii: + \tex_ifnum:D \l_fp_output_integer_int = \c_one + \l_fp_output_exponent_int \c_zero + \tex_else:D + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_decimal_int \l_fp_output_extended_int + \l_fp_output_exponent_int -\c_nine + \tex_fi:D + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \tl_new:c { c_fp_sin ( \l_fp_trig_arg_tl ) _tl } + \tl_set:cx { c_fp_sin ( \l_fp_trig_arg_tl ) _tl } + { + \tex_ifnum:D \l_fp_input_a_sign_int > \c_zero + + + \tex_else:D + - + \tex_fi:D + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \tex_number:D \etex_numexpr:D + \l_fp_output_decimal_int + \c_one_thousand_million + \scan_stop: + e + \int_use:N \l_fp_output_exponent_int + } +} +\cs_new_protected_nopar:Npn \fp_sin_aux_ii: { + \tex_ifcase:D \l_fp_trig_octant_int + \tex_or:D + \exp_after:wN \fp_trig_calc_sin: + \tex_or:D + \exp_after:wN \fp_trig_calc_cos: + \tex_or:D + \exp_after:wN \fp_trig_calc_cos: + \tex_or:D + \exp_after:wN \fp_trig_calc_sin: + \tex_fi:D +} +% \end{macrocode} +%\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_cos:Nn} +%\begin{macro}{\fp_cos:cn} +%\begin{macro}{\fp_gcos:Nn} +%\begin{macro}{\fp_gcos:cn} +%\begin{macro}[aux]{\fp_cos_aux:NNn} +%\begin{macro}[aux]{\fp_cos_aux_i:} +%\begin{macro}[aux]{\fp_cos_aux_ii:} +% Cosine is almost identical, but there is no short cut code here. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_cos:Nn { + \fp_cos_aux:NNn \tl_set:Nn +} +\cs_new_protected_nopar:Npn \fp_gcos:Nn { + \fp_cos_aux:NNn \tl_gset:Nn +} +\cs_generate_variant:Nn \fp_cos:Nn { c } +\cs_generate_variant:Nn \fp_gcos:Nn { c } +\cs_new_protected_nopar:Npn \fp_cos_aux:NNn #1#2#3 { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tl_set:Nx \l_fp_trig_arg_tl + { + \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero + - + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \tex_number:D \etex_numexpr:D + \l_fp_input_a_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_input_a_exponent_int + } + \etex_ifcsname:D c_fp_cos ( \l_fp_trig_arg_tl ) _tl \tex_endcsname:D + \tex_else:D + \exp_after:wN \fp_cos_aux_i: + \tex_fi:D + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { \use:c { c_fp_cos ( \l_fp_trig_arg_tl ) _tl } } + } + \fp_tmp:w +} +% \end{macrocode} +% Almost the same as for sine: just a bit of correction for the sign +% of the output. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_cos_aux_i: { + \fp_trig_normalise: + \fp_cos_aux_ii: + \tex_ifnum:D \l_fp_output_integer_int = \c_one + \l_fp_output_exponent_int \c_zero + \tex_else:D + \l_fp_output_integer_int \l_fp_output_decimal_int + \l_fp_output_decimal_int \l_fp_output_extended_int + \l_fp_output_exponent_int -\c_nine + \tex_fi:D + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \tl_new:c { c_fp_cos ( \l_fp_trig_arg_tl ) _tl } + \tl_set:cx { c_fp_cos ( \l_fp_trig_arg_tl ) _tl } + { + \tex_ifnum:D \l_fp_input_a_sign_int > \c_zero + + + \tex_else:D + - + \tex_fi:D + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \tex_number:D \etex_numexpr:D + \l_fp_output_decimal_int + \c_one_thousand_million + \scan_stop: + e + \int_use:N \l_fp_output_exponent_int + } +} +\cs_new_protected_nopar:Npn \fp_cos_aux_ii: { + \tex_ifcase:D \l_fp_trig_octant_int + \tex_or:D + \exp_after:wN \fp_trig_calc_cos: + \tex_or:D + \exp_after:wN \fp_trig_calc_sin: + \tex_or:D + \exp_after:wN \fp_trig_calc_sin: + \tex_or:D + \exp_after:wN \fp_trig_calc_cos: + \tex_fi:D + \tex_ifnum:D \l_fp_input_a_sign_int > \c_zero + \tex_ifnum:D \l_fp_trig_octant_int > \c_two + \l_fp_input_a_sign_int \c_minus_one + \tex_fi:D + \tex_else:D + \tex_ifnum:D \l_fp_trig_octant_int > \c_two + \tex_else:D + \l_fp_input_a_sign_int \c_one + \tex_fi:D + \tex_fi:D +} +% \end{macrocode} +%\end{macro} %\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} % -%\subsection{Fixed-point conditionals} +%\begin{macro}{\fp_trig_calc_cos:} +%\begin{macro}{\fp_trig_calc_sin:} +%\begin{macro}[aux]{\fp_trig_calc_aux:} +% These functions actually do the calculation for sine and cosine. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_trig_calc_cos: { + \tex_ifnum:D \l_fp_input_a_decimal_int = \c_zero + \l_fp_output_integer_int \c_one + \l_fp_output_decimal_int \c_zero + \tex_else:D + \l_fp_trig_sign_int \c_minus_one + \fp_mul:NNNNNN + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \fp_div_integer:NNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \c_two + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_count_int \c_three + \tex_ifnum:D \l_fp_trig_extended_int = \c_zero + \tex_ifnum:D \l_fp_trig_decimal_int = \c_zero + \l_fp_output_integer_int \c_one + \l_fp_output_decimal_int \c_zero + \l_fp_output_extended_int \c_zero + \tex_else:D + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_one_thousand_million + \l_fp_output_extended_int \c_zero + \tex_fi:D + \tex_else:D + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int 999999999 \scan_stop: + \l_fp_output_extended_int \c_one_thousand_million + \tex_fi:D + \tex_advance:D \l_fp_output_extended_int -\l_fp_trig_extended_int + \tex_advance:D \l_fp_output_decimal_int -\l_fp_trig_decimal_int + \exp_after:wN \fp_trig_calc_aux: + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_trig_calc_sin: { + \l_fp_output_integer_int \c_zero + \tex_ifnum:D \l_fp_input_a_decimal_int = \c_zero + \l_fp_output_decimal_int \c_zero + \tex_else:D + \l_fp_output_decimal_int \l_fp_input_a_decimal_int + \l_fp_output_extended_int \l_fp_input_a_extended_int + \l_fp_trig_sign_int \c_one + \l_fp_trig_decimal_int \l_fp_input_a_decimal_int + \l_fp_trig_extended_int \l_fp_input_a_extended_int + \l_fp_count_int \c_two + \exp_after:wN \fp_trig_calc_aux: + \tex_fi:D +} +% \end{macrocode} +% This implements a Taylor series calculation for the trigonometric +% functions. Lots of shuffling about as \TeX\ is not exactly a natural +% choice for this sort of thing. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_trig_calc_aux: { + \l_fp_trig_sign_int -\l_fp_trig_sign_int + \fp_mul:NNNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \fp_mul:NNNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_input_a_decimal_int \l_fp_input_a_extended_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \fp_div_integer:NNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_count_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \tex_advance:D \l_fp_count_int \c_one + \fp_div_integer:NNNNN + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \l_fp_count_int + \l_fp_trig_decimal_int \l_fp_trig_extended_int + \tex_advance:D \l_fp_count_int \c_one + \tex_ifnum:D \l_fp_trig_decimal_int > \c_zero + \tex_ifnum:D \l_fp_trig_sign_int > \c_zero + \tex_advance:D \l_fp_output_decimal_int \l_fp_trig_decimal_int + \tex_advance:D \l_fp_output_extended_int + \l_fp_trig_extended_int + \tex_ifnum:D \l_fp_output_extended_int < \c_one_thousand_million + \tex_else:D + \tex_advance:D \l_fp_output_decimal_int \c_one + \tex_advance:D \l_fp_output_extended_int + -\c_one_thousand_million + \tex_fi:D + \tex_ifnum:D \l_fp_output_decimal_int < \c_one_thousand_million + \tex_else:D + \tex_advance:D \l_fp_output_integer_int \c_one + \tex_advance:D \l_fp_output_decimal_int + -\c_one_thousand_million + \tex_fi:D + \tex_else:D + \tex_advance:D \l_fp_output_decimal_int -\l_fp_trig_decimal_int + \tex_advance:D \l_fp_output_extended_int + -\l_fp_input_a_extended_int + \tex_ifnum:D \l_fp_output_extended_int < \c_zero + \tex_advance:D \l_fp_output_decimal_int \c_minus_one + \tex_advance:D \l_fp_output_extended_int \c_one_thousand_million + \tex_fi:D + \tex_ifnum:D \l_fp_output_decimal_int < \c_zero + \tex_advance:D \l_fp_output_integer_int \c_minus_one + \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million + \tex_fi:D + \tex_fi:D + \exp_after:wN \fp_trig_calc_aux: + \tex_fi:D +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_tan:Nn} +%\begin{macro}{\fp_tan:cn} +%\begin{macro}{\fp_gtan:Nn} +%\begin{macro}{\fp_gtan:cn} +%\begin{macro}[aux]{\fp_tan_aux:NNn} +%\begin{macro}[aux]{\fp_tan_aux_i:} +%\begin{macro}[aux]{\fp_tan_aux_ii:} +%\begin{macro}[aux]{\fp_tan_aux_iii:} +%\begin{macro}[aux]{\fp_tan_aux_iv:} +% As might be expected, tangents are calculated from the sine and cosine +% by division. So there is a bit of set up, the two subsidiary pieces +% of work are done and then a division takes place. For small numbers, +% the same approach is used as for sines, with the input value simply +% returned as is. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_tan:Nn { + \fp_tan_aux:NNn \tl_set:Nn +} +\cs_new_protected_nopar:Npn \fp_gtan:Nn { + \fp_tan_aux:NNn \tl_gset:Nn +} +\cs_generate_variant:Nn \fp_tan:Nn { c } +\cs_generate_variant:Nn \fp_gtan:Nn { c } +\cs_new_protected_nopar:Npn \fp_tan_aux:NNn #1#2#3 { + \group_begin: + \fp_split:Nn a {#3} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tl_set:Nx \l_fp_trig_arg_tl + { + \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero + - + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \tex_number:D \etex_numexpr:D + \l_fp_input_a_decimal_int + \c_one_thousand_million + e + \int_use:N \l_fp_input_a_exponent_int + } + \tex_ifnum:D \l_fp_input_a_exponent_int < -\c_five + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 { \l_fp_trig_arg_tl } + } + \tex_else:D + \etex_ifcsname:D + c_fp_tan ( \l_fp_trig_arg_tl ) _tl + \tex_endcsname:D + \tex_else:D + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_tan_aux_i: + \tex_fi:D + \cs_set_protected_nopar:Npx \fp_tmp:w + { + \group_end: + #1 \exp_not:N #2 + { \use:c { c_fp_tan ( \l_fp_trig_arg_tl ) _tl } } + } + \tex_fi:D + \fp_tmp:w +} +% \end{macrocode} +% The business of the calculation does not check for stored sines or +% cosines as there would then be an overhead to reading them back in. +% There is also no need to worry about `small' sine values as +% these will have been dealt with earlier. There is a two-step lead off +% so that undefined division is not even attempted. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_tan_aux_i: { + \tex_ifnum:D \l_fp_input_a_exponent_int < \c_ten + \exp_after:wN \fp_tan_aux_ii: + \tex_else:D + \cs_new_eq:cN { c_fp_tan ( \l_fp_trig_arg_tl ) _tl } + \c_zero_fp + \exp_after:wN \fp_trig_overflow_msg: + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_tan_aux_ii: { + \fp_trig_normalise: + \fp_cos_aux_ii: + \tex_ifnum:D \l_fp_input_a_decimal_int = \c_zero + \tex_ifnum:D \l_fp_input_a_integer_int = \c_zero + \cs_new_eq:cN { c_fp_tan ( \l_fp_trig_arg_tl ) _tl } + \c_undefined_fp + \tex_else:D + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_tan_aux_iii: + \tex_fi:D + \tex_else:D + \exp_after:wN \fp_tan_aux_iii: + \tex_fi:D +} +% \end{macrocode} +% The division is done here using the same code as the standard division +% unit, shifting the digits in the calculated sine and cosine to +% maintain accuracy. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_tan_aux_iii: { + \l_fp_input_b_integer_int \l_fp_output_decimal_int + \l_fp_input_b_decimal_int \l_fp_output_extended_int + \l_fp_input_b_exponent_int -\c_nine + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int + \fp_sin_aux_ii: + \l_fp_input_a_integer_int \l_fp_output_decimal_int + \l_fp_input_a_decimal_int \l_fp_output_extended_int + \l_fp_input_a_exponent_int -\c_nine + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int + \tex_ifnum:D \l_fp_input_a_decimal_int = \c_zero + \tex_ifnum:D \l_fp_input_a_integer_int = \c_zero + \cs_new_eq:cN { c_fp_tan ( \l_fp_trig_arg_tl ) _tl } + \c_zero_fp + \tex_else:D + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_tan_aux_iv: + \tex_fi:D + \tex_else:D + \exp_after:wN \fp_tan_aux_iv: + \tex_fi:D +} + \cs_new_protected_nopar:Npn \fp_tan_aux_iv: { + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_zero + \cs_set_eq:NN \fp_div_store: \fp_div_store_integer: + \l_fp_div_offset_int \c_one_hundred_million + \fp_div_loop: + \l_fp_output_exponent_int + \etex_numexpr:D + \l_fp_input_a_exponent_int - \l_fp_input_b_exponent_int + \scan_stop: + \tex_ifnum:D \l_fp_trig_octant_int < \c_three + \l_fp_output_sign_int \c_one + \tex_else:D + \l_fp_output_sign_int \c_minus_one + \tex_fi:D + \fp_standardise:NNNN + \l_fp_output_sign_int + \l_fp_output_integer_int + \l_fp_output_decimal_int + \l_fp_output_exponent_int + \tl_new:c { c_fp_tan ( \l_fp_trig_arg_tl ) _tl } + \tl_set:cx { c_fp_tan ( \l_fp_trig_arg_tl ) _tl } + { + \tex_ifnum:D \l_fp_output_sign_int > \c_zero + + + \tex_else:D + - + \tex_fi:D + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \tex_number:D \etex_numexpr:D + \l_fp_output_decimal_int + \c_one_thousand_million + \scan_stop: + e + \int_use:N \l_fp_output_exponent_int + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\subsection{Tests for special values} +% +%\begin{macro}{\fp_if_infinity_p:N} +%\begin{macro}[TF]{\fp_if_infinity:N} +% Testing for infinity is easy. +% \begin{macrocode} +\prg_new_conditional:Npnn \fp_if_infinity:N #1 { p , T , F , TF } { + \tex_ifx:D #1 \c_infinity_fp + \prg_return_true: + \tex_else:D + \prg_return_false: + \tex_fi:D +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_if_undefined_p:N} +%\begin{macro}[TF]{\fp_if_undefined:N} +% Testing for an undefined value is easy. +% \begin{macrocode} +\prg_new_conditional:Npnn \fp_if_undefined:N #1 { p , T , F , TF } { + \tex_ifx:D #1 \c_undefined_fp + \prg_return_true: + \tex_else:D + \prg_return_false: + \tex_fi:D +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_if_zero_p:N} +%\begin{macro}[TF]{\fp_if_zero:N} +% Testing for a zero fixed-point is also easy. +% \begin{macrocode} +\prg_new_conditional:Npnn \fp_if_zero:N #1 { p , T , F , TF } { + \tex_ifx:D #1 \c_zero_fp + \prg_return_true: + \tex_else:D + \prg_return_false: + \tex_fi:D +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\subsection{Floating-point conditionals} % %\begin{macro}[TF]{\fp_compare:nNn} %\begin{macro}[TF]{\fp_compare:NNN} @@ -1900,20 +3786,31 @@ % faster. The lead off for both is the same: get the two numbers % read and then look for a function to handle the comparison. % \begin{macrocode} -\prg_new_protected_conditional:Npnn \fp_compare:nNn #1#2#3 - { T , F , TF } { +\prg_new_protected_conditional:Npnn \fp_compare:nNn #1#2#3 { T , F , TF } + { \group_begin: \fp_split:Nn a {#1} + \fp_standardise:NNNN + \l_fp_input_a_sign_int + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \l_fp_input_a_exponent_int \fp_split:Nn b {#3} + \fp_standardise:NNNN + \l_fp_input_b_sign_int + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \l_fp_input_b_exponent_int \fp_compare_aux:N #2 } -\prg_new_protected_conditional:Npnn \fp_compare:NNN #1#2#3 - { T , F , TF } { +\prg_new_protected_conditional:Npnn \fp_compare:NNN #1#2#3 { T , F , TF } + { \group_begin: \fp_read:N #3 - \l_fp_input_b_sign_int \l_fp_input_a_sign_int - \l_fp_input_b_integer_int \l_fp_input_a_integer_int - \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int + \l_fp_input_b_sign_int \l_fp_input_a_sign_int + \l_fp_input_b_integer_int \l_fp_input_a_integer_int + \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int + \l_fp_input_b_exponent_int \l_fp_input_a_exponent_int \fp_read:N #1 \fp_compare_aux:N #2 } @@ -1933,8 +3830,14 @@ \tex_ifnum:D \l_fp_input_a_sign_int = \l_fp_input_b_sign_int \tex_ifnum:D \l_fp_input_a_integer_int = \l_fp_input_b_integer_int \tex_ifnum:D \l_fp_input_a_decimal_int = \l_fp_input_b_decimal_int - \group_end: - \prg_return_true: + \tex_ifnum:D + \l_fp_input_a_exponent_int = \l_fp_input_b_exponent_int + \group_end: + \prg_return_true: + \tex_else:D + \group_end: + \prg_return_false: + \tex_fi:D \tex_else:D \group_end: \prg_return_false: @@ -1949,8 +3852,8 @@ \tex_fi:D } % \end{macrocode} -% For comparitors life is a lot moe complex, as there are three cases for -% the integer part (equality as well as greater and less than). The +% For comparators life is a lot more complex, as there are three cases +% for the integer part (equality as well as greater and less than). The % code here is quite repetitive to keep speed up, and simply does % exhaustive checks. % \begin{macrocode} @@ -1989,353 +3892,84 @@ \tex_fi:D } \cs_new_protected_nopar:cpn { fp_compare_absolute_a > b: } { - \tex_ifnum:D \l_fp_input_a_integer_int > \l_fp_input_b_integer_int + \tex_ifnum:D \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int \group_end: - \prg_return_true: - \tex_else:D - \tex_ifnum:D \l_fp_input_a_integer_int < \l_fp_input_b_integer_int - \group_end: - \prg_return_false: - \tex_else:D - \tex_ifnum:D \l_fp_input_a_decimal_int > \l_fp_input_b_decimal_int + \prg_return_true: + \tex_else:D + \tex_ifnum:D \l_fp_input_a_exponent_int < \l_fp_input_b_exponent_int + \tex_ifnum:D + \etex_numexpr:D + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + = \c_zero \group_end: \prg_return_true: \tex_else:D \group_end: \prg_return_false: \tex_fi:D + \tex_else:D + \tex_ifnum:D \l_fp_input_a_integer_int > \l_fp_input_b_integer_int + \group_end: + \prg_return_true: + \tex_else:D + \tex_ifnum:D + \l_fp_input_a_integer_int < \l_fp_input_b_integer_int + \group_end: + \prg_return_false: + \tex_else:D + \tex_ifnum:D + \l_fp_input_a_decimal_int > \l_fp_input_b_decimal_int + \group_end: + \prg_return_true: + \tex_else:D + \group_end: + \prg_return_false: + \tex_fi:D + \tex_fi:D + \tex_fi:D \tex_fi:D \tex_fi:D } \cs_new_protected_nopar:cpn { fp_compare_absolute_a < b: } { - \tex_ifnum:D \l_fp_input_b_integer_int > \l_fp_input_a_integer_int - \group_end: - \prg_return_true: - \tex_else:D - \tex_ifnum:D \l_fp_input_b_integer_int < \l_fp_input_a_integer_int + \tex_ifnum:D \l_fp_input_b_exponent_int > \l_fp_input_a_exponent_int + \tex_ifnum:D + \etex_numexpr:D + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + = \c_zero \group_end: \prg_return_false: \tex_else:D - \tex_ifnum:D \l_fp_input_b_decimal_int > \l_fp_input_a_decimal_int + \group_end: + \prg_return_true: + \tex_fi:D + \tex_else:D + \tex_ifnum:D \l_fp_input_b_exponent_int < \l_fp_input_a_exponent_int + \group_end: + \prg_return_false: + \tex_else:D + \tex_ifnum:D \l_fp_input_b_integer_int > \l_fp_input_a_integer_int \group_end: \prg_return_true: \tex_else:D - \group_end: - \prg_return_false: - \tex_fi:D - \tex_fi:D - \tex_fi:D -} -% \end{macrocode} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -% -%\subsection{Formatting fixed point numbers} -% -% When transferring fixed points to higher level code it is desirable -% to allow flexible formatting. -% -%\begin{macro}{\l_fp_round_precision_int} -%\begin{macro}{\l_fp_remove_zeros_bool} -%\begin{macro}{\l_fp_round_mode_tl} -% \begin{macrocode} -\keys_define:nn { fp } { - precision .int_set:N = \l_fp_round_precision_int , - remove-trailing-zeros .bool_set:N = \l_fp_remove_zeros_bool , - round-mode .choice: , - round-mode - / half-even .tl_set:N = \l_fp_round_mode_tl , - round-mode - / half-from-zero .tl_set:N = \l_fp_round_mode_tl , - round-mode - / none .tl_set:N = \l_fp_round_mode_tl , - round-mode - / truncate .tl_set:N = \l_fp_round_mode_tl , -} -\keys_set:nn { fp } { - precision = 9 , - remove-trailing-zeros = true , - round-mode = none , -} -% \end{macrocode} -%\end{macro} -%\end{macro} -%\end{macro} -% -%\begin{macro}{\fp_to_tl:NN} -%\begin{macro}{\fp_to_tl:Nc} -%\begin{macro}{\fp_to_tl:cN} -%\begin{macro}{\fp_to_tl:cc} -%\begin{macro}{\fp_gto_tl:NN} -%\begin{macro}{\fp_gto_tl:Nc} -%\begin{macro}{\fp_gto_tl:cN} -%\begin{macro}{\fp_gto_tl:cc} -%\begin{macro}[aux]{\fp_to_tl_aux:NNN} -%\begin{macro}[aux]{\fp_remove_zeros:NNNNNNNNN} -%\begin{macro}[aux]{\fp_remove_zeros_aux:w} -%\begin{macro}[aux]{\fp_round_half-from-zero:} -%\begin{macro}[aux]{\fp_round_from_zero:} -%\begin{macro}[aux]{\fp_round_from_zero_aux:NNNNNNNNN} -%\begin{macro}[aux]{\fp_round_from_zero_decimal:N} -%\begin{macro}[aux]{\fp_round_from_zero_integer:} -%\begin{macro}[aux]{\fp_round_half-even:} -%\begin{macro}[aux]{\fp_round_even:} -%\begin{macro}[aux]{\fp_round_even_aux:NNNNNNNNN} -%\begin{macro}[aux]{\fp_round_even_decimal:N} -%\begin{macro}[aux]{\fp_round_even_integer:} -%\begin{macro}[aux]{\fp_round_none:} -%\begin{macro}[aux]{\fp_round_truncate:} -% The usual lead off with a series of wrapper functions. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_to_tl:NN { - \fp_to_tl_aux:NNN \tl_set:Nn -} -\cs_new_protected_nopar:Npn \fp_gto_tl:NN { - \fp_to_tl_aux:NNN \tl_gset:Nn -} -\cs_generate_variant:Nn \fp_to_tl:NN { Nc } -\cs_generate_variant:Nn \fp_to_tl:NN { c } -\cs_generate_variant:Nn \fp_to_tl:NN { cc } -\cs_generate_variant:Nn \fp_gto_tl:NN { Nc } -\cs_generate_variant:Nn \fp_gto_tl:NN { c } -\cs_generate_variant:Nn \fp_gto_tl:NN { cc } -% \end{macrocode} -% The main body of the conversion follows the pattern of reading the -% \texttt{fp} then processing it. Rounding takes place first, so -% that zero stripping is easier. This may involve loosing the decimal -% part entirely. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_to_tl_aux:NNN #1#2#3 { - \group_begin: - \fp_read:N #2 - \use:c { fp_round_ \l_fp_round_mode_tl :} - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \tl_set:Nx \l_fp_tmp_tl - { - \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero - - - \tex_fi:D - \int_use:N \l_fp_input_a_integer_int - \intexpr_compare:nNnT { \l_fp_round_precision_int } > { \c_zero } - { - . - \bool_if:NTF \l_fp_remove_zeros_bool - { - \exp_after:wN \use_i:nn - \exp_after:wN \fp_remove_zeros:NNNNNNNNN - } - { \exp_after:wN \use_none:n } - \int_use:N \l_fp_input_a_decimal_int - } - } - \exp_after:wN \group_end: \exp_after:wN - #1 \exp_after:wN #3 \exp_after:wN { \l_fp_tmp_tl } -} -% \end{macrocode} -% For removing zeros, the code above ensures there will be exactly -% \( 9 \) tokens to deal with. The idea here is to go through them one -% at a time and see if the remained is equal to zero. The input can -% then be discarded if the precision in the output is correct. Speed -% is not quite so vital here so everything is coded in \LaTeX3 rather -% than primitives. This approach avoids needing to reverse the input. -% \begin{macrocode} -\cs_new_nopar:Npn \fp_remove_zeros:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { - \fp_remove_zeros_aux:w #1#2#3#4#5#6#7#8#9 \q_stop 1 -} -\cs_new_nopar:Npn \fp_remove_zeros_aux:w #1#2 \q_stop #3 { - #1 - \intexpr_compare:nNnTF { 0 #2 } = { \c_zero } - { - \intexpr_compare:nNnF { \l_fp_round_precision_int } < { #3 + 1 } - { - \intexpr_compare:nNnT {#3} < { 9 } - { \fp_remove_zeros_aux:w #2 \q_stop { #3 + 1 } } - } - } - { - \intexpr_compare:nNnT {#3} < { 9 } - { \fp_remove_zeros_aux:w #2 \q_stop { #3 + 1 } } - } -} -% \end{macrocode} -% Rounding away from zero is relatively easy, as it only depends on -% the digit immediately before the rounded position. The code here -% therefore does a fast reversal of the direct of the input, then -% checks the position before considering the size of the digit itself. -% The position here refers to the digit that will be rounded, which is -% therefore out by one from the digit being considered during the loop. -% \begin{macrocode} -\cs_new_protected_nopar:cpn { fp_round_half-from-zero: } { - \tex_ifnum:D \l_fp_round_precision_int < \c_nine - \exp_after:wN \fp_round_from_zero: - \tex_fi:D -} -\cs_new_protected_nopar:Npn \fp_round_from_zero: { - \bool_set_false:N \l_fp_round_carry_bool - \l_fp_round_position_int \c_eight - \tl_clear:N \l_fp_round_decimal_tl - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \exp_after:wN \use_i:nn \exp_after:wN - \fp_round_from_zero_aux:NNNNNNNNN - \int_use:N \l_fp_input_a_decimal_int -} -\cs_new_protected_nopar:Npn \fp_round_from_zero_aux:NNNNNNNNN - #1#2#3#4#5#6#7#8#9 { - \fp_round_from_zero_decimal:N #9#8#7#6#5#4#3#2#1 - \fp_round_from_zero_integer: -} -\cs_new_protected_nopar:Npn \fp_round_from_zero_decimal:N #1 { - \tex_ifnum:D \l_fp_round_position_int < \l_fp_round_precision_int - \bool_if:NTF \l_fp_round_carry_bool - { \l_fp_tmp_int \etex_numexpr:D #1 + \c_one \scan_stop: } - { \l_fp_tmp_int \etex_numexpr:D #1 \scan_stop: } - \tex_ifnum:D \l_fp_tmp_int = \c_ten - \l_fp_tmp_int \c_zero - \tex_else:D - \bool_set_false:N \l_fp_round_carry_bool - \tex_fi:D - \tl_set:Nx \l_fp_round_decimal_tl - { \int_use:N \l_fp_tmp_int \l_fp_round_decimal_tl } - \tex_else:D - \tl_set:Nx \l_fp_round_decimal_tl { 0 \l_fp_round_decimal_tl } - \tex_ifnum:D \l_fp_round_position_int = \l_fp_round_precision_int - \tex_ifnum:D #1 > \c_four - \bool_set_true:N \l_fp_round_carry_bool - \tex_fi:D - \tex_fi:D - \tex_fi:D - \tex_advance:D \l_fp_round_position_int \c_minus_one - \tex_ifnum:D \l_fp_round_position_int > \c_minus_one - \exp_after:wN \fp_round_from_zero_decimal:N - \tex_fi:D -} -\cs_new_protected_nopar:Npn \fp_round_from_zero_integer: { - \bool_if:NT \l_fp_round_carry_bool - { \tex_advance:D \l_fp_input_a_integer_int \c_one } - \l_fp_input_a_decimal_int \l_fp_round_decimal_tl \scan_stop: -} -% \end{macrocode} -% The general outline is similar when rounding where ties go to the -% nearest even number. However, life is more complicated as there is a -% need to track the discarded digits, and to see whether the digit to -% round is odd or even. This is done by tracking the discarded digits. -% When reaching the digit to check for rounding, the discards are used -% to indicate if there is an exact half to take into account. When the -% rounding takes place without an exact half, things are the same as -% for the `away from zero' approach. When rounding an exact -% half, there is an odd/even test before applying any modification. -% \begin{macrocode} -\cs_new_protected_nopar:cpn { fp_round_half-even: } { - \tex_ifnum:D \l_fp_round_precision_int < \c_nine - \exp_after:wN \fp_round_even: - \tex_fi:D -} -\cs_new_protected_nopar:Npn \fp_round_even: { - \bool_set_false:N \l_fp_round_carry_bool - \l_fp_round_position_int \c_eight - \tl_clear:N \l_fp_round_decimal_tl - \int_zero:N \l_fp_round_discard_int - \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million - \exp_after:wN \use_i:nn \exp_after:wN - \fp_round_even_aux:NNNNNNNNN - \int_use:N \l_fp_input_a_decimal_int -} -\cs_new_protected_nopar:Npn \fp_round_even_aux:NNNNNNNNN - #1#2#3#4#5#6#7#8#9 { - \fp_round_even_decimal:N #9#8#7#6#5#4#3#2#1 - \fp_round_even_integer: -} -\cs_new_protected_nopar:Npn \fp_round_even_decimal:N #1 { - \tex_ifnum:D \l_fp_round_position_int < \l_fp_round_precision_int - \bool_if:NTF \l_fp_round_carry_bool - { - \tex_ifnum:D \l_fp_round_discard_int = \c_zero - \l_fp_round_discard_int \c_one - \tex_ifodd:D #1 \scan_stop: - \l_fp_tmp_int \etex_numexpr:D #1 + \c_one \scan_stop: + \tex_ifnum:D + \l_fp_input_b_integer_int < \l_fp_input_a_integer_int + \group_end: + \prg_return_false: + \tex_else:D + \tex_ifnum:D + \l_fp_input_b_decimal_int > \l_fp_input_a_decimal_int + \group_end: + \prg_return_true: \tex_else:D - \l_fp_tmp_int \etex_numexpr:D #1 \scan_stop: + \group_end: + \prg_return_false: \tex_fi:D - \tex_else:D - \l_fp_tmp_int \etex_numexpr:D #1 + \c_one \scan_stop: - \tex_fi:D - } - { \l_fp_tmp_int \etex_numexpr:D #1 \scan_stop: } - \tex_ifnum:D \l_fp_tmp_int = \c_ten - \l_fp_tmp_int \c_zero - \tex_else:D - \bool_set_false:N \l_fp_round_carry_bool - \tex_fi:D - \tl_set:Nx \l_fp_round_decimal_tl - { \int_use:N \l_fp_tmp_int \l_fp_round_decimal_tl } - \tex_else:D - \tl_set:Nx \l_fp_round_decimal_tl { 0 \l_fp_round_decimal_tl } - \tex_ifnum:D \l_fp_round_position_int = \l_fp_round_precision_int - \tex_ifnum:D #1 > \c_four - \bool_set_true:N \l_fp_round_carry_bool - \tex_ifnum:D #1 = \c_five - \tex_else:D - \l_fp_round_discard_int \c_one \tex_fi:D \tex_fi:D - \tex_else:D - \tex_advance:D \l_fp_round_discard_int #1 \scan_stop: - \tex_fi:D - \tex_fi:D - \tex_advance:D \l_fp_round_position_int \c_minus_one - \tex_ifnum:D \l_fp_round_position_int > \c_minus_one - \exp_after:wN \fp_round_even_decimal:N + \tex_fi:D \tex_fi:D } -\cs_new_protected_nopar:Npn \fp_round_even_integer: { - \bool_if:NT \l_fp_round_carry_bool - { - \tex_ifnum:D \l_fp_round_discard_int = \c_zero - \tex_ifodd:D \l_fp_input_a_integer_int - \tex_advance:D \l_fp_input_a_integer_int \c_one - \tex_fi:D - \tex_else:D - \tex_advance:D \l_fp_input_a_integer_int \c_one - \tex_fi:D - } - \l_fp_input_a_decimal_int \l_fp_round_decimal_tl \scan_stop: -} -% \end{macrocode} -% The only task that is needed when not rounding is to ensure that -% the zero-stripping function will remove things reliably. This is -% done by setting the precision to one digit: no rounding will always -% leave at least one decimal digit, even if it is zero. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_round_none: { - \l_fp_round_precision_int \c_one -} -% \end{macrocode} -% Truncating input is done by using the \cs{tex_divide:D} primitive -% as this turns out to be the most convenient method to do this. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_round_truncate: { - \intexpr_compare:nNnF { \l_fp_round_precision_int } > { 8 } - { - \intexpr_compare:nNnTF { \l_fp_round_precision_int } < { 1 } - { \l_fp_input_a_decimal_int \c_zero \scan_stop: } - { - \int_set:Nn \l_fp_tmp_int - { - \prg_replicate:nn { 9 - \l_fp_round_precision_int } - { 10 * } - 1 - } - \tex_divide:D \l_fp_input_a_decimal_int \l_fp_tmp_int - \tex_multiply:D \l_fp_input_a_decimal_int \l_fp_tmp_int - } - } -} + % \end{macrocode} %\end{macro} %\end{macro} @@ -2345,43 +3979,39 @@ %\end{macro} %\end{macro} %\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} % %\subsection{Messages} % -%\begin{macro}{\fp_msg_overflow:} -% To avoid expansion issues above, the messages are all set up as -% functions. +%\begin{macro}{\fp_overflow_msg:} +% A generic overflow message, used whenever there is a possible +% overflow. % \begin{macrocode} -\cs_new_protected_nopar:Npn \fp_msg_overflow: { +\msg_kernel_new:nnnn { fpu } { overflow } + { Number~too~big. } + { + The~input~given~is~too~big~for~the~LaTeX~floating~point~unit. \\ + Further~errors~may~well~occur! + } +\cs_new_protected_nopar:Npn \fp_overflow_msg: { \msg_kernel_error:nn { fpu } { overflow } -} +} % \end{macrocode} %\end{macro} % +%\begin{macro}{\fp_trig_overflow_msg:} +% A slightly more helpful message for trigonometric overflows. % \begin{macrocode} -\msg_kernel_new:nnnn { fpu } { overflow } - { Arithmetic~overflow. } +\msg_kernel_new:nnnn { fpu } { trigonometric-overflow } + { Number~too~big~for~trigonometry~unit. } { - The~calculation~requested~exceeds~the~capacity \\ - of~the~fixed-point~unit. + The~trigonometry~code~can~only~work~with~numbers~smaller~ + than~1000000000. } +\cs_new_protected_nopar:Npn \fp_trig_overflow_msg: { + \msg_kernel_error:nn { fpu } { trigonometric-overflow } +} % \end{macrocode} -% +%\end{macro}% % \begin{macrocode} %</initex|package> % \end{macrocode} diff --git a/Master/texmf-dist/source/latex/expl3/l3prg.dtx b/Master/texmf-dist/source/latex/expl3/l3prg.dtx index 4ea121eb1f4..29dcded112d 100644 --- a/Master/texmf-dist/source/latex/expl3/l3prg.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3prg.dtx @@ -36,7 +36,7 @@ \RequirePackage{l3names} %</driver|package> %\fi -\GetIdInfo$Id: l3prg.dtx 1853 2010-03-21 09:11:08Z joseph $ +\GetIdInfo$Id: l3prg.dtx 1992 2010-08-04 20:41:40Z joseph $ {L3 Experimental control structures} %\iffalse %<*driver> @@ -619,6 +619,53 @@ % Returns the type of <variable> (\texttt{tl}, \texttt{int}, etc.) %\end{function} % +%\subsection{Mapping to variables} +% +%\begin{function}{ \prg_new_map_functions:Nn } +% \begin{syntax} +% \cs{prg_new_map_functions:Nn} \meta{token} \Arg{name} +% \end{syntax} +% Creates a family of mapping functions which can be applied to +% a token list, dividing the list up at each occurance of the +% \meta{token}. The functions defined will be +% \begin{itemize} +% \item \cs{\meta{name}_map_function:NN} +% \item \cs{\meta{name}_map_function:nN} +% \item \cs{\meta{name}_map_inline:Nn} +% \item \cs{\meta{name}_map_inline:nn} +% \item \cs{\meta{name}_map_break:} +% \end{itemize} +% Of these, the \texttt{inline} functions are not expandable but +% the other functions can be used in expansion contexts. The use of +% each function is best illustrated by the \cs{clist_map_\ldots} +% family defined by \LaTeX3 itself for mapping to comma-separated +% lists. An error will be raised if the \meta{name} has already been +% used to generate a family of mapping functions. All of the +% definitions are created globally. +%\end{function} +% +%\begin{function}{ \prg_set_map_functions:Nn } +% \begin{syntax} +% \cs{prg_set_map_functions:Nn} \meta{token} \Arg{name} +% \end{syntax} +% Creates a family of mapping functions which can be applied to +% a token list, dividing the list up at each occurance of the +% \meta{token}. The functions defined will be +% \begin{itemize} +% \item \cs{\meta{name}_map_function:NN} +% \item \cs{\meta{name}_map_function:nN} +% \item \cs{\meta{name}_map_inline:Nn} +% \item \cs{\meta{name}_map_inline:nn} +% \item \cs{\meta{name}_map_break:} +% \end{itemize} +% Of these, the \texttt{inline} functions are not expandable but +% the other functions can be used in expansion contexts. The use of +% each function is best illustrated by the \cs{clist_map_\ldots} +% family defined by \LaTeX3 itself for mapping to comma-separated +% lists. Any existing defintions for the \meta{name} will be +% overwritten. All of the definitions are created globally. +%\end{function} +% % \end{documentation} % % \begin{implementation} @@ -1774,6 +1821,104 @@ %\end{macro} %\end{macro} % +%\subsection{Mapping to variables} +% +%\begin{macro}{\prg_new_map_functions:Nn} +%\begin{macro}{\prg_set_map_functions:Nn} +% The idea here is to generate all of the various mapping functions +% in one go. Everything is done with expansion so that the performance +% hit is taken at definition time and not at point of use. The inline +% version uses a counter as this keeps things nestable, and global to +% avoid problems with, for example, table cells. +% \begin{macrocode} +\cs_new_protected:Npn \prg_new_map_functions:Nn #1#2 { + \cs_if_free:cTF { #2 _map_function:NN } + { \prg_set_map_functions:Nn #1 {#2} } + { + \msg_kernel_error:nnx { code } { csname-already-defined } + { \token_to_str:c { #2 _map_function:NN } } + } +} +\cs_new_protected:Npn \prg_set_map_functions:Nn #1#2 { + \cs_gset_nopar:cpx { #2 _map_function:NN } ##1##2 + { + \exp_not:N \tl_if_empty:NF ##1 + { + \exp_not:N \exp_after:wN + \exp_not:c { #2 _map_function_aux:Nw } + \exp_not:N \exp_after:wN ##2 ##1 + \exp_not:n { #1 \q_recursion_tail #1 \q_recursion_stop } + } + } + \cs_gset:cpx { #2 _map_function:nN } ##1##2 + { + \exp_not:N \tl_if_blank:nF {##1} + { + \exp_not:c { #2 _map_function_aux:Nw } ##2 ##1 + \exp_not:n { #1 \q_recursion_tail #1 \q_recursion_stop } + } + } + \cs_gset:cpx { #2 _map_function_aux:Nw } ##1##2 #1 + { + \exp_not:N \quark_if_recursion_tail_stop:n {##2} + ##1 {##2} + \exp_not:c { #2 _map_function_aux:Nw } ##1 + } + \cs_if_free:cT { g_ #2 _map_inline_int } + { \int_new:c { g_ #2 _map_inline_int } } + \cs_gset_protected_nopar:cpx { #2 _map_inline:Nn } ##1##2 + { + \exp_not:N \tl_if_empty:NF ##1 + { + \exp_not:N \int_gincr:N \exp_not:c { g_ #2 _map_inline_int } + \cs_gset:cpn + { + #2 _map_inline_ + \exp_not:N \int_use:N \exp_not:c { g_ #2 _map_inline_int } + :n + } + ####1 {##2} + \exp_not:N \exp_last_unbraced:NcV + \exp_not:c { #2 _map_function_aux:Nw } + { + #2 _map_inline_ + \exp_not:N \int_use:N \exp_not:c { g_ #2 _map_inline_int } + :n + } + ##1 \exp_not:n { #1 \q_recursion_tail #1 \q_recursion_stop } + \exp_not:N \int_gdecr:N \exp_not:c { g_ #2 _map_inline_int } + } + } + \cs_gset_protected:cpx { #2 _map_inline:nn } ##1##2 + { + \exp_not:N \tl_if_empty:nF {##1} + { + \exp_not:N \int_gincr:N \exp_not:c { g_ #2 _map_inline_int } + \cs_gset:cpn + { + #2 _map_inline_ + \exp_not:N \int_use:N \exp_not:c { g_ #2 _map_inline_int } + :n + } + ####1 {##2} + \exp_not:N \exp_args:Nc + \exp_not:c { #2 _map_function_aux:Nw } + { + #2 _map_inline_ + \exp_not:N \int_use:N \exp_not:c { g_ #2 _map_inline_int } + :n + } + ##1 \exp_not:n { #1 \q_recursion_tail #1 \q_recursion_stop } + \exp_not:N \int_gdecr:N \exp_not:c { g_ #2 _map_inline_int } + } + } + \cs_gset_eq:cN { #2 _map_break: } + \use_none_delimit_by_q_recursion_stop:w +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% % That's it (for now). % \begin{macrocode} %</initex|package> |