summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2012-08-16 22:41:08 +0000
committerKarl Berry <karl@freefriends.org>2012-08-16 22:41:08 +0000
commitca1c73f9a8de69e467230c4a57ccf8b07cd275a9 (patch)
tree6272657307f73c14327d6b8bce5d6b7ff97c3f66 /Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
parent22c251adda514ed7b453066de05b2f89707d0fe6 (diff)
finish l3 update
git-svn-id: svn://tug.org/texlive/trunk@27427 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx340
1 files changed, 205 insertions, 135 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
index 2517236fb21..9813509686d 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
@@ -35,7 +35,7 @@
%%
%
%<*driver>
-\RequirePackage{l3names}
+\RequirePackage{l3bootstrap}
\GetIdInfo$Id: l3fp-logic.dtx 3504 2012-03-06 06:38:45Z bruno $
{L3 Floating-point conditionals}
\documentclass[full]{l3doc}
@@ -77,6 +77,20 @@
%<@@=fp>
% \end{macrocode}
%
+% \subsection{Syntax of internal functions}
+%
+% \begin{itemize}
+% \item \cs{@@_compare_npos:nwnw} \Arg{expo_1} \meta{body_1} |;|
+% \Arg{expo_2} \meta{body_2} |;|
+% \item \cs{@@_max_o:w} \meta{floating point array}
+% \item \cs{@@_min_o:w} \meta{floating point array}
+% \item \cs{@@_not_o:w} \meta{floating point}
+% \item \cs{@@_\string&_o:ww} \meta{floating point} \meta{floating point}
+% \item \cs{@@_\string|_o:ww} \meta{floating point} \meta{floating point}
+% \item \cs{@@_ternary:NwwN}, \cs{@@_ternary_i:NwwN},
+% \cs{@@_ternary_ii:NwwN} have to be understood.
+% \end{itemize}
+%
% \subsection{Existence test}
%
% \begin{macro}[pTF]{\fp_if_exist:N, \fp_if_exist:c}
@@ -95,44 +109,91 @@
%
% \subsection{Comparison}
%
-% \begin{macro}[int, EXP]{\@@_compare:ww}
-% \begin{macro}[aux, EXP]
-% {
-% \@@_compare_nan:w, \@@_compare_mantissa:ww,
-% \@@_compare_mantissa:nnnnnnnn
-% }
-% \begin{syntax}
-% \cs{@@_compare:ww} \meta{X} |;| \meta{Y} |;|
-% \end{syntax}
+% \begin{macro}[pTF, EXP]{\fp_compare:n}
+% \begin{macro}[aux, EXP]{\@@_compare_return:w}
+% Within floating point expressions, comparison operators are treated
+% as operations, so we evaluate |#1|, then compare with $0$.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \fp_compare:n #1 { p , T , F , TF }
+ {
+ \exp_after:wN \@@_compare_return:w
+ \tex_romannumeral:D -`0 \@@_parse:n {#1}
+ }
+\cs_new:Npn \@@_compare_return:w \s_@@ \@@_chk:w #1#2;
+ {
+ \if_meaning:w 0 #1
+ \prg_return_false:
+ \else:
+ \prg_return_true:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[pTF, EXP]{\fp_compare:nNn}
+% \begin{macro}[aux, EXP]{\@@_compare_aux:wn}
+% Evaluate |#1| and |#3|, using an auxiliary to expand both, and feed
+% the two floating point numbers swapped to \cs{@@_compare_back:ww},
+% defined below. Compare the result with |`#2-`=|, which is $-1$ for
+% |<|, $0$ for |=|, $1$ for |>| and $2$ for |?|.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \fp_compare:nNn #1#2#3 { p , T , F , TF }
+ {
+ \if_int_compare:w
+ \exp_after:wN \@@_compare_aux:wn
+ \tex_romannumeral:D -`0 \@@_parse:n {#1} {#3}
+ = \__int_eval:w `#2 - `= \__int_eval_end:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+\cs_new:Npn \@@_compare_aux:wn #1; #2
+ {
+ \exp_after:wN \@@_compare_back:ww
+ \tex_romannumeral:D -`0 \@@_parse:n {#2} #1;
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_compare_back:ww, \@@_compare_nan:w}
+% \begin{quote}
+% \cs{@@_compare_back:ww} \meta{y} |;| \meta{x} |;|
+% \end{quote}
% Expands (in the same way as \cs{int_eval:n}) to $-1$ if $x<y$, $0$
-% if $x=y$, $1$ if $x>y$, and $2$ otherwise (denoted as $x?y$). A
-% trick that will later be useful is that the character codes of |<|,
-% |=|, |>| and |?| are contiguous, and in the same order as the return
-% codes of \cs{@@_compare:ww}.
+% if $x=y$, $1$ if $x>y$, and $2$ otherwise (denoted as $x?y$). If
+% either operand is \texttt{nan}, stop the comparison with
+% \cs{@@_compare_nan:w} returning $2$. If $x$ is negative, swap the
+% outputs $1$ and $-1$ (\emph{i.e.}, $>$ and $<$); we can henceforth
+% assume that $x\geq 0$. If $y\geq 0$, and they have the same type,
+% either they are normal and we compare them with
+% \cs{@@_compare_npos:nwnw}, or they are equal. If $y\geq 0$, but of
+% a different type, the highest type is a larger number. Finally, if
+% $y\leq 0$, then $x>y$, unless both are zero.
% \begin{macrocode}
-\cs_new:Npn \@@_compare:ww \s_@@ \@@_chk:w #1#2#3; \s_@@ \@@_chk:w #4#5#6;
+\cs_new:Npn \@@_compare_back:ww
+ \s_@@ \@@_chk:w #1 #2 #3;
+ \s_@@ \@@_chk:w #4 #5 #6;
{
\__int_value:w
\if_meaning:w 3 #1 \exp_after:wN \@@_compare_nan:w \fi:
\if_meaning:w 3 #4 \exp_after:wN \@@_compare_nan:w \fi:
- \if_meaning:w 2 #2 - \fi:
+ \if_meaning:w 2 #5 - \fi:
\if_meaning:w #2 #5
\if_meaning:w #1 #4
\if_meaning:w 1 #1
- \@@_compare_mantissa:ww #3; #6;
+ \@@_compare_npos:nwnw #6; #3;
\else:
0
\fi:
\else:
- \if_int_compare:w #1 < #4 - \fi: 1
+ \if_int_compare:w #4 < #1 - \fi: 1
\fi:
\else:
- \if_meaning:w 0 #1
- \if_meaning:w 0 #4
- 0
- \else:
- 1
- \fi:
+ \if_int_compare:w #1#4 = \c_zero
+ 0
\else:
1
\fi:
@@ -140,7 +201,26 @@
\exp_stop_f:
}
\cs_new:Npn \@@_compare_nan:w #1 \exp_stop_f: { \c_two }
-\cs_new:Npn \@@_compare_mantissa:ww #1#2; #3#4;
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int, EXP]{\@@_compare_npos:nwnw}
+% \begin{macro}[aux, EXP]{\@@_compare_mantissa:nnnnnnnn}
+% \begin{quote}
+% \cs{@@_compare_npos:nwnw}
+% \Arg{expo_1} \meta{body_1} |;|
+% \Arg{expo_2} \meta{body_2} |;|
+% \end{quote}
+% Within an \cs{__int_value:w} \ldots{} \cs{exp_stop_f:} construction,
+% this expands to $0$ if the two numbers are equal, $-1$ if the first
+% is smaller, and $1$ if the first is bigger. First compare the
+% exponents: the larger one denotes the larger number. If they are
+% equal, we must compare mantissas. If both the first $8$ digits and
+% the next $8$ digits coincide, the numbers are equal. If only the
+% first $8$ digits coincide, the next $8$ decide. Otherwise, the
+% first $8$ digits are compared.
+% \begin{macrocode}
+\cs_new:Npn \@@_compare_npos:nwnw #1#2; #3#4;
{
\if_int_compare:w #1 = #3 \exp_stop_f:
\@@_compare_mantissa:nnnnnnnn #2 #4
@@ -150,83 +230,114 @@
}
\cs_new:Npn \@@_compare_mantissa:nnnnnnnn #1#2#3#4#5#6#7#8
{
- \if_int_compare:w #1 = #5 \exp_stop_f:
- \if_int_compare:w #2 = #6 \exp_stop_f:
- \if_int_compare:w #3 = #7 \exp_stop_f:
- \if_int_compare:w #4 = #8 \exp_stop_f:
- 0
- \else:
- \if_int_compare:w #4 < #8 - \fi: 1
- \fi:
- \else:
- \if_int_compare:w #3 < #7 - \fi: 1
- \fi:
+ \if_int_compare:w #1#2 = #5#6 \exp_stop_f:
+ \if_int_compare:w #3#4 = #7#8 \exp_stop_f:
+ 0
\else:
- \if_int_compare:w #2 < #6 - \fi: 1
+ \if_int_compare:w #3#4 < #7#8 - \fi: 1
\fi:
\else:
- \if_int_compare:w #1 < #5 - \fi: 1
+ \if_int_compare:w #1#2 < #5#6 - \fi: 1
\fi:
}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[pTF, EXP]{\fp_compare:nNn}
-% \begin{macro}[aux, EXP]{\@@_compare_aux:wn}
-% Evaluate |#1| and |#3|, using an auxiliary to expand both, in the
-% correct order. Then compare this to |`#2-`=|, which is $-1$ for
-% |<|, $0$ for |=|, $1$ for |>| and $2$ for |?|.
+% \subsection{Extrema}
+%
+% \begin{macro}[int, EXP]{\@@_max_o:w, \@@_min_o:w}
+% The maximum (minimum) of an array of floating point numbers is
+% computed by reading them sequentially, keeping track of the largest
+% (smallest) number found so far. We start with $-\infty$ ($\infty$)
+% since every number is larger (smaller) than that. The weird fp-like
+% trailing marker breaks the loop correctly: see the precise
+% definition of \cs{@@_minmax_loop:Nww}.
% \begin{macrocode}
-\prg_new_conditional:Npnn \fp_compare:nNn #1#2#3 { p , T , F , TF }
+\cs_new:Npn \@@_max_o:w #1 @
{
- \if_int_compare:w
- \exp_after:wN \@@_compare_aux:wn
- \tex_romannumeral:D -`0 \@@_parse:n {#3} {#1}
- = \__int_eval:w `#2 - `= \__int_eval_end:
- \prg_return_true:
- \else:
- \prg_return_false:
- \fi:
+ \exp_after:wN \@@_minmax_loop:Nww
+ \exp_after:wN \c_minus_one
+ \c_minus_inf_fp
+ #1
+ \s_@@ \@@_chk:w { 3 \@@_minmax_break_o:w } ;
}
-\cs_new:Npn \@@_compare_aux:wn #1; #2
+\cs_new:Npn \@@_min_o:w #1 @
{
- \exp_after:wN \@@_compare:ww
- \tex_romannumeral:D -`0 \@@_parse:n {#2} #1;
+ \exp_after:wN \@@_minmax_loop:Nww
+ \exp_after:wN \c_one
+ \c_inf_fp
+ #1
+ \s_@@ \@@_chk:w { 3 \@@_minmax_break_o:w } ;
}
% \end{macrocode}
% \end{macro}
-% \end{macro}
%
-% \begin{macro}[EXP,pTF]{\fp_compare:n}
-% \begin{macro}[aux,EXP]{\@@_compare_aux:w}
-% For floating points the comparison operators are treated as
-% operations, so we simply evaluate then compare with \cs{c_zero_fp}.
+% \begin{macro}[aux, EXP]{\@@_minmax_loop:Nww}
+% The first argument is $-1$ or $1$ to denote the case where the
+% currently largest (smallest) number found (first floating point
+% argument) should be replaced by the new number (second floating
+% point argument). If the new number is \texttt{nan}, keep that as
+% the extremum, unless that extremum is already a \texttt{nan}.
+% Otherwise, compare the two numbers. If the new number is larger (in
+% the case of |max|) or smaller (in the case of |min|), the test
+% yields \texttt{true}, and we keep the second number as a new
+% maximum; otherwise we keep the first number. Then loop.
% \begin{macrocode}
-\prg_new_conditional:Npnn \fp_compare:n #1 { p , T , F , TF }
- {
- \exp_after:wN \@@_compare_aux:w
- \tex_romannumeral:D -`0 \@@_parse:n {#1}
- }
-\cs_new:Npn \@@_compare_aux:w \s_@@ \@@_chk:w #1#2;
+\cs_new:Npn \@@_minmax_loop:Nww
+ #1 \s_@@ \@@_chk:w #2#3; \s_@@ \@@_chk:w #4#5;
{
- \if_meaning:w 0 #1
- \prg_return_false:
+ \if_meaning:w 3 #4
+ \if_meaning:w 3 #2
+ \@@_minmax_i:ww
+ \else:
+ \@@_minmax_ii:ww
+ \fi:
\else:
- \prg_return_true:
+ \if_int_compare:w
+ \@@_compare_back:ww
+ \s_@@ \@@_chk:w #4#5;
+ \s_@@ \@@_chk:w #2#3;
+ = #1
+ \@@_minmax_ii:ww
+ \else:
+ \@@_minmax_i:ww
+ \fi:
\fi:
+ \@@_minmax_loop:Nww #1
+ \s_@@ \@@_chk:w #2#3;
+ \s_@@ \@@_chk:w #4#5;
}
% \end{macrocode}
% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_minmax_i:ww, \@@_minmax_ii:ww}
+% Keep the first/second number, and remove the other.
+% \begin{macrocode}
+\cs_new:Npn \@@_minmax_i:ww #1 \fi: \fi: #2 \s_@@ #3 ; \s_@@ #4;
+ { \fi: \fi: #2 \s_@@ #3 ; }
+\cs_new:Npn \@@_minmax_ii:ww #1 \fi: \fi: #2 \s_@@ #3 ;
+ { \fi: \fi: #2 }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, EXP]{\@@_minmax_break_o:w}
+% This function is called from within an \cs{if_meaning:w} test. Skip
+% to the end of the tests, close the current test with \cs{fi:}, clean
+% up, and return the appropriate number with one post-expansion.
+% \begin{macrocode}
+\cs_new:Npn \@@_minmax_break_o:w #1 \fi: \fi: #2 \s_@@ #3; #4;
+ { \fi: \@@_exp_after_o:w \s_@@ #3; }
+% \end{macrocode}
% \end{macro}
%
% \subsection{Boolean operations}
%
-% \begin{macro}[int, EXP]{\@@_not:w}
+% \begin{macro}[int, EXP]{\@@_not_o:w}
% Return \texttt{true} or \texttt{false}, with two expansions, one to
% exit the conditional, and one to please \pkg{l3fp-parse}.
% \begin{macrocode}
-\cs_new:Npn \@@_not:w \s_@@ \@@_chk:w #1#2;
+\cs_new:Npn \@@_not_o:w \s_@@ \@@_chk:w #1#2;
{
\if_meaning:w 0 #1
\exp_after:wN \exp_after:wN \exp_after:wN \c_one_fp
@@ -247,23 +358,34 @@
% \cs{@@_\&_o:ww}, inserting an extra argument, \cs{else:}, before
% \cs{s_@@}. In all cases, expand after the floating point number.
% \begin{macrocode}
-\cs_new:cpn { @@_ \iow_char:N \& _o:ww } #1 \s_@@ \@@_chk:w #2#3;
- {
- \if_meaning:w 0 #2 #1
- \@@_and_return:wNw \s_@@ \@@_chk:w #2#3;
- \fi:
- \@@_exp_after_o:w
- }
-\cs_new_nopar:cpx { @@_ \iow_char:N \| _o:ww }
- { \exp_not:c { @@_ \iow_char:N \& _o:ww } \exp_not:N \else: }
+\group_begin:
+ \char_set_catcode_letter:N &
+ \char_set_catcode_letter:N |
+ \cs_new:Npn \@@_&_o:ww #1 \s_@@ \@@_chk:w #2#3;
+ {
+ \if_meaning:w 0 #2 #1
+ \@@_and_return:wNw \s_@@ \@@_chk:w #2#3;
+ \fi:
+ \@@_exp_after_o:w
+ }
+ \cs_new_nopar:Npn \@@_|_o:ww { \@@_&_o:ww \else: }
+\group_end:
\cs_new:Npn \@@_and_return:wNw #1; \fi: #2#3; { \fi: #2 #1; }
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
+% \subsection{Ternary operator}
+%
+%^^A todo: understand and optimize.
% \begin{macro}[int, EXP]
% {\@@_ternary:NwwN, \@@_ternary_i:NwwN, \@@_ternary_ii:NwwN}
+% \begin{macro}[aux, EXP]
+% {
+% \@@_ternary_loop_break:w, \@@_ternary_loop:Nw,
+% \@@_ternary_map_break:, \@@_ternary_break_point:n
+% }
% The first function receives the test and the true branch of the |?:|
% ternary operator. It returns the true branch, unless the test
% branch is zero. In that case, the function returns a very specific
@@ -271,7 +393,6 @@
% function, and the false branch. It returns the previous input,
% unless that is the special \texttt{nan}, in which case we return the
% false branch.
-%^^A todo: optimize.
% \begin{macrocode}
\cs_new:Npn \@@_ternary:NwwN #1 #2@ #3@ #4
{
@@ -288,7 +409,8 @@
\@@_parse_until:Nw \c_two
\@@_parse_expand:w
\else:
- \@@_error:n { Missing~':'~clause~for~'?:'. }
+ \__msg_kernel_expandable_error:nnnn
+ { kernel } { fp-missing } { : } { ~for~?: }
\exp_after:wN \@@_parse_until_test:NwN
\exp_after:wN #1
\tex_romannumeral:D -`0
@@ -328,58 +450,6 @@
}
% \end{macrocode}
% \end{macro}
-%
-% \begin{macro}[int, EXP]{\@@_max:w, \@@_min:w}
-% \begin{macrocode}
-\cs_new:Npn \@@_max:w #1@
- {
- \exp_after:wN \@@_minmax_loop:Nww
- \exp_after:wN \c_minus_one
- \c_minus_inf_fp
- #1
- \s_@@ \@@_chk:w { 3 \@@_minmax_break:w } ;
- }
-\cs_new:Npn \@@_min:w #1@
- {
- \exp_after:wN \@@_minmax_loop:Nww
- \exp_after:wN \c_one
- \c_inf_fp
- #1
- \s_@@ \@@_chk:w { 3 \@@_minmax_break:w } ;
- }
-\cs_new:Npn \@@_minmax_loop:Nww
- #1 \s_@@ \@@_chk:w #2#3; \s_@@ \@@_chk:w #4#5;
- {
- \if_meaning:w 3 #4
- \if_meaning:w 3 #2
- \@@_minmax_i:ww
- \else:
- \@@_minmax_ii:ww
- \fi:
- \else:
- \if_int_compare:w \@@_compare:ww \s_@@ \@@_chk:w #2#3;
- \s_@@ \@@_chk:w #4#5; = #1
- \@@_minmax_ii:ww
- \else:
- \@@_minmax_i:ww
- \fi:
- \fi:
- \@@_minmax_loop:Nww #1
- \s_@@ \@@_chk:w #2#3;
- \s_@@ \@@_chk:w #4#5;
- }
-\cs_new:Npn \@@_minmax_i:ww
- #1 \@@_minmax_loop:Nww #2 \s_@@ #3; \s_@@ #4;
- { #1 \@@_minmax_loop:Nww #2 \s_@@ #3; }
-\cs_new:Npn \@@_minmax_ii:ww
- #1 \@@_minmax_loop:Nww #2 \s_@@ #3; \s_@@ #4;
- { #1 \@@_minmax_loop:Nww #2 \s_@@ #4; }
-\cs_new:Npn \@@_minmax_break:w #1 \@@_minmax_loop:Nww #2 #3; #4;
- {
- \fi:
- \@@_exp_after_o:w #3;
- }
-% \end{macrocode}
% \end{macro}
%
% \begin{macrocode}
@@ -390,4 +460,4 @@
%
% \PrintChanges
%
-% \PrintIndex \ No newline at end of file
+% \PrintIndex