diff options
author | Karl Berry <karl@freefriends.org> | 2012-08-16 22:41:08 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2012-08-16 22:41:08 +0000 |
commit | ca1c73f9a8de69e467230c4a57ccf8b07cd275a9 (patch) | |
tree | 6272657307f73c14327d6b8bce5d6b7ff97c3f66 /Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx | |
parent | 22c251adda514ed7b453066de05b2f89707d0fe6 (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.dtx | 340 |
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 |