% This is file `numerica.sty'. % % This work may be distributed and/or modified under the conditions % of the LaTeX Project Public License, either version 1.3c of this % license or any later version; see % http://www.latex-project.org/lppl.txt % % Andrew Parsloe (ajparsloe@gmail.com) % \RequirePackage{amsmath,mathtools} \ProvidesExplPackage{numerica} {2023/08/19} {3.0.0} {Numerically evaluate mathematical expressions in their LaTeX form} \tl_const:Nn \c_nmc_version_tl { 30 } \bool_new:N \l__nmc_dec_comma_bool \keys_define:nn { numerica/package } { comma .bool_set:N = \l__nmc_dec_comma_bool, comma .default:n = true, comma .initial:n = false, rounding .int_set:N = \l__nmc_round_int, rounding .initial:n = 6, approx .tl_set:N = \l__nmc_eq_tl, approx .default:n = \approx, approx .initial:n = {=} } \ProcessKeyOptions [ numerica/package ] % *unspaced* decimal comma \bool_if:NTF \l__nmc_dec_comma_bool { \tl_const:Nn \c__nmc_vv_delim_tl {;} \mathchardef \nmcComma \mathcode`, \AtBeginDocument { \char_set_active_eq:nN { `, } \__nmc_dec_comma: \char_set_mathcode:nn { `, } { "8000 } } } { \tl_const:Nn \c__nmc_vv_delim_tl {,} } \cs_new_protected:Npn \__nmc_dec_comma: { \peek_after:Nw \__nmc_check_for_digit: } \cs_new:Npn \__nmc_check_for_digit: { \token_case_charcode:NnTF \l_peek_token { {0}{} {1}{} {2}{} {3}{} {4}{} {5}{} {6}{} {7}{} {8}{} {9}{} } { { \nmcComma } } { \nmcComma } } % \sgn \lb; missing hyp & inverse trig & hyp fns \cs_new:Npn \__nmc_fn_def:N #1 { \cs_if_free:NT #1 { \DeclareMathOperator{#1}{\cs_to_str:N #1} } } \cs_generate_variant:Nn \__nmc_fn_def:N { c } \AtBeginDocument { \clist_map_inline:nn { sgn, lb } { \__nmc_fn_def:c {#1} } \clist_map_inline:nn { csch, sech } { \__nmc_fn_def:c {#1} } \clist_map_inline:nn { csc, sec, cot } { \__nmc_fn_def:c {arc#1} } \clist_map_inline:nn { sinh, cosh, tanh, csch, sech, tanh } { \__nmc_fn_def:c {a#1} \__nmc_fn_def:c {ar#1} \__nmc_fn_def:c {arc#1} } \cs_if_free:NT \abs {\DeclarePairedDelimiter{\abs}{\lvert}{\rvert} } \cs_if_free:NT \ceil { \DeclarePairedDelimiter{\ceil}{\lceil}{\rceil} } \cs_if_free:NT \floor { \DeclarePairedDelimiter{\floor}{\lfloor}{\rfloor} } \cs_if_free:NT \sfrac { \NewDocumentCommand \sfrac { mm } { \mathchoice{{\scriptstyle #1/#2}} {{\scriptstyle #1/#2}} {{\scriptscriptstyle #1/#2}} {{#1/#2}} } } } \RenewDocumentCommand \land {} { \,\wedge\, } \RenewDocumentCommand \lor {} { \,\vee\, } \NewDocumentCommand \Q {} { \prg_do_nothing: } % Qleave apart \NewDocumentCommand \q {} { \prg_do_nothing: } % qleave to \ProvideDocumentCommand \comma {} {,} \ProvideDocumentCommand \equals {} { \ensuremath{=} } \ProvideDocumentCommand \degree {} { \ensuremath{^\circ} } % \int_const:Nn \c__nmc_and_int { 0 } \int_const:Nn \c__nmc_cmp_int { 1 } \int_const:Nn \c__nmc_sum_int { 2 } \int_const:Nn \c__nmc_uny_int { 3 } \int_const:Nn \c__nmc_prn_int { 4 } \int_const:Nn \c__nmc_srd_int { 5 } \int_new:N \l__nmc_num_sgn_int % tables \tl_new:N \l__nmc_toss_tl \tl_new:N \l__nmca_tl \fp_new:N \l_tmpc_fp \fp_new:N \l_tmpd_fp \int_new:N \l__nmca_int \seq_new:N \l_tmpc_seq % \cs_if_exist:NTF \seq_map_pairwise_function:NNN { \cs_set_eq:NN \__nmc_braid:NNN \seq_map_pairwise_function:NNN } { \cs_set_eq:NN \__nmc_braid:NNN \seq_mapthread_function:NNN } \cs_if_exist:NF \int_if_zero_p:n { \prg_new_conditional:Npnn \int_if_zero:n #1 { p,T,F,TF } { \int_compare:nNnTF { #1 } = { 0 } { \prg_return_true: } { \prg_return_false: } } } \prg_new_conditional:Npnn \__nmc_if_mod_zero:nn #1#2 { p,T,F,TF } { \bool_if:nTF { !\int_compare_p:nNn { #1 } = { 0 } && \int_compare_p:nNn { \int_mod:nn { #1 } { #2 } } = { 0 } } { \prg_return_true: } { \prg_return_false: } } % fpify & delim property lists \prop_new:N \g__nmc_class_prop % latex tokens % #1(clist) tokens; #2(tl) { fpify: delim: } routines \cs_new_protected:Npn \__nmc_fill_class:nn #1#2 { \clist_map_inline:nn { #1 } { \prop_gput:Nnn \g__nmc_class_prop { ##1 } { #2 } } } % \__nmc_fill_class:nn { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 } { \__nmc_fpify_dec: \__nmc_delim_dec: } \__nmc_fill_class:nn { e, \pi, \gamma, \phi, \deg, \infty } { \__nmc_fpify_const: \__nmc_delim_const: } % arith \__nmc_fill_class:nn { +, - } { \__nmc_fpify_arith: \__nmc_delim_pm: } \prop_put:Nnn \g__nmc_class_prop { * } { \__nmc_fpify_arith: \__nmc_delim_arith: } \prop_put:Nnn \g__nmc_class_prop { / } { \__nmc_fpify_slash: \__nmc_delim_arith: } \__nmc_fill_class:nn { \times, \cdot, \div } { \__nmc_fpify_arith_alt: \__nmc_delim_arith: } \prop_put:Nnn \g__nmc_class_prop { ^ } { \__nmc_fpify_power: \__nmc_delim_power: } \__nmc_fill_class:nn { \frac, \dfrac } { \__nmc_fpify_frac: \__nmc_delim_frac: } \__nmc_fill_class:nn { \tfrac, \sfrac } { \__nmc_fpify_frac: \__nmc_delim_tfrac: } % comparisons \__nmc_fill_class:nn { =, <, >, \ne, \neq, \nless, \ngtr, \ge, \geq, \geqq, \geqslant, \le, \leq, \leqq, \leqslant, \ngeq, \ngeqq, \ngeqslant, nleq, \nleqq, \nleqslant, } { \__nmc_fpify_comparison: \__nmc_delim_comparison: } % logic, surd \__nmc_fill_class:nn { \wedge, \land, \vee, \lor } { \__nmc_fpify_andor: \__nmc_delim_andor: } \__nmc_fill_class:nn { \surd, \neg, \lnot } { \__nmc_fpify_surd: \__nmc_delim_surd: } % left \__nmc_fill_class:nn { (, [, \{, \lparen, \lbrack, \lbrace } { \__nmc_fpify_lparen: \__nmc_delim_lparen: } \__nmc_fill_class:nn { |, \lvert, \lfloor, \lceil } { \__nmc_fpify_lvert: \__nmc_delim_lvert: } \__nmc_fill_class:nn { \left, \mleft, \bigl, \Bigl, \biggl, \Biggl } { \__nmc_fpify_lmod: \__nmc_delim_lmod: } % right \__nmc_fill_class:nn { \right, \mright, \bigr, \Bigr, \biggr, \Biggr } { \__nmc_fpify_rmod: \__nmc_delim_rparen: } % unary fns: f \__nmc_fill_class:nn { \sin, \cos, \tan, \csc, \sec, \cot, \arcsin, \arccos, \arctan, \arccsc, \arcsec, \arccot, \sinh, \cosh, \tanh, \csch, \sech, \coth, \asinh, \acosh, \atanh, \acsch, \asech, \acoth, \arsinh, \arcosh, \artanh, \arcsch, \arsech, \arcoth, \arcsinh, \arccosh, \arctanh, \arccsch, \arcsech, \arccoth, \exp, \ln, \lg, \lb, \sgn } { \__nmc_fpify_unary: \__nmc_delim_unary: } \prop_put:Nnn \g__nmc_class_prop { \degree } { \__nmc_fpify_degree: \__nmc_delim_append: } % factorial \prop_put:Nnn \g__nmc_class_prop { ! } { \__nmc_fpify_fact: \__nmc_delim_fact: } % f{} \__nmc_fill_class:nn { \sqrt, \abs, \floor, \ceil } { \__nmc_fpify_unarybrace: \__nmc_delim_unarybrace: } % binary ( f_{arg1}{arg2}, f{arg1}{arg2} ) \prop_put:Nnn \g__nmc_class_prop { \log } { \__nmc_fpify_unarysub: \__nmc_delim_log: } \__nmc_fill_class:nn { \tbinom, \binom, \dbinom } { \__nmc_fpify_binom: \__nmc_delim_frac: } % nary f(arg1,...) \__nmc_fill_class:nn { \min, \max, \gcd } { \__nmc_fpify_nary: \__nmc_delim_nary: } \bool_if:NTF \l__nmc_dec_comma_bool { \prop_put:Nnn \g__nmc_class_prop { , } { \__nmc_fpify_dec: \__nmc_delim_dec: } \prop_put:Nnn \g__nmc_class_prop { ; } {\__nmc_fpify_comma: \__nmc_delim_comma: } } { \prop_put:Nnn \g__nmc_class_prop { . } { \__nmc_fpify_dec: \__nmc_delim_dec: } \prop_put:Nnn \g__nmc_class_prop { , } {\__nmc_fpify_comma: \__nmc_delim_comma: } } % fontlike (ignore cmd; heed {arg} ) \__nmc_fill_class:nn { \mathrm, \mathit, \mathcal, \mathtt, \mathbf, \mathbb, \mathsf, \mathfrak, \mathscr, \mathnormal, \boldsymbol, \ensuremath, \smash, \textrm, \textsf, \texttt, \textit, \textsl, \textsc, \textbf } { \__nmc_fpify_font: \__nmc_delim_font: } % ignore cmd, [arg1], {arg2}; heed {arg3} \prop_put:Nnn \g__nmc_class_prop { \textcolor } { \__nmc_fpify_color: \__nmc_delim_color: } % splitfrac ( ignore cmd, heed {arg1}{arg2} ) \__nmc_fill_class:nn { \splitfrac, \splitdfrac } { \__nmc_fpify_splitfrac: \__nmc_delim_append_twobraced: } % absorb \__nmc_fill_class:nn { {{}}, \\, &, \to, \q_nil, \dots, \ldots, \cdots, \quad, \qquad, \hfill, \hfil, \mathstrut, $, \(, \), \[, \], \ , \,, \;, \:, \!, \>, \thinspace, \medspace, \thickspace, \negthinspace, \negmedspace, \negthickspace, \lefteqn, \displaystyle, \textstyle, \scriptstyle, \scriptscriptstyle, \middle, \big, \Big, \bigg, \Bigg, \protect, \mleftright, \mleftrightrestore, \comma, \equals } { \prg_do_nothing: \__nmc_delim_absorb: } \__nmc_fill_class:nn { \vphantom, \hphantom, \phantom, \label, \mspace, \mbox, \text } { \__nmc_fpify_absorb_m: \__nmc_delim_absorb_i: } \__nmc_fill_class:nn { \hspace } { \__nmc_fpify_absorb_sm: \__nmc_delim_absorb_ii: } \__nmc_fill_class:nn { \xmathstrut, \color } { \__nmc_fpify_absorb_om: \__nmc_delim_absorb_ii: } % kerning \__nmc_fill_class:nn { \mskip, \mkern } { \__nmc_fpify_mkern: \__nmc_delim_mkern: } % ams environs f{arg1} (& f{arg1}{arg2} for aligned, aligned*) \__nmc_fill_class:nn { \begin, \end } { \__nmc_fpify_BE: \__nmc_delim_BE: } % cleave \__nmc_fill_class:nn { \q, \Q } { \prg_do_nothing: \__nmc_delim_cleave: } % sum, prod \__nmc_fill_class:nn { \sum, \prod } { \__nmc_fpify_sum: \__nmc_delim_sum: } % nmcFn \__nmc_fill_class:nn { \eval, \nmcEvaluate, \iter, \nmcIterate, \solve, \nmcSolve, \recur, \nmcRecur, \tabulate, \nmcTabulate, \info, \nmcInfo, \constants, \nmcConstants, \macros, \nmcMacros, \reuse, \nmcReuse } { \__nmc_fpify_cmd: \__nmc_delim_cmd: } % substitution classes %%%%%%%%%%%%%%%%%%%%%%%%%% \prop_new:N \l__nmc_subst_var_prop % variables \prop_new:N \g__nmc_subst_var_prop % macros (user & reuse) \prop_new:N \g__nmc_subst_fpfn_prop % math toks for l3fp eval \prop_new:N \g__nmc_subst_misc_prop % misc subst % #1 prop; #2 seq (keys); #3 seq (values) \cs_new_protected:Npn \__nmc_subst:NNN #1#2#3 { \cs_set_protected:Npn \__nmc_substitutions:nn ##1##2 { \prop_gput:Nnn #1 { ##1 } { ##2 } } \__nmc_braid:NNN #2 #3 \__nmc_substitutions:nn } \seq_set_from_clist:Nn \l_tmpa_seq { e, \pi, \gamma, \phi, \deg, \infty, \sin, \cos, \tan, \csc, \sec, \cot, \arcsin, \arccos, \arctan, \arccsc, \arcsec, \arccot, \sinh, \cosh, \tanh, \csch, \sech, \coth, \asinh, \acosh, \atanh, \acsch, \asech, \acoth, \arsinh, \arcosh, \artanh, \arcsch, \arsech, \arcoth, \arcsinh, \arccosh, \arctanh, \arccsch, \arcsech, \arccoth, \exp, \ln, \lg, \lb, \sgn, \max, \min, \surd, \sqrt, \times, \cdot, \div, \abs, \floor, \ceil, \lvert, \lfloor, \lceil, \neg, \lnot, \wedge, \land, \vee, \lor, \le, \leq, \leqq, \leqslant, \ge, \geq, \geqq, \geqslant, \ne, \neq, \nless, \ngtr, \nleq, \nleqq,\nleqslant, \ngeq, \ngeqq, \ngeqslant } \seq_set_from_clist:Nn \l_tmpb_seq { exp(1), (pi), (0.5772156649015329), (1.618033988749895), (0.0174532925199433), inf, sin\__nmc_deg:, cos\__nmc_deg:, tan\__nmc_deg:, csc\__nmc_deg:, sec\__nmc_deg:, cot\__nmc_deg:, asin\__nmc_deg:, acos\__nmc_deg:, atan\__nmc_deg:, acsc\__nmc_deg:, asec\__nmc_deg:, acot\__nmc_deg:, sinh, cosh, tanh, csch, sech, coth, asinh, acosh, atanh, acsch, asech, acoth, asinh, acosh, atanh, acsch, asech, acoth, asinh, acosh, atanh, acsch, asech, acoth, exp, ln, (0.4342944819032518)ln, (1.442695040888963)ln, sign, max, min, sqrt, sqrt, *, *, /, abs, floor, ceil, abs, floor, ceil, !, !, &&, &&, ||, ||, <=, <=, <=, <=, >=, >=, >=, >=, !=, !=, !<, !>, !<=, !<=, !<=, !>=, !>=, !>= } \__nmc_subst:NNN \g__nmc_subst_fpfn_prop \l_tmpa_seq \l_tmpb_seq \seq_set_from_clist:Nn \l_tmpa_seq { \cosh, \sinh, \tanh, \csch, \sech, \coth, (, [, \{, \lparen, \lbrack, \lbrace, \left, \bigl, \Bigl, \biggl, \Biggl, \lvert, \lceil, \lfloor, sum, prod, deriv, integ, iter, solve, \eval, \nmcEvaluate, \iter, \nmcIterate, \solve, \nmcSolve, \recur, \nmcRecur, \tabulate, \nmcTabulate, \info, \nmcInfo, \constants, \nmcConstants, \macros, \nmcMacros, \reuse, \nmcReuse, <=, =<, >=, => } \seq_set_from_clist:Nn \l_tmpb_seq { acosh, asinh, atanh, acsch, asech, acoth, ), ], \}, \rparen, \rbrack, \rbrace, \right, \bigr, \Bigr, \biggr, \Biggr, \rvert, \rceil, \rfloor, term, factor, bisection, subdivision, iteration, step, eval, eval, iter, iter, solve, solve, recur, recur, table, table, info, info, consts, consts, macros, macros, reuse, reuse, \leq, \leq, \geq, \geq } \__nmc_subst:NNN \g__nmc_subst_misc_prop \l_tmpa_seq \l_tmpb_seq % base function variants %%%%%%%%%%%%%%%%%%%%%%%% \cs_generate_variant:Nn \tl_if_head_eq_meaning_p:nN { V } \cs_generate_variant:Nn \tl_if_head_is_group:nTF { V } \cs_generate_variant:Nn \tl_if_in:NnTF { NV } \cs_generate_variant:Nn \tl_if_in:NnT { NV } \cs_generate_variant:Nn \tl_if_in:nnTF { nV } \cs_generate_variant:Nn \tl_if_in:nnT { nV } \cs_generate_variant:Nn \tl_if_eq:nnTF { V, VV } \cs_generate_variant:Nn \tl_if_eq:nnT { V } \cs_generate_variant:Nn \tl_if_eq:nnF { V } \cs_generate_variant:Nn \tl_replace_once:Nnn { NV, NnV, Nnx } \cs_generate_variant:Nn \tl_count_tokens:n { V } \cs_generate_variant:Nn \str_if_eq:nnTF { V } \cs_generate_variant:Nn \str_if_in:NnTF { NV } \cs_generate_variant:Nn \seq_set_split:Nnn { NV, NVV } \cs_generate_variant:Nn \seq_use:Nn { NV } \cs_generate_variant:Nn \prop_put_if_new:Nnn { No } \cs_generate_variant:Nn \iow_open:Nn { NV } \cs_generate_variant:Nn \iow_now:Nn { NV } \cs_generate_variant:Nn \regex_extract_once:NnN { NV } \cs_generate_variant:Nn \keys_set_known:nn { x } \cs_generate_variant:Nn \file_get:nnN { V } \cs_generate_variant:Nn \file_get:nnNT { V } \cs_generate_variant:Nn \file_get:nnNTF { V } % environments \tl_new:N \l__nmc_equals_tl \int_new:N \l__nmc_env_def_int % 0 undefined; 1 provisional; 2 defined \prop_new:N \g__nmc_env_prop \prop_new:N \g__nmc_envi_prop \prop_gput_from_keyval:Nn \g__nmc_env_prop { $ = \__nmc_math_env_sym:nnnnn {$}{}{}{}{$}, math = \__nmc_math_env:nnnn {math}{}{\mskip 12muplus6muminus9mu(vv)}{\quad}, \( = \__nmc_math_env_sym:nnnnn {\(}{}{}{}{\)}, \[ = \__nmc_math_env_sym:nnnnn {\[}{}{\mskip 36muminus24mu(vv)}{\]\[}{\]}, displaymath = \__nmc_math_env:nnnn {displaymath}{}{}{}, equation = \__nmc_math_env:nnnn {equation}{}{}{}, equation* = \__nmc_math_env:nnnn {equation*}{}{}{}, multline = \mode_if_math:TF { \__nmc_math_env:nnnn {multline}{}{}{\hfill\\} } { \__nmc_math_env:nnnn {multline}{}{\\(vv)}{} }, multline* = \mode_if_math:TF { \__nmc_math_env:nnnn {multline*}{}{}{\hfill\\} } { \__nmc_math_env:nnnn {multline*}{}{\\(vv)}{} }, eqnarray = \__nmc_math_env_cum:nnnn {eqnarray}{&=&} {\mskip 36muminus24mu(vv)}{}, eqnarray* = \__nmc_math_env_cum:nnnn {eqnarray*}{&=&} {\mskip 36muminus24mu(vv)}{}, align = \__nmc_math_env_cum:nnnn {align}{}{}{}, align* = \__nmc_math_env_cum:nnnn {align*}{}{}{}, gather = \__nmc_math_env_cum:nnnn {gather}{=} {\mskip 12muplus6muminus9mu(vv)}{}, gather* = \__nmc_math_env_cum:nnnn {gather*}{=} {\mskip 12muplus6muminus9mu(vv)}{}, flalign = \__nmc_math_env_cum:nnnn {flalign}{}{}{}, flalign* = \__nmc_math_env_cum:nnnn {flalign*}{}{}{}, alignat = \__nmc_math_env_cum:nnnn {alignat}{&=\;&}{\qquad&(vv)}{} \tl_set:Nn \l__nmc_env_arg_tl {2}, alignat* = \__nmc_math_env_cum:nnnn {alignat*}{&=\;&}{\qquad&(vv)}{} \tl_set:Nn \l__nmc_env_arg_tl {2}, } \prop_gput_from_keyval:Nn \g__nmc_envi_prop { aligned = \__nmc_math_env_cum:nnnn {aligned}{}{}{}, alignedat = \__nmc_math_env_cum:nnnn {alignedat}{&=\;&}{\qquad&(vv)}{} \tl_set:Nn \l__nmc_env_arg_tl {2}, array = \__nmc_math_env_cum:nnnn {array}{&=&}{&(vv)}{} \tl_set:Nn \l__nmc_env_arg_tl {rcrl}, gathered = \__nmc_math_env_cum:nnnn {gathered}{=} {\mskip 12muplus6muminus9mu(vv)}{}, cases = \__nmc_math_env_cum:nnnn {cases}{=}{\quad\hfill(vv)}{}, dcases = \__nmc_math_env_cum:nnnn {dcases}{=}{\quad\hfill(vv)}{} } % #1 env #2 equals #3 vv #4 multisep #5 \) et al or arg \cs_new_protected:Npn \__nmc_math_env_sym:nnnnn #1#2#3#4#5 { \__nmc_math_env_delims:nn {#1}{#5} \__nmc_math_env_set:Vnnnn \c__nmc_vv_delim_tl{#1}{=} {\mskip 12muplus6muminus9mu(vv)}{\quad} \tl_if_blank:nF {#2#3#4} { \__nmc_math_env_aux:Vnnn \c__nmc_vv_delim_tl {#2}{#3}{#4} } \tl_replace_once:NnV \l__nmc_equals_tl { = } \l__nmc_eq_tl } \cs_new_protected:Npn \__nmc_math_env:nnnn #1#2#3#4 { \__nmc_math_env_delims:n { #1 } \__nmc_math_env_set:Vnnnn \c__nmc_vv_delim_tl {#1}{=} {\mskip 36muminus24mu(vv)}{\end{#1}\begin{#1}} \tl_if_blank:nF {#2#3#4} { \__nmc_math_env_aux:Vnnn \c__nmc_vv_delim_tl {#2}{#3}{#4} } \tl_replace_once:NnV \l__nmc_equals_tl { = } \l__nmc_eq_tl } \cs_new_protected:Npn \__nmc_math_env_cum:nnnn #1#2#3#4 { \__nmc_math_env_delims:n { #1 } \__nmc_math_env_set:Vnnnn \c__nmc_vv_delim_tl{#1}{&=} {\mskip 36muminus24mu(vv)}{\\} \tl_if_blank:nF {#2#3#4} { \__nmc_math_env_aux:Vnnn \c__nmc_vv_delim_tl {#2}{#3}{#4} } \tl_replace_once:NnV \l__nmc_equals_tl { = } \l__nmc_eq_tl } \cs_new_protected:Npn \__nmc_math_env_set:nnnnn #1#2#3#4#5 { \tl_clear:N \l__nmc_env_arg_tl \tl_set:Nn \l__nmc_env_tl {#2} \tl_set:Nn \l__nmc_equals_tl {#3} \tl_set:Nn \l__nmc_vv_tl {#1#4} \tl_set:Nn \l__nmc_multi_sep_tl {#5} } \cs_generate_variant:Nn \__nmc_math_env_set:nnnnn { V } \cs_new_protected:Npn \__nmc_math_env_aux:nnnn #1#2#3#4 { \tl_if_blank:nF { #2 } { \tl_set:Nn \l__nmc_equals_tl {#2} } \tl_if_blank:nF { #3 } { \tl_set:Nn \l__nmc_vv_tl {#1#3} } \tl_if_blank:nF { #4 } { \tl_set:Nn \l__nmc_multi_sep_tl {#4} } } \cs_generate_variant:Nn \__nmc_math_env_aux:nnnn { V } % general purpose routines %%%%%%%%%%%%%%%%%%%%%% % \tl_new:N \l__nmcA_tl etc. \clist_map_inline:nn { A,B,C,L,R } { \tl_new:c { l__nmc_#1_tl } } % prune head from A, put in B; record new head of A in C \cs_new_protected:Npn \__nmc_next: { \exp_last_unbraced:NV\__nmc_next:w \l__nmcA_tl\q_stop} \cs_new_protected:Npn \__nmc_next:w #1#2#3\q_stop { \__nmc_assign_vals:nnnN {#1} {#2} {#3} \l__nmcB_tl } % get |arg| \cs_new_protected:Npn \__nmc_absval_arg:N #1 { \exp_last_unbraced:NV \__nmc_absval_arg:wN \l__nmcA_tl\q_stop #1 } \cs_new_protected:Npn \__nmc_absval_arg:wN #1|#2#3\q_stop #4 { \__nmc_assign_vals:nnnN {#1} {#2} {#3} #4 } \cs_new_protected:Npn \__nmc_assign_vals:nnnN #1#2#3#4 { \tl_if_single:nTF { #2 } { \tl_set:Nn \l__nmcA_tl { #2#3 } } { \tl_set:Nn \l__nmcA_tl { {#2}#3 } } \tl_set:Nn #4 { #1 } \tl_set:Nn \l__nmcC_tl { #2 } } \cs_new_protected:Npn \__nmc_parenth:N #1 { \tl_set:Nx #1 { ( \exp_not:o #1 ) } } \cs_new_protected:Npn \__nmc_accum_fn_parenth:Nnn #1#2#3 { \tl_put_right:Nx #1 { #3( \exp_not:o {#2} ) } } \cs_generate_variant:Nn \__nmc_accum_fn_parenth:Nnn { NV } % wrap #3 in #2 & #4, & append to #1 \cs_new_protected:Npn \__nmc_put_right_wrap:NnNn #1#2#3#4 { \tl_put_right:Nx #1 { #2 \exp_not:o #3 #4 } } \cs_new_protected:Npn \__nmc_get_arg_L:nN #1#2 { \tl_set:Nn \l__nmc_L_tl { #1 } \prop_get:NnN \g__nmc_subst_misc_prop { #1 } \l__nmc_R_tl \__nmc_get_arg_L_aux:NNV #1#2 \l__nmc_R_tl } \cs_generate_variant:Nn \__nmc_get_arg_L:nN { V } \cs_new_protected:Npn \__nmc_get_arg_L_aux:NNn #1#2#3 { \__nmc_get_arg_LR:NNN #1#2#3 } \cs_generate_variant:Nn \__nmc_get_arg_L_aux:NNn { NNV } % #1 ldelim; #2 <-- arg (delims *not* included) % #3 rdelim (*must* differ from #1) \cs_new_protected:Npn \__nmc_get_arg_LR:NNN #1#2#3 { \int_set:Nn \l__nmca_int { 1 } \tl_map_inline:Nn \l__nmcA_tl { \str_case:nn { ##1 } { { #1 } { \int_incr:N \l__nmca_int } { #3 } { \int_decr:N \l__nmca_int \int_if_zero:nT { \l__nmca_int } { \__nmc_next: \tl_map_break: } } { \q_nil } { \__nmc_error_what:n { Unmatched~\__nmc_verb:n { #1 }\ in } \tl_map_break: } } \__nmc_next: \tl_if_single:nTF { ##1 } { \tl_put_right:Nn #2 { ##1 } } { \tl_put_right:Nn #2 { {##1} } } } } % number parsing % #1 <== multi-char num poss. in sci notation % #2 delim: vs fpify: boolean \cs_new_protected:Npn \__nmc_get_dec:NN #1#2 { \tl_concat:NNN \l__nmcA_tl \l__nmcB_tl \l__nmcA_tl \regex_extract_once:NVN \l__nmc_num_regex \l__nmcA_tl \l_tmpa_seq \seq_pop:NN \l_tmpa_seq #1 \bool_if:NF #2 { \bool_if:NT \l__nmc_dec_comma_bool { \tl_replace_once:Nnn #1 {,} {.} } \bool_if:NT \l__nmc_sci_num_in_bool { \tl_replace_once:NVn #1 \l__nmc_sci_num_in_tl {e} } } \regex_replace_once:NnN \l__nmc_num_regex {} \l__nmcA_tl \tl_set:Nx \l__nmcC_tl { \tl_head:N \l__nmcA_tl } } % calc fn vals; explicit/implicit eval. of vv-list % #1(tl) var; #2(tl) fn; #3(fp) var val; #4(fp) <-- fn val % mode 0 (no vals in vv-list change) \cs_new_protected:Npn \__nmc_calc_fn_val:nNnN #1#2#3#4 { \prop_put:Nnx \l__nmc_subst_var_prop { #1 } { \fp_to_tl:n { #3 } } \__nmc_fpify_set:NV #4 #2 } \cs_generate_variant:Nn \__nmc_calc_fn_val:nNnN { V } \cs_new_protected:Npn \__nmc_calc_mode:n #1 { \tl_set:Nx \l__nmc_mode_tl { \int_eval:n { #1 } } \str_case:Vn \l__nmc_mode_tl { { 1 } { \cs_set_eq:NN \__nmc_calc_fn_val:nNnN \__nmc_calc_fn_vali:nNnN } { 2 } { \cs_set_eq:NN \__nmc_calc_fn_val:nNnN \__nmc_calc_fn_valii:nNnN } } } \cs_generate_variant:Nn \__nmc_calc_mode:n { V } % mode 1 (all vals in vv-list may change) \cs_new_protected:Npn \__nmc_calc_fn_vali:nNnN #1#2#3#4 { \prop_put:Nnx \l__nmc_vv_change_prop { #1 } { \fp_to_tl:n { #3 } } \__nmc_vv_get_vars_vals:NN \l__nmc_calc_fn_seq \l__nmc_vv_change_prop \__nmc_fpify_set:NV #4 #2 } % mode 2 (some vals in vv-list held const.) \cs_new_protected:Npn \__nmc_calc_fn_valii:nNnN #1#2#3#4 { \prop_put:Nnx \l__nmc_vv_change_prop { #1 } { \fp_to_tl:n { #3 } } \clist_map_inline:Nn \g__nmc_unchanged_clist { \prop_get:NnN \l__nmc_subst_var_prop { ##1 } \l__nmc_subst_tl \prop_put:NnV \l__nmc_vv_change_prop { ##1 } \l__nmc_subst_tl } \__nmc_vv_get_vars_vals:NN \l__nmc_calc_fn_seq \l__nmc_vv_change_prop \__nmc_fpify_set:NV #4 #2 } % fp-set #1 to fpified #2 \cs_new_protected:Npn \__nmc_fpify_set:Nn #1#2 { \group_begin: \tl_clear:N \l_tmpa_tl \__nmc_fpify:nN { #2 } \l_tmpa_tl \exp_args:NNNV \group_end: \tl_set:Nn \l__nmc_fp_exprn_tl \l_tmpa_tl \bool_if:NF \g__nmc_error_bool { \fp_set:Nn #1 { \l__nmc_fp_exprn_tl } \__nmc_error_fpflag: } } \cs_generate_variant:Nn \__nmc_fpify_set:Nn { NV, cv } \cs_new:Npn \__nmc_verb:n #1 { \texttt{ \tl_to_str:n { #1 } } } \cs_generate_variant:Nn \__nmc_verb:n { V } \cs_new:Npn \__nmc_verb:N #1 { \texttt{ \tl_to_str:N #1 } } \cs_generate_variant:Nn \__nmc_verb:N { c } % numerica errors %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \int_new:N \l__nmc_depth_int \seq_new:N \g__nmc_error_where_seq \bool_new:N \g__nmc_error_bool \msg_new:nnn { numerica } { base } { numerica~error~in~#1~on~line~\msg_line_number:. } \cs_new_protected:Npn \__nmc_error_msg:n #1 { \tl_set:Nn \l_tmpa_tl { ??? } \seq_if_empty:NF \g__nmc_error_where_seq { \seq_gpop:NN \g__nmc_error_where_seq \l_tmpa_tl \textsf{ !!!~#1:~\l_tmpa_tl.~!!! } } \msg_log:nnx { numerica } { base } \l_tmpa_tl } \cs_new_protected:Npn \__nmc_error_where:n #1 { \seq_gpush:Nx \g__nmc_error_where_seq { #1 \int_compare:nNnT { \l__nmc_depth_int } > { 1 } { ~(\int_eval:n { (\l__nmc_depth_int-1)/2 } ) } } } \cs_new_protected:Npn \__nmc_error_what:n #1 { \bool_gset_true:N \g__nmc_error_bool \tl_gclear:N \g__nmc_reuse_tl \int_compare:nNnF \l__nmc_dbg_int < { 0 } { \__nmc_error_msg:n { #1 } } } \cs_generate_variant:Nn \__nmc_error_what:n { V, x } % l3fp exceptions; ln(1),cos(90),sin(360) underflow ignored! % Invalid op --> LaTeX *error*, hence \fp_trap:nn { invalid_operation } { flag } \cs_new_protected:Npn \__nmc_error_fpflag: { \flag_if_raised:nTF { fp_overflow } { \__nmc_flag:n { 1 } } { \flag_if_raised:nTF { fp_division_by_zero } { \__nmc_flag:n { 2 } } { \flag_if_raised:nT { fp_invalid_operation } { \__nmc_flag:n { 3 } } } } } \cs_new_protected:Npn \__nmc_flag:n #1 { \__nmc_error_what:V { \__nmc_verb:n{l3fp}~error~`\clist_item:nn { Overflow, Division~by~zero, Invalid~operation }{ #1 }'~in } } %%%%%%%% multi-tok --> single token vars %%%%%%%% % no math delims; #1(seq) vv-list; #2(tl) formula \int_new:N \g__nmc_prep_multitok_int \tl_new:N \l_nmc_multitoka_tl \tl_new:N \l_nmc_multitokb_tl \seq_new:N \l__nmc_multitoka_seq \seq_new:N \l__nmc_multitokb_seq \cs_new_protected:Npn \__nmc_prep_multitok:NN #1#2 { \seq_clear:N \l__nmc_multitoka_seq \seq_map_inline:Nn #1 { \seq_set_split:Nnn \l__nmc_multitokb_seq { = } { ##1 } \seq_pop:NN \l__nmc_multitokb_seq \l_tmpb_tl \int_compare:nNnT { \tl_count_tokens:V \l_tmpb_tl } > { 1 } { \seq_push:NV \l__nmc_multitoka_seq \l_tmpb_tl } } % big --> small \seq_sort:Nn \l__nmc_multitoka_seq { \int_compare:nNnTF { \tl_count:n {##2} } > { \tl_count:n { ##1 } } { \sort_return_swapped: } { \sort_return_same: } } % multitoks => \nmc_a, \nmc_b, etc \seq_map_inline:Nn \l__nmc_multitoka_seq { \int_gincr:N \g__nmc_prep_multitok_int \tl_set:Nn \l_nmc_multitoka_tl { ##1 } \tl_set:Nx \l_nmc_multitokb_tl { \cs:w nmc_\int_to_alph:n { \g__nmc_prep_multitok_int } \cs_end: } \tl_gset:cn { nmc_\int_to_alph:n { \g__nmc_prep_multitok_int } } { ##1 } \regex_replace_all:nnN { \u{l_nmc_multitoka_tl} } { \u{l_nmc_multitokb_tl} } #1 \regex_replace_all:nnN { \u{l_nmc_multitoka_tl} } { \u{l_nmc_multitokb_tl} } #2 } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \tl_new:N \l__nmc_mode_tl \tl_new:N \l__nmc_formula_tl \tl_new:N \l__nmc_formula_dup_tl \tl_new:N \l__nmc_env_tl \tl_new:N \l__nmc_result_tl \tl_new:N \l__nmc_show_tl \tl_new:N \l__nmc_display_tl \tl_new:N \l__nmc_fp_expr_tl \tl_new:N \l__nmc_fp_exprn_tl \tl_new:N \l__nmc_eq_var_tl \tl_new:N \l__nmc_eq_val_tl \tl_new:N \l__nmc_vv_fp_expr_tl \tl_new:N \l__nmc_vv_tl \tl_new:N \l__nmc_vvv_tl \tl_new:N \l__nmc_punc_tl \tl_new:N \l__nmc_math_delimi_tl \tl_new:N \l__nmc_math_delimii_tl \tl_new:N \l__nmc_outer_delimi_tl \tl_new:N \l__nmc_outer_delimii_tl \tl_new:N \l__nmc_env_arg_tl \tl_new:N \l__nmc_dbg_vv_tl \tl_new:N \l__nmc_dbg_idiii_tl \tl_new:N \l__nmc_dbg_idii_tl \tl_new:N \l__nmc_dbg_idv_tl \tl_new:N \l__nmc_bool_F_tl \tl_new:N \l__nmc_bool_T_tl \int_new:N \l__nmc_sci_expon_int \int_new:N \l__nmc_num_alt_int \int_new:N \l__nmc_multi_int \seq_new:N \l__nmc_vv_visible_seq \seq_new:N \l__nmc_vv_no_consts_seq \seq_new:N \l__nmc_vv_all_seq \seq_new:N \l__nmc_calc_fn_seq \seq_new:N \l__nmc_dbg_stored_seq \seq_new:N \l__nmc_vva_seq \seq_new:N \l__nmc_vvb_seq \bool_new:N \l__nmc_TF_out_bool \bool_new:N \l__nmc_allow_TF_out_bool \bool_new:N \l__nmc_sci_num_x_bool \bool_new:N \l__nmc_sci_num_table_bool \bool_new:N \l__nmc_num_only_bool \bool_new:N \l__nmc_round_bool \bool_new:N \l__nmc_see_formula_bool \bool_new:N \l__nmc_see_vv_bool \bool_new:N \l__nmc_vv_val_only_bool \bool_new:N \l__nmc_dbg_count_bool \prop_new:N \l__nmc_vv_change_prop % ##1 = number-only switch, ##2 = keyval settings, % ##3 = formula, ##4 = vv-list, ##5 = number-format spec., % #1 = \nmcCommand, #2 = cmd id, #3 = short-name cmd \cs_new_protected:Npn \nmc_define:NnN #1#2#3 { \NewDocumentCommand #1 { s O{} m O{} O{} } { \group_begin: \bool_set_eq:NN \l__nmc_num_only_bool ##1 \__nmc_initialize:n { #2 } \bool_if:NF \g__nmc_error_bool { \__nmc_settings:nn { #2 } { ##2 } } \bool_if:NF \g__nmc_error_bool { \__nmc_formula:nn { #2 } { ##3 } } \bool_if:NF \g__nmc_error_bool { \__nmc_trailing_args:nnn { #2 } { ##4 } { ##5 } } \bool_if:NF \g__nmc_error_bool { \use:c { __nmc_#2_process: } } \int_if_zero:nTF { \l__nmc_dbg_int } { \bool_if:NF \g__nmc_error_bool { \use:c { __nmc_#2_display: } } } { \__nmc_dbg_display:nn { \l__nmc_dbg_int } { #2 } } \group_end: } \ProvideDocumentCommand #3 {} { #1 } \cs_new_protected:cpn { __nmc_#2_vv_digest:N } ##1 {} \clist_map_inline:nn { initialize, formula, settings, process, display } { \cs_new_protected:cpn { __nmc_#2_##1: } {} } } \nmc_define:NnN \nmcEvaluate { eval } \eval % initialize \cs_new_protected:Npn \__nmc_initialize:n #1 { \bool_gset_false:N \g__nmc_error_bool \bool_set_false:N \l__nmc_sci_num_out_bool \bool_set_false:N \l__nmc_sci_num_x_bool \bool_set_false:N \l__nmc_sci_num_table_bool \bool_set_false:N \l__nmc_round_bool \tl_set:Nn \l__nmc_dbg_idiii_tl { vv-list } \int_zero:N \l__nmc_multi_int % \int_incr:N \l__nmc_depth_int \int_compare:nNnT \l__nmc_depth_int > { 1 } % for nesting { \bool_set_true:N \l__nmc_num_only_bool } \prop_concat:NNN \l__nmc_subst_var_prop \g__nmc_subst_var_prop \l__nmc_subst_var_prop \use:c { __nmc_#1_initialize: } } % #1 id, #2 settings \cs_new_protected:Npn \__nmc_settings:nn #1#2 { \__nmc_error_where:n { settings } \tl_if_empty:nF { #2 } { \keys_set_known:nn { numerica/generic } { #2 } \keys_set_known:xn { numerica/#1 }{ #2 } } \tl_if_empty:NT \l__nmc_multi_delim_tl { \tl_set_eq:NN \l__nmc_multi_delim_tl \c__nmc_vv_delim_tl } \use:c { __nmc_#1_settings: } \int_compare:nNnT \l__nmc_depth_int > { 1 } % for nesting { \int_zero:N \l__nmc_dbg_int } \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl } \cs_new_protected:Npn \__nmc_formula:nn #1#2 { \__nmc_error_where:n { formula } \tl_set:Nn \l__nmc_formula_tl { #2 } \tl_trim_spaces:N \l__nmc_formula_tl \use:c { __nmc_#1_formula: } } % #2=vv, #3=number format \cs_new_protected:Npn \__nmc_trailing_args:nnn #1#2#3 { \__nmc_error_where:n { variable=value~list } \tl_if_in:nnTF { #2 } { = }% vv-list { \__nmc_vv_extract_visible:nN { #2 } \l__nmc_vva_seq \use:c { __nmc_#1_vv_digest:N } \l__nmc_vva_seq \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl \__nmc_get_num_format:n { #3 } \tl_if_blank:nF { #3 } { \bool_set_true:N \l__nmc_round_bool } } { % empty vv-list \use:c { __nmc_#1_vv_digest:N } \c_empty_seq \bool_set_false:N \l__nmc_see_vv_bool \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl \__nmc_get_num_format:n { #2#3 } \tl_if_blank:nF { #2#3 } { \bool_set_true:N \l__nmc_round_bool } } } %%%%%%%%%% debug %%%%%%%%%% \cs_new_protected:Npn \__nmc_dbg_display:nn #1#2 { \__nmc_dbg_display:xnn { \mode_if_math:TF { ed }{ * } } { #1 } { #2 } \tl_clear:N \l__nmc_show_tl } \cs_new_protected:Npn \__nmc_dbg_display:nnn #1#2#3 { % #2 dbg int, #3 fn id \seq_reverse:N \l__nmc_vv_all_seq \raggedright \begin{ align#1 } \__nmc_if_mod_zero:nnT { #2 } { 2 } { \__nmc_dbg:Nnn \l__nmc_formula_tl { #2 } \l__nmc_dbg_idii_tl } \__nmc_if_mod_zero:nnT { #2 } { 3 } { \__nmc_dbg:Nnn \l__nmc_dbg_vv_tl { #2 } \l__nmc_dbg_idiii_tl } \__nmc_if_mod_zero:nnT { #2 } { 5 } { \__nmc_dbg_stored: \__nmc_dbg:Nnn \l_tmpa_tl { #2 } \l__nmc_dbg_idv_tl } \__nmc_if_mod_zero:nnT { #2 } { 7 } { \__nmc_dbg:Nnn \l__nmc_fp_expr_tl { #2 } { fp-form } } \__nmc_if_mod_zero:nnT { #2 } { 11 } {\__nmc_dbg:Nnn \l__nmc_show_tl { #2 } { LaTeX } } \end{ align#1 } \bool_set_false:N \l__nmc_dbg_count_bool } \cs_generate_variant:Nn \__nmc_dbg_display:nnn { x } \cs_new_protected:Npn \__nmc_dbg_vv_view:n #1 { \seq_set_eq:NN \l__nmc_vv_no_consts_seq \l__nmc_vv_all_seq \int_step_inline:nn { \seq_count:N \g__nmc_consts_vv_seq } { \seq_pop:NN \l__nmc_vv_no_consts_seq \l__nmc_toss_tl } \seq_reverse:N \l__nmc_vv_no_consts_seq \int_step_inline:nn { #1 } { \seq_pop:NN \l__nmc_vv_no_consts_seq \l__nmc_toss_tl } \tl_gset:Nx \l__nmc_dbg_vv_tl { \seq_use:Nn \l__nmc_vv_no_consts_seq {,~} } } \cs_new_protected:Npn \__nmc_dbg_get_data: { \seq_clear:N \l__nmc_dbg_stored_seq \__nmc_dbg_vv_view:n { 0 } \seq_map_inline:Nn \l__nmc_vv_no_consts_seq { \__nmc_split_eq:w ##1\q_stop \prop_get:NVN \l__nmc_subst_var_prop \l__nmc_eq_var_tl \l_tmpa_tl \tl_put_left:Nn \l_tmpa_tl { = } \tl_put_left:NV \l_tmpa_tl \l__nmc_eq_var_tl \seq_put_right:NV \l__nmc_dbg_stored_seq \l_tmpa_tl } } \cs_new_protected:Npn \__nmc_dbg_stored: { \seq_clear:N \l_tmpa_seq \seq_map_inline:Nn \l__nmc_dbg_stored_seq { \prop_get:NnNTF \l__nmc_subst_var_prop { ##1 } \l_tmpa_tl { \tl_put_left:Nn \l_tmpa_tl { ##1= } \seq_put_right:NV \l_tmpa_seq \l_tmpa_tl } { \seq_put_right:Nn \l_tmpa_seq { ##1 } } } \tl_gset:Nx \l_tmpa_tl { \seq_use:Nn \l_tmpa_seq {,~} } } \cs_new:Npn \__nmc_dbg:Nnn #1#2#3 { \bool_if:NT \l__nmc_dbg_count_bool { \\ } \hbox:n { #3:} & \quad \int_compare:nNnTF \l__nmc_depth_int > { 1 } { \hbox:n } { \vbox_top:n } { \tl_to_str:N #1 } \bool_set_true:N \l__nmc_dbg_count_bool } \cs_generate_variant:Nn \__nmc_dbg_display:nnnn { V, x } %%%%%%%%%% number-formatting routines %%%%%%%%%%% \int_zero_new:N \l__nmc_frac_out_int \bool_new:N \l__nmc_pad_zeros_bool \bool_new:N \l__nmc_sci_num_out_bool \cs_new_protected:Npn \__nmc_get_num_format:n #1 { \__nmc_error_where:n { result~format~spec } \tl_clear:N \l_tmpa_tl \str_set:Nn \l_tmpa_str { #1 } \int_zero:N \l__nmc_num_alt_int \str_if_in:nnTF { #1 } { ? } { \__nmc_num_bool_spec: } { \str_if_in:nnTF { #1 } { / } { \__nmc_num_frac_spec: } { \str_if_in:nnT { #1 } { * } { \bool_set_true:N \l__nmc_pad_zeros_bool \str_remove_all:Nn \l_tmpa_str { * } } } } \str_map_inline:Nn \l_tmpa_str { \str_if_in:nnTF { 1234567890- } { ##1 } { \tl_put_right:Nn \l_tmpa_tl { ##1 } } { \__nmc_num_sci_spec:n { ##1 } } } \tl_if_empty:NF \l_tmpa_tl { \int_set:Nn \l__nmc_round_int \l_tmpa_tl } \int_compare:nNnT { \l__nmc_depth_int } > { 2 } { \__nmc_num_deep_output:N \l_tmpa_tl } \bool_if:NF \g__nmc_error_bool { \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl } } \cs_new_protected:Npn \__nmc_num_bool_spec: { \bool_set_eq:NN \l__nmc_TF_out_bool \l__nmc_allow_TF_out_bool \int_incr:N \l__nmc_num_alt_int \str_remove_once:Nn \l_tmpa_str { ? } \str_if_in:NnT \l_tmpa_str { ? } { \int_incr:N \l__nmc_num_alt_int \str_remove_once:Nn \l_tmpa_str { ? } \str_if_in:NnT \l_tmpa_str { ? } { \int_incr:N \l__nmc_num_alt_int \str_remove_all:Nn \l_tmpa_str { ? } } } \bool_if:NT \l__nmc_num_only_bool { \int_set:Nn \l__nmc_num_alt_int { 1 } } } \cs_new_protected:Npn \__nmc_num_frac_spec: { \int_incr:N \l__nmc_frac_out_int % 1 \str_remove_once:Nn \l_tmpa_str { / } \str_if_in:NnTF \l_tmpa_str { / } { \int_incr:N \l__nmc_frac_out_int % 2 \str_if_in:NnTF \l_tmpa_str { t } { \int_incr:N \l__nmc_frac_out_int } % 3 { \str_if_in:NnT \l_tmpa_str { d } { \int_set:Nn \l__nmc_frac_out_int { 4 } } } } { \str_if_in:NnT \l_tmpa_str { s } { \int_set:Nn \l__nmc_frac_out_int { 5 } } } } \cs_new_protected:Npn \__nmc_num_sci_spec:n #1 { \str_case:nn { #1 } { { x } { \bool_set_true:N \l__nmc_sci_num_x_bool } { t } { \bool_set_true:N \l__nmc_sci_num_table_bool } } \tl_set:Nn \l__nmc_sci_num_out_tl { #1 } \bool_set_true:N \l__nmc_sci_num_out_bool \int_incr:N \l__nmc_num_alt_int } \cs_new_protected:Npn \__nmc_num_deep_output:N #1 { \bool_set_true:N \l__nmc_sci_num_out_bool \bool_set_false:N \l__nmc_sci_num_x_bool \bool_set_false:N \l__nmc_sci_num_table_bool \tl_set:Nn \l__nmc_sci_num_out_tl { e } \bool_set_false:N \l__nmc_pad_zeros_bool \int_zero:N \l__nmc_num_alt_int } %%%%%%%%%% % #1=fpify-ed in; #2=tl fmt'ed out; #3=int rndg; #4 sci bool \cs_new_protected:Npn \__nmc_num_format:nNnN #1#2#3#4 { \bool_if:NTF \l__nmc_TF_out_bool { \__nmc_num_bool_out:nNn { #1 } #2 { \l__nmc_num_alt_int } } { \int_if_zero:nTF \l__nmc_frac_out_int { \bool_if:NTF #4 { \exp_last_unbraced:Nx \__nmc_sci_output_aux:wNn { \fp_to_scientific:n { #1 } } \q_stop #2 { #3 } } { \__nmc_num_format_decimal:nNn { #1 } #2 { #3 } } \bool_if:NT \l__nmc_dec_comma_bool { \tl_replace_once:Nnn #2 {.} {,} } } { \__nmc_num_frac_out:nNn { #1 } #2 { #3 }} } } \cs_new_protected:Npn \__nmc_num_bool_out:nNn #1#2#3 { \fp_compare:nNnTF { 0 } = { round(#1, \l__nmc_round_int) } { \tl_set:Nx #2 { \clist_item:nn {0,F,\texttt{F}} { #3 } } } { \tl_set:Nx #2 { \clist_item:nn {1,T,\texttt{T}} { #3 } } } } \cs_new_protected:Npn \__nmc_num_frac_out:nNn #1#2#3 { \group_begin: \int_set:Nn \l_tmpa_int { \l__nmc_frac_denom_min_int - 1 } \fp_set:Nn \l_tmpc_fp { #1 } \fp_set_eq:NN \l_tmpb_fp \c_one_fp \fp_set:Nn \l_tmpa_fp { \l_tmpc_fp * \l_tmpa_int } \fp_do_until:nNnn { 0 } = { \l_tmpb_fp } { \int_incr:N \l_tmpa_int \int_compare:nNnTF { \l_tmpa_int } > { \l__nmc_frac_denom_max_int } { \__nmc_error_what:n { No~result~to~\int_use:N \l__nmc_round_int\ zeros~with~$ \int_use:N \l__nmc_frac_denom_min_int \le \texttt{denom} \le \int_use:N \l__nmc_frac_denom_max_int $~in } \fp_zero:N \l_tmpb_fp } { \fp_add:Nn \l_tmpa_fp { \l_tmpc_fp } \fp_set:Nn \l_tmpb_fp { round( ( \l_tmpa_fp - round( \l_tmpa_fp, 0 ) ) / \l_tmpa_int, #3 ) } } } \bool_if:NF \g__nmc_error_bool { \__nmc_num_frac_out_aux:xxNNN { \fp_to_int:n {abs(\l_tmpa_fp)} } { \int_use:N \l_tmpa_int } \l__nmca_tl \l__nmc_frac_out_int \l_tmpa_fp } \exp_args:NNNV \group_end: \tl_set:Nn #2 { \l__nmca_tl } } \cs_new_protected:Npn \__nmc_num_frac_out_aux:nnNNN #1#2#3#4#5 { \int_case:nn { #4 } { { 1 } { \tl_set:Nn #3 { #1 / #2 } } { 2 } { \tl_set:Nn #3 { \frac { #1 } { #2 } } } { 3 } { \tl_set:Nn #3 { \tfrac { #1 } { #2 } } } { 4 } { \tl_set:Nn #3 { \dfrac { #1 } { #2 } } } { 5 } { \cs_if_exist:NTF \sfrac { \tl_set:Nn #3 { \sfrac { #1 } { #2 } } } { \tl_set:Nn #3 { \scriptstyle #1 / #2 } } } } \fp_compare:nNnT { #5 } < { 0 } { \tl_put_left:Nn #3 {-} } } \cs_generate_variant:Nn \__nmc_num_frac_out_aux:nnNNN { xx } \cs_new_protected:Npn \__nmc_num_format_decimal:nNn #1#2#3 { \tl_set:Nx #2 { \fp_eval:n { 0 + round( #1, #3 ) } } \__nmc_error_fpflag: \bool_if:NF \g__nmc_error_bool { \int_set:Nn \l__nmc_num_sgn_int { \fp_sign:n { #2 } } \bool_lazy_and:nnT { \int_compare_p:nNn { #3 } > { 0 } } { \l__nmc_pad_zeros_bool } { \__nmc_num_pad:Nn #2 { #3 } } } } \cs_new_protected:Npn \__nmc_num_pad:Nn #1#2 { \tl_if_in:NnTF #1 { . } { \tl_set:Nx #1 { \__nmc_num_pad_aux:Vn #1 { #2 } } } { \tl_set:Nx #1 { \__nmc_num_pad_aux:Vn { #1.} { #2 } } } } \cs_new:Npn \__nmc_num_pad_aux:nn #1#2 { \__nmc_num_pad:wN #1\q_stop { #2 } } \cs_generate_variant:Nn \__nmc_num_pad_aux:nn { V } \cs_new:Npn \__nmc_num_pad:wN #1.#2\q_stop#3 { \int_if_zero:nTF { #3 } { #1 } { #1.#2\prg_replicate:nn { #3 - \tl_count:n { #2 } } { 0 } } } \cs_new_protected:Npn \__nmc_sci_output_aux:wNn #1e#2\q_stop#3#4 { % #1e#2=fp input; #3=formatted tl out; #4 = rounding \tl_set:Nx #3 { \fp_eval:n { 0 + round( #1, #4 ) } } \__nmc_error_fpflag: \bool_if:NF \g__nmc_error_bool { \int_set:Nn \l__nmc_sci_expon_int { #2 } \tl_if_eq:VnT #3 { 10 } { \int_incr:N \l__nmc_sci_expon_int \tl_set:Nn #3 { 1 } } \bool_if:NT \l__nmc_pad_zeros_bool { \__nmc_num_pad:Nn #3 { #4 } } \bool_lazy_or:nnT { !\int_if_zero_p:n { \l__nmc_sci_expon_int } } { \int_compare_p:nNn { \l__nmc_num_alt_int } > { 1 } } { \bool_if:NTF \l__nmc_sci_num_table_bool { \tl_put_left:Nx #3 { \__nmc_sci_num_table:n { #2 } } } { \tl_put_right:Nx #3 { \__nmc_sci_write:n { \int_use:N \l__nmc_sci_expon_int } } } } } \int_set:Nn \l__nmc_num_sgn_int { \fp_sign:n { #1 } } % tables } \cs_new:Npn \__nmc_sci_write:n #1 { % #1 exponent \int_compare:nNnTF { \l__nmc_depth_int } > { 2 } { e#1 } { \bool_if:NTF \l__nmc_sci_num_x_bool { \exp_not:N \times 10^{#1} } { \text{ \l__nmc_sci_num_out_tl {#1} } } } } \cs_new:Npn \__nmc_sci_num_table:n #1 { (#1)\exp_not:n {\,} } % vv-list routines %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \cs_new_protected:Npn \__nmc_vv_extract_visible:nN #1#2 { % #2 reverses #1 \seq_clear:N \l__nmc_vv_visible_seq \seq_set_split:NVn \l__nmc_vvb_seq \c__nmc_vv_delim_tl { #1 } \seq_remove_all:Nn \l__nmc_vvb_seq {} \seq_clear:N #2 \seq_map_inline:Nn \l__nmc_vvb_seq % remove { } from {var} { \tl_if_head_is_group:nTF { ##1 } { \seq_put_left:Nx #2 { \tl_head:n { ##1 } \tl_tail:n { ##1 } } } { \seq_put_right:Nn \l__nmc_vv_visible_seq { ##1 } \seq_put_left:Nn #2 { ##1 } } } \seq_if_empty:NTF \l__nmc_vv_visible_seq { \bool_set_false:N \l__nmc_see_vv_bool } { \tl_replace_once:Nnx \l__nmc_vv_tl { vv } { \seq_use:NV \l__nmc_vv_visible_seq \c__nmc_vv_delim_tl } } } % #1 is reversed vv seq \cs_new_protected:Npn \__nmc_vv_digest:N #1 { \seq_concat:NNN \l__nmc_vv_all_seq \g__nmc_consts_vv_seq #1 \bool_if:NT \l__nmc_multitok_bool { \__nmc_prep_multitok:NN \l__nmc_vv_all_seq \l__nmc_formula_tl } \__nmc_vv_get_vars_vals:NN \l__nmc_vv_all_seq \c_empty_prop } % #1(seq) vv-list;#2(prop) changed vars (implicit-mode) \cs_new_protected:Npn \__nmc_vv_get_vars_vals:NN #1#2 { \seq_set_eq:NN \l_tmpa_seq #1 \seq_clear:N \l__nmc_calc_fn_seq \seq_map_inline:Nn \l_tmpa_seq { \__nmc_vv_split_item:n { ##1 } \bool_if:NT \g__nmc_error_bool { \seq_map_break: } \__nmc_vv_record:NVN \l__nmc_eq_var_tl \l__nmc_eq_val_tl #2 \bool_if:NTF \g__nmc_error_bool { \seq_map_break: } { \seq_put_right:Nn \l__nmc_calc_fn_seq { ##1 } } } } \cs_new_protected:Npn \__nmc_vv_get_vars_vals_lims:NN #1#2 { % for summation, integration limits \__nmc_vv_split_item:V #1 \bool_if:NF \g__nmc_error_bool { \__nmc_vv_record:NVN \l__nmc_eq_var_tl \l__nmc_eq_val_tl #2 } } % changed var=vals in prop #3 \cs_new_protected:Npn \__nmc_vv_record:NnN #1#2#3 { \prop_get:NVNF #3 #1 \l__nmc_vv_fp_expr_tl { \tl_clear:N \l__nmc_vv_fp_expr_tl \__nmc_fpify:nN { #2 } \l__nmc_vv_fp_expr_tl } \bool_if:nF { \l__nmc_vv_val_only_bool || \g__nmc_error_bool } { \__nmc_vv_write:VN #1 \l__nmc_vv_fp_expr_tl } } \cs_generate_variant:Nn \__nmc_vv_record:NnN { NV } % #1 = var; #2 = val as fp expr. \cs_new_protected:Npn \__nmc_vv_write:nN #1#2 { \tl_if_empty:NF #2 { \tl_if_eq:VnTF #2 { inf } { \prop_put:Nnn \l__nmc_subst_var_prop { #1 } { inf } } { \prop_put:Nnx \l__nmc_subst_var_prop { #1 } { \fp_to_tl:n {#2} } } \__nmc_error_fpflag: } } \cs_generate_variant:Nn \__nmc_vv_write:nN { V } \cs_new_protected:Npn \__nmc_vv_split_item:n #1 { \bool_set_false:N \l__nmc_vv_val_only_bool \tl_if_in:nnTF { #1 } { = } { \__nmc_split_eq:w #1\q_stop \tl_if_empty:NT \l__nmc_eq_val_tl { \__nmc_error_what:n { No~value~for~\__nmc_verb:N\l__nmc_eq_var_tl\ in } } } { \bool_set_true:N \l__nmc_vv_val_only_bool \tl_set:Nn \l__nmc_eq_val_tl { #1 } } } \cs_generate_variant:Nn \__nmc_vv_split_item:n { V } \cs_new_protected:Npn \__nmc_split_eq:w #1=#2\q_stop { \tl_set:Nn \l__nmc_eq_var_tl { #1 } \tl_trim_spaces:N \l__nmc_eq_var_tl \tl_set:Nn \l__nmc_eq_val_tl { #2 } } %%%%%%%%%%%% eval-specific routines %%%%%%%%%%%%% \cs_set_protected:Npn \__nmc_eval_initialize: { \tl_set:Nn \l__nmc_dbg_idii_tl { formula } \tl_set:Nn \l__nmc_dbg_idv_tl { stored } \tl_clear:N \l__nmc_show_tl \__nmc_env_initialize: } \cs_new_protected:Npn \__nmc_env_initialize: { \int_zero:N \l__nmc_env_def_int \bool_set_true:N \l__nmc_allow_TF_out_bool \bool_if:NTF \l__nmc_num_only_bool { \bool_set_false:N \l__nmc_see_formula_bool \bool_set_false:N \l__nmc_see_vv_bool \__nmc_math_env_delims:nn {}{} \tl_clear:N \l__nmc_env_arg_tl \tl_set:Nn \l__nmc_multi_sep_tl { ~ } \int_set:Nn \l__nmc_env_def_int { 2 } } { \mode_if_math:T { \int_incr:N \l__nmc_env_def_int \prop_get:NVNT \g__nmc_envi_prop \@currenvir \l_tmpb_tl { \__nmc_env_params_def:Nnn \l_tmpb_tl { 0 } { 1 } \__nmc_math_env_delims:nn {}{} \tl_clear:N \l__nmc_env_arg_tl \int_incr:N \l__nmc_env_def_int } } } } \cs_set_protected:Npn \__nmc_eval_settings: { \__nmc_env_settings: } \cs_set_protected:Npn \__nmc_env_settings: { \int_if_zero:nTF \l__nmc_env_def_int % math mode F/T { \exp_args:NV \__nmc_env_s_zero:n \l__nmc_env_s_tl } { \exp_args:NV \__nmc_env_s_one:n \l__nmc_env_s_tl } } \cs_new_protected:Npn \__nmc_env_s_zero:n #1 { \prop_get:NnNTF \g__nmc_envi_prop { #1 } \l_tmpb_tl { \__nmc_error_what:n { Math~mode~needed~for~\__nmc_verb:n {#1}\ environment~in } } { \prop_if_in:NnT \g__nmc_env_prop { #1 } { \__nmc_env_delims_outer:n { #1 } \int_incr:N \l__nmc_env_def_int } } } \cs_new_protected:Npn \__nmc_env_s_one:n #1 { \int_compare:nNnT { \l__nmc_env_def_int } = { 1 } { \prop_get:NnNT \g__nmc_envi_prop { #1 } \l_tmpb_tl { \__nmc_env_params_def:Nnn \l_tmpb_tl { 1 } { 1 } \int_incr:N \l__nmc_env_def_int } } } \cs_set_protected:Npn \__nmc_eval_formula: { \__nmc_env_formula: } \cs_new_protected:Npn \__nmc_env_formula: { \__nmc_env_extract_formula:x { \tl_head:N \l__nmc_formula_tl } \int_if_zero:nTF \l__nmc_env_def_int % m mode F, no or invalid env { \exp_args:NVV \__nmc_env_f_zero:nn \l__nmc_env_s_tl \l__nmc_env_f_tl } { \int_compare:nNnT { \l__nmc_env_def_int } = { 1 } { \exp_args:NVV \__nmc_env_f_one:nn \l__nmc_env_s_tl \l__nmc_env_f_tl } % mmode T or set env } \__nmc_env_params_set:oooN \l__nmc_s_equals_tl \l__nmc_s_vv_tl \l__nmc_s_multi_sep_tl \l__nmc_env_s_arg_tl \bool_if:NT \l__nmc_env_rbrace_bool { \exp_args:NV \__nmc_env_rbrace:n \l__nmc_env_rbrace_tl \bool_if:NF \l__nmc_vv_settings_bool { \tl_set:Nn \l__nmc_vv_tl { ,\mskip 12muplus6muminus6mu (vv) } } } } \cs_new_protected:Npn \__nmc_env_rbrace:n #1 { \prop_if_in:NVT \g__nmc_envi_prop \l__nmc_env_tl { \tl_if_blank:nTF { #1 } { \tl_set:Nn \l__nmcA_tl { .\q_nil } } { \tl_set:Nn \l__nmcA_tl { #1\q_nil } } \__nmc_next: \quark_if_nil:NTF \l__nmcC_tl { \tl_set:Nn \l__nmc_env_sp_rbrace_tl { \right } \tl_set_eq:NN \l__nmc_env_rbrace_tl \l__nmcB_tl } { \tl_concat:NNN \l__nmc_env_sp_rbrace_tl \l__nmcB_tl \right \tl_set_eq:NN \l__nmc_env_rbrace_tl \l__nmcC_tl } \tl_set:Nn \l__nmc_multi_sep_tl { \\ } } } \cs_new_protected:Npn \__nmc_env_f_zero:nn #1#2 { \prop_get:NnNTF \g__nmc_envi_prop { #2 } \l_tmpb_tl { \__nmc_error_what:n { Math~mode~needed~for~\__nmc_verb:n {#2}\ environment~in } } { \prop_get:NnNTF \g__nmc_env_prop { #2 } \l_tmpb_tl { \__nmc_env_params_def:Nnn \l_tmpb_tl { 1 } { 1 } } { \__nmc_env_f_zero_aux:nn { #1 } { #2 } } } } \cs_new_protected:Npn \__nmc_env_f_zero_aux:nn #1#2 { \bool_if:nTF { \tl_if_blank_p:n { #1 } && \tl_if_blank_p:n { #2 } } { \prop_get:NnN \g__nmc_env_prop { $ } \l_tmpb_tl \__nmc_env_params_def:Nnn \l_tmpb_tl { 0 } { 0 } } { \tl_if_empty:nTF { #1 } { \__nmc_error_what:n { Unknown~math~environment~ \__nmc_verb:n { #2 }~in } } { \__nmc_error_where:n { settings } \__nmc_error_what:n { Unknown~math~environment~ \__nmc_verb:n { #1 }~in } } } } \cs_new_protected:Npn \__nmc_env_f_one:nn #1#2 { \prop_get:NnNTF \g__nmc_envi_prop { #2 } \l_tmpb_tl { \__nmc_env_params_def:Nnn \l_tmpb_tl { 1 } { 1 } \mode_if_math:F { \tl_concat:NNN \l__nmc_math_delimi_tl \l__nmc_outer_delimi_tl\l__nmc_math_delimi_tl \tl_concat:NNN \l__nmc_math_delimii_tl \l__nmc_math_delimii_tl \l__nmc_outer_delimii_tl } } { \mode_if_math:TF { \exp_args:NV \__nmc_env_params_def:nn \@currenvir { 0 } \__nmc_math_env_delims:nn {}{} } { \__nmc_env_params_def:nn { #1 } { 1 } } } } \cs_new_protected:Npn \__nmc_env_params_def:nn #1#2 { \prop_get:NnNTF \g__nmc_env_prop { #1 } \l_tmpb_tl { \__nmc_env_params_def:Nnn \l_tmpb_tl { #2 } { 1 } } { \prop_get:NnN \g__nmc_env_prop { $ } \l_tmpb_tl \__nmc_env_params_def:Nnn \l_tmpb_tl { 0 } { 0 } } } \cs_new_protected:Npn \__nmc_env_params_def:Nnn #1#2#3 { #1 \__nmc_int_to_bool:Nn \l__nmc_see_formula_bool { #2 } \__nmc_int_to_bool:Nn \l__nmc_see_vv_bool { #3 } } \cs_new_protected:Npn \__nmc_env_params_set:nnnN #1#2#3#4 { \tl_if_empty:nF { #1 } { \tl_set:Nn \l__nmc_equals_tl { #1 } } \bool_if:NT \l__nmc_vv_settings_bool { \tl_set:Nn \l__nmc_vv_tl { #2 } } \tl_if_empty:nF { #3 } { \tl_set:Nn \l__nmc_multi_sep_tl { #3 } } \tl_if_empty:NF { #4 } { \tl_set_eq:NN \l__nmc_env_arg_tl #4 } \int_if_zero:nF { 1 + \l__nmc_see_force_int } { \__nmc_int_to_bool:Nn \l__nmc_see_formula_bool { \l__nmc_see_force_int } } } \cs_generate_variant:Nn \__nmc_env_params_set:nnnN { ooo } \tl_new:N \l__nmc_env_f_tl \cs_new_protected:Npn \__nmc_env_extract_formula:n #1 { \str_case:nn {#1} { {$} { \__nmc_env_extract_formula_aux:n {$} } {\(} { \__nmc_env_extract_formula_aux:n {\(} } {\[} { \__nmc_env_extract_formula_aux:n {\[} } {\begin} { \tl_set:Nx \l__nmc_env_f_tl { \tl_item:Nn \l__nmc_formula_tl { 2 } } \tl_set:Nx \l__nmc_formula_tl { \tl_range:Nnn\l__nmc_formula_tl {3}{-3} } } } } \cs_generate_variant:Nn \__nmc_env_extract_formula:n { x } \cs_new_protected:Npn \__nmc_env_extract_formula_aux:n #1 { \tl_set:Nx \l__nmc_formula_tl { \tl_range:Nnn\l__nmc_formula_tl {2}{-2} } \tl_set:Nn \l__nmc_env_f_tl { #1 } } \cs_new_protected:Npn \__nmc_math_env_delims:nn #1#2 { \tl_set:Nn \l__nmc_math_delimi_tl {#1} \tl_set:Nn \l__nmc_math_delimii_tl {#2} } \cs_new_protected:Npn \__nmc_math_env_delims:n #1 { \__nmc_math_env_delims:nn { \begin{#1} } { \end{#1} } } \cs_new_protected:Npn \__nmc_env_delims_outer:n #1 { \str_case:nnF {#1} { {$} { \__nmc_math_env_delims:nn {$}{$} } {\(} { \__nmc_math_env_delims:nn {\(}{\)} } {\[} { \__nmc_math_env_delims:nn {\[}{\]} } } { \__nmc_math_env_delims:n {#1} } \tl_set_eq:NN \l__nmc_outer_delimi_tl \l__nmc_math_delimi_tl \tl_set_eq:NN \l__nmc_outer_delimii_tl \l__nmc_math_delimii_tl } \cs_generate_variant:Nn \__nmc_env_delims_outer:n { V } % \cs_set_protected:Npn \__nmc_eval_vv_digest:N #1 { \__nmc_vv_digest:N #1 } % \cs_set_protected:Npn \__nmc_eval_process: { \__nmc_error_where:n { formula } % prepare \seq_set_split:NVV \l__nmc_multi_seq \l__nmc_multi_delim_tl \l__nmc_formula_tl \seq_remove_all:Nn \l__nmc_multi_seq {} \int_set:Nn \l__nmc_multi_int { \seq_count:N \l__nmc_multi_seq } % loop: process -> display/debug \seq_map_variable:NNn \l__nmc_multi_seq \l__nmc_formula_tl { \int_decr:N \l__nmc_multi_int \tl_clear:N \l__nmc_display_tl \tl_set_eq:NN \l__nmc_formula_dup_tl \l__nmc_formula_tl \tl_clear:N \l__nmc_fp_expr_tl \__nmc_fpify:VN \l__nmc_formula_tl \l__nmc_fp_expr_tl \bool_if:NF \g__nmc_error_bool { \tl_set:Nx \l__nmc_result_tl { \fp_to_tl:n { \l__nmc_fp_expr_tl } } \__nmc_error_fpflag: } \bool_if:NT \g__nmc_error_bool { \seq_map_break: } \int_compare:nNnTF { \l__nmc_depth_int } < { 3 } { \__nmc_eval_process_aux: } { \tl_put_right:NV \l__nmc_show_tl \l__nmc_result_tl } } \int_if_zero:nF \l__nmc_dbg_int { \__nmc_dbg_get_data: \__nmc_if_mod_zero:nnT \l__nmc_dbg_int { 11 } { \__nmc_eval_display: } } } \cs_new_protected:Npn \__nmc_eval_process_aux: { \__nmc_num_format:nNnN { \l__nmc_result_tl } \l__nmc_result_tl { \l__nmc_round_int } \l__nmc_sci_num_out_bool \tl_put_right:Nx \l__nmc_display_tl { \bool_if:NT \l__nmc_see_formula_bool { \exp_not:o \l__nmc_formula_dup_tl \bool_if:NTF \l__nmc_TF_out_bool { \rightarrow } { \l__nmc_equals_tl } } \exp_not:o \l__nmc_result_tl \bool_if:nT { \l__nmc_see_vv_bool && !\l__nmc_env_rbrace_bool } { \exp_not:o \l__nmc_vv_tl } } \int_if_zero:nF { \l__nmc_multi_int } { \__nmc_eval_rdisplay:ooo \l__nmc_display_tl \l__nmc_multi_punc_tl \l__nmc_multi_sep_tl } } \cs_set_protected:Npn \__nmc_eval_display: { \tl_gset:NV \g__nmc_reuse_tl \l__nmc_result_tl \__nmc_eval_rdisplay:ooo \l__nmc_display_tl \l__nmc_punc_tl \l__nmc_math_delimii_tl \bool_if:NTF \l__nmc_env_rbrace_bool { \bool_if:NF \l__nmc_see_vv_bool { \tl_clear:N \l__nmc_vv_tl } \__nmc_eval_rdisplay:ooo \l__nmc_env_sp_rbrace_tl \l__nmc_env_rbrace_tl \l__nmc_vv_tl \__nmc_eval_ldisplay:noo {\left.} \l__nmc_math_delimi_tl \l__nmc_env_arg_tl } { \__nmc_eval_ldisplay:noo {} \l__nmc_math_delimi_tl \l__nmc_env_arg_tl } \__nmc_if_mod_zero:nnF { \l__nmc_dbg_int } { 11 } { \mode_if_math:TF { \exp_after:wN \group_end: \l__nmc_show_tl \group_begin: } { \l__nmc_show_tl } } } \cs_new_protected:Npn \__nmc_eval_rdisplay:nnn #1#2#3 { \tl_put_right:Nn \l__nmc_show_tl { #1 #2 #3 } } \cs_generate_variant:Nn \__nmc_eval_rdisplay:nnn { ooo } \cs_new_protected:Npn \__nmc_eval_ldisplay:nnn #1#2#3 { \tl_if_blank:nTF { #3 } { \tl_put_left:Nn \l__nmc_show_tl { #1 #2 } } { \tl_put_left:Nn \l__nmc_show_tl { #1 #2 {#3} } } } \cs_generate_variant:Nn \__nmc_eval_ldisplay:nnn { noo } %%%%%%%%%%%% fpify LaTeX math expr %%%%%%%%%%%%% \bool_new:N \l__nmc_insert_aster_bool \tl_new:N \l__nmc_subst_tl \tl_new:N \l__nmc_accum_tl \tl_new:N \l__nmc_arg_tl % unary functions \tl_new:N \l__nmc_fn_tl \tl_new:N \l__nmc_fn_arg_tl \tl_new:N \l__nmc_power_arg_tl \bool_new:N \l__nmc_hyperbolic_bool \bool_new:N \l__nmc_trig_bool % factorial \fp_new:N \l__nmc_fact_fp \tl_new:N \l__nmc_fact_arg_tl % n-ary \int_new:N \l_tmpc_int \int_new:N \l_tmpd_int \bool_new:N \l__nmc_comma_nary_bool % sqrt \tl_new:N \l__nmc_ubrace_n_tl % binom \tl_new:N \l__nmc_binom_top_tl \tl_new:N \l__nmc_binom_bot_tl % sum/prod \tl_new:N \l__nmc_sum_var_tl \tl_new:N \l__nmc_summand_tl \tl_new:N \l__nmc_sum_op_tl \tl_new:N \l__nmc_sum_type_tl \tl_new:N \l__nmc_sum_typei_tl \tl_new:N \g__nmc_sum_A_tl \bool_new:N \l__nmc_sum_bool \int_new:N \l__nmc_sum_index_int \int_new:N \l__nmc_sum_end_int \int_new:N \l__nmc_sum_round_int \int_new:N \l__nmc_suma_int \int_new:N \l__nmc_sumb_int \fp_new:N \l__nmc_sum_total_fp \fp_new:N \l__nmc_sum_prev_fp \fp_new:N \l__nmc_sum_rounded_fp % #1 = latex expr #2 = fp-ified result \cs_new_protected:Npn \__nmc_fpify:nN #1#2 { \group_begin: \bool_set_false:N \l__nmc_superscript_bool \bool_set_false:N \l__nmc_insert_aster_bool \bool_set_false:N \l__nmc_trig_bool \tl_clear:N \l__nmc_accum_tl \tl_clear:N \l__nmcC_tl \tl_if_empty:nTF { #1 } { \__nmc_error_what:n { Empty~argument~to~fp-ify~in } } { \tl_set:Nn \l__nmcA_tl { #1\q_nil } } \bool_until_do:nn { \quark_if_nil_p:N \l__nmcC_tl || \g__nmc_error_bool } { \tl_clear:N \l__nmc_arg_tl \__nmc_next: \prop_get:NVNTF \g__nmc_class_prop \l__nmcB_tl \l_tmpb_tl { \exp_last_unbraced:NV \use_i:nn \l_tmpb_tl } { \tl_if_empty:NF \l__nmcB_tl { \__nmc_fpify_var: } } } \exp_args:NNNV \group_end: \tl_put_right:Nn #2 \l__nmc_accum_tl } \cs_generate_variant:Nn \__nmc_fpify:nN { V } % (fpify) #2, append to #1 \cs_new_protected:Npn \__nmc_accum_fpify_parenth:NN #1#2 { \group_begin: \tl_clear:N \l_tmpa_tl \__nmc_fpify:VN #2 \l_tmpa_tl \exp_args:NNNV \group_end: \__nmc_accum_fn_parenth:Nnn #1\l_tmpa_tl{} } % (fp-ify) next braced arg, append to #1 \cs_new_protected:Npn \__nmc_fpify_next_braced:N #1 { \__nmc_next: \__nmc_accum_fpify_parenth:NN #1 \l__nmcB_tl } %%%%%%%%%% \cs_new_protected:Npn \__nmc_fpify_unknown: { \exp_args:NnV\str_if_in:nnTF { )]\}\rbrace } \l__nmcB_tl { \__nmc_error_what:n { Unmatched~\__nmc_verb:N\l__nmcB_tl\ in } } { \tl_if_single:NTF \l__nmcB_tl { \__nmc_error_what:n { Unknown~token~\__nmc_verb:V\l__nmcB_tl\ in } } { \__nmc_fpify:VN \l__nmcB_tl \l__nmc_accum_tl } % brace group } } % to ensure e.g. 3*4 instead of 34 \cs_new_protected:Npn \__nmc_insert_aster: { \bool_if:NT \l__nmc_insert_aster_bool { \tl_put_right:Nn \l__nmc_accum_tl { * } } } \cs_new_protected:Npn \__nmc_fpify_dec: { \__nmc_get_dec:NN \l__nmc_fact_arg_tl \c_false_bool \tl_if_eq:VnF \l__nmcC_tl { ! } { \__nmc_insert_aster: \tl_put_right:NV \l__nmc_accum_tl \l__nmc_fact_arg_tl \bool_set_true:N \l__nmc_insert_aster_bool } } \cs_new_protected:Npn \__nmc_fpify_var: { % ( ) in case var < 0 raised to power \prop_get:NVNTF \l__nmc_subst_var_prop \l__nmcB_tl \l__nmc_subst_tl { \tl_set_eq:NN \l__nmc_fact_arg_tl \l__nmc_subst_tl \tl_if_in:noF { ! } \l__nmcC_tl { \__nmc_accum_fn_parenth:NVn \l__nmc_accum_tl \l__nmc_subst_tl {} \bool_set_true:N \l__nmc_insert_aster_bool } } { \tl_trim_spaces:N \l__nmcB_tl \tl_if_empty:NF \l__nmcB_tl { \__nmc_fpify_unknown:{} } } } \cs_new_protected:Npn \__nmc_fpify_const: { % if const used as var \prop_get:NVNTF \l__nmc_subst_var_prop \l__nmcB_tl \l__nmc_subst_tl { \__nmc_fpify_var: } { \prop_get:NVN \g__nmc_subst_fpfn_prop \l__nmcB_tl \l__nmc_subst_tl \tl_if_eq:VnTF \l__nmcC_tl { ! } { \tl_clear:N \l__nmc_fact_arg_tl } { \tl_put_right:NV \l__nmc_accum_tl \l__nmc_subst_tl } \bool_set_true:N \l__nmc_insert_aster_bool } } \cs_new_protected:Npn \__nmc_fpify_arith: { \tl_put_right:NV \l__nmc_accum_tl \l__nmcB_tl \bool_set_false:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_slash: { \tl_put_right:NV \l__nmc_accum_tl \l__nmcB_tl \__nmc_delim_arg:Nnn \l__nmc_arg_tl { 1 } { \c__nmc_uny_int } \__nmc_accum_fpify_parenth:NN \l__nmc_accum_tl \l__nmc_arg_tl \bool_set_true:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_arith_alt: { \prop_get:NVN \g__nmc_subst_fpfn_prop \l__nmcB_tl \l__nmcB_tl \tl_put_right:NV \l__nmc_accum_tl \l__nmcB_tl \bool_set_false:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_comparison: { \tl_if_in:noTF { <=> } \l__nmcC_tl { \tl_concat:NNN \l_tmpa_tl \l__nmcB_tl \l__nmcC_tl \__nmc_next: } { \prop_get:NVNF \g__nmc_subst_fpfn_prop \l__nmcB_tl \l_tmpa_tl { \tl_set_eq:NN \l_tmpa_tl \l__nmcB_tl } % < = > } \__nmc_delim_arg:Nnn \l__nmc_arg_tl { 1 } { \c__nmc_cmp_int } \tl_clear:N \l_tmpb_tl \__nmc_fpify:VN \l__nmc_arg_tl \l_tmpb_tl \bool_if:NF \g__nmc_error_bool { \__nmc_accum_fn_parenth:NVn \l__nmc_accum_tl \l_tmpb_tl { - } \tl_set:Nx \l__nmc_accum_tl { round( \l__nmc_accum_tl, \int_use:N \l__nmc_round_int ) } \tl_put_right:NV \l__nmc_accum_tl \l_tmpa_tl \tl_put_right:Nn \l__nmc_accum_tl { 0 } } } \cs_new_protected:Npn \__nmc_fpify_andor: { \prop_get:NVN \g__nmc_subst_fpfn_prop \l__nmcB_tl \l_tmpa_tl \tl_put_right:NV \l__nmc_accum_tl \l_tmpa_tl \__nmc_delim_arg:Nnn \l__nmc_arg_tl { 1 } { \c__nmc_and_int } \tl_clear:N \l_tmpa_tl \__nmc_fpify:VN \l__nmc_arg_tl \l_tmpa_tl \tl_put_right:NV \l__nmc_accum_tl \l_tmpa_tl \bool_set_false:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_lparen: { \__nmc_get_arg_L:VN \l__nmcB_tl \l__nmc_arg_tl \tl_set_eq:NN \l__nmc_fact_arg_tl \l__nmc_arg_tl \tl_if_eq:VnTF \l__nmcC_tl { ! } { \bool_set_false:N \l__nmc_insert_aster_bool } { \__nmc_accum_fpify_parenth:NN \l__nmc_accum_tl \l__nmc_arg_tl \bool_set_true:N \l__nmc_insert_aster_bool } } \cs_new_protected:Npn \__nmc_fpify_lvert: { \tl_if_eq:VnTF \l__nmcB_tl { | } { \tl_set:Nn \l__nmc_L_tl { \lvert } \__nmc_absval_arg:N \l__nmc_arg_tl \tl_set:Nn \l__nmc_R_tl { \rvert } } { \tl_set_eq:NN \l__nmc_L_tl \l__nmcB_tl \__nmc_get_arg_L:VN \l__nmcB_tl \l__nmc_arg_tl } \__nmc_fpify_lvert_aux: } \cs_new_protected:Npn \__nmc_fpify_lvert_aux: { \tl_if_eq:VnTF \l__nmcC_tl { ! } { \tl_set:NV \l__nmc_fact_arg_tl \l__nmc_L_tl \tl_put_right:NV \l__nmc_fact_arg_tl \l__nmc_arg_tl \tl_put_right:NV \l__nmc_fact_arg_tl \l__nmc_R_tl } { \tl_clear:N \l_tmpa_tl \__nmc_fpify:VN \l__nmc_arg_tl \l_tmpa_tl \str_case:onF \l__nmc_L_tl { { \lvert } { \tl_put_right:Nn \l__nmc_accum_tl { abs( } } { \lceil } { \tl_put_right:Nn \l__nmc_accum_tl { ceil( } } { \lfloor } { \tl_put_right:Nn \l__nmc_accum_tl { floor( } } { | } { \tl_put_right:Nn \l__nmc_accum_tl { abs( } } { / } { \tl_put_right:Nn \l__nmc_accum_tl { / } } } { \tl_put_right:Nn \l__nmc_accum_tl { ( } } \tl_put_right:NV \l__nmc_accum_tl \l_tmpa_tl \tl_if_eq:VnF \l__nmc_R_tl { . } { \tl_put_right:Nn \l__nmc_accum_tl { ) } \bool_set_true:N \l__nmc_insert_aster_bool } } } \cs_new_protected:Npn \__nmc_fpify_lmod: { \tl_set_eq:NN \l__nmc_L_tl \l__nmcB_tl \prop_get:NVN \g__nmc_subst_misc_prop \l__nmc_L_tl \l__nmc_R_tl \str_case:on \l__nmcC_tl { { | } { \__nmc_fpify_lmod_abs:V \l__nmc_L_tl } { . } { \__nmc_next: } %\__nmc_fpify_lmod_aux:V \l__nmc_L_tl } { / } %{ \__nmc_next: } { \tl_put_right:Nn \l__nmc_accum_tl { / } \__nmc_fpify_lmod_aux:V \l__nmc_L_tl } } } \cs_new_protected:Npn \__nmc_fpify_lmod_abs:n #1 { \__nmc_next: \tl_put_right:Nn \l__nmc_accum_tl { abs( } \exp_args:NNNV\__nmc_get_arg_LR:NNN { #1 } \l__nmc_arg_tl \l__nmc_R_tl \__nmc_next: \tl_clear:N \l_tmpa_tl \__nmc_fpify:VN \l__nmc_arg_tl \l_tmpa_tl \tl_put_right:NV \l__nmc_accum_tl \l_tmpa_tl \tl_put_right:Nn \l__nmc_accum_tl { ) } \bool_set_true:N \l__nmc_insert_aster_bool } \cs_generate_variant:Nn \__nmc_fpify_lmod_abs:n { V } \cs_new_protected:Npn \__nmc_fpify_lmod_aux:n #1 { \__nmc_next: \exp_args:NNNV\__nmc_get_arg_LR:NNN #1 \l__nmc_arg_tl \l__nmc_R_tl \tl_if_eq:VnT \l__nmcC_tl { . } { \__nmc_next: } \tl_clear:N \l_tmpa_tl \__nmc_fpify:VN \l__nmc_arg_tl \l_tmpa_tl \tl_put_right:NV \l__nmc_accum_tl \l_tmpa_tl \bool_set_true:N \l__nmc_insert_aster_bool } \cs_generate_variant:Nn \__nmc_fpify_lmod_aux:n { V } \cs_new_protected:Npn \__nmc_fpify_rmod: { \tl_if_eq:VnT \l__nmcC_tl { . } { \__nmc_next: } } \cs_new_protected:Npn \__nmc_fpify_unary: { \tl_set:NV \l__nmc_fn_tl \l__nmcB_tl \tl_if_eq:VnTF \l__nmcC_tl { ^ } { \__nmc_fpify_unary_superscript: } { \prop_get:NVN \g__nmc_subst_fpfn_prop \l__nmc_fn_tl \l__nmc_fn_tl } \str_if_in:NnTF \l__nmc_fn_tl { h } { \bool_set_true:N \l__nmc_hyperbolic_bool } { \bool_set_false:N \l__nmc_hyperbolic_bool \bool_set_true:N \l__nmc_trig_bool } % get fn arg \__nmc_delim_arg:Nnn \l__nmc_arg_tl { 1 } { \c__nmc_uny_int } \tl_clear:N \l__nmc_fn_arg_tl \__nmc_fpify:VN \l__nmc_arg_tl \l__nmc_fn_arg_tl \bool_if:NT \l__nmc_hyperbolic_bool { \tl_set:Nx \l__nmc_fn_tl { \__nmc_fpify_unary_hyperbolic:N \l__nmc_fn_arg_tl } } % append fn \bool_if:NTF \l__nmc_hyperbolic_bool { \tl_put_right:NV \l__nmc_accum_tl \l__nmc_fn_tl } { \__nmc_accum_fn_parenth:NVn \l__nmc_accum_tl \l__nmc_fn_arg_tl \l__nmc_fn_tl } \bool_if:NT \l__nmc_superscript_bool { % e.g. \sin^{2} \tl_put_right:Nn \l__nmc_accum_tl { ^ } \tl_put_right:NV \l__nmc_accum_tl \l__nmc_power_arg_tl \bool_set_false:N \l__nmc_superscript_bool } \bool_set_true:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_unary_superscript: { \__nmc_next: \tl_clear:N \l__nmc_power_arg_tl \__nmc_fpify_next_braced:N \l__nmc_power_arg_tl \tl_if_eq:VnTF \l__nmc_power_arg_tl { (-1) } { % inverse trig/hyp. function? \prop_get:NVNF \g__nmc_subst_misc_prop \l__nmc_fn_tl \l__nmc_fn_tl { \prop_get:NVN \g__nmc_subst_fpfn_prop \l__nmc_fn_tl \l__nmc_subst_tl \tl_concat:NNN \l__nmc_fn_tl a \l__nmc_subst_tl } } { % not inverse fn \prop_get:NVN \g__nmc_subst_fpfn_prop \l__nmc_fn_tl \l__nmc_fn_tl \bool_set_true:N \l__nmc_superscript_bool } } \cs_new:Npn \__nmc_fpify_unary_hyperbolic:N #1 { \str_case:on \l__nmc_fn_tl { { sinh } { ( 0.5( exp(#1)- exp(-(#1)) ) ) } { cosh } { ( 0.5( exp(#1) + exp(-(#1)) ) ) } { tanh } { ( (exp(2(#1))-1)/(exp(2(#1))+1) ) } { asinh } { ln( #1 + sqrt((#1)^2+1) ) } { acosh } { ln( #1 + sqrt((#1)^2-1) ) } { atanh } { ( 0.5 ln( (1+(#1))/(1-(#1)) ) ) } { csch } { 1/( 0.5( exp(#1)- exp(-(#1)) ) ) } { sech } { 1/( 0.5( exp(#1) + exp(-(#1)) ) ) } { coth } { ( (exp(2(#1))+1)/(exp(2(#1))-1) ) } { acsch } { ( ln(1/(#1)+sqrt(1/(#1)^2+1)) ) } { asech } { ( ln(1/(#1)+sqrt(1/(#1)^2-1)) ) } { acoth } { ( 0.5 ln( ((#1)+1)/((#1)-1) ) ) } } } \cs_new_protected:Npn \__nmc_fpify_degree: { \bool_if:NF \l__nmc_deg_bool { \tl_put_right:Nn \l__nmc_accum_tl { (0.0174532925199433) } } } \cs_new_protected:Npn \__nmc_fpify_power: { \tl_put_right:Nn \l__nmc_accum_tl { ^ } \__nmc_fpify_next_braced:N \l__nmc_accum_tl \bool_set_true:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_frac: { \tl_put_right:Nn \l__nmc_accum_tl { ( } \__nmc_fpify_next_braced:N \l__nmc_accum_tl \tl_put_right:Nn \l__nmc_accum_tl { / } \__nmc_fpify_next_braced:N \l__nmc_accum_tl \tl_put_right:Nn \l__nmc_accum_tl { ) } \bool_set_true:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_unarybrace: { \prop_get:NVN \g__nmc_subst_fpfn_prop \l__nmcB_tl \l__nmc_subst_tl \tl_if_eq:VnT \l__nmcC_tl { * } { \__nmc_next: } \tl_if_eq:VnTF \l__nmcC_tl { [ } { % n-th root \tl_if_eq:VnTF \l__nmc_subst_tl { sqrt } { \__nmc_next: \__nmc_fpify_ubrace_n: } { \__nmc_next: \__nmc_next: \__nmc_next: \__nmc_fpify_ubrace_aux: } } { \__nmc_fpify_ubrace_aux: } \bool_set_true:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_ubrace_aux: { \tl_set_eq:NN \l_tmpa_tl \l__nmc_subst_tl \__nmc_fpify_next_braced:N \l_tmpa_tl \tl_if_eq:VnTF \l__nmcC_tl { ! } { \__nmc_fpify_ubrace_fact: } { \tl_put_right:NV \l__nmc_accum_tl \l_tmpa_tl } } \cs_new_protected:Npn \__nmc_fpify_ubrace_n: { \__nmc_error_where:n { \textbackslash sqrt } \tl_clear:N \l__nmc_arg_tl \tl_clear:N \l__nmc_ubrace_n_tl \tl_put_right:Nn \l__nmc_accum_tl { ( } \__nmc_get_arg_LR:NNN [ \l__nmc_arg_tl ] \__nmc_fpify:VN \l__nmc_arg_tl \l__nmc_ubrace_n_tl \tl_set:Nx \l__nmc_ubrace_n_tl { \fp_to_int:n \l__nmc_ubrace_n_tl } \int_compare:nNnF { \l__nmc_ubrace_n_tl } > { 0 } { \__nmc_error_what:n { Integer~$>0$~required~for~[arg]~of } } \bool_if:NF \g__nmc_error_bool { \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl \__nmc_next: \tl_clear:N \l_tmpa_tl \__nmc_fpify:VN \l__nmcB_tl \l_tmpa_tl \bool_if:nTF { \fp_compare_p:nNn { \l_tmpa_tl } < { 0 } && \int_if_even_p:n { \l__nmc_ubrace_n_tl } } { \flag_raise:n { fp_invalid_operation } \__nmc_error_fpflag: } { \tl_put_right:Nx \l__nmc_accum_tl { \__nmc_fpify_ubrace_n_aux:VV {\l_tmpa_tl}{ \l__nmc_ubrace_n_tl }} } } \tl_put_right:Nn \l__nmc_accum_tl { ) } } \cs_new:Npn \__nmc_fpify_ubrace_n_aux:nn #1#2 { sign( #1 )( abs( #1 ) )^( 1/( #2 ) ) } \cs_generate_variant:Nn \__nmc_fpify_ubrace_n_aux:nn { VV } \cs_new_protected:Npn \__nmc_fpify_ubrace_fact: { \tl_if_eq:VnF \l__nmc_subst_tl { sqrt } { \str_case:onT \l__nmc_subst_tl { { abs } { \tl_set:Nn \l__nmc_fact_arg_tl { \abs } } { ceil } { \tl_set:Nn \l__nmc_fact_arg_tl { \ceil } } { floor} { \tl_set:Nn \l__nmc_fact_arg_tl { \floor } } } { \tl_put_right:Nx \l__nmc_fact_arg_tl { { \exp_not:o \l__nmcB_tl } } } } } \cs_new_protected:Npn \__nmc_fpify_unarysub: { % e.g. \log_{10} \str_if_eq:VnTF \l__nmcC_tl { _ } { \__nmc_next: \__nmc_next: \__nmc_fpify_unarysub:N \l__nmcB_tl } { \__nmc_fpify_unarysub:N \l__nmc_log_base_tl } } \cs_new_protected:Npn \__nmc_fpify_unarysub:N #1 { \__nmc_fpify:VN #1 \l__nmc_arg_tl \bool_if:NF \g__nmc_error_bool { \fp_compare:nF { 0 < \l__nmc_arg_tl != 1 } { \__nmc_error_what:n { Valid~base~required~for~\__nmc_verb:n { \log }~in } } } \bool_if:NF \g__nmc_error_bool { \tl_set:Nx \l_tmpa_tl { \fp_eval:n { 1/(ln(\l__nmc_arg_tl)) } } \__nmc_error_fpflag: } \bool_if:NF \g__nmc_error_bool { \__nmc_accum_fn_parenth:NVn \l__nmc_accum_tl \l_tmpa_tl {} \tl_put_left:Nn \l__nmcA_tl { \ln } } } \cs_new_protected:Npn \__nmc_fpify_surd: { \prop_get:NVN \g__nmc_subst_fpfn_prop \l__nmcB_tl \l__nmc_subst_tl \tl_put_right:NV \l__nmc_accum_tl \l__nmc_subst_tl \tl_clear:N \l__nmc_arg_tl \__nmc_delim_arg:Nnn \l__nmc_arg_tl { 1 } { \c__nmc_srd_int } \__nmc_parenth:N \l__nmc_arg_tl \__nmc_fpify:VN \l__nmc_arg_tl \l__nmc_accum_tl \bool_set_true:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_fact: { \__nmc_error_where:n { factorial } \tl_clear:N \l_tmpa_tl \__nmc_fpify:VN \l__nmc_fact_arg_tl \l_tmpa_tl \bool_if:NF \g__nmc_error_bool { \tl_set:Nx \l_tmpa_tl { \fp_to_int:n \l_tmpa_tl } \tl_if_eq:VnTF \l__nmcC_tl { ! } { \__nmc_fpify_fact_repeated: } { \int_compare:nNnTF { \l_tmpa_tl } < { 0 } { \__nmc_error_what:n { Integer~$\ge 0$~required~in } } { \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl \__nmc_accum_fn_parenth:NVn \l__nmc_accum_tl \l_tmpa_tl { fact } } } } \bool_set_true:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_fact_repeated: { \int_compare:nNnTF { \l_tmpa_tl } < { -1 } { \__nmc_error_what:n { Integer~$\ge -1$~required~for~double~factorial~in } } { \__nmc_fpify_double_fact:N \l_tmpa_tl \tl_set:Nx \l_tmpa_tl { \fp_use:N \l__nmc_fact_fp } \__nmc_accum_fn_parenth:NVn \l__nmc_accum_tl \l_tmpa_tl {} \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl } } \cs_new_protected:Npn \__nmc_fpify_double_fact:N #1 { \__nmc_next: \int_compare:nNnTF { #1 } > { 0 } { \int_if_even:nTF { #1 } { \__nmc_fpify_fact_do:nNn { 2 } #1 { 2 } } { \__nmc_fpify_fact_do:nNn { 1 } #1 { 2 } } } { \fp_set:Nn \l__nmc_fact_fp { 1 } } } % multiply nos from #1 to #2, put in \l__nmc_fact_fp % step #3 = 1 (!), = 2 (!!) \cs_new_protected:Npn \__nmc_fpify_fact_do:nNn #1#2#3 { \fp_set:Nn \l__nmc_fact_fp { #1 } \int_step_inline:nnnn { #1 + #3 } { #3 } { #2 } { \fp_set:Nn \l__nmc_fact_fp { \l__nmc_fact_fp * ##1 } } } \cs_new_protected:Npn \__nmc_fpify_nary: { \bool_set_true:N \l__nmc_comma_nary_bool \str_case:on \l__nmcB_tl { { \gcd } { \__nmc_fpify_nary_gcd: } { \max } { \__nmc_fpify_nary_maxmin: } { \min } { \__nmc_fpify_nary_maxmin: } } \bool_set_false:N \l__nmc_comma_nary_bool } \cs_new_protected:Npn \__nmc_fpify_nary_gcd: { \__nmc_insert_aster: \__nmc_delim_arg:Nnn \l__nmc_arg_tl { 1 } { \c_max_int } \tl_set:Nx \l__nmc_arg_tl { \tl_range:Nnn \l__nmc_arg_tl { 2 } { -2 } } \tl_clear:N \l_tmpa_tl \__nmc_fpify:VN \l__nmc_arg_tl \l_tmpa_tl \seq_set_split:NnV \l_tmpa_seq {,} \l_tmpa_tl % , for l3fp % eval. 1st expr. \seq_pop:NN \l_tmpa_seq \l_tmpb_tl \int_set:Nn \l_tmpb_int { \fp_to_int:n \l_tmpb_tl } \seq_map_inline:Nn \l_tmpa_seq { \int_set:Nn \l_tmpd_int { \fp_to_int:n { ##1 } } \int_set:Nn \l_tmpa_int { \int_max:nn { \l_tmpd_int } { \l_tmpb_int } } \int_set:Nn \l_tmpb_int { \int_min:nn { \l_tmpd_int } { \l_tmpb_int } } \int_set:Nn \l_tmpc_int { \int_mod:nn { \l_tmpa_int } { \l_tmpb_int } } \int_until_do:nNnn { \l_tmpc_int } = { 0 } { \int_set_eq:NN \l_tmpa_int \l_tmpb_int \int_set_eq:NN \l_tmpb_int \l_tmpc_int \int_set:Nn \l_tmpc_int { \int_mod:nn { \l_tmpa_int } { \l_tmpb_int } } } } \tl_put_right:Nx \l__nmc_accum_tl { \int_use:N \l_tmpb_int } \bool_set_false:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_nary_maxmin: { \prop_get:NVN \g__nmc_subst_fpfn_prop \l__nmcB_tl \l__nmc_subst_tl \__nmc_delim_arg:Nnn \l__nmc_arg_tl { 1 } { \c_max_int } \tl_clear:N \l_tmpa_tl \__nmc_fpify:VN \l__nmc_arg_tl \l_tmpa_tl % em-brace in case nested \tl_put_right:Nx \l__nmc_accum_tl { { \l__nmc_subst_tl \exp_not:o \l_tmpa_tl } } \bool_set_true:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_comma: { \tl_put_right:Nn \l__nmc_accum_tl {,} \bool_set_false:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_binom: { \__nmc_fpify_next_braced:N \l__nmc_binom_top_tl \__nmc_fpify_next_braced:N \l__nmc_binom_bot_tl \__nmc_error_where:n { binomial~coeff } \tl_set:Nx \l__nmc_binom_bot_tl { \fp_to_int:n \l__nmc_binom_bot_tl } \int_compare:nNnT \l__nmc_binom_bot_tl < { 0 } { \__nmc_error_what:n {Integer~$\ge 0$~required~in~\{arg2\}~of } } \bool_if:NF \g__nmc_error_bool { \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl \__nmc_fpify_binom_calc:NN \l__nmc_binom_top_tl \l__nmc_binom_bot_tl } } \cs_new_protected:Npn \__nmc_fpify_binom_calc:NN #1 #2 { \tl_put_right:Nn \l__nmc_accum_tl { ( } \int_if_zero:nTF { #2 } { \tl_put_right:Nn \l__nmc_accum_tl { 1 } } { % calc. top \fp_set:Nn \l_tmpa_fp { #1 } \int_step_inline:nnnn { 1 } { 1 } { #2 - 1 } { \fp_set:Nn \l_tmpa_fp { \l_tmpa_fp * ( #1 - ##1 ) } } \tl_put_right:Nx \l__nmc_accum_tl { \fp_use:N \l_tmpa_fp } \tl_put_right:Nn \l__nmc_accum_tl { / } \__nmc_fpify_fact_do:nNn { 1 } #2 { 1 } \tl_put_right:Nx \l__nmc_accum_tl { \fp_use:N \l__nmc_fact_fp } } \tl_put_right:Nn \l__nmc_accum_tl { ) } } \cs_new_protected:Npn \__nmc_fpify_font: { \__nmc_next: \__nmc_accum_fpify_parenth:NN \l__nmc_accum_tl \l__nmcB_tl } \cs_new_protected:Npn \__nmc_fpify_splitfrac: { \__nmc_next: \tl_set_eq:NN \l_tmpb_tl \l__nmcB_tl \__nmc_next: \tl_put_right:NV \l_tmpb_tl \l__nmcB_tl \__nmc_accum_fpify_parenth:NN \l__nmc_accum_tl \l_tmpb_tl } % \cs { m }, \cs { o m }, \cs { * m } \cs_new_protected:Npn \__nmc_fpify_absorb_m: { \__nmc_next: } \cs_new_protected:Npn \__nmc_fpify_absorb_om: { \str_if_eq:VnT \l__nmcC_tl { [ } { \__nmc_next: \__nmc_get_arg_LR:NNN [ \l__nmc_toss_tl ] } \__nmc_next: } \cs_new_protected:Npn \__nmc_fpify_absorb_sm: { \str_if_eq:VnT \l__nmcC_tl { * } { \__nmc_next: } \__nmc_next: } \cs_new_protected:Npn \__nmc_fpify_color: { \__nmc_fpify_absorb_om: \__nmc_fpify_next_braced:N \l__nmc_accum_tl \bool_set_true:N \l__nmc_insert_aster_bool } \regex_new:N \l__nmc_glue_regex \regex_set:Nn \l__nmc_glue_regex { (\d+\s*mu)|(\1\s*plus\s*\d+\s*mu)|\2\s*minus\s*\d+\s*mu } \cs_new_protected:Npn \__nmc_fpify_mkern: { \exp_args:NV \token_if_eq_catcode:NNTF \l__nmcC_tl \mkern { \__nmc_next: } { \regex_replace_case_once:nNT { { \d+\s*mu\s*plus\s*\d+\s*mu\s*minus\s*\d+\s*mu } {} { \d+\s*mu\s*plus\s*\d+\s*mu } {} { \d+\s*mu\s*minus\s*\d+\s*mu } {} { \d+\s*mu } {} } \l__nmcA_tl { \tl_set:Nx \l__nmcC_tl { \tl_head:N \l__nmcA_tl } } } } \cs_new_protected:Npn \__nmc_fpify_BE: { \__nmc_next: \tl_if_in:VnT \l__nmcB_tl { alignat } { \__nmc_next: } } \cs_new_protected:Npn \__nmc_fpify_cmd: { % \cm { s O m O O } % \__nmc_insert_aster: \prop_get:NoNT \g__nmc_subst_misc_prop \l__nmcB_tl \l_tmpa_tl { \exp_args:NV \__nmc_cmd:n \l_tmpa_tl \bool_set_false:N \l__nmc_insert_aster_bool \bool_set_false:N \l__nmc_wraps_math_bool } } \cs_new_protected:Npn \__nmc_cmd:n #1 { % #1=id; \cm { s O m O O } \tl_put_right:Nn \l__nmc_accum_tl { ( } \tl_set:Nn \l__nmc_arg_tl { {#1} } \tl_if_eq:VnT \l__nmcC_tl { * } { \__nmc_next: } \bool_set_true:N \l__nmc_num_only_bool \__nmc_get_sqbrarg:N \l__nmc_arg_tl % settings \__nmc_next: \tl_put_right:Nx \l__nmc_arg_tl { { \exp_not:o \l__nmcB_tl } } \__nmc_get_sqbrarg:N \l__nmc_arg_tl % vv \__nmc_get_sqbrarg:N \l__nmc_arg_tl % num format \group_begin: \int_add:Nn \l__nmc_depth_int { 2 } \exp_last_unbraced:No \__nmc_cmd_aux:nnnnn \l__nmc_arg_tl \bool_if:nT { \l__nmc_round_bool && !\g__nmc_error_bool } { \tl_set:Nx \l__nmc_result_tl { \fp_eval:n { round(\l__nmc_result_tl, \l__nmc_round_int) } } } \exp_args:NNNV \group_end: \tl_put_right:Nn \l__nmc_accum_tl \l__nmc_result_tl \tl_put_right:Nn \l__nmc_accum_tl { ) } } \cs_new_protected:Npn \__nmc_cmd_aux:nnnnn #1#2#3#4#5 { \__nmc_initialize:n { #1 } \__nmc_formula:nn {#1} {#3} \bool_if:NF \g__nmc_error_bool { \__nmc_settings:nn {#1} {#2} } \bool_if:NF \g__nmc_error_bool { \__nmc_trailing_args:nnn {#1} {#4} {#5} } \bool_if:NF \g__nmc_error_bool { \use:c { __nmc_#1_process: } } } \cs_new_protected:Npn \__nmc_get_sqbrarg:N #1 { \tl_if_eq:VnTF \l__nmcC_tl { [ } { \__nmc_next: \tl_clear:N \l_tmpa_tl \__nmc_get_arg_LR:NNN [ \l_tmpa_tl ] \tl_put_right:Nx #1 { { \exp_not:o \l_tmpa_tl } } } { \tl_put_right:Nn #1 { {} } } } % sum/prod %%%%%%%%%%%%%%%%%% \cs_new_protected:Npn \__nmc_fpify_sum: { \__nmc_insert_aster: \group_begin: \tl_if_eq:VnTF \l__nmcB_tl { \sum } { % sum \tl_set:Nn \l__nmc_sum_op_tl { + } \fp_zero:N \l__nmc_sum_total_fp \fp_set:Nn \l__nmc_sum_prev_fp { 1 } \tl_set:Nn \l__nmc_sum_type_tl { sum } \tl_set:Nn \l__nmc_sum_typei_tl { summation } \bool_set_true:N \l__nmc_sum_bool } { % product \tl_set:Nn \l__nmc_sum_op_tl { * } \fp_set:Nn \l__nmc_sum_total_fp { 1 } \fp_set:Nn \l__nmc_sum_prev_fp { 2 } \tl_set:Nn \l__nmc_sum_type_tl { product } \tl_set:Nn \l__nmc_sum_typei_tl { product } \bool_set_false:N \l__nmc_sum_bool } \__nmc_error_where:n { \l__nmc_sum_type_tl } \bool_if:NF \g__nmc_error_bool { \__nmc_error_where:n { \l__nmc_sum_type_tl } \__nmc_sum_get_limits:NNN \l__nmc_sum_var_tl \l__nmc_sum_index_int \l__nmc_sum_end_int \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl } \bool_if:NTF \g__nmc_error_bool { \group_end: } { % get the summand/multiplicand \__nmc_delim_arg:Nnn \l__nmc_arg_tl { 1 } { \c__nmc_sum_int } \tl_if_eq:VnF \l__nmcC_tl { ( } { \__nmc_parenth:N \l__nmc_arg_tl } \tl_set_eq:NN \l__nmc_summand_tl \l__nmc_arg_tl % do the sum/prod \__nmc_error_where:n { \l__nmc_sum_type_tl } \__nmc_sum_do:nn { \l__nmc_sum_index_int } { \l__nmc_sum_end_int } \tl_gset_eq:NN \g_tmpa_tl \l__nmcA_tl \tl_gset_eq:NN \g_tmpb_tl \l__nmcC_tl \exp_args:NNNV \group_end: \fp_set:Nn \l__nmc_sum_total_fp { \l__nmc_sum_total_fp } \tl_set_eq:NN \l__nmcA_tl \g_tmpa_tl \tl_set_eq:NN \l__nmcC_tl \g_tmpb_tl \tl_put_right:Nx \l__nmc_accum_tl { \fp_use:N \l__nmc_sum_total_fp } \bool_set_true:N \l__nmc_insert_aster_bool \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl } } \cs_new_protected:Npn \__nmc_sum_get_limits:NNN #1#2#3 { % #1 (tl) sum var #2, #3 (ints) lower, upper limits \str_if_eq:VnTF \l__nmcC_tl { _ } { \__nmc_sum_limit_lower:NN #1#2 \bool_if:NF \g__nmc_error_bool { \__nmc_sum_limit_upper:N #3 } } { \__nmc_sum_limit_upper:N #3 \__nmc_sum_limit_lower:NN #1#2 } } \cs_new_protected:Npn \__nmc_sum_limit_lower:NN #1#2 { \__nmc_next: \__nmc_next: \bool_if:NT \l__nmc_multitok_bool { % may not be in vv-list \seq_clear:N \l_tmpc_seq \seq_push:NV \l_tmpc_seq \l__nmcB_tl \__nmc_prep_multitok:NN \l_tmpc_seq \l__nmcA_tl \seq_pop:NN \l_tmpc_seq \l__nmcB_tl } \str_if_in:NnTF \l__nmcB_tl { = } { \__nmc_vv_get_vars_vals_lims:NN \l__nmcB_tl \c_empty_prop \tl_set_eq:NN #1 \l__nmc_eq_var_tl \__nmc_sum_limit_assign:NNn #2 \l__nmc_vv_fp_expr_tl { lower } \seq_if_in:NVF \l__nmc_calc_fn_seq \l__nmcB_tl { \seq_put_left:NV \l__nmc_calc_fn_seq \l__nmcB_tl } } { \__nmc_error_what:n { No~\l__nmc_sum_typei_tl\ variable~in } } } \cs_new_protected:Npn \__nmc_sum_limit_upper:N #1 { \__nmc_next: \__nmc_next: \__nmc_vv_get_vars_vals_lims:NN \l__nmcB_tl \c_empty_prop \bool_if:NF \g__nmc_error_bool { \__nmc_sum_limit_assign:NNn #1 \l__nmc_vv_fp_expr_tl { upper } } } \cs_new_protected:Npn \__nmc_sum_limit_assign:NNn #1#2#3 { \tl_if_in:VnTF #2 { inf } { \int_set:Nn #1 { \fp_sign:n { #2 } * \c_max_int } } { \fp_compare:nNnTF { abs(#2) } > { \c_max_int } { \int_set:Nn #1 { \fp_sign:n { #2 } * \c_max_int } } { \tl_set:Nx #2 { \fp_to_int:n #2 } \bool_if:NF \g__nmc_error_bool { \int_set:Nn #1 { #2 } } } } } % #1#2 lower/upper limits (int); result in \l__nmc_sum_total_fp \cs_new_protected:Npn \__nmc_sum_do:nn #1#2 { \int_compare:nNnTF { \c_max_int } = { \int_max:nn { \int_abs:n { #1 } } { \int_abs:n { #2 } } } { \bool_if:NTF \l__nmc_sum_bool { \__nmc_sum_do_infinite:Nn #1 { sum } } { \__nmc_sum_do_infinite:Nn #1 { prod } } } { \int_step_function:nnnN { #1 } { 1 } { #2 } \__nmc_sum_eval:n } \bool_if:NF \g__nmc_error_bool { \int_compare:nNnT { #2 } < { #1 } { \tl_if_eq:VnTF \l__nmc_sum_op_tl { * } { \fp_set:Nn \l__nmc_sum_total_fp { 1 } } { \fp_set:Nn \l__nmc_sum_total_fp { 0 } } } } } \cs_set:Npn \__nmc_sum_do_infinite:Nn #1#2 { \int_set:Nn \l__nmc_sum_round_int { \l__nmc_round_int + \use:c { l__nmc_#2_extra_int } } \int_set:Nn \l__nmc_suma_int { #1 - 1 } % check loop \bool_do_while:nn { \l__nmc_sum_cont_bool } { % main loop \bool_set_false:N \l__nmc_sum_cont_bool \fp_until_do:nNnn { \l__nmc_sum_prev_fp } = { \l__nmc_sum_rounded_fp } { \int_incr:N \l__nmc_suma_int \fp_set_eq:NN \l__nmc_sum_prev_fp \l__nmc_sum_rounded_fp \__nmc_sum_eval:n { \l__nmc_suma_int } \fp_set:Nn \l__nmc_sum_rounded_fp { round( \l__nmc_sum_total_fp, \l__nmc_sum_round_int ) } } % query terms \int_set:Nn \l__nmc_sumb_int { \l__nmc_suma_int + \use:c { l__nmc_#2_query_int } } \int_while_do:nNnn { \l__nmc_suma_int } < { \l__nmc_sumb_int } { \int_incr:N \l__nmc_suma_int \__nmc_sum_query:n { \l__nmc_suma_int } } } \tl_gset:cx { g__nmc_info_\tl_range:Nnn \l__nmc_sum_type_tl{1}{4} _tl } { \int_eval:n { \l__nmc_suma_int - #1 - \use:c { l__nmc_#2_query_int } } } } \cs_new_protected:Npn \__nmc_sum_eval:n #1 { \__nmc_calc_fn_val:VNnN \l__nmc_sum_var_tl \l__nmc_summand_tl { #1 } \l_tmpb_fp \fp_set:Nn \l__nmc_sum_total_fp { \l__nmc_sum_total_fp \l__nmc_sum_op_tl \l_tmpb_fp } } \cs_new_protected:Npn \__nmc_sum_query:n #1 { \__nmc_sum_eval:n { #1 } \fp_set:Nn \l__nmc_sum_rounded_fp { round( \l__nmc_sum_total_fp, \l__nmc_sum_round_int ) } \fp_compare:nNnF { \l__nmc_sum_prev_fp } = { \l__nmc_sum_rounded_fp } { \bool_set_true:N \l__nmc_sum_cont_bool \int_set_eq:NN \l__nmc_sumb_int \l__nmc_suma_int } } % delimit math args %%%%%%%%%%%%%%%%%%% \tl_new:N \l__nmc_delim_arg_tl \tl_new:N \l__nmc_delim_argi_tl \int_new:N \l__nmc_delim_pas_int \int_new:N \l__nmc_delim_pos_int \bool_new:N \l__nmc_delim_stop_bool \bool_new:N \l__nmc_delim_lmod_bool \prg_new_conditional:Npnn \__nmc_if_pospas_gtr:n #1 { p, TF } { \bool_if:nTF { \int_compare_p:nNn { \l__nmc_delim_pos_int } > { 1 } && \int_compare_p:nNn { \l__nmc_delim_pas_int } > { #1 } } { \prg_return_true: } { \prg_return_false: } } % #1 <-- \l__nmc_delim_arg_tl; % #2 (int) initial pos % #3 (int) parsing state \cs_new_protected:Npn \__nmc_delim_arg:Nnn #1#2#3 { \tl_if_head_is_group:VTF \l__nmcA_tl { \__nmc_next: \tl_set_eq:NN #1 \l__nmcB_tl } { \group_begin: \bool_set_false:N \__nmc_delim_stop_bool \bool_set_false:N \l__nmc_delim_lmod_bool \int_set:Nn \l__nmc_delim_pos_int { #2 } \int_set:Nn \l__nmc_delim_pas_int { #3 } \tl_clear:N \l__nmc_delim_arg_tl \bool_until_do:nn { \l__nmc_delim_stop_bool || \quark_if_nil_p:N \l__nmcC_tl } { \prop_get:NVNTF \g__nmc_class_prop \l__nmcC_tl \l__nmc_class_tl { \exp_last_unbraced:NV \use_ii:nn \l__nmc_class_tl } { \__nmc_delim_var: } \int_incr:N \l__nmc_delim_pos_int } \tl_gset_eq:NN \g_tmpa_tl \l__nmcA_tl \tl_gset_eq:NN \g_tmpb_tl \l__nmc_delim_arg_tl \exp_args:NNNV \group_end: \tl_set:Nn \l__nmcC_tl \l__nmcC_tl \tl_set_eq:NN \l__nmcA_tl \g_tmpa_tl \tl_set_eq:NN #1 \g_tmpb_tl } } % delimit arg routines %%%%%%%%%%%%%%%% \cs_new_protected:Npn \__nmc_delim_stop: { \tl_if_eq:VnTF \l__nmcC_tl { \q } { \bool_set_false:N \l__nmc_delim_stop_bool } { \bool_set_true:N \l__nmc_delim_stop_bool } } \cs_new_protected:Npn \__nmc_delim_stop_if_gtr:n #1 { \int_compare:nNnT { \l__nmc_delim_pas_int } > { #1 } { \__nmc_delim_stop: } } \cs_new_protected:Npn \__nmc_delim_append: { \__nmc_next: \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmcB_tl } \cs_new_protected:Npn \__nmc_delim_append_braced: { \__nmc_next: \tl_put_right:Nx \l__nmc_delim_arg_tl { { \exp_not:o\l__nmcB_tl } } } \cs_new_protected:Npn \__nmc_delim_append_twobraced: { \__nmc_delim_append: \__nmc_delim_append_braced: \__nmc_delim_append_braced: } \cs_new_protected:Npn \__nmc_delim_append_sqbra: { \__nmc_next: \tl_clear:N \l_tmpa_tl \__nmc_get_arg_LR:NNN [ \l_tmpa_tl ] \__nmc_put_right_wrap:NnNn \l__nmc_delim_arg_tl { [ } \l_tmpa_tl { ] } } \cs_new_protected:Npn \__nmc_delim_dec: { \__nmc_if_pospas_gtr:nTF { \c__nmc_uny_int } { \__nmc_delim_stop: } { \__nmc_next: \__nmc_get_dec:NN \l_tmpa_tl \c_true_bool \tl_put_right:NV \l__nmc_delim_arg_tl \l_tmpa_tl \bool_if:NT \l__nmc_trig_bool { \__nmc_degrees: } } } \cs_new_protected:Npn \__nmc_degrees: { \tl_if_eq:VnT \l__nmcC_tl { \degree } { \bool_if:NF \l__nmc_deg_bool { \tl_put_right:Nn \l__nmc_delim_arg_tl { (0.0174532925199433) } } \__nmc_next: } } \cs_new_protected:Npn \__nmc_delim_var: { \__nmc_if_pospas_gtr:nTF { \c__nmc_uny_int } { \__nmc_delim_stop: } { \__nmc_delim_append: } } \cs_new_protected:Npn \__nmc_delim_const: { \__nmc_if_pospas_gtr:nTF { \c__nmc_uny_int } { \__nmc_delim_stop: } { \__nmc_delim_append: } } \cs_new_protected:Npn \__nmc_delim_arith: { \__nmc_if_pospas_gtr:nTF { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_delim_append: } } \cs_new_protected:Npn \__nmc_delim_pm: { \__nmc_if_pospas_gtr:nTF { \c__nmc_cmp_int } { \__nmc_delim_stop: } { \__nmc_delim_append: } } \cs_new_protected:Npn \__nmc_delim_comparison: { \int_compare:nNnT { \l__nmc_delim_pas_int } = { \c__nmc_cmp_int } { \tl_put_left:NV \l__nmcA_tl \l__nmc_delim_arg_tl \tl_put_left:Nn \l__nmcA_tl { \land } \tl_put_left:Nn \l__nmcC_tl { \land } } \__nmc_if_pospas_gtr:nTF { \c__nmc_and_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \__nmc_delim_arg:Nnn \l__nmc_delim_argi_tl { 1 } { \c__nmc_cmp_int } \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmc_delim_argi_tl } } \cs_new_protected:Npn \__nmc_delim_andor: { \__nmc_delim_stop: } \cs_new_protected:Npn \__nmc_delim_lparen: { \__nmc_if_pospas_gtr:nTF { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_next: \str_case:on \l__nmcB_tl { { ( } { \__nmc_delim_lparen:nn { ( } { ) } } { [ } { \__nmc_delim_lparen:nn { [ } { ] } } { \{ } { \__nmc_delim_lparen:nn {\{ } {\} } } { \lparen } { \__nmc_delim_lparen:nn { \lparen } { \rparen } } { \lbrack } { \__nmc_delim_lparen:nn { \lbrack } { \rbrack } } { \lbrace } { \__nmc_delim_lparen:nn { \lbrace } { \rbrace } } } \__nmc_delim_lparen_auxi: } } \cs_new_protected:Npn \__nmc_delim_lparen:nn #1#2 { \tl_put_right:Nn \l__nmc_delim_arg_tl { ( } \__nmc_get_arg_LR:NNN #1 \l__nmc_delim_arg_tl #2 \bool_if:NT \l__nmc_delim_lmod_bool { \tl_set:Nx \l__nmc_delim_arg_tl { \tl_range:Nnn \l__nmc_delim_arg_tl { 1 } { -2 } } } \tl_put_right:Nn \l__nmc_delim_arg_tl { ) } \int_incr:N \l__nmc_delim_pos_int } \cs_generate_variant:Nn \__nmc_delim_lparen:nn { VV } \cs_new_protected:Npn \__nmc_delim_lparen_auxi: { \int_compare:nNnT { \l__nmc_delim_pas_int } = { \c__nmc_uny_int } { \__nmc_delim_arg:Nnn \l__nmc_delim_argi_tl { 2 } { \c__nmc_prn_int } } \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmc_delim_argi_tl \__nmc_delim_stop_if_gtr:n { \c__nmc_sum_int } } \cs_new_protected:Npn \__nmc_delim_rparen: { \__nmc_if_pospas_gtr:nTF { \c__nmc_cmp_int } { \__nmc_delim_stop: } { \__nmc_next: \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmcB_tl } } \cs_new_protected:Npn \__nmc_delim_lvert: { \__nmc_if_pospas_gtr:nTF { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_next: \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmcB_tl \str_case:on \l__nmcB_tl { { \lvert } { \__nmc_delim_lvert:nn { \lvert } { \rvert } } { \lceil } { \__nmc_delim_lvert:nn { \lceil } { \rceil } } { \lfloor } { \__nmc_delim_lvert:nn { \lfloor } { \rfloor } } { | } { \__nmc_absval_arg:N \l__nmc_delim_arg_tl \tl_put_right:Nn \l__nmc_delim_arg_tl { | } } } \__nmc_delim_lparen_auxi:n { 0 } } } \cs_new_protected:Npn \__nmc_delim_lvert:nn #1#2 { \__nmc_delim_lparen:nn { #1 } { #2 } \tl_put_right:Nn \l__nmc_delim_arg_tl { #2 } } \cs_new_protected:Npn \__nmc_delim_lmod: { \__nmc_if_pospas_gtr:nTF { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_next: \tl_if_in:nVTF { |/ } \l__nmcC_tl { \prop_get:NVN \g__nmc_subst_misc_prop \l__nmcB_tl \l_tmpb_tl \__nmc_delim_lparen:VV \l__nmcB_tl \l_tmpb_tl \__nmc_next: \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmcB_tl \tl_if_eq:VnTF \l__nmcC_tl { | } { \__nmc_delim_lparen_auxi:n { 0 } } { \__nmc_next: \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmcB_tl \__nmc_delim_stop: } } { \tl_if_eq:VnTF \l__nmcC_tl { . } { \__nmc_next: } { \bool_set_true:N \l__nmc_delim_lmod_bool } \int_decr:N \l__nmc_delim_pos_int } } } \cs_new_protected:Npn \__nmc_delim_unary: { \__nmc_if_pospas_gtr:nTF { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \tl_if_head_is_group:VTF \l__nmcA_tl { \__nmc_delim_append_braced: \__nmc_delim_stop: } { \tl_if_eq:VnT \l__nmcC_tl { ^ } { \__nmc_delim_append: \__nmc_delim_append_braced: } \__nmc_delim_arg:Nnn \l__nmc_delim_argi_tl { 1 } { \c__nmc_uny_int } \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmc_delim_argi_tl \__nmc_delim_stop_if_gtr:n { \c__nmc_sum_int } } } } \cs_new_protected:Npn \__nmc_delim_power: { \__nmc_if_pospas_gtr:nTF { \c__nmc_prn_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \__nmc_delim_append_braced: \__nmc_delim_stop_if_gtr:n { \c__nmc_sum_int } } } \cs_new_protected:Npn \__nmc_delim_tfrac: { \__nmc_if_pospas_gtr:nTF { \c__nmc_uny_int } { \__nmc_delim_stop: } { \__nmc_delim_append_twobraced: } } \cs_new_protected:Npn \__nmc_delim_frac: % also \(d)binom { \__nmc_if_pospas_gtr:nTF { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_delim_append_twobraced: \__nmc_delim_stop_if_gtr:n { \c__nmc_sum_int } } } \cs_new_protected:Npn \__nmc_delim_unarybrace: { \__nmc_if_pospas_gtr:nTF { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \str_case:on \l__nmcC_tl { { * } { \__nmc_delim_append: } { [ } { \__nmc_delim_append_sqbra: } } \__nmc_delim_append_braced: \__nmc_delim_arg:Nnn \l__nmc_delim_argi_tl { 2 } { \c__nmc_prn_int } \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmc_delim_argi_tl \__nmc_delim_stop_if_gtr:n { \c__nmc_sum_int } } } \cs_new_protected:Npn \__nmc_delim_log: { \__nmc_if_pospas_gtr:nTF { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \__nmc_delim_append: \__nmc_delim_append_braced: \__nmc_delim_arg:Nnn \l__nmc_delim_argi_tl { 1 } { \c__nmc_uny_int } \__nmc_accum_fn_parenth:NVn \l__nmc_delim_arg_tl \l__nmc_delim_argi_tl {} } } \cs_new_protected:Npn \__nmc_delim_surd: { \__nmc_if_pospas_gtr:nTF { \c__nmc_uny_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \tl_clear:N \l__nmc_delim_argi_tl \tl_if_eq:VnT \l__nmcB_tl { \prod } { \prg_replicate:nn { 2 } { \__nmc_delim_append: \__nmc_delim_append_braced: } } \tl_if_head_is_group:VTF \l__nmcA_tl { \__nmc_delim_append_braced: \__nmc_delim_stop: } { \__nmc_delim_arg:Nnn \l__nmc_delim_argi_tl { 1 } { \c__nmc_srd_int } \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmc_delim_argi_tl \__nmc_delim_stop_if_gtr:n { \c__nmc_sum_int } } } } \cs_new_protected:Npn \__nmc_delim_fact: { \__nmc_if_pospas_gtr:nTF { \c__nmc_prn_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \tl_if_eq:VnT \l__nmcC_tl { ! } { \__nmc_delim_append: } \__nmc_delim_stop_if_gtr:n { \c__nmc_sum_int } } } \cs_new_protected:Npn \__nmc_delim_cleave: { \__nmc_next: \tl_if_eq:VnTF \l__nmcB_tl { \q } { \int_zero:N \l__nmc_delim_pos_int } % adhere { \bool_set_true:N \l__nmc_delim_stop_bool } % sever } \cs_new_protected:Npn \__nmc_delim_nary: { \__nmc_if_pospas_gtr:nTF { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \__nmc_get_arg_LR:NNN ( \l__nmcB_tl ) \__nmc_put_right_wrap:NnNn \l__nmc_delim_arg_tl { ( } \l__nmcB_tl { ) } \__nmc_delim_stop_if_gtr:n { \c__nmc_sum_int } } } \cs_new_protected:Npn \__nmc_delim_comma: { \__nmc_if_pospas_gtr:nTF { \c__nmc_cmp_int } { \__nmc_delim_stop: } { \__nmc_delim_append: } } \cs_new_protected:Npn \__nmc_delim_sum: { \__nmc_if_pospas_gtr:nTF { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \__nmc_delim_append: \__nmc_delim_append_braced: \__nmc_delim_append: \__nmc_delim_append_braced: \__nmc_delim_arg:Nnn \l__nmc_delim_argi_tl { 1 } { \c__nmc_sum_int } \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmc_delim_argi_tl \__nmc_delim_stop_if_gtr:n { \c__nmc_cmp_int } } } \cs_new_protected:Npn \__nmc_delim_absorb: { \__nmc_next: \int_decr:N \l__nmc_delim_pos_int } \cs_new_protected:Npn \__nmc_delim_absorb_i: { \__nmc_delim_absorb: \__nmc_next: } \cs_new_protected:Npn \__nmc_delim_absorb_ii: { \__nmc_delim_absorb_i: \str_case:VnT \l__nmcB_tl { { * } { } { [ } { \__nmc_get_arg_LR:NNN [ \l__nmc_toss_tl ] } } { \__nmc_next: } } \cs_new_protected:Npn \__nmc_delim_color: { \__nmc_next: \str_if_eq:VnT \l__nmcC_tl { [ } { \__nmc_next: \__nmc_get_arg_LR:NNN [ \l__nmc_toss_tl ] } \__nmc_delim_font: } \cs_new_protected:Npn \__nmc_delim_font: { \__nmc_next: \__nmc_next: \tl_put_left:NV \l__nmcA_tl \l__nmcB_tl \tl_set:Nx \l__nmcC_tl { \tl_head:N \l__nmcB_tl } \int_decr:N \l__nmc_delim_pos_int } \cs_new_protected:Npn \__nmc_delim_mkern: { \__nmc_delim_absorb: \__nmc_fpify_mkern: } \cs_new_protected:Npn \__nmc_delim_BE: { \__nmc_if_pospas_gtr:nTF { \c__nmc_cmp_int } { \__nmc_delim_stop: } { \__nmc_next: \__nmc_next: \str_if_in:VnTF \l__nmcB_tl { alignat } { \__nmc_next: } \tl_put_right:Nn \l__nmc_delim_arg_tl { \c_group_begin_token } \__nmc_get_arg_LR:NNN \begin \l__nmc_delim_arg_tl \end \tl_put_right:Nn \l__nmc_delim_arg_tl { \c_group_end_token } \__nmc_next: } } \cs_new_protected:Npn \__nmc_delim_cmd: { % \cmd { s O m O O } \__nmc_if_pospas_gtr:nTF { \c__nmc_sum_int } { \__nmc_delim_stop: } { \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmcC_tl \__nmc_next: \tl_if_eq:VnT \l__nmcC_tl { * } { \__nmc_next: } \tl_put_right:Nn \l__nmc_delim_arg_tl { * } \__nmc_delim_nmcfn_aux:NN [ ] \__nmc_next: \tl_put_right:Nx \l__nmc_delim_arg_tl { { \exp_not:o \l__nmcB_tl } } \__nmc_delim_nmcfn_aux:NN [ ] \__nmc_delim_nmcfn_aux:NN [ ] } } \cs_new_protected:Npn \__nmc_delim_nmcfn_aux:NN #1#2 { \tl_if_eq:VnT \l__nmcC_tl { [ } { \__nmc_next: \tl_clear:N \l_tmpa_tl \__nmc_get_arg_LR:NNN #1 \l_tmpa_tl ] \__nmc_put_right_wrap:NnNn \l__nmc_delim_arg_tl { #1 } \l_tmpa_tl { #2 } } } %%%%%%%%% info on "infinite" processes %%%%%%%%%% \nmc_define:NnN \nmcInfo { info } \info \clist_map_inline:nn { sum,prod } { \tl_new:c { g__nmc_info_#1_tl } \tl_gset:cn { g__nmc_info_#1_tl } { 0 } } \seq_new:N \l_nmc_info_seq \clist_new:N \g__nmc_info_proc_clist \clist_gset:Nn \g__nmc_info_proc_clist { sum, prod } \cs_set_protected:Npn \__nmc_info_initialize: { \seq_clear:N \l_tmpa_seq \tl_set:Nn \l__nmc_dbg_idii_tl { process } \clist_map_inline:Nn \g__nmc_info_proc_clist { \seq_put_right:Nx \l_nmc_info_seq { ##1~{ \use:c { g__nmc_info_##1_tl } } } } } \cs_set_protected:Npn \__nmc_info_formula: { \tl_clear:N \l__nmc_formula_dup_tl } \cs_set_protected:Npn \__nmc_info_process: { \int_if_zero:nTF \l__nmc_dbg_int { \tl_set_eq:Nc \l__nmc_result_tl { g__nmc_info_\l__nmc_formula_tl _tl } } { \tl_set:Nx \l__nmc_formula_tl { \seq_use:Nn \l_nmc_info_seq {,~} } } } \cs_set_protected:Npn \__nmc_info_display: { \tl_set_eq:NN \l__nmc_show_tl \l__nmc_result_tl \bool_if:NF \l__nmc_num_only_bool { \prop_if_in:NVTF \g__nmc_subst_misc_prop \l__nmc_formula_tl { \tl_if_empty:cT { g__nmc_info_\l__nmc_formula_tl _tl } { \tl_set:Nn \l__nmc_show_tl { 0 } } \prop_get:NVN \g__nmc_subst_misc_prop \l__nmc_formula_tl \l_tmpb_tl \tl_put_right:Nn \l__nmc_show_tl { \ } \tl_put_right:NV \l__nmc_show_tl \l_tmpb_tl % pluralise? \int_if_zero:nF { \l__nmc_result_tl - 1 } { \tl_put_right:Nn \l__nmc_show_tl { s } } \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl } { \__nmc_error_where:n { info~command } \__nmc_error_what:n { Unknown~process~\__nmc_verb:N \l__nmc_formula_tl\ in } } } \l__nmc_show_tl } %%%%%%%%%%%%% user-defined macros %%%%%%%%%%%%%%% \clist_new:N \g__nmc_macros_clist \clist_new:N \l__nmc_macrosa_clist \clist_new:N \l__nmc_macrosb_clist \bool_new:N \l__nmc_macros_free_bool \nmc_define:NnN \nmcMacros { macros } \macros \cs_set_protected:Npn \__nmc_macros_initialize: { \tl_set:Nn \l__nmc_dbg_idii_tl { macros } \tl_set:Nn \l__nmc_dbg_idv_tl { stored } \tl_set_eq:NN \l__nmc_multi_delim_tl \c__nmc_vv_delim_tl } \cs_set_protected:Npn \__nmc_macros_vv_digest:N #1 { \__nmc_error_where:n { macros~command } \seq_set_split:NVV \l_tmpa_seq \l__nmc_multi_delim_tl \l__nmc_formula_tl \clist_set:Nx \l__nmc_macrosa_clist { \seq_use:Nn \l_tmpa_seq {,} } \clist_clear:N \l__nmc_macrosb_clist \clist_map_inline:Nn \l__nmc_macrosa_clist { \cs_if_exist:NTF ##1 { \__nmc_storemacros:NN \l__nmc_macrosb_clist ##1 } { \__nmc_error_what:n { Undefined~macro~\__nmc_verb:n {##1}in } \clist_map_break: } } \bool_if:NF \g__nmc_error_bool { \tl_set:No \l__nmc_formula_tl \l__nmc_macrosb_clist \__nmc_vv_digest:N #1 \int_if_zero:nF \l__nmc_dbg_int { \__nmc_dbg_vv_view:n { 0 } } \clist_set:No \l__nmc_macrosb_clist \l__nmc_formula_tl } } % https://tex.stackexchange.com/questions/683578/storing-the-unknown-contents-of-a-macro-in-a-clist % (thanks to David Carlisle) % #1 clist #2 macro \cs_new_protected:Npn \__nmc_storemacros:NN #1#2 { \ifcsname \exp_after:wN \use_none:n \token_to_str:N #2~ code \endcsname \exp_after:wN\exp_after:wN\exp_after:wN \clist_put_right:Nn \exp_after:wN\exp_after:wN\exp_after:wN #1 \exp_after:wN\exp_after:wN\exp_after:wN { \exp_after:wN\exp_after:wN\exp_after:wN #2 \exp_after:wN\exp_after:wN \exp_after:wN { \csname \exp_after:wN \use_none:n \token_to_str:N #2~ code \endcsname } } \else \exp_after:wN \clist_put_right:Nn \exp_after:wN #1 \exp_after:wN { \exp_after:wN #2 \exp_after:wN { #2 } } \fi } \cs_set_protected:Npn \__nmc_macros_process: { \bool_if:NTF \l__nmc_macros_free_bool { \__nmc_macros_deregister:N \l__nmc_macrosa_clist } { \__nmc_macros_register:N \l__nmc_macrosb_clist } \clist_gremove_duplicates:N \g__nmc_macros_clist \bool_if:NT \l__nmc_num_only_bool { \tl_set:Nx \l__nmc_result_tl {\clist_count:N \g__nmc_macros_clist }} } \cs_set_protected:Npn \__nmc_macros_display: { \bool_if:NT \l__nmc_num_only_bool { \l__nmc_result_tl } } %%%%%%%%%% \cs_new_protected:Npn \__nmc_macros_deregister:N #1 { \clist_if_empty:NT #1 { \clist_set_eq:NN #1 \g__nmc_macros_clist \tl_set:No \l__nmc_formula_tl \g__nmc_macros_clist } \clist_map_inline:Nn #1 { \cs_if_exist:NT ##1 { \clist_gremove_all:Nn \g__nmc_macros_clist { ##1 } \prop_gremove:NV \g__nmc_subst_var_prop { ##1 } } } \__nmc_macros_reg_dbg_aux:Nn \c_true_bool { freed } } \cs_new_protected:Npn \__nmc_macros_register:N #1 { \__nmc_error_where:n { macros~command } \clist_reverse:N #1 \clist_map_inline:Nn #1 { \__nmc_macros_reg_split:w ##1\q_stop \bool_if:NT \g__nmc_error_bool { \clist_map_break: } } \bool_if:NF \g__nmc_error_bool { \__nmc_macros_reg_props: } } \cs_new_protected:Npn \__nmc_macros_reg_split:w #1#2\q_stop { \tl_clear:N \l__nmc_vv_fp_expr_tl \__nmc_fpify:nN { #2 } \l__nmc_vv_fp_expr_tl \bool_if:NF \g__nmc_error_bool { \prop_put:Nnx \l__nmc_subst_var_prop { #1 } { \fp_eval:n \l__nmc_vv_fp_expr_tl } \__nmc_error_fpflag: } } \cs_new_protected:Npn \__nmc_macros_reg_props: { \clist_gconcat:NNN \g__nmc_macros_clist \l__nmc_macrosa_clist \g__nmc_macros_clist \clist_remove_duplicates:N \g__nmc_macros_clist \clist_map_inline:Nn \l__nmc_macrosa_clist { \prop_get:NnN \l__nmc_subst_var_prop { ##1 } \l_tmpa_tl \prop_gput:Nno \g__nmc_subst_var_prop { ##1 } \l_tmpa_tl } \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl \int_if_zero:nF { \l__nmc_dbg_int } { \__nmc_macros_reg_dbg: } } \cs_new_protected:Npn \__nmc_macros_reg_dbg: { \tl_if_empty:NTF \l__nmc_formula_tl { \__nmc_macros_reg_dbg_aux:Nn \c_true_bool { macros } \clist_clear:N \l__nmc_macrosb_clist \clist_map_inline:Nn \g__nmc_macros_clist { \__nmc_storemacros:NN \l__nmc_macrosb_clist ##1 } \tl_set:No \l__nmc_formula_tl \l__nmc_macrosb_clist } { \__nmc_macros_reg_dbg_aux:Nn \l__nmc_macros_free_bool { added } } } \cs_new_protected:Npn \__nmc_macros_reg_dbg_aux:Nn #1#2 { \tl_set:Nn \l__nmc_dbg_idii_tl { #2 } \bool_if:nT { #1 || \seq_if_empty_p:N \l__nmc_vva_seq } { \int_if_zero:nF { \l__nmc_dbg_int } { \int_set:Nn \l__nmc_dbg_int { 2*5 } } } \seq_set_from_clist:NN \l__nmc_dbg_stored_seq \g__nmc_macros_clist } %%%%%%%%%%%% user-defined constants %%%%%%%%%%%%% \seq_new:N \g__nmc_consts_seq % all \seq_new:N \g__nmc_consts_vv_seq % multitok in vv-list \seq_new:N \l__nmc_constsa_seq \seq_new:N \l__nmc_constsb_seq \int_new:N \g__nmc_consts_vv_int % count multitok + 1 \int_gincr:N \g__nmc_consts_vv_int % the +1 if zero \bool_new:N \l__nmc_consts_add_bool \nmc_define:NnN \nmcConstants { consts } \constants \cs_set_protected:Npn \__nmc_consts_initialize: { \tl_set:Nn \l__nmc_dbg_idii_tl { added } \tl_set:Nn \l__nmc_dbg_idv_tl { constants } \tl_set_eq:NN \l__nmc_multi_delim_tl \c__nmc_vv_delim_tl } \cs_set_protected:Npn \__nmc_consts_vv_digest:N #1 { % #1=*reversed* vv-list \bool_if:nF { \l__nmc_consts_add_bool || \tl_if_empty_p:N \l__nmc_formula_tl } { \__nmc_consts_clear: } \seq_set_split:NVV \l__nmc_constsa_seq \l__nmc_multi_delim_tl \l__nmc_formula_tl \seq_remove_all:Nn \l__nmc_constsa_seq {} \seq_reverse:N \l__nmc_constsa_seq \seq_concat:NNN \l__nmc_constsb_seq #1 \l__nmc_constsa_seq \__nmc_vv_digest:N \l__nmc_constsb_seq \seq_set_split:NVV \l__nmc_constsb_seq \l__nmc_multi_delim_tl \l__nmc_formula_tl \seq_remove_all:Nn \l__nmc_constsb_seq {} \seq_reverse:N \l__nmc_constsb_seq \tl_set:Nx \l__nmc_formula_tl { \seq_use:NV \l__nmc_constsb_seq \c__nmc_vv_delim_tl } \int_if_zero:nF \l__nmc_dbg_int { \__nmc_dbg_vv_view:n { \seq_count:N \l__nmc_constsa_seq } } } \cs_new_protected:Npn \__nmc_consts_clear: { \seq_gclear:N \g__nmc_consts_vv_seq \seq_map_inline:Nn \g__nmc_consts_seq { \__nmc_split_eq:w ##1\q_stop \prop_gremove:NV \g__nmc_subst_var_prop \l__nmc_eq_var_tl } \seq_gclear:N \g__nmc_consts_seq } \cs_set_protected:Npn \__nmc_consts_process: { \__nmc_error_where:n { constants~command } \tl_if_empty:NF \l__nmc_formula_tl { \seq_map_inline:Nn \l__nmc_constsb_seq { \__nmc_split_eq:w ##1\q_stop \prop_get:NVN \l__nmc_subst_var_prop \l__nmc_eq_var_tl \l_tmpb_tl \seq_pop:NN \l__nmc_constsa_seq \l_tmpa_tl \exp_last_unbraced:No\__nmc_split_eq:w \l_tmpa_tl\q_stop \int_compare:nNnTF { \tl_count:N \l__nmc_eq_var_tl } = { 1 } { \prop_gput:NVV \g__nmc_subst_var_prop \l__nmc_eq_var_tl \l_tmpb_tl \tl_set:Nx \l_tmpa_tl { \exp_not:o \l__nmc_eq_var_tl = \l_tmpb_tl } } { \tl_set:Nx \l_tmpb_tl { \fp_eval:n \l_tmpb_tl } % 1e2 => 100 \tl_set:Nx \l_tmpa_tl { \exp_not:o \l__nmc_eq_var_tl = \l_tmpb_tl } \bool_if:NT \l__nmc_dec_comma_bool { \tl_replace_once:Nnn \l_tmpb_tl {.} {,} } \tl_put_left:Nx \l_tmpb_tl { \exp_not:o \l__nmc_eq_var_tl = } \seq_gput_right:NV \g__nmc_consts_vv_seq \l_tmpb_tl % , } \seq_gput_right:NV \g__nmc_consts_seq \l_tmpa_tl % . } \int_gset:Nn \g__nmc_consts_vv_int { 1 + \seq_count:N \g__nmc_consts_vv_seq } } \int_compare:nNnT { \l__nmc_dbg_int } = { 30 } { \tl_if_empty:NT \l__nmc_formula_tl { \int_set:Nn \l__nmc_dbg_int { \l__nmc_dbg_int / 2 } } \seq_if_empty:NT \l__nmc_vva_seq { \int_set:Nn \l__nmc_dbg_int { \l__nmc_dbg_int / 3 } } } \seq_set_eq:NN \l__nmc_dbg_stored_seq \g__nmc_consts_seq \bool_if:NT \l__nmc_num_only_bool { \tl_set:Nx \l__nmc_result_tl { \seq_count:N \g__nmc_consts_seq } } } \cs_set_protected:Npn \__nmc_consts_display: { \bool_if:NT \l__nmc_num_only_bool { \bool_if:NT \l__nmc_num_only_bool { \l__nmc_result_tl } } } %%%%%%% save/retrieve results to/from file %%%%%% \tl_new:N \g__nmc_reuse_tl \bool_new:N \l__nmc_reuse_named_bool \bool_new:N \g__nmc_reuse_filed_bool \bool_new:N \g__nmc_reuse_defined_bool \tl_new:N \g__nmc_reuse_filed_tl \clist_new:N \g__nmc_reuse_exclude_clist \seq_new:N \g__nmc_reuse_names_seq \int_new:N \l__nmc_reuse_mode_int \ior_new:N \g__nmc_ior \iow_new:N \g__nmc_iow \tl_gset:Nn \g__nmc_reuse_filename_tl { .nmc } \tl_gput_left:NV \g__nmc_reuse_filename_tl \jobname % save \g__nmc_reuse_tl from last \eval-uation etc to \#1 \nmc_define:NnN \nmcReuse { reuse } \reuse \cs_set_protected:Npn \__nmc_reuse_initialize: { \tl_set:Nn \l__nmc_dbg_idiii_tl { saved } } \cs_set_protected:Npn \__nmc_reuse_process: { \__nmc_error_where:n { reuse~command } \__nmc_reuse_filed: \tl_if_empty:NTF \l__nmc_formula_tl { \int_if_zero:nTF { 1 + \l__nmc_reuse_mode_int } { \__nmc_reuse_delete_all: } { \__nmc_reuse_define: } } { \int_case:nn \l__nmc_reuse_mode_int { { -1 } { \__nmc_reuse_delete_one:c \l__nmc_formula_tl } { 0 } { \__nmc_reuse_save_one:c \l__nmc_formula_tl } { 1 } { \__nmc_reuse_delete_one:c \l__nmc_formula_tl \__nmc_reuse_save_one:c \l__nmc_formula_tl } { 2 } { \__nmc_reuse_load_one: } } } \__nmc_reuse_view:Nn \l__nmc_formula_tl { \l__nmc_dbg_int } } \cs_set_protected:Npn \__nmc_reuse_display: { \bool_if:NT \l__nmc_num_only_bool { \bool_if:NF \g__nmc_reuse_filed_bool { \__nmc_reuse_filed: } \clist_count:N \g__nmc_reuse_filed_tl } } %%%%%%%%%% \cs_new_protected:Npn \__nmc_reuse_filed: { \bool_gset_false:N \g__nmc_reuse_filed_bool \file_get:VnNT \g__nmc_reuse_filename_tl {} \g__nmc_reuse_filed_tl { \bool_lazy_or:nnTF { \tl_if_empty_p:N \g__nmc_reuse_filed_tl } { \tl_if_head_eq_meaning_p:VN \g__nmc_reuse_filed_tl \par } { \tl_gclear:N \g__nmc_reuse_filed_tl } { \bool_gset_true:N \g__nmc_reuse_filed_bool \seq_gclear:N \g__nmc_reuse_names_seq \clist_gclear:N \g__nmc_reuse_exclude_clist \clist_gset:NV \g__nmc_reuse_filed_tl \g__nmc_reuse_filed_tl \clist_map_inline:Nn \g__nmc_reuse_filed_tl { \__nmc_reuse_names:Nn ##1 } } } } \cs_new_protected:Npn \__nmc_reuse_names:Nn #1#2 { \seq_gput_right:Nn \g__nmc_reuse_names_seq #1 \cs_if_free:NF #1 { \clist_gput_right:Nn \g__nmc_reuse_exclude_clist #1 } } \cs_new_protected:Npn \__nmc_reuse_define: { \__nmc_error_where:n { \g__nmc_reuse_filename_tl } \clist_map_inline:Nn \g__nmc_reuse_filed_tl { \__nmc_reuse_gset:Nn ##1 } \bool_gset_true:N \g__nmc_reuse_defined_bool \seq_gpop:NN \g__nmc_error_where_seq \l_tmpa_tl } \cs_new_protected:Npn \__nmc_reuse_gset:Nn #1#2 { \cs_if_free:NT #1 { \tl_gset:Nn #1 { #2 } } } %%%%%%%%% \cs_new_protected:Npn \__nmc_reuse_load_one: { \clist_map_inline:Nn \g__nmc_reuse_filed_tl { \__nmc_reuse_load_one:cNn \l__nmc_formula_tl ##1 } } \cs_new_protected:Npn \__nmc_reuse_load_one:NNn #1#2#3 { \tl_if_eq:nnT { #1 } { #2 } { \__nmc_reuse_gset:Nn #2 { #3 } \clist_map_break: } } \cs_generate_variant:Nn \__nmc_reuse_load_one:NNn { c } \cs_new_protected:Npn \__nmc_reuse_delete_all: { \seq_map_inline:Nn \g__nmc_reuse_names_seq { \clist_if_in:NnF \g__nmc_reuse_exclude_clist { ##1 } { \cs_undefine:N ##1 } } \tl_gclear:N \g__nmc_reuse_filed_tl \seq_gclear:N \g__nmc_reuse_names_seq \clist_gclear:N \g__nmc_reuse_exclude_clist \bool_gset_false:N \g__nmc_reuse_filed_bool \bool_gset_false:N \g__nmc_reuse_defined_bool \iow_open:NV \g__nmc_iow \g__nmc_reuse_filename_tl \iow_close:N \g__nmc_iow } \cs_new_protected:Npn \__nmc_reuse_delete_one:N #1 { \seq_gremove_all:Nn \g__nmc_reuse_names_seq { #1 } \clist_gremove_all:Nn \g__nmc_reuse_exclude_clist { #1 } \tl_gset:NV \g_tmpa_tl \g__nmc_reuse_filed_tl \tl_gclear:N \g__nmc_reuse_filed_tl \clist_map_inline:Nn \g_tmpa_tl { \__nmc_reuse_undefine:NNn #1 ##1 } \iow_open:NV \g__nmc_iow \g__nmc_reuse_filename_tl \iow_now:NV \g__nmc_iow \g__nmc_reuse_filed_tl \iow_close:N \g__nmc_iow } \cs_generate_variant:Nn \__nmc_reuse_delete_one:N { c } \cs_new_protected:Npn \__nmc_reuse_undefine:NNn #1#2#3 { \tl_if_eq:nnTF { #1 } { #2 } { \cs_undefine:N #1 } { \clist_gput_right:Nn \g__nmc_reuse_filed_tl { #2 { #3 } } } } \cs_new_protected:Npn \__nmc_reuse_save_one:N #1 { \__nmc_reuse_check_name:N #1 \bool_if:nF { \g__nmc_error_bool || \l__nmc_reuse_named_bool } { \tl_set:Nx \l_tmpa_tl { { \exp_not:o \g__nmc_reuse_tl } } \tl_put_left:Nn \l_tmpa_tl { #1 } \exp_last_unbraced:NV \tl_gset:Nn \l_tmpa_tl \clist_gput_left:NV \g__nmc_reuse_filed_tl \l_tmpa_tl \iow_open:NV \g__nmc_iow \g__nmc_reuse_filename_tl \str_set:NV \l_tmpa_str \g__nmc_reuse_filed_tl \iow_now:NV \g__nmc_iow \l_tmpa_str \iow_close:N \g__nmc_iow } } \cs_generate_variant:Nn \__nmc_reuse_save_one:N { c } \cs_new_protected:Npn \__nmc_reuse_check_name:N #1 { \seq_if_in:NnTF \g__nmc_reuse_names_seq { #1 } { \__nmc_error_where:n { \g__nmc_reuse_filename_tl } \tl_set:Nx \l_tmpa_tl { { \exp_not:o \g__nmc_reuse_tl } } \tl_put_left:Nn \l_tmpa_tl { #1 } \str_if_in:NVTF \g__nmc_reuse_filed_tl \l_tmpa_tl { \exp_last_unbraced:NV \tl_gset:Nn \l_tmpa_tl \bool_set_true:N \l__nmc_reuse_named_bool } { \tl_if_empty:NTF \g__nmc_reuse_tl { \__nmc_reuse_load_one: \bool_set_true:N \l__nmc_reuse_named_bool \__nmc_error_what:n { Nothing~to~save~to~\__nmc_verb:n { #1 } in } } { \__nmc_error_what:n { Saved~value~for~\__nmc_verb:n {#1} already~exists~in~file } } } \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl } { \tl_if_empty:NTF \g__nmc_reuse_tl { \__nmc_error_what:n { Nothing~to~save~to~\__nmc_verb:n {#1} in } } { \cs_if_exist:NT #1 { \__nmc_error_what:n { \__nmc_verb:n { #1 } defined~elsewhere;~failed~save~in } } } } } \cs_new_protected:Npn \__nmc_reuse_view:Nn #1#2 { \tl_set:Nx \l__nmc_dbg_vv_tl { \clist_use:Nn \g__nmc_reuse_filed_tl {,~} } } %%%%%%%%%%%%%%%%%%% settings %%%%%%%%%%%%%%%%%%%% \bool_new:N \l__nmc_vv_settings_bool \bool_new:N \l__nmc_env_rbrace_bool \bool_new:N \l__nmc_num_spaces_bool \bool_new:N \l__nmc_multitok_bool \bool_new:N \l__nmc_deg_bool \bool_new:N \l__nmc_sci_num_in_bool \int_new:N \l__nmc_see_force_int \tl_new:N \l__nmc_sci_num_in_tl \tl_new:N \l__nmc_s_vv_tl \tl_new:N \l__nmc_multi_punc_tl \tl_new:N \l__nmc_env_rbrace_tl \tl_new:N \l__nmc_env_sp_rbrace_tl \tl_new:N \l__nmc_multi_sep_tl \int_new:N \l__nmc_dbg_int \int_new:N \l__nmc_prod_extra_int \int_new:N \l__nmc_prod_query_int \regex_new:N \l__nmc_num_regex \cs_new_protected:Npn \__nmc_num_spaces:n #1 { \int_if_zero:nTF { #1 } { \regex_set:Nn \l__nmc_num_regex { (\-?\d*[.,]?\d*) } } { \regex_set:Nn \l__nmc_num_regex { (\-?[\s\d]*[.,]?[\s\d]*) } } \bool_if:NT \l__nmc_sci_num_in_bool { \exp_args:NV \__nmc_sci_num_in:nn \l__nmc_sci_num_in_tl { #1 } } } \cs_set_protected:Npn \__nmc_sci_num_in:nn #1#2 { \int_if_zero:nTF { #2 } { \regex_set:Nn \l__nmc_num_regex { (\-?\d*[.,]?\d*(?:#1\d+|#1\-\d+)?) } } { \regex_set:Nn \l__nmc_num_regex { (\-?[\s\d]*[.,]?[\s\d]*(?:#1\d+|#1\-\d+)?) } } } \cs_new_protected:Npn \__nmc_dbg_int:nn #1#2 { \int_compare:nNnTF { \int_abs:n { #1 } } = { 1 } { \int_set:Nn \l__nmc_dbg_int { \int_sign:n { #1 }*#2 } } { \int_set:Nn \l__nmc_dbg_int { #1 } } } \cs_new:Npn \__nmc_int_to_bool:Nn #1#2 { \bool_set:Nn #1 { !\int_if_zero_p:n { #2 } } } \cs_new:Npn \__nmc_deg: { \bool_if:NT { \l__nmc_deg_bool } { d } } \cs_new:Npn \__nmc_set_dead:n #1 { See~the~documentation;~\__nmc_verb:n {`#1'}~key~discontinued~in } \keys_define:nn { numerica/generic } { dbg .code:n = \__nmc_dbg_int:nn { #1 } { 2*3*5*7*11 }, dbg .initial:n = 0, ^ .code:n = \bool_set_true:N \l__nmc_sci_num_in_bool \tl_set:Nn \l__nmc_sci_num_in_tl { #1 } \__nmc_sci_num_in:nn { #1 } { 0 }, ^ .default:n = e, xx .code:n = \__nmc_int_to_bool:Nn \l__nmc_multitok_bool { #1 }, xx .initial:n = 1, ff .tl_set:N = \l__nmc_multi_delim_tl, ff .default:V = \c__nmc_vv_delim_tl, ff .initial:n = \prg_do_nothing:, 1s2 .code:n = \__nmc_num_spaces:n { #1 }, 1s2 .default:n = 1, 1s2 .initial:n = 0, /min .int_set:N = \l__nmc_frac_denom_min_int, /min .initial:n = 1, /max .int_set:N = \l__nmc_frac_denom_max_int, /max .initial:n = 200, vvmode .code:n = \__nmc_calc_mode:n { \int_if_zero:nTF { #1 }01 }, vv@ .code:n = \__nmc_calc_mode:n { \int_if_zero:nTF { #1 }01 }, vv@ .initial:n = 0, o .code:n = \__nmc_int_to_bool:Nn \l__nmc_deg_bool { #1 }, o .default:n = 1, o .initial:n = 0, log .tl_set:N = \l__nmc_log_base_tl, log .initial:n = 10, S+ .int_set:N = \l__nmc_sum_extra_int, S+ .initial:n = 2, S? .int_set:N = \l__nmc_sum_query_int, S? .initial:n = 0, P+ .int_set:N = \l__nmc_prod_extra_int, P+ .initial:n = 2, P? .int_set:N = \l__nmc_prod_query_int, P? .initial:n = 0, % env .tl_set:N = \l__nmc_env_s_tl, arg .tl_set:N = \l__nmc_env_s_arg_tl, eq .tl_set:N = \l__nmc_s_equals_tl, eq .default:n = {=}, vvi .code:n = \bool_set_true:N \l__nmc_vv_settings_bool \tl_set:Nn \l__nmc_s_vv_tl { #1 }, % deprecated vvd .code:n = \bool_set_true:N \l__nmc_vv_settings_bool \tl_set:Nn \l__nmc_s_vv_tl { #1 }, % deprecated vv .code:n = \bool_set_true:N \l__nmc_vv_settings_bool \tl_set:Nn \l__nmc_s_vv_tl { #1 }, pp .tl_set:N = \l__nmc_multi_punc_tl, pp .default:n = {,}, sep .tl_set:N = \l__nmc_s_multi_sep_tl, \} .code:n = \tl_set:Nn \l__nmc_env_rbrace_tl { #1 } \bool_set_true:N \l__nmc_env_rbrace_bool, \} .default:n = \ \}, p .tl_set:N = \l__nmc_punc_tl, p .default:n = {,}, f .int_set:N = \l__nmc_see_force_int, f .initial:n = -1, % () .code:n = \__nmc_error_what:n { \__nmc_set_dead:n { () } } \int_zero:N \l__nmc_dbg_int, reuse .code:n = \__nmc_error_what:n { \__nmc_set_dead:n { reuse } }, * .code:n = \msg_warning:nnn {numerica} {base} { settings:~*~key~discontinued;~use~e.g.~env=multline* } } % display related \keys_define:nn { numerica/eval } { view .code:n = \__nmc_dbg_int:nn { 1 } { 2*3*5*7*11 } } \keys_define:nn { numerica/info } { view .code:n = \__nmc_dbg_int:nn { 1 } { 2 } } \keys_define:nn { numerica/macros } { view .code:n = \__nmc_dbg_int:nn { 1 } { 2*3*5 }, free .code:n = \bool_set_true:N \l__nmc_macros_free_bool } \keys_define:nn { numerica/consts } { view .code:n = \__nmc_dbg_int:nn { 1 } { 2*3*5 }, add .code:n = \bool_set_true:N \l__nmc_consts_add_bool } \keys_define:nn { numerica/reuse } { view .code:n = \__nmc_dbg_int:nn { 1 } { 3 }, delete .code:n = \int_set:Nn \l__nmc_reuse_mode_int { -1 }, save .code:n = \int_set:Nn \l__nmc_reuse_mode_int { 0 }, renew .code:n = \int_set:Nn \l__nmc_reuse_mode_int { 1 }, load .code:n = \int_set:Nn \l__nmc_reuse_mode_int { 2 } } %%%%%%%%%% % for debugging \__nmc_fpify:nN & \__nmc_delim_arg:Nnn % A, B, C generated by \__nmc_next: % \ProvideDocumentCommand \abc {} % { % \exp_args:Nx \clist_show:n % { % { A~=~\exp_not:o \l__nmcA_tl }, % { B~=~\exp_not:o \l__nmcB_tl }, % { C~=~\exp_not:o \l__nmcC_tl } % } % } % end of file `numerica.sty'