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-convert.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-convert.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx new file mode 100644 index 00000000000..057cef4b176 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx @@ -0,0 +1,476 @@ +% \iffalse meta-comment +% +%% File: l3fp-convert.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-convert.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 Floating-point conversion} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \textsf{l3fp-convert} package\\ Floating point conversion^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \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} +% +% ^^A todo: tests +% ^^A todo: doc functions +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\texttt{l3fp-convert} implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +% \subsection{Trimming trailing zeros} +% +% \begin{macro}[int, EXP]{\@@_trim_zeros:w} +% \begin{macro}[aux, EXP] +% {\@@_trim_zeros_loop:w, \@@_trim_zeros_dot:w, \@@_trim_zeros_end:w} +% If |#1| ends with a $0$, the \texttt{loop} auxiliary takes that zero +% as an end-delimiter for its first argument, and the second argument +% is the same \texttt{loop} auxiliary. Once the last trailing zero is +% reached, the second argument will be the \texttt{dot} auxiliary, +% which removes a trailing dot if any. We then cleanup with the +% \texttt{end} auxiliary, keeping only the number. +% \begin{macrocode} +\cs_new:Npn \@@_trim_zeros:w #1 ; + { + \@@_trim_zeros_loop:w #1 + ; \@@_trim_zeros_loop:w 0; \@@_trim_zeros_dot:w .; \s__stop + } +\cs_new:Npn \@@_trim_zeros_loop:w #1 0; #2 { #2 #1 ; #2 } +\cs_new:Npn \@@_trim_zeros_dot:w #1 .; { \@@_trim_zeros_end:w #1 ; } +\cs_new:Npn \@@_trim_zeros_end:w #1 ; #2 \s__stop { #1 } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Scientific notation} +% +% \begin{variable}{\c_@@_scientific_inf_tl} +% Result of converting $\infty$ to a scientific representation: after +% triggering an \enquote{invalid operation} exception, +% \cs{fp_to_scientific:n} yields that result, larger than any finite +% floating point number. +% \begin{macrocode} +\tl_const:Nx \c_@@_scientific_inf_tl + { 1e \int_use:N \c_@@_max_exponent_int } +% \end{macrocode} +% \end{variable} +% +% \begin{macro} +% {\fp_to_scientific:N, \fp_to_scientific:c, \fp_to_scientific:n} +% The three public functions evaluate their argument, then pass it to +% \cs{@@_to_scientific:w}. +% \begin{macrocode} +\cs_new:Npn \fp_to_scientific:N #1 { \exp_after:wN \@@_to_scientific:w #1 } +\cs_generate_variant:Nn \fp_to_scientific:N { c } +\cs_new:Npn \fp_to_scientific:n #1 + { + \exp_after:wN \@@_to_scientific:w + \tex_romannumeral:D -`0 \@@_parse:n {#1} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP] +% { +% \@@_to_scientific:w, +% \@@_to_scientific_normal:wnnnnn, +% \@@_to_scientific_normal:wNw +% } +% Expressing an internal floating point number in scientific notation +% is quite easy: no rounding, and the format is very well defined. +% First cater for the sign: negative numbers (|#2=2|) start with |-|. +% Then filter the special cases: we insert \cs{prg_do_nothing:} +% because \cs{@@_invalid_operation:Nnw} expands after taking one +% floating point argument. In the normal case, decrement the exponent +% and unbrace the $4$ brace groups, then in a second step grab the +% first digit (previously hidden in braces) to order the various parts +% correctly. Finally trim zeros. +% \begin{macrocode} +\cs_new:Npn \@@_to_scientific:w \s_@@ \@@_chk:w #1#2#3 ; + { + \if_meaning:w 2 #2 \exp_after:wN - \tex_romannumeral:D -`0 \fi: + \if_case:w #1 \exp_stop_f: + \@@_case_return:nw { \exp_after:wN 0 } + \or: \exp_after:wN \@@_to_scientific_normal:wnnnnn + \or: + \@@_case_use:nw + { + \@@_invalid_operation:Nnw + \c_@@_scientific_inf_tl { fp_to_scientific } + } + \or: + \@@_case_use:nw + { \@@_invalid_operation:Nnw 0 { fp_to_scientific } } + \fi: + \s_@@ \@@_chk:w #1 #2 #3 ; \prg_do_nothing: + } +\cs_new:Npn \@@_to_scientific_normal:wnnnnn + \s_@@ \@@_chk:w 1 #1 #2 #3#4#5#6 ; \prg_do_nothing: + { + \if_int_compare:w #2 = \c_one + \exp_after:wN \@@_to_scientific_normal:wNw + \else: + \exp_after:wN \@@_to_scientific_normal:wNw + \exp_after:wN e + \int_use:N \__int_eval:w #2 - \c_one + \fi: + ; #3 #4 #5 #6 ; + } +\cs_new:Npn \@@_to_scientific_normal:wNw #1 ; #2#3; + { \@@_trim_zeros:w #2.#3 ; #1 } +% \end{macrocode} +% \end{macro} +% +% \subsection{Decimal representation} +% +% \begin{variable}{\c_@@_decimal_inf_tl} +% Result of converting $\infty$ to a decimal representation: after +% triggering an \enquote{invalid operation} exception, +% \cs{fp_to_decimal:n} yields a~$1$ followed by $\ExplSyntaxOn +% \int_use:N \c__fp_max_exponent_int$~$0$, larger than any finite +% floating point number. Since the expanded token list is very long, +% we use an \texttt{n}-type assignment. +% \begin{macrocode} +\tl_const:Nn \c_@@_decimal_inf_tl + { + \exp_after:wN \exp_after:wN \exp_after:wN 1 + \prg_replicate:nn \c_@@_max_exponent_int 0 + } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}[EXP] +% {\fp_to_decimal:N, \fp_to_decimal:c, \fp_to_decimal:n} +% All three public variants are based on the same \cs{@@_to_decimal:w} +% after evaluating their argument to an internal floating point. +% \begin{macrocode} +\cs_new:Npn \fp_to_decimal:N #1 { \exp_after:wN \@@_to_decimal:w #1 } +\cs_generate_variant:Nn \fp_to_decimal:N { c } +\cs_new_nopar:Npn \fp_to_decimal:n + { + \exp_after:wN \@@_to_decimal:w + \tex_romannumeral:D -`0 \@@_parse:n + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP, aux] +% { +% \@@_to_decimal:w, +% \@@_to_decimal_normal:wnnnnn, +% \@@_to_decimal_large:Nnnw, +% \@@_to_decimal_huge:wnnnn, +% } +% The structure is similar to \cs{@@_to_scientific:w}. Insert |-| for +% negative numbers. Zero gives $0$, $\pm\infty$ and \nan{} yield an +% \enquote{invalid operation} exception. Normal numbers with an +% exponent in the range $[1,15]$ have that number of digits before the +% decimal separator: \enquote{decimate} them, and remove leading zeros +% with \cs{__int_value:w}, then trim trailing zeros and dot. Normal +% numbers with an exponent $16$ or larger have no decimal separator, +% we only need to add trailing zeros. When the exponent is +% non-positive, the result should be $0.\meta{zeros}\meta{digits}$, +% trimmed. +% \begin{macrocode} +\cs_new:Npn \@@_to_decimal:w \s_@@ \@@_chk:w #1#2#3 ; + { + \if_meaning:w 2 #2 \exp_after:wN - \tex_romannumeral:D -`0 \fi: + \if_case:w #1 \exp_stop_f: + \@@_case_return:nw { \exp_after:wN 0 } + \or: \exp_after:wN \@@_to_decimal_normal:wnnnnn + \or: + \@@_case_use:nw + { + \@@_invalid_operation:Nnw + \c_@@_decimal_inf_tl { fp_to_decimal } + } + \or: + \@@_case_use:nw + { \@@_invalid_operation:Nnw 0 { fp_to_decimal } } + \fi: + \s_@@ \@@_chk:w #1 #2 #3 ; \prg_do_nothing: + } +\cs_new:Npn \@@_to_decimal_normal:wnnnnn + \s_@@ \@@_chk:w 1 #1 #2 #3#4#5#6 ; \prg_do_nothing: + { + \int_compare:nNnTF {#2} > \c_zero + { + \int_compare:nNnTF {#2} < \c_sixteen + { + \@@_decimate:nNnnnn { \c_sixteen - #2 } + \@@_to_decimal_large:Nnnw + } + { + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_to_decimal_huge:wnnnn + \prg_replicate:nn { #2 - \c_sixteen } { 0 } ; + } + {#3} {#4} {#5} {#6} + } + { + \exp_after:wN \@@_trim_zeros:w + \exp_after:wN 0 + \exp_after:wN . + \tex_romannumeral:D -`0 \prg_replicate:nn { - #2 } { 0 } + #3#4#5#6 ; + } + } +\cs_new:Npn \@@_to_decimal_large:Nnnw #1#2#3#4; + { + \exp_after:wN \@@_trim_zeros:w \__int_value:w + \if_int_compare:w #2 > \c_zero + #2 + \fi: + \exp_stop_f: + #3.#4 ; + } +\cs_new:Npn \@@_to_decimal_huge:wnnnn #1; #2#3#4#5 { #2#3#4#5 #1 } +% \end{macrocode} +% \end{macro} +% +% \subsection{Token list representation} +% +% \begin{macro}[EXP]{\fp_to_tl:N, \fp_to_tl:c, \fp_to_tl:n} +% These three public functions evaluate their argument, then pass it +% to \cs{@@_to_tl:w}. +% \begin{macrocode} +\cs_new:Npn \fp_to_tl:N #1 { \exp_after:wN \@@_to_tl:w #1 } +\cs_generate_variant:Nn \fp_to_tl:N { c } +\cs_new_nopar:Npn \fp_to_tl:n + { + \exp_after:wN \@@_to_tl:w + \tex_romannumeral:D -`0 \@@_parse:n + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP, aux]{\@@_to_tl:w, \@@_to_tl_normal:nnnnn} +% A structure similar to \cs{@@_to_scientific:w} and +% \cs{@@_to_decimal:w}, but without the \enquote{invalid operation} +% exception. First filter special cases. We express normal numbers +% in decimal notation if the exponent is in the range $[-2,16]$, and +% otherwise use scientific notation. The weird \cs{prg_do_nothing:} +% is needed because the \texttt{decimal} and \texttt{scientific} +% auxiliaries we use expect it. +% \begin{macrocode} +\cs_new:Npn \@@_to_tl:w \s_@@ \@@_chk:w #1#2 + { + \if_meaning:w 2 #2 \exp_after:wN - \tex_romannumeral:D -`0 \fi: + \if_case:w #1 \exp_stop_f: + \@@_case_return:nw { 0 } + \or: \exp_after:wN \@@_to_tl_normal:nnnnn + \or: \@@_case_return:nw { inf } + \else: \@@_case_return:nw { nan } + \fi: + } +\cs_new:Npn \@@_to_tl_normal:nnnnn #1#2 ; + { + \if_int_compare:w #1 > \c_sixteen + \exp_after:wN \@@_to_scientific_normal:wnnnnn + \else: + \if_int_compare:w #1 < - \c_two + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_to_scientific_normal:wnnnnn + \else: + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_to_decimal_normal:wnnnnn + \fi: + \fi: + \s_@@ \@@_chk:w 1 0 {#1} #2 ; \prg_do_nothing: + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Formatting} +% +% ^^A todo +% +% \subsection{Convert to dimension or integer} +% +% \begin{macro}[EXP]{\fp_to_dim:N, \fp_to_dim:c, \fp_to_dim:n} +% These three public functions rely on \cs{fp_to_decimal:n} +% internally. +% \begin{macrocode} +\cs_new:Npn \fp_to_dim:N #1 { \fp_to_decimal:N #1 pt } +\cs_generate_variant:Nn \fp_to_dim:N { c } +\cs_new:Npn \fp_to_dim:n #1 { \fp_to_decimal:n {#1} pt } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\fp_to_int:N, \fp_to_int:c, \fp_to_int:n} +% These three public functions evaluate their argument, then pass it +% to \cs{fp_to_int:w}. +% \begin{macrocode} +\cs_new:Npn \fp_to_int:N #1 { \exp_after:wN \@@_to_int:w #1 } +\cs_generate_variant:Nn \fp_to_int:N { c } +\cs_new_nopar:Npn \fp_to_int:n + { + \exp_after:wN \@@_to_int:w + \tex_romannumeral:D -`0 \@@_parse:n + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_to_int:w} +% To convert to an integer, first round to $0$ places (to the nearest +% integer), then express the result as a decimal number: the +% definition of \cs{@@_to_decimal:w} is such that there will be no +% trailing dot nor zero. +% \begin{macrocode} +\cs_new:Npn \@@_to_int:w #1; + { + \exp_after:wN \@@_to_decimal:w \tex_romannumeral:D -`0 + \@@_round:Nwn \@@_round_to_nearest:NNN #1; { 0 } \prg_do_nothing: + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Convert from a dimension} +% +% \begin{macro}[EXP]{\dim_to_fp:n} +% \begin{macro}[aux, EXP] +% { +% \@@_from_dim_test:N, +% \@@_from_dim:Nw, +% \@@_from_dim_ii:wNNnnnnnn, +% \@@_from_dim_iii:wnnnnwN, +% } +% The dimension expression (which can in fact be a glue expression) +% is evaluated, converted to a number (\emph{i.e.}, expressed in +% scaled points), then multiplied by $2^{-16} = 0.0000152587890625$ +% to give a value expressed in points. We use the auxiliary function +% \begin{quote} +% \cs{@@_mul_npos:Nnwnw} \meta{sign} \newline +% ~~\Arg{exp_1} \meta{body_1} |;| \Arg{exp_2} \meta{body_2} |;| +% \end{quote} +% \begin{macrocode} +\cs_new:Npn \dim_to_fp:n #1 + { + \exp_after:wN \@@_from_dim_test:N + \__int_value:w \etex_glueexpr:D #1 ; + } +\cs_new:Npn \@@_from_dim_test:N #1 + { + \if_meaning:w 0 #1 + \exp_after:wN \@@_use_i_until_s:nw + \exp_after:wN \c_zero_fp + \else: + \if_meaning:w - #1 + \exp_after:wN \@@_from_dim:Nw + \exp_after:wN 2 + \__int_value:w + \else: + \exp_after:wN \@@_from_dim:Nw + \exp_after:wN 0 + \__int_value:w #1 + \fi: + \fi: + } +\cs_new:Npn \@@_from_dim:Nw #1 #2; + { + \@@_pack_twice_four:wNNNNNNNN \@@_from_dim_ii:wNNnnnnnn ; + #2 000 0000 00 {10}987654321; #1 + } +\cs_new:Npn \@@_from_dim_ii:wNNnnnnnn #1; #2#3#4#5#6#7#8#9 + { \@@_from_dim_iii:wnnnnwN #1 {#2#300} {0000} ; } +\cs_new:Npn \@@_from_dim_iii:wnnnnwN #1; #2#3#4#5#6; #7 + { + \@@_mul_npos:Nnwnw #7 {#5} #1 ; + {-4} {1525} {8789} {0625} {0000} ; + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Use and eval} +% +% \begin{macro}[EXP]{\fp_use:N, \fp_use:c, \fp_eval:n} +% Those public functions are simple copies of the decimal conversions. +% \begin{macrocode} +\cs_new_eq:NN \fp_use:N \fp_to_decimal:N +\cs_generate_variant:Nn \fp_use:N { c } +\cs_new_eq:NN \fp_eval:n \fp_to_decimal:n +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\fp_abs:n} +% Trivial but useful. +% \begin{macrocode} +\cs_new:Npn \fp_abs:n #1 { \fp_to_decimal:n { abs ( #1 ) } } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file |