summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/expl3/l3fp.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/expl3/l3fp.dtx')
-rw-r--r--Master/texmf-dist/source/latex/expl3/l3fp.dtx3916
1 files changed, 2773 insertions, 1143 deletions
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}