diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/expl3')
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/expl3.dtx | 5 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3candidates.dtx | 2 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3expan.dtx | 20 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3fp.dtx | 2393 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3intexpr.dtx | 25 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3names.dtx | 20 |
6 files changed, 2453 insertions, 12 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/expl3.dtx b/Master/texmf-dist/source/latex/expl3/expl3.dtx index 63fb9616c72..b063be947dc 100644 --- a/Master/texmf-dist/source/latex/expl3/expl3.dtx +++ b/Master/texmf-dist/source/latex/expl3/expl3.dtx @@ -37,7 +37,7 @@ \RequirePackage{l3names} %</driver|package> %\fi -\GetIdInfo$Id: expl3.dtx 1905 2010-05-19 07:45:31Z joseph $ +\GetIdInfo$Id: expl3.dtx 1955 2010-06-15 06:04:59Z joseph $ {L3 Experimental code bundle wrapper}% %\iffalse %<*driver> @@ -919,7 +919,8 @@ l3precom, l3calc, l3xref, - l3file + l3file, + l3fp, } % \end{macrocode} % diff --git a/Master/texmf-dist/source/latex/expl3/l3candidates.dtx b/Master/texmf-dist/source/latex/expl3/l3candidates.dtx index 2c8d8968e6c..8051fb7f340 100644 --- a/Master/texmf-dist/source/latex/expl3/l3candidates.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3candidates.dtx @@ -37,7 +37,7 @@ %</driver|package> %\fi \errorcontextlines=999 -\GetIdInfo$Id$ +\GetIdInfo$Id: l3candidates.dtx 1957 2010-06-15 06:33:43Z mittelba $ {L3 Experimental 'extras' module} %\iffalse %<*driver> diff --git a/Master/texmf-dist/source/latex/expl3/l3expan.dtx b/Master/texmf-dist/source/latex/expl3/l3expan.dtx index 1a77ea97d71..e28b81baa32 100644 --- a/Master/texmf-dist/source/latex/expl3/l3expan.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3expan.dtx @@ -36,7 +36,7 @@ \RequirePackage{l3names} %</driver|package> %\fi -\GetIdInfo$Id: l3expan.dtx 1873 2010-03-24 08:32:54Z joseph $ +\GetIdInfo$Id: l3expan.dtx 1948 2010-06-10 18:53:09Z joseph $ {L3 Experimental Argument Expansion module} %\iffalse %<*driver> @@ -440,10 +440,12 @@ % \begin{function}{ % \exp_last_unbraced:Nf| % \exp_last_unbraced:NV| +% \exp_last_unbraced:No| % \exp_last_unbraced:Nv| % \exp_last_unbraced:NcV| -% \exp_last_unbraced:NNo| % \exp_last_unbraced:NNV| +% \exp_last_unbraced:NNo| +% \exp_last_unbraced:NNNV| % \exp_last_unbraced:NNNo| % } % \begin{syntax} @@ -1165,25 +1167,31 @@ %\end{macro} % %\begin{macro}{\exp_last_unbraced:NV} +%\begin{macro}{\exp_last_unbraced:No} %\begin{macro}{\exp_last_unbraced:Nv} %\begin{macro}{\exp_last_unbraced:Nf} %\begin{macro}{\exp_last_unbraced:NcV} -%\begin{macro}{\exp_last_unbraced:NNo} %\begin{macro}{\exp_last_unbraced:NNV} +%\begin{macro}{\exp_last_unbraced:NNo} +%\begin{macro}{\exp_last_unbraced:NNNV} %\begin{macro}{\exp_last_unbraced:NNNo} % Now the business end. % \begin{macrocode} \cs_new_nopar:Npn \exp_last_unbraced:Nf { \::f_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:NV { \::V_unbraced \::: } +\cs_new_nopar:Npn \exp_last_unbraced:No { \::o_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:Nv { \::v_unbraced \::: } \cs_new_nopar:Npn \exp_last_unbraced:NcV { \::c \::V_unbraced \::: } +\cs_new_nopar:Npn \exp_last_unbraced:NNV { + \::N \::V_unbraced \::: +} \cs_new:Npn \exp_last_unbraced:NNo #1#2#3 { \exp_after:wN #1 \exp_after:wN #2 #3 } -\cs_new_nopar:Npn \exp_last_unbraced:NNV { - \::N \::V_unbraced \::: +\cs_new_nopar:Npn \exp_last_unbraced:NNNV { + \::N \::N \::V_unbraced \::: } \cs_new:Npn \exp_last_unbraced:NNNo #1#2#3#4 { \exp_after:wN #1 \exp_after:wN #2 \exp_after:wN #3 #4 @@ -1196,6 +1204,8 @@ %\end{macro} %\end{macro} %\end{macro} +%\end{macro} +%\end{macro} % % \begin{macrocode} %</initex|package> diff --git a/Master/texmf-dist/source/latex/expl3/l3fp.dtx b/Master/texmf-dist/source/latex/expl3/l3fp.dtx new file mode 100644 index 00000000000..7b3b63ba16f --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3fp.dtx @@ -0,0 +1,2393 @@ +% \iffalse +%% File: l3fp.dtx Copyright (C) 2010 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 +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% 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 LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%<*driver|package> +\RequirePackage{l3names} +%</driver|package> +%\fi +\GetIdInfo$Id: l3fp.dtx 1979 2010-07-08 19:51:19Z joseph $ + {L3 Experimental floating-point operations} +%\iffalse +%<*driver> +%\fi +\ProvidesFile{\filename.\filenameext} + [\filedate\space v\fileversion\space\filedescription] +%\iffalse +\documentclass[full]{l3doc} +\begin{document} + \DocInput{l3fp.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3fp} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}\\ +% Fixed-point arithmetic} +% \author{\Team} +% \date{\filedate} +% \maketitle +% +%\begin{documentation} +% +%\section{Fixed-point numbers} +% +% This module implements a fixed-point data type and arithmetic support. +% Fixed-point numbers are real numbers with a fixed range of decimal +% places available, in this case nine before and nine after the +% decimal point. As this is a low-level module, error-checking is +% minimal. +% +% 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 { - } +%\end{verbatim} +% will all be interpreted as zero values without raising an error. +% +% Number which are too large for the fixed-point unit to handle will +% result in errors, either from \TeX\ or from \LaTeX. The \LaTeX\ code +% does not check that the input will not overflow, hence the +% possibility of a \TeX\ error. On the other hand, numbers which are too +% small will be dropped, which will mean that extra decimal digits will +% simply be lost. +% +% Operations which give an undefined result (such as division by +% \( 0 \)) or those which result in \( \pm \infty \) will not lead +% to errors. Instead special marker values are returned, which +% can be tested for using \cs{fp_if_undefined:N(TF)} and +% \cs{fp_if_infinity:N(TF)}. In this way it is possible to work with +% asymptopic functions without first checking the input. If these +% special values are carried forward in calculations they will be +% treated as \( 0 \). +% +% Fixed-point numbers are stored in the \texttt{fp} fixed-point +% variable type. This has a standard range of functions for +% variable management. +% +%\subsection{Fixed-point variables} +% +%\begin{function}{ +% \fp_new:N | +% \fp_new:c | +%} +% \begin{syntax} +% \cs{fp_new:N} \meta{fixed-point} +% \end{syntax} +% Creates a new \meta{fixed-point} or raises an error if the +% name is already taken. The declaration global. The +% \meta{fixed-point} will initially be set to "+0.000000000". +%\end{function} +% +%\begin{function}{ +% \fp_set_eq:NN | +% \fp_set_eq:cN | +% \fp_set_eq:Nc | +% \fp_set_eq:cc | +%} +% \begin{syntax} +% \cs{fp_set_eq:NN} \meta{fp1} \meta{fp2} +% \end{syntax} +% Sets the value of \meta{fixed-point1} equal to that of +% \meta{fixed-point2}. This assignment is restricted to the +% current \TeX\ group level. +%\end{function} +% +%\begin{function}{ +% \fp_gset_eq:NN | +% \fp_gset_eq:cN | +% \fp_gset_eq:Nc | +% \fp_gset_eq:cc | +%} +% \begin{syntax} +% \cs{tl_gset_eq:NN} \meta{tl var1} \meta{tl var2} +% \end{syntax} +% Sets the value of \meta{fixed-point1} equal to that of +% \meta{fixed-point2}. This assignment is global and so is +% not limited by the current \TeX\ group level. +%\end{function} +% +%\begin{function}{ +% \fp_zero:N | +% \fp_zero:c | +%} +% \begin{syntax} +% \cs{fp_zero:N} \meta{fixed-point} +% \end{syntax} +% Sets the \meta{fixed-point} to "+0.000000000" within the current +% scope. +%\end{function} +% +%\begin{function}{ +% \fp_gzero:N | +% \fp_gzero:c | +%} +% \begin{syntax} +% \cs{fp_gzero:N} \meta{fixed-point} +% \end{syntax} +% Sets the \meta{fixed-point} to "+0.000000000" globally. +%\end{function} +% +%\begin{function}{ +% \fp_set:Nn | +% \fp_set:cn | +%} +% \begin{syntax} +% \cs{fp_set:Nn} \meta{fixed-point} \Arg{value} +% \end{syntax} +% Sets the \meta{fixed-point} variable to \meta{value} within +% the scope of the current \TeX\ group. +%\end{function} +% +%\begin{function}{ +% \fp_gset:Nn | +% \fp_gset:cn | +%} +% \begin{syntax} +% \cs{fp_gset:Nn} \meta{fixed-point} \Arg{value} +% \end{syntax} +% Sets the \meta{fixed-point} variable to \meta{value} globally. +%\end{function} +% +%\begin{function}{ +% \fp_set_from_dim:Nn | +% \fp_set_from_dim:cn | +%} +% \begin{syntax} +% \cs{fp_set_from_dim:Nn} \meta{fixed-point} \Arg{dimexpr} +% \end{syntax} +% Sets the \meta{fixed-point} variable to the distance represented +% by the \meta{dimension expression} in the units points. This means +% that distances given in other units are first converted to points +% before being assigned to the \meta{fixed-point}. The assignment +% is local. +%\end{function} +% +%\begin{function}{ +% \fp_gset_from_dim:Nn | +% \fp_gset_from_dim:cn | +%} +% \begin{syntax} +% \cs{fp_gset_from_dim:Nn} \meta{fixed-point} \Arg{dimexpr} +% \end{syntax} +% Sets the \meta{fixed-point} variable to the distance represented +% by the \meta{dimension expression} in the units points. This means +% that distances given in other units are first converted to points +% before being assigned to the \meta{fixed-point}. The assignment +% is global. +%\end{function} +% +%\begin{function}{ +% \fp_show:N | +% \fp_show:c | +%} +% \begin{syntax} +% \cs{fp_show:N} \meta{fixed-point} +% \end{syntax} +% Displays the content of the \meta{fixed-point} on the +% terminal. +%\end{function} +% +%\subsection{Unary operations} +% +% The unary operations alter the value stored within an \texttt{fp} +% variable. +% +%\begin{function}{ +% \fp_abs:N | +% \fp_abs:c | +%} +% \begin{syntax} +% \cs{fp_abs:N} \meta{fixed-point} +% \end{syntax} +% Converts the \meta{fixed-point} to its absolute value, assigning +% the result within the current \TeX\ group. +%\end{function} +% +%\begin{function}{ +% \fp_gabs:N | +% \fp_gabs:c | +%} +% \begin{syntax} +% \cs{fp_gabs:N} \meta{fixed-point} +% \end{syntax} +% Converts the \meta{fixed-point} to its absolute value, assigning +% the result globally. +%\end{function} +% +%\begin{function}{ +% \fp_neg:N | +% \fp_neg:c | +%} +% \begin{syntax} +% \cs{fp_neg:N} \meta{fixed-point} +% \end{syntax} +% Reverse the sign of the \meta{fixed-point}, assigning the result +% within the current \TeX\ group. +%\end{function} +% +%\begin{function}{ +% \fp_gneg:N | +% \fp_gneg:c | +%} +% \begin{syntax} +% \cs{fp_gneg:N} \meta{fixed-point} +% \end{syntax} +% Reverse the sign of the \meta{fixed-point}, assigning the result +% globally. +%\end{function} +% +%\subsection{Transferring \texttt{fp} to \texttt{tl} data} +% +% The highly-structured internal format used for \texttt{fp} data +% will not generally be desirable for use in user output. As a result, +% the module provides a set of intermediate level functions to convert +% \texttt{fp} into \texttt{tl} material. This process is governed by +% a number of settings, which determine how the output is rounded and +% how trailing zeros are handled. +% +%\begin{function}{ +% \fp_to_tl:NN | +% \fp_to_tl:Nc | +% \fp_to_tl:cN | +% \fp_to_tl:cc | +%} +% \begin{syntax} +% \cs{fp_to_tl:NN} \meta{fixed-point} \meta{token list variable} +% \end{syntax} +% Transfers the content of the \meta{fixed-point} into the +% \meta{token list variable}, formatting according to the currently +% prevailing formatting settings. The \meta{token list variable} is +% set within the current \TeX\ group. +%\end{function} +% +%\begin{function}{ +% \fp_gto_tl:NN | +% \fp_gto_tl:Nc | +% \fp_gto_tl:cN | +% \fp_gto_tl:cc | +%} +% \begin{syntax} +% \cs{fp_gto_tl:NN} \meta{fixed-point} \meta{token list variable} +% \end{syntax} +% Transfers the content of the \meta{fixed-point} into the +% \meta{token list variable}, formatting according to the currently +% prevailing formatting settings. The \meta{token list variable} is +% set globally. +%\end{function} +% +% The exact behaviour of the transfer process is governed by a small +% family of key--value settings. These are accessible using the +% \cs{keys_set:nn} function in the \texttt{fp} path: +%\begin{verbatim} +% \keys_set:nn { fp } { +% % Settings here +% } +%\end{verbatim} +% +%\DescribeOption{remove-trailing-zeros} +% The Boolean setting \texttt{remove-trailing-zeros} is used to govern +% whether trailing zeros in the decimal part of the \texttt{fp} are +% removed. +%\begin{verbatim} +% \fp_new:N \l_test_fp +% \tl_new:N \l_test_tl +% \fp_set:Nn \l_test_fp { 1.234 } +% \keys_set:nn { fp } { remove-trailing-zeros = false } +% \fp_to_tl \l_test_fp \l_test_tl % => '1.234000000' +% \keys_set:nn { fp } { remove-trailing-zeros = true } +% \fp_to_tl \l_test_fp \l_test_tl % => '1.234' +%\end{verbatim} +% Removing trailing zeros will always leave the result as a real number: +%\begin{verbatim} +% \fp_set:Nn \l_test_fp { 1.0 } +% \keys_set:nn { fp } { remove-trailing-zeros = true } +% \fp_to_tl \l_test_fp \l_test_tl % => '1.0' +%\end{verbatim} +% +%\DescribeOption{round-mode} +%\DescribeOption{precision} +% The two options \texttt{round-mode} and \texttt{precision} determine +% whether any rounding takes place for the decimal part of the output, +% and if so how many significant output digits are retained. The +% \texttt{precision} option indicates how many decimal digits should +% be retained in the output, and therefore takes numerical values +% only. The \texttt{round-mode} option takes one of the values +% \texttt{none}, \texttt{truncate}, \texttt{half-from-zero} and +% \texttt{half-even}. The \texttt{none} setting completely disables any +% rounding, and therefore does not interact at all with +% \texttt{precision}. The number of digits in the \texttt{tl} will +% therefore depend only on the values in the \texttt{fp}, and whether +% \texttt{remove-trailing-zeros} is active +%\begin{verbatim} +% \fp_set:Nn \l_test_fp { 1.234 } +% \keys_set:nn { fp } { +% round-mode = none , +% remove-trailing-zeros = false , +% } +% \fp_to_tl \l_test_fp \l_test_tl % => '1.234000000' +% \keys_set:nn { fp } { +% round-mode = none , +% remove-trailing-zeros = true , +% } +% \fp_to_tl \l_test_fp \l_test_tl % => '1.234' +%\end{verbatim} +% In all other cases (\texttt{truncate}, \texttt{half-from-zero} +% and \texttt{half-even}) modification of the \texttt{fp} value will +% always provide the number of decimal digits specified by +% \texttt{precision}. This includes trailing zeros if they fall within +% the \texttt{precision} requested. The \texttt{truncate} setting will +% cause the transfer to simply discard excess decimal digits. +%\begin{verbatim} +% \keys_set:nn { fp } { +% precision = 3 , +% remove-trailing-zeros = true , +% round-mode = truncate , +% } +% \fp_set:Nn \l_test_fp { 1.23556 } +% \fp_to_tl \l_test_fp \l_test_tl % => 1.235 +% \fp_set:Nn \l_test_fp { 1.2 } +% \fp_to_tl \l_test_fp \l_test_tl % => 1.200 +%\end{verbatim} +% The \texttt{half-from-zero} setting will round the number such that +% if the digit to be rounded is \( 5 \) then rounding will occur +% away from zero (increasing the absolute value). +%\begin{verbatim} +% \keys_set:nn { fp } { +% precision = 3 , +% remove-trailing-zeros = true , +% round-mode = half-from-zero , +% } +% \fp_set:Nn \l_test_fp { 1.23556 } +% \fp_to_tl \l_test_fp \l_test_tl % => 1.236 +% \fp_set:Nn \l_test_fp { 1.2358 } +% \fp_to_tl \l_test_fp \l_test_tl % => 1.236 +% \fp_set:Nn \l_test_fp { 1.23505 } +% \fp_to_tl \l_test_fp \l_test_tl % => 1.235 +% \fp_set:Nn \l_test_fp { -1.23556 } +% \fp_to_tl \l_test_fp \l_test_tl % => -1.236 +% \fp_set:Nn \l_test_fp { -1.23 } +% \fp_to_tl \l_test_fp \l_test_tl % => -1.230 +%\end{verbatim} +% The alternative \texttt{half-even} setting behaves indentically to +% \texttt{half-from-zero} apart from the case where the discarded number +% is exctly half. In this special case the result is rounded to the +% nearest even number in the final digit. This form of rounding is +% sometimes used as it is does not add any bias to the final result. +%\begin{verbatim} +% \keys_set:nn { fp } { +% precision = 3 , +% remove-trailing-zeros = true , +% round-mode = half-even , +% } +% \fp_set:Nn \l_test_fp { 1.23556 } +% \fp_to_tl \l_test_fp \l_test_tl % => 1.236 +% \fp_set:Nn \l_test_fp { 1.23550 } +% \fp_to_tl \l_test_fp \l_test_tl % => 1.236 +% \fp_set:Nn \l_test_fp { 1.23450 } +% \fp_to_tl \l_test_fp \l_test_tl % => 1.234 +% \fp_set:Nn \l_test_fp { 1.234500001 } +% \fp_to_tl \l_test_fp \l_test_tl % => 1.235 +%\end{verbatim} +% +%\subsection{Constants} +% +%\begin{variable}{ \c_zero_fp } +% A permanently zero fixed-point variable. +%\end{variable} +% +%\begin{variable}{ \c_undefined_fp } +% A special marker fixed-point variable representing the result of +% an operation which does not give a defined result (such as division +% by \( 0 \)). +%\end{variable} +% +%\begin{variable}{ \c_infinity_fp } +% A special marker fixed-point variable representing \( \infty \). +%\end{variable} +% +%\begin{variable}{ \c_minus_infinity_fp } +% A special marker fixed-point variable representing \( -\infty \). +%\end{variable} +% +%\subsection{Tests on fixed-point values} +% +%\begin{function}{ +% \fp_if_infinite_p:N / (EXP) | +% \fp_if_infinite:N / (EXP) (TF) | +%} +% \begin{syntax} +% \cs{fp_if_infinite_p:N} \meta{fixed-point} +% \cs{fp_if_infinite:NTF} \meta{fixed-point} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if \meta{fixed-point} is infinite (\emph{i.e}.~equal to the +% either of the special marker variables \cs{c_infinity_fp} or +% \cs{c_minus_infinity_fp}). The branching versions then leave either +% \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the +% function chosen. The logical truth of the test is left in the input +% stream by the predicate version. +%\end{function} +% +%\begin{function}{ +% \fp_if_plus_infinity_p:N / (EXP) | +% \fp_if_plus_infinity:N / (EXP) (TF) | +%} +% \begin{syntax} +% \cs{fp_if_plus_infinity_p:N} \meta{fixed-point} +% \cs{fp_if_plus_infinity:NTF} \meta{fixed-point} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if \meta{fixed-point} is \( +\infty \) (\emph{i.e}.~equal to +% the special \cs{c_infinity_fp} variable). The branching versions then +% leave either \meta{true code} or \meta{false code} in the input +% stream, as appropriate to the truth of the test and the variant of +% the function chosen. The logical truth of the test is left in the +% input stream by the predicate version. +%\end{function} +% +%\begin{function}{ +% \fp_if_minus_infinity_p:N / (EXP) | +% \fp_if_minus_infinity:N / (EXP) (TF) | +%} +% \begin{syntax} +% \cs{fp_if_minus_infinity_p:N} \meta{fixed-point} +% \cs{fp_if_minus_infinity:NTF} \meta{fixed-point} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if \meta{fixed-point} is \( +\infty \) (\emph{i.e}.~equal to +% the special \cs{c_minus_infinity_fp} variable). The branching +% versions then leave either \meta{true code} or \meta{false code} in +% the input stream, as appropriate to the truth of the test and the +% variant of the function chosen. The logical truth of the test is left +% in the input stream by the predicate version. +%\end{function} +% +%\begin{function}{ +% \fp_if_undefined_p:N / (EXP) | +% \fp_if_undefined:N / (EXP) (TF) | +%} +% \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} +% \end{syntax} +% Tests if \meta{fixed-point} is undefined (\emph{i.e}.~equal to the +% special \cs{c_undefined_fp} variable). The branching versions then +% leave either \meta{true code} or \meta{false code} in the input +% stream, as appropriate to the truth of the test and the variant of +% the function chosen. The logical truth of the test is left in the +% input stream by the predicate version. +%\end{function} +% +%\begin{function}{ +% \fp_if_zero_p:N / (EXP) | +% \fp_if_zero:N / (EXP) (TF) | +%} +% \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} +% \end{syntax} +% Tests if \meta{fixed-point} is equal to zero (\emph{i.e}.~equal to +% the special \cs{c_zero_fp} variable). The branching versions then +% leave either \meta{true code} or \meta{false code} in the input +% stream, as appropriate to the truth of the test and the variant of +% the function chosen. The logical truth of the test is left in the +% input stream by the predicate version. +%\end{function} +% +%\begin{function}{ +% \fp_compare:nNn / (TF) | +% \fp_compare:NNN / (TF) | +%} +% \begin{syntax} +% \cs{fp_compare:nNnTF} \Arg{value1} \meta{relation} \Arg{value2} +% ~~\Arg{true code} \Arg{false code} +% \cs{fp_compare:NNNTF} \Arg{fp1} \meta{relation} \Arg{fp2} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Compares the two \meta{values} or \meta{fixed-points} based on the +% \meta{relation} (\texttt{=}, \verb"<" or \verb">"), and leaves +% either the \meta{true code} or \meta{false code} in the input stream, +% as appropriate to the truth of the test and the variant of the +% function chosen. The tests treat undefined fixed-points +% as zero, as the comparison is intended for real numbers only. +%\end{function} +% +%\subsection{Arithmetic operations} +% +% 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 \)). +% +%\begin{function}{ +% \fp_add:Nn | +% \fp_add:cn | +%} +% \begin{syntax} +% \cs{fp_add:Nn} \meta{fixed-point} \Arg{value} +% \end{syntax} +% Adds the \meta{value} to the \meta{fixed-point}, making the +% assignment within the current \TeX\ group level. +%\end{function} +% +%\begin{function}{ +% \fp_gadd:Nn | +% \fp_gadd:cn | +%} +% \begin{syntax} +% \cs{fp_gadd:Nn} \meta{fixed-point} \Arg{value} +% \end{syntax} +% Adds the \meta{value} to the \meta{fixed-point}, making the +% assignment globally. +%\end{function} +% +%\begin{function}{ +% \fp_sub:Nn | +% \fp_sub:cn | +%} +% \begin{syntax} +% \cs{fp_sub:Nn} \meta{fixed-point} \Arg{value} +% \end{syntax} +% Subtracts the \meta{value} from the \meta{fixed-point}, making the +% assignment within the current \TeX\ group level. +%\end{function} +% +%\begin{function}{ +% \fp_gsub:Nn | +% \fp_gsub:cn | +%} +% \begin{syntax} +% \cs{fp_gsub:Nn} \meta{fixed-point} \Arg{value} +% \end{syntax} +% Subtracts the \meta{value} from the \meta{fixed-point}, making the +% assignment globally. +%\end{function} +% +%\begin{function}{ +% \fp_mul:Nn | +% \fp_mul:cn | +%} +% \begin{syntax} +% \cs{fp_mul:Nn} \meta{fixed-point} \Arg{value} +% \end{syntax} +% Multiples the \meta{fixed-point} by the \meta{value}, making the +% assignment within the current \TeX\ group level. +%\end{function} +% +%\begin{function}{ +% \fp_gmul:Nn | +% \fp_gmul:cn | +%} +% \begin{syntax} +% \cs{fp_gmul:Nn} \meta{fixed-point} \Arg{value} +% \end{syntax} +% Multiples the \meta{fixed-point} by the \meta{value}, making the +% assignment globally. +%\end{function} +% +%\begin{function}{ +% \fp_div:Nn | +% \fp_div:cn | +%} +% \begin{syntax} +% \cs{fp_div:Nn} \meta{fixed-point} \Arg{value} +% \end{syntax} +% Divides the \meta{fixed-point} by the \meta{value}, making the +% assignment within the current \TeX\ group level. If the \meta{value} +% is zero, the \meta{fixed-point} will be set to \cs{c_undefined_fp}. +%\end{function} +% +%\begin{function}{ +% \fp_gdiv:Nn | +% \fp_gdiv:cn | +%} +% \begin{syntax} +% \cs{fp_gdiv:Nn} \meta{fixed-point} \Arg{value} +% \end{syntax} +% Divides the \meta{fixed-point} by the \meta{value}, making the +% assignment globally. If the \meta{value} is zero, the +% \meta{fixed-point} will be set to \cs{c_undefined_fp}. +%\end{function} +% +%\end{documentation} +% +%\begin{implementation} +% +%\section{Implementation} +% +% Announce and ensure that the required packages are loaded. +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\filename}{\filedate}{\fileversion}{\filedescription} +\package_check_loaded_expl: +%</package> +%<*initex|package> +% \end{macrocode} +% +% Internally, a fixed-point number is a token list variable of the +% correct format. The first token in the variable is the sign: normally +% this will be "+" or "-", but this token can also be used to indicate +% a special state (for exampe if a calculation would give infinity as +% a result). The main part of the number is then stored as a decimal: +% there are always nine digits in the decimal part. This ensures that +% two numbers which are equal to one another will always be stored in +% the same way. For the same reason, zero is stored as "+0.000000000". +% +%\subsection{General variables} +% +%\begin{macro}{\l_fp_input_a_integer_int} +%\begin{macro}{\l_fp_input_a_decimal_int} +%\begin{macro}{\l_fp_input_b_integer_int} +%\begin{macro}{\l_fp_input_b_decimal_int} +% Storage for the input, divided into integer and decimal parts. +% \begin{macrocode} +\int_new:N \l_fp_input_a_integer_int +\int_new:N \l_fp_input_a_decimal_int +\int_new:N \l_fp_input_b_integer_int +\int_new:N \l_fp_input_b_decimal_int +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\l_fp_input_a_sign_int} +%\begin{macro}{\l_fp_input_b_sign_int} +% The sign of each item in the input is stored as an \texttt{int} as +% this allows some faster manipulation than would otherwise be possible. +% \begin{macrocode} +\int_new:N \l_fp_input_a_sign_int +\int_new:N \l_fp_input_b_sign_int +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\l_fp_split_sign_int} +% Used to speed up the sign-finding system. +% \begin{macrocode} +\int_new:N \l_fp_split_sign_int +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_fp_mul_a_i_int} +%\begin{macro}{\l_fp_mul_a_ii_int} +%\begin{macro}{\l_fp_mul_a_iii_int} +%\begin{macro}{\l_fp_mul_a_iv_int} +%\begin{macro}{\l_fp_mul_a_v_int} +%\begin{macro}{\l_fp_mul_a_vi_int} +%\begin{macro}{\l_fp_mul_b_i_int} +%\begin{macro}{\l_fp_mul_b_ii_int} +%\begin{macro}{\l_fp_mul_b_iii_int} +%\begin{macro}{\l_fp_mul_b_iv_int} +%\begin{macro}{\l_fp_mul_b_v_int} +%\begin{macro}{\l_fp_mul_b_vi_int} +% For multiplication, each number is split into six parts (three for the +% decimal, three for the integer). So that they are a bt easier to keep +% a track of these are simply numbered: i--iii are the integer and iv-vi +% the decimal part. +% \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{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}{\l_fp_mul_output_int} +%\begin{macro}{\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{macro} +%\end{macro} +% +%\begin{macro}{\l_fp_div_count_int} +%\begin{macro}{\l_fp_div_offset_int} +% Values used during division: an offset for small denominators and +% a count for the actual division. +% \begin{macrocode} +\int_new:N \l_fp_div_count_int +\int_new:N \l_fp_div_offset_int +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\l_fp_output_sign_int} +%\begin{macro}{\l_fp_output_integer_int} +%\begin{macro}{\l_fp_output_decimal_int} +% 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 +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\l_fp_round_carry_bool} +%\begin{macro}{\l_fp_round_decimal_tl} +%\begin{macro}{\l_fp_round_discard_int} +%\begin{macro}{\l_fp_round_position_int} +% The rounding system needs space to track carrying forward and also +% to hold onto dicarded material (which may be relevant when rounding +% to an even last digit). The current position in the decimal part also +% needs to be tracked. For speed reasons, the decimal part of the number +% is build back up in a token list when rounding, as this avoids +% worrying about place value. +% \begin{macrocode} +\bool_new:N \l_fp_round_carry_bool +\tl_new:N \l_fp_round_decimal_tl +\int_new:N \l_fp_round_discard_int +\int_new:N \l_fp_round_position_int +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\l_fp_tmp_int} +% A scratch \texttt{int}: used only where the value is not carried +% forward. +% \begin{macrocode} +\int_new:N \l_fp_tmp_int +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_fp_tmp_tl} +% The usual scratch token list. +% \begin{macrocode} +\tl_new:N \l_fp_tmp_tl +% \end{macrocode} +%\end{macro} +% +%\subsection{Constants} +% +%\begin{macro}{\c_zero_fp} +% The constanct zero value. +% \begin{macrocode} +\tl_new:N \c_zero_fp +\tl_set:Nn \c_zero_fp { + 0.000000000 } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\c_undefined_fp} +%\begin{macro}{\c_infinity_fp} +%\begin{macro}{\c_minus_infinity_fp} +% Special marker values for various mathematically-valid results which +% are not fixed-point numbers. +% \begin{macrocode} +\tl_new:N \c_undefined_fp +\tl_set:Nn \c_undefined_fp { X 0.000000000 } +\tl_new:N \c_infinity_fp +\tl_set:Nn \c_infinity_fp { +2147483647.2147483647 } +\tl_new:N \c_minus_infinity_fp +\tl_set:Nn \c_minus_infinity_fp { -2147483647.2147483647 } +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\c_one_hundred_million} +%\begin{macro}{\c_one_thousand_million} +% There is some speed to gain by moving numbers into fixed positions. +% \begin{macrocode} +\int_new:N \c_one_hundred_million +\int_set:Nn \c_one_hundred_million { 100000000 } +\int_new:N \c_one_thousand_million +\int_set:Nn \c_one_thousand_million { 1000000000 } +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\subsection{Tests for special values} +% +%\begin{macro}{\fp_if_infinite_p:N} +%\begin{macro}[TF]{\fp_if_infinite:N} +%\begin{macro}{\fp_if_plus_infinity_p:N} +%\begin{macro}[TF]{\fp_if_plus_infinity:N} +%\begin{macro}{\fp_if_minus_infinity_p:N} +%\begin{macro}[TF]{\fp_if_minus_infinity:N} +% Testing for infinite values is complicated by the sign of infinity. +% There are therefore three tests, one which will match \( +\infty \) +% or \( -\infty \) and one test each for the two individual cases. +% \begin{macrocode} +\prg_new_conditional:Npnn \fp_if_infinite:N #1 { p , T , F , TF } { + \tex_ifx:D #1 \c_infinity_fp + \prg_return_true: + \tex_else:D + \tex_ifx:D #1 \c_minus_infinity_fp + \prg_return_true: + \tex_else:D + \prg_return_false: + \tex_fi:D + \tex_fi:D +} +\prg_new_conditional:Npnn \fp_if_plus_infinity:N #1 { p , T , F , TF } { + \tex_ifx:D #1 \c_infinity_fp + \prg_return_true: + \tex_else:D + \prg_return_false: + \tex_fi:D +} +\prg_new_conditional:Npnn \fp_if_minus_infinity:N #1 { p , T , F , TF } + { + \tex_ifx:D #1 \c_minus_infinity_fp + \prg_return_true: + \tex_else:D + \prg_return_false: + \tex_fi:D +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_if_undefined_p:N} +%\begin{macro}[TF]{\fp_if_undefined:N} +% Testing for an undefined value is easy. +% \begin{macrocode} +\prg_new_conditional:Npnn \fp_if_undefined:N #1 { p , T , F , TF } { + \tex_ifx:D #1 \c_undefined_fp + \prg_return_true: + \tex_else:D + \prg_return_false: + \tex_fi:D +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_if_zero_p:N} +%\begin{macro}[TF]{\fp_if_zero:N} +% Testing for a zero fixed-point is also easy. +% \begin{macrocode} +\prg_new_conditional:Npnn \fp_if_zero:N #1 { p , T , F , TF } { + \tex_ifx:D #1 \c_zero_fp + \prg_return_true: + \tex_else:D + \prg_return_false: + \tex_fi:D +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\subsection{Operations for \texttt{fp} variables} +% +%\begin{macro}{\fp_new:N} +%\begin{macro}{\fp_new:c} +% Fixed-points always have a value, and of course this has to be +% initialised globally. +% \begin{macrocode} +\cs_new_protected_nopar: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} +%\end{macro} +% +%\begin{macro}{\fp_zero:N} +%\begin{macro}{\fp_zero:c} +%\begin{macro}{\fp_gzero:N} +%\begin{macro}{\fp_gzero:c} +% Zeroing fixed-points is pretty obvious. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_zero:N #1 { + \tl_set_eq:NN #1 \c_zero_fp +} +\cs_new_protected_nopar: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} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_set:Nn} +%\begin{macro}{\fp_set:cn} +%\begin{macro}{\fp_gset:Nn} +%\begin{macro}{\fp_gset:cn} +%\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_nopar:Npn \fp_set_aux:NNn #1#2#3 { + \group_begin: + \fp_split:Nn a {#3} + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \tl_set:Nx \l_fp_tmp_tl + { + \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero + - + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + } + \exp_after:wN \group_end: \exp_after:wN + #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } +} +\cs_generate_variant:Nn \fp_set:Nn { c } +\cs_generate_variant:Nn \fp_gset:Nn { c } +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_set_from_dim:Nn} +%\begin{macro}{\fp_set_from_dim:cn} +%\begin{macro}{\fp_gset_from_dim:Nn} +%\begin{macro}{\fp_gset_from_dim:cn} +%\begin{macro}[aux]{\fp_set_from_dim_aux:NNn} +%\begin{macro}[aux]{\fp_set_from_dim_aux:w} +%\begin{macro}{\l_fp_tmp_dim} +% 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. +% \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_nopar:Npn \fp_set_from_dim_aux:NNn #1#2#3 { + \group_begin: + \l_fp_tmp_dim \etex_dimexpr:D #3 \scan_stop: + \fp_split:Nn a + { + \exp_after:wN \fp_set_from_dim_aux:w + \dim_use:N \l_fp_tmp_dim + } + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \tl_set:Nx \l_fp_tmp_tl + { + \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero + - + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + } + \exp_after:wN \group_end: \exp_after:wN + #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } +} +\cs_set_protected_nopar:Npx \fp_set_from_dim_aux:w { + \cs_set_nopar: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_tmp_dim +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_set_eq:NN} +%\begin{macro}{\fp_set_eq:cN} +%\begin{macro}{\fp_set_eq:Nc} +%\begin{macro}{\fp_set_eq:cc} +%\begin{macro}{\fp_gset_eq:NN} +%\begin{macro}{\fp_gset_eq:cN} +%\begin{macro}{\fp_gset_eq:Nc} +%\begin{macro}{\fp_gset_eq:cc} +% 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} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_show:N} +%\begin{macro}{\fp_show:c} +% 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} +%\end{macro} +% +%\begin{macro}{\fp_use:N} +%\begin{macro}{\fp_use:c} +% These are token lists, so this is easy. +% \begin{macrocode} +\cs_new_eq:NN \fp_use:N \tl_use:N +\cs_new_eq:NN \fp_use:c \tl_use:c +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\subsection{Internal utilities} +% +%\begin{macro}{\fp_read:N} +%\begin{macro}[aux]{\fp_read_aux:w} +% Reading a stored value is made easier as the format is designed to +% match the delimited function. This is always used to read the first +% value (register "a"). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_read:N #1 { + \exp_after:wN \fp_read_aux:w #1 \q_stop +} +\cs_new_protected_nopar:Npn \fp_read_aux:w #1#2 . #3 \q_stop { + \tex_if:D #1 - + \l_fp_input_a_sign_int \c_minus_one + \tex_else:D + \l_fp_input_a_sign_int \c_one + \tex_fi:D + \l_fp_input_a_integer_int #2 \scan_stop: + \l_fp_input_a_decimal_int #3 \scan_stop: +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_split:Nn} +%\begin{macro}[aux]{\fp_split_sign:} +%\begin{macro}[aux]{\fp_split_aux_i:w} +%\begin{macro}[aux]{\fp_split_aux_ii:w} +%\begin{macro}[aux]{\fp_split_aux_iii:w} +%\begin{macro}[aux]{\fp_split_decimal:w} +%\begin{macro}[aux]{\fp_split_decimal_aux:w} +% The aim here is to use as much of \TeX's mechanism as possible to pick +% up the numerical input without any mistakes. In particular, negative +% numbers have to be filtered out first in case the integer part is +% \( 0 \) (in which case \TeX\ would drop the "-" sign). That process +% has to be done in a loop for cases where the sign is repeated. The +% next phase is to find the integer part, which will terminate +% with a ".", and trigger the decimal-finding code. The later will +% allow the decimal to be too long, truncating the result. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_split:Nn #1#2 { + \tl_set:Nx \l_fp_tmp_tl {#2} + \l_fp_split_sign_int \c_one + \fp_split_sign: + \use:c { l_fp_input_ #1 _sign_int } \l_fp_split_sign_int + \tex_afterassignment:D \fp_split_aux_i:w + \use:c { l_fp_input_ #1 _integer_int } + \etex_numexpr:D 0 \l_fp_tmp_tl . . \q_stop #1 +} +\cs_new_protected_nopar:Npn \fp_split_sign: { + \tex_ifnum:D \pdf_strcmp:D + { \exp_after:wN \tl_head:w \l_fp_tmp_tl ? \q_nil } { - } + = \c_zero + \tl_set:Nx \l_fp_tmp_tl + { + \exp_after:wN + \tl_tail:w \l_fp_tmp_tl \prg_do_nothing: \q_nil + } + \l_fp_split_sign_int -\l_fp_split_sign_int + \exp_after:wN \fp_split_sign: + \tex_else:D + \tex_ifnum:D \pdf_strcmp:D + { \exp_after:wN \tl_head:w \l_fp_tmp_tl ? \q_nil } { + } + = \c_zero + \tl_set:Nx \l_fp_tmp_tl + { + \exp_after:wN + \tl_tail:w \l_fp_tmp_tl \prg_do_nothing: \q_nil + } + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_split_sign: + \tex_fi:D + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_split_aux_i:w #1 . #2 . #3 \q_stop { + \fp_split_aux_ii:w #2 000000000 \q_stop +} +\cs_new_protected_nopar:Npn \fp_split_aux_ii:w #1#2#3#4#5#6#7#8#9 { + \fp_split_aux_iii:w {#1#2#3#4#5#6#7#8#9} +} +\cs_new_protected_nopar:Npn \fp_split_aux_iii:w #1#2 \q_stop { + \l_fp_tmp_int 1 #1 \scan_stop: + \exp_after:wN \fp_split_decimal:w + \int_use:N \l_fp_tmp_int 000000000 \q_stop +} +\cs_new_protected_nopar:Npn \fp_split_decimal:w #1#2#3#4#5#6#7#8#9 { + \fp_split_decimal_aux:w {#2#3#4#5#6#7#8#9} +} +\cs_new_protected_nopar:Npn \fp_split_decimal_aux:w #1#2#3 \q_stop #4 { + \use:c { l_fp_input_ #4 _decimal_int } #1#2 \scan_stop: + \tex_ifnum:D + \etex_numexpr:D + \use:c { l_fp_input_ #4 _integer_int } + + \use:c { l_fp_input_ #4 _decimal_int } + \scan_stop: + = \c_zero + \use:c { l_fp_input_ #4 _sign_int } \c_one + \tex_fi:D +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\subsection{Unary functions} +% +%\begin{macro}{\fp_abs:N} +%\begin{macro}{\fp_abs:c} +%\begin{macro}{\fp_gabs:N} +%\begin{macro}{\fp_gabs:c} +%\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:NN \tl_set:Nn +} +\cs_new_protected_nopar:Npn \fp_gabs:N { + \fp_abs:NN \tl_gset:Nn +} +\cs_generate_variant:Nn \fp_abs:N { c } +\cs_generate_variant:Nn \fp_gabs:N { c } +\cs_new_protected_nopar:Npn \fp_abs:NN #1#2 { + \group_begin: + \fp_read:N #2 + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \tl_set:Nx \l_fp_tmp_tl + { + + + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + } + \exp_after:wN \group_end: \exp_after:wN + #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_neg:N} +%\begin{macro}{\fp_neg:c} +%\begin{macro}{\fp_gneg:N} +%\begin{macro}{\fp_gneg:c} +%\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_nopar: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_tmp_tl + { + \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero + + + \tex_else:D + - + \tex_fi:D + \int_use:N \l_fp_input_a_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_input_a_decimal_int + } + \exp_after:wN \group_end: \exp_after:wN + #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\subsection{Basic arithmetic} +% +%\begin{macro}{\fp_add:Nn} +%\begin{macro}{\fp_add:cn} +%\begin{macro}{\fp_gadd:Nn} +%\begin{macro}{\fp_gadd:cn} +%\begin{macro}[aux]{\fp_add_aux:NNn} +%\begin{macro}[aux]{\fp_add_core:} +% 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_nopar:Npn \fp_add_aux:NNn #1#2#3 { + \group_begin: + \fp_read:N #2 + \fp_split:Nn b {#3} + \fp_add_core: + \exp_after:wN \group_end: \exp_after:wN + #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } +} +\cs_new_protected_nopar:Npn \fp_add_core: { + \tex_ifnum:D + \etex_numexpr:D + \l_fp_input_a_sign_int * \l_fp_input_b_sign_int + \scan_stop: + > \c_zero + \exp_after:wN \fp_add_sum: + \tex_else:D + \exp_after:wN \fp_add_difference: + \tex_fi:D + \tl_set:Nx \l_fp_tmp_tl + { + \tex_ifnum:D \l_fp_output_sign_int < \c_zero + - + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_output_decimal_int + } +} +% \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 + \etex_numexpr:D + \l_fp_input_a_integer_int + \l_fp_input_b_integer_int + \scan_stop: + \l_fp_output_decimal_int + \etex_numexpr:D + \l_fp_input_a_decimal_int + \l_fp_input_b_decimal_int + \scan_stop: + \tex_ifnum:D \l_fp_output_decimal_int < \c_one_thousand_million + \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million + \tex_else:D + \tex_advance:D \l_fp_output_integer_int \c_one + \tex_fi:D +} +% \end{macrocode} +% When the signs of the two parts of the input are different, the +% absolute difference is worked out first. There is then a caculation to +% see which way around everything has worked out, so that the final +% sign is correct. The differnce might also give a zero resul with +% 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 + \etex_numexpr:D + \l_fp_input_a_integer_int - \l_fp_input_b_integer_int + \scan_stop: + \l_fp_output_decimal_int + \etex_numexpr:D + \l_fp_input_a_decimal_int - \l_fp_input_b_decimal_int + \scan_stop: + \tex_ifnum:D \l_fp_output_decimal_int < \c_zero + \tex_advance:D \l_fp_output_integer_int \c_minus_one + \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million + \tex_fi:D + \tex_ifnum:D \l_fp_output_integer_int < \c_zero + \l_fp_output_sign_int \l_fp_input_b_sign_int + \tex_ifnum:D \l_fp_output_decimal_int = \c_zero + \l_fp_output_integer_int -\l_fp_output_integer_int + \tex_else:D + \l_fp_output_decimal_int + \etex_numexpr:D + \c_one_thousand_million - \l_fp_output_decimal_int + \scan_stop: + \l_fp_output_integer_int + \etex_numexpr:D + - \l_fp_output_integer_int - \c_one + \scan_stop: + \tex_fi:D + \tex_else:D + \l_fp_output_sign_int \l_fp_input_a_sign_int + \tex_fi:D + \tex_ifnum:D + \etex_numexpr:D + \l_fp_output_integer_int + \l_fp_output_decimal_int + \scan_stop: + = \c_zero + \l_fp_output_sign_int \c_one + \tex_fi:D + \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_sub:Nn} +%\begin{macro}{\fp_sub:cn} +%\begin{macro}{\fp_gsub:Nn} +%\begin{macro}{\fp_gsub:cn} +%\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_nopar:Npn \fp_sub_aux:NNn #1#2#3 { + \group_begin: + \fp_read:N #2 + \fp_split:Nn b {#3} + \tex_multiply:D \l_fp_input_b_sign_int \c_minus_one + \fp_add_core: + \exp_after:wN \group_end: \exp_after:wN + #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_mul:Nn} +%\begin{macro}{\fp_mul:cn} +%\begin{macro}{\fp_gmul:Nn} +%\begin{macro}{\fp_gmul:cn} +%\begin{macro}[aux]{\fp_mul_aux:NNn} +%\begin{macro}[aux]{\fp_mul_split:NNNN} +%\begin{macro}[aux]{\fp_mul_split:w} +%\begin{macro}[aux]{\fp_mul_end_level:} +%\begin{macro}[aux]{\fp_mul_end_level:w} +% 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_nopar:Npn \fp_mul_aux:NNn #1#2#3 { + \group_begin: + \fp_read:N #2 + \fp_split:Nn b {#3} + \fp_mul_split:NNNN \l_fp_input_a_integer_int + \l_fp_mul_a_i_int \l_fp_mul_a_ii_int \l_fp_mul_a_iii_int + \fp_mul_split:NNNN \l_fp_input_a_decimal_int + \l_fp_mul_a_iv_int \l_fp_mul_a_v_int \l_fp_mul_a_vi_int + \fp_mul_split:NNNN \l_fp_input_b_integer_int + \l_fp_mul_b_i_int \l_fp_mul_b_ii_int \l_fp_mul_b_iii_int + \fp_mul_split:NNNN \l_fp_input_b_decimal_int + \l_fp_mul_b_iv_int \l_fp_mul_b_v_int \l_fp_mul_b_vi_int + \l_fp_mul_output_int \c_zero + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_vi_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_iv_int + \tex_divide:D \l_fp_mul_output_int \c_thousand + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_vi_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_iii_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_vi_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_ii_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_vi_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_vi_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \l_fp_output_decimal_int 0 \l_fp_mul_output_tl \scan_stop: + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_v_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_v_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iv_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iv_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_iii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_iii_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \l_fp_output_integer_int 0 \l_fp_mul_output_tl \scan_stop: + \tl_clear:N \l_fp_mul_output_tl + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_ii_int + \fp_mul_product:NN \l_fp_mul_a_ii_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \fp_mul_product:NN \l_fp_mul_a_i_int \l_fp_mul_b_i_int + \fp_mul_end_level: + \tex_ifnum:D \l_fp_mul_output_tl = \c_zero + \tex_else:D + \exp_after:wN \fp_msg_overflow: + \tex_fi:D + \tex_advance:D \l_fp_output_decimal_int \c_one_thousand_million + \tl_set:Nx \l_fp_tmp_tl + { + \tex_ifnum:D + \etex_numexpr:D + \l_fp_input_a_sign_int * \l_fp_input_b_sign_int + \scan_stop: + < \c_zero + \tex_ifnum:D + \etex_numexpr:D + \l_fp_output_integer_int + \l_fp_output_decimal_int + \scan_stop: + = \c_one_thousand_million + + + \tex_else:D + - + \tex_fi:D + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_output_decimal_int + } + \exp_after:wN \group_end: \exp_after:wN + #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } +} +% \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_nopar:Npn \fp_mul_split:NNNN #1#2#3#4 { + \tex_advance:D #1 \c_one_thousand_million + \cs_set_protected_nopar: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 +} +\cs_new_protected_nopar:Npn \fp_mul_product:NN #1#2 { + \l_fp_mul_output_int + \etex_numexpr:D \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 \fp_mul_end_level:w + \int_use:N \l_fp_mul_output_int \q_stop +} +\cs_new_protected_nopar:Npn \fp_mul_end_level:w + #1#2#3#4#5#6#7#8#9 \q_stop { + \tl_set:Nx \l_fp_mul_output_tl { #8#9 \l_fp_mul_output_tl } + \l_fp_mul_output_int #5#6#7 \scan_stop: +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_div:Nn} +%\begin{macro}{\fp_div:cn} +%\begin{macro}{\fp_gdiv:Nn} +%\begin{macro}{\fp_gdiv:cn} +%\begin{macro}[aux]{\fp_div_aux:NNn} +%\begin{macro}[aux]{\fp_div_aux:} +%\begin{macro}[aux]{\fp_div_offset_create:} +%\begin{macro}[aux]{\fp_div_offset_create_aux:w} +%\begin{macro}[aux]{\fp_div_loop:} +%\begin{macro}[aux]{\fp_div_loop_aux_i:w} +%\begin{macro}[aux]{\fp_div_loop_aux_ii:w} +%\begin{macro}[aux]{\fp_div_divide:} +%\begin{macro}[aux]{\fp_div_divide_aux:} +%\begin{macro}[aux]{\fp_div_store:} +%\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_nopar:Npn \fp_div_aux:NNn #1#2#3 { + \group_begin: + \fp_read:N #2 + \fp_split:Nn b {#3} + \tex_ifnum:D + \etex_numexpr:D + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + \scan_stop: + = \c_zero + \tl_set_eq:NN \l_fp_tmp_tl \c_undefined_fp + \tex_else:D + \tex_ifnum:D + \etex_numexpr:D + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + \scan_stop: + = \c_zero + \tl_set_eq:NN \l_fp_tmp_tl \c_zero_fp + \tex_else:D + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_div_aux: + \tex_fi:D + \tex_fi:D + \exp_after:wN \group_end: \exp_after:wN + #1 \exp_after:wN #2 \exp_after:wN { \l_fp_tmp_tl } +} +% \end{macrocode} +% The main division algorithm has to avoid overflows for awkward +% cases (division of large numbers by small ones). That requires that +% the denominator has an integer part if the numerator does: an offset +% is only created if it is needed. The idea then is find how many +% times the denominator can be removed from the numerator. This +% is stored in the result, the denominator is divided by ten and +% the process is repeated with the remainder of the numerator. Cycling +% through this sequence eventually removes all of the digits of the +% denominator, if the numerator does not reach zero first. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_div_aux: { + \l_fp_div_offset_int \c_one + \tex_ifnum:D \l_fp_input_a_integer_int > \c_zero + \exp_after:wN \fp_div_offset_create: + \tex_fi:D + \l_fp_output_integer_int \c_zero + \l_fp_output_decimal_int \c_one_thousand_million + \cs_set_eq:NN \fp_div_store: \fp_div_store_integer: + \fp_div_loop: + \tl_set:Nx \l_fp_tmp_tl + { + \tex_ifnum:D + \etex_numexpr:D + \l_fp_input_a_sign_int * \l_fp_input_b_sign_int + \scan_stop: + < \c_zero + \tex_ifnum:D + \etex_numexpr:D + \l_fp_output_integer_int + \l_fp_output_decimal_int + \scan_stop: + = \c_one_thousand_million + + + \tex_else:D + - + \tex_fi:D + \tex_else:D + + + \tex_fi:D + \int_use:N \l_fp_output_integer_int + . + \exp_after:wN \use_none:n + \int_use:N \l_fp_output_decimal_int + } +} +% \end{macrocode} +% The offset is created such that it will automatically be accounted +% for in the rest of the process. Rather than doing any integer division +% a delimited function is used to transfer the digit from the +% integer to the decimal parts. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_div_offset_create: { + \tex_ifnum:D \l_fp_input_b_integer_int = \c_zero + \tex_advance:D \l_fp_input_b_decimal_int \c_one_thousand_million + \exp_after:wN \fp_div_offset_create_aux:w + \int_use:N \l_fp_input_b_decimal_int \q_stop + \exp_after:wN \fp_div_offset_create: + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_div_offset_create_aux:w + #1#2#3#4#5#6#7#8#9 \q_stop { + \l_fp_input_b_integer_int #2 \scan_stop: + \l_fp_input_b_decimal_int #3#4#5#6#7#8#9 0 \scan_stop: + \tex_multiply:D \l_fp_div_offset_int \c_ten +} +% \end{macrocode} +% The main division loop must start with both numerator and +% denominator above zero, so the test is at the tail of the loop. +% Once again, division by ten for the denominator is avoided, with +% a delimited function doing the job. The test at the end of the +% function means that the loop terminates as soon as one part of the +% input reaches zero: this saves dead loops if the division is +% exact. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_div_loop: { + \l_fp_div_count_int \c_zero + \fp_div_divide: + \tex_divide:D \l_fp_input_b_decimal_int \c_ten + \tex_advance:D \l_fp_input_b_integer_int \c_one_thousand_million + \exp_after:wN \fp_div_loop_aux_i:w + \int_use:N \l_fp_input_b_integer_int + \fp_div_store: + \tex_ifnum:D + \etex_numexpr:D + \l_fp_input_a_integer_int + \l_fp_input_a_decimal_int + > \c_zero + \tex_ifnum:D + \etex_numexpr:D + \l_fp_input_b_integer_int + \l_fp_input_b_decimal_int + > \c_zero + \exp_after:wN \exp_after:wN \exp_after:wN + \fp_div_loop: + \tex_fi:D + \tex_fi:D +} +% \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: { + \tex_ifnum:D \l_fp_input_a_integer_int > \l_fp_input_b_integer_int + \exp_after:wN \fp_div_divide_aux: + \tex_else:D + \tex_ifnum:D \l_fp_input_a_integer_int < \l_fp_input_b_integer_int + \tex_else:D + \tex_ifnum:D + \l_fp_input_a_decimal_int < \l_fp_input_b_decimal_int + \tex_else:D + \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: + \tex_fi:D + \tex_fi:D + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_div_loop_aux_i:w #1#2#3#4#5#6#7#8#9 { + \fp_div_loop_aux_ii:w #2#3#4#5#6#7#8#9 +} +\cs_new_protected_nopar:Npn \fp_div_loop_aux_ii:w #1#2#3#4#5#6#7#8#9 { + \l_fp_input_b_integer_int #1#2#3#4#5#6#7#8 \scan_stop: + \l_fp_input_b_decimal_int + \etex_numexpr:D + \l_fp_input_b_decimal_int + \c_one_hundred_million * #9 + \scan_stop: +} +\cs_new_protected_nopar:Npn \fp_div_divide_aux: { + \tex_advance:D \l_fp_div_count_int \c_one + \tex_advance:D \l_fp_input_a_integer_int -\l_fp_input_b_integer_int + \tex_advance:D \l_fp_input_a_decimal_int -\l_fp_input_b_decimal_int + \tex_ifnum:D \l_fp_input_a_decimal_int < \c_zero + \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 + \tex_fi:D + \fp_div_divide: +} +% \end{macrocode} +% The final stage of each loop is to store the result. This is done +% separately for the integer and decimal parts. The offset is used to +% get the digits in the correct place, and so also indicates when the +% switch from the integer to the decimal. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_div_store: { } +\cs_new_protected_nopar:Npn \fp_div_store_integer: { + \l_fp_output_integer_int + \etex_numexpr:D + \l_fp_output_integer_int + + \l_fp_div_count_int * \l_fp_div_offset_int + \scan_stop: + \tex_ifnum:D \l_fp_div_offset_int > \c_one + \tex_divide:D \l_fp_div_offset_int \c_ten + \tex_else:D + \cs_set_eq:NN \fp_div_store: \fp_div_store_decimal: + \l_fp_div_offset_int \c_one_hundred_million + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_div_store_decimal: { + \l_fp_output_decimal_int + \etex_numexpr:D + \l_fp_output_decimal_int + + \l_fp_div_count_int * \l_fp_div_offset_int + \scan_stop: + \tex_divide:D \l_fp_div_offset_int \c_ten +} +% \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} +% +%\subsection{Fixed-point conditionals} +% +%\begin{macro}[TF]{\fp_compare:nNn} +%\begin{macro}[TF]{\fp_compare:NNN} +%\begin{macro}[aux]{\fp_compare_aux:N} +%\begin{macro}[aux]{\fp_compare_=:} +%\begin{macro}[aux]{\fp_compare_<:} +%\begin{macro}[aux]{\fp_compare_>:} +%\begin{macro}[aux]{\fp_compare_absolute_a>b:} +%\begin{macro}[aux]{\fp_compare_absolute_a<b:} +% 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_split:Nn b {#3} + \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 + \fp_read:N #1 + \fp_compare_aux:N #2 +} +\cs_new_protected_nopar: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_=: } { + \tex_ifnum:D \l_fp_input_a_sign_int = \l_fp_input_b_sign_int + \tex_ifnum:D \l_fp_input_a_integer_int = \l_fp_input_b_integer_int + \tex_ifnum:D \l_fp_input_a_decimal_int = \l_fp_input_b_decimal_int + \group_end: + \prg_return_true: + \tex_else:D + \group_end: + \prg_return_false: + \tex_fi:D + \tex_else:D + \group_end: + \prg_return_false: + \tex_fi:D + \tex_else:D + \group_end: + \prg_return_false: + \tex_fi:D +} +% \end{macrocode} +% For comparitors life is a lot moe complex, as there are three cases for +% the integer part (equality as well as greater and less than). The +% code here is quite repetitive to keep speed up, and simply does +% exhaustive checks. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { fp_compare_>: } { + \tex_ifnum:D \l_fp_input_a_sign_int > \l_fp_input_b_sign_int + \group_end: + \prg_return_true: + \tex_else:D + \tex_ifnum:D \l_fp_input_a_sign_int < \l_fp_input_b_sign_int + \group_end: + \prg_return_false: + \tex_else:D + \tex_ifnum:D \l_fp_input_a_sign_int > \c_zero + \use:c { fp_compare_absolute_a > b: } + \tex_else:D + \use:c { fp_compare_absolute_a < b: } + \tex_fi:D + \tex_fi:D + \tex_fi:D +} +\cs_new_protected_nopar:cpn { fp_compare_<: } { + \tex_ifnum:D \l_fp_input_b_sign_int > \l_fp_input_a_sign_int + \group_end: + \prg_return_true: + \tex_else:D + \tex_ifnum:D \l_fp_input_b_sign_int < \l_fp_input_a_sign_int + \group_end: + \prg_return_false: + \tex_else:D + \tex_ifnum:D \l_fp_input_b_sign_int > \c_zero + \use:c { fp_compare_absolute_a < b: } + \tex_else:D + \use:c { fp_compare_absolute_a > b: } + \tex_fi:D + \tex_fi:D + \tex_fi:D +} +\cs_new_protected_nopar:cpn { fp_compare_absolute_a > b: } { + \tex_ifnum:D \l_fp_input_a_integer_int > \l_fp_input_b_integer_int + \group_end: + \prg_return_true: + \tex_else:D + \tex_ifnum:D \l_fp_input_a_integer_int < \l_fp_input_b_integer_int + \group_end: + \prg_return_false: + \tex_else:D + \tex_ifnum:D \l_fp_input_a_decimal_int > \l_fp_input_b_decimal_int + \group_end: + \prg_return_true: + \tex_else:D + \group_end: + \prg_return_false: + \tex_fi:D + \tex_fi:D + \tex_fi:D +} +\cs_new_protected_nopar:cpn { fp_compare_absolute_a < b: } { + \tex_ifnum:D \l_fp_input_b_integer_int > \l_fp_input_a_integer_int + \group_end: + \prg_return_true: + \tex_else:D + \tex_ifnum:D \l_fp_input_b_integer_int < \l_fp_input_a_integer_int + \group_end: + \prg_return_false: + \tex_else:D + \tex_ifnum:D \l_fp_input_b_decimal_int > \l_fp_input_a_decimal_int + \group_end: + \prg_return_true: + \tex_else:D + \group_end: + \prg_return_false: + \tex_fi:D + \tex_fi:D + \tex_fi:D +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\subsection{Formatting fixed point numbers} +% +% When transferring fixed points to higher level code it is desirable +% to allow flexible formatting. +% +%\begin{macro}{\l_fp_round_precision_int} +%\begin{macro}{\l_fp_remove_zeros_bool} +%\begin{macro}{\l_fp_round_mode_tl} +% \begin{macrocode} +\keys_define:nn { fp } { + precision .int_set:N = \l_fp_round_precision_int , + remove-trailing-zeros .bool_set:N = \l_fp_remove_zeros_bool , + round-mode .choice: , + round-mode + / half-even .tl_set:N = \l_fp_round_mode_tl , + round-mode + / half-from-zero .tl_set:N = \l_fp_round_mode_tl , + round-mode + / none .tl_set:N = \l_fp_round_mode_tl , + round-mode + / truncate .tl_set:N = \l_fp_round_mode_tl , +} +\keys_set:nn { fp } { + precision = 9 , + remove-trailing-zeros = true , + round-mode = none , +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\fp_to_tl:NN} +%\begin{macro}{\fp_to_tl:Nc} +%\begin{macro}{\fp_to_tl:cN} +%\begin{macro}{\fp_to_tl:cc} +%\begin{macro}{\fp_gto_tl:NN} +%\begin{macro}{\fp_gto_tl:Nc} +%\begin{macro}{\fp_gto_tl:cN} +%\begin{macro}{\fp_gto_tl:cc} +%\begin{macro}[aux]{\fp_to_tl_aux:NNN} +%\begin{macro}[aux]{\fp_remove_zeros:NNNNNNNNN} +%\begin{macro}[aux]{\fp_remove_zeros_aux:w} +%\begin{macro}[aux]{\fp_round_half-from-zero:} +%\begin{macro}[aux]{\fp_round_from_zero:} +%\begin{macro}[aux]{\fp_round_from_zero_aux:NNNNNNNNN} +%\begin{macro}[aux]{\fp_round_from_zero_decimal:N} +%\begin{macro}[aux]{\fp_round_from_zero_integer:} +%\begin{macro}[aux]{\fp_round_half-even:} +%\begin{macro}[aux]{\fp_round_even:} +%\begin{macro}[aux]{\fp_round_even_aux:NNNNNNNNN} +%\begin{macro}[aux]{\fp_round_even_decimal:N} +%\begin{macro}[aux]{\fp_round_even_integer:} +%\begin{macro}[aux]{\fp_round_none:} +%\begin{macro}[aux]{\fp_round_truncate:} +% The usual lead off with a series of wrapper functions. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_to_tl:NN { + \fp_to_tl_aux:NNN \tl_set:Nn +} +\cs_new_protected_nopar:Npn \fp_gto_tl:NN { + \fp_to_tl_aux:NNN \tl_gset:Nn +} +\cs_generate_variant:Nn \fp_to_tl:NN { Nc } +\cs_generate_variant:Nn \fp_to_tl:NN { c } +\cs_generate_variant:Nn \fp_to_tl:NN { cc } +\cs_generate_variant:Nn \fp_gto_tl:NN { Nc } +\cs_generate_variant:Nn \fp_gto_tl:NN { c } +\cs_generate_variant:Nn \fp_gto_tl:NN { cc } +% \end{macrocode} +% The main body of the conversion follows the pattern of reading the +% \texttt{fp} then processing it. Rounding takes place first, so +% that zero stripping is easier. This may involve loosing the decimal +% part entirely. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_to_tl_aux:NNN #1#2#3 { + \group_begin: + \fp_read:N #2 + \use:c { fp_round_ \l_fp_round_mode_tl :} + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \tl_set:Nx \l_fp_tmp_tl + { + \tex_ifnum:D \l_fp_input_a_sign_int < \c_zero + - + \tex_fi:D + \int_use:N \l_fp_input_a_integer_int + \intexpr_compare:nNnT { \l_fp_round_precision_int } > { \c_zero } + { + . + \bool_if:NTF \l_fp_remove_zeros_bool + { + \exp_after:wN \use_i:nn + \exp_after:wN \fp_remove_zeros:NNNNNNNNN + } + { \exp_after:wN \use_none:n } + \int_use:N \l_fp_input_a_decimal_int + } + } + \exp_after:wN \group_end: \exp_after:wN + #1 \exp_after:wN #3 \exp_after:wN { \l_fp_tmp_tl } +} +% \end{macrocode} +% For removing zeros, the code above ensures there will be exactly +% \( 9 \) tokens to deal with. The idea here is to go through them one +% at a time and see if the remained is equal to zero. The input can +% then be discarded if the precision in the output is correct. Speed +% is not quite so vital here so everything is coded in \LaTeX3 rather +% than primitives. This approach avoids needing to reverse the input. +% \begin{macrocode} +\cs_new_nopar:Npn \fp_remove_zeros:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { + \fp_remove_zeros_aux:w #1#2#3#4#5#6#7#8#9 \q_stop 1 +} +\cs_new_nopar:Npn \fp_remove_zeros_aux:w #1#2 \q_stop #3 { + #1 + \intexpr_compare:nNnTF { 0 #2 } = { \c_zero } + { + \intexpr_compare:nNnF { \l_fp_round_precision_int } < { #3 + 1 } + { + \intexpr_compare:nNnT {#3} < { 9 } + { \fp_remove_zeros_aux:w #2 \q_stop { #3 + 1 } } + } + } + { + \intexpr_compare:nNnT {#3} < { 9 } + { \fp_remove_zeros_aux:w #2 \q_stop { #3 + 1 } } + } +} +% \end{macrocode} +% Rounding away from zero is relatively easy, as it only depends on +% the digit immediately before the rounded position. The code here +% therefore does a fast reversal of the direct of the input, then +% checks the position before considering the size of the digit itself. +% The position here refers to the digit that will be rounded, which is +% therefore out by one from the digit being considered during the loop. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { fp_round_half-from-zero: } { + \tex_ifnum:D \l_fp_round_precision_int < \c_nine + \exp_after:wN \fp_round_from_zero: + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_round_from_zero: { + \bool_set_false:N \l_fp_round_carry_bool + \l_fp_round_position_int \c_eight + \tl_clear:N \l_fp_round_decimal_tl + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_round_from_zero_aux:NNNNNNNNN + \int_use:N \l_fp_input_a_decimal_int +} +\cs_new_protected_nopar:Npn \fp_round_from_zero_aux:NNNNNNNNN + #1#2#3#4#5#6#7#8#9 { + \fp_round_from_zero_decimal:N #9#8#7#6#5#4#3#2#1 + \fp_round_from_zero_integer: +} +\cs_new_protected_nopar:Npn \fp_round_from_zero_decimal:N #1 { + \tex_ifnum:D \l_fp_round_position_int < \l_fp_round_precision_int + \bool_if:NTF \l_fp_round_carry_bool + { \l_fp_tmp_int \etex_numexpr:D #1 + \c_one \scan_stop: } + { \l_fp_tmp_int \etex_numexpr:D #1 \scan_stop: } + \tex_ifnum:D \l_fp_tmp_int = \c_ten + \l_fp_tmp_int \c_zero + \tex_else:D + \bool_set_false:N \l_fp_round_carry_bool + \tex_fi:D + \tl_set:Nx \l_fp_round_decimal_tl + { \int_use:N \l_fp_tmp_int \l_fp_round_decimal_tl } + \tex_else:D + \tl_set:Nx \l_fp_round_decimal_tl { 0 \l_fp_round_decimal_tl } + \tex_ifnum:D \l_fp_round_position_int = \l_fp_round_precision_int + \tex_ifnum:D #1 > \c_four + \bool_set_true:N \l_fp_round_carry_bool + \tex_fi:D + \tex_fi:D + \tex_fi:D + \tex_advance:D \l_fp_round_position_int \c_minus_one + \tex_ifnum:D \l_fp_round_position_int > \c_minus_one + \exp_after:wN \fp_round_from_zero_decimal:N + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_round_from_zero_integer: { + \bool_if:NT \l_fp_round_carry_bool + { \tex_advance:D \l_fp_input_a_integer_int \c_one } + \l_fp_input_a_decimal_int \l_fp_round_decimal_tl \scan_stop: +} +% \end{macrocode} +% The general outline is similar when rounding where ties go to the +% nearest even number. However, life is more complicated as there is a +% need to track the discarded digits, and to see whether the digit to +% round is odd or even. This is done by tracking the discarded digits. +% When reaching the digit to check for rounding, the discards are used +% to indicate if there is an exact half to take into account. When the +% rounding takes place without an exact half, things are the same as +% for the \enquote{away from zero} approach. When rounding an exact +% half, there is an odd/even test before applying any modification. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { fp_round_half-even: } { + \tex_ifnum:D \l_fp_round_precision_int < \c_nine + \exp_after:wN \fp_round_even: + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_round_even: { + \bool_set_false:N \l_fp_round_carry_bool + \l_fp_round_position_int \c_eight + \tl_clear:N \l_fp_round_decimal_tl + \int_zero:N \l_fp_round_discard_int + \tex_advance:D \l_fp_input_a_decimal_int \c_one_thousand_million + \exp_after:wN \use_i:nn \exp_after:wN + \fp_round_even_aux:NNNNNNNNN + \int_use:N \l_fp_input_a_decimal_int +} +\cs_new_protected_nopar:Npn \fp_round_even_aux:NNNNNNNNN + #1#2#3#4#5#6#7#8#9 { + \fp_round_even_decimal:N #9#8#7#6#5#4#3#2#1 + \fp_round_even_integer: +} +\cs_new_protected_nopar:Npn \fp_round_even_decimal:N #1 { + \tex_ifnum:D \l_fp_round_position_int < \l_fp_round_precision_int + \bool_if:NTF \l_fp_round_carry_bool + { + \tex_ifnum:D \l_fp_round_discard_int = \c_zero + \l_fp_round_discard_int \c_one + \tex_ifodd:D #1 \scan_stop: + \l_fp_tmp_int \etex_numexpr:D #1 + \c_one \scan_stop: + \tex_else:D + \l_fp_tmp_int \etex_numexpr:D #1 \scan_stop: + \tex_fi:D + \tex_else:D + \l_fp_tmp_int \etex_numexpr:D #1 + \c_one \scan_stop: + \tex_fi:D + } + { \l_fp_tmp_int \etex_numexpr:D #1 \scan_stop: } + \tex_ifnum:D \l_fp_tmp_int = \c_ten + \l_fp_tmp_int \c_zero + \tex_else:D + \bool_set_false:N \l_fp_round_carry_bool + \tex_fi:D + \tl_set:Nx \l_fp_round_decimal_tl + { \int_use:N \l_fp_tmp_int \l_fp_round_decimal_tl } + \tex_else:D + \tl_set:Nx \l_fp_round_decimal_tl { 0 \l_fp_round_decimal_tl } + \tex_ifnum:D \l_fp_round_position_int = \l_fp_round_precision_int + \tex_ifnum:D #1 > \c_four + \bool_set_true:N \l_fp_round_carry_bool + \tex_ifnum:D #1 = \c_five + \tex_else:D + \l_fp_round_discard_int \c_one + \tex_fi:D + \tex_fi:D + \tex_else:D + \tex_advance:D \l_fp_round_discard_int #1 \scan_stop: + \tex_fi:D + \tex_fi:D + \tex_advance:D \l_fp_round_position_int \c_minus_one + \tex_ifnum:D \l_fp_round_position_int > \c_minus_one + \exp_after:wN \fp_round_even_decimal:N + \tex_fi:D +} +\cs_new_protected_nopar:Npn \fp_round_even_integer: { + \bool_if:NT \l_fp_round_carry_bool + { + \tex_ifnum:D \l_fp_round_discard_int = \c_zero + \tex_ifodd:D \l_fp_input_a_integer_int + \tex_advance:D \l_fp_input_a_integer_int \c_one + \tex_fi:D + \tex_else:D + \tex_advance:D \l_fp_input_a_integer_int \c_one + \tex_fi:D + } + \l_fp_input_a_decimal_int \l_fp_round_decimal_tl \scan_stop: +} +% \end{macrocode} +% The only task that is needed when not rounding is to ensure that +% the zero-stripping function will remove things reliably. This is +% done by setting the precision to one digit: no rounding will always +% leave at least one decimal digit, even if it is zero. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_round_none: { + \l_fp_round_precision_int \c_one +} +% \end{macrocode} +% Truncating input is done by using the \cs{tex_divide:D} primitive +% as this turns out to be the most convenient method to do this. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_round_truncate: { + \intexpr_compare:nNnF { \l_fp_round_precision_int } > { 8 } + { + \intexpr_compare:nNnTF { \l_fp_round_precision_int } < { 1 } + { \l_fp_input_a_decimal_int \c_zero \scan_stop: } + { + \int_set:Nn \l_fp_tmp_int + { + \prg_replicate:nn { 9 - \l_fp_round_precision_int } + { 10 * } + 1 + } + \tex_divide:D \l_fp_input_a_decimal_int \l_fp_tmp_int + \tex_multiply:D \l_fp_input_a_decimal_int \l_fp_tmp_int + } + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\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{Messages} +% +%\begin{macro}{\fp_msg_overflow:} +% To avoid expansion issues above, the messages are all set up as +% functions. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \fp_msg_overflow: { + \msg_kernel_error:nn { fpu } { overflow } +} +% \end{macrocode} +%\end{macro} +% +% \begin{macrocode} +\msg_kernel_new:nnnn { fpu } { overflow } + { Arithmetic~overflow. } + { + The~calculation~requested~exceeds~the~capacity \\ + of~the~fixed-point~unit. + } +% \end{macrocode} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +%\end{implementation} +% +%\PrintChanges +% +%\PrintIndex
\ No newline at end of file diff --git a/Master/texmf-dist/source/latex/expl3/l3intexpr.dtx b/Master/texmf-dist/source/latex/expl3/l3intexpr.dtx index 4c43e63e6db..71801f8780d 100644 --- a/Master/texmf-dist/source/latex/expl3/l3intexpr.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3intexpr.dtx @@ -36,7 +36,7 @@ \RequirePackage{l3names} %</driver|package> %\fi -\GetIdInfo$Id: l3intexpr.dtx 1086 2009-03-20 19:29:35Z morten $ +\GetIdInfo$Id: l3intexpr.dtx 1957 2010-06-15 06:33:43Z mittelba $ {L3 Integer Expressions} %\iffalse %<*driver> @@ -463,11 +463,32 @@ % \begin{macro}[TF]{\intexpr_compare:nNn} % More efficient but less natural in typing. % \begin{macrocode} -\prg_set_conditional:Npnn \intexpr_compare:nNn #1#2#3{p,TF,T,F}{ +\prg_set_conditional:Npnn \intexpr_compare:nNn #1#2#3{p}{ \if_intexpr_compare:w \intexpr_eval:w #1 #2 \intexpr_eval:w #3 \intexpr_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } +\cs_set_nopar:Npn \intexpr_compare:nNnT #1#2#3 { + \tex_ifnum:D \etex_numexpr:D #1 #2 \etex_numexpr:D #3 \scan_stop: + \tex_expandafter:D \use:n + \tex_else:D + \tex_expandafter:D \use_none:n + \tex_fi:D +} +\cs_set_nopar:Npn \intexpr_compare:nNnF #1#2#3 { + \tex_ifnum:D \etex_numexpr:D #1 #2 \etex_numexpr:D #3 \scan_stop: + \tex_expandafter:D \use_none:n + \tex_else:D + \tex_expandafter:D \use:n + \tex_fi:D +} +\cs_set_nopar:Npn \intexpr_compare:nNnTF #1#2#3 { + \tex_ifnum:D \etex_numexpr:D #1 #2 \etex_numexpr:D #3 \scan_stop: + \tex_expandafter:D \use_i:nn + \tex_else:D + \tex_expandafter:D \use_ii:nn + \tex_fi:D +} % \end{macrocode} % \end{macro} % \end{macro} diff --git a/Master/texmf-dist/source/latex/expl3/l3names.dtx b/Master/texmf-dist/source/latex/expl3/l3names.dtx index 651be378791..99b224d62c5 100644 --- a/Master/texmf-dist/source/latex/expl3/l3names.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3names.dtx @@ -128,7 +128,7 @@ \RequirePackage{l3names} %</driver> %\fi -\GetIdInfo$Id: l3names.dtx 1853 2010-03-21 09:11:08Z joseph $ +\GetIdInfo$Id: l3names.dtx 1981 2010-07-11 07:28:30Z will $ {L3 Experimental Naming Scheme for TeX Primitives} % % @@ -324,6 +324,10 @@ \endlinechar =\the \endlinechar \relax \catcode 95=\the \catcode 95 \relax \catcode 58=\the \catcode 58 \relax + \catcode 124=\the \catcode 124 \relax + \catcode 38=\the \catcode 38 \relax + \catcode 94=\the \catcode 94 \relax + \catcode 34=\the \catcode 34 \relax \noexpand\fi } \catcode126=10\relax % tilde is a space char. @@ -332,6 +336,10 @@ \endlinechar=32\relax % endline is space \catcode95=11\relax % underscore letter \catcode58=11\relax % colon letter +\catcode124=12\relax % vert bar, other +\catcode38=4\relax % ampersand, alignment token +\catcode34=12\relax % doublequote, other +\catcode94=7\relax % caret, math superscript % \end{macrocode} % % \subsection{Setting up primitive names} @@ -981,6 +989,10 @@ \tex_endlinechar:D =\tex_the:D \tex_endlinechar:D \tex_relax:D \tex_catcode:D 95=\tex_the:D \tex_catcode:D 95 \tex_relax:D \tex_catcode:D 58=\tex_the:D \tex_catcode:D 58 \tex_relax:D + \tex_catcode:D 124=\tex_the:D \tex_catcode:D 124 \tex_relax:D + \tex_catcode:D 38=\tex_the:D \tex_catcode:D 38 \tex_relax:D + \tex_catcode:D 94=\tex_the:D \tex_catcode:D 94 \tex_relax:D + \tex_catcode:D 34=\tex_the:D \tex_catcode:D 34 \tex_relax:D \tex_noexpand:D \tex_fi:D } \tex_def:D \ExplSyntaxStatus { 1 } @@ -990,6 +1002,10 @@ \tex_endlinechar:D =32 \tex_relax:D % endline is space \tex_catcode:D 95=11 \tex_relax:D % underscore letter \tex_catcode:D 58=11 \tex_relax:D % colon letter + \tex_catcode:D 124=11 \tex_relax:D % vertical bar, other + \tex_catcode:D 38=4 \tex_relax:D % ampersand, alignment token + \tex_catcode:D 94=7 \tex_relax:D % caret, math superscript + \tex_catcode:D 34=12 \tex_relax:D % doublequote, other \tex_fi:D } % \end{macrocode} @@ -1138,7 +1154,7 @@ % as the packages in this distribution do like this: % \begin{verbatim} % \RequirePackage{l3names} -% \GetIdInfo$Id: l3names.dtx 1853 2010-03-21 09:11:08Z joseph $ +% \GetIdInfo$Id: l3names.dtx 1981 2010-07-11 07:28:30Z will $ % {L3 Experimental Box module} % \ProvidesExplPackage % {\filename}{\filedate}{\fileversion}{\filedescription} |