diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3fp-symbolic.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3fp-symbolic.dtx | 673 |
1 files changed, 673 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-symbolic.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-symbolic.dtx new file mode 100644 index 00000000000..277ecfabf55 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-symbolic.dtx @@ -0,0 +1,673 @@ +% \iffalse +% +%% File l3fp-symbolic.dtx (C) Copyright 2012-2015,2017,2018,2020,2021,2023 The LaTeX 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 "l3kernel bundle" (The Work in LPPL) +% and all files in that bundle must be distributed together. +% +% ----------------------------------------------------------------------- +% +% The development version of the bundle can be found at +% +% https://github.com/latex3/latex3 +% +% for those people who are interested. +% +%<*driver> +\documentclass[full]{l3doc} +\usepackage{amsmath} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3fp-symbolic} package\\ Symbolic expressions^^A +% } +% +% \author{^^A +% The \LaTeX{} Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2023-10-23} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-symbolic} implementation} +% +% \begin{macrocode} +%<*package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% \subsection{Misc} +% +% \begin{variable}{\l_@@_symbolic_fp} +% Scratch floating point. +% \begin{macrocode} +\fp_new:N \l_@@_symbolic_fp +% \end{macrocode} +% \end{variable} +% +% \subsection{Building blocks for expressions} +% +% Every symbolic expression has the form \cs{s_@@_symbolic} +% \cs{@@_symbolic_chk:w} \meta{operation} |,| \Arg{operands} \meta{junk} +% |;| where the \meta{operation} is a list of \texttt{N}-type tokens, +% the \meta{operands} is an array of floating point objects, and the +% \meta{junk} is to be discarded. If the outermost operator (last to be +% evaluated) is unary, the expression has the form +% \begin{quote} +% \cs{s_@@_symbolic} \cs{@@_symbolic_chk:w} \\ +% \cs{@@_types_unary:NNw} |\__fp_|\meta{op}|_o:w| \meta{token} |,| \\ +% |{| \meta{operand} |}| \meta{junk} |;| +% \end{quote} +% where the \meta{op} is a unary operation (|set_sign|, |cos|, +% \ldots{}), and the \meta{token} and \meta{operand} are used as +% arguments for \cs{@@_\meta{op}_o:w} (or the type-specific analog of +% this function). If the outermost operator is binary, the expression +% has the form +% \begin{quote} +% \cs{s_@@_symbolic} \cs{@@_symbolic_chk:w} \\ +% \cs{@@_types_binary:Nww} |\__fp_|\meta{op}|_o:ww| |,| \\ +% |{| \meta{operand_1} \meta{operand_2} |}| \meta{junk} |;| +% \end{quote} +% where the \meta{op} is an operation (|+|, |&|, \ldots{}), and +% |\__fp_|\meta{op}|_o:ww| receives the \meta{operands} as arguments. +% If the expression consists of a single variable, it is stored as +% \begin{quote} +% \cs{s_@@_symbolic} \cs{@@_symbolic_chk:w} \\ +% \cs{@@_variable_o:w} \meta{identifier} |,| \\ +% |{| |}| \meta{junk} |;| +% \end{quote} +% +% Symbolic expressions are stored in a prefix form. When encountering a +% symbolic expression in a floating point computation, we attempt to +% evaluate the operands as much as possible, and if that yields floating +% point numbers rather than expressions, we apply the operator which +% follows (if the function is known). +% +% For instance, the expression |a + b * sin(c)| is stored as +% \begin{verbatim} +% \s__fp_symbolic \__fp_symbolic_chk:w +% \__fp_types_binary:Nww \__fp_+_o:ww , +% { +% \s__fp_symbolic \__fp_symbolic_chk:w +% \__fp_variable_o:w a , { } ; +% \s__fp_symbolic \__fp_symbolic_chk:w +% \__fp_types_binary:Nww \__fp_*_o:ww , +% { +% \s__fp_symbolic \__fp_symbolic_chk:w +% \__fp_variable_o:w b , { } ; +% \s__fp_symbolic \__fp_symbolic_chk:w +% \__fp_types_unary:NNw \__fp_sin_o:w \use_i:nn , +% { +% \s__fp_symbolic \__fp_symbolic_chk:w +% \__fp_variable_o:w c , { } ; +% } ; +% } ; +% } ; +% \end{verbatim} +% +% \begin{variable}{\s_@@_symbolic} +% Scan mark indicating the start of a symbolic expression. +% \begin{macrocode} +\scan_new:N \s_@@_symbolic +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_symbolic_chk:w} +% Analog of \cs{@@_chk:w} for symbolic expressions. +% \begin{macrocode} +\cs_new_protected:Npn \@@_symbolic_chk:w #1,#2#3; + { + \msg_error:nne { fp } { misused-fp } + { + \@@_to_tl_dispatch:w + \s_@@_symbolic \@@_symbolic_chk:w #1,{#2}; + } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Expanding after a symbolic expression} +% +% \begin{macro}[EXP] +% {\@@_if_has_symbolic:nTF, \@@_if_has_symbolic_aux:w} +% Tests if |#1| contains \cs{s_@@_symbolic} at top-level. This test +% should be precise enough to determine if a given an array contains a +% symbolic expression or only consists in floating points. Used in +% \cs{@@_exp_after_symbolic_f:nw}. +% \begin{macrocode} +\cs_new:Npn \@@_if_has_symbolic:nTF #1 + { + \@@_if_has_symbolic_aux:w + #1 \s_@@_mark \use_i:nn + \s_@@_symbolic \s_@@_mark \use_ii:nn + \s_@@_stop + } +\cs_new:Npn \@@_if_has_symbolic_aux:w + #1 \s_@@_symbolic #2 \s_@@_mark #3#4 \s_@@_stop { #3 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_exp_after_symbolic_f:nw} +% \begin{macro}[EXP] +% {\@@_exp_after_symbolic_aux:w, \@@_exp_after_symbolic_loop:N} +% This function does two things: trigger an \texttt{f}-expansion of +% the argument~|#1| after the following symbolic expression, and +% evaluate all pieces of the expression which can be evaluated. +% \begin{macrocode} +\cs_new:Npn \@@_exp_after_symbolic_f:nw + #1 \s_@@_symbolic \@@_symbolic_chk:w #2, #3#4; + { + \exp_after:wN \@@_exp_after_symbolic_aux:w + \exp:w + \@@_exp_after_symbolic_loop:N #2 + { , \exp:w \use_none:nn } + \exp_after:wN \exp_end: \exp_after:wN + { + \exp:w \exp_end_continue_f:w + \@@_exp_after_array_f:w #3 \s_@@_expr_stop + \exp_after:wN + } + \exp_after:wN ; + \exp:w \exp_end_continue_f:w #1 + } +\cs_new:Npn \@@_exp_after_symbolic_aux:w #1, #2; + { + \@@_if_has_symbolic:nTF {#2} + { \s_@@_symbolic \@@_symbolic_chk:w #1, {#2} ; } + { #1 #2 @ \prg_do_nothing: } + } +\cs_new:Npn \@@_exp_after_symbolic_loop:N #1 + { + \exp_after:wN \exp_end: + \exp_after:wN #1 + \exp:w + \@@_exp_after_symbolic_loop:N + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Applying infix operators to expressions} +% +% \begin{macro}[EXP]{\@@_symbolic_binary_o:Nww} +% Used when applying infix operators to expressions. +% \begin{macrocode} +\cs_new:Npn \@@_symbolic_binary_o:Nww #1 #2; #3; + { + \@@_exp_after_symbolic_f:nw { \exp_after:wN \exp_stop_f: } + \s_@@_symbolic \@@_symbolic_chk:w + \@@_types_binary:Nww #1 , { #2; #3; } ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{@makeother}{^} %^^A Hack! +% \begin{@makeother}{|} %^^A Hack! +% \begin{@makeother}{&} %^^A Hack! +% \begin{macro}[EXP] +% { +% \@@_symbolic_+_symbolic_o:ww, +% \@@_symbolic_+_o:ww, +% \@@_+_symbolic_o:ww, +% \@@_symbolic_-_symbolic_o:ww, +% \@@_symbolic_-_o:ww, +% \@@_-_symbolic_o:ww, +% \@@_symbolic_*_symbolic_o:ww, +% \@@_symbolic_*_o:ww, +% \@@_*_symbolic_o:ww, +% \@@_symbolic_/_symbolic_o:ww, +% \@@_symbolic_/_o:ww, +% \@@_/_symbolic_o:ww, +% \@@_symbolic_^_symbolic_o:ww, +% \@@_symbolic_^_o:ww, +% \@@_^_symbolic_o:ww, +% \@@_symbolic_|_symbolic_o:ww, +% \@@_symbolic_|_o:ww, +% \@@_|_symbolic_o:ww, +% \@@_symbolic_&_symbolic_o:ww, +% \@@_symbolic_&_o:ww, +% \@@_&_symbolic_o:ww, +% } +% \begin{macrocode} +\cs_set:Npn \@@_tmp:w #1#2 + { + \cs_new_nopar:cpn + { @@_symbolic_#2_symbolic_o:ww } + { \@@_symbolic_binary_o:Nww #1 } + \cs_new_eq:cc + { @@_symbolic_#2 _o:ww } + { @@_symbolic_#2_symbolic_o:ww } + \cs_new_eq:cc + { @@ _#2_symbolic_o:ww } + { @@_symbolic_#2_symbolic_o:ww } + } +\tl_map_inline:nn { + - * / ^ & | } + { \exp_args:Nc \@@_tmp:w { @@_#1_o:ww } {#1} } +% \end{macrocode} +% \end{macro} +% \end{@makeother} +% \end{@makeother} +% \end{@makeother} +% +% \subsection{Applying prefix functions to expressions} +% +% \begin{macro}[aux, EXP]{\@@_symbolic_unary_o:NNw} +% Used when applying infix operators to expressions. +% \begin{macrocode} +\cs_new:Npn \@@_symbolic_unary_o:NNw #1#2#3; @ + { + \@@_exp_after_symbolic_f:nw { \exp_after:wN \exp_stop_f: } + \s_@@_symbolic \@@_symbolic_chk:w + \@@_types_unary:NNw #1#2 , { #3; } ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP] +% { +% \@@_symbolic_acos_o:w , +% \@@_symbolic_acsc_o:w , +% \@@_symbolic_asec_o:w , +% \@@_symbolic_asin_o:w , +% \@@_symbolic_cos_o:w , +% \@@_symbolic_cot_o:w , +% \@@_symbolic_csc_o:w , +% \@@_symbolic_exp_o:w , +% \@@_symbolic_ln_o:w , +% \@@_symbolic_not_o:w , +% \@@_symbolic_sec_o:w , +% \@@_symbolic_set_sign_o:w , +% \@@_symbolic_sin_o:w , +% \@@_symbolic_tan_o:w , +% } +% \begin{macrocode} +\tl_map_inline:nn + { + {acos} {acsc} {asec} {asin} {cos} {cot} {csc} {exp} {ln} + {not} {sec} {set_sign} {sin} {sqrt} {tan} + } + { + \cs_new_nopar:cpe { @@_symbolic_#1_o:w } + { + \exp_not:N \@@_symbolic_unary_o:NNw + \exp_not:c { @@_#1_o:w } + } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Conversions} +% +% \begin{macro}[EXP] +% { +% \@@_symbolic_to_decimal:w, +% \@@_symbolic_to_int:w, +% \@@_symbolic_to_scientific:w +% } +% \begin{macro}[EXP]{\@@_symbolic_convert:wnnN} +% Symbolic expressions cannot be converted to decimal, integer, or +% scientific notation unless they can be reduced to +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1#2#3 + { + \cs_new_nopar:cpn { @@_symbolic_to_#1:w } + { + \exp_after:wN \@@_symbolic_convert:wnnN + \exp:w \exp_end_continue_f:w + \@@_exp_after_symbolic_f:nw { { #2 } { fp_to_#1 } #3 } + } + } +\@@_tmp:w { decimal } { 0 } \@@_to_decimal_dispatch:w +\@@_tmp:w { int } { 0 } \@@_to_int_dispatch:w +\@@_tmp:w { scientific } { nan } \@@_to_scientific_dispatch:w +\cs_new:Npn \@@_symbolic_convert:wnnN #1#2; #3#4#5 + { + \str_if_eq:nnTF {#1} { \s_@@_symbolic } + { \@@_invalid_operation:nnw {#3} {#4} #1#2; } + { #5 #1#2; } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP] +% {\@@_symbolic_cs_arg_to_fn:NN, \@@_symbolic_op_arg_to_fn:nN} +% \begin{macrocode} +\cs_new:Npn \@@_symbolic_cs_arg_to_fn:NN #1 + { + \exp_args:Nf \@@_symbolic_op_arg_to_fn:nN + { \@@_types_cs_to_op:N #1 } + } +\cs_new:Npn \@@_symbolic_op_arg_to_fn:nN #1#2 + { + \str_case:nnF { #1 #2 } + { + { not ? } { ! } + { set_sign 0 } { abs } + { set_sign 2 } { - } + } + { + \token_if_eq_meaning:NNTF #2 \use_ii:nn + { #1 d } {#1} + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_symbolic_to_tl:w} +% \begin{macro}[rEXP] +% { +% \@@_symbolic_unary_to_tl:NNw, +% \@@_symbolic_binary_to_tl:Nww +% } +% Converting a symbolic expression to a token list is possible. +% \begin{macrocode} +\cs_new:Npn \@@_symbolic_to_tl:w + \s_@@_symbolic \@@_symbolic_chk:w #1#2, #3#4; + { + \str_case:nnTF {#1} + { + { \@@_types_unary:NNw } { \@@_symbolic_unary_to_tl:NNw } + { \@@_types_binary:Nww } { \@@_symbolic_binary_to_tl:Nww } + { \@@_function_o:w } { \@@_symbolic_function_to_tl:Nw } + } + { #2, #3 @ } + { \tl_to_str:n {#2} } + } +\cs_new:Npn \@@_symbolic_unary_to_tl:NNw #1#2 , #3 @ + { + \use:e + { + \@@_symbolic_cs_arg_to_fn:NN #1#2 + ( \@@_to_tl_dispatch:w #3 ) + } + } +\cs_new:Npn \@@_symbolic_binary_to_tl:Nww #1, #2; #3; @ + { + \use:e + { + ( \@@_to_tl_dispatch:w #2; ) + \@@_types_cs_to_op:N #1 + ( \@@_to_tl_dispatch:w #3; ) + } + } +\cs_new:Npn \@@_symbolic_function_to_tl:Nw #1, #2@ + { + \use:e + { + \@@_types_cs_to_op:N #1 + ( \@@_array_to_clist:n {#2} ) + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Identifiers} +% +% Functions defined here are not necessarily tied to symbolic +% expressions. +% +% \begin{macro}[TF]{\@@_id_if_invalid:n} +% \begin{macro}[EXP]{\@@_id_if_invalid_aux:N} +% If |#1| contains a space, it is not a valid identifier. Otherwise, +% loop through letters in |#1|: if it is not a letter, break the loop +% and return \texttt{true}. If the end of the loop is reached +% without finding any non-letter, return \texttt{false}. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn + \@@_id_if_invalid:n #1 { T , F , TF } + { + \tl_if_empty:nTF {#1} + { \prg_return_true: } + { + \tl_if_in:onTF { \tl_to_str:n {#1} } { ~ } + { \prg_return_true: } + { + \exp_after:wN \@@_id_if_invalid_aux:N \tl_to_str:n {#1} + { ? \prg_break:n \prg_return_false: } + \prg_break_point: + } + } + } +\cs_new:Npn \@@_id_if_invalid_aux:N #1 + { + \use_none:n #1 + \int_compare:nF { `a <= `#1 <= `z } + { + \int_compare:nF { `A <= `#1 <= `Z } + { \prg_break:n \prg_return_true: } + } + \@@_id_if_invalid_aux:N + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Declaring variables and assigning values} +% +% \begin{macro}[EXP]{\@@_variable_o:w} +% We do not use \cs{exp_last_unbraced:Nv} to extract the value of +% |\l__fp_variable_#1_fp| because in \cs{fp_set_variable:nn} we define +% this \texttt{fp} variable to be something which \texttt{f}-expands +% to an actual floating point, rather than a genuine floating point. +% \begin{macrocode} +\cs_new:Npn \@@_variable_o:w #1 @ #2 + { + \fp_if_exist:cTF { l_@@_variable_#1_fp } + { + \exp_last_unbraced:Nf \@@_exp_after_array_f:w + { \use:c { l_@@_variable_#1_fp } } \s_@@_expr_stop + \exp_after:wN \exp_stop_f: #2 + } + { + \token_if_eq_meaning:NNTF #2 \prg_do_nothing: + { + \s_@@_symbolic \@@_symbolic_chk:w + \@@_variable_o:w #1 , { } ; + } + { + \exp_after:wN \s_@@_symbolic + \exp_after:wN \@@_symbolic_chk:w + \exp_after:wN \@@_variable_o:w + \exp:w + \@@_exp_after_symbolic_loop:N #1 + { , \exp:w \use_none:nn } + \exp_after:wN \exp_end: + \exp_after:wN { \exp_after:wN } \exp_after:wN ; + #2 + } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% {\@@_variable_set_parsing:Nn, \@@_variable_set_parsing_aux:NNn} +% \begin{macrocode} +\cs_new:Npn \@@_variable_set_parsing:Nn #1#2 + { + \cs_set_nopar:Npn \@@_tmp:w + { + \@@_exp_after_symbolic_f:nw { \@@_parse_infix:NN } + \s_@@_symbolic \@@_symbolic_chk:w + \@@_variable_o:w #2 , { } ; + } + \exp_args:NNc \@@_variable_set_parsing_aux:NNn #1 + { @@_parse_word_#2:N } {#2} + } +\cs_new:Npn \@@_variable_set_parsing_aux:NNn #1#2#3 + { + \cs_if_eq:NNF #2 \@@_tmp:w + { + \cs_if_exist:NTF #2 + { + \msg_warning:nnnn + { fp } { id-used-elsewhere } {#3} { variable } + #1 #2 \@@_tmp:w + } + { + \cs_new_eq:NN #2 \scan_stop: % to declare the function + #1 #2 \@@_tmp:w + } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\fp_clear_variable:n} +% \begin{macro}{\@@_clear_variable:n} +% \begin{macrocode} +\cs_new_protected:Npn \fp_clear_variable:n #1 + { + \@@_id_if_invalid:nTF {#1} + { \msg_error:nnn { fp } { id-invalid } {#1} } + { \exp_args:No \@@_clear_variable:n { \tl_to_str:n {#1} } } + } +\cs_new_protected:Npn \@@_clear_variable:n #1 + { + \cs_undefine:c { l_@@_variable_#1_fp } + \@@_variable_set_parsing:Nn \cs_set_eq:NN {#1} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_new_variable:n} +% \begin{macro}{\@@_new_variable:n} +% Check that |#1| is a valid identifier. If the identifier is already +% in use, complain. Then set |\__fp_parse_word_#1:N| to use +% |\__fp_variable_o:w|. +% \begin{macrocode} +\cs_new_protected:Npn \fp_new_variable:n #1 + { + \@@_id_if_invalid:nTF {#1} + { \msg_error:nnn { fp } { id-invalid } {#1} } + { \exp_args:No \@@_new_variable:n { \tl_to_str:n {#1} } } + } +\cs_new_protected:Npn \@@_new_variable:n #1 + { + \cs_if_exist:cT { @@_parse_word_#1:N } + { + \msg_error:nnn + { fp } { id-already-defined } {#1} + \cs_undefine:c { @@_parse_word_#1:N } + \cs_undefine:c { l_@@_variable_#1_fp } + } + \@@_variable_set_parsing:Nn \cs_gset_eq:NN {#1} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\fp_set_variable:nn} +% \begin{macro}{\@@_set_variable:nn} +% Refuse invalid identifiers. If the variable does not exist yet, +% define it just as in \cs{fp_new_variable:n} (but without unnecessary +% checks). Then evaluate~|#2|. If the result contains the +% identifier~|#1|, we would later get a loop in cases such as +% \begin{quote} +% \cs{fp_set_variable:nn} |{A}| |{A}|\\ +% \cs{fp_show:n} |{A}| +% \end{quote} +% To detect this, define |\l__fp_variable_#1_fp| to raise an +% internal flag and evaluate to \texttt{nan}. Then re-evaluate +% \cs{l_@@_symbolic_fp}, and store the result in~|#1|. If the flag is +% raised, |#1|~was present in \cs{l_@@_symbolic_fp}. In all cases, +% the |#1|-free result ends up in |\l__fp_variable_#1_fp|. +% \begin{macrocode} +\flag_new:n { @@_symbolic } +\cs_new_protected:Npn \fp_set_variable:nn #1 + { + \@@_id_if_invalid:nTF {#1} + { \msg_error:nnn { fp } { id-invalid } {#1} } + { \exp_args:No \@@_set_variable:nn { \tl_to_str:n {#1} } } + } +\cs_new_protected:Npn \@@_set_variable:nn #1#2 + { + \@@_variable_set_parsing:Nn \cs_set_eq:NN {#1} + \fp_set:Nn \l_@@_symbolic_fp {#2} + \cs_set_nopar:cpn { l_@@_variable_#1_fp } + { \flag_ensure_raised:n { @@_symbolic } \c_nan_fp } + \flag_clear:n { @@_symbolic } + \fp_set:cn { l_@@_variable_#1_fp } { \l_@@_symbolic_fp } + \flag_if_raised:nT { @@_symbolic } + { + \msg_error:nneee { fp } { id-loop } + { \tl_to_str:n {#1} } + { \tl_to_str:n {#2} } + { \fp_to_tl:N \l_@@_symbolic_fp } + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Messages} +% +% \begin{macrocode} +\msg_new:nnnn { fp } { id-invalid } + { Floating~point~identifier~'#1'~invalid. } + { + LaTeX~has~been~asked~to~create~a~new~floating~point~identifier~'#1'~ + but~this~may~only~contain~ASCII~letters. + } +\msg_new:nnnn { fp } { id-already-defined } + { Floating~point~identifier~'#1'~already~defined. } + { + LaTeX~has~been~asked~to~create~a~new~floating~point~identifier~'#1'~ + but~this~name~has~already~been~used~elsewhere. + } +\msg_new:nnnn { fp } { id-used-elsewhere } + { Floating~point~identifier~'#1'~already~used~for~something~else. } + { + LaTeX~has~been~asked~to~create~a~new~floating~point~identifier~'#1'~ + but~this~name~is~used,~and~is~not~a~user-defined~#2. + } +\msg_new:nnnn { fp } { id-loop } + { Variable~'#1'~used~in~the~definition~of~'#1'. } + { + LaTeX~has~been~asked~to~set~the~floating~point~identifier~'#1'~ + to~the~expression~'#2'.~Evaluating~this~expression~yields~'#3',~ + which~contains~'#1'~itself. + } +% \end{macrocode} +% +% \subsection{Road-map} +% +% The following functions are not implemented: |min|, |max|, |?:|, +% comparisons, |round|, |atan|, |acot|. +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex |