diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx | 301 |
1 files changed, 135 insertions, 166 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx index de3bae56fd4..8d2a67dc46e 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-aux.dtx @@ -22,9 +22,8 @@ % %<*driver> \documentclass[full]{l3doc} -\GetIdInfo$Id: l3fp-aux.dtx 6968 2017-02-20 16:08:44Z bruno $ - {L3 Floating-point support functions} -\documentclass[full]{l3doc} +\def\ExplFileDate{2017/03/18} +\def\ExplFileVersion{7019} \begin{document} \DocInput{\jobname.dtx} \end{document} @@ -68,7 +67,6 @@ % % ^^A todo: make sanitize and pack more homogeneous between modules. % -% ^^A begin[todo]: move % \subsection{Internal representation} % % Internally, a floating point number \meta{X} is a @@ -79,25 +77,21 @@ % Let us explain each piece separately. % % Internal floating point numbers will be used in expressions, -% and in this context will be subject to f-expansion. They must +% and in this context will be subject to \texttt{f}-expansion. They must % leave a recognizable mark after \texttt{f}-expansion, to prevent the % floating point number from being re-parsed. Thus, \cs{s_@@} % is simply another name for \tn{relax}. % -% Since floating point numbers are always accessed by the various -% operations using f-expansion, we can safely let them be protected: -% \texttt{x}-expansion will then leave them untouched. However, when -% used directly without an accessor function, floating points should -% produce an error. \cs{s_@@} will do nothing, and \cs{@@_chk:w} -% produces an error. -% -% The (decimal part of the) IEEE-754-2008 standard requires the -% format to be able to represent special floating point numbers -% besides the usual positive and negative cases. The various -% possibilities will be distinguished by their \meta{case}, which -% is a single digit:\footnote{Bruno: I need to implement subnormal -% numbers. Also, quiet and signalling \texttt{nan} must be better -% distinguished.} +% When used directly without an accessor function, floating points +% should produce an error: this is the role of \cs{@@_chk:w}. We could +% make floating point variables be protected to prevent them from +% expanding under \texttt{x}-expansion, but it seems more convenient to +% treat them as a subcase of token list variables. +% +% The (decimal part of the) IEEE-754-2008 standard requires the format +% to be able to represent special floating point numbers besides the +% usual positive and negative cases. We distinguish the various +% possibilities by their \meta{case}, which is a single digit: % \begin{itemize} % \item[0] zeros: |+0| and |-0|, % \item[1] \enquote{normal} numbers (positive and negative), @@ -121,19 +115,16 @@ % \cs{s_@@} \cs{@@_chk:w} 1 \meta{sign} \Arg{exponent} % \Arg{X_1} \Arg{X_2} \Arg{X_3} \Arg{X_4} |;| % \end{quote} -% Here, the \meta{exponent} is an integer, at most -% $\cs{c_@@_max_exponent_int} = -% \the\csname\detokenize{c__fp_max_exponent_int}\endcsname$ -% in absolute value. The body consists in four -% blocks of exactly $4$ digits, $ 0000 \leq \meta{X_i} \leq 9999$, -% such that +% Here, the \meta{exponent} is an integer, between +% $-\ExplSyntaxOn\int_use:N\c__fp_minus_min_exponent_int$ and +% $\ExplSyntaxOn\int_use:N\c__fp_max_exponent_int$. The body consists +% in four blocks of exactly $4$ digits, +% $0000 \leq \meta{X_i} \leq 9999$, and the floating point is % \[ -% \meta{X} -% = (-1)^{\meta{sign}} 10^{-\meta{exponent}} -% \sum_{i=1}^{4} \meta{X_i} 10^{-4i} +% (-1)^{\meta{sign}/2} \meta{X_1}\meta{X_2}\meta{X_3}\meta{X_4}\cdot 10^{\meta{exponent}-16} % \] -% and such that the \meta{exponent} is minimal. This implies -% $ 1000 \leq \meta{X_1} \leq 9999 $. +% where we have concatenated the $16$ digits. Currently, floating point numbers are normalized such that +% the \meta{exponent} is minimal, in other words, $1000 \leq \meta{X_1} \leq 9999$. % % \begin{table}\centering % \caption{Internal representation of floating point numbers.} @@ -156,30 +147,7 @@ % \end{tabular} % \end{table} % -% \subsection{Internal storage of floating points numbers} -% -% A floating point number \meta{X} is stored as -% \begin{quote} -% \cs{s_@@} \cs{@@_chk:w} \meta{case} \meta{sign} \meta{body} |;| -% \end{quote} -% Here, \meta{case} is 0 for $\pm 0$, 1 for normal numbers, 2 for $\pm -% \infty$, and 3 for \texttt{nan}, and \meta{sign} is $0$ for positive -% numbers, $1$ for \texttt{nan}s, and $2$ for negative numbers. The -% \meta{body} of normal numbers is \Arg{exponent} \Arg{X_1} \Arg{X_2} -% \Arg{X_3} \Arg{X_4}, with -% \[ -% \meta{X} = (-1)^{\meta{sign}} 10^{-\meta{exponent}} \sum_i -% \meta{X_i} 10^{-4i}. -% \] -% Calculations are done in base $10000$, \emph{i.e.} one myriad. The -% \meta{exponent} lies between $\pm\cs{c_@@_max_exponent_int} = \pm -% \the\csname\detokenize{c__fp_max_exponent_int}\endcsname$ inclusive. -% -% Additionally, positive and negative floating point numbers may only be -% stored with $1000\leq\meta{X_1}<10000$. This requirement is necessary -% in order to preserve accuracy and speed. -% -% ^^A end[todo] +% Calculations are done in base $10000$, \emph{i.e.} one myriad. % % \subsection{Using arguments and semicolons} % @@ -212,7 +180,6 @@ % \end{macrocode} % \end{macro} % -% ^^A todo: rename to \@@_args_swap:Nww % \begin{macro}[int, EXP]{\@@_reverse_args:Nww} % Many internal functions take arguments delimited by semicolons, and % it is occasionally useful to swap two such arguments. @@ -223,7 +190,7 @@ % % \begin{macro}[int, EXP]{\@@_rrot:www} % Rotate three arguments delimited by semicolons. This is the inverse -% (or the square) of the Forth primitive |ROT|. +% (or the square) of the Forth primitive |ROT|, hence the name. % \begin{macrocode} \cs_new:Npn \@@_rrot:www #1; #2; #3; { #2; #3; #1; } % \end{macrocode} @@ -284,14 +251,7 @@ % % \begin{variable} % {\c_zero_fp, \c_minus_zero_fp, \c_inf_fp, \c_minus_inf_fp, \c_nan_fp} -% The special floating points. All of them have the form -% \begin{quote} -% \cs{s_@@} \cs{@@_chk:w} \meta{case} \meta{sign} \cs[no-index]{s_@@_\ldots} |;| -% \end{quote} -% where the dots in \cs[no-index]{s_@@_\ldots} are one of \texttt{invalid}, -% \texttt{underflow}, \texttt{overflow}, \texttt{division}, -% \texttt{exact}, describing how the floating point was created. We -% define the floating points here as \enquote{exact}. +% The special floating points. We define the floating points here as \enquote{exact}. % \begin{macrocode} \tl_const:Nn \c_zero_fp { \s_@@ \@@_chk:w 0 0 \s_@@_exact ; } \tl_const:Nn \c_minus_zero_fp { \s_@@ \@@_chk:w 0 2 \s_@@_exact ; } @@ -317,20 +277,15 @@ % \end{macrocode} % \end{variable} % -% \begin{variable}[int]{\c_@@_max_exponent_int} -% Normal floating point numbers have an exponent at most -% \texttt{max_exponent} in absolute value. Larger numbers are rounded -% to $\pm\infty$. Smaller numbers are subnormal (not implemented yet), -% and digits beyond -% $10^{-\text{\texttt{max_exponent}}}$ are rounded away, hence the -% true minimum exponent is $-\text{\texttt{max_exponent}}-16$; -% beyond this, numbers are rounded to zero. Why this choice of -% limits? When computing $(a\cdot 10^n)^(b\cdot 10^p)$, we need to -% evaluate $\log(a\cdot 10^n) = \log(a) + n \log(10)$ as a fixed point -% number, which we manipulate as blocks of $4$ digits. Multiplying -% such a fixed point number by $n<10000$ is much cheaper than larger -% $n$, because we can multiply $n$ with each block safely. +% \begin{variable}[int]{\c_@@_minus_min_exponent_int, \c_@@_max_exponent_int} +% Normal floating point numbers have an exponent between $-$ +% \texttt{minus_min_exponent} and \texttt{max_exponent} inclusive. +% Larger numbers are rounded to $\pm\infty$. Smaller numbers are +% rounded to $\pm 0$. It would be more natural to define a +% \texttt{min_exponent} with the opposite sign but that would waste +% one \TeX{} count. % \begin{macrocode} +\int_const:Nn \c_@@_minus_min_exponent_int { 10000 } \int_const:Nn \c_@@_max_exponent_int { 10000 } % \end{macrocode} % \end{variable} @@ -343,6 +298,20 @@ % \end{macrocode} % \end{variable} % +% \begin{variable}{\c_@@_overflowing_fp} +% A floating point number that is bigger than all normal floating +% point numbers. This replaces infinities when converting to formats +% that do not support infinities. +% \begin{macrocode} +\tl_const:Nx \c_@@_overflowing_fp + { + \s_@@ \@@_chk:w 1 0 + { \int_eval:n { \c_@@_max_exponent_int + 1 } } + {1000} {0000} {0000} {0000} ; + } +% \end{macrocode} +% \end{variable} +% % \begin{macro}[int, EXP]{\@@_zero_fp:N, \@@_inf_fp:N} % In case of overflow or underflow, we have to output % a zero or infinity with a given sign. @@ -354,29 +323,9 @@ % \end{macrocode} % \end{macro} % -%^^A todo: currently unused. -% \begin{macro}[int, EXP]{\@@_max_fp:N, \@@_min_fp:N} -% In some cases, we need to output the smallest or biggest positive or -% negative finite numbers. -% \begin{macrocode} -\cs_new:Npn \@@_min_fp:N #1 - { - \s_@@ \@@_chk:w 1 #1 - { \int_eval:n { - \c_@@_max_exponent_int } } - {1000} {0000} {0000} {0000} ; - } -\cs_new:Npn \@@_max_fp:N #1 - { - \s_@@ \@@_chk:w 1 #1 - { \int_use:N \c_@@_max_exponent_int } - {9999} {9999} {9999} {9999} ; - } -% \end{macrocode} -% \end{macro} -% % \begin{macro}[int, EXP]{\@@_exponent:w} % For normal numbers, the function expands to the exponent, otherwise -% to $0$. +% to $0$. This is used in \pkg{l3str-format}. % \begin{macrocode} \cs_new:Npn \@@_exponent:w \s_@@ \@@_chk:w #1 { @@ -416,8 +365,8 @@ { \if_case:w \if_int_compare:w #2 > \c_@@_max_exponent_int 1 ~ \else: - \if_int_compare:w #2 < - \c_@@_max_exponent_int 2 ~ \else: - \if_meaning:w 1 #1 3 ~ \else: 0 ~ \fi: \fi: \fi: + \if_int_compare:w #2 < - \c_@@_minus_min_exponent_int 2 ~ \else: + \if_meaning:w 1 #1 3 ~ \fi: \fi: \fi: 0 ~ \or: \exp_after:wN \@@_overflow:w \or: \exp_after:wN \@@_underflow:w \or: \exp_after:wN \@@_sanitize_zero:w @@ -433,11 +382,11 @@ % % \subsection{Expanding after a floating point number} % -% ^^A todo: maybe delete \cs{@@_exp_after_o:nw}? % \begin{macro}[int, EXP]{\@@_exp_after_o:w} -% \begin{macro}[int, EXP]{\@@_exp_after_o:nw, \@@_exp_after_f:nw} +% \begin{macro}[int, EXP]{\@@_exp_after_f:nw} % \begin{syntax} -% \cs{@@_exp_after_o:nw} \Arg{tokens} \meta{floating point} \meta{more tokens} +% \cs{@@_exp_after_o:w} \meta{floating point} +% \cs{@@_exp_after_f:nw} \Arg{tokens} \meta{floating point} % \end{syntax} % Places \meta{tokens} (empty in the case of \cs{@@_exp_after_o:w}) % between the \meta{floating point} and the \meta{more tokens}, then @@ -458,16 +407,6 @@ { } #1 } -\cs_new:Npn \@@_exp_after_o:nw #1 \s_@@ \@@_chk:w #2 - { - \if_meaning:w 1 #2 - \exp_after:wN \@@_exp_after_normal:nNNw - \else: - \exp_after:wN \@@_exp_after_special:nNNw - \fi: - { #1 } - #2 - } \cs_new:Npn \@@_exp_after_f:nw #1 \s_@@ \@@_chk:w #2 { \if_meaning:w 1 #2 @@ -697,6 +636,58 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}[aux, EXP] +% { +% \@@_basics_pack_low:NNNNNw, +% \@@_basics_pack_high:NNNNNw, +% \@@_basics_pack_high_carry:w +% } +% Addition and multiplication of significands are done in two steps: +% first compute a (more or less) exact result, then round and pack +% digits in the final (braced) form. These functions take care of the +% packing, with special attention given to the case where rounding has +% caused a carry. Since rounding can only shift the final digit by +% $1$, a carry always produces an exact power of $10$. Thus, +% \cs{@@_basics_pack_high_carry:w} is always followed by four times +% |{0000}|. +% +% This is used in \pkg{l3fp-basics} and \pkg{l3fp-extended}. +% \begin{macrocode} +\cs_new:Npn \@@_basics_pack_low:NNNNNw #1 #2#3#4#5 #6; + { + #1 - 1 ; {#2#3#4#5} {#6} ; } +\cs_new:Npn \@@_basics_pack_high:NNNNNw #1 #2#3#4#5 #6; + { + \if_meaning:w 2 #1 + \@@_basics_pack_high_carry:w + \fi: + ; {#2#3#4#5} {#6} + } +\cs_new:Npn \@@_basics_pack_high_carry:w \fi: ; #1 + { \fi: + 1 ; {1000} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP] +% { +% \@@_basics_pack_weird_low:NNNNw, +% \@@_basics_pack_weird_high:NNNNNNNNw +% } +% This is used in \pkg{l3fp-basics} for additions and +% divisions. Their syntax is confusing, hence the name. +% \begin{macrocode} +\cs_new:Npn \@@_basics_pack_weird_low:NNNNw #1 #2#3#4 #5; + { + \if_meaning:w 2 #1 + + 1 + \fi: + \__int_eval_end: + #2#3#4; {#5} ; + } +\cs_new:Npn \@@_basics_pack_weird_high:NNNNNNNNw + 1 #1#2#3#4 #5#6#7#8 #9; { ; {#1#2#3#4} {#5#6#7#8} {#9} } +% \end{macrocode} +% \end{macro} +% % \subsection{Decimate (dividing by a power of 10)} % % ^^A begin[todo] @@ -711,7 +702,7 @@ % \begin{syntax} % \meta{f_1} \meta{rounding} \Arg{X'_1} \Arg{X'_2} \meta{extra-digits} |;| % \end{syntax} -% where $0\leq\meta{X'_i}<10^{8}-1$ are $8$ digit numbers, +% where $0\leq\meta{X'_i}<10^{8}-1$ are $8$ digit integers, % forming the truncation of our number. In other words, % \[ % \left( @@ -727,15 +718,15 @@ % is the (non-$0$, non-$5$) digit closest to $10^{17}$ times the % difference. In particular, if the shift is $17$ or more, all % the digits are dropped, \meta{rounding} is $1$ (not $0$), and -% \meta{X'_1} \meta{X'_2} are both zero. +% \meta{X'_1} and \meta{X'_2} are both zero. % % If the shift is $1$, the \meta{rounding} digit is simply the % only digit that was pushed out of the brace groups (this is % important for subtraction). It would be more natural for the -% \meta{rounding} digit to be placed after the \meta{X_i}, +% \meta{rounding} digit to be placed after the \meta{X'_i}, % but the choice we make involves less reshuffling. % -% Note that this function fails for negative \meta{shift}. +% Note that this function treats negative \meta{shift} as $0$. % \begin{macrocode} \cs_new:Npn \@@_decimate:nNnnnn #1 { @@ -939,39 +930,28 @@ % \subsection{Integer floating points} % % \begin{macro}[int, EXP, pTF]{\@@_int:w} -% \begin{macro}[aux, EXP]{\@@_int_normal:nnnnn, \@@_int_test:Nw} -% Tests if the floating point argument is an integer. This holds if -% the rounding digit resulting from \cs{@@_decimate:nNnnnn} is~$0$. +% Tests if the floating point argument is an integer. For normal +% floating point numbers, this holds if the rounding digit resulting +% from \cs{@@_decimate:nNnnnn} is~$0$. % \begin{macrocode} -\prg_new_conditional:Npnn \@@_int:w \s_@@ \@@_chk:w #1 #2 #3; { TF , T , F , p } +\prg_new_conditional:Npnn \@@_int:w \s_@@ \@@_chk:w #1 #2 #3 #4; + { TF , T , F , p } { \if_case:w #1 \exp_stop_f: \prg_return_true: - \or: \@@_int_normal:nnnnn #3 + \or: + \if_charcode:w 0 + \@@_decimate:nNnnnn { \c_@@_prec_int - #3 } + \@@_use_i_until_s:nw #4 + \prg_return_true: + \else: + \prg_return_false: + \fi: \else: \prg_return_false: \fi: } -\cs_new:Npn \@@_int_normal:nnnnn #1 #2#3#4#5 - { - \if_int_compare:w #1 > 0 \exp_stop_f: - \@@_decimate:nNnnnn { \c_@@_prec_int - #1 } - \@@_int_test:Nw - {#2} {#3} {#4} {#5} - \else: - \prg_return_false: - \fi: - } -\cs_new:Npn \@@_int_test:Nw #1#2; - { - \if_meaning:w 0 #1 - \prg_return_true: - \else: - \prg_return_false: - \fi: - } % \end{macrocode} % \end{macro} -% \end{macro} % % \subsection{Small integer floating points} % @@ -985,20 +965,13 @@ % Tests if the floating point argument is an integer or $\pm\infty$. % If so, it is converted to an integer in the range $[-10^{8},10^{8}]$ % and fed as a braced argument to the \meta{true code}. -% Otherwise, the \meta{false code} is performed. First filter special -% cases: neither \texttt{nan} nor infinities are integers. Normal -% numbers with a non-positive exponent are never integers. When the -% exponent is greater than $8$, the number is too large for the range. -% Otherwise, decimate, and test the digits after the decimal -% separator. The \cs{use_iii:nnn} remove a trailing |;| and the true -% branch, leaving only the false branch. The \cs{__int_value:w} -% appearing in the case where the normal floating point is an integer -% takes care of expanding all the conditionals until the trailing |;|. -% That integer is fed to \cs{@@_small_int_true:wTF} which places it as -% a braced argument of the true branch. The \cs{use_i:nn} in -% \cs{@@_small_int_test:NnnwNTF} removes the top-level \cs{else:} -% coming from \cs{@@_small_int_normal:NnwTF}, hence will call the -% \cs{use_iii:nnn} which follows, taking the false branch. +% Otherwise, the \meta{false code} is performed. +% +% First filter special cases: zeros and infinities are integers, +% \texttt{nan} is not. For normal numbers, decimate. If the rounding +% digit is not $0$ run the \meta{false code}. If it is, then the +% integer is |#2| |#3|; use |#3| if |#2| vanishes and otherwise +% $10^{8}$. % \begin{macrocode} \cs_new:Npn \@@_small_int:wTF \s_@@ \@@_chk:w #1#2 { @@ -1018,27 +991,23 @@ \cs_new:Npn \@@_small_int_true:wTF #1; #2#3 { #2 {#1} } \cs_new:Npn \@@_small_int_normal:NnwTF #1#2#3; { - \if_int_compare:w #2 > 0 \exp_stop_f: - \@@_decimate:nNnnnn { \c_@@_prec_int - #2 } - \@@_small_int_test:NnnwNnw - #3 #1 {#2} - \else: - \exp_after:wN \use_iii:nnn - \fi: - ; + \@@_decimate:nNnnnn { \c_@@_prec_int - #2 } + \@@_small_int_test:NnnwNw + #3 #1 } -\cs_new:Npn \@@_small_int_test:NnnwNnw #1#2#3#4; #5#6 +\cs_new:Npn \@@_small_int_test:NnnwNw #1#2#3#4; #5 { \if_meaning:w 0 #1 \exp_after:wN \@@_small_int_true:wTF \__int_value:w \if_meaning:w 2 #5 - \fi: - \if_int_compare:w #6 > \c_@@_half_prec_int + \if_int_compare:w #2 > 0 \exp_stop_f: 1 0000 0000 \else: #3 \fi: + \exp_after:wN ; \else: - \use_i:nn + \exp_after:wN \use_ii:nn \fi: } % \end{macrocode} |