summaryrefslogtreecommitdiff
path: root/macros/latex/required/l3kernel/l3fp-assign.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/required/l3kernel/l3fp-assign.dtx')
-rw-r--r--macros/latex/required/l3kernel/l3fp-assign.dtx316
1 files changed, 316 insertions, 0 deletions
diff --git a/macros/latex/required/l3kernel/l3fp-assign.dtx b/macros/latex/required/l3kernel/l3fp-assign.dtx
new file mode 100644
index 0000000000..d54f092085
--- /dev/null
+++ b/macros/latex/required/l3kernel/l3fp-assign.dtx
@@ -0,0 +1,316 @@
+% \iffalse meta-comment
+%
+%% File: l3fp-assign.dtx
+%
+% Copyright (C) 2011-2024 The LaTeX 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
+%
+% https://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 development version of the bundle can be found at
+%
+% https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\documentclass[full,kernel]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3fp-assign} module\\
+% Floating point expressions^^A
+% }
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+% \date{Released 2024-04-11}
+% \maketitle
+%
+% \begin{documentation}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3fp-assign} implementation}
+%
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=fp>
+% \end{macrocode}
+%
+% \subsection{Assigning values}
+%
+% \begin{macro}{\fp_new:N}
+% Floating point variables are initialized to be $+0$.
+% \begin{macrocode}
+\cs_new_protected:Npn \fp_new:N #1
+ { \cs_new_eq:NN #1 \c_zero_fp }
+\cs_generate_variant:Nn \fp_new:N {c}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \fp_set:Nn, \fp_set:cn,
+% \fp_gset:Nn, \fp_gset:cn,
+% \fp_const:Nn, \fp_const:cn
+% }
+% Simply use \cs{@@_parse:n} within various \texttt{f}-expanding
+% assignments.
+% \begin{macrocode}
+\cs_new_protected:Npn \fp_set:Nn #1#2
+ { \__kernel_tl_set:Nx #1 { \exp_not:f { \@@_parse:n {#2} } } }
+\cs_new_protected:Npn \fp_gset:Nn #1#2
+ { \__kernel_tl_gset:Nx #1 { \exp_not:f { \@@_parse:n {#2} } } }
+\cs_new_protected:Npn \fp_const:Nn #1#2
+ { \tl_const:Ne #1 { \exp_not:f { \@@_parse:n {#2} } } }
+\cs_generate_variant:Nn \fp_set:Nn {c}
+\cs_generate_variant:Nn \fp_gset:Nn {c}
+\cs_generate_variant:Nn \fp_const:Nn {c}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \fp_set_eq:NN , \fp_set_eq:cN , \fp_set_eq:Nc , \fp_set_eq:cc,
+% \fp_gset_eq:NN, \fp_gset_eq:cN, \fp_gset_eq:Nc, \fp_gset_eq:cc
+% }
+% Copying a floating point is the same as copying the underlying token
+% list.
+% \begin{macrocode}
+\cs_new_eq:NN \fp_set_eq:NN \tl_set_eq:NN
+\cs_new_eq:NN \fp_gset_eq:NN \tl_gset_eq:NN
+\cs_generate_variant:Nn \fp_set_eq:NN { c , Nc , cc }
+\cs_generate_variant:Nn \fp_gset_eq:NN { c , Nc , cc }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\fp_zero:N, \fp_zero:c, \fp_gzero:N, \fp_gzero:c}
+% Setting a floating point to zero: copy \cs{c_zero_fp}.
+% \begin{macrocode}
+\cs_new_protected:Npn \fp_zero:N #1 { \fp_set_eq:NN #1 \c_zero_fp }
+\cs_new_protected:Npn \fp_gzero:N #1 { \fp_gset_eq:NN #1 \c_zero_fp }
+\cs_generate_variant:Nn \fp_zero:N { c }
+\cs_generate_variant:Nn \fp_gzero:N { c }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {\fp_zero_new:N, \fp_zero_new:c, \fp_gzero_new:N, \fp_gzero_new:c}
+% Set the floating point to zero, or define it if needed.
+% \begin{macrocode}
+\cs_new_protected:Npn \fp_zero_new:N #1
+ { \fp_if_exist:NTF #1 { \fp_zero:N #1 } { \fp_new:N #1 } }
+\cs_new_protected:Npn \fp_gzero_new:N #1
+ { \fp_if_exist:NTF #1 { \fp_gzero:N #1 } { \fp_new:N #1 } }
+\cs_generate_variant:Nn \fp_zero_new:N { c }
+\cs_generate_variant:Nn \fp_gzero_new:N { c }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Updating values}
+%
+% These match the equivalent functions in \pkg{l3int} and \pkg{l3skip}.
+%
+% \begin{macro}
+% {
+% \fp_add:Nn, \fp_add:cn, \fp_gadd:Nn, \fp_gadd:cn,
+% \fp_sub:Nn, \fp_sub:cn, \fp_gsub:Nn, \fp_gsub:cn,
+% }
+% \begin{macro}{\@@_add:NNNn}
+% For the sake of error recovery we should not simply set |#1| to
+% $|#1| \pm (|#2|)$: for instance, if |#2| is % ^^A(
+% |0)+2|, the parsing error would be raised at the last closing
+% parenthesis rather than at the closing parenthesis in the user
+% argument. Thus we evaluate |#2| instead of just putting
+% parentheses. As an optimization we use \cs{@@_parse:n} rather than
+% \cs{fp_eval:n}, which would convert the result away from the
+% internal representation and back.
+% \begin{macrocode}
+\cs_new_protected:Npn \fp_add:Nn { \@@_add:NNNn \fp_set:Nn + }
+\cs_new_protected:Npn \fp_gadd:Nn { \@@_add:NNNn \fp_gset:Nn + }
+\cs_new_protected:Npn \fp_sub:Nn { \@@_add:NNNn \fp_set:Nn - }
+\cs_new_protected:Npn \fp_gsub:Nn { \@@_add:NNNn \fp_gset:Nn - }
+\cs_new_protected:Npn \@@_add:NNNn #1#2#3#4
+ { #1 #3 { #3 #2 \@@_parse:n {#4} } }
+\cs_generate_variant:Nn \fp_add:Nn { c }
+\cs_generate_variant:Nn \fp_gadd:Nn { c }
+\cs_generate_variant:Nn \fp_sub:Nn { c }
+\cs_generate_variant:Nn \fp_gsub:Nn { c }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Showing values}
+%
+% \begin{macro}{\fp_show:N, \fp_show:c, \fp_log:N, \fp_log:c, \@@_show:NN}
+% This shows the result of computing its argument by
+% passing the right data to \cs{tl_show:n} or \cs{tl_log:n}.
+% \begin{macrocode}
+\cs_new_protected:Npn \fp_show:N { \@@_show:NN \tl_show:n }
+\cs_generate_variant:Nn \fp_show:N { c }
+\cs_new_protected:Npn \fp_log:N { \@@_show:NN \tl_log:n }
+\cs_generate_variant:Nn \fp_log:N { c }
+\cs_new_protected:Npn \@@_show:NN #1#2
+ {
+ \__kernel_chk_tl_type:NnnT #2 { fp }
+ { \exp_args:No \@@_show_validate:n #2 }
+ { \exp_args:Ne #1 { \token_to_str:N #2 = \fp_to_tl:N #2 } }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+% {
+% \@@_show_validate:n, \@@_show_validate_aux:n, \@@_show_validate:nn,
+% }
+% \begin{macro}[EXP]
+% {
+% \@@_show_validate:w,
+% \@@_tuple_show_validate:w,
+% \@@_symbolic_show_validate:w
+% }
+% To support symbolic expression, validation has to be done recursively.
+% Two |\@@_show_validate:nn| wrappers are used to distinguish between
+% initial and recursive calls, in which the former provides a demo of
+% possible forms a |fp| variable would have.
+% \begin{macrocode}
+\cs_new:Npn \@@_show_validate:n #1
+ {
+ \@@_show_validate:nn { #1 }
+ {
+ \s_@@ \@@_chk:w ??? ;~ or \iow_newline:
+ \s_@@_tuple \_@@_tuple_chk:w ? ;~ or \iow_newline:
+ \s_@@_symbolic \@@_symbolic_chk:w ? , ? ;
+ }
+ }
+\cs_new:Npn \@@_show_validate_aux:n #1
+ {
+ \@@_show_validate:nn { #1 } { }
+ }
+\cs_new:Npn \@@_show_validate:nn #1#2
+ {
+ \tl_if_empty:nF { #1 }
+ {
+ \str_case:enF { \tl_head:n { #1 } }
+ {
+ { \s_@@ }
+ {
+ \@@_show_validate:w #1 \s_@@
+ \@@_chk:w ??? ; \s_@@_stop
+ }
+ { \s_@@_tuple }
+ {
+ \@@_tuple_show_validate:w #1
+ \s_@@_tuple \_@@_tuple_chk:w ?? ; \s_@@_stop
+ }
+ { \s_@@_symbolic }
+ {
+ \@@_symbolic_show_validate:w #1
+ \s_@@_symbolic \@@_symbolic_chk:w ? , ?? ; \s_@@_stop
+ }
+ }
+ { #2 }
+ }
+ }
+\cs_new:Npn \@@_show_validate:w
+ #1 \s_@@ \@@_chk:w #2#3#4#5 ; #6 \s_@@_stop
+ {
+ \str_if_eq:nnF { #2 } {?}
+ {
+ \token_if_eq_meaning:NNTF #2 1
+ { \s_@@ \@@_chk:w #2 #3 { #4 } #5 ; }
+ { \s_@@ \@@_chk:w #2 #3 #4 #5 ; }
+ \@@_show_validate_aux:n { #6 }
+ }
+ }
+\cs_new:Npn \@@_tuple_show_validate:w
+ #1 \s_@@_tuple \_@@_tuple_chk:w #2#3 ; #4 \s_@@_stop
+ {
+ \str_if_eq:nnF { #2 } {?}
+ { \s_@@_tuple \@@_tuple_chk:w { \@@_show_validate_aux:n { #2 } } ; }
+ }
+\cs_new:Npn \@@_symbolic_show_validate:w
+ #1 \s_@@_symbolic \@@_symbolic_chk:w #2 , #3#4 ; #5 \s_@@_stop
+ {
+ \str_if_eq:nnF { #2 } {?}
+ {
+ \s_@@_symbolic \@@_symbolic_chk:w \exp_not:n { #2 } ,
+ { \@@_show_validate_aux:n { #3 } };
+ \@@_show_validate_aux:n { #5 }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\fp_show:n, \fp_log:n}
+% Use general tools.
+% \begin{macrocode}
+\cs_new_protected:Npn \fp_show:n
+ { \__kernel_msg_show_eval:Nn \fp_to_tl:n }
+\cs_new_protected:Npn \fp_log:n
+ { \__kernel_msg_log_eval:Nn \fp_to_tl:n }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Some useful constants and scratch variables}
+%
+% \begin{variable}{\c_one_fp, \c_e_fp}
+% Some constants.
+% \begin{macrocode}
+\fp_const:Nn \c_e_fp { 2.718 2818 2845 9045 }
+\fp_const:Nn \c_one_fp { 1 }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_pi_fp, \c_one_degree_fp}
+% We simply round $\pi$ to and $\pi/180$ to $16$ significant digits.
+% \begin{macrocode}
+\fp_const:Nn \c_pi_fp { 3.141 5926 5358 9793 }
+\fp_const:Nn \c_one_degree_fp { 0.0 1745 3292 5199 4330 }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_tmpa_fp, \l_tmpb_fp, \g_tmpa_fp, \g_tmpb_fp}
+% Scratch variables are simply initialized there.
+% \begin{macrocode}
+\fp_new:N \l_tmpa_fp
+\fp_new:N \l_tmpb_fp
+\fp_new:N \g_tmpa_fp
+\fp_new:N \g_tmpb_fp
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintChanges
+%
+% \PrintIndex