[latex3-commits] [git/LaTeX3-latex3-latex3] master: Make all functions robust against tuples (d5cfca5)
Bruno Le Floch
bruno at le-floch.fr
Mon Feb 12 03:02:34 CET 2018
Repository : https://github.com/latex3/latex3
On branch : master
Link : https://github.com/latex3/latex3/commit/d5cfca5c9279d4d0475b0b273bc7bc2fa2848ff4
>---------------------------------------------------------------
commit d5cfca5c9279d4d0475b0b273bc7bc2fa2848ff4
Author: Bruno Le Floch <bruno at le-floch.fr>
Date: Sun Feb 11 11:42:32 2018 -0500
Make all functions robust against tuples
Previously things like atan((1,2),3) would break horribly; now it
rightfully errors out and cleanly recovers with a nan result
>---------------------------------------------------------------
d5cfca5c9279d4d0475b0b273bc7bc2fa2848ff4
l3kernel/l3fp-aux.dtx | 77 ++++++++++++++++++++----
l3kernel/l3fp-convert.dtx | 2 +-
l3kernel/l3fp-logic.dtx | 13 ++++-
l3kernel/l3fp-parse.dtx | 120 ++++++++++++++++++++++++++++++++++----
l3kernel/l3fp-random.dtx | 24 ++++----
l3kernel/l3fp-round.dtx | 11 +++-
l3kernel/l3fp-trig.dtx | 52 +++++++----------
l3kernel/testfiles/m3rand001.tlg | 4 +-
8 files changed, 229 insertions(+), 74 deletions(-)
diff --git a/l3kernel/l3fp-aux.dtx b/l3kernel/l3fp-aux.dtx
index 4f427f4..5cf11db 100644
--- a/l3kernel/l3fp-aux.dtx
+++ b/l3kernel/l3fp-aux.dtx
@@ -468,20 +468,20 @@
%
% \subsection{Other floating point types}
%
-% \begin{macro}{\s_@@_tuple, \@@_chk_tuple:w}
+% \begin{macro}{\s_@@_tuple, \@@_tuple_chk:w}
% \begin{variable}{\c_@@_empty_tuple_fp}
% Floating point tuples take the form \cs{s_@@_tuple}
-% \cs{@@_chk_tuple:w} |{| \meta{fp 1} \meta{fp 2} \dots |}| |;| where
+% \cs{@@_tuple_chk:w} |{| \meta{fp 1} \meta{fp 2} \dots |}| |;| where
% each \meta{fp} is a floating point number or tuple, hence ends with
-% |;| itself. When a tuple is typeset, \cs{@@_chk_tuple:w} produces
+% |;| itself. When a tuple is typeset, \cs{@@_tuple_chk:w} produces
% an error, just like usual floating point numbers.
% Tuples may have zero or one element.
% \begin{macrocode}
\__scan_new:N \s_@@_tuple
-\cs_new_protected:Npn \@@_chk_tuple:w #1 ;
- { \@@_misused:n { \s_@@_tuple \@@_chk_tuple:w #1 ; } }
+\cs_new_protected:Npn \@@_tuple_chk:w #1 ;
+ { \@@_misused:n { \s_@@_tuple \@@_tuple_chk:w #1 ; } }
\tl_const:Nn \c_@@_empty_tuple_fp
- { \s_@@_tuple \@@_chk_tuple:w { } ; }
+ { \s_@@_tuple \@@_tuple_chk:w { } ; }
% \end{macrocode}
% \end{variable}
% \end{macro}
@@ -494,8 +494,8 @@
% with the |\use_none:n #1| construction.
% \begin{macrocode}
\cs_new:Npn \@@_array_count:n #1
- { \@@_tuple_count:w \s_@@_tuple \@@_chk_tuple:w {#1} ; }
-\cs_new:Npn \@@_tuple_count:w \s_@@_tuple \@@_chk_tuple:w #1 ;
+ { \@@_tuple_count:w \s_@@_tuple \@@_tuple_chk:w {#1} ; }
+\cs_new:Npn \@@_tuple_count:w \s_@@_tuple \@@_tuple_chk:w #1 ;
{
\__int_value:w \__int_eval:w 0
\@@_tuple_count_loop:Nw #1 { ? \__prg_break: } ;
@@ -519,6 +519,24 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}[EXP]{\@@_array_if_all_fp:nTF, \@@_array_if_all_fp_loop:w}
+% True if all items are floating point numbers. Used for |min|.
+% \begin{macrocode}
+\cs_new:Npn \@@_array_if_all_fp:nTF #1
+ {
+ \@@_array_if_all_fp_loop:w #1 { \s_@@ \__prg_break: } ;
+ \__prg_break_point: \use_i:nn
+ }
+\cs_new:Npn \@@_array_if_all_fp_loop:w #1#2 ;
+ {
+ \@@_if_type_fp:NTwFw
+ #1 \@@_array_if_all_fp_loop:w
+ \s_@@ { \__prg_break:n \use_iii:nnn }
+ \q_stop
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}[EXP]
% {\@@_type_from_scan:N, \@@_type_from_scan_other:N, \@@_type_from_scan:w}
% Used as \cs{@@_type_from_scan:N} \meta{token}.
@@ -548,6 +566,43 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}[EXP]{\@@_change_func_type:NNN}
+% \begin{macro}[EXP]{\@@_change_func_type_aux:w, \@@_change_func_type_chk:NNN}
+% Arguments are \meta{type marker} \meta{function} \meta{recovery}.
+% This gives the function obtained by placing the type after |@@|. If
+% the function is not defined then \meta{recovery} \meta{function} is
+% used instead; however that test is not run when the \meta{type
+% marker} is \cs{s_@@}.
+% \begin{macrocode}
+\cs_new:Npn \@@_change_func_type:NNN #1#2#3
+ {
+ \@@_if_type_fp:NTwFw
+ #1 #2
+ \s_@@
+ {
+ \exp_after:wN \@@_change_func_type_chk:NNN
+ \cs:w
+ @@ \@@_type_from_scan_other:N #1
+ \exp_after:wN \@@_change_func_type_aux:w \token_to_str:N #2
+ \cs_end:
+ #2 #3
+ }
+ \q_stop
+ }
+\exp_last_unbraced:NNNNo
+ \cs_new:Npn \@@_change_func_type_aux:w #1 { \tl_to_str:n { @@ } } { }
+\cs_new:Npn \@@_change_func_type_chk:NNN #1#2#3
+ {
+ \if_meaning:w \scan_stop: #1
+ \exp_after:wN #3 \exp_after:wN #2
+ \else:
+ \exp_after:wN #1
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \begin{macro}[EXP]{\@@_exp_after_any_f:Nnw, \@@_exp_after_any_f:nw}
% \begin{macro}[EXP]{\@@_exp_after_stop_f:nw}
% The |Nnw| function simply dispatches to the appropriate
@@ -587,10 +642,10 @@
% \cs{s_@@_stop}
% \end{quote}
% \begin{macrocode}
-\cs_new:Npn \@@_exp_after_tuple_f:nw #1 \s_@@_tuple \@@_chk_tuple:w #2 ;
+\cs_new:Npn \@@_exp_after_tuple_f:nw #1 \s_@@_tuple \@@_tuple_chk:w #2 ;
{
\exp_after:wN \s_@@_tuple
- \exp_after:wN \@@_chk_tuple:w
+ \exp_after:wN \@@_tuple_chk:w
\exp_after:wN {
\exp:w \exp_end_continue_f:w
\@@_exp_after_array_f:w #2 \s_@@_stop
@@ -1175,7 +1230,7 @@
{ \exp_last_unbraced:Nf \@@_func_to_name_aux:w { \cs_to_str:N #1 } X }
\cs_set_protected:Npn \@@_tmp:w #1 #2
{ \cs_new:Npn \@@_func_to_name_aux:w ##1 #1 ##2 #2 ##3 X {##2} }
-\exp_args:Nff \@@_tmp:w { \tl_to_str:n { @@_ } } { \tl_to_str:n { _o:w } }
+\exp_args:Nff \@@_tmp:w { \tl_to_str:n { @@_ } } { \tl_to_str:n { _o: } }
% \end{macrocode}
% \end{macro}
%
diff --git a/l3kernel/l3fp-convert.dtx b/l3kernel/l3fp-convert.dtx
index 11fab52..ee0d9a2 100644
--- a/l3kernel/l3fp-convert.dtx
+++ b/l3kernel/l3fp-convert.dtx
@@ -329,7 +329,7 @@
}
\cs_new:Npn \@@_to_tl_other:w #1
{ \cs:w @@ \@@_type_from_scan_other:N #1 _to_tl:w \cs_end: #1 }
-\cs_new:Npn \@@_tuple_to_tl:w \s_@@_tuple \@@_chk_tuple:w #1 ;
+\cs_new:Npn \@@_tuple_to_tl:w \s_@@_tuple \@@_tuple_chk:w #1 ;
{
\int_case:nnF { \@@_array_count:n {#1} }
{
diff --git a/l3kernel/l3fp-logic.dtx b/l3kernel/l3fp-logic.dtx
index 19cad2b..ead5868 100644
--- a/l3kernel/l3fp-logic.dtx
+++ b/l3kernel/l3fp-logic.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3fp-logic.dtx Copyright (C) 2011-2017 The LaTeX3 Project
+%% File: l3fp-logic.dtx Copyright (C) 2011-2018 The LaTeX3 Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -418,7 +418,8 @@
%
% \subsection{Extrema}
%
-% \begin{macro}[EXP]{\@@_minmax_o:Nw}
+% \begin{macro}[EXP]{\@@_minmax_o:Nw, \@@_minmax_aux_o:Nw}
+% First check all operands are floating point numbers.
% The argument~|#1| is $2$~to find the maximum of an array~|#2| of
% floating point numbers, and $0$~to find the minimum. We read
% numbers sequentially, keeping track of the largest (smallest) number
@@ -430,7 +431,13 @@
% fp-like trailing marker breaks the loop correctly: see the precise
% definition of \cs{@@_minmax_loop:Nww}.
% \begin{macrocode}
-\cs_new:Npn \@@_minmax_o:Nw #1#2 @
+\cs_new:Npn \@@_minmax_o:Nw #1
+ {
+ \@@_parse_function_all_fp_o:fnw
+ { \token_if_eq_meaning:NNTF 0 #1 { min } { max } }
+ { \@@_minmax_aux_o:Nw #1 }
+ }
+\cs_new:Npn \@@_minmax_aux_o:Nw #1#2 @
{
\if_meaning:w 0 #1
\exp_after:wN \@@_minmax_loop:Nww \exp_after:wN +
diff --git a/l3kernel/l3fp-parse.dtx b/l3kernel/l3fp-parse.dtx
index 541749a..e1517c5 100644
--- a/l3kernel/l3fp-parse.dtx
+++ b/l3kernel/l3fp-parse.dtx
@@ -1777,38 +1777,55 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_parse_apply_unary:NNNwN, \@@_parse_apply_unary_aux:NwNw, \@@_parse_apply_unary_aux:nNNNw}
+% \begin{macro}[EXP]{\@@_parse_apply_unary:NNNwN}
+% \begin{macro}[EXP]{\@@_parse_apply_unary_chk:NwNw, \@@_parse_apply_unary_chk:nNNNw}
+% \begin{macro}[EXP]{\@@_parse_apply_unary_type:NNN, \@@_parse_apply_unary_error:NNw}
% In contrast to \cs{@@_parse_apply_function:NNNwN}, this checks that
% the operand |#4| is a single argument (namely there is a single
% |;|). We use the fact that any floating point starts with a
-% \enquote{safe} token like \cs{s__fp}. If there is no argument
+% \enquote{safe} token like \cs{s_@@}. If there is no argument
% produce the |fp-no-arg| error; if there are at least two produce
% |fp-multi-arg|. For the error message extract the mathematical
% function name (such as |sin|) from the \pkg{expl3} function that
% computes it, such as \cs{@@_sin_o:w}.
+%
+% In addition, since there is a single argument we can dispatch on
+% type and check that the resulting function exists. This catches
+% things like |sin((1,2))| where it does not make sense to take the
+% sine of a tuple.
% \begin{macrocode}
\cs_new:Npn \@@_parse_apply_unary:NNNwN #1#2#3#4@#5
{
- \@@_parse_apply_unary_aux:NwNw #4 @ ; . \q_stop
+ \@@_parse_apply_unary_chk:NwNw #4 @ ; . \q_stop
+ \@@_parse_apply_unary_type:NNN
#3 #2 #4 @
\exp:w \exp_end_continue_f:w #5 #1
}
-\cs_new:Npn \@@_parse_apply_unary_aux:NwNw #1#2 ; #3#4 \q_stop
+\cs_new:Npn \@@_parse_apply_unary_chk:NwNw #1#2 ; #3#4 \q_stop
{
\if_meaning:w @ #3 \else:
\token_if_eq_meaning:NNTF . #3
- { \@@_parse_apply_unary_aux:nNNNw { no } }
- { \@@_parse_apply_unary_aux:nNNNw { multi } }
+ { \@@_parse_apply_unary_chk:nNNNNw { no } }
+ { \@@_parse_apply_unary_chk:nNNNNw { multi } }
\fi:
}
-\cs_new:Npn \@@_parse_apply_unary_aux:nNNNw #1#2#3#4#5 @
+\cs_new:Npn \@@_parse_apply_unary_chk:nNNNNw #1#2#3#4#5#6 @
{
#2
- \@@_error:nffn { fp-#1-arg } { \@@_func_to_name:N #3 } { } { }
- \exp_after:wN #3 \exp_after:wN #4 \c_nan_fp @
+ \@@_error:nffn { fp-#1-arg } { \@@_func_to_name:N #4 } { } { }
+ \exp_after:wN #4 \exp_after:wN #5 \c_nan_fp @
+ }
+\cs_new:Npn \@@_parse_apply_unary_type:NNN #1#2#3
+ {
+ \@@_change_func_type:NNN #3 #1 \@@_parse_apply_unary_error:NNw
+ #2 #3
}
+\cs_new:Npn \@@_parse_apply_unary_error:NNw #1#2
+ { \@@_invalid_operation_o:fw { \@@_func_to_name:N #1 } }
% \end{macrocode}
% \end{macro}
+% \end{macro}
+% \end{macro}
%
% \begin{macro}[EXP]{\@@_parse_prefix_-:Nw, \@@_parse_prefix_!:Nw}
% The unary~|-| and boolean not are harder: we parse the operand using
@@ -2309,7 +2326,7 @@
\exp_after:wN #1
\exp:w \exp_end_continue_f:w
\@@_exp_after_tuple_f:nw { }
- \s_@@_tuple \@@_chk_tuple:w { #2 #4 } ;
+ \s_@@_tuple \@@_tuple_chk:w { #2 #4 } ;
#5 #1
}
% \end{macrocode}
@@ -2587,6 +2604,87 @@
% \end{macro}
% \end{macro}
%
+% \subsection{Tools for functions}
+%
+% \begin{macro}[EXP]{\@@_parse_function_all_fp_o:fnw}
+% Followed by \Arg{function name} \Arg{code} \meta{float array} |@|
+% this checks all floats are floating point numbers (no tuples).
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_function_all_fp_o:fnw #1#2#3 @
+ {
+ \@@_array_if_all_fp:nTF {#3}
+ { #2 #3 @ }
+ {
+ \@@_error:nffn { fp-bad-args }
+ {#1}
+ { \fp_to_tl:n { \s_@@_tuple \@@_tuple_chk:w {#3} ; } }
+ { }
+ \exp_after:wN \c_nan_fp
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_parse_function_one_two:nnw}
+% \begin{macro}[EXP]
+% {
+% \@@_parse_function_one_two_error_o:w,
+% \@@_parse_function_one_two_aux:nnw,
+% \@@_parse_function_one_two_auxii:nnw
+% }
+% This is followed by \Arg{function name} \Arg{code} \meta{float
+% array} |@|. It checks that the \meta{float array} consists of one
+% or two floating point numbers (not tuples), then leaves the
+% \meta{code} (if there is one float) or its tail (if there are two
+% floats) followed by the \meta{float array}. The \meta{code} should
+% start with a single token such as \cs{@@_atan_default:w} that deals
+% with the single-float case.
+%
+% The first \cs{@@_if_type_fp:NTwFw} test catches the case of no
+% argument and the case of a tuple argument. The next one
+% distinguishes the case of a single argument (no error, just add
+% \cs{c_one_fp}) from a tuple second argument. Finally check there is
+% no further argument.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_function_one_two:nnw #1#2#3
+ {
+ \@@_if_type_fp:NTwFw
+ #3 { } \s_@@ \@@_parse_function_one_two_error_o:w \q_stop
+ \@@_parse_function_one_two_aux:nnw {#1} {#2} #3
+ }
+\cs_new:Npn \@@_parse_function_one_two_error_o:w #1#2#3#4 @
+ {
+ \@@_error:nffn { fp-bad-args }
+ {#2}
+ { \fp_to_tl:n { \s_@@_tuple \@@_tuple_chk:w {#4} ; } }
+ { }
+ \exp_after:wN \c_nan_fp
+ }
+\cs_new:Npn \@@_parse_function_one_two_aux:nnw #1#2 #3; #4
+ {
+ \@@_if_type_fp:NTwFw
+ #4 { }
+ \s_@@
+ {
+ \if_meaning:w @ #4
+ \exp_after:wN \use_iv:nnnn
+ \fi:
+ \@@_parse_function_one_two_error_o:w
+ }
+ \q_stop
+ \@@_parse_function_one_two_auxii:nnw {#1} {#2} #3; #4
+ }
+\cs_new:Npn \@@_parse_function_one_two_auxii:nnw #1#2#3; #4; #5
+ {
+ \if_meaning:w @ #5 \else:
+ \exp_after:wN \@@_parse_function_one_two_error_o:w
+ \fi:
+ \use_ii:nn {#1} { \use_none:n #2 } #3; #4; #5
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \subsection{Candidate: defining new \pkg{l3fp} functions}
%
% \begin{macro}[EXP]{\fp_function:Nw}
@@ -2723,6 +2821,8 @@
{ #1~got~more~than~one~argument;~used~nan. }
\__kernel_msg_new:nnn { kernel } { fp-num-args }
{ #1~expects~between~#2~and~#3~arguments. }
+\__kernel_msg_new:nnn { kernel } { fp-bad-args }
+ { Arguments~in~#1#2~are~invalid. }
%<*package>
\cs_if_exist:cT { @unexpandable at protect }
{
diff --git a/l3kernel/l3fp-random.dtx b/l3kernel/l3fp-random.dtx
index e7989a2..6f01b05 100644
--- a/l3kernel/l3fp-random.dtx
+++ b/l3kernel/l3fp-random.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3fp-random.dtx Copyright (C) 2016,2017 The LaTeX3 Project
+%% File: l3fp-random.dtx Copyright (C) 2016-2018 The LaTeX3 Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -213,8 +213,9 @@
% \begin{macro}[EXP]{\@@_randint_o:Nw}
% \begin{macro}[EXP]
% {
+% \@@_randint_default:w,
% \@@_randint_badarg:w,
-% \@@_randint_e:w,
+% \@@_randint_o:w,
% \@@_randint_e:wnn,
% \@@_randint_e:wwNnn,
% \@@_randint_e:wwwNnn,
@@ -243,19 +244,13 @@
% bound. The result is compared to the upper bound and the process
% repeats if needed.
% \begin{macrocode}
-\cs_new:Npn \@@_randint_o:Nw ? #1 @
+\cs_new:Npn \@@_randint_o:Nw ?
{
- \if_case:w
- \__int_eval:w \@@_array_count:n {#1} - 1 \__int_eval_end:
- \exp_after:wN \@@_randint_e:w \c_one_fp #1
- \or: \@@_randint_e:w #1
- \else:
- \__kernel_msg_expandable_error:nnnnn
- { kernel } { fp-num-args } { randint() } { 1 } { 2 }
- \exp_after:wN \c_nan_fp \exp:w
- \fi:
- \exp_after:wN \exp_end:
+ \@@_parse_function_one_two:nnw
+ { randint }
+ { \@@_randint_default:w \@@_randint_o:w }
}
+\cs_new:Npn \@@_randint_default:w #1 { \exp_after:wN #1 \c_one_fp }
\cs_new:Npn \@@_randint_badarg:w \s_@@ \@@_chk:w #1#2#3;
{
\@@_int:wTF \s_@@ \@@_chk:w #1#2#3;
@@ -269,7 +264,7 @@
}
{ 1 \exp_stop_f: }
}
-\cs_new:Npn \@@_randint_e:w #1; #2;
+\cs_new:Npn \@@_randint_o:w #1; #2; @
{
\if_case:w
\@@_randint_badarg:w #1;
@@ -282,6 +277,7 @@
{ randint } { \@@_array_to_clist:n { #1; #2; } }
\exp:w
\fi:
+ \exp_after:wN \exp_end:
}
\cs_new:Npn \@@_randint_e:wnn #1;
{
diff --git a/l3kernel/l3fp-round.dtx b/l3kernel/l3fp-round.dtx
index df4a3a4..9b2885e 100644
--- a/l3kernel/l3fp-round.dtx
+++ b/l3kernel/l3fp-round.dtx
@@ -422,14 +422,21 @@
%
% ^^A todo: This macro is intermingled with l3fp-parse.
% ^^A todo: Add explanations.
-% \begin{macro}[EXP]{\@@_round_o:Nw}
+% \begin{macro}[EXP]{\@@_round_o:Nw, \@@_round_aux_o:Nw}
+% First check that all arguments are floating point numbers.
% The |trunc|, |ceil| and |floor| functions expect one or two
% arguments (the second is $0$ by default), and the |round| function
% also accepts a third argument (\texttt{nan} by default), which
% changes |#1| from \cs{@@_round_to_nearest:NNN} to one of its
% analogues.
% \begin{macrocode}
-\cs_new:Npn \@@_round_o:Nw #1#2 @
+\cs_new:Npn \@@_round_o:Nw #1
+ {
+ \@@_parse_function_all_fp_o:fnw
+ { \@@_round_name_from_cs:N #1 }
+ { \@@_round_aux_o:Nw #1 }
+ }
+\cs_new:Npn \@@_round_aux_o:Nw #1#2 @
{
\if_case:w
\__int_eval:w \@@_array_count:n {#2} \__int_eval_end:
diff --git a/l3kernel/l3fp-trig.dtx b/l3kernel/l3fp-trig.dtx
index 132c598..5351d5c 100644
--- a/l3kernel/l3fp-trig.dtx
+++ b/l3kernel/l3fp-trig.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3fp-trig.dtx Copyright (C) 2011-2017 The LaTeX3 Project
+%% File: l3fp-trig.dtx Copyright (C) 2011-2018 The LaTeX3 Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -1087,44 +1087,34 @@
%
% \subsubsection{Arctangent and arccotangent}
%
-% \begin{macro}[EXP]{\@@_atan_o:Nw, \@@_acot_o:Nw}
-% \begin{macro}[EXP]{\@@_atan_dispatch_o:NNnNw}
+% \begin{macro}[EXP]{\@@_atan_o:Nw, \@@_acot_o:Nw, \@@_atan_default:w}
% The parsing step manipulates \texttt{atan} and \texttt{acot} like
% \texttt{min} and \texttt{max}, reading in an array of operands, but
% also leaves \cs{use_i:nn} or \cs{use_ii:nn} depending on whether the
-% result should be given in radians or in degrees. Here, we dispatch
-% according to the number of arguments. The one-argument versions of
-% arctangent and arccotangent are special cases of the two-argument
-% ones: $\operatorname{atan}(y) = \operatorname{atan}(y, 1) = \operatorname{acot}(1, y)$ and
-% $\operatorname{acot}(x) = \operatorname{atan}(1, x) = \operatorname{acot}(x, 1)$.
+% result should be given in radians or in degrees. The helper
+% \cs{@@_parse_function_one_two:nnw} checks that the operand is one or
+% two floating point numbers (not tuples) and leaves its second
+% argument or its tail accordingly (its first argument is used for
+% error messages). More precisely if we are given a single floating
+% point number \cs{@@_atan_default:w} places \cs{c_one_fp} (expanded)
+% after it; otherwise \cs{@@_atan_default:w} is omitted by
+% \cs{@@_parse_function_one_two:nnw}.
% \begin{macrocode}
-\cs_new:Npn \@@_atan_o:Nw
+\cs_new:Npn \@@_atan_o:Nw #1
{
- \@@_atan_dispatch_o:NNnNw
- \@@_acotii_o:Nww \@@_atanii_o:Nww { atan }
+ \@@_parse_function_one_two:nnw
+ { #1 { atan } { atand } }
+ { \@@_atan_default:w \@@_atanii_o:Nww #1 }
}
-\cs_new:Npn \@@_acot_o:Nw
+\cs_new:Npn \@@_acot_o:Nw #1
{
- \@@_atan_dispatch_o:NNnNw
- \@@_atanii_o:Nww \@@_acotii_o:Nww { acot }
- }
-\cs_new:Npn \@@_atan_dispatch_o:NNnNw #1#2#3#4#5@
- {
- \if_case:w
- \__int_eval:w \@@_array_count:n {#5} - 1 \__int_eval_end:
- \exp_after:wN #1 \exp_after:wN #4 \c_one_fp #5
- \exp:w
- \or: #2 #4 #5 \exp:w
- \else:
- \__kernel_msg_expandable_error:nnnnn
- { kernel } { fp-num-args } { #3() } { 1 } { 2 }
- \exp_after:wN \c_nan_fp \exp:w
- \fi:
- \exp_after:wN \exp_end:
+ \@@_parse_function_one_two:nnw
+ { #1 { acot } { acotd } }
+ { \@@_atan_default:w \@@_acotii_o:Nww #1 }
}
+\cs_new:Npx \@@_atan_default:w #1#2#3 @ { #1 #2 #3 \c_one_fp @ }
% \end{macrocode}
% \end{macro}
-% \end{macro}
%
% \begin{macro}[EXP]{\@@_atanii_o:Nww, \@@_acotii_o:Nww}
% If either operand is \texttt{nan}, we return it. If both are
@@ -1139,7 +1129,7 @@
% \cs{@@_acotii_o:ww} simply reverses its two arguments.
% \begin{macrocode}
\cs_new:Npn \@@_atanii_o:Nww
- #1 \s_@@ \@@_chk:w #2#3#4; \s_@@ \@@_chk:w #5
+ #1 \s_@@ \@@_chk:w #2#3#4; \s_@@ \@@_chk:w #5 #6 @
{
\if_meaning:w 3 #2 \@@_case_return_i_o:ww \fi:
\if_meaning:w 3 #5 \@@_case_return_ii_o:ww \fi:
@@ -1156,7 +1146,7 @@
\fi:
\@@_atan_normal_o:NNnwNnw #1
\s_@@ \@@_chk:w #2#3#4;
- \s_@@ \@@_chk:w #5
+ \s_@@ \@@_chk:w #5 #6
}
\cs_new:Npn \@@_acotii_o:Nww #1#2; #3;
{ \@@_atanii_o:Nww #1#3; #2; }
diff --git a/l3kernel/testfiles/m3rand001.tlg b/l3kernel/testfiles/m3rand001.tlg
index ab39ffa..c3a3af6 100644
--- a/l3kernel/testfiles/m3rand001.tlg
+++ b/l3kernel/testfiles/m3rand001.tlg
@@ -80,7 +80,7 @@ spelling (e.g., `I\hbox'). Otherwise just continue,
and I'll forget about whatever was undefined.
! Undefined control sequence.
<argument> \LaTeX3 error:
- randint() expects between 1 and 2 arguments.
+ Arguments in randint() are invalid.
l. ... }
The control sequence at the end of the top line
of your error message was never \def'ed. If you have
@@ -125,7 +125,7 @@ spelling (e.g., `I\hbox'). Otherwise just continue,
and I'll forget about whatever was undefined.
! Undefined control sequence.
<argument> \LaTeX3 error:
- randint() expects between 1 and 2 arguments.
+ Arguments in randint(1, 2, 3) are invalid.
l. ... }
The control sequence at the end of the top line
of your error message was never \def'ed. If you have
More information about the latex3-commits
mailing list