diff options
author | Karl Berry <karl@freefriends.org> | 2012-07-23 17:15:00 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2012-07-23 17:15:00 +0000 |
commit | 134349701bddf7cbbacf6030c6b9f9838aff96fa (patch) | |
tree | ec1140c46e1c0347a671a6fa3cf8af5a79e95f93 /Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx | |
parent | f7855c12c18bb97b7b9e49ab685ee558d8c0b47b (diff) |
l3kernel 3990 (17jul12)
git-svn-id: svn://tug.org/texlive/trunk@27108 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 | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx new file mode 100644 index 00000000000..2517236fb21 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx @@ -0,0 +1,393 @@ +% \iffalse meta-comment +% +%% File: l3fp-logic.dtx Copyright (C) 2011-2012 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 +%% 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 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> +\RequirePackage{l3names} +\GetIdInfo$Id: l3fp-logic.dtx 3504 2012-03-06 06:38:45Z bruno $ + {L3 Floating-point conditionals} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3fp-logic} package\thanks{This file +% has version number \ExplFileVersion, last +% revised \ExplFileDate.}\\ +% Floating point conditionals} +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3fp-logic} Implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% \subsection{Existence test} +% +% \begin{macro}[pTF]{\fp_if_exist:N, \fp_if_exist:c} +% Copies of the \texttt{cs} functions defined in \pkg{l3basics}. +% \begin{macrocode} +\cs_new_eq:NN \fp_if_exist:NTF \cs_if_exist:NTF +\cs_new_eq:NN \fp_if_exist:NT \cs_if_exist:NT +\cs_new_eq:NN \fp_if_exist:NF \cs_if_exist:NF +\cs_new_eq:NN \fp_if_exist_p:N \cs_if_exist_p:N +\cs_new_eq:NN \fp_if_exist:cTF \cs_if_exist:cTF +\cs_new_eq:NN \fp_if_exist:cT \cs_if_exist:cT +\cs_new_eq:NN \fp_if_exist:cF \cs_if_exist:cF +\cs_new_eq:NN \fp_if_exist_p:c \cs_if_exist_p:c +% \end{macrocode} +% \end{macro} +% +% \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} +% 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}. +% \begin{macrocode} +\cs_new:Npn \@@_compare: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 + \if_meaning:w #1 #4 + \if_meaning:w 1 #1 + \@@_compare_mantissa:ww #3; #6; + \else: + 0 + \fi: + \else: + \if_int_compare:w #1 < #4 - \fi: 1 + \fi: + \else: + \if_meaning:w 0 #1 + \if_meaning:w 0 #4 + 0 + \else: + 1 + \fi: + \else: + 1 + \fi: + \fi: + \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; + { + \if_int_compare:w #1 = #3 \exp_stop_f: + \@@_compare_mantissa:nnnnnnnn #2 #4 + \else: + \if_int_compare:w #1 < #3 - \fi: 1 + \fi: + } +\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: + \else: + \if_int_compare:w #2 < #6 - \fi: 1 + \fi: + \else: + \if_int_compare:w #1 < #5 - \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 |?|. +% \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 {#3} {#1} + = \__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:ww + \tex_romannumeral:D -`0 \@@_parse:n {#2} #1; + } +% \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{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; + { + \if_meaning:w 0 #1 + \prg_return_false: + \else: + \prg_return_true: + \fi: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Boolean operations} +% +% \begin{macro}[int, EXP]{\@@_not: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; + { + \if_meaning:w 0 #1 + \exp_after:wN \exp_after:wN \exp_after:wN \c_one_fp + \else: + \exp_after:wN \exp_after:wN \exp_after:wN \c_zero_fp + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]+\@@_&_o:ww+ +% \begin{macro}[int, EXP]+\@@_|_o:ww+ +% \begin{macro}[aux, EXP]{\@@_and_return:wNw} +% For \texttt{and}, if the first number is zero, return it (with the +% same sign). Otherwise, return the second one. For \texttt{or}, the +% logic is reversed: if the first number is non-zero, return it, +% otherwise return the second number: we achieve that by hi-jacking +% \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: } +\cs_new:Npn \@@_and_return:wNw #1; \fi: #2#3; { \fi: #2 #1; } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int, EXP] +% {\@@_ternary:NwwN, \@@_ternary_i:NwwN, \@@_ternary_ii:NwwN} +% 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 +% \texttt{nan}. The second function receives the output of the first +% 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 + { + \if_meaning:w \@@_parse_infix_::N #4 + \@@_ternary_loop:Nw + #2 + \s_@@ \@@_chk:w { \@@_ternary_loop_break:w } ; + \@@_ternary_break_point:n { \exp_after:wN \@@_ternary_i:NwwN } + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \@@_parse_exp_after_array:wf #3 \s_@@_stop + \exp_after:wN @ + \tex_romannumeral:D + \@@_parse_until:Nw \c_two + \@@_parse_expand:w + \else: + \@@_error:n { Missing~':'~clause~for~'?:'. } + \exp_after:wN \@@_parse_until_test:NwN + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \@@_parse_exp_after_array:wf #3 \s_@@_stop + \exp_after:wN #4 + \exp_after:wN #1 + \fi: + } +\cs_new:Npn \@@_ternary_loop_break:w #1 \fi: #2 \@@_ternary_break_point:n #3 + { + \c_zero = \c_zero \fi: + \exp_after:wN \@@_ternary_ii:NwwN + } +\cs_new:Npn \@@_ternary_loop:Nw \s_@@ \@@_chk:w #1#2; + { + \if_int_compare:w #1 > \c_zero + \exp_after:wN \@@_ternary_map_break: + \fi: + \@@_ternary_loop:Nw + } +\cs_new:Npn \@@_ternary_map_break: #1 \@@_ternary_break_point:n #2 {#2} +\cs_new:Npn \@@_ternary_i:NwwN #1#2@#3@#4 + { + \exp_after:wN \@@_parse_until_test:NwN + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \@@_parse_exp_after_array:wf #2 \s_@@_stop + #4 #1 + } +\cs_new:Npn \@@_ternary_ii:NwwN #1#2@#3@#4 + { + \exp_after:wN \@@_parse_until_test:NwN + \exp_after:wN #1 + \tex_romannumeral:D -`0 + \@@_parse_exp_after_array:wf #3 \s_@@_stop + #4 #1 + } +% \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} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file |