diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx | 581 |
1 files changed, 581 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx new file mode 100644 index 00000000000..16a3fb465f6 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-trig.dtx @@ -0,0 +1,581 @@ +% \iffalse meta-comment +% +%% File: l3fp-trig.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-trig.dtx 3514 2012-03-08 06:14:48Z bruno $ + {L3 Floating-point trigonometric functions} +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3fp-trig} package\thanks{This file +% has version number \ExplFileVersion, last +% revised \ExplFileDate.}\\ +% Floating point trigonometric functions} +% \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{Implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<@@=fp> +% \end{macrocode} +% +%^^A todo: check EXP/rEXP everywhere. +% +% \subsection{Inverting a floating point number} +% +% \begin{macro}[int, EXP]{\@@_one_over:w} +% Expects a floating point of the form \cs{s_@@} \ldots{} |;| and +% computes its multiplicative inverse. This is used to compute the +% cotangent function very near $0$. +% \begin{macrocode} +\cs_new_nopar:Npx \@@_one_over:w + { + \exp_not:N \exp_after:wN + \exp_not:c { @@_/_o:ww } + \exp_not:N \c_one_fp + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Direct trigonometric functions} +% +% The approach for all trigonometric functions (sine, cosine, tangent, +% and cotangent) is the same. +% \begin{itemize} +% \item Filter out special cases ($\pm 0$, $\pm\inf$ and \nan{}). +% \item Keep the sign for later, and work with the absolute value $|x|$ +% of the argument. +% \item For numbers less than $1$, shift the mantissa to convert them to +% fixed point numbers. Very small numbers take a slightly different +% route. +% \item For numbers $\geq 1$, subtract a multiple of $\pi/2$ to bring +% them to the range to $[0, \pi/2]$. +% \item Reduce further to $[0, \pi/4]$ using $\sin x = \cos (\pi/2-x)$. +% \item Use the appropriate power series depending on the octant +% $\lfloor\frac{|x|}{\pi/4}\rfloor \mod 8$, the sign, and the function +% to compute. +% \end{itemize} +% +% \subsubsection{Sign and special numbers} +% +% \begin{macro}[int, EXP]{\@@_sin:w} +% The sine of $\pm 0$ or \nan{} is the same floating point number. +% The sine of $\pm\infty$ raises an invalid operation exception. +% Otherwise, check the exponent, preparing to use +% \cs{@@_sin_series:NNwww} for the calculation, with a sign |#2|, and +% an initial octant of $0$. The question mark is an argument which is +% not used in this case. +% \begin{macrocode} +\cs_new:Npn \@@_sin:w \s_@@ \@@_chk:w #1#2 + { + \if_case:w #1 \exp_stop_f: + \@@_case_return_same_o:w + \or: + \exp_after:wN \@@_trig_exponent:NNNNwn + \exp_after:wN \@@_sin_series:NNwww + \exp_after:wN ? + \exp_after:wN #2 + \exp_after:wN \c_zero + \or: + \@@_case_use:nw + { \@@_invalid_operation:Nnw \c_nan_fp { sin } } + \else: \@@_case_return_same_o:w + \fi: + \s_@@ \@@_chk:w #1#2 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_cos:w} +% The cosine of $\pm 0$ is $1$. The cosine of $\pm\infty$ raises an +% invalid operation exception. The cosine of \nan{} is itself. +% Otherwise, check the exponent, preparing to use +% \cs{@@_sin_series:NNwww} for the calculation, with a positive sign +% ($0$), and an initial octant of $2$, because $\cos x = \sin ( \pi/2 +% + |x|)$. The question mark is an argument which is not used in this +% case. +% \begin{macrocode} +\cs_new:Npn \@@_cos:w \s_@@ \@@_chk:w #1#2 + { + \if_case:w #1 \exp_stop_f: + \@@_case_return_o:Nw \c_one_fp + \or: + \@@_case_use:nw %^^A todo: is that faster than the exp_after route? + { + \@@_trig_exponent:NNNNwn + \@@_sin_series:NNwww + ? + 0 + \c_two + } + \or: + \@@_case_use:nw + { \@@_invalid_operation:Nnw \c_nan_fp { cos } } + \else: \@@_case_return_same_o:w + \fi: + \s_@@ \@@_chk:w #1#2 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_tan:w} +% The tangent of $\pm 0$ or \nan{} is the same floating point number. +% The tangent of $\pm\infty$ raises an invalid operation exception. +% Otherwise, check the exponent, preparing to use +% \cs{@@_tan_series:NNwww} for the calculation, with a positive sign +% ($0$), and an initial octant of $1$, chosen to be distinct from the +% octants for sine and cosine. See \cs{@@_cot:w} for an +% explanation of the $0$ argument. +% \begin{macrocode} +\cs_new:Npn \@@_tan:w \s_@@ \@@_chk:w #1#2 + { + \if_case:w #1 \exp_stop_f: + \@@_case_return_same_o:w + \or: + \exp_after:wN \@@_trig_exponent:NNNNwn + \exp_after:wN \@@_tan_series:NNwww + \exp_after:wN 0 + \exp_after:wN #2 + \exp_after:wN \c_one + \or: + \@@_case_use:nw + { \@@_invalid_operation:Nnw \c_nan_fp { tan } } + \else: \@@_case_return_same_o:w + \fi: + \s_@@ \@@_chk:w #1#2 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int, EXP]{\@@_cot:w} +% The cotangent of $\pm 0$ is $\pm \infty$ with the same sign, +% produced by \cs{@@_one_over:w}. The cotangent of $\pm\infty$ raises +% an invalid operation exception. The cotangent of \nan{} is itself. +% We use $\cot x = - \tan (\pi/2 + x)$, and the initial octant for the +% tangent was chosen to be $1$, so the octant here starts at $3$. The +% change in sign is obtained by feeding \cs{@@_tan_series:NNwww} two +% signs rather than just the sign of the argument: the first of those +% indicates whether we compute tangent or cotangent. Those signs are +% eventually combined. +% \begin{macrocode} +\cs_new:Npn \@@_cot:w \s_@@ \@@_chk:w #1#2 + { + \if_case:w #1 \exp_stop_f: + \exp_after:wN \@@_one_over:w + \or: + \exp_after:wN \@@_trig_exponent:NNNNwn + \exp_after:wN \@@_tan_series:NNwww + \exp_after:wN 2 + \exp_after:wN #2 + \exp_after:wN \c_three + \or: + \@@_case_use:nw + { \@@_invalid_operation:Nnw \c_nan_fp { cot } } + \else: \@@_case_return_same_o:w + \fi: + \s_@@ \@@_chk:w #1#2 + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Small and tiny arguments} +% +% \begin{macro}[aux, EXP]{\@@_trig_exponent:NNNNwn} +% The first four arguments control what trigonometric function we +% compute, then follows a normal floating point number. If the +% floating point is smaller than $10^{-8}$, then call the appropriate +% \texttt{_epsilon} auxiliary. Otherwise, call the function |#1|, +% with arguments |#2|, |#3|, the octant, computed in an integer +% expression starting with |#4|, and a fixed point number obtained +% from the floating point number by argument reduction. Numbers less +% than $1$ are converted using \cs{@@_trig_small:w} which simply +% shifts the mantissa, while large numbers need argument reduction. +% \begin{macrocode} +\cs_new:Npn \@@_trig_exponent:NNNNwn #1#2#3#4 \s_@@ \@@_chk:w 1#5#6 + { + \if_int_compare:w #6 > - \c_eight + \exp_after:wN #1 + \exp_after:wN #2 + \exp_after:wN #3 + \int_use:N \__int_eval:w #4 + \if_int_compare:w #6 > \c_zero + \exp_after:wN \@@_trig_large:w \__int_value:w + \else: + \exp_after:wN \@@_trig_small:w \__int_value:w + \fi: + \else: + \if_case:w #4 + \@@_sin_epsilon:w + \or: \@@_sin_epsilon:w + \or: \@@_cos_epsilon:w + \else: \@@_cot_epsilon:w + \fi: + #5 + \fi: + #6 ; + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP] +% {\@@_sin_epsilon:w, \@@_cos_epsilon:w, \@@_cot_epsilon:w} +% Sine and tangent of tiny numbers give the number itself: the +% relative error is less than $5 \cdot 10^{-17}$, which is +% appropriate. Cosine simply gives $1$. Cotangent computes the +% inverse. This is actually slightly wrong because further terms in +% the power series could affect the rounding for cotangent. +% \begin{macrocode} +\cs_new:Npn \@@_sin_epsilon:w #1 \fi: #2 \fi: #3 ; + { \fi: \fi: \@@_exp_after_o:w \s_@@ \@@_chk:w 1 #2 {#3} } +\cs_new:Npn \@@_cos_epsilon:w #1 \fi: #2 \fi: #3 ; #4 ; + { \fi: \fi: \exp_after:wN \c_one_fp } +\cs_new:Npn \@@_cot_epsilon:w \fi: #1 \fi: #2 ; + { \fi: \fi: \@@_one_over:w \s_@@ \@@_chk:w 1 #1 {#2} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_trig_small:w, \@@_trig_small_aux:wwNN} +% Floating point numbers less than $1$ are converted to fixed point +% numbers by shifting the mantissa. Since we have already filtered +% out numbers less than $10^{-8}$, no digit is lost in converting to +% a fixed point number. +% \begin{macrocode} +\cs_new:Npn \@@_trig_small:w #1; + { + \exp_after:wN \exp_after:wN \exp_after:wN \@@_trig_small_aux:wwNN + \prg_replicate:nn { - #1 } { 0 } ; + } +\cs_new:Npn \@@_trig_small_aux:wwNN #1; #2#3#4#5; + { + \@@_pack_twice_four:wNNNNNNNN + \@@_pack_twice_four:wNNNNNNNN + \@@_pack_twice_four:wNNNNNNNN + . + ; + #1#2#3#4#5 0000 0000; + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Reduction of large arguments} +% +% In the case of a floating point argument greater or equal to $1$, we +% need to perform argument reduction. +% +% \begin{macro}[aux, rEXP] +% { +% \@@_trig_large:w, \@@_trig_large_i:www, +% \@@_trig_large_ii:wnnnnnn, \@@_trig_large_break:w +% } +% We shift the mantissa by one digit at a time, subtracting a multiple +% of $2\pi$ at each step. We use a value of $2\pi$ rounded up, +% consistent with the choice of \cs{c_pi_fp}. This is not quite +% correct from an accuracy perspective, but has the nice property that +% $\sin(180\mathrm{deg}) = 0$ exactly. The arguments of +% \cs{@@_trig_large_i:www} are a leading block of up to $5$ digits, +% three brace groups of $4$ digits each, and the exponent, decremented +% at each step. The multiple of $2\pi$ to subtract is estimated as +% $\lfloor |#1| / 6283\rfloor$ (the formula chosen always gives a +% non-negative integer). The subtraction has a form similar to our +% usual multiplications (see \pkg{l3fp-basics} or +% \pkg{l3fp-extended}). Once the exponent reaches $0$, we are done +% subtracting $2\pi$, and we call \cs{@@_trig_octant_loop:nw} to do +% the reduction by $\pi/2$. +% \begin{macrocode} +\cs_new:Npn \@@_trig_large:w #1; #2#3; + { \@@_trig_large_i:www #2; #3 ; #1; } +\cs_new:Npn \@@_trig_large_i:www #1; #2; #3; + { + \if_meaning:w 0 #3 \@@_trig_large_break:w \fi: + \exp_after:wN \@@_trig_large_ii:wnnnnnn + \int_use:N \__int_eval:w ( #1 - 3141 ) / 6283 ; + {#1} #2; + \int_use:N \__int_eval:w \c_minus_one + #3; + } +\cs_new:Npn \@@_trig_large_ii:wnnnnnn #1; #2#3#4#5; + { + \exp_after:wN \@@_trig_large_i:www + \int_use:N \__int_eval:w -5 0000 + #20 - #1*62831 + \exp_after:wN \@@_fixed_mul_pack:NNNNNw + \int_use:N \__int_eval:w 4 9995 0000 + #30 - #1*8530 + \exp_after:wN \@@_fixed_mul_pack:NNNNNw + \int_use:N \__int_eval:w 4 9995 0000 + #40 - #1*7179 + \exp_after:wN \@@_fixed_mul_pack:NNNNNw + \int_use:N \__int_eval:w 5 0000 0000 + #50 - #1*5880 + \exp_after:wN ; + \exp_after:wN ; + } +\cs_new:Npn \@@_trig_large_break:w \fi: #1; #2; + { \fi: \@@_trig_octant_loop:nw #2 {0000} {0000} ; } +% \end{macrocode} +% \end{macro} +% +%^^A todo: optimize: we don't need 6x4 digits here, only 4x4. +% +% \begin{macro}[aux, rEXP] +% { +% \@@_trig_octant_loop:nw, \@@_trig_octant_break:w, +% \@@_trig_octant_neg:w +% } +% We receive a fixed point number as argument. As long as it is +% greater than $1.5707$ (a slight underestimate of $\pi/2$), subtract +% $\pi/2$, and leave |+ \c_two| in the integer expression for the +% octant. Once it becomes smaller, if it is greater than $0.7854$ +% (overestimate of $\pi/4$), then compute $\pi/2 - x$ and increment +% the octant. If it is negative, correct this by changing the sign +% and decrementing the octant (by adding $7$). The result is in all +% cases in the range $[0, 0.7854]$, appropriate for a series +% expansion. +% \begin{macrocode} +\cs_new:Npn \@@_trig_octant_loop:nw #1#2; + { + \if_int_compare:w #1 < 15707 \exp_stop_f: + \@@_trig_octant_break:w + \fi: + + \c_two + \@@_fixed_sub_back:wwN + {15707} {9632} {6794} {8970} {0000} {0000} ; + {#1} #2; + \@@_trig_octant_loop:nw + } +\cs_new:Npn \@@_trig_octant_break:w #1 \fi: + #2#3 #4; #5#6; #7; + { + \fi: + \if_int_compare:w #5 < 7854 \exp_stop_f: + \if_int_compare:w #5 < \c_zero + \exp_after:wN \@@_trig_octant_neg:w + \fi: + \exp_after:wN \@@_use_i_until_s:nw + \exp_after:wN . + \fi: + + \c_one + \@@_fixed_sub:wwN + {15707} {9632} {6794} {8970} {0000} {0000} ; + {#5} #6 ; . ; + } +\cs_new:Npn \@@_trig_octant_neg:w #1\fi: #2; #3#4#5#6#7#8; #9 + { + \fi: + + \c_seven + \exp_after:wN \@@_fixed_add_after:NNNNNwN + \int_use:N \__int_eval:w 1 9999 9998 - #30000 - #4 + \exp_after:wN \@@_fixed_add_pack:NNNNNwN + \int_use:N \__int_eval:w 1 9999 9998 - #5#6 + \exp_after:wN \@@_fixed_add_pack:NNNNNwN + \int_use:N \__int_eval:w 2 0000 0000 - #7#8 ; {#9} ; + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Computing the power series} +% +% \begin{macro}[aux, EXP]{\@@_sin_series:NNwww, \@@_sin_series_aux:Nnww} +% Here we receive an unused |?|, a \meta{sign} ($0$ or $2$), a +% (non-negative) \meta{octant} delimited by a dot, a \meta{fixed +% point} number, and junk delimited by a semicolon. The auxiliary +% receives: +% \begin{itemize} +% \item The final sign, which depends on the octant |#3| and the +% original sign |#2|, +% \item The octant |#3|, which will control the series we use. +% \item The square |#4 * #4| of the argument, computed with +% \cs{@@_fixed_mul:wwn}. +% \item The number itself. +% \end{itemize} +% If the octant is in $\{1,2,5,6,\ldots{}\}$, we are near an extremum +% of the function and we use the series +% \[ +% \cos(x) = 1 - x^2 \bigg( \frac{1}{2!} - x^2 \bigg( \frac{1}{4!} +% - x^2 \bigg( \cdots \bigg) \bigg) \bigg) . +% \] +% Otherwise, the series +% \[ +% \sin(x) = x \bigg( 1 - x^2 \bigg( \frac{1}{3!} - x^2 \bigg( +% \frac{1}{5!} - x^2 \bigg( \cdots \bigg) \bigg) \bigg) \bigg) +% \] +% is used. Finally, the fixed point number is converted to a floating +% point number with the given sign, and we check for overflow or +% underflow. %^^A todo: can over/underflow really happen?? +% \begin{macrocode} +\cs_new:Npn \@@_sin_series:NNwww #1#2#3 . #4; #5; + { + \@@_fixed_mul:wwn #4; #4; + { + \exp_after:wN \@@_sin_series_aux:Nnww + \__int_value:w + \if_int_odd:w \__int_eval:w ( #3 + \c_two ) / \c_four \__int_eval_end: + #2 + \else: + \if_meaning:w #2 0 2 \else: 0 \fi: + \fi: + {#3} + } + #4 ; + } +\cs_new:Npn \@@_sin_series_aux:Nnww #1#2 #3; #4; + { + \if_int_odd:w \__int_eval:w #2 / \c_two \__int_eval_end: + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: + { + \@@_fixed_continue:wn {0000}{0000}{0000}{0001}{5619}{2070}; % 1/18! + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0000}{0000}{0477}{9477}{3324}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0000}{0011}{4707}{4559}{7730}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0000}{2087}{6756}{9878}{6810}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0027}{5573}{1922}{3985}{8907}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{2480}{1587}{3015}{8730}{1587}; + \@@_fixed_mul_sub_back:wwwn #3; {0013}{8888}{8888}{8888}{8888}{8889}; + \@@_fixed_mul_sub_back:wwwn #3; {0416}{6666}{6666}{6666}{6666}{6667}; + \@@_fixed_mul_sub_back:wwwn #3; {5000}{0000}{0000}{0000}{0000}{0000}; + \@@_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000}; + } + { + \@@_fixed_continue:wn {0000}{0000}{0000}{0028}{1145}{7254}; % 1/17! + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0000}{0000}{7647}{1637}{3182}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0000}{0160}{5904}{3836}{8216}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0002}{5052}{1083}{8544}{1719}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0275}{5731}{9223}{9858}{9065}; + \@@_fixed_mul_sub_back:wwwn #3; {0001}{9841}{2698}{4126}{9841}{2698}; + \@@_fixed_mul_sub_back:wwwn #3; {0083}{3333}{3333}{3333}{3333}{3333}; + \@@_fixed_mul_sub_back:wwwn #3; {1666}{6666}{6666}{6666}{6666}{6667}; + \@@_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000}; + \@@_fixed_mul:wwn #4; + } + { + \exp_after:wN \@@_sanitize:Nw + \exp_after:wN #1 + \int_use:N \__int_eval:w \@@_fixed_to_float:wN + } + #1 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux, EXP]{\@@_tan_series:NNwww, \@@_tan_series_aux:Nnww} +% Similar to \cs{@@_sin_series:NNwww}, but with slightly different +% rules to find the sign. The result is expressed as a ratio of +% polynomials, of the form +% \[ +% \tan(x) \simeq +% \frac{x (1 - x^2 (a_1 - x^2 (a_2 - x^2 (a_3 - x^2 (a_4 - x^2 a_5)))))} +% {1 - x^2 (b_1 - x^2 (b_2 - x^2 (b_3 - x^2 (b_4 - x^2 b_5))))} . +% \] +% The ratio of the two fixed point numbers is converted to a floating +% point number directly to avoid rounding issues. The two fixed +% points may be exchanged before computing the ratio, depending on the +% quadrant. +% \begin{macrocode} +\cs_new:Npn \@@_tan_series:NNwww #1#2#3. #4; #5; + { + \@@_fixed_mul:wwn #4; #4; + { + \exp_after:wN \@@_tan_series_aux:Nnww + \__int_value:w + \if_int_odd:w \__int_eval:w #3 / \c_two \__int_eval_end: + \exp_after:wN \reverse_if:N + \fi: + \if_meaning:w #1#2 2 \else: 0 \fi: + {#3} + } + #4 ; + } +\cs_new:Npn \@@_tan_series_aux:Nnww #1 #2 #3; #4; + { + \@@_fixed_continue:wn {0000}{0000}{1527}{3493}{0856}{7059}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{0159}{6080}{0274}{5257}{6472}; + \@@_fixed_mul_sub_back:wwwn #3; {0002}{4571}{2320}{0157}{2558}{8481}; + \@@_fixed_mul_sub_back:wwwn #3; {0115}{5830}{7533}{5397}{3168}{2147}; + \@@_fixed_mul_sub_back:wwwn #3; {1929}{8245}{6140}{3508}{7719}{2982}; + \@@_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000}; + \@@_fixed_mul:wwn #4; + { + \@@_fixed_continue:wn {0000}{0007}{0258}{0681}{9408}{4706}; + \@@_fixed_mul_sub_back:wwwn #3; {0000}{2343}{7175}{1399}{6151}{7670}; + \@@_fixed_mul_sub_back:wwwn #3; {0019}{2638}{4588}{9232}{8861}{3691}; + \@@_fixed_mul_sub_back:wwwn #3; {0536}{6357}{0691}{4344}{6852}{4252}; + \@@_fixed_mul_sub_back:wwwn #3; {5263}{1578}{9473}{6842}{1052}{6315}; + \@@_fixed_mul_sub_back:wwwn #3;{10000}{0000}{0000}{0000}{0000}{0000}; + { + \exp_after:wN \@@_sanitize:Nw + \exp_after:wN #1 + \int_use:N \__int_eval:w + \reverse_if:N \if_int_odd:w + \__int_eval:w (#2 - \c_one) / \c_two \__int_eval_end: + \exp_after:wN \@@_reverse_args:Nww + \fi: + \@@_fixed_div_to_float:ww + } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex
\ No newline at end of file |