summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2012-07-23 17:15:00 +0000
committerKarl Berry <karl@freefriends.org>2012-07-23 17:15:00 +0000
commit134349701bddf7cbbacf6030c6b9f9838aff96fa (patch)
treeec1140c46e1c0347a671a6fa3cf8af5a79e95f93 /Master/texmf-dist/source/latex/l3kernel/l3fp-convert.dtx
parentf7855c12c18bb97b7b9e49ab685ee558d8c0b47b (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.dtx476
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