summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3fp.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp.dtx6035
1 files changed, 705 insertions, 5330 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
index 64a6b39252f..68f71f540cc 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3fp.dtx Copyright (C) 2010-2012 The LaTeX3 Project
+%% File: l3fp.dtx Copyright (C) 2011-2012 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -29,27 +29,31 @@
%% Snapshots taken from the repository represent work in progress and may
%% not work or may contain conflicting material! We therefore ask
%% people _not_ to put them into distributions, archives, etc. without
-%% prior consultation with the LaTeX3 Project.
+%% prior consultation with the LaTeX3 Project Team.
%%
%% -----------------------------------------------------------------------
+%%
%
%<*driver|package>
\RequirePackage{l3names}
-\GetIdInfo$Id: l3fp.dtx 3490 2012-03-04 01:00:53Z bruno $
- {L3 Experimental floating-point operations}
+\GetIdInfo$Id: l3fp.dtx 3986 2012-07-15 19:23:51Z joseph $
+ {L3 Floating points}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
+\usepackage{amsmath}
+\providecommand\nan{\texttt{NaN}}
\begin{document}
\DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
+%
% \title{^^A
-% The \pkg{l3fp} package\\ Floating-point operations^^A
+% The \textsf{l3fp} package: floating points^^A
% \thanks{This file describes v\ExplFileVersion,
-% last revised \ExplFileDate.}^^A
+% last revised \ExplFileDate.}^^A
% }
%
% \author{^^A
@@ -67,5497 +71,868 @@
%
% \begin{documentation}
%
-% 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 \expandafter\mathopen\string|
-% x \expandafter\mathclose\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
-%\begin{verbatim}
-% \fp_set:Nn \l_my_fp { }
-% \fp_set:Nn \l_my_fp { . }
-% \fp_set:Nn \l_my_fp { - }
+% A floating point number is one which is stored as a mantissa and a
+% separate exponent. The module implements expandably a wide set of
+% arithmetic, trigonometric, and other operations on floating point
+% numbers, to be used within floating point expressions. Floating point
+% expressions support the following operations with their usual
+% precedence.
+% \begin{itemize}
+% \item Basic arithmetic: addition $x+y$, subtraction $x-y$,
+% multiplication $x*y$, division $x/y$, and parentheses.
+% \item Trigonometry: $\sin x$, $\cos x$, $\tan x$, $\cot x$.
+% \item Exponentials: $\exp x$, $\ln x$, $x^y$.
+% \item Comparison operators: $x<y$, $x<=y$, $x>?y$, $x!=y$ \emph{etc.}
+% \item Boolean logic: negation $!x$, conjunction $\&\&$, disjunction
+% $\vert\vert$, ternary operator $x?y:z$.
+% \item [\emph{not yet}] Inverse trigonometric functions:
+% $\operatorname{asin} x$, $\operatorname{acos} x$,
+% $\operatorname{atan} x$, $\operatorname{acot} x$.
+% \item [\emph{not yet}] Hyperbolic functions and their inverse
+% functions: $\sinh x$, $\cosh x$, $\tanh x$, $\coth x$, and
+% $\operatorname{asinh} x$, $\operatorname{acosh} x$,
+% $\operatorname{atanh} x$, $\operatorname{acoth} x$.
+% \item Extrema: $\max(x,y,\ldots)$, $\min(x,y,\ldots)$,
+% $\operatorname{abs}(x)$.
+% \item Rounding functions: $\operatorname{round}(x,n)$ round to
+% closest, $\operatorname{round} 0(x,n)$ round towards zero,
+% $\operatorname{round}\pm(x,n)$ round towards $\pm\infty$. And
+% (\emph{not yet}) modulo, and \enquote{quantize}.
+% \item Constants: \texttt{pi}, \texttt{deg} (one degree in radians).
+% \item Dimensions, automatically expressed in points, \emph{e.g.},
+% \texttt{pc} is $12$.
+% \item Automatic conversion (no need for \cs{\meta{type}_use:N}) of
+% integer, dimension, and skip variables to floating points,
+% expressing dimensions in points and ignoring the stretch and
+% shrink components of skips.
+% \end{itemize}
+% Floating point numbers can be given either explicitly (in a form such
+% as |1.234e-34|, or |-.0001|), or as a stored floating point variable,
+% which is automatically replaced by its current value. See
+% section~\ref{sec:fp-floats} for a description of what a floating point is,
+% section~\ref{sec:fp-precedence} for details about how an expression is
+% parsed, and section~\ref{sec:fp-operations} to know what the various
+% operations do. Some operations may raise exceptions (error messages),
+% described in section~\ref{sec:fp-exceptions}.
+%
+% An example of use could be the following.
+% \begin{verbatim}
+% \LaTeX{} can now compute: $ \frac{\sin (3.5)}{2} + 2\cdot 10^{-3}
+% = \ExplSyntaxOn \fp_to_decimal:n {sin 3.5 /2 + 2e-3} $.
+% \end{verbatim}
+% But in all fairness, this module is mostly meant as an underlying tool
+% for higher-level commands. For example, one could provide a function
+% to typeset nicely the result of floating point computations.
+% \begin{verbatim}
+% \usepackage{xparse, siunitx}
+% \ExplSyntaxOn
+% \NewDocumentCommand { \calcnum } { m }
+% { \num { \fp_to_scientific:n {#1} } }
+% \ExplSyntaxOff
+% \calcnum { 2 pi * sin ( 2.3 ^ 5 ) }
% \end{verbatim}
-% will all be interpreted as zero values without raising an error.
-%
-% Operations which give an undefined result (such as division by
-% $0$) will not lead to errors. Instead special marker values are
-% returned, which can be tested for using for 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$.
-%
-% Floating point numbers are stored in the \texttt{fp} floating point
-% variable type. This has a standard range of functions for
-% variable management.
-%
-% \section{Floating-point variables}
%
-% \begin{function}{\fp_new:N, \fp_new:c}
-% \begin{syntax}
-% \cs{fp_new:N} \meta{floating point variable}
-% \end{syntax}
-% Creates a new \meta{floating point variable} or raises an error if
-% the name is already taken. The declaration is global. The
-% \meta{floating point} will initially be set to |+0.000000000e0|
-% (the zero floating point).
-% \end{function}
+% \section{Creating and initialising floating point variables}
%
-% \begin{function}{\fp_const:Nn, \fp_const:cn}
+% \begin{function}[updated = 2012-05-08]{\fp_new:N, \fp_new:c}
% \begin{syntax}
-% \cs{fp_const:Nn} \meta{floating point variable} \Arg{value}
+% \cs{fp_new:N} \meta{fp~var}
% \end{syntax}
-% Creates a new constant \meta{floating point variable} or raises an
-% error if the name is already taken. The value of the
-% \meta{floating point variable} will be set globally to the
-% \meta{value}.
+% Creates a new \meta{fp~var} or raises an error if the name is
+% already taken. The declaration is global. The \meta{fp~var} will
+% initially be $+0$.
% \end{function}
%
-% \begin{function}
-% {
-% \fp_set_eq:NN, \fp_set_eq:cN, \fp_set_eq:Nc, \fp_set_eq:cc,
-% \fp_gset_eq:NN, \fp_gset_eq:cN, \fp_gset_eq:Nc, \fp_gset_eq:cc
-% }
+% \begin{function}[updated = 2012-05-08]{\fp_const:Nn, \fp_const:cn}
% \begin{syntax}
-% \cs{fp_set_eq:NN} \meta{fp var1} \meta{fp var2}
+% \cs{fp_const:Nn} \meta{fp~var} \Arg{floating point expression}
% \end{syntax}
-% Sets the value of \meta{floating point variable1} equal to that of
-% \meta{floating point variable2}.
+% Creates a new constant \meta{fp~var} or raises an error if the name
+% is already taken. The \meta{fp~var} will be set globally equal to
+% the result of evaluating the \meta{floating point expression}.
% \end{function}
%
-% \begin{function}{\fp_zero:N, \fp_zero:c, \fp_gzero:N, \fp_gzero:c}
+% \begin{function}[updated = 2012-05-08]
+% {\fp_zero:N, \fp_zero:c, \fp_gzero:N, \fp_gzero:c}
% \begin{syntax}
-% \cs{fp_zero:N} \meta{floating point variable}
+% \cs{fp_zero:N} \meta{fp~var}
% \end{syntax}
-% Sets the \meta{floating point variable} to |+0.000000000e0|.
+% Sets the \meta{fp~var} to~$+0$.
% \end{function}
%
-% \begin{function}[added = 2012-01-07]
+% \begin{function}[updated = 2012-05-08]
% {\fp_zero_new:N, \fp_zero_new:c, \fp_gzero_new:N, \fp_gzero_new:c}
% \begin{syntax}
-% \cs{fp_zero_new:N} \meta{floating point variable}
+% \cs{fp_zero_new:N} \meta{fp~var}
% \end{syntax}
-% Ensures that the \meta{floating point variable} exists globally
+% Ensures that the \meta{fp~var} exists globally
% by applying \cs{fp_new:N} if necessary, then applies
-% \cs{fp_(g)zero:N} to leave the \meta{floating point variable}
-% set to zero.
+% \cs{fp_(g)zero:N} to leave the \meta{fp~var} set to zero.
% \end{function}
%
-% \begin{function}{\fp_set:Nn, \fp_set:cn, \fp_gset:Nn, \fp_gset:cn}
+% \section{Setting floating point variables}
+%
+% \begin{function}[updated = 2012-05-08]
+% {\fp_set:Nn, \fp_set:cn, \fp_gset:Nn, \fp_gset:cn}
% \begin{syntax}
-% \cs{fp_set:Nn} \meta{floating point variable} \Arg{value}
+% \cs{fp_set:Nn} \meta{fp~var} \Arg{floating point expression}
% \end{syntax}
-% Sets the \meta{floating point variable} variable to \meta{value}.
+% Sets \meta{fp~var} equal to the result of computing the
+% \meta{floating point expression}.
% \end{function}
%
-% \begin{function}
+% \begin{function}[updated = 2012-05-08]
% {
-% \fp_set_from_dim:Nn, \fp_set_from_dim:cn,
-% \fp_gset_from_dim:Nn, \fp_gset_from_dim:cn
+% \fp_set_eq:NN , \fp_set_eq:cN , \fp_set_eq:Nc , \fp_set_eq:cc ,
+% \fp_gset_eq:NN, \fp_gset_eq:cN, \fp_gset_eq:Nc, \fp_gset_eq:cc
% }
% \begin{syntax}
-% \cs{fp_set_from_dim:Nn} \meta{floating point variable} \Arg{dimexpr}
+% \cs{fp_set_eq:NN} \meta{fp~var_1} \meta{fp~var_2}
% \end{syntax}
-% 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{floating point variable}.
+% Sets the floating point variable \meta{fp~var_1} equal to the current
+% value of \meta{fp~var_2}.
% \end{function}
%
-% \begin{function}[rEXP]{\fp_use:N, \fp_use:c}
+% \begin{function}[updated = 2012-05-08]
+% {\fp_add:Nn, \fp_add:cn, \fp_gadd:Nn, \fp_gadd:cn}
% \begin{syntax}
-% \cs{fp_use:N} \meta{floating point variable}
+% \cs{fp_add:Nn} \meta{fp~var} \Arg{floating point expression}
% \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 |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.
+% Adds the result of computing the \meta{floating point expression} to
+% the \meta{fp~var}.
% \end{function}
%
-% \begin{function}{\fp_show:N, \fp_show:c}
+% \begin{function}[updated = 2012-05-08]
+% {\fp_sub:Nn, \fp_sub:cn, \fp_gsub:Nn, \fp_gsub:cn}
% \begin{syntax}
-% \cs{fp_show:N} \meta{floating point variable}
+% \cs{fp_sub:Nn} \meta{fp~var} \Arg{floating point expression}
% \end{syntax}
-% Displays the content of the \meta{floating point variable} on the
-% terminal.
+% Subtracts the result of computing the \meta{floating point
+% expression} from the \meta{fp~var}.
% \end{function}
%
-% \begin{function}[EXP, pTF, added=2012-03-03]{\fp_if_exist:N, \fp_if_exist:c}
+% \section{Using floating point numbers}
+%
+% \begin{function}[EXP, added = 2012-05-08, updated = 2012-07-08]{\fp_eval:n}
% \begin{syntax}
-% \cs{fp_if_exist_p:N} \meta{fp~var}
-% \cs{fp_if_exist:NTF} \meta{fp~var} \Arg{true code} \Arg{false code}
+% \cs{fp_eval:n} \Arg{floating point expression}
% \end{syntax}
-% Tests whether the \meta{fp~var} is currently defined. This does not
-% check that the \meta{fp~var} really is a floating point variable.
+% Evaluates the \meta{floating point expression} and expresses the
+% result as a decimal number with~$16$ significant figures and no
+% exponent. Leading or trailing zeros may be inserted to compensate
+% for the exponent. Non-significant trailing zeros are trimmed, and
+% integers are expressed without a decimal separator. The values
+% $\pm\infty$ and \texttt{nan} trigger an \enquote{invalid operation}
+% exception. This function is identical to \cs{fp_to_decimal:n}.
% \end{function}
%
-% \section{Conversion of floating point values to other formats}
-%
-% 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}[rEXP]{\fp_to_dim:N, \fp_to_dim:c}
+% \begin{function}[EXP, added = 2012-05-08, updated = 2012-07-08]
+% {\fp_to_decimal:N, \fp_to_decimal:c, \fp_to_decimal:n}
% \begin{syntax}
-% \cs{fp_to_dim:N} \meta{floating point variable}
+% \cs{fp_to_decimal:N} \meta{fp~var}
+% \cs{fp_to_decimal:n} \Arg{floating point expression}
% \end{syntax}
-% Inserts the value of the \meta{floating point variable}
-% into the input stream converted into a dimension in points.
+% Evaluates the \meta{floating point expression} and expresses the
+% result as a decimal number with $16$ significant figures and no
+% exponent. Leading or trailing zeros may be inserted to compensate
+% for the exponent. Non-significant trailing zeros are trimmed, and
+% integers are expressed without a decimal separator. The values
+% $\pm\infty$ and \texttt{nan} trigger an \enquote{invalid operation}
+% exception.
% \end{function}
%
-% \begin{function}[rEXP]{\fp_to_int:N, \fp_to_int:c}
+% \begin{function}[EXP, updated = 2012-07-08]
+% {\fp_to_dim:N, \fp_to_dim:c, \fp_to_dim:n}
% \begin{syntax}
-% \cs{fp_to_int:N} \meta{floating point variable}
+% \cs{fp_to_dim:N} \meta{fp~var}
+% \cs{fp_to_dim:n} \Arg{floating point expression}
% \end{syntax}
-% 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.
+% Evaluates the \meta{floating point expression} and expresses the
+% result as a dimension (in \texttt{pt}) suitable for use in dimension
+% expressions. The output is identical to \cs{fp_to_decimal:n}, with
+% an additional trailing \texttt{pt}. In particular, floating point
+% numbers outside the range $[- 2^{14} + 2^{-17}, 2^{14} - 2^{-17}]$
+% overflow \TeX{}'s maximum dimension. The values $\pm\infty$ and
+% \texttt{nan} trigger an \enquote{invalid operation} exception.
% \end{function}
%
-% \begin{function}[rEXP]{\fp_to_tl:N, \fp_to_tl:c}
+% \begin{function}[EXP, updated = 2012-07-08]
+% {\fp_to_int:N, \fp_to_int:c, \fp_to_int:n}
% \begin{syntax}
-% \cs{fp_to_tl:N} \meta{floating point variable}
+% \cs{fp_to_int:N} \meta{fp~var}
+% \cs{fp_to_int:n} \Arg{floating point expression}
% \end{syntax}
-% 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.
+% Evaluates the \meta{floating point expression}, and rounds the
+% result to the closest integer, with ties rounded to an even integer.
+% The result may be outside the range $[- 2^{31} + 1, 2^{31} - 1]$ of
+% valid \TeX{} integers, triggering \TeX{} errors if used in an
+% integer expression. The values $\pm\infty$ and \texttt{nan} trigger
+% an \enquote{invalid operation} exception.
% \end{function}
%
-% \section{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}[EXP, added = 2012-05-08, updated = 2012-07-08]
+% {\fp_to_scientific:N, \fp_to_scientific:c, \fp_to_scientific:n}
+% \begin{syntax}
+% \cs{fp_to_scientific:N} \meta{fp~var}
+% \cs{fp_to_scientific:n} \Arg{floating point expression}
+% \end{syntax}
+% Evaluates the \meta{floating point expression} and expresses the
+% result in scientific notation with $16$ significant figures:
+% \begin{quote}
+% \meta{optional \texttt{-}}\meta{digit}\texttt{.}\meta{15 digits}\texttt{e}\meta{optional sign}\meta{exponent}
+% \end{quote}
+% The leading \meta{digit} is non-zero except in the case of $\pm 0$.
+% The values $\pm\infty$ and \texttt{nan} trigger an \enquote{invalid
+% operation} exception.
+% \end{function}
%
-% \begin{function}
-% {
-% \fp_round_figures:Nn, \fp_round_figures:cn,
-% \fp_ground_figures:Nn, \fp_ground_figures:cn
-% }
+% \begin{function}[EXP, updated = 2012-07-08]
+% {\fp_to_tl:N, \fp_to_tl:c, \fp_to_tl:n}
% \begin{syntax}
-% \cs{fp_round_figures:Nn} \meta{floating point variable} \Arg{target}
+% \cs{fp_to_tl:N} \meta{fp~var}
+% \cs{fp_to_tl:n} \Arg{floating point expression}
% \end{syntax}
-% Rounds the \meta{floating point variable} to the \meta{target} number
-% of significant figures (an integer expression).
+% Evaluates the \meta{floating point expression} and expresses the
+% result in (almost) the shortest possible form. Numbers greater or
+% equal to $10^{16}$, or less than $10^{-3}$ are expressed in
+% scientific notation with trailing zeros trimmed (see
+% \cs{fp_to_scientific:n}). Numbers in the range $[10^{-3},10^{16})$
+% are expressed in a decimal notation without exponent, with trailing
+% zeros trimmed, and no decimal separator for integer values (see
+% \cs{fp_to_decimal:n}. The special values $\pm 0$, $\pm \inf$ and
+% \texttt{nan} are rendered as |0|, |-0|, \texttt{inf}, \texttt{-inf},
+% and \texttt{nan} respectively.
% \end{function}
%
-% \begin{function}
-% {
-% \fp_round_places:Nn, \fp_round_places:cn,
-% \fp_ground_places:Nn, \fp_ground_places:cn
-% }
+% \begin{function}[EXP, updated = 2012-07-08]{\fp_use:N, \fp_use:c}
% \begin{syntax}
-% \cs{fp_round_places:Nn} \meta{floating point variable} \Arg{target}
+% \cs{fp_use:N} \meta{fp~var}
% \end{syntax}
-% Rounds the \meta{floating point variable} to the \meta{target} number
-% of decimal places (an integer expression).
+% Inserts the value of the \meta{fp~var} into the input stream as a
+% decimal number with $16$ significant figures and no exponent.
+% Leading or trailing zeros may be inserted to compensate for the
+% exponent. Non-significant trailing zeros are trimmed. Integers are
+% expressed without a decimal separator. The values $\pm\infty$ and
+% \texttt{nan} trigger an \enquote{invalid operation} exception. This
+% function is identical to \cs{fp_to_decimal:N}.
% \end{function}
%
-% \section{Floating-point conditionals}
+% \section{Floating point conditionals}
%
-% \begin{function}[EXP,pTF]{\fp_if_undefined:N}
+% \begin{function}[EXP, pTF, updated = 2012-05-08]
+% {\fp_if_exist:N, \fp_if_exist:c}
% \begin{syntax}
-% \cs{fp_if_undefined_p:N} \meta{fixed-point} \\
-% \cs{fp_if_undefined:NTF} \meta{fixed-point} \Arg{true code} \Arg{false code}
+% \cs{fp_if_exist_p:N} \meta{fp~var}
+% \cs{fp_if_exist:NTF} \meta{fp~var} \Arg{true code} \Arg{false code}
% \end{syntax}
-% Tests if \meta{floating point} is undefined (\emph{i.e.}~equal to the
-% special \cs{c_undefined_fp} variable).
+% Tests whether the \meta{fp~var} is currently defined. This does not
+% check that the \meta{fp~var} really is a floating point variable.
% \end{function}
%
-% \begin{function}[EXP,pTF]{\fp_if_zero:N}
+% \begin{function}[EXP, pTF, updated = 2012-05-08]
+% {\fp_compare:nNn, \fp_compare:n}
% \begin{syntax}
-% \cs{fp_if_zero_p:N} \meta{fixed-point}
-% \cs{fp_if_zero:NTF} \meta{fixed-point} \Arg{true code} \Arg{false code}
+% \cs{fp_compare_p:nNn} \Arg{fpexpr_1} \meta{relation} \Arg{fpexpr_2}
+% \cs{fp_compare:nNnTF} \Arg{fpexpr_1} \meta{relation} \Arg{fpexpr_2} \Arg{true code} \Arg{false code}
+% \cs{fp_compare_p:n} \{ \meta{fpexpr_1} \meta{relation} \meta{fpexpr_2} \}
+% \cs{fp_compare:nTF} \{ \meta{fpexpr_1} \meta{relation} \meta{fpexpr_2} \} \Arg{true code} \Arg{false code}
% \end{syntax}
-% Tests if \meta{floating point} is equal to zero (\emph{i.e.}~equal to
-% the special \cs{c_zero_fp} variable).
+% Compares the \meta{fpexpr_1} and the \meta{fpexpr_2}, and returns
+% \texttt{true} if the \meta{relation} is obeyed. Two floating point
+% numbers $x$ and $y$ may obey four mutually exclusive relations:
+% $x<y$, $x=y$, $x>y$, or $x$ and $y$ are not ordered. The latter
+% case occurs exactly when one of the operands is \texttt{nan}, and
+% this relations is denoted by the symbol |?|. The \texttt{nNn}
+% functions support the \meta{relations} |<|, |=|, |>|, and |?|. The
+% \texttt{n} functions support as a \meta{relation} any combination of
+% those four symbols, plus an optional leading |!| (which negates the
+% \meta{relation}), with the restriction that the \meta{relation} may
+% not start with |?|. Common choices of \meta{relation} include |>=|
+% (greater or equal), |!=| (not equal), |!?| (comparable). Note that
+% a \texttt{nan} is distinct from any value, even another
+% \texttt{nan}, hence $x=x$ is not true for a \texttt{nan}. Thus to
+% test if a value is \texttt{nan}, use
+% \begin{verbatim}
+% \fp_compare:nNnTF { <value> } != { <value> }
+% { } % <value> is nan
+% { } % <value> is not nan
+% \end{verbatim}
% \end{function}
%
-% \begin{function}[TF]{\fp_compare:nNn}
+% \section{Some useful constants, and scratch variables}
+%
+% \begin{variable}[added = 2012-05-08]{\c_zero_fp, \c_minus_zero_fp}
+% Zero, with either sign.
+% \end{variable}
+%
+% \begin{variable}[added = 2012-05-08]{\c_inf_fp, \c_minus_inf_fp}
+% Infinity, with either sign. These can be input directly in a
+% floating point expression as \texttt{inf} and \texttt{-inf}.
+% \end{variable}
+%
+% \begin{variable}[updated = 2012-05-08]{\c_e_fp}
+% The value of the base of the natural logarithm, $\mathrm{e} = \exp(1)$.
+% \end{variable}
+%
+% \begin{variable}[updated = 2012-05-08]{\c_pi_fp}
+% The value of $\pi$. This can be input directly in a floating point
+% expression as \texttt{pi}. The value is rounded in a slightly odd
+% way, to ensure for instance that \texttt{sin(pi)} yields an exact $0$.
+% \end{variable}
+%
+% \begin{variable}[added = 2012-05-08]{\c_one_degree_fp}
+% The value of $1^{\circ}$ in radians. Multiply an angle given in
+% degrees by this value to obtain a result in radians, suitable to be
+% used for trigonometric functions. Within floating point
+% expressions, this can be accessed by \texttt{deg}.
+% \end{variable}
+%
+% \begin{variable}{\l_tmpa_fp, \l_tmpb_fp}
+% Scratch floating points for local assignment. These are never used by
+% the kernel code, and so are safe for use with any \LaTeX3-defined
+% function. However, they may be overwritten by other non-kernel
+% code and so should only be used for short-term storage.
+% \end{variable}
+%
+% \begin{variable}{\g_tmpa_fp, \g_tmpb_fp}
+% Scratch floating points for global assignment. These are never used by
+% the kernel code, and so are safe for use with any \LaTeX3-defined
+% function. However, they may be overwritten by other non-kernel
+% code and so should only be used for short-term storage.
+% \end{variable}
+%
+% \section{Floating point exceptions}
+% \label{sec:fp-exceptions}
+%^^A todo: redoc
+%
+% \enquote{Exceptions} may occur when performing some floating point
+% operations, such as \texttt{0 / 0}, or \texttt{10 ** 1e9999}. The
+% \textsc{IEEE} standard defines $5$ types of exceptions.
+% \begin{itemize}
+% \item \emph{Overflow} occurs whenever the result of an operation is
+% too large to be represented as a normal floating point number. This
+% results in $\pm \infty$.
+% \item \emph{Underflow} occurs whenever the result of an operation is
+% too close to $0$ to be represented as a normal floating point
+% number. This results in $\pm 0$.
+% \item \emph{Invalid operation} occurs for operations with no defined
+% outcome, for instance $0/0$, or $\sin(\infty)$, and almost any
+% operation involving a \nan{}. This results in a \nan{}.
+% \item \emph{Division by zero} occurs when dividing a non-zero number
+% by $0$, or when evaluating \emph{e.g.}, $\ln(0)$ or $\cot(0)$. This
+% results in $\pm\infty$.
+% \item \emph{Inexact} occurs whenever the result of a computation is
+% not exact, in other words, almost always. This exception is
+% entirely ignored in \LaTeX3.
+% \end{itemize}
+% To each exception is associated a \enquote{flag}, which can be either
+% \emph{on} or \emph{off}. By default, when an exception occurs, the
+% corresponding flag is turned on. The state of the flag can be tested
+% and modified. The behaviour when an exception occurs can be modified
+% (using \cs{fp_trap:nn}) to either produce an error and turn the flag
+% on, or only turn the flag on, or do nothing at all.
+%
+% \begin{function}[EXP, pTF, added = 2012-05-28]{\fp_if_flag_on:n}
% \begin{syntax}
-% \cs{fp_compare:nNnTF}
-% ~~\Arg{floating point1} \meta{relation} \Arg{floating point2}
-% ~~\Arg{true code} \Arg{false code}
+% \cs{fp_if_flag_on_p:n} \Arg{exception}
+% \cs{fp_if_flag_on:nTF} \Arg{exception} \Arg{true code} \Arg{false code}
% \end{syntax}
-% This function compared the two \meta{floating point} values, which
-% may be stored as \texttt{fp} variables, using the \meta{relation}:
-% \begin{center}
-% \begin{tabular}{ll}
-% Equal & |=| \\
-% Greater than & |>| \\
-% Less than & |<| \\
-% \end{tabular}
-% \end{center}
-% The tests treat undefined floating points as
-% zero as the comparison is intended for real numbers only.
+% Tests if the flag for the \meta{exception} is on, which normally
+% means the given \meta{exception} has occurred.
% \end{function}
%
-% \begin{function}[TF]{\fp_compare:n}
+% \begin{function}[added = 2012-05-28]{\fp_flag_off:n}
% \begin{syntax}
-% \cs{fp_compare:nTF}
-% ~~\{ \meta{floating point1} \meta{relation} \meta{floating point2} \}
-% ~~\Arg{true code} \Arg{false code}
+% \cs{fp_flag_off:n} \Arg{exception}
% \end{syntax}
-% This function compared the two \meta{floating point} values, which
-% may be stored as \texttt{fp} variables, using the \meta{relation}:
-% \begin{center}
-% \begin{tabular}{ll}
-% Equal & |=| or |==| \\
-% Greater than & |>| \\
-% Greater than or equal & |>=| \\
-% Less than & |<| \\
-% Less than or equal & |<=| \\
-% Not equal & |!=| \\
-% \end{tabular}
-% \end{center}
-% The tests treat undefined floating points as
-% zero as the comparison is intended for real numbers only.
+% Locally turns off the flag which indicates whether the
+% \meta{exception} has occurred.
% \end{function}
%
-% \section{Unary floating-point operations}
-%
-% The unary operations alter the value stored within an \texttt{fp}
-% variable.
+% \begin{function}[EXP, added = 2012-05-28]{\fp_flag_on:n}
+% \begin{syntax}
+% \cs{fp_flag_on:n} \Arg{exception}
+% \end{syntax}
+% Locally turns on the flag to indicate (or pretend) that the
+% \meta{exception} has occurred. Note that this function is
+% expandable: it is used internally by \pkg{l3fp} to signal when
+% exceptions do occur.
+% \end{function}
%
-% \begin{function}{\fp_abs:N, \fp_abs:c, \fp_gabs:N, \fp_gabs:c}
+% \begin{function}[added = 2012-05-28]{\fp_trap:nn}
% \begin{syntax}
-% \cs{fp_abs:N} \meta{floating point variable}
+% \cs{fp_trap:nn} \Arg{exception} \Arg{trap type}
% \end{syntax}
-% Converts the \meta{floating point variable} to its absolute value.
+% All occurrences of the \meta{exception} (\texttt{invalid_operation},
+% \texttt{division_by_zero}, \texttt{overflow}, or \texttt{underflow})
+% within the current group are treated as \meta{trap type}, which can
+% be
+% \begin{itemize}
+% \item \texttt{none}: the \meta{exception} will be entirely
+% ignored, and leave no trace;
+% \item \texttt{flag}: the \meta{exception} will turn the
+% corresponding flag on when it occurs;
+% \item \texttt{error}: additionally, the \meta{exception} will halt
+% the \TeX{} run and display some information about the current
+% operation in the terminal.
+% \end{itemize}
% \end{function}
%
-% \begin{function}{\fp_neg:N, \fp_neg:c, \fp_gneg:N, \fp_gneg:c}
+% \section{Floating point expressions}
+%
+% \begin{function}[added = 2012-05-08, updated = 2012-05-27]
+% {\fp_show:N, \fp_show:c, \fp_show:n}
% \begin{syntax}
-% \cs{fp_neg:N} \meta{floating point variable}
+% \cs{fp_show:N} \meta{fp~var}
+% \cs{fp_show:n} \Arg{floating point expression}
% \end{syntax}
-% Reverse the sign of the \meta{floating point variable}.
+% Evaluates the \meta{floating point expression} and displays the
+% result in the terminal.
% \end{function}
%
-% \section{Floating-point arithmetic}
+% \subsection{Input of floating point numbers} \label{sec:fp-floats}
%
-% Binary arithmetic operations act on the value stored in an
-% \texttt{fp}, so for example
-% \begin{verbatim}
-% \fp_set:Nn \l_my_fp { 1.234 }
-% \fp_sub:Nn \l_my_fp { 5.678 }
-% \end{verbatim}
-% sets \cs{l_my_fp} to the result of $1.234 - 5.678$
-% (\emph{i.e.}~$-4.444$).
+%^^A todo: write a grammar
+%^^A todo: clarify what has changed compared to the previous l3fp
+%
+% We support four types of floating point numbers:
+% \begin{itemize}
+% \item $\pm 0.d_1d_2\ldots{}d_{16} \cdot 10^{n}$, a normal floating
+% point number, with $d_i\in [0,9]$, $d_1\neq 0$, and $\lvert n\rvert
+% \leq \ExplSyntaxOn \int_use:N \c__fp_max_exponent_int$;
+% \item $\pm 0$, zero, with a given sign;
+% \item $\pm \infty$, infinity, with a given sign;
+% \item \texttt{nan}, is \enquote{not a number}, and can be either quiet
+% or signalling (\emph{not yet}: this distinction is currently
+% unsupported);
+% \item [\emph{not yet}] subnormal numbers $\pm 0.d_1d_2\ldots{}d_{16}
+% \cdot 10^{-\ExplSyntaxOn\int_use:N \c__fp_max_exponent_int}$ with
+% $d_1=0$.
+% \end{itemize}
+% Normal floating point numbers are stored in base $10$, with $16$
+% significant figures.
+%
+% On input, a normal floating point number consists of:
+% \begin{itemize}
+% \item \meta{sign}: a possibly empty string of |+| and |-| characters;
+% \item \meta{mantissa}: a non-empty string of digits together with zero
+% or one dot;
+% \item \meta{exponent} optionally: the character |e|, followed by a
+% possibly empty string of |+|~and~|-| tokens, and a non-empty string
+% of digits.
+% \end{itemize}
+% The sign of the resulting number is |+| if \meta{sign} contains an
+% even number of |-|, and |-| otherwise, hence, an empty \meta{sign}
+% denotes a non-negative input. The stored mantissa is obtained from
+% \meta{mantissa} by omitting the decimal separator and leading zeros,
+% and rounding to $16$ significant digits, filling with trailing zeros
+% if necessary. In particular, the value stored is exact if the input
+% \meta{mantissa} has at most $16$ digits. The stored \meta{exponent}
+% is obtained by combining the input \meta{exponent} ($0$ if absent)
+% with a shift depending on the position of the mantissa and the number
+% of leading zeros.
+%
+% A special case arises if the resulting \meta{exponent} is either
+% too large or too small to be represented. This results either in an
+% overflow (the number is then replaced by $\pm\infty$), or an
+% underflow (resulting in $\pm 0$).
+%
+% The result is thus $\pm 0$ if and only if \meta{mantissa} contains no
+% non-zero digit (\emph{i.e.}, consists only in~|0| characters, and an
+% optional |.| character), or there is an underflow. Note that a single
+% dot is currently a valid floating point number, equal to~$+0$, but
+% that is not guaranteed to remain the case.
+%
+% Special numbers are input as follows:
+% \begin{itemize}
+% \item \texttt{inf} represents $+\infty$, and can be preceded by any
+% \meta{sign}.
+% \item \texttt{nan} represents a (quiet) non-number. It can be preceded
+% by any sign, but that will be ignored.
+% \item Any unrecognisable string will yield a signalling \texttt{nan}.
+% \end{itemize}
+%
+% Note that~|e-1| is not a representation of $10^{-1}$, because it
+% could be mistaken with the difference of \enquote{\texttt{e}} and
+% $1$. This is consistent with several other programming languages.
+% However, in order to avoid confusions, |e-1| is not considered to
+% be this difference either. To input the base of natural logarithms,
+% use \texttt{exp(1)} or \cs{c_e_fp}.
+%
+% \subsection{Precedence of operators}
+% \label{sec:fp-precedence}
+%
+% ^^A List "juxtaposition" somewhere in the list.
%
-% \begin{function}{\fp_add:Nn, \fp_add:cn, \fp_gadd:Nn, \fp_gadd:cn}
+% We list here all the operations supported in floating point
+% expressions, in order of decreasing precedence: operations listed
+% earlier bind more tightly than operations listed below them.
+% \begin{itemize}
+% \item Implicit multiplication by juxtaposition (\texttt{2pi}, \emph{etc}).
+% \item Function calls (\texttt{sin}, \texttt{ln}, \emph{etc}).
+% \item Binary |**| and |^| (right associative).
+% \item Unary |+|, |-|, |!|.
+% \item Binary |*|, |/| and |%|.
+% \item Binary |+| and |-|.
+% \item Comparisons |>=|, |!=|, |<?|, \emph{etc}.
+% \item Logical \texttt{and}, denoted by |&&|.
+% \item Logical \texttt{or}, denoted by \verb*+||+.
+% \item Ternary operator |?:| (right associative).
+% \end{itemize}
+% The precedence of operations can be overridden using parentheses.
+% In particular, those precedences imply that
+% \begin{align*}
+% \mathtt{sin 2pi} & = \sin(2\pi) = 0, \\
+% \mathtt{2\char`\^2max(3,4)} & = 2^{2 \max(3,4)} = 256.
+% \end{align*}
+% Functions are called on the value of their argument, contrarily to
+% \TeX{} macros.
+%
+% \subsection{Operations} \label{sec:fp-operations}
+%
+% We now present the various operations allowed in floating point
+% expressions. When used as a truth value, a floating point expression
+% is \texttt{false} if it is $\pm 0$, and \texttt{false} otherwise.
+%
+% The exceptions listed below are mostly not implemented yet. ^^A todo:
+%
+% \begin{function}{?:}
% \begin{syntax}
-% \cs{fp_add:Nn} \meta{floating point} \Arg{value}
+% \cs{fp_eval:n} \{ \meta{operand_1} |?| \meta{operand_2} |:| \meta{operand_3} \}
% \end{syntax}
-% Adds the \meta{value} to the \meta{floating point}.
+% The ternary operator |?:| results in \meta{operand_2} if
+% \meta{operand_1} is true, and \meta{operand_3} if it is false (equal to
+% $\pm 0$). All three \meta{operands} are evaluated in all cases. The
+% operator is right associative, hence
+% \begin{verbatim}
+% \fp_eval:n
+% {
+% 1 + 3 > 4 ? 1 :
+% 2 + 4 > 5 ? 2 :
+% 3 + 5 > 6 ? 3 : 4
+% }
+% \end{verbatim}
+% first tests whether $1 + 3 > 4$; since this isn't true, the branch
+% following |:| is taken, and $2 + 4 > 5$ is compared; since this is
+% true, the branch before |:| is taken, and everything else is
+% (evaluated then) ignored. That allows testing for various cases in
+% a concise manner, with the drawback that all computations are made
+% in all cases.
% \end{function}
%
-% \begin{function}{\fp_sub:Nn, \fp_sub:cn, \fp_gsub:Nn, \fp_gsub:cn}
+% \begingroup \catcode`\|=12
+% \begin{function}{TWO BARS} ^^A To fix
% \begin{syntax}
-% \cs{fp_sub:Nn} \meta{floating point} \Arg{value}
+% \cs{fp_eval:n} \{ \meta{operand_1} \texttt{||} \meta{operand_2} \}
% \end{syntax}
-% Subtracts the \meta{value} from the \meta{floating point}.
+% If \meta{operand_1} is true (non-zero), use that value, otherwise the
+% value of \meta{operand_2}. Both \meta{operands} are evaluated in all
+% cases.
% \end{function}
+% \endgroup
%
-% \begin{function}{\fp_mul:Nn, \fp_mul:cn, \fp_gmul:Nn, \fp_gmul:cn}
+% \begingroup \catcode`\&=12
+% \begin{function}{&&}
% \begin{syntax}
-% \cs{fp_mul:Nn} \meta{floating point} \Arg{value}
+% \cs{fp_eval:n} \{ \meta{operand_1} \texttt{&&} \meta{operand_2} \}
% \end{syntax}
-% Multiples the \meta{floating point} by the \meta{value}.
+% If \meta{operand_1} is false (equal to $\pm 0$), use that value,
+% otherwise the value of \meta{operand_2}. Both \meta{operands} are
+% evaluated in all cases.
% \end{function}
+% \endgroup
%
-% \begin{function}{\fp_div:Nn, \fp_div:cn, \fp_gdiv:Nn, \fp_gdiv:cn}
+% \begin{function}{\<, =, >, ?}
% \begin{syntax}
-% \cs{fp_div:Nn} \meta{floating point} \Arg{value}
+% \cs{fp_eval:n} \{ \meta{operand_1} \meta{comparison} \meta{operand_2} \}
% \end{syntax}
-% 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{floating point} will be set to
-% \cs{c_undefined_fp}.
+% The \meta{comparison} consists of a non-empty string of |<|, |=|,
+% |>|, and |?|, optionally preceeded by |!|. It may not start with
+% |?|. This evaluates to $+1$ if the \meta{comparison} between the
+% \meta{operand_1} and \meta{operand_2} is true, and $+0$ otherwise.
% \end{function}
%
-% \section{Floating-point power operations}
-%
-% \begin{function}{\fp_pow:Nn, \fp_pow:cn, \fp_gpow:Nn, \fp_gpow:cn}
+% \begin{function}{+, -}
% \begin{syntax}
-% \cs{fp_pow:Nn} \meta{floating point} \Arg{value}
+% \cs{fp_eval:n} \{ \meta{operand_1} |+| \meta{operand_2} \}
+% \cs{fp_eval:n} \{ \meta{operand_1} |-| \meta{operand_2} \}
% \end{syntax}
-% Raises the \meta{floating point} to the given \meta{value}. If the
-% \meta{floating point} is negative, then the \meta{value} should be
-% either a positive real number or a negative integer. If the
-% \meta{floating point} is positive, then the \meta{value} may be any
-% real value. Mathematically invalid operations such as $0^{0}$
-% will give set the \meta{floating point} to to \cs{c_undefined_fp}.
+% Computes the sum or the difference of its two \meta{operands}. The
+% \enquote{invalid operation} exception occurs for $\infty-\infty$.
+% \enquote{Inexact}, \enquote{underflow} and \enquote{overflow} occur
+% when appropriate.
% \end{function}
%
-% \section{Exponential and logarithm functions}
-%
-% \begin{function}{\fp_exp:Nn, \fp_exp:cn, \fp_gexp:Nn, \fp_gexp:cn}
+% \begin{function}{*, /}
% \begin{syntax}
-% \cs{fp_exp:Nn} \meta{floating point} \Arg{value}
+% \cs{fp_eval:n} \{ \meta{operand_1} |*| \meta{operand_2} \}
+% \cs{fp_eval:n} \{ \meta{operand_1} |/| \meta{operand_2} \}
% \end{syntax}
-% Calculates the exponential of the \meta{value} and assigns this
-% to the \meta{floating point}.
+% Computes the product or the ratio of its two \meta{operands}. The
+% \enquote{invalid operation} exception occurs for $\infty/\infty$,
+% $0/0$, or $0*\infty$. \enquote{Division by zero} occurs when
+% dividing a finite non-zero number by $\pm 0$. The
+% \enquote{inexact}, \enquote{underflow} and \enquote{overflow}
+% exceptions occur when appropriate.
% \end{function}
%
-% \begin{function}{\fp_ln:Nn, \fp_ln:cn, \fp_gln:Nn, \fp_gln:cn}
+% \begin{function}{+, -, !}
% \begin{syntax}
-% \cs{fp_ln:Nn} \meta{floating point} \Arg{value}
+% \cs{fp_eval:n} \{ |+| \meta{operand} \}
+% \cs{fp_eval:n} \{ |-| \meta{operand} \}
+% \cs{fp_eval:n} \{ |!| \meta{operand} \}
% \end{syntax}
-% Calculates the natural logarithm of the \meta{value} and assigns
-% this to the \meta{floating point}.
+% The unary |+| does nothing, the unary |-| changes the sign of the
+% \meta{operand}, and |!| \meta{operand} evaluates to $1$ if
+% \meta{operand} is false and $0$ otherwise (this is the \texttt{not}
+% boolean function).
% \end{function}
%
-% \section{Trigonometric functions}
-%
-% The trigonometric functions all work in radians. They accept a maximum
-% input value of $100\,000\,000$, as there are issues with range
-% reduction and very large input values.
-%
-% \begin{function}{\fp_sin:Nn, \fp_sin:cn, \fp_gsin:Nn, \fp_gsin:cn}
+% \begingroup\catcode`\^=12
+% \begin{function}{**, ^}
% \begin{syntax}
-% \cs{fp_sin:Nn} \meta{floating point} \Arg{value}
+% \cs{fp_eval:n} \{ \meta{operand_1} |**| \meta{operand_2} \}
+% \cs{fp_eval:n} \{ \meta{operand_1} |^| \meta{operand_2} \}
% \end{syntax}
-% Assigns the sine of the \meta{value} to the \meta{floating point}.
-% The \meta{value} should be given in radians.
+% Raises \meta{operand_1} to the power \meta{operand_2}. This operation
+% is right associative, hence \texttt{2 ** 2 ** 3} equals
+% $2\sp{2\sp{3}} = 256$. The \enquote{invalid operation} exception
+% occurs if \meta{operand_1} is negative or $-0$, \meta{operand_2} is
+% not an integer, and the result is non-zero. \enquote{Division by
+% zero} occurs \emph{not yet}. The \enquote{inexact},
+% \enquote{underflow} and \enquote{overflow} exceptions occur when
+% appropriate.
% \end{function}
+% \endgroup
%
-% \begin{function}{\fp_cos:Nn, \fp_cos:cn, \fp_gcos:Nn, \fp_gcos:cn}
+% \begin{function}{abs}
% \begin{syntax}
-% \cs{fp_cos:Nn} \meta{floating point} \Arg{value}
+% \cs{fp_eval:n} \{ |abs(| \meta{fpexpr} |)| \}
% \end{syntax}
-% Assigns the cosine of the \meta{value} to the \meta{floating point}.
-% The \meta{value} should be given in radians.
+% Computes the absolute value of the \meta{fpexpr}. This function
+% never raises an exception when \meta{fpexpr} is a number.
% \end{function}
%
-% \begin{function}{\fp_tan:Nn, \fp_tan:cn, \fp_gtan:Nn, \fp_gtan:cn}
+% \begin{function}{exp}
% \begin{syntax}
-% \cs{fp_tan:Nn} \meta{floating point} \Arg{value}
+% \cs{fp_eval:n} \{ |exp(| \meta{fpexpr} |)| \}
% \end{syntax}
-% Assigns the tangent of the \meta{value} to the \meta{floating point}.
-% The \meta{value} should be given in radians.
+% Computes the exponential of the \meta{fpexpr}. The
+% \enquote{inexact}, \enquote{underflow} and \enquote{overflow}
+% exceptions occur when appropriate.
% \end{function}
%
-% \section{Constant floating point values}
-%
-% \begin{variable}{\c_e_fp}
-% The value of the base of natural numbers, $\mathrm{e}$.
-% \end{variable}
-%
-% \begin{variable}{\c_one_fp}
-% A floating point variable with permanent value $1$: used for
-% speeding up some comparisons.
-% \end{variable}
-%
-% \begin{variable}{\c_pi_fp}
-% The value of $\pi$.
-% \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}
-%
-% \section{Notes on the floating point unit}
-%
-% As calculation of the elemental transcendental functions is
-% computationally expensive compared to storage of results, after
-% calculating a trigonometric function, exponent, \emph{etc.}~the module
-% stored the result for reuse. Thus the performance of the module for
-% repeated operations, most probably trigonometric functions, should be
-% much higher than if the values were re-calculated every time they
-% were needed.
-%
-% 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{\pkg{l3fp} Implementation}
-%
-% \TestFiles{m3fp003.lvt}
-%
-% \begin{macrocode}
-%<*initex|package>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*package>
-\ProvidesExplPackage
- {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
-\package_check_loaded_expl:
-%</package>
-% \end{macrocode}
-%
-% \subsection{Constants}
-%
-% \begin{variable}{\c_forty_four}
-% \begin{variable}{\c_one_million}
-% \begin{variable}{\c_one_hundred_million}
-% \begin{variable}{\c_five_hundred_million}
-% \begin{variable}{\c_one_thousand_million}
-% There is some speed to gain by moving numbers into fixed positions.
-% \begin{macrocode}
-\int_const:Nn \c_forty_four { 44 }
-\int_const:Nn \c_one_million { 1 000 000 }
-\int_const:Nn \c_one_hundred_million { 100 000 000 }
-\int_const:Nn \c_five_hundred_million { 500 000 000 }
-\int_const:Nn \c_one_thousand_million { 1 000 000 000 }
-% \end{macrocode}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-%
-% \begin{variable}{\c_fp_pi_by_four_decimal_int}
-% \begin{variable}{\c_fp_pi_by_four_extended_int}
-% \begin{variable}{\c_fp_pi_decimal_int}
-% \begin{variable}{\c_fp_pi_extended_int}
-% \begin{variable}{\c_fp_two_pi_decimal_int}
-% \begin{variable}{\c_fp_two_pi_extended_int}
-% Parts of $\pi$ for trigonometric range reduction, implemented
-% as \texttt{int} variables for speed.
-% \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{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-%
-% \begin{variable}{\c_e_fp}
-% The value $\mathrm{e}$ as a \enquote{machine number}.
-% \begin{macrocode}
-\tl_const:Nn \c_e_fp { + 2.718281828 e 0 }
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\c_one_fp}
-% The constant value $1$: used for fast comparisons.
-% \begin{macrocode}
-\tl_const:Nn \c_one_fp { + 1.000000000 e 0 }
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\c_pi_fp}
-% The value $\pi$ as a \enquote{machine number}.
-% \begin{macrocode}
-\tl_const:Nn \c_pi_fp { + 3.141592654 e 0 }
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\c_undefined_fp}
-% A marker for undefined values.
-% \begin{macrocode}
-\tl_const:Nn \c_undefined_fp { X 0.000000000 e 0 }
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\c_zero_fp}
-% The constant zero value.
-% \begin{macrocode}
-\tl_const:Nn \c_zero_fp { + 0.000000000 e 0 }
-% \end{macrocode}
-% \end{variable}
-%
-% \subsection{Variables}
-%
-% \begin{variable}{\l_fp_arg_tl}
-% A token list to store the formalised representation of the input
-% for transcendental functions.
-% \begin{macrocode}
-\tl_new:N \l_fp_arg_tl
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\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{variable}
-%
-% \begin{variable}{\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{variable}
-%
-% \begin{variable}{\l_fp_exp_integer_int}
-% \begin{variable}{\l_fp_exp_decimal_int}
-% \begin{variable}{\l_fp_exp_extended_int}
-% \begin{variable}{\l_fp_exp_exponent_int}
-% Used for the calculation of exponent values.
-% \begin{macrocode}
-\int_new:N \l_fp_exp_integer_int
-\int_new:N \l_fp_exp_decimal_int
-\int_new:N \l_fp_exp_extended_int
-\int_new:N \l_fp_exp_exponent_int
-% \end{macrocode}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-%
-% \begin{variable}{\l_fp_input_a_sign_int}
-% \begin{variable}{\l_fp_input_a_integer_int}
-% \begin{variable}{\l_fp_input_a_decimal_int}
-% \begin{variable}{\l_fp_input_a_exponent_int}
-% \begin{variable}{\l_fp_input_b_sign_int}
-% \begin{variable}{\l_fp_input_b_integer_int}
-% \begin{variable}{\l_fp_input_b_decimal_int}
-% \begin{variable}{\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{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-%
-% \begin{variable}{\l_fp_input_a_extended_int}
-% \begin{variable}{\l_fp_input_b_extended_int}
-% For internal use, \enquote{extended} floating point numbers are
-% needed.
-% \begin{macrocode}
-\int_new:N \l_fp_input_a_extended_int
-\int_new:N \l_fp_input_b_extended_int
-% \end{macrocode}
-% \end{variable}
-% \end{variable}
-%
-% \begin{variable}{\l_fp_mul_a_i_int}
-% \begin{variable}{\l_fp_mul_a_ii_int}
-% \begin{variable}{\l_fp_mul_a_iii_int}
-% \begin{variable}{\l_fp_mul_a_iv_int}
-% \begin{variable}{\l_fp_mul_a_v_int}
-% \begin{variable}{\l_fp_mul_a_vi_int}
-% \begin{variable}{\l_fp_mul_b_i_int}
-% \begin{variable}{\l_fp_mul_b_ii_int}
-% \begin{variable}{\l_fp_mul_b_iii_int}
-% \begin{variable}{\l_fp_mul_b_iv_int}
-% \begin{variable}{\l_fp_mul_b_v_int}
-% \begin{variable}{\l_fp_mul_b_vi_int}
-% 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
-\int_new:N \l_fp_mul_a_iii_int
-\int_new:N \l_fp_mul_a_iv_int
-\int_new:N \l_fp_mul_a_v_int
-\int_new:N \l_fp_mul_a_vi_int
-\int_new:N \l_fp_mul_b_i_int
-\int_new:N \l_fp_mul_b_ii_int
-\int_new:N \l_fp_mul_b_iii_int
-\int_new:N \l_fp_mul_b_iv_int
-\int_new:N \l_fp_mul_b_v_int
-\int_new:N \l_fp_mul_b_vi_int
-% \end{macrocode}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-%
-% \begin{variable}{\l_fp_mul_output_int}
-% \begin{variable}{\l_fp_mul_output_tl}
-% Space for multiplication results.
-% \begin{macrocode}
-\int_new:N \l_fp_mul_output_int
-\tl_new:N \l_fp_mul_output_tl
-% \end{macrocode}
-% \end{variable}
-% \end{variable}
-%
-% \begin{variable}{\l_fp_output_sign_int}
-% \begin{variable}{\l_fp_output_integer_int}
-% \begin{variable}{\l_fp_output_decimal_int}
-% \begin{variable}{\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{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-%
-% \begin{variable}{\l_fp_output_extended_int}
-% Again, for calculations an extended part.
-% \begin{macrocode}
-\int_new:N \l_fp_output_extended_int
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_fp_round_carry_bool}
-% To indicate that a digit needs to be carried forward.
-% \begin{macrocode}
-\bool_new:N \l_fp_round_carry_bool
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\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
-% \end{macrocode}
-% \end{variable}
+% \begin{function}{ln}
+% \begin{syntax}
+% \cs{fp_eval:n} \{ |ln(| \meta{fpexpr} |)| \}
+% \end{syntax}
+% Computes the natural logarithm of the \meta{fpexpr}. Negative
+% numbers have no (real) logarithm, hence the \enquote{invalid
+% operation} is raised in that case. \enquote{Division by zero}
+% occurs when evaluating the logarithm of $\pm 0$. The
+% \enquote{inexact}, \enquote{underflow} and \enquote{overflow}
+% exceptions occur when appropriate.
+% \end{function}
%
-% \begin{variable}{\l_fp_round_position_int}
-% \begin{variable}{\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{variable}
-% \end{variable}
+% \begin{function}{max, min}
+% \begin{syntax}
+% \cs{fp_eval:n} \{ |max(| \meta{fpexpr_1} |,| \meta{fpexpr_2} |,| \ldots{} |)| \}
+% \cs{fp_eval:n} \{ |min(| \meta{fpexpr_1} |,| \meta{fpexpr_2} |,| \ldots{} |)| \}
+% \end{syntax}
+% Evalutes each \meta{fpexpr} and computes the largest (smallest) of
+% those. If any of the \meta{fpexpr} is a \nan{}, the result is
+% \nan{}.
+% \end{function}
%
-% \begin{variable}{\l_fp_sign_tl}
-% There are places where the sign needs to be set up \enquote{early},
-% so that the registers can be re-used.
-% \begin{macrocode}
-\tl_new:N \l_fp_sign_tl
-% \end{macrocode}
-% \end{variable}
+% \begin{function}{round, round0, round+, round-}
+% \begin{syntax}
+% \cs{fp_eval:n} \{ |round| \meta{option} |(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |round| \meta{option} |(| \meta{fpexpr_1} , \meta{fpexpr_2} |)| \}
+% \end{syntax}
+% Rounds \meta{fpexpr_1} to \meta{fpexpr_2} places (this must be an
+% integer). When \meta{fpexpr_2} is missing, it is assumed to be $0$,
+% \emph{i.e.}, \meta{fpexpr_1} is rounded to an integer. The
+% \meta{option} controls the rounding direction:
+% \begin{itemize}
+% \item by default, the function rounds to the closest allowed number
+% (rounding ties to even);
+% \item with |0|, the function rounds towards $0$, \emph{i.e.}, truncates;
+% \item with |+|, the function rounds towards $+\infty$;
+% \item with |-|, the function rounds towards $-\infty$.
+% \end{itemize}
+% \end{function}
%
-% \begin{variable}{\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{variable}
+% \begin{function}{sin, cos, tan, cot}
+% \begin{syntax}
+% \cs{fp_eval:n} \{ |sin(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |cos(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |tan(| \meta{fpexpr} |)| \}
+% \cs{fp_eval:n} \{ |cot(| \meta{fpexpr} |)| \}
+% \end{syntax}
+% Computes the sine, cosine, tangent or cotangent of the
+% \meta{fpexpr}. The trigonometric functions are undefined for an
+% argument of $\pm\infty$, leading to the \enquote{invalid operation}
+% exception. Additionally, evaluating tangent or cotangent at one of
+% their poles leads to a \enquote{division by zero} exception. Other
+% exceptions occur when appropriate.
+% \end{function}
%
-% \begin{variable}{\l_fp_internal_int}
-% A scratch \texttt{int}: used only where the value is not carried
-% forward.
-% \begin{macrocode}
-\int_new:N \l_fp_internal_int
-% \end{macrocode}
+% \begin{variable}{inf, nan}
+% The special values $+\infty$, $-\infty$, and \nan{} are represented
+% as \texttt{inf}, \texttt{-inf} and \texttt{nan} (see \cs{c_inf_fp},
+% \cs{c_minus_inf_fp} and \cs{c_nan_fp}).
% \end{variable}
%
-% \begin{variable}{\l_fp_internal_tl}
-% A scratch token list variable for expanding material.
-% \begin{macrocode}
-\tl_new:N \l_fp_internal_tl
-% \end{macrocode}
+% \begin{variable}{pi}
+% The value of $\pi$ (see \cs{c_pi_fp}).
% \end{variable}
%
-% \begin{variable}{\l_fp_trig_octant_int}
-% To track which octant the trigonometric input is in.
-% \begin{macrocode}
-\int_new:N \l_fp_trig_octant_int
-% \end{macrocode}
+% \begin{variable}{deg}
+% The value of $1^{\circ}$ in radians (see \cs{c_one_degree_fp}).
% \end{variable}
%
-% \begin{variable}{\l_fp_trig_sign_int}
-% \begin{variable}{\l_fp_trig_decimal_int}
-% \begin{variable}{\l_fp_trig_extended_int}
-% Used for the calculation of trigonometric values.
-% \begin{macrocode}
-\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{variable}
-% \end{variable}
+% \begin{variable}{em, ex, in, pt, pc, cm, mm, dd, cc, nd, nc, bp, sp}
+% \newcommand{\unit}[1]{\text{\texttt{#1}}}
+% Those units of measurement are equal to their values in \texttt{pt},
+% namely
+% \begin{align*}
+% 1 \unit{in} & = 72.27 \unit{pt} \\
+% 1 \unit{pt} & = 1 \unit{pt} \\
+% 1 \unit{pc} & = 12 \unit{pt} \\
+% 1 \unit{cm} & = \frac{1}{2.54} \unit{in} = 28.45275590551181 \unit{pt} \\
+% 1 \unit{mm} & = \frac{1}{25.4} \unit{in} = 2.845275590551181 \unit{pt} \\
+% 1 \unit{dd} & = 0.376065 \unit{mm} = 1.07000856496063 \unit{pt} \\
+% 1 \unit{cc} & = 12 \unit{dd} = 12.84010277952756 \unit{pt} \\
+% 1 \unit{nd} & = 0.375 \unit{mm} = 1.066978346456693 \unit{pt} \\
+% 1 \unit{nc} & = 12 \unit{nd} = 12.80374015748031 \unit{pt} \\
+% 1 \unit{bp} & = \frac{1}{72} \unit{in} = 1.00375 \unit{pt} \\
+% 1 \unit{sp} & = 2^{-16} \unit{pt} = 1.52587890625e-5 \unit{pt}.
+% \end{align*}
+% The values of the (font-dependent) units \texttt{em} and \texttt{ex}
+% are gathered from \TeX{} when the surrounding floating point
+% expression is evaluated.
% \end{variable}
%
-% \subsection{Parsing numbers}
-%
-% \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:Npn \fp_read:N #1
- { \exp_after:wN \fp_read_aux:w #1 \q_stop }
-\cs_new_protected:Npn \fp_read_aux:w #1#2 . #3 e #4 \q_stop
- {
- \if:w #1 -
- \l_fp_input_a_sign_int \c_minus_one
- \else:
- \l_fp_input_a_sign_int \c_one
- \fi:
- \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:
- }
-% \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:Npn \fp_split:Nn #1#2
- {
- \tl_set:Nx \l_fp_internal_tl {#2}
- \tl_set_rescan:Nno \l_fp_internal_tl { \char_set_catcode_ignore:n { 32 } }
- { \l_fp_internal_tl }
- \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_internal_tl e e \q_stop #1
- }
-\cs_new_protected_nopar:Npn \fp_split_sign:
- {
- \if_int_compare:w \pdftex_strcmp:D
- { \exp_after:wN \tl_head:w \l_fp_internal_tl ? \q_stop } { - }
- = \c_zero
- \tl_set:Nx \l_fp_internal_tl
- {
- \exp_after:wN
- \tl_tail:w \l_fp_internal_tl \prg_do_nothing: \q_stop
- }
- \l_fp_split_sign_int -\l_fp_split_sign_int
- \exp_after:wN \fp_split_sign:
- \else:
- \if_int_compare:w \pdftex_strcmp:D
- { \exp_after:wN \tl_head:w \l_fp_internal_tl ? \q_stop } { + }
- = \c_zero
- \tl_set:Nx \l_fp_internal_tl
- {
- \exp_after:wN
- \tl_tail:w \l_fp_internal_tl \prg_do_nothing: \q_stop
- }
- \exp_after:wN \exp_after:wN \exp_after:wN \fp_split_sign:
- \fi:
- \fi:
- }
-\cs_new_protected:Npn \fp_split_exponent:w #1 e #2 e #3 \q_stop #4
- {
- \use:c { l_fp_input_ #4 _exponent_int }
- \int_eval:w 0 #2 \scan_stop:
- \tex_afterassignment:D \fp_split_aux_i:w
- \use:c { l_fp_input_ #4 _integer_int }
- \int_eval:w 0 #1 . . \q_stop #4
- }
-\cs_new_protected:Npn \fp_split_aux_i:w #1 . #2 . #3 \q_stop
- { \fp_split_aux_ii:w #2 000000000 \q_stop }
-\cs_new_protected: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:Npn \fp_split_aux_iii:w #1#2 \q_stop
- {
- \l_fp_internal_int 1 #1 \scan_stop:
- \exp_after:wN \fp_split_decimal:w
- \int_use:N \l_fp_internal_int 000000000 \q_stop
- }
-\cs_new_protected: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:Npn \fp_split_decimal_aux:w #1#2#3 \q_stop #4
- {
- \use:c { l_fp_input_ #4 _decimal_int } #1#2 \scan_stop:
- \if_int_compare:w
- \int_eval:w
- \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
- \fi:
- \if_int_compare:w
- \use:c { l_fp_input_ #4 _integer_int } < \c_one_thousand_million
- \else:
- \exp_after:wN \fp_overflow_msg:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \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}
-\cs_new_protected:Npn \fp_standardise:NNNN #1#2#3#4
- {
- \if_int_compare:w
- \int_eval:w #2 + #3 = \c_zero
- #1 \c_one
- #4 \c_zero
- \exp_after:wN \use_none:nnnn
- \else:
- \exp_after:wN \fp_standardise_aux:NNNN
- \fi:
- #1#2#3#4
- }
-\cs_new_protected:Npn \fp_standardise_aux:NNNN #1#2#3#4
- {
- \cs_set_protected_nopar:Npn \fp_standardise_aux:
- {
- \if_int_compare:w #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:
- \fi:
- }
- \cs_set_protected: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:
- {
- \if_int_compare:w #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:
- \fi:
- }
- \cs_set_protected: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_internal_tl
- {
- ##9
- \exp_after:wN \use_none:n \int_use:N #3
- }
- #3 \l_fp_internal_tl \scan_stop:
- \tex_advance:D #4 \c_one
- }
- \fp_standardise_aux:
- \if_int_compare:w #4 < \c_one_hundred
- \if_int_compare:w #4 > -\c_one_hundred
- \else:
- #1 \c_one
- #2 \c_zero
- #3 \c_zero
- #4 \c_zero
- \fi:
- \else:
- \exp_after:wN \fp_overflow_msg:
- \fi:
- }
-\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}
-%
-% \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}
-\cs_new_protected_nopar:Npn \fp_level_input_exponents:
- {
- \if_int_compare:w \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int
- \exp_after:wN \fp_level_input_exponents_a:
- \else:
- \exp_after:wN \fp_level_input_exponents_b:
- \fi:
- }
-\cs_new_protected_nopar:Npn \fp_level_input_exponents_a:
- {
- \if_int_compare:w \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:
- \fi:
- }
-\cs_new_protected: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_internal_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_internal_tl \scan_stop:
- \tex_advance:D \l_fp_input_b_exponent_int \c_one
- }
-\cs_new_protected_nopar:Npn \fp_level_input_exponents_b:
- {
- \if_int_compare:w \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:
- \fi:
- }
-\cs_new_protected: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_internal_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_internal_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}[aux]{\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: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, \fp_new:c}
-% \UnitTested
-% Fixed-points always have a value, and of course this has to be
-% initialised globally.
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_new:N #1
- {
- \tl_new:N #1
- \tl_gset_eq:NN #1 \c_zero_fp
- }
-\cs_generate_variant:Nn \fp_new:N { c }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\fp_const:Nn, \fp_const:cn}
-% A simple wrapper.
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_const:Nn #1#2
- {
- \fp_new:N #1
- \fp_gset:Nn #1 {#2}
- }
-\cs_generate_variant:Nn \fp_const:Nn { c }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\fp_zero:N, \fp_zero:c}
-% \UnitTested
-% \begin{macro}{\fp_gzero:N, \fp_gzero:c}
-% \UnitTested
-% Zeroing fixed-points is pretty obvious.
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_zero:N #1
- { \tl_set_eq:NN #1 \c_zero_fp }
-\cs_new_protected:Npn \fp_gzero:N #1
- { \tl_gset_eq:NN #1 \c_zero_fp }
-\cs_generate_variant:Nn \fp_zero:N { c }
-\cs_generate_variant:Nn \fp_gzero:N { c }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}
-% {\fp_zero_new:N, \fp_zero_new:c, \fp_gzero_new:N, \fp_gzero_new:c}
-% Create a floating point if needed, otherwise clear it.
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_zero_new:N #1
- { \fp_if_exist:NTF #1 { \fp_zero:N #1 } { \fp_new:N #1 } }
-\cs_new_protected:Npn \fp_gzero_new:N #1
- { \fp_if_exist:NTF #1 { \fp_gzero:N #1 } { \fp_new:N #1 } }
-\cs_generate_variant:Nn \fp_zero_new:N { c }
-\cs_generate_variant:Nn \fp_gzero_new:N { c }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\fp_set:Nn, \fp_set:cn}
-% \UnitTested
-% \begin{macro}{\fp_gset:Nn, \fp_gset:cn}
-% \UnitTested
-% \begin{macro}[aux]{\fp_set_aux:NNn}
-% To trap any input errors, a very simple version of the parser is run
-% here. This will pick up any invalid characters at this stage, saving
-% issues later. The splitting approach is the same as the more
-% advanced function later.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_set:Nn { \fp_set_aux:NNn \tl_set:Nn }
-\cs_new_protected_nopar:Npn \fp_gset:Nn { \fp_set_aux:NNn \tl_gset:Nn }
-\cs_new_protected: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
- \cs_set_protected_nopar:Npx \fp_tmp:w
- {
- \group_end:
- #1 \exp_not:N #2
- {
- \if_int_compare:w \l_fp_input_a_sign_int < \c_zero
- -
- \else:
- +
- \fi:
- \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
- }
-\cs_generate_variant:Nn \fp_set:Nn { c }
-\cs_generate_variant:Nn \fp_gset:Nn { c }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-%
-%
-% \begin{macro}{\fp_set_from_dim:Nn, \fp_set_from_dim:cn}
-% \UnitTested
-% \begin{macro}{\fp_gset_from_dim:Nn, \fp_gset_from_dim:cn}
-% \UnitTested
-% \begin{macro}[aux]{\fp_set_from_dim_aux:NNn}
-% \begin{macro}[aux]{\fp_set_from_dim_aux:w}
-% \begin{variable}{\l_fp_internal_dim}
-% \begin{variable}{\l_fp_internal_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. 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 }
-\cs_new_protected_nopar:Npn \fp_gset_from_dim:Nn
- { \fp_set_from_dim_aux:NNn \tl_gset:Nx }
-\cs_new_protected:Npn \fp_set_from_dim_aux:NNn #1#2#3
- {
- \group_begin:
- \l_fp_internal_skip \etex_glueexpr:D #3 \scan_stop:
- \l_fp_internal_dim \l_fp_internal_skip
- \fp_split:Nn a
- {
- \exp_after:wN \fp_set_from_dim_aux:w
- \dim_use:N \l_fp_internal_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
- \cs_set_protected_nopar:Npx \fp_tmp:w
- {
- \group_end:
- #1 \exp_not:N #2
- {
- \if_int_compare:w \l_fp_input_a_sign_int < \c_zero
- -
- \else:
- +
- \fi:
- \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
- }
-\cs_set_protected_nopar:Npx \fp_set_from_dim_aux:w
- {
- \cs_set:Npn \exp_not:N \fp_set_from_dim_aux:w
- ##1 \tl_to_str:n { pt } {##1}
- }
-\fp_set_from_dim_aux:w
-\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_internal_dim
-\skip_new:N \l_fp_internal_skip
-% \end{macrocode}
-% \end{variable}
+% \begin{variable}{true, false}
+% Other names for $1$ and $+0$.
% \end{variable}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
%
-% \begin{macro}{\fp_set_eq:NN, \fp_set_eq:cN, \fp_set_eq:Nc, \fp_set_eq:cc}
-% \UnitTested
-% \begin{macro}{\fp_gset_eq:NN, \fp_gset_eq:cN, \fp_gset_eq:Nc, \fp_gset_eq:cc}
-% \UnitTested
-% Pretty simple, really.
-% \begin{macrocode}
-\cs_new_eq:NN \fp_set_eq:NN \tl_set_eq:NN
-\cs_new_eq:NN \fp_set_eq:cN \tl_set_eq:cN
-\cs_new_eq:NN \fp_set_eq:Nc \tl_set_eq:Nc
-\cs_new_eq:NN \fp_set_eq:cc \tl_set_eq:cc
-\cs_new_eq:NN \fp_gset_eq:NN \tl_gset_eq:NN
-\cs_new_eq:NN \fp_gset_eq:cN \tl_gset_eq:cN
-\cs_new_eq:NN \fp_gset_eq:Nc \tl_gset_eq:Nc
-\cs_new_eq:NN \fp_gset_eq:cc \tl_gset_eq:cc
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\fp_show:N, \fp_show:c}
-% \UnitTested
-% Simple showing of the underlying variable.
-% \begin{macrocode}
-\cs_new_eq:NN \fp_show:N \tl_show:N
-\cs_new_eq:NN \fp_show:c \tl_show:c
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\fp_use:N, \fp_use:c}
-% \UnitTested
-% \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: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:Npn \fp_use_aux:w #1#2 e #3 \q_stop
- {
- \if:w #1 -
- -
- \fi:
- \if_int_compare:w #3 > \c_zero
- \exp_after:wN \fp_use_large:w
- \else:
- \if_int_compare:w #3 < \c_zero
- \exp_after:wN \exp_after:wN \exp_after:wN
- \fp_use_small:w
- \else:
- \exp_after:wN \exp_after:wN \exp_after:wN \fp_use_none:w
- \fi:
- \fi:
- #2 e #3 \q_stop
- }
-% \end{macrocode}
-% When the exponent is zero, the input is simply returned as output.
-% \begin{macrocode}
-\cs_new: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: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:Npn \fp_use_large:w #1 . #2 e #3 \q_stop
- {
- \if_int_compare:w #3 < \c_ten
- \exp_after:wN \fp_use_large_aux_i:w
- \else:
- \exp_after:wN \fp_use_large_aux_ii:w
- \fi:
- #1#2 e #3 \q_stop
- }
-\cs_new: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:cpn { fp_use_large_aux_1:w } #1#2 \q_stop { #1 . #2 }
-\cs_new:cpn { fp_use_large_aux_2:w } #1#2#3 \q_stop
- { #1#2 . #3 }
-\cs_new:cpn { fp_use_large_aux_3:w } #1#2#3#4 \q_stop
- { #1#2#3 . #4 }
-\cs_new:cpn { fp_use_large_aux_4:w } #1#2#3#4#5 \q_stop
- { #1#2#3#4 . #5 }
-\cs_new:cpn { fp_use_large_aux_5:w } #1#2#3#4#5#6 \q_stop
- { #1#2#3#4#5 . #6 }
-\cs_new: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: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: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:cpn { fp_use_large_aux_9:w } #1 \q_stop { #1 . }
-\cs_new: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}
-%
-% \begin{macro}[pTF]{\fp_if_exist:N, \fp_if_exist:c}
-% Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
-% \begin{macrocode}
-\cs_new_eq:NN \fp_if_exist:NTF \cs_if_exist:NTF
-\cs_new_eq:NN \fp_if_exist:NT \cs_if_exist:NT
-\cs_new_eq:NN \fp_if_exist:NF \cs_if_exist:NF
-\cs_new_eq:NN \fp_if_exist_p:N \cs_if_exist_p:N
-\cs_new_eq:NN \fp_if_exist:cTF \cs_if_exist:cTF
-\cs_new_eq:NN \fp_if_exist:cT \cs_if_exist:cT
-\cs_new_eq:NN \fp_if_exist:cF \cs_if_exist:cF
-\cs_new_eq:NN \fp_if_exist_p:c \cs_if_exist_p:c
-% \end{macrocode}
-% \end{macro}
-%
-% \subsection{Transferring to other types}
-%
-% 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_dim:N, \fp_to_dim:c}
-% A very simple wrapper.
-% \begin{macrocode}
-\cs_new:Npn \fp_to_dim:N #1 { \fp_use:N #1 pt }
-\cs_generate_variant:Nn \fp_to_dim:N { c }
-% \end{macrocode}
-% \end{macro}
-%
-%
-% \begin{macro}{\fp_to_int:N, \fp_to_int:c}
-% \UnitTested
-% \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:Npn \fp_to_int:N #1
- { \exp_after:wN \fp_to_int_aux:w #1 \q_stop }
-\cs_generate_variant:Nn \fp_to_int:N { c }
-\cs_new:Npn \fp_to_int_aux:w #1#2 e #3 \q_stop
- {
- \if:w #1 -
- -
- \fi:
- \if_int_compare:w #3 < \c_zero
- \exp_after:wN \fp_to_int_small:w
- \else:
- \exp_after:wN \fp_to_int_large:w
- \fi:
- #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:Npn \fp_to_int_small:w #1 . #2 e #3 \q_stop
- {
- \if_int_compare:w #3 > \c_one
- \else:
- \if_int_compare:w #1 < \c_five
- 0
- \else:
- 1
- \fi:
- \fi:
- }
-% \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:Npn \fp_to_int_large:w #1 . #2 e #3 \q_stop
- {
- \if_int_compare:w #3 < \c_ten
- \exp_after:wN \fp_to_int_large_aux_i:w
- \else:
- \exp_after:wN \fp_to_int_large_aux_ii:w
- \fi:
- #1#2 e #3 \q_stop
- }
-\cs_new: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:cpn { fp_to_int_large_aux_1:w } #1#2 \q_stop
- { \fp_to_int_large_aux:nnn { #2 0 } {#1} }
-\cs_new: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: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: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: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: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: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: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:cpn { fp_to_int_large_aux_9:w } #1 \q_stop {#1}
-\cs_new:Npn \fp_to_int_large_aux:nnn #1#2#3
- {
- \if_int_compare:w #1 < \c_five_hundred_million
- #3#2
- \else:
- \int_value:w \int_eval:w #3#2 + 1 \int_eval_end:
- \fi:
- }
-\cs_new: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}
-%
-% \begin{macro}{\fp_to_tl:N, \fp_to_tl:c}
-% \UnitTested
-% \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:Npn \fp_to_tl:N #1
- { \exp_after:wN \fp_to_tl_aux:w #1 \q_stop }
-\cs_generate_variant:Nn \fp_to_tl:N { c }
-\cs_new:Npn \fp_to_tl_aux:w #1#2 e #3 \q_stop
- {
- \if:w #1 -
- -
- \fi:
- \if_int_compare:w #3 < \c_zero
- \exp_after:wN \fp_to_tl_small:w
- \else:
- \exp_after:wN \fp_to_tl_large:w
- \fi:
- #2 e #3 \q_stop
- }
-% \end{macrocode}
-% For \enquote{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:Npn \fp_to_tl_large:w #1 e #2 \q_stop
- {
- \if_int_compare:w #2 < \c_ten
- \exp_after:wN \fp_to_tl_large_aux_i:w
- \else:
- \exp_after:wN \fp_to_tl_large_aux_ii:w
- \fi:
- #1 e #2 \q_stop
- }
-\cs_new: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: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:cpn { fp_to_tl_large_0:w } #1 . #2 \q_stop
- {
- #1
- \fp_to_tl_large_zeros:NNNNNNNNN #2
- }
-\cs_new:cpn { fp_to_tl_large_1:w } #1 . #2#3 \q_stop
- {
- #1#2
- \fp_to_tl_large_zeros:NNNNNNNNN #3 0
- }
-\cs_new: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: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: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: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: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: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:cpn { fp_to_tl_large_8:w } #1 .
- {
- #1
- \use:c { fp_to_tl_large_8_aux:w }
- }
-\cs_new: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: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:Npn \fp_to_tl_small:w #1 e #2 \q_stop
- {
- \if_int_compare:w #2 = \c_minus_one
- \exp_after:wN \fp_to_tl_small_one:w
- \else:
- \if_int_compare:w #2 = -\c_two
- \exp_after:wN \exp_after:wN \exp_after:wN \fp_to_tl_small_two:w
- \else:
- \exp_after:wN \exp_after:wN \exp_after:wN \fp_to_tl_small_aux:w
- \fi:
- \fi:
- #1 e #2 \q_stop
- }
-\cs_new:Npn \fp_to_tl_small_one:w #1 . #2 e #3 \q_stop
- {
- \if_int_compare:w \fp_use_ix:NNNNNNNNN #2 > \c_four
- \if_int_compare:w
- \int_eval:w #1 \fp_use_i_to_iix:NNNNNNNNN #2 + 1
- < \c_one_thousand_million
- 0.
- \exp_after:wN \fp_to_tl_small_zeros:NNNNNNNNN
- \int_value:w \int_eval:w
- #1 \fp_use_i_to_iix:NNNNNNNNN #2 + 1
- \int_eval_end:
- \else:
- 1
- \fi:
- \else:
- 0. #1
- \fp_to_tl_small_zeros:NNNNNNNNN #2
- \fi:
- }
-\cs_new:Npn \fp_to_tl_small_two:w #1 . #2 e #3 \q_stop
- {
- \if_int_compare:w \fp_use_iix_ix:NNNNNNNNN #2 > \c_forty_four
- \if_int_compare:w
- \int_eval:w #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
- \int_value:w \int_eval:w
- #1 \fp_use_i_to_vii:NNNNNNNNN #2 0 + \c_ten
- \int_eval_end:
- \else:
- 0.1
- \fi:
- \else:
- 0.0
- #1
- \fp_to_tl_small_zeros:NNNNNNNNN #2
- \fi:
- }
-\cs_new:Npn \fp_to_tl_small_aux:w #1 . #2 e #3 \q_stop
- {
- #1
- \fp_to_tl_large_zeros:NNNNNNNNN #2
- e #3
- }
-% \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:Npn \fp_to_tl_large_zeros:NNNNNNNNN #1#2#3#4#5#6#7#8#9
- {
- \if_int_compare:w #9 = \c_zero
- \if_int_compare:w #8 = \c_zero
- \if_int_compare:w #7 = \c_zero
- \if_int_compare:w #6 = \c_zero
- \if_int_compare:w #5 = \c_zero
- \if_int_compare:w #4 = \c_zero
- \if_int_compare:w #3 = \c_zero
- \if_int_compare:w #2 = \c_zero
- \if_int_compare:w #1 = \c_zero
- \else:
- . #1
- \fi:
- \else:
- . #1#2
- \fi:
- \else:
- . #1#2#3
- \fi:
- \else:
- . #1#2#3#4
- \fi:
- \else:
- . #1#2#3#4#5
- \fi:
- \else:
- . #1#2#3#4#5#6
- \fi:
- \else:
- . #1#2#3#4#5#6#7
- \fi:
- \else:
- . #1#2#3#4#5#6#7#8
- \fi:
- \else:
- . #1#2#3#4#5#6#7#8#9
- \fi:
- }
-\cs_new:Npn \fp_to_tl_small_zeros:NNNNNNNNN #1#2#3#4#5#6#7#8#9
- {
- \if_int_compare:w #9 = \c_zero
- \if_int_compare:w #8 = \c_zero
- \if_int_compare:w #7 = \c_zero
- \if_int_compare:w #6 = \c_zero
- \if_int_compare:w #5 = \c_zero
- \if_int_compare:w #4 = \c_zero
- \if_int_compare:w #3 = \c_zero
- \if_int_compare:w #2 = \c_zero
- \if_int_compare:w #1 = \c_zero
- \else:
- #1
- \fi:
- \else:
- #1#2
- \fi:
- \else:
- #1#2#3
- \fi:
- \else:
- #1#2#3#4
- \fi:
- \else:
- #1#2#3#4#5
- \fi:
- \else:
- #1#2#3#4#5#6
- \fi:
- \else:
- #1#2#3#4#5#6#7
- \fi:
- \else:
- #1#2#3#4#5#6#7#8
- \fi:
- \else:
- #1#2#3#4#5#6#7#8#9
- \fi:
- }
-% \end{macrocode}
-% Some quick \enquote{return a few} functions.
-% \begin{macrocode}
-\cs_new:Npn \fp_use_iix_ix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 {#8#9}
-\cs_new:Npn \fp_use_ix:NNNNNNNNN #1#2#3#4#5#6#7#8#9 {#9}
-\cs_new: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: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}
-% \end{macro}
-% \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, \fp_round_figures:cn}
-% \UnitTested
-% \begin{macro}{\fp_ground_figures:Nn, \fp_ground_figures:cn}
-% \UnitTested
-% \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: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 }
- \if_int_compare:w \l_fp_round_target_int < \c_ten
- \exp_after:wN \fp_round:
- \fi:
- \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
- {
- \if_int_compare:w \l_fp_input_a_sign_int < \c_zero
- -
- \else:
- +
- \fi:
- \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}
-%
-% \begin{macro}{\fp_round_places:Nn, \fp_round_places:cn}
-% \UnitTested
-% \begin{macro}{\fp_ground_places:Nn, \fp_ground_places:cn}
-% \UnitTested
-% \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: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 }
- \if_int_compare:w \l_fp_round_target_int < \c_ten
- \exp_after:wN \fp_round:
- \fi:
- \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
- {
- \if_int_compare:w \l_fp_input_a_sign_int < \c_zero
- -
- \else:
- +
- \fi:
- \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}
-%
-% \begin{macro}{\fp_round:}
-% \begin{macro}[aux]{\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: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:
- \if_int_compare:w \l_fp_input_a_integer_int < \c_ten
- \else:
- \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
- \fi:
- }
-\cs_new_protected:Npn \fp_round_loop:N #1
- {
- \if_int_compare:w \l_fp_round_position_int < \l_fp_round_target_int
- \bool_if:NTF \l_fp_round_carry_bool
- { \l_fp_internal_int \int_eval:w #1 + \c_one \scan_stop: }
- { \l_fp_internal_int \int_eval:w #1 \scan_stop: }
- \if_int_compare:w \l_fp_internal_int = \c_ten
- \l_fp_internal_int \c_zero
- \else:
- \bool_set_false:N \l_fp_round_carry_bool
- \fi:
- \tl_set:Nx \l_fp_round_decimal_tl
- { \int_use:N \l_fp_internal_int \l_fp_round_decimal_tl }
- \else:
- \tl_set:Nx \l_fp_round_decimal_tl { 0 \l_fp_round_decimal_tl }
- \if_int_compare:w \l_fp_round_position_int = \l_fp_round_target_int
- \if_int_compare:w #1 > \c_four
- \bool_set_true:N \l_fp_round_carry_bool
- \fi:
- \fi:
- \fi:
- \tex_advance:D \l_fp_round_position_int \c_minus_one
- \if_int_compare:w \l_fp_round_position_int > \c_minus_one
- \exp_after:wN \fp_round_loop:N
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Unary functions}
-%
-% \begin{macro}{\fp_abs:N, \fp_abs:c}
-% \UnitTested
-% \begin{macro}{\fp_gabs:N, \fp_gabs:c}
-% \UnitTested
-% \begin{macro}[aux]{\fp_abs_aux:NN}
-% Setting the absolute value is easy: read the value, ignore the sign,
-% return the result.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_abs:N { \fp_abs_aux:NN \tl_set:Nn }
-\cs_new_protected_nopar:Npn \fp_gabs:N { \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: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
- \cs_set_protected_nopar:Npx \fp_tmp:w
- {
- \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
- }
- }
- \fp_tmp:w
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\fp_neg:N, \fp_neg:c}
-% \UnitTested
-% \begin{macro}{\fp_gneg:N, \fp_gneg:c}
-% \UnitTested
-% \begin{macro}[aux]{\fp_neg:NN}
-% Just a bit more complex: read the input, reverse the sign and
-% output the result.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_neg:N { \fp_neg_aux:NN \tl_set:Nn }
-\cs_new_protected_nopar:Npn \fp_gneg:N { \fp_neg_aux:NN \tl_gset:Nn }
-\cs_generate_variant:Nn \fp_neg:N { c }
-\cs_generate_variant:Nn \fp_gneg:N { c }
-\cs_new_protected:Npn \fp_neg_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_internal_tl
- {
- \if_int_compare:w \l_fp_input_a_sign_int < \c_zero
- +
- \else:
- -
- \fi:
- \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_internal_tl }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Basic arithmetic}
-%
-% \begin{macro}{\fp_add:Nn, \fp_add:cn}
-% \UnitTested
-% \begin{macro}{\fp_gadd:Nn,\fp_gadd:cn}
-% \UnitTested
-% \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.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_add:Nn { \fp_add_aux:NNn \tl_set:Nn }
-\cs_new_protected_nopar:Npn \fp_gadd:Nn { \fp_add_aux:NNn \tl_gset:Nn }
-\cs_generate_variant:Nn \fp_add:Nn { c }
-\cs_generate_variant:Nn \fp_gadd:Nn { c }
-% \end{macrocode}
-% Addition takes place using one of two paths. If the signs of the
-% two parts are the same, they are simply combined. On the other
-% hand, if the signs are different the calculation finds this
-% difference.
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_add_aux:NNn #1#2#3
- {
- \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:
- \fp_tmp:w #1#2
- }
-\cs_new_protected_nopar:Npn \fp_add_core:
- {
- \fp_level_input_exponents:
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_a_sign_int * \l_fp_input_b_sign_int
- > \c_zero
- \exp_after:wN \fp_add_sum:
- \else:
- \exp_after:wN \fp_add_difference:
- \fi:
- \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:Npx \fp_tmp:w ##1##2
- {
- \group_end:
- ##1 ##2
- {
- \if_int_compare:w \l_fp_output_sign_int < \c_zero
- -
- \else:
- +
- \fi:
- \int_use:N \l_fp_output_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \l_fp_output_decimal_int + \c_one_thousand_million
- e
- \int_use:N \l_fp_output_exponent_int
- }
- }
- }
-% \end{macrocode}
-% Finding the sum of two numbers is trivially easy.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_add_sum:
- {
- \l_fp_output_sign_int \l_fp_input_a_sign_int
- \l_fp_output_integer_int
- \int_eval:w
- \l_fp_input_a_integer_int + \l_fp_input_b_integer_int
- \scan_stop:
- \l_fp_output_decimal_int
- \int_eval:w
- \l_fp_input_a_decimal_int + \l_fp_input_b_decimal_int
- \scan_stop:
- \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million
- \else:
- \tex_advance:D \l_fp_output_integer_int \c_one
- \tex_advance:D \l_fp_output_decimal_int -\c_one_thousand_million
- \fi:
- }
-% \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 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:
- {
- \l_fp_output_integer_int
- \int_eval:w
- \l_fp_input_a_integer_int - \l_fp_input_b_integer_int
- \scan_stop:
- \l_fp_output_decimal_int
- \int_eval:w
- \l_fp_input_a_decimal_int - \l_fp_input_b_decimal_int
- \scan_stop:
- \if_int_compare:w \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
- \fi:
- \if_int_compare:w \l_fp_output_integer_int < \c_zero
- \l_fp_output_sign_int \l_fp_input_b_sign_int
- \if_int_compare:w \l_fp_output_decimal_int = \c_zero
- \l_fp_output_integer_int -\l_fp_output_integer_int
- \else:
- \l_fp_output_decimal_int
- \int_eval:w
- \c_one_thousand_million - \l_fp_output_decimal_int
- \scan_stop:
- \l_fp_output_integer_int
- \int_eval:w
- - \l_fp_output_integer_int - \c_one
- \scan_stop:
- \fi:
- \else:
- \l_fp_output_sign_int \l_fp_input_a_sign_int
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
+% \begin{function}[EXP, added = 2012-05-08]{\dim_to_fp:n}
+% \begin{syntax}
+% \cs{dim_to_fp:n} \Arg{dimexpr}
+% \end{syntax}
+% Expands to an internal floating point number equal to the value of
+% the \meta{dimexpr} in \texttt{pt}.
+% \end{function}
%
-% \begin{macro}{\fp_sub:Nn, \fp_sub:cn}
-% \UnitTested
-% \begin{macro}{\fp_gsub:Nn,\fp_gsub:cn}
-% \UnitTested
-% \begin{macro}[aux]{\fp_sub_aux:NNn}
-% Subtraction is essentially the same as addition, but with the sign
-% of the second component reversed. Thus the core of the two function
-% groups is the same, with just a little set up here.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_sub:Nn { \fp_sub_aux:NNn \tl_set:Nn }
-\cs_new_protected_nopar:Npn \fp_gsub:Nn { \fp_sub_aux:NNn \tl_gset:Nn }
-\cs_generate_variant:Nn \fp_sub:Nn { c }
-\cs_generate_variant:Nn \fp_gsub:Nn { c }
-\cs_new_protected:Npn \fp_sub_aux:NNn #1#2#3
- {
- \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:
- \fp_tmp:w #1#2
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
+% \begin{function}[EXP, added = 2012-05-14, updated = 2012-07-08]{\fp_abs:n}
+% \begin{syntax}
+% \cs{fp_abs:n} \Arg{floating point expression}
+% \end{syntax}
+% Evaluates the \meta{floating point expression} as described for
+% \cs{fp_eval:n} and leaves the absolute value of the result in
+% the input stream.
+% \end{function}
%
-% \begin{macro}{\fp_mul:Nn, \fp_mul:cn}
-% \UnitTested
-% \begin{macro}{\fp_gmul:Nn,\fp_gmul:cn}
-% \UnitTested
-% \begin{macro}[aux]{\fp_mul_aux:NNn}
-% \begin{macro}[aux]{\fp_mul_internal:}
-% \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:NNNNNNNNN}
-% The pattern is much the same for multiplication.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_mul:Nn { \fp_mul_aux:NNn \tl_set:Nn }
-\cs_new_protected_nopar:Npn \fp_gmul:Nn { \fp_mul_aux:NNn \tl_gset:Nn }
-\cs_generate_variant:Nn \fp_mul:Nn { c }
-\cs_generate_variant:Nn \fp_gmul:Nn { c }
-% \end{macrocode}
-% The approach to multiplication is as follows. First, the two numbers
-% are split into blocks of three digits. These are then multiplied
-% together to find products for each group of three output digits. This
-% is al written out in full for speed reasons. Between each block of
-% three digits in the output, there is a carry step. The very lowest
-% digits are not calculated, while
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_mul_aux:NNn #1#2#3
- {
- \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_mul_internal:
- \l_fp_output_exponent_int
- \int_eval:w
- \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
- {
- \group_end:
- #1 \exp_not:N #2
- {
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_a_sign_int * \l_fp_input_b_sign_int
- < \c_zero
- \if_int_compare:w
- \int_eval:w
- \l_fp_output_integer_int + \l_fp_output_decimal_int
- = \c_zero
- +
- \else:
- -
- \fi:
- \else:
- +
- \fi:
- \int_use:N \l_fp_output_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \l_fp_output_decimal_int + \c_one_thousand_million
- e
- \int_use:N \l_fp_output_exponent_int
- }
- }
- \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_internal:
- {
- \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
-% the first digit can then be dropped using a delimited argument. The
-% groups of three digits are then assigned to the various parts of
-% the input: notice that |##9| contains the last two digits of the
-% smallest part of the input.
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_mul_split:NNNN #1#2#3#4
- {
- \tex_advance:D #1 \c_one_thousand_million
- \cs_set_protected:Npn \fp_mul_split_aux:w
- ##1##2##3##4##5##6##7##8##9 \q_stop {
- #2 ##2##3##4 \scan_stop:
- #3 ##5##6##7 \scan_stop:
- #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:Npn \fp_mul_product:NN #1#2
- {
- \l_fp_mul_output_int
- \int_eval:w \l_fp_mul_output_int + #1 * #2 \scan_stop:
- }
-% \end{macrocode}
-% At the end of each output group of three, there is a transfer of
-% information so that there is no danger of an overflow. This is done by
-% expansion to keep the number of calculations down.
-% \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 \use_i:nn \exp_after:wN
- \fp_mul_end_level:NNNNNNNNN \int_use:N \l_fp_mul_output_int
- }
-\cs_new_protected: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}
+% ^^A todo
+% ^^A \section{Rounding}
+% ^^A
+% ^^A This explains how to go from a floating point number to a
+% ^^A rounded value for various applications. Perhaps worth coding
+% ^^A functionalities up to what siunitx can do on this matter.
%
-% \begin{macro}{\fp_div:Nn, \fp_div:cn}
-% \UnitTested
-% \begin{macro}{\fp_gdiv:Nn,\fp_gdiv:cn}
-% \UnitTested
-% \begin{macro}[aux]{\fp_div_aux:NNn}
-% \begin{macro}{\fp_div_internal:}
-% \begin{macro}[aux]{\fp_div_loop:}
-% \begin{macro}[aux]{\fp_div_divide:}
-% \begin{macro}[aux]{\fp_div_divide_aux:}
-% \begin{macro}[aux]{\fp_div_store:}
-% \begin{macro}[aux]{\fp_div_store_integer:}
-% \begin{macro}[aux]{\fp_div_store_decimal:}
-% The pattern is much the same for multiplication.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_div:Nn { \fp_div_aux:NNn \tl_set:Nn }
-\cs_new_protected_nopar:Npn \fp_gdiv:Nn { \fp_div_aux:NNn \tl_gset:Nn }
-\cs_generate_variant:Nn \fp_div:Nn { c }
-\cs_generate_variant:Nn \fp_gdiv:Nn { c }
-% \end{macrocode}
-% Division proper starts with a couple of tests. If the denominator is
-% zero then a error is issued. On the other hand, if the numerator is
-% zero then the result must be $0.0$ and can be given with no
-% further work.
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_div_aux:NNn #1#2#3
- {
- \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
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int
- = \c_zero
- \cs_set_protected:Npx \fp_tmp:w ##1##2
- {
- \group_end:
- #1 \exp_not:N #2 { \c_undefined_fp }
- }
- \else:
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int
- = \c_zero
- \cs_set_protected:Npx \fp_tmp:w ##1##2
- {
- \group_end:
- #1 \exp_not:N #2 { \c_zero_fp }
- }
- \else:
- \exp_after:wN \exp_after:wN \exp_after:wN \fp_div_internal:
- \fi:
- \fi:
- \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_internal: {
- \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
- \int_eval:w
- \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:Npx \fp_tmp:w ##1##2
- {
- \group_end:
- ##1 ##2
- {
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_a_sign_int * \l_fp_input_b_sign_int
- < \c_zero
- \if_int_compare:w
- \int_eval:w
- \l_fp_output_integer_int + \l_fp_output_decimal_int
- = \c_zero
- +
- \else:
- -
- \fi:
- \else:
- +
- \fi:
- \int_use:N \l_fp_output_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \l_fp_output_decimal_int + \c_one_thousand_million
- \int_eval_end:
- e
- \int_use:N \l_fp_output_exponent_int
- }
- }
-}
-% \end{macrocode}
-% 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_count_int \c_zero
- \fp_div_divide:
- \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
- \if_int_compare:w
- \int_eval:w \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int
- > \c_zero
- \if_int_compare:w \l_fp_div_offset_int > \c_zero
- \exp_after:wN \exp_after:wN \exp_after:wN
- \fp_div_loop:
- \fi:
- \fi:
- }
-% \end{macrocode}
-% Checking to see if the numerator can be divides needs quite an
-% involved check. Either the integer part has to be bigger for the
-% numerator or, if it is not smaller then the decimal part of the
-% numerator must not be smaller than that of the denominator. Once
-% the test is right the rest is much as elsewhere.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_div_divide:
- {
- \if_int_compare:w \l_fp_input_a_integer_int > \l_fp_input_b_integer_int
- \exp_after:wN \fp_div_divide_aux:
- \else:
- \if_int_compare:w \l_fp_input_a_integer_int < \l_fp_input_b_integer_int
- \else:
- \if_int_compare:w
- \l_fp_input_a_decimal_int < \l_fp_input_b_decimal_int
- \else:
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \fp_div_divide_aux:
- \fi:
- \fi:
- \fi:
- }
-\cs_new_protected_nopar:Npn \fp_div_divide_aux:
- {
- \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
- \if_int_compare:w \l_fp_input_a_decimal_int < \c_zero
- \tex_advance:D \l_fp_input_a_integer_int \c_minus_one
- \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million
- \fi:
- \fp_div_divide:
- }
-% \end{macrocode}
-% 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 \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
- \int_eval:w
- \l_fp_output_decimal_int +
- \l_fp_count_int * \l_fp_div_offset_int
- \int_eval_end:
- \tex_divide:D \l_fp_div_offset_int \c_ten
- }
-\cs_new_protected:Npn \fp_div_loop_step:w #1#2#3#4#5#6#7#8#9 \q_stop
- {
- \l_fp_input_a_integer_int
- \int_eval:w #2 + \l_fp_input_a_integer_int \int_eval_end:
- \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}
+% ^^A todo
+% ^^A \section{Floating points}
+% ^^A
+% ^^A Here, there may be a discussion of what floating point numbers
+% ^^A are, and a list of relevant resources (\emph{e.g.}, some of
+% ^^A Kahan's articles), and previous \TeX{} packages.
%
-% \subsection{Arithmetic for internal use}
+% \section{Disclaimer and roadmap}
%
-% 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:
+% The package may break down if:
% \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.
+% \item the escape character is either a digit, or an underscore,
+% \item the \tn{uccodes} are changed: the test for whether a character
+% is a letter actually tests if the upper-case code of the character
+% is between A and Z.
% \end{itemize}
-% The 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:Npn \fp_add:NNNNNNNNN #1#2#3#4#5#6#7#8#9
- {
- #7 \int_eval:w #1 + #4 \int_eval_end:
- #8 \int_eval:w #2 + #5 \int_eval_end:
- #9 \int_eval:w #3 + #6 \int_eval_end:
- \if_int_compare:w #9 < \c_one_thousand_million
- \else:
- \tex_advance:D #8 \c_one
- \tex_advance:D #9 -\c_one_thousand_million
- \fi:
- \if_int_compare:w #8 < \c_one_thousand_million
- \else:
- \tex_advance:D #7 \c_one
- \tex_advance:D #8 -\c_one_thousand_million
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\fp_sub:NNNNNNNNN}
-% 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. The flipping flag is
-% used in the rare case where a sign change is possible.
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_sub:NNNNNNNNN #1#2#3#4#5#6#7#8#9
- {
- #7 \int_eval:w #1 - #4 \int_eval_end:
- #8 \int_eval:w #2 - #5 \int_eval_end:
- #9 \int_eval:w #3 - #6 \int_eval_end:
- \if_int_compare:w #9 < \c_zero
- \tex_advance:D #8 \c_minus_one
- \tex_advance:D #9 \c_one_thousand_million
- \fi:
- \if_int_compare:w #8 < \c_zero
- \tex_advance:D #7 \c_minus_one
- \tex_advance:D #8 \c_one_thousand_million
- \fi:
- \if_int_compare:w #7 < \c_zero
- \if_int_compare:w \int_eval:w #8 + #9 = \c_zero
- #7 -#7
- \else:
- \tex_advance:D #7 \c_one
- #8 \int_eval:w \c_one_thousand_million - #8 \int_eval_end:
- #9 \int_eval:w \c_one_thousand_million - #9 \int_eval_end:
- \fi:
- \fi:
- }
-% \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: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_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:
- #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_mul:NNNNNNNNN}
-% For internal multiplication where the integer does need to be
-% retained. This means of course that this code is quite slow, and so
-% is only used when necessary.
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_mul:NNNNNNNNN #1#2#3#4#5#6#7#8#9
- {
- \fp_mul_split:NNNN #2
- \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int
- \fp_mul_split:NNNN #3
- \l_fp_mul_a_iv_int \l_fp_mul_a_v_int \l_fp_mul_a_vi_int
- \fp_mul_split:NNNN #5
- \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int
- \fp_mul_split:NNNN #6
- \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 #1 \l_fp_mul_b_vi_int
- \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_product:NN \l_fp_mul_a_vi_int #4
- \fp_mul_end_level:
- \fp_mul_product:NN #1 \l_fp_mul_b_v_int
- \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_product:NN \l_fp_mul_a_v_int #4
- \fp_mul_end_level:
- \fp_mul_product:NN #1 \l_fp_mul_b_iv_int
- \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_product:NN \l_fp_mul_a_iv_int #4
- \fp_mul_end_level:
- #9 0 \l_fp_mul_output_tl \scan_stop:
- \tl_clear:N \l_fp_mul_output_tl
- \fp_mul_product:NN #1 \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 #4
- \fp_mul_end_level:
- \fp_mul_product:NN #1 \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 #4
- \fp_mul_end_level:
- \fp_mul_product:NN #1 \l_fp_mul_b_i_int
- \fp_mul_product:NN \l_fp_mul_a_i_int #4
- \fp_mul_end_level:
- #8 0 \l_fp_mul_output_tl \scan_stop:
- \tl_clear:N \l_fp_mul_output_tl
- \fp_mul_product:NN #1 #4
- \fp_mul_end_level:
- #7 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:Npn \fp_div_integer:NNNNN #1#2#3#4#5
- {
- \l_fp_internal_int #1
- \tex_divide:D \l_fp_internal_int #3
- \l_fp_internal_int \int_eval:w #1 - \l_fp_internal_int * #3 \int_eval_end:
- #4 #1
- \tex_divide:D #4 #3
- #5 #2
- \tex_divide:D #5 #3
- \tex_multiply:D \l_fp_internal_int \c_one_thousand
- \tex_divide:D \l_fp_internal_int #3
- #5 \int_eval:w #5 + \l_fp_internal_int * \c_one_million \int_eval_end:
- \if_int_compare:w #5 > \c_one_thousand_million
- \tex_advance:D #4 \c_one
- \tex_advance:D #5 -\c_one_thousand_million
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\fp_extended_normalise:}
-% \begin{macro}[aux]{\fp_extended_normalise_aux_i:}
-% \begin{macro}[aux]{\fp_extended_normalise_aux_i:w}
-% \begin{macro}[aux]{\fp_extended_normalise_aux_ii:w}
-% \begin{macro}[aux]{\fp_extended_normalise_aux_ii:}
-% \begin{macro}[aux]{\fp_extended_normalise_aux:NNNNNNNNN}
-% The \enquote{extended} integers for internal use are mainly used in
-% fixed-point mode. This comes up in a few places, so a generalised
-% utility is made available to carry out the change. This function
-% simply calls the two loops to shift the input to the point of
-% having a zero exponent.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_extended_normalise:
- {
- \fp_extended_normalise_aux_i:
- \fp_extended_normalise_aux_ii:
- }
-\cs_new_protected_nopar:Npn \fp_extended_normalise_aux_i:
- {
- \if_int_compare:w \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_extended_normalise_aux_i:w
- \int_use:N \l_fp_input_a_decimal_int \q_stop
- \exp_after:wN \fp_extended_normalise_aux_i:
- \fi:
- }
-\cs_new_protected:Npn \fp_extended_normalise_aux_i:w
- #1#2#3#4#5#6#7#8#9 \q_stop
- {
- \l_fp_input_a_integer_int
- \int_eval:w \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_extended_int \c_one_thousand_million
- \exp_after:wN \fp_extended_normalise_aux_ii:w
- \int_use:N \l_fp_input_a_extended_int \q_stop
- }
-\cs_new_protected:Npn \fp_extended_normalise_aux_ii:w
- #1#2#3#4#5#6#7#8#9 \q_stop
- {
- \l_fp_input_a_decimal_int
- \int_eval:w \l_fp_input_a_decimal_int + #2 \scan_stop:
- \l_fp_input_a_extended_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_extended_normalise_aux_ii:
- {
- \if_int_compare:w \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_extended_normalise_ii_aux:NNNNNNNNN
- \int_use:N \l_fp_input_a_decimal_int
- \exp_after:wN \fp_extended_normalise_aux_ii:
- \fi:
- }
-\cs_new_protected:Npn \fp_extended_normalise_ii_aux:NNNNNNNNN
- #1#2#3#4#5#6#7#8#9
- {
- \if_int_compare:w \l_fp_input_a_integer_int = \c_zero
- \l_fp_input_a_decimal_int #1#2#3#4#5#6#7#8 \scan_stop:
- \else:
- \tl_set:Nx \l_fp_internal_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_internal_tl \scan_stop:
- \fi:
- \tex_divide:D \l_fp_input_a_extended_int \c_ten
- \tl_set:Nx \l_fp_internal_tl
- {
- #9
- \int_use:N \l_fp_input_a_extended_int
- }
- \l_fp_input_a_extended_int \l_fp_internal_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}
-% \end{macro}
-%
-% \begin{macro}{\fp_extended_normalise_output:}
-% \begin{macro}[aux]{\fp_extended_normalise_output_aux_i:NNNNNNNNN}
-% \begin{macro}[aux]{\fp_extended_normalise_output_aux_ii:NNNNNNNNN}
-% \begin{macro}[aux]{\fp_extended_normalise_output_aux:N}
-% At some stages in working out extended output, it is possible for the
-% value to need shifting to keep the integer part in range. This only
-% ever happens such that the integer needs to be made smaller.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_extended_normalise_output:
- {
- \if_int_compare:w \l_fp_output_integer_int > \c_nine
- \tex_advance:D \l_fp_output_integer_int \c_one_thousand_million
- \exp_after:wN \use_i:nn \exp_after:wN
- \fp_extended_normalise_output_aux_i:NNNNNNNNN
- \int_use:N \l_fp_output_integer_int
- \exp_after:wN \fp_extended_normalise_output:
- \fi:
- }
-\cs_new_protected:Npn \fp_extended_normalise_output_aux_i:NNNNNNNNN
- #1#2#3#4#5#6#7#8#9
- {
- \l_fp_output_integer_int #1#2#3#4#5#6#7#8 \scan_stop:
- \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million
- \tl_set:Nx \l_fp_internal_tl
- {
- #9
- \exp_after:wN \use_none:n
- \int_use:N \l_fp_output_decimal_int
- }
- \exp_after:wN \fp_extended_normalise_output_aux_ii:NNNNNNNNN
- \l_fp_internal_tl
- }
-\cs_new_protected:Npn \fp_extended_normalise_output_aux_ii:NNNNNNNNN
- #1#2#3#4#5#6#7#8#9
- {
- \l_fp_output_decimal_int #1#2#3#4#5#6#7#8#9 \scan_stop:
- \fp_extended_normalise_output_aux:N
- }
-\cs_new_protected:Npn \fp_extended_normalise_output_aux:N #1
- {
- \tex_advance:D \l_fp_output_extended_int \c_one_thousand_million
- \tex_divide:D \l_fp_output_extended_int \c_ten
- \tl_set:Nx \l_fp_internal_tl
- {
- #1
- \exp_after:wN \use_none:n
- \int_use:N \l_fp_output_extended_int
- }
- \l_fp_output_extended_int \l_fp_internal_tl \scan_stop:
- \tex_advance:D \l_fp_output_exponent_int \c_one
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Trigonometric functions}
-%
-% \begin{macro}{\fp_trig_normalise:}
-% \begin{macro}[aux]{\fp_trig_normalise_aux:}
-% \begin{macro}[aux]{\fp_trig_sub:NNN}
-% 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:
- {
- \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten
- \l_fp_input_a_extended_int \c_zero
- \fp_extended_normalise:
- \fp_trig_normalise_aux:
- \if_int_compare:w \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
- \fi:
- \exp_after:wN \fp_trig_octant:
- \else:
- \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:
- \fi:
- }
-\cs_new_protected_nopar:Npn \fp_trig_normalise_aux:
- {
- \if_int_compare:w \l_fp_input_a_integer_int > \c_three
- \fp_trig_sub:NNN
- \c_six \c_fp_two_pi_decimal_int \c_fp_two_pi_extended_int
- \exp_after:wN \fp_trig_normalise_aux:
- \else:
- \if_int_compare:w \l_fp_input_a_integer_int > \c_two
- \if_int_compare:w \l_fp_input_a_decimal_int > \c_fp_pi_decimal_int
- \fp_trig_sub:NNN
- \c_six \c_fp_two_pi_decimal_int \c_fp_two_pi_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:
- \fi:
- \fi:
- \fi:
- }
-% \end{macrocode}
-% Here, there may be a sign change but there will never be any
-% variation in the input. So a dedicated function can be used.
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_trig_sub:NNN #1#2#3
- {
- \l_fp_input_a_integer_int
- \int_eval:w \l_fp_input_a_integer_int - #1 \int_eval_end:
- \l_fp_input_a_decimal_int
- \int_eval:w \l_fp_input_a_decimal_int - #2 \int_eval_end:
- \l_fp_input_a_extended_int
- \int_eval:w \l_fp_input_a_extended_int - #3 \int_eval_end:
- \if_int_compare:w \l_fp_input_a_extended_int < \c_zero
- \tex_advance:D \l_fp_input_a_decimal_int \c_minus_one
- \tex_advance:D \l_fp_input_a_extended_int \c_one_thousand_million
- \fi:
- \if_int_compare:w \l_fp_input_a_decimal_int < \c_zero
- \tex_advance:D \l_fp_input_a_integer_int \c_minus_one
- \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million
- \fi:
- \if_int_compare:w \l_fp_input_a_integer_int < \c_zero
- \l_fp_input_a_sign_int -\l_fp_input_a_sign_int
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int
- = \c_zero
- \l_fp_input_a_integer_int -\l_fp_input_a_integer_int
- \else:
- \l_fp_input_a_integer_int
- \int_eval:w
- - \l_fp_input_a_integer_int - \c_one
- \int_eval_end:
- \l_fp_input_a_decimal_int
- \int_eval:w
- \c_one_thousand_million - \l_fp_input_a_decimal_int
- \int_eval_end:
- \l_fp_input_a_extended_int
- \int_eval:w
- \c_one_thousand_million - \l_fp_input_a_extended_int
- \int_eval_end:
- \fi:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\fp_trig_octant:}
-% \begin{macro}[aux]
-% {\fp_trig_octant_aux_i:, \fp_trig_octant_aux_ii:}
-% Here, the input is further reduced into the range
-% $ 0 < x \le \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 \enquote{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 $. The check for octant $4$ is needed as an exact
-% $\pi$ input will otherwise end up in the wrong place!
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_trig_octant:
- {
- \l_fp_trig_octant_int \c_one
- \fp_trig_octant_aux_i:
- \if_int_compare:w \l_fp_input_a_decimal_int < \c_ten
- \l_fp_input_a_decimal_int \c_zero
- \l_fp_input_a_extended_int \c_zero
- \fi:
- \if_int_odd:w \l_fp_trig_octant_int
- \else:
- \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
- \fi:
- }
-\cs_new_protected_nopar:Npn \fp_trig_octant_aux_i:
- {
- \if_int_compare:w \l_fp_trig_octant_int > \c_four
- \l_fp_trig_octant_int \c_four
- \l_fp_input_a_decimal_int \c_fp_pi_by_four_decimal_int
- \l_fp_input_a_extended_int \c_fp_pi_by_four_extended_int
- \else:
- \exp_after:wN \fp_trig_octant_aux_ii:
- \fi:
- }
-\cs_new_protected_nopar:Npn \fp_trig_octant_aux_ii:
- {
- \if_int_compare:w \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_i:
- \else:
- \if_int_compare:w
- \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_i:
- \fi:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\fp_sin:Nn, \fp_sin:cn}
-% \UnitTested
-% \begin{macro}{\fp_gsin:Nn,\fp_gsin:cn}
-% \UnitTested
-% \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: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_arg_tl
- {
- \if_int_compare:w \l_fp_input_a_sign_int < \c_zero
- -
- \else:
- +
- \fi:
- \int_use:N \l_fp_input_a_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \l_fp_input_a_decimal_int + \c_one_thousand_million
- e
- \int_use:N \l_fp_input_a_exponent_int
- }
- \if_int_compare:w \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_arg_tl }
- }
- \else:
- \if_cs_exist:w
- c_fp_sin ( \l_fp_arg_tl ) _fp
- \cs_end:
- \else:
- \exp_after:wN \exp_after:wN \exp_after:wN
- \fp_sin_aux_i:
- \fi:
- \cs_set_protected_nopar:Npx \fp_tmp:w
- {
- \group_end:
- #1 \exp_not:N #2
- { \use:c { c_fp_sin ( \l_fp_arg_tl ) _fp } }
- }
- \fi:
- \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:
- \if_int_compare:w \l_fp_output_integer_int = \c_one
- \l_fp_output_exponent_int \c_zero
- \else:
- \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
- \fi:
- \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_arg_tl ) _fp }
- \tl_gset:cx { c_fp_sin ( \l_fp_arg_tl ) _fp }
- {
- \if_int_compare:w \l_fp_input_a_sign_int > \c_zero
- +
- \else:
- -
- \fi:
- \int_use:N \l_fp_output_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \l_fp_output_decimal_int + \c_one_thousand_million
- e
- \int_use:N \l_fp_output_exponent_int
- }
- }
-\cs_new_protected_nopar:Npn \fp_sin_aux_ii:
- {
- \if_case:w \l_fp_trig_octant_int
- \or:
- \exp_after:wN \fp_trig_calc_sin:
- \or:
- \exp_after:wN \fp_trig_calc_cos:
- \or:
- \exp_after:wN \fp_trig_calc_cos:
- \or:
- \exp_after:wN \fp_trig_calc_sin:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\fp_cos:Nn, \fp_cos:cn}
-% \UnitTested
-% \begin{macro}{\fp_gcos:Nn,\fp_gcos:cn}
-% \UnitTested
-% \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: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_arg_tl
- {
- \if_int_compare:w \l_fp_input_a_sign_int < \c_zero
- -
- \else:
- +
- \fi:
- \int_use:N \l_fp_input_a_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \l_fp_input_a_decimal_int + \c_one_thousand_million
- e
- \int_use:N \l_fp_input_a_exponent_int
- }
- \if_cs_exist:w c_fp_cos ( \l_fp_arg_tl ) _fp \cs_end:
- \else:
- \exp_after:wN \fp_cos_aux_i:
- \fi:
- \cs_set_protected_nopar:Npx \fp_tmp:w
- {
- \group_end:
- #1 \exp_not:N #2
- { \use:c { c_fp_cos ( \l_fp_arg_tl ) _fp } }
- }
- \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:
- \if_int_compare:w \l_fp_output_integer_int = \c_one
- \l_fp_output_exponent_int \c_zero
- \else:
- \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
- \fi:
- \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_arg_tl ) _fp }
- \tl_gset:cx { c_fp_cos ( \l_fp_arg_tl ) _fp }
- {
- \if_int_compare:w \l_fp_input_a_sign_int > \c_zero
- +
- \else:
- -
- \fi:
- \int_use:N \l_fp_output_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \l_fp_output_decimal_int + \c_one_thousand_million
- e
- \int_use:N \l_fp_output_exponent_int
- }
- }
-\cs_new_protected_nopar:Npn \fp_cos_aux_ii:
- {
- \if_case:w \l_fp_trig_octant_int
- \or:
- \exp_after:wN \fp_trig_calc_cos:
- \or:
- \exp_after:wN \fp_trig_calc_sin:
- \or:
- \exp_after:wN \fp_trig_calc_sin:
- \or:
- \exp_after:wN \fp_trig_calc_cos:
- \fi:
- \if_int_compare:w \l_fp_input_a_sign_int > \c_zero
- \if_int_compare:w \l_fp_trig_octant_int > \c_two
- \l_fp_input_a_sign_int \c_minus_one
- \fi:
- \else:
- \if_int_compare:w \l_fp_trig_octant_int > \c_two
- \else:
- \l_fp_input_a_sign_int \c_one
- \fi:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\fp_trig_calc_cos:}
-% \begin{macro}{\fp_trig_calc_sin:}
-% \begin{macro}[aux]{\fp_trig_calc_Taylor:}
-% These functions actually do the calculation for sine and cosine.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_trig_calc_cos:
- {
- \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero
- \l_fp_output_integer_int \c_one
- \l_fp_output_decimal_int \c_zero
- \else:
- \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
- \if_int_compare:w \l_fp_trig_extended_int = \c_zero
- \if_int_compare:w \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
- \else:
- \l_fp_output_integer_int \c_zero
- \l_fp_output_decimal_int \c_one_thousand_million
- \l_fp_output_extended_int \c_zero
- \fi:
- \else:
- \l_fp_output_integer_int \c_zero
- \l_fp_output_decimal_int 999999999 \scan_stop:
- \l_fp_output_extended_int \c_one_thousand_million
- \fi:
- \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_Taylor:
- \fi:
- }
-\cs_new_protected_nopar:Npn \fp_trig_calc_sin:
- {
- \l_fp_output_integer_int \c_zero
- \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero
- \l_fp_output_decimal_int \c_zero
- \else:
- \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_Taylor:
- \fi:
- }
-% \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_Taylor:
- {
- \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
- \if_int_compare:w \l_fp_trig_decimal_int > \c_zero
- \if_int_compare:w \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
- \if_int_compare:w \l_fp_output_extended_int < \c_one_thousand_million
- \else:
- \tex_advance:D \l_fp_output_decimal_int \c_one
- \tex_advance:D \l_fp_output_extended_int
- -\c_one_thousand_million
- \fi:
- \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million
- \else:
- \tex_advance:D \l_fp_output_integer_int \c_one
- \tex_advance:D \l_fp_output_decimal_int
- -\c_one_thousand_million
- \fi:
- \else:
- \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
- \if_int_compare:w \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
- \fi:
- \if_int_compare:w \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
- \fi:
- \fi:
- \exp_after:wN \fp_trig_calc_Taylor:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\fp_tan:Nn, \fp_tan:cn}
-% \UnitTested
-% \begin{macro}{\fp_gtan:Nn,\fp_gtan:cn}
-% \UnitTested
-% \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: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_arg_tl
- {
- \if_int_compare:w \l_fp_input_a_sign_int < \c_zero
- -
- \else:
- +
- \fi:
- \int_use:N \l_fp_input_a_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \l_fp_input_a_decimal_int + \c_one_thousand_million
- e
- \int_use:N \l_fp_input_a_exponent_int
- }
- \if_int_compare:w \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_arg_tl }
- }
- \else:
- \if_cs_exist:w
- c_fp_tan ( \l_fp_arg_tl ) _fp
- \cs_end:
- \else:
- \exp_after:wN \exp_after:wN \exp_after:wN
- \fp_tan_aux_i:
- \fi:
- \cs_set_protected_nopar:Npx \fp_tmp:w
- {
- \group_end:
- #1 \exp_not:N #2
- { \use:c { c_fp_tan ( \l_fp_arg_tl ) _fp } }
- }
- \fi:
- \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 \enquote{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:
- {
- \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten
- \exp_after:wN \fp_tan_aux_ii:
- \else:
- \cs_new_eq:cN { c_fp_tan ( \l_fp_arg_tl ) _fp }
- \c_zero_fp
- \exp_after:wN \fp_trig_overflow_msg:
- \fi:
- }
-\cs_new_protected_nopar:Npn \fp_tan_aux_ii:
- {
- \fp_trig_normalise:
- \if_int_compare:w \l_fp_input_a_sign_int > \c_zero
- \if_int_compare:w \l_fp_trig_octant_int > \c_two
- \l_fp_output_sign_int \c_minus_one
- \else:
- \l_fp_output_sign_int \c_one
- \fi:
- \else:
- \if_int_compare:w \l_fp_trig_octant_int > \c_two
- \l_fp_output_sign_int \c_one
- \else:
- \l_fp_output_sign_int \c_minus_one
- \fi:
- \fi:
- \fp_cos_aux_ii:
- \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero
- \if_int_compare:w \l_fp_input_a_integer_int = \c_zero
- \cs_new_eq:cN { c_fp_tan ( \l_fp_arg_tl ) _fp }
- \c_undefined_fp
- \else:
- \exp_after:wN \exp_after:wN \exp_after:wN
- \fp_tan_aux_iii:
- \fi:
- \else:
- \exp_after:wN \fp_tan_aux_iii:
- \fi:
- }
-% \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
- \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero
- \if_int_compare:w \l_fp_input_a_integer_int = \c_zero
- \cs_new_eq:cN { c_fp_tan ( \l_fp_arg_tl ) _fp }
- \c_zero_fp
- \else:
- \exp_after:wN \exp_after:wN \exp_after:wN \fp_tan_aux_iv:
- \fi:
- \else:
- \exp_after:wN \fp_tan_aux_iv:
- \fi:
- }
-\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
- \int_eval:w
- \l_fp_input_a_exponent_int - \l_fp_input_b_exponent_int
- \int_eval_end:
- \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_arg_tl ) _fp }
- \tl_gset:cx { c_fp_tan ( \l_fp_arg_tl ) _fp }
- {
- \if_int_compare:w \l_fp_output_sign_int > \c_zero
- +
- \else:
- -
- \fi:
- \int_use:N \l_fp_output_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \l_fp_output_decimal_int + \c_one_thousand_million
- 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}
-%
-% \subsection{Exponent and logarithm functions}
-%
-% \begin{variable}{\c_fp_exp_1_tl}
-% \begin{variable}{\c_fp_exp_2_tl}
-% \begin{variable}{\c_fp_exp_3_tl}
-% \begin{variable}{\c_fp_exp_4_tl}
-% \begin{variable}{\c_fp_exp_5_tl}
-% \begin{variable}{\c_fp_exp_6_tl}
-% \begin{variable}{\c_fp_exp_7_tl}
-% \begin{variable}{\c_fp_exp_8_tl}
-% \begin{variable}{\c_fp_exp_9_tl}
-% \begin{variable}{\c_fp_exp_10_tl}
-% \begin{variable}{\c_fp_exp_20_tl}
-% \begin{variable}{\c_fp_exp_30_tl}
-% \begin{variable}{\c_fp_exp_40_tl}
-% \begin{variable}{\c_fp_exp_50_tl}
-% \begin{variable}{\c_fp_exp_60_tl}
-% \begin{variable}{\c_fp_exp_70_tl}
-% \begin{variable}{\c_fp_exp_80_tl}
-% \begin{variable}{\c_fp_exp_90_tl}
-% \begin{variable}{\c_fp_exp_100_tl}
-% \begin{variable}{\c_fp_exp_200_tl}
-% Calculation of exponentials requires a number of precomputed values:
-% first the positive integers.
-% \begin{macrocode}
-\tl_const:cn { c_fp_exp_1_tl } { { 2 } { 718281828 } { 459045235 } { 0 } }
-\tl_const:cn { c_fp_exp_2_tl } { { 7 } { 389056098 } { 930650227 } { 0 } }
-\tl_const:cn { c_fp_exp_3_tl } { { 2 } { 008553692 } { 318766774 } { 1 } }
-\tl_const:cn { c_fp_exp_4_tl } { { 5 } { 459815003 } { 314423908 } { 1 } }
-\tl_const:cn { c_fp_exp_5_tl } { { 1 } { 484131591 } { 025766034 } { 2 } }
-\tl_const:cn { c_fp_exp_6_tl } { { 4 } { 034287934 } { 927351226 } { 2 } }
-\tl_const:cn { c_fp_exp_7_tl } { { 1 } { 096633158 } { 428458599 } { 3 } }
-\tl_const:cn { c_fp_exp_8_tl } { { 2 } { 980957987 } { 041728275 } { 3 } }
-\tl_const:cn { c_fp_exp_9_tl } { { 8 } { 103083927 } { 575384008 } { 3 } }
-\tl_const:cn { c_fp_exp_10_tl } { { 2 } { 202646579 } { 480671652 } { 4 } }
-\tl_const:cn { c_fp_exp_20_tl } { { 4 } { 851651954 } { 097902280 } { 8 } }
-\tl_const:cn { c_fp_exp_30_tl } { { 1 } { 068647458 } { 152446215 } { 13 } }
-\tl_const:cn { c_fp_exp_40_tl } { { 2 } { 353852668 } { 370199854 } { 17 } }
-\tl_const:cn { c_fp_exp_50_tl } { { 5 } { 184705528 } { 587072464 } { 21 } }
-\tl_const:cn { c_fp_exp_60_tl } { { 1 } { 142007389 } { 815684284 } { 26 } }
-\tl_const:cn { c_fp_exp_70_tl } { { 2 } { 515438670 } { 919167006 } { 30 } }
-\tl_const:cn { c_fp_exp_80_tl } { { 5 } { 540622384 } { 393510053 } { 34 } }
-\tl_const:cn { c_fp_exp_90_tl } { { 1 } { 220403294 } { 317840802 } { 39 } }
-\tl_const:cn { c_fp_exp_100_tl } { { 2 } { 688117141 } { 816135448 } { 43 } }
-\tl_const:cn { c_fp_exp_200_tl } { { 7 } { 225973768 } { 125749258 } { 86 } }
-% \end{macrocode}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-%
-% \begin{variable}{\c_fp_exp_-1_tl}
-% \begin{variable}{\c_fp_exp_-2_tl}
-% \begin{variable}{\c_fp_exp_-3_tl}
-% \begin{variable}{\c_fp_exp_-4_tl}
-% \begin{variable}{\c_fp_exp_-5_tl}
-% \begin{variable}{\c_fp_exp_-6_tl}
-% \begin{variable}{\c_fp_exp_-7_tl}
-% \begin{variable}{\c_fp_exp_-8_tl}
-% \begin{variable}{\c_fp_exp_-9_tl}
-% \begin{variable}{\c_fp_exp_-10_tl}
-% \begin{variable}{\c_fp_exp_-20_tl}
-% \begin{variable}{\c_fp_exp_-30_tl}
-% \begin{variable}{\c_fp_exp_-40_tl}
-% \begin{variable}{\c_fp_exp_-50_tl}
-% \begin{variable}{\c_fp_exp_-60_tl}
-% \begin{variable}{\c_fp_exp_-70_tl}
-% \begin{variable}{\c_fp_exp_-80_tl}
-% \begin{variable}{\c_fp_exp_-90_tl}
-% \begin{variable}{\c_fp_exp_-100_tl}
-% \begin{variable}{\c_fp_exp_-200_tl}
-% Now the negative integers.
-% \begin{macrocode}
-\tl_const:cn { c_fp_exp_-1_tl } { { 3 } { 678794411 } { 71442322 } { -1 } }
-\tl_const:cn { c_fp_exp_-2_tl } { { 1 } { 353352832 } { 366132692 } { -1 } }
-\tl_const:cn { c_fp_exp_-3_tl } { { 4 } { 978706836 } { 786394298 } { -2 } }
-\tl_const:cn { c_fp_exp_-4_tl } { { 1 } { 831563888 } { 873418029 } { -2 } }
-\tl_const:cn { c_fp_exp_-5_tl } { { 6 } { 737946999 } { 085467097 } { -3 } }
-\tl_const:cn { c_fp_exp_-6_tl } { { 2 } { 478752176 } { 666358423 } { -3 } }
-\tl_const:cn { c_fp_exp_-7_tl } { { 9 } { 118819655 } { 545162080 } { -4 } }
-\tl_const:cn { c_fp_exp_-8_tl } { { 3 } { 354626279 } { 025118388 } { -4 } }
-\tl_const:cn { c_fp_exp_-9_tl } { { 1 } { 234098040 } { 866795495 } { -4 } }
-\tl_const:cn { c_fp_exp_-10_tl } { { 4 } { 539992976 } { 248451536 } { -5 } }
-\tl_const:cn { c_fp_exp_-20_tl } { { 2 } { 061153622 } { 438557828 } { -9 } }
-\tl_const:cn { c_fp_exp_-30_tl } { { 9 } { 357622968 } { 840174605 } { -14 } }
-\tl_const:cn { c_fp_exp_-40_tl } { { 4 } { 248354255 } { 291588995 } { -18 } }
-\tl_const:cn { c_fp_exp_-50_tl } { { 1 } { 928749847 } { 963917783 } { -22 } }
-\tl_const:cn { c_fp_exp_-60_tl } { { 8 } { 756510762 } { 696520338 } { -27 } }
-\tl_const:cn { c_fp_exp_-70_tl } { { 3 } { 975449735 } { 908646808 } { -31 } }
-\tl_const:cn { c_fp_exp_-80_tl } { { 1 } { 804851387 } { 845415172 } { -35 } }
-\tl_const:cn { c_fp_exp_-90_tl } { { 8 } { 194012623 } { 990515430 } { -40 } }
-\tl_const:cn { c_fp_exp_-100_tl } { { 3 } { 720075976 } { 020835963 } { -44 } }
-\tl_const:cn { c_fp_exp_-200_tl } { { 1 } { 383896526 } { 736737530 } { -87 } }
-% \end{macrocode}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-%
-% \begin{macro}{\fp_exp:Nn, \fp_exp:cn}
-% \UnitTested
-% \begin{macro}{\fp_gexp:Nn,\fp_gexp:cn}
-% \UnitTested
-% \begin{macro}[aux]{\fp_exp_aux:NNn}
-% \begin{macro}[aux]{\fp_exp_internal:}
-% \begin{macro}[aux]{\fp_exp_aux:}
-% \begin{macro}[aux]{\fp_exp_integer:}
-% \begin{macro}[aux]{\fp_exp_integer_tens:}
-% \begin{macro}[aux]{\fp_exp_integer_units:}
-% \begin{macro}[aux]{\fp_exp_integer_const:n}
-% \begin{macro}[aux]{\fp_exp_integer_const:nnnn}
-% \begin{macro}[aux]{\fp_exp_decimal:}
-% \begin{macro}[aux]{\fp_exp_Taylor:}
-% \begin{macro}[aux]{\fp_exp_const:Nx}
-% \begin{macro}[aux]{\fp_exp_const:cx}
-% The calculation of an exponent starts off starts in much the same
-% way as the trigonometric functions: normalise the input, look for
-% a pre-defined value and if one is not found hand off to the real
-% workhorse function. The test for a definition of the result is used
-% so that overflows do not result in any outcome being defined.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_exp:Nn { \fp_exp_aux:NNn \tl_set:Nn }
-\cs_new_protected_nopar:Npn \fp_gexp:Nn { \fp_exp_aux:NNn \tl_gset:Nn }
-\cs_generate_variant:Nn \fp_exp:Nn { c }
-\cs_generate_variant:Nn \fp_gexp:Nn { c }
-\cs_new_protected:Npn \fp_exp_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
- \l_fp_input_a_extended_int \c_zero
- \tl_set:Nx \l_fp_arg_tl
- {
- \if_int_compare:w \l_fp_input_a_sign_int < \c_zero
- -
- \else:
- +
- \fi:
- \int_use:N \l_fp_input_a_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \l_fp_input_a_decimal_int + \c_one_thousand_million
- e
- \int_use:N \l_fp_input_a_exponent_int
- }
- \if_cs_exist:w c_fp_exp ( \l_fp_arg_tl ) _fp \cs_end:
- \else:
- \exp_after:wN \fp_exp_internal:
- \fi:
- \cs_set_protected_nopar:Npx \fp_tmp:w
- {
- \group_end:
- #1 \exp_not:N #2
- {
- \if_cs_exist:w c_fp_exp ( \l_fp_arg_tl ) _fp
- \cs_end:
- \use:c { c_fp_exp ( \l_fp_arg_tl ) _fp }
- \else:
- \c_zero_fp
- \fi:
- }
- }
- \fp_tmp:w
- }
-% \end{macrocode}
-% The first real step is to convert the input into a fixed-point
-% representation for further calculation: anything which is dropped
-% here as too small would not influence the output in any case. There
-% are a couple of overflow tests: the maximum
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_exp_internal:
- {
- \if_int_compare:w \l_fp_input_a_exponent_int < \c_three
- \fp_extended_normalise:
- \if_int_compare:w \l_fp_input_a_sign_int > \c_zero
- \if_int_compare:w \l_fp_input_a_integer_int < 230 \scan_stop:
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \fp_exp_aux:
- \else:
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \fp_exp_overflow_msg:
- \fi:
- \else:
- \if_int_compare:w \l_fp_input_a_integer_int < 230 \scan_stop:
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \fp_exp_aux:
- \else:
- \fp_exp_const:cx { c_fp_exp ( \l_fp_arg_tl ) _fp }
- { \c_zero_fp }
- \fi:
- \fi:
- \else:
- \exp_after:wN \fp_exp_overflow_msg:
- \fi:
- }
-% \end{macrocode}
-% The main algorithm makes use of the fact that
-% \[
-% \mathrm{e}^{nmp.q} =
-% \mathrm{e}^{n}
-% \mathrm{e}^{m}
-% \mathrm{e}^{p}
-% \mathrm{e}^{0.q}
-% \]
-% and that there is a Taylor series that can be used to calculate
-% $ \mathrm{e}^{0.q} $. Thus the approach needed is in three parts.
-% First, the exponent of the integer part of the input is found
-% using the pre-calculated constants. Second, the Taylor series is
-% used to find the exponent for the decimal part of the input. Finally,
-% the two parts are multiplied together to give the result. As the
-% normalisation code will already have dealt with any overflowing
-% values, there are no further checks needed.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_exp_aux:
- {
- \if_int_compare:w \l_fp_input_a_integer_int > \c_zero
- \exp_after:wN \fp_exp_integer:
- \else:
- \l_fp_output_integer_int \c_one
- \l_fp_output_decimal_int \c_zero
- \l_fp_output_extended_int \c_zero
- \l_fp_output_exponent_int \c_zero
- \exp_after:wN \fp_exp_decimal:
- \fi:
- }
-% \end{macrocode}
-% The integer part calculation starts with the hundreds. This is
-% set up such that very large negative numbers can short-cut the entire
-% procedure and simply return zero. In other cases, the code either
-% recovers the exponent of the hundreds value or sets the appropriate
-% storage to one (so that multiplication works correctly).
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_exp_integer:
- {
- \if_int_compare:w \l_fp_input_a_integer_int < \c_one_hundred
- \l_fp_exp_integer_int \c_one
- \l_fp_exp_decimal_int \c_zero
- \l_fp_exp_extended_int \c_zero
- \l_fp_exp_exponent_int \c_zero
- \exp_after:wN \fp_exp_integer_tens:
- \else:
- \tl_set:Nx \l_fp_internal_tl
- {
- \exp_after:wN \use_i:nnn
- \int_use:N \l_fp_input_a_integer_int
- }
- \l_fp_input_a_integer_int
- \int_eval:w
- \l_fp_input_a_integer_int - \l_fp_internal_tl 00
- \int_eval_end:
- \if_int_compare:w \l_fp_input_a_sign_int < \c_zero
- \if_int_compare:w \l_fp_output_integer_int > 200 \scan_stop:
- \fp_exp_const:cx { c_fp_exp ( \l_fp_arg_tl ) _fp }
- { \c_zero_fp }
- \else:
- \fp_exp_integer_const:n { - \l_fp_internal_tl 00 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \fp_exp_integer_tens:
- \fi:
- \else:
- \fp_exp_integer_const:n { \l_fp_internal_tl 00 }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \fp_exp_integer_tens:
- \fi:
- \fi:
- }
-% \end{macrocode}
-% The tens and units parts are handled in a similar way, with a
-% multiplication step to build up the final value. That also includes a
-% correction step to avoid an overflow of the integer part.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_exp_integer_tens:
- {
- \l_fp_output_integer_int \l_fp_exp_integer_int
- \l_fp_output_decimal_int \l_fp_exp_decimal_int
- \l_fp_output_extended_int \l_fp_exp_extended_int
- \l_fp_output_exponent_int \l_fp_exp_exponent_int
- \if_int_compare:w \l_fp_input_a_integer_int > \c_nine
- \tl_set:Nx \l_fp_internal_tl
- {
- \exp_after:wN \use_i:nn
- \int_use:N \l_fp_input_a_integer_int
- }
- \l_fp_input_a_integer_int
- \int_eval:w
- \l_fp_input_a_integer_int - \l_fp_internal_tl 0
- \int_eval_end:
- \if_int_compare:w \l_fp_input_a_sign_int > \c_zero
- \fp_exp_integer_const:n { \l_fp_internal_tl 0 }
- \else:
- \fp_exp_integer_const:n { - \l_fp_internal_tl 0 }
- \fi:
- \fp_mul:NNNNNNNNN
- \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int
- \l_fp_output_integer_int \l_fp_output_decimal_int
- \l_fp_output_extended_int
- \l_fp_output_integer_int \l_fp_output_decimal_int
- \l_fp_output_extended_int
- \tex_advance:D \l_fp_output_exponent_int \l_fp_exp_exponent_int
- \fp_extended_normalise_output:
- \fi:
- \fp_exp_integer_units:
- }
-\cs_new_protected_nopar:Npn \fp_exp_integer_units:
- {
- \if_int_compare:w \l_fp_input_a_integer_int > \c_zero
- \if_int_compare:w \l_fp_input_a_sign_int > \c_zero
- \fp_exp_integer_const:n { \int_use:N \l_fp_input_a_integer_int }
- \else:
- \fp_exp_integer_const:n
- { - \int_use:N \l_fp_input_a_integer_int }
- \fi:
- \fp_mul:NNNNNNNNN
- \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int
- \l_fp_output_integer_int \l_fp_output_decimal_int
- \l_fp_output_extended_int
- \l_fp_output_integer_int \l_fp_output_decimal_int
- \l_fp_output_extended_int
- \tex_advance:D \l_fp_output_exponent_int \l_fp_exp_exponent_int
- \fp_extended_normalise_output:
- \fi:
- \fp_exp_decimal:
- }
-% \end{macrocode}
-% Recovery of the stored constant values into the separate registers
-% is done with a simple expansion then assignment.
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_exp_integer_const:n #1
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \fp_exp_integer_const:nnnn
- \cs:w c_fp_exp_ #1 _tl \cs_end:
- }
-\cs_new_protected:Npn \fp_exp_integer_const:nnnn #1#2#3#4
- {
- \l_fp_exp_integer_int #1 \scan_stop:
- \l_fp_exp_decimal_int #2 \scan_stop:
- \l_fp_exp_extended_int #3 \scan_stop:
- \l_fp_exp_exponent_int #4 \scan_stop:
- }
-% \end{macrocode}
-% Finding the exponential for the decimal part of the number requires
-% a Taylor series calculation. The set up is done here with the loop
-% itself a separate function. Once the decimal part is available this
-% is multiplied by the integer part already worked out to give
-% the final result.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_exp_decimal:
- {
- \if_int_compare:w \l_fp_input_a_decimal_int > \c_zero
- \if_int_compare:w \l_fp_input_a_sign_int > \c_zero
- \l_fp_exp_integer_int \c_one
- \l_fp_exp_decimal_int \l_fp_input_a_decimal_int
- \l_fp_exp_extended_int \l_fp_input_a_extended_int
- \else:
- \l_fp_exp_integer_int \c_zero
- \if_int_compare:w \l_fp_exp_extended_int = \c_zero
- \l_fp_exp_decimal_int
- \int_eval:w
- \c_one_thousand_million - \l_fp_input_a_decimal_int
- \int_eval_end:
- \l_fp_exp_extended_int \c_zero
- \else:
- \l_fp_exp_decimal_int
- \int_eval:w
- 999999999 - \l_fp_input_a_decimal_int
- \scan_stop:
- \l_fp_exp_extended_int
- \int_eval:w
- \c_one_thousand_million - \l_fp_input_a_extended_int
- \int_eval_end:
- \fi:
- \fi:
- \l_fp_input_b_sign_int \l_fp_input_a_sign_int
- \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int
- \l_fp_input_b_extended_int \l_fp_input_a_extended_int
- \l_fp_count_int \c_one
- \fp_exp_Taylor:
- \fp_mul:NNNNNNNNN
- \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int
- \l_fp_output_integer_int \l_fp_output_decimal_int
- \l_fp_output_extended_int
- \l_fp_output_integer_int \l_fp_output_decimal_int
- \l_fp_output_extended_int
- \fi:
- \if_int_compare:w \l_fp_output_extended_int < \c_five_hundred_million
- \else:
- \tex_advance:D \l_fp_output_decimal_int \c_one
- \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million
- \else:
- \l_fp_output_decimal_int \c_zero
- \tex_advance:D \l_fp_output_integer_int \c_one
- \fi:
- \fi:
- \fp_standardise:NNNN
- \l_fp_output_sign_int
- \l_fp_output_integer_int
- \l_fp_output_decimal_int
- \l_fp_output_exponent_int
- \fp_exp_const:cx { c_fp_exp ( \l_fp_arg_tl ) _fp }
- {
- +
- \int_use:N \l_fp_output_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \l_fp_output_decimal_int + \c_one_thousand_million
- e
- \int_use:N \l_fp_output_exponent_int
- }
- }
-% \end{macrocode}
-% The Taylor series for $ \exp(x) $ is
-% \[
-% 1 + x + \frac{x^2}{2!} + \frac{x^3}{3!} + \frac{x^4}{4!} + \cdots
-% \]
-% which converges for $ -1 < x < 1 $. The code above sets up
-% the $ x $ part, leaving the loop to multiply the running
-% value by $ x / n $ and add it onto the sum. The way that this is
-% done is that the running total is stored in the \texttt{exp} set of
-% registers, while the current item is stored as \texttt{input_b}.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_exp_Taylor:
- {
- \tex_advance:D \l_fp_count_int \c_one
- \tex_multiply:D \l_fp_input_b_sign_int \l_fp_input_a_sign_int
- \fp_mul:NNNNNN
- \l_fp_input_a_decimal_int \l_fp_input_a_extended_int
- \l_fp_input_b_decimal_int \l_fp_input_b_extended_int
- \l_fp_input_b_decimal_int \l_fp_input_b_extended_int
- \fp_div_integer:NNNNN
- \l_fp_input_b_decimal_int \l_fp_input_b_extended_int
- \l_fp_count_int
- \l_fp_input_b_decimal_int \l_fp_input_b_extended_int
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_b_decimal_int + \l_fp_input_b_extended_int
- > \c_zero
- \if_int_compare:w \l_fp_input_b_sign_int > \c_zero
- \tex_advance:D \l_fp_exp_decimal_int \l_fp_input_b_decimal_int
- \tex_advance:D \l_fp_exp_extended_int
- \l_fp_input_b_extended_int
- \if_int_compare:w \l_fp_exp_extended_int < \c_one_thousand_million
- \else:
- \tex_advance:D \l_fp_exp_decimal_int \c_one
- \tex_advance:D \l_fp_exp_extended_int
- -\c_one_thousand_million
- \fi:
- \if_int_compare:w \l_fp_exp_decimal_int < \c_one_thousand_million
- \else:
- \tex_advance:D \l_fp_exp_integer_int \c_one
- \tex_advance:D \l_fp_exp_decimal_int
- -\c_one_thousand_million
- \fi:
- \else:
- \tex_advance:D \l_fp_exp_decimal_int -\l_fp_input_b_decimal_int
- \tex_advance:D \l_fp_exp_extended_int
- -\l_fp_input_a_extended_int
- \if_int_compare:w \l_fp_exp_extended_int < \c_zero
- \tex_advance:D \l_fp_exp_decimal_int \c_minus_one
- \tex_advance:D \l_fp_exp_extended_int \c_one_thousand_million
- \fi:
- \if_int_compare:w \l_fp_exp_decimal_int < \c_zero
- \tex_advance:D \l_fp_exp_integer_int \c_minus_one
- \tex_advance:D \l_fp_exp_decimal_int \c_one_thousand_million
- \fi:
- \fi:
- \exp_after:wN \fp_exp_Taylor:
- \fi:
- }
-% \end{macrocode}
-% This is set up as a function so that the power code can redirect
-% the effect.
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_exp_const:Nx #1#2
- {
- \tl_new:N #1
- \tl_gset:Nx #1 {#2}
- }
-\cs_generate_variant:Nn \fp_exp_const:Nx { c }
-% \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}
-%
-% \begin{variable}{\c_fp_ln_10_1_tl}
-% \begin{variable}{\c_fp_ln_10_2_tl}
-% \begin{variable}{\c_fp_ln_10_3_tl}
-% \begin{variable}{\c_fp_ln_10_4_tl}
-% \begin{variable}{\c_fp_ln_10_5_tl}
-% \begin{variable}{\c_fp_ln_10_6_tl}
-% \begin{variable}{\c_fp_ln_10_7_tl}
-% \begin{variable}{\c_fp_ln_10_8_tl}
-% \begin{variable}{\c_fp_ln_10_9_tl}
-% Constants for working out logarithms: first those for the powers of
-% ten.
-% \begin{macrocode}
-\tl_const:cn { c_fp_ln_10_1_tl } { { 2 } { 302585092 } { 994045684 } { 0 } }
-\tl_const:cn { c_fp_ln_10_2_tl } { { 4 } { 605170185 } { 988091368 } { 0 } }
-\tl_const:cn { c_fp_ln_10_3_tl } { { 6 } { 907755278 } { 982137052 } { 0 } }
-\tl_const:cn { c_fp_ln_10_4_tl } { { 9 } { 210340371 } { 976182736 } { 0 } }
-\tl_const:cn { c_fp_ln_10_5_tl } { { 1 } { 151292546 } { 497022842 } { 1 } }
-\tl_const:cn { c_fp_ln_10_6_tl } { { 1 } { 381551055 } { 796427410 } { 1 } }
-\tl_const:cn { c_fp_ln_10_7_tl } { { 1 } { 611809565 } { 095831979 } { 1 } }
-\tl_const:cn { c_fp_ln_10_8_tl } { { 1 } { 842068074 } { 395226547 } { 1 } }
-\tl_const:cn { c_fp_ln_10_9_tl } { { 2 } { 072326583 } { 694641116 } { 1 } }
-% \end{macrocode}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-%^^A 0.69...309 4.
-% \begin{variable}{\c_fp_ln_2_1_tl }
-% \begin{variable}{\c_fp_ln_2_2_tl }
-% \begin{variable}{\c_fp_ln_2_3_tl }
-% The smaller set for powers of two.
-% \begin{macrocode}
-\tl_const:cn { c_fp_ln_2_1_tl } { { 0 } { 693147180 } { 559945309 } { 0 } }
-\tl_const:cn { c_fp_ln_2_2_tl } { { 1 } { 386294361 } { 119890618 } { 0 } }
-\tl_const:cn { c_fp_ln_2_3_tl } { { 2 } { 079441541 } { 679835928 } { 0 } }
-% \end{macrocode}
-% \end{variable}
-% \end{variable}
-% \end{variable}
-%
-% \begin{macro}{\fp_ln:Nn, \fp_ln:cn}
-% \UnitTested
-% \begin{macro}{\fp_gln:Nn,\fp_gln:cn}
-% \UnitTested
-% \begin{macro}[aux]{\fp_ln_aux:NNn}
-% \begin{macro}[aux]{\fp_ln_aux:}
-% \begin{macro}[aux]{\fp_ln_exponent:}
-% \begin{macro}[aux]{\fp_ln_internal:}
-% \begin{macro}[aux]{\fp_ln_exponent_tens:}
-% \begin{macro}[aux]{\fp_ln_exponent_units:}
-% \begin{macro}[aux]{\fp_ln_normalise:}
-% \begin{macro}[aux]{\fp_ln_nornalise_aux:NNNNNNNNN}
-% \begin{macro}[aux]{\fp_ln_mantissa:}
-% \begin{macro}[aux]{\fp_ln_mantissa_aux:}
-% \begin{macro}[aux]{\fp_ln_mantissa_divide_two:}
-% \begin{macro}[aux]{\fp_ln_integer_const:nn}
-% \begin{macro}[aux]{\fp_ln_Taylor:}
-% \begin{macro}[aux]{\fp_ln_fixed:}
-% \begin{macro}[aux]{\fp_ln_fixed_aux:NNNNNNNNN}
-% \begin{macro}[aux]{\fp_ln_Taylor_aux:}
-% The approach for logarithms is again based on a mix of tables and
-% Taylor series. Here, the initial validation is a bit easier and so it
-% is set up earlier, meaning less need to escape later on.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_ln:Nn { \fp_ln_aux:NNn \tl_set:Nn }
-\cs_new_protected_nopar:Npn \fp_gln:Nn { \fp_ln_aux:NNn \tl_gset:Nn }
-\cs_generate_variant:Nn \fp_ln:Nn { c }
-\cs_generate_variant:Nn \fp_gln:Nn { c }
-\cs_new_protected:Npn \fp_ln_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
- \if_int_compare:w \l_fp_input_a_sign_int > \c_zero
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int
- > \c_zero
- \exp_after:wN \exp_after:wN \exp_after:wN \fp_ln_aux:
- \else:
- \cs_set_protected:Npx \fp_tmp:w ##1##2
- {
- \group_end:
- ##1 \exp_not:N ##2 { \c_zero_fp }
- }
- \exp_after:wN \exp_after:wN \exp_after:wN \fp_ln_error_msg:
- \fi:
- \else:
- \cs_set_protected:Npx \fp_tmp:w ##1##2
- {
- \group_end:
- ##1 \exp_not:N ##2 { \c_zero_fp }
- }
- \exp_after:wN \fp_ln_error_msg:
- \fi:
- \fp_tmp:w #1 #2
- }
-% \end{macrocode}
-% As the input at this stage meets the validity criteria above, the
-% argument can now be saved for further processing. There is no need
-% to look at the sign of the input as it must be positive. The function
-% here simply sets up to either do the full calculation or recover
-% the stored value, as appropriate.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_ln_aux:
- {
- \tl_set:Nx \l_fp_arg_tl
- {
- +
- \int_use:N \l_fp_input_a_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \l_fp_input_a_decimal_int + \c_one_thousand_million
- e
- \int_use:N \l_fp_input_a_exponent_int
- }
- \if_cs_exist:w c_fp_ln ( \l_fp_arg_tl ) _fp \cs_end:
- \else:
- \exp_after:wN \fp_ln_exponent:
- \fi:
- \cs_set_protected:Npx \fp_tmp:w ##1##2
- {
- \group_end:
- ##1 \exp_not:N ##2
- { \use:c { c_fp_ln ( \l_fp_arg_tl ) _fp } }
- }
- }
-% \end{macrocode}
-% The main algorithm here uses the fact the logarithm can be divided
-% up, first taking out the powers of ten, then powers of two and finally
-% using a Taylor series for the remainder.
-% \[
-% \ln ( 10^{n} \times 2^{m} \times x )
-% = \ln ( 10^{n} ) + \ln ( 2^{m} ) + \ln ( x )
-% \]
-% The second point to remember is that
-% \[
-% \ln ( x^{-1} ) = - \ln ( x )
-% \]
-% which means that for the powers of $ 10 $ and $ 2 $ constants
-% are only needed for positive powers.
-%
-% The first step is to set up the sign for the output functions and
-% work out the powers of ten in the exponent. First the larger powers
-% are sorted out. The values for the constants are the same as those
-% for the smaller ones, just with a shift in the exponent.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_ln_exponent:
- {
- \fp_ln_internal:
- \if_int_compare:w \l_fp_output_extended_int < \c_five_hundred_million
- \else:
- \tex_advance:D \l_fp_output_decimal_int \c_one
- \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million
- \else:
- \l_fp_output_decimal_int \c_zero
- \tex_advance:D \l_fp_output_integer_int \c_one
- \fi:
- \fi:
- \fp_standardise:NNNN
- \l_fp_output_sign_int
- \l_fp_output_integer_int
- \l_fp_output_decimal_int
- \l_fp_output_exponent_int
- \tl_const:cx { c_fp_ln ( \l_fp_arg_tl ) _fp }
- {
- \if_int_compare:w \l_fp_output_sign_int > \c_zero
- +
- \else:
- -
- \fi:
- \int_use:N \l_fp_output_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \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_ln_internal:
- {
- \if_int_compare:w \l_fp_input_a_exponent_int < \c_zero
- \l_fp_input_a_exponent_int -\l_fp_input_a_exponent_int
- \l_fp_output_sign_int \c_minus_one
- \else:
- \l_fp_output_sign_int \c_one
- \fi:
- \if_int_compare:w \l_fp_input_a_exponent_int > \c_nine
- \exp_after:wN \fp_ln_exponent_tens:NN
- \int_use:N \l_fp_input_a_exponent_int
- \else:
- \l_fp_output_integer_int \c_zero
- \l_fp_output_decimal_int \c_zero
- \l_fp_output_extended_int \c_zero
- \l_fp_output_exponent_int \c_zero
- \fi:
- \fp_ln_exponent_units:
- }
-\cs_new_protected:Npn \fp_ln_exponent_tens:NN #1 #2
- {
- \l_fp_input_a_exponent_int #2 \scan_stop:
- \fp_ln_const:nn { 10 } { #1 }
- \tex_advance:D \l_fp_exp_exponent_int \c_one
- \l_fp_output_integer_int \l_fp_exp_integer_int
- \l_fp_output_decimal_int \l_fp_exp_decimal_int
- \l_fp_output_extended_int \l_fp_exp_extended_int
- \l_fp_output_exponent_int \l_fp_exp_exponent_int
- }
-% \end{macrocode}
-% Next the smaller powers of ten, which will need to be combined
-% with the above: always an additive process.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_ln_exponent_units:
- {
- \if_int_compare:w \l_fp_input_a_exponent_int > \c_zero
- \fp_ln_const:nn { 10 } { \int_use:N \l_fp_input_a_exponent_int }
- \fp_ln_normalise:
- \fp_add:NNNNNNNNN
- \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int
- \l_fp_output_integer_int \l_fp_output_decimal_int
- \l_fp_output_extended_int
- \l_fp_output_integer_int \l_fp_output_decimal_int
- \l_fp_output_extended_int
- \fi:
- \fp_ln_mantissa:
- }
-% \end{macrocode}
-% The smaller table-based parts may need to be exponent shifted so that
-% they stay in line with the larger parts. This is similar to the
-% approach in other places, but here there is a need to watch the
-% extended part of the number. The only case where the new exponent is
-% larger than the old is if there was no previous part. Then simply set
-% the exponent.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_ln_normalise:
- {
- \if_int_compare:w \l_fp_exp_exponent_int < \l_fp_output_exponent_int
- \tex_advance:D \l_fp_exp_decimal_int \c_one_thousand_million
- \exp_after:wN \use_i:nn \exp_after:wN
- \fp_ln_normalise_aux:NNNNNNNNN
- \int_use:N \l_fp_exp_decimal_int
- \exp_after:wN \fp_ln_normalise:
- \else:
- \l_fp_output_exponent_int \l_fp_exp_exponent_int
- \fi:
- }
-\cs_new_protected:Npn \fp_ln_normalise_aux:NNNNNNNNN #1#2#3#4#5#6#7#8#9
- {
- \if_int_compare:w \l_fp_exp_integer_int = \c_zero
- \l_fp_exp_decimal_int #1#2#3#4#5#6#7#8 \scan_stop:
- \else:
- \tl_set:Nx \l_fp_internal_tl
- {
- \int_use:N \l_fp_exp_integer_int
- #1#2#3#4#5#6#7#8
- }
- \l_fp_exp_integer_int \c_zero
- \l_fp_exp_decimal_int \l_fp_internal_tl \scan_stop:
- \fi:
- \tex_divide:D \l_fp_exp_extended_int \c_ten
- \tl_set:Nx \l_fp_internal_tl
- {
- #9
- \int_use:N \l_fp_exp_extended_int
- }
- \l_fp_exp_extended_int \l_fp_internal_tl \scan_stop:
- \tex_advance:D \l_fp_exp_exponent_int \c_one
- }
-% \end{macrocode}
-% The next phase is to decompose the mantissa by division by two to
-% leave a value which is in the range $ 1 \le x < 2 $. The sum of the
-% two powers needs to take account of the sign of the output: if it
-% is negative then the result gets \emph{smaller} as the mantissa gets
-% \emph{bigger}.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_ln_mantissa:
- {
- \l_fp_count_int \c_zero
- \l_fp_input_a_extended_int \c_zero
- \fp_ln_mantissa_aux:
- \if_int_compare:w \l_fp_count_int > \c_zero
- \fp_ln_const:nn { 2 } { \int_use:N \l_fp_count_int }
- \fp_ln_normalise:
- \if_int_compare:w \l_fp_output_sign_int > \c_zero
- \exp_after:wN \fp_add:NNNNNNNNN
- \else:
- \exp_after:wN \fp_sub:NNNNNNNNN
- \fi:
- \l_fp_output_integer_int \l_fp_output_decimal_int
- \l_fp_output_extended_int
- \l_fp_exp_integer_int \l_fp_exp_decimal_int \l_fp_exp_extended_int
- \l_fp_output_integer_int \l_fp_output_decimal_int
- \l_fp_output_extended_int
- \fi:
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int > \c_one
- \exp_after:wN \fp_ln_Taylor:
- \fi:
- }
-\cs_new_protected_nopar:Npn \fp_ln_mantissa_aux:
- {
- \if_int_compare:w \l_fp_input_a_integer_int > \c_one
- \tex_advance:D \l_fp_count_int \c_one
- \fp_ln_mantissa_divide_two:
- \exp_after:wN \fp_ln_mantissa_aux:
- \fi:
- }
-% \end{macrocode}
-% A fast one-shot division by two.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_ln_mantissa_divide_two:
- {
- \if_int_odd:w \l_fp_input_a_decimal_int
- \tex_advance:D \l_fp_input_a_extended_int \c_one_thousand_million
- \fi:
- \if_int_odd:w \l_fp_input_a_integer_int
- \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million
- \fi:
- \tex_divide:D \l_fp_input_a_integer_int \c_two
- \tex_divide:D \l_fp_input_a_decimal_int \c_two
- \tex_divide:D \l_fp_input_a_extended_int \c_two
- }
-% \end{macrocode}
-% Recovering constants makes use of the same auxiliary code as for
-% exponents.
-% \begin{macrocode}
-\cs_new_protected:Npn \fp_ln_const:nn #1#2
- {
- \exp_after:wN \exp_after:wN \exp_after:wN
- \fp_exp_integer_const:nnnn
- \cs:w c_fp_ln_ #1 _ #2 _tl \cs_end:
- }
-% \end{macrocode}
-% The Taylor series for the logarithm function is best implemented using
-% the identity
-% \[
-% \ln(x) = \ln\left( \frac{y + 1}{y - 1} \right)
-% \]
-% with
-% \[
-% y = \frac{x - 1}{x + 1}
-% \]
-% This leads to the series
-% \[
-% \ln(x)
-% = 2y
-% \left(
-% 1 + y^{2}
-% \left(
-% \frac{1}{3} + y^{2}
-% \left(
-% \frac{1}{5} + y^{2}
-% \left(
-% \frac{1}{7} + y^{2}
-% \left(
-% \frac{1}{9} + \cdots
-% \right)
-% \right)
-% \right)
-% \right)
-% \right)
-% \]
-% This expansion has the advantage that a lot of the work can be
-% loaded up early by finding $ y^{2} $ before the loop itself starts.
-% (In practice, the implementation does the multiplication by two at the
-% end of the loop, and expands out the brackets as this is an overall
-% more efficient approach.)
-%
-% At the implementation level, the code starts by calculating $ y $
-% and storing that in input \texttt{a} (which is no longer needed
-% for other purposes). That is done using the full division system
-% avoiding the parsing step. The value is then switched to a fixed-point
-% representation. There is then some shuffling to get all of the working
-% space set up. At this stage, a lot of registers are in use and so
-% the Taylor series is calculated within a group so that the
-% \texttt{output} variables can be used to hold the result. The value
-% of $ y^{2} $ is held in input \texttt{b} (there are a few
-% assignments saved by choosing this over \texttt{a}), while input
-% \texttt{a} is used for the \enquote{loop value}.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_ln_Taylor:
- {
- \group_begin:
- \l_fp_input_a_integer_int \c_zero
- \l_fp_input_a_exponent_int \c_zero
- \l_fp_input_b_integer_int \c_two
- \l_fp_input_b_decimal_int \l_fp_input_a_decimal_int
- \l_fp_input_b_exponent_int \c_zero
- \fp_div_internal:
- \fp_ln_fixed:
- \l_fp_input_a_integer_int \l_fp_output_integer_int
- \l_fp_input_a_decimal_int \l_fp_output_decimal_int
- \l_fp_input_a_extended_int \c_zero
- \l_fp_input_a_exponent_int \l_fp_output_exponent_int
- \l_fp_output_decimal_int \c_zero %^^A Bug?
- \l_fp_output_decimal_int \l_fp_input_a_decimal_int
- \l_fp_output_extended_int \l_fp_input_a_extended_int
- \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_input_b_decimal_int \l_fp_input_b_extended_int
- \l_fp_count_int \c_one
- \fp_ln_Taylor_aux:
- \cs_set_protected_nopar:Npx \fp_tmp:w
- {
- \group_end:
- \l_fp_exp_integer_int \c_zero
- \exp_not:N \l_fp_exp_decimal_int
- \int_use:N \l_fp_output_decimal_int \scan_stop:
- \exp_not:N \l_fp_exp_extended_int
- \int_use:N \l_fp_output_extended_int \scan_stop:
- \exp_not:N \l_fp_exp_exponent_int
- \int_use:N \l_fp_output_exponent_int \scan_stop:
- }
- \fp_tmp:w
-% \end{macrocode}
-% After the loop part of the Taylor series, the factor of $ 2 $ needs
-% to be included. The total for the result can then be constructed.
-% \begin{macrocode}
- \tex_advance:D \l_fp_exp_decimal_int \l_fp_exp_decimal_int
- \if_int_compare:w \l_fp_exp_extended_int < \c_five_hundred_million
- \else:
- \tex_advance:D \l_fp_exp_extended_int -\c_five_hundred_million
- \tex_advance:D \l_fp_exp_decimal_int \c_one
- \fi:
- \tex_advance:D \l_fp_exp_extended_int \l_fp_exp_extended_int
- \fp_ln_normalise:
- \if_int_compare:w \l_fp_output_sign_int > \c_zero
- \exp_after:wN \fp_add:NNNNNNNNN
- \else:
- \exp_after:wN \fp_sub:NNNNNNNNN
- \fi:
- \l_fp_output_integer_int \l_fp_output_decimal_int
- \l_fp_output_extended_int
- \c_zero \l_fp_exp_decimal_int \l_fp_exp_extended_int
- \l_fp_output_integer_int \l_fp_output_decimal_int
- \l_fp_output_extended_int
- }
-% \end{macrocode}
-% The usual shifts to move to fixed-point working. This is done using
-% the \texttt{output} registers as this saves a reassignment here.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_ln_fixed:
- {
- \if_int_compare:w \l_fp_output_exponent_int < \c_zero
- \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million
- \exp_after:wN \use_i:nn \exp_after:wN
- \fp_ln_fixed_aux:NNNNNNNNN
- \int_use:N \l_fp_output_decimal_int
- \exp_after:wN \fp_ln_fixed:
- \fi:
- }
-\cs_new_protected:Npn \fp_ln_fixed_aux:NNNNNNNNN #1#2#3#4#5#6#7#8#9
- {
- \if_int_compare:w \l_fp_output_integer_int = \c_zero
- \l_fp_output_decimal_int #1#2#3#4#5#6#7#8 \scan_stop:
- \else:
- \tl_set:Nx \l_fp_internal_tl
- {
- \int_use:N \l_fp_output_integer_int
- #1#2#3#4#5#6#7#8
- }
- \l_fp_output_integer_int \c_zero
- \l_fp_output_decimal_int \l_fp_internal_tl \scan_stop:
- \fi:
- \tex_advance:D \l_fp_output_exponent_int \c_one
- }
-% \end{macrocode}
-% The main loop for the Taylor series: unlike some of the other similar
-% functions, the result here is not the final value and is therefore
-% subject to further manipulation outside of the loop.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_ln_Taylor_aux:
- {
- \tex_advance:D \l_fp_count_int \c_two
- \fp_mul:NNNNNN
- \l_fp_input_a_decimal_int \l_fp_input_a_extended_int
- \l_fp_input_b_decimal_int \l_fp_input_b_extended_int
- \l_fp_input_a_decimal_int \l_fp_input_a_extended_int
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int
- > \c_zero
- \fp_div_integer:NNNNN
- \l_fp_input_a_decimal_int \l_fp_input_a_extended_int
- \l_fp_count_int
- \l_fp_exp_decimal_int \l_fp_exp_extended_int
- \tex_advance:D \l_fp_output_decimal_int \l_fp_exp_decimal_int
- \tex_advance:D \l_fp_output_extended_int \l_fp_exp_extended_int
- \if_int_compare:w \l_fp_output_extended_int < \c_one_thousand_million
- \else:
- \tex_advance:D \l_fp_output_decimal_int \c_one
- \tex_advance:D \l_fp_output_extended_int
- -\c_one_thousand_million
- \fi:
- \if_int_compare:w \l_fp_output_decimal_int < \c_one_thousand_million
- \else:
- \tex_advance:D \l_fp_output_integer_int \c_one
- \tex_advance:D \l_fp_output_decimal_int
- -\c_one_thousand_million
- \fi:
- \exp_after:wN \fp_ln_Taylor_aux:
- \fi:
- }
-% \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_pow:Nn, \fp_pow:cn}
-% \UnitTested
-% \begin{macro}{\fp_gpow:Nn,\fp_gpow:cn}
-% \UnitTested
-% \begin{macro}[aux]{\fp_pow_aux:NNn}
-% \begin{macro}[aux]{\fp_pow_aux_i:}
-% \begin{macro}[aux]{\fp_pow_positive:}
-% \begin{macro}[aux]{\fp_pow_negative:}
-% \begin{macro}[aux]{\fp_pow_aux_ii:}
-% \begin{macro}[aux]{\fp_pow_aux_iii:}
-% \begin{macro}[aux]{\fp_pow_aux_iv:}
-% The approach used for working out powers is to first filter out the
-% various special cases and then do most of the work using the
-% logarithm and exponent functions. The two storage areas are used
-% in the reverse of the `natural' logic as this avoids some
-% re-assignment in the sanity checking code.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_pow:Nn { \fp_pow_aux:NNn \tl_set:Nn }
-\cs_new_protected_nopar:Npn \fp_gpow:Nn { \fp_pow_aux:NNn \tl_gset:Nn }
-\cs_generate_variant:Nn \fp_pow:Nn { c }
-\cs_generate_variant:Nn \fp_gpow:Nn { c }
-\cs_new_protected:Npn \fp_pow_aux:NNn #1#2#3
- {
- \group_begin:
- \fp_read:N #2
- \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_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
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int
- = \c_zero
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int
- = \c_zero
- \cs_set_protected:Npx \fp_tmp:w ##1##2
- {
- \group_end:
- ##1 ##2 { \c_undefined_fp }
- }
- \else:
- \cs_set_protected:Npx \fp_tmp:w ##1##2
- {
- \group_end:
- ##1 ##2 { \c_zero_fp }
- }
- \fi:
- \else:
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int
- = \c_zero
- \cs_set_protected:Npx \fp_tmp:w ##1##2
- {
- \group_end:
- ##1 ##2 { \c_one_fp }
- }
- \else:
- \exp_after:wN \exp_after:wN \exp_after:wN
- \fp_pow_aux_i:
- \fi:
- \fi:
- \fp_tmp:w #1 #2
-}
-% \end{macrocode}
-% Simply using the logarithm function directly will fail when negative
-% numbers are raised to integer powers, which is a mathematically valid
-% operation. So there are some more tests to make, after forcing the
-% power into an integer and decimal parts, if necessary.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_pow_aux_i:
- {
- \if_int_compare:w \l_fp_input_b_sign_int > \c_zero
- \tl_set:Nn \l_fp_sign_tl { + }
- \exp_after:wN \fp_pow_aux_ii:
- \else:
- \l_fp_input_a_extended_int \c_zero
- \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten
- \group_begin:
- \fp_extended_normalise:
- \if_int_compare:w
- \int_eval:w
- \l_fp_input_a_decimal_int + \l_fp_input_a_extended_int
- = \c_zero
- \group_end:
- \tl_set:Nn \l_fp_sign_tl { - }
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \fp_pow_aux_ii:
- \else:
- \group_end:
- \cs_set_protected:Npx \fp_tmp:w ##1##2
- {
- \group_end:
- ##1 ##2 { \c_undefined_fp }
- }
- \fi:
- \else:
- \cs_set_protected:Npx \fp_tmp:w ##1##2
- {
- \group_end:
- ##1 ##2 { \c_undefined_fp }
- }
- \fi:
- \fi:
- }
-% \end{macrocode}
-% The approach used here for powers works well in most cases but gives
-% poorer results for negative integer powers, which often have exact
-% values. So there is some filtering to do. For negative powers where
-% the power is small, an alternative approach is used in which the
-% positive value is worked out and the reciprocal is then taken. The
-% filtering is unfortunately rather long.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_pow_aux_ii:
- {
- \if_int_compare:w \l_fp_input_a_sign_int > \c_zero
- \exp_after:wN \fp_pow_aux_iv:
- \else:
- \if_int_compare:w \l_fp_input_a_exponent_int < \c_ten
- \group_begin:
- \l_fp_input_a_extended_int \c_zero
- \fp_extended_normalise:
- \if_int_compare:w \l_fp_input_a_decimal_int = \c_zero
- \if_int_compare:w \l_fp_input_a_integer_int > \c_ten
- \group_end:
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \fp_pow_aux_iv:
- \else:
- \group_end:
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \fp_pow_aux_iii:
- \fi:
- \else:
- \group_end:
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \exp_after:wN \exp_after:wN
- \exp_after:wN \fp_pow_aux_iv:
- \fi:
- \else:
- \exp_after:wN \exp_after:wN \exp_after:wN
- \fp_pow_aux_iv:
- \fi:
- \fi:
- \cs_set_protected:Npx \fp_tmp:w ##1##2
- {
- \group_end:
- ##1 ##2
- {
- \l_fp_sign_tl
- \int_use:N \l_fp_output_integer_int
- .
- \exp_after:wN \use_none:n
- \int_value:w \int_eval:w
- \l_fp_output_decimal_int + \c_one_thousand_million
- e
- \int_use:N \l_fp_output_exponent_int
- }
- }
- }
-% \end{macrocode}
-% For the small negative integer powers, the calculation is done for
-% the positive power and the reciprocal is then taken.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_pow_aux_iii:
- {
- \l_fp_input_a_sign_int \c_one
- \fp_pow_aux_iv:
- \l_fp_input_a_integer_int \c_one
- \l_fp_input_a_decimal_int \c_zero
- \l_fp_input_a_exponent_int \c_zero
- \l_fp_input_b_integer_int \l_fp_output_integer_int
- \l_fp_input_b_decimal_int \l_fp_output_decimal_int
- \l_fp_input_b_exponent_int \l_fp_output_exponent_int
- \fp_div_internal:
- }
-% \end{macrocode}
-% The business end of the code starts by finding the logarithm of the
-% given base. There is a bit of a shuffle so that this does not have
-% to be re-parsed and so that the output ends up in the correct place.
-% There is also a need to enable using the short-cut for a
-% pre-calculated result. The internal part of the multiplication
-% function can then be used to do the second part of the calculation
-% directly. There is some more set up before doing the exponential:
-% the idea here is to deactivate some internals so that everything works
-% smoothly.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \fp_pow_aux_iv:
- {
- \group_begin:
- \l_fp_input_a_integer_int \l_fp_input_b_integer_int
- \l_fp_input_a_decimal_int \l_fp_input_b_decimal_int
- \l_fp_input_a_exponent_int \l_fp_input_b_exponent_int
- \fp_ln_internal:
- \cs_set_protected_nopar:Npx \fp_tmp:w
- {
- \group_end:
- \exp_not:N \l_fp_input_b_sign_int
- \int_use:N \l_fp_output_sign_int \scan_stop:
- \exp_not:N \l_fp_input_b_integer_int
- \int_use:N \l_fp_output_integer_int \scan_stop:
- \exp_not:N \l_fp_input_b_decimal_int
- \int_use:N \l_fp_output_decimal_int \scan_stop:
- \exp_not:N \l_fp_input_b_extended_int
- \int_use:N \l_fp_output_extended_int \scan_stop:
- \exp_not:N \l_fp_input_b_exponent_int
- \int_use:N \l_fp_output_exponent_int \scan_stop:
- }
- \fp_tmp:w
- \l_fp_input_a_extended_int \c_zero
- \fp_mul:NNNNNNNNN
- \l_fp_input_a_integer_int \l_fp_input_a_decimal_int
- \l_fp_input_a_extended_int
- \l_fp_input_b_integer_int \l_fp_input_b_decimal_int
- \l_fp_input_b_extended_int
- \l_fp_output_integer_int \l_fp_output_decimal_int
- \l_fp_output_extended_int
- \l_fp_output_exponent_int
- \int_eval:w
- \l_fp_input_a_exponent_int + \l_fp_input_b_exponent_int
- \scan_stop:
- \fp_extended_normalise_output:
- \tex_multiply:D \l_fp_input_a_sign_int \l_fp_input_b_sign_int
- \l_fp_input_a_integer_int \l_fp_output_integer_int
- \l_fp_input_a_decimal_int \l_fp_output_decimal_int
- \l_fp_input_a_extended_int \l_fp_output_extended_int
- \l_fp_input_a_exponent_int \l_fp_output_exponent_int
- \l_fp_output_integer_int \c_zero
- \l_fp_output_decimal_int \c_zero
- \l_fp_output_extended_int \c_zero
- \l_fp_output_exponent_int \c_zero
- \cs_set_eq:NN \fp_exp_const:Nx \use_none:nn
- \fp_exp_internal:
- }
-% \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}[pTF]{\fp_if_undefined:N}
-% \UnitTested
-% Testing for an undefined value is easy.
-% \begin{macrocode}
-\prg_new_conditional:Npnn \fp_if_undefined:N #1 { p , T , F , TF }
- {
- \if_meaning:w #1 \c_undefined_fp
- \prg_return_true:
- \else:
- \prg_return_false:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[pTF]{\fp_if_zero:N}
-% \UnitTested
-% Testing for a zero fixed-point is also easy.
-% \begin{macrocode}
-\prg_new_conditional:Npnn \fp_if_zero:N #1 { p , T , F , TF }
- {
- \if_meaning:w #1 \c_zero_fp
- \prg_return_true:
- \else:
- \prg_return_false:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsection{Floating-point conditionals}
-%
-% \begin{macro}[TF]{\fp_compare:nNn}
-% \begin{macro}[TF]{\fp_compare:NNN}
-% \UnitTested
-% \begin{macro}[aux]{\fp_compare_aux:N}
-% \begin{macro}[aux]{\fp_compare_=:}
-% \begin{macro}[aux]{\fp_compare_<:}
-% \begin{macro}[aux]{\fp_compare_<_aux:}
-% \begin{macro}[aux]{\fp_compare_absolute_a>b:}
-% \begin{macro}[aux]{\fp_compare_absolute_a<b:}
-% \begin{macro}[aux]{\fp_compare_>:}
-% The idea for the comparisons is to provide two versions: slower and
-% 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 }
- {
- \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 }
- {
- \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_exponent_int \l_fp_input_a_exponent_int
- \fp_read:N #1
- \fp_compare_aux:N #2
- }
-\cs_new_protected:Npn \fp_compare_aux:N #1
- {
- \cs_if_exist:cTF { fp_compare_#1: }
- { \use:c { fp_compare_#1: } }
- {
- \group_end:
- \prg_return_false:
- }
- }
-% \end{macrocode}
-% For equality, the test is pretty easy as things are either equal or
-% they are not.
-% \begin{macrocode}
-\cs_new_protected_nopar:cpn { fp_compare_=: }
- {
- \if_int_compare:w \l_fp_input_a_sign_int = \l_fp_input_b_sign_int
- \if_int_compare:w \l_fp_input_a_integer_int = \l_fp_input_b_integer_int
- \if_int_compare:w \l_fp_input_a_decimal_int = \l_fp_input_b_decimal_int
- \if_int_compare:w
- \l_fp_input_a_exponent_int = \l_fp_input_b_exponent_int
- \group_end:
- \prg_return_true:
- \else:
- \group_end:
- \prg_return_false:
- \fi:
- \else:
- \group_end:
- \prg_return_false:
- \fi:
- \else:
- \group_end:
- \prg_return_false:
- \fi:
- \else:
- \group_end:
- \prg_return_false:
- \fi:
- }
-% \end{macrocode}
-% Comparing two values is quite complex. First, there is a filter step
-% to check if one or other of the given values is zero. If it is then
-% the result is relatively easy to determine.
-% \begin{macrocode}
-\cs_new_protected_nopar:cpn { fp_compare_>: }
- {
- \if_int_compare:w \int_eval:w
- \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int
- = \c_zero
- \if_int_compare:w \int_eval:w
- \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int
- = \c_zero
- \group_end:
- \prg_return_false:
- \else:
- \if_int_compare:w \l_fp_input_b_sign_int > \c_zero
- \group_end:
- \prg_return_false:
- \else:
- \group_end:
- \prg_return_true:
- \fi:
- \fi:
- \else:
- \if_int_compare:w \int_eval:w
- \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int
- = \c_zero
- \if_int_compare:w \l_fp_input_a_sign_int > \c_zero
- \group_end:
- \prg_return_true:
- \else:
- \group_end:
- \prg_return_false:
- \fi:
- \else:
- \use:c { fp_compare_>_aux: }
- \fi:
- \fi:
- }
-% \end{macrocode}
-% Next, check the sign of the input: this again may give an obvious
-% result. If both signs are the same, then hand off to comparing the
-% absolute values.
-% \begin{macrocode}
-\cs_new_protected_nopar:cpn { fp_compare_>_aux: }
- {
- \if_int_compare:w \l_fp_input_a_sign_int > \l_fp_input_b_sign_int
- \group_end:
- \prg_return_true:
- \else:
- \if_int_compare:w \l_fp_input_a_sign_int < \l_fp_input_b_sign_int
- \group_end:
- \prg_return_false:
- \else:
- \if_int_compare:w \l_fp_input_a_sign_int > \c_zero
- \use:c { fp_compare_absolute_a>b: }
- \else:
- \use:c { fp_compare_absolute_a<b: }
- \fi:
- \fi:
- \fi:
- }
-% \end{macrocode}
-% Rather long runs of checks, as there is the need to go through each
-% layer of the input and do the comparison. There is also the need to
-% avoid messing up with equal inputs at each stage.
-% \begin{macrocode}
-\cs_new_protected_nopar:cpn { fp_compare_absolute_a>b: }
- {
- \if_int_compare:w \l_fp_input_a_exponent_int > \l_fp_input_b_exponent_int
- \group_end:
- \prg_return_true:
- \else:
- \if_int_compare:w \l_fp_input_a_exponent_int < \l_fp_input_b_exponent_int
- \group_end:
- \prg_return_false:
- \else:
- \if_int_compare:w \l_fp_input_a_integer_int > \l_fp_input_b_integer_int
- \group_end:
- \prg_return_true:
- \else:
- \if_int_compare:w
- \l_fp_input_a_integer_int < \l_fp_input_b_integer_int
- \group_end:
- \prg_return_false:
- \else:
- \if_int_compare:w
- \l_fp_input_a_decimal_int > \l_fp_input_b_decimal_int
- \group_end:
- \prg_return_true:
- \else:
- \group_end:
- \prg_return_false:
- \fi:
- \fi:
- \fi:
- \fi:
- \fi:
- }
-\cs_new_protected_nopar:cpn { fp_compare_absolute_a<b: }
- {
- \if_int_compare:w \l_fp_input_b_exponent_int > \l_fp_input_a_exponent_int
- \group_end:
- \prg_return_true:
- \else:
- \if_int_compare:w \l_fp_input_b_exponent_int < \l_fp_input_a_exponent_int
- \group_end:
- \prg_return_false:
- \else:
- \if_int_compare:w \l_fp_input_b_integer_int > \l_fp_input_a_integer_int
- \group_end:
- \prg_return_true:
- \else:
- \if_int_compare:w
- \l_fp_input_b_integer_int < \l_fp_input_a_integer_int
- \group_end:
- \prg_return_false:
- \else:
- \if_int_compare:w
- \l_fp_input_b_decimal_int > \l_fp_input_a_decimal_int
- \group_end:
- \prg_return_true:
- \else:
- \group_end:
- \prg_return_false:
- \fi:
- \fi:
- \fi:
- \fi:
- \fi:
- }
-% \end{macrocode}
-% This is just a case of reversing the two input values and then
-% running the tests already defined.
-% \begin{macrocode}
-\cs_new_protected_nopar:cpn { fp_compare_<: }
- {
- \tl_set:Nx \l_fp_internal_tl
- {
- \int_set:Nn \exp_not:N \l_fp_input_a_sign_int
- { \int_use:N \l_fp_input_b_sign_int }
- \int_set:Nn \exp_not:N \l_fp_input_a_integer_int
- { \int_use:N \l_fp_input_b_integer_int }
- \int_set:Nn \exp_not:N \l_fp_input_a_decimal_int
- { \int_use:N \l_fp_input_b_decimal_int }
- \int_set:Nn \exp_not:N \l_fp_input_a_exponent_int
- { \int_use:N \l_fp_input_b_exponent_int }
- \int_set:Nn \exp_not:N \l_fp_input_b_sign_int
- { \int_use:N \l_fp_input_a_sign_int }
- \int_set:Nn \exp_not:N \l_fp_input_b_integer_int
- { \int_use:N \l_fp_input_a_integer_int }
- \int_set:Nn \exp_not:N \l_fp_input_b_decimal_int
- { \int_use:N \l_fp_input_a_decimal_int }
- \int_set:Nn \exp_not:N \l_fp_input_b_exponent_int
- { \int_use:N \l_fp_input_a_exponent_int }
- }
- \l_fp_internal_tl
- \use:c { fp_compare_>: }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
+% The following need to be done. I'll try to time-order the items.
+% \begin{itemize}
+% \item Decide what exponent range to consider.
+% \item Change the internal representation of fp, by replacing braced
+% groups of $4$ digits by delimited arguments.
+% \item Modulo and remainder, and rounding functions |quantize|,
+% |quantize0|, |quantize+|, |quantize-|, |quantize=|, |round=|.
+% Should the modulo also be provided as (catcode 12) |%|?
+% \item \cs{fp_format:nn} \Arg{fpexpr} \Arg{format}, but what should
+% \meta{format} be? More general pretty printing?
+% \item Add |and|, |or|, |xor|? Perhaps under the names \texttt{all},
+% \texttt{any}, and \texttt{xor}?
+% \item Add \texttt{csc} and \texttt{sec}.
+% \item Add $\log(x,b)$ for logarithm of $x$ in base $b$.
+% \item \texttt{hypot} (Euclidean length) and $\atan(x,y) = \atan(x/y)$,
+% also called \texttt{atan2} in other math packages.
+% Cartesian-to-polar transform. Other inverse trigonometric functions
+% \texttt{acos}, \texttt{asin}, \texttt{atan} (one and two arguments).
+% Also \texttt{asec}, \texttt{acsc}?
+% \item Hyperbolic functions \texttt{cosh}, \texttt{sinh}, \texttt{tanh}.
+% \item Inverse hyperbolics.
+% \item Base conversion, input such as \texttt{0xAB.CDEF}.
+% \item Random numbers (pgfmath provides |rnd|, |rand|, |random|), with
+% seed reset at every \cs{fp_set:Nn}.
+% \item Factorial (not with |!|), gamma function.
+% \item Improve coefficients of \texttt{sin}, \texttt{cos} and
+% \texttt{tan}.
+% \item Treat upper and lower case letters identically in
+% identifiers, and ignore underscores.
+% \item Parse $-3<-2<-1$ as it should, not $(-3<-2)<-1$.
+% \item Add an |array(1,2,3)| and |i=complex(0,1)|.
+% \item Provide an experimental |map| function? Perhaps easier to
+% implement if it is a single character, |@sin(1,2)|?
+% \item Provide \cs{fp_if_nan:nTF}?
+% \end{itemize}
+% \pkg{Pgfmath} also provides box-measurements (depth, height, width), but
+% boxes are not possible expandably.
%
-% \begin{macro}[TF]{\fp_compare:n}
-% \begin{macro}[aux]
-% {
-% \fp_compare_aux_i:w, \fp_compare_aux_ii:w, \fp_compare_aux_iii:w,
-% \fp_compare_aux_iv:w, \fp_compare_aux_v:w, \fp_compare_aux_vi:w,
-% \fp_compare_aux_vii:w
-% }
-% As \TeX{} cannot help out here, a daisy-chain of delimited functions
-% are used. This is very much a first-generation approach: revision will
-% be needed if these functions are really useful.
-% \begin{macrocode}
-\prg_new_protected_conditional:Npnn \fp_compare:n #1 { T , F , TF }
- {
- \group_begin:
- \tl_set:Nx \l_fp_internal_tl
- {
- \group_end:
- \fp_compare_aux_i:w #1 \exp_not:n { == \q_nil == \q_stop }
- }
- \l_fp_internal_tl
- }
-\cs_new_protected:Npn \fp_compare_aux_i:w #1 == #2 == #3 \q_stop
- {
- \quark_if_nil:nTF {#2}
- { \fp_compare_aux_ii:w #1 != \q_nil != \q_stop }
- { \fp_compare:nNnTF {#1} = {#2} \prg_return_true: \prg_return_false: }
- }
-\cs_new_protected:Npn \fp_compare_aux_ii:w #1 != #2 != #3 \q_stop
- {
- \quark_if_nil:nTF {#2}
- { \fp_compare_aux_iii:w #1 <= \q_nil <= \q_stop }
- { \fp_compare:nNnTF {#1} = {#2} \prg_return_false: \prg_return_true: }
- }
-\cs_new_protected:Npn \fp_compare_aux_iii:w #1 <= #2 <= #3 \q_stop
- {
- \quark_if_nil:nTF {#2}
- { \fp_compare_aux_iv:w #1 >= \q_nil >= \q_stop }
- { \fp_compare:nNnTF {#1} > {#2} \prg_return_false: \prg_return_true: }
- }
-\cs_new_protected:Npn \fp_compare_aux_iv:w #1 >= #2 >= #3 \q_stop
- {
- \quark_if_nil:nTF {#2}
- { \fp_compare_aux_v:w #1 = \q_nil \q_stop }
- { \fp_compare:nNnTF {#1} < {#2} \prg_return_false: \prg_return_true: }
- }
-\cs_new_protected:Npn \fp_compare_aux_v:w #1 = #2 = #3 \q_stop
- {
- \quark_if_nil:nTF {#2}
- { \fp_compare_aux_vi:w #1 < \q_nil < \q_stop }
- { \fp_compare:nNnTF {#1} = {#2} \prg_return_true: \prg_return_false: }
- }
-\cs_new_protected:Npn \fp_compare_aux_vi:w #1 < #2 < #3 \q_stop
- {
- \quark_if_nil:nTF {#2}
- { \fp_compare_aux_vii:w #1 > \q_nil > \q_stop }
- { \fp_compare:nNnTF {#1} < {#2} \prg_return_true: \prg_return_false: }
- }
-\cs_new_protected:Npn \fp_compare_aux_vii:w #1 > #2 > #3 \q_stop
- {
- \quark_if_nil:nTF {#2}
- { \prg_return_false: }
- { \fp_compare:nNnTF {#1} > {#2} \prg_return_true: \prg_return_false: }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
+% Bugs. (Exclamation points mark important bugs.)
+% \begin{itemize}
+% \item[!] \cs{fp_eval:n} |{nan}| mustn't produce an error.
+% \item $1-10^{-16}$ should not give $1$.
+% \item When rounding towards $-\infty$, |\dim_to_fp:n {0pt}| should
+% return $-0$, not $+0$.
+% \item \texttt{0e9999999999} gives a \TeX{} \enquote{number too
+% large} error.
+% \item \texttt{tan} and \texttt{cot} give very slightly wrong results
+% for arguments near $10^{-8}$.
+% \item[!] Multiplying $0$ with $\infty$ doesn't trigger an invalid
+% operation error.
+% \item Conversion to integers with \cs{fp_to_int:n} does not check
+% for overflow.
+% \item Subnormals are not implemented.
+% \end{itemize}
%
-% \subsection{Messages}
+% \end{documentation}
%
-% \begin{macro}{\fp_overflow_msg:}
-% A generic overflow message, used whenever there is a possible
-% overflow.
-% \begin{macrocode}
-\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{implementation}
%
-% \begin{macro}{\fp_exp_overflow_msg:}
-% A slightly more helpful message for exponent overflows.
-% \begin{macrocode}
-\msg_kernel_new:nnnn { fpu } { exponent-overflow }
- { Number~too~big~for~exponent~unit. }
- {
- The~exponent~of~the~input~given~is~too~big~for~the~floating~point~
- unit:~the~maximum~input~value~for~an~exponent~is~230.
- }
-\cs_new_protected_nopar:Npn \fp_exp_overflow_msg:
- { \msg_kernel_error:nn { fpu } { exponent-overflow } }
-% \end{macrocode}
-% \end{macro}
+% \section{\pkg{l3fp} implementation}
%
-% \begin{macro}{\fp_ln_error_msg:}
-% Logarithms are only valid for positive number
% \begin{macrocode}
-\msg_kernel_new:nnnn { fpu } { logarithm-input-error }
- { Invalid~input~to~ln~function. }
- { Logarithms~can~only~be~calculated~for~positive~numbers. }
-\cs_new_protected_nopar:Npn \fp_ln_error_msg: {
- \msg_kernel_error:nn { fpu } { logarithm-input-error }
-}
+%<*package>
% \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 } { trigonometric-overflow }
- { Number~too~big~for~trigonometry~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 } }
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+\__expl_package_check:
% \end{macrocode}
-% \end{macro}
%
% \begin{macrocode}
-%</initex|package>
+%</package>
% \end{macrocode}
%
% \end{implementation}
%
-%\PrintIndex
+% \PrintIndex