% This is file `numerica.sty', % the base of the `numerica' package. % % 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{expl3}[2017/07/15] \RequirePackage{xparse,l3keys2e} \RequirePackage{amsmath,mathtools} \ProvidesExplPackage {numerica} {2021/02/15} {1.0.0} {Evaluate math expressions in the LaTeX form they are typeset} %------------------------------------------------ \cs_if_free:NT \arccsc { \DeclareMathOperator{\arccsc}{arccsc} } \cs_if_free:NT \arcsec { \DeclareMathOperator{\arcsec}{arcsec} } \cs_if_free:NT \arccot { \DeclareMathOperator{\arccot}{arccot} } \cs_if_free:NT \csch { \DeclareMathOperator{\csch}{csch} } \cs_if_free:NT \sech { \DeclareMathOperator{\sech}{sech} } \cs_if_free:NT \asinh { \DeclareMathOperator{\asinh}{asinh} } \cs_if_free:NT \acosh { \DeclareMathOperator{\acosh}{acosh} } \cs_if_free:NT \atanh { \DeclareMathOperator{\atanh}{atanh} } \cs_if_free:NT \acsch { \DeclareMathOperator{\acsch}{acsch} } \cs_if_free:NT \asech { \DeclareMathOperator{\asech}{asech} } \cs_if_free:NT \acoth { \DeclareMathOperator{\acoth}{acoth} } \cs_if_free:NT \sgn { \DeclareMathOperator{\sgn}{sgn} } \cs_if_free:NT \lb { \DeclareMathOperator{\lb}{lb} } % mathtools \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} } \RenewDocumentCommand \land {} { \,\wedge\, } \RenewDocumentCommand \lor {} { \,\vee\, } % Qleave apart; qleave to \NewDocumentCommand \Q {} { \prg_do_nothing: } \NewDocumentCommand \q {} { \prg_do_nothing: } \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: } } % constants \tl_const:Nn \c__nmc_digits_tl { 123456789 } \tl_const:Nn \c__nmc_decimals_tl { 1234567890. } \tl_const:Nn \c__nmc_sdigits_tl { -1234567890 } \tl_const:Nn \c__nmc_comparisons_tl { <=> } \tl_const:Nn \c__nmc_modds_tl { |./ } \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_trg_int { 3 } \int_const:Nn \c__nmc_uny_int { 4 } \int_const:Nn \c__nmc_prn_int { 5 } \int_const:Nn \c__nmc_srd_int { 6 } \seq_const_from_clist:Nn \c__nmc_T_out_seq { 1,T,\texttt{T} } \seq_const_from_clist:Nn \c__nmc_F_out_seq { 0,F,\texttt{F} } \int_new:N \l__nmc_trg_int \int_new:N \l__nmc_num_sgn_int \tl_new:N \l__nmc_toss_tl \seq_new:N \l_tmpc_seq %----------------------------------------------------------- % processing and substitution property lists % #1 clist of keys; #2 tl of values \cs_new_protected:Npn \__nmc_fill_class:nn #1#2 { \clist_map_inline:nn { #1 } { \prop_gput:Nnn \g__nmc_class_prop { ##1 } { #2 } } } % math token classes \prop_new:N \g__nmc_class_prop % decimals \__nmc_fill_class:nn { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, . } { \__nmc_fpify_dec: \__nmc_delim_dec: } % constants \__nmc_fill_class:nn { e, \pi, \gamma, \phi, \deg, \infty } { \__nmc_fpify_const: \__nmc_delim_const: } % plus minus \__nmc_fill_class:nn { +, - } { \__nmc_fpify_arith: \__nmc_delim_pm: } % arith. \prop_put:Nnn \g__nmc_class_prop { * } { \__nmc_fpify_arith: \__nmc_delim_arith: } % slash \prop_put:Nnn \g__nmc_class_prop { / } { \__nmc_fpify_slash: \__nmc_delim_arith: } % arith. alternatives \__nmc_fill_class:nn { \times, \cdot, \div } { \__nmc_fpify_arith_alt: \__nmc_delim_arith: } % 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: } % and or \__nmc_fill_class:nn { \wedge, \land, \vee, \lor } { \__nmc_fpify_andor: \__nmc_delim_andor: } % lparen \__nmc_fill_class:nn { (, [, \{, \lparen, \lbrack, \lbrace } { \__nmc_fpify_lparen: \__nmc_delim_lparen: } % lvert etc. \__nmc_fill_class:nn { |, \lvert, \lfloor, \lceil } { \__nmc_fpify_lvert: \__nmc_delim_lvert: } % lmodifiers \__nmc_fill_class:nn { \left, \bigl, \Bigl, \biggl, \Biggl } { \__nmc_fpify_lmod: \__nmc_delim_lmod: } % rmodifiers \__nmc_fill_class:nn { \right, \bigr, \Bigr, \biggr, \Biggr } { \prg_do_nothing: \__nmc_delim_rparen: } % trig, hyper, other unary fns \__nmc_fill_class:nn { \sin, \cos, \tan, \csc, \sec, \cot } { { \__nmc_fpify_unary:n { \l__nmc_trg_int } } { \__nmc_delim_unary:n { \l__nmc_trg_int } } } \__nmc_fill_class:nn { \arcsin, \arccos, \arctan, \arccsc, \arcsec, \arccot, \sinh, \cosh, \tanh, \csch, \sech, \coth, \asinh, \acosh, \atanh, \acsch, \asech, \acoth, \exp, \ln, \lg, \lb, \sgn } { { \__nmc_fpify_unary:n { \c__nmc_uny_int } } { \__nmc_delim_unary:n { \c__nmc_uny_int } } } % power \prop_put:Nnn \g__nmc_class_prop { ^ } { \__nmc_fpify_power: \__nmc_delim_power: } % (d)frac \__nmc_fill_class:nn { \frac, \dfrac } { \__nmc_fpify_frac: \__nmc_delim_frac: } % tfrac \prop_put:Nnn \g__nmc_class_prop { \tfrac } { \__nmc_fpify_frac: \__nmc_delim_tfrac: } % binom \__nmc_fill_class:nn { \tbinom, \binom, \dbinom } { \__nmc_fpify_binom: \__nmc_delim_frac: } % unary with braced arg \__nmc_fill_class:nn { \sqrt, \abs, \floor, \ceil } { \__nmc_fpify_unarybrace: \__nmc_delim_unarybrace: } % unary subscripted \prop_put:Nnn \g__nmc_class_prop { \log } { \__nmc_fpify_unarysub: \__nmc_delim_log: } % surd, not \__nmc_fill_class:nn { \surd, \neg, \lnot } { \__nmc_fpify_surd: \__nmc_delim_surd: } % factorial \prop_put:Nnn \g__nmc_class_prop { ! } { \__nmc_fpify_fact: \__nmc_delim_fact: } % cleave \__nmc_fill_class:nn { \q, \Q } { \prg_do_nothing: \__nmc_delim_qleave: } % n-ary \__nmc_fill_class:nn { \min, \max, \gcd } { \__nmc_fpify_nary: \__nmc_delim_nary: } % comma (n-ary fns) \prop_put:Nnn \g__nmc_class_prop { , } { \__nmc_fpify_comma: \__nmc_delim_comma: } % absorb \__nmc_fill_class:nn { {{}}, \\, &, \to, \q_nil, \dots, \ldots, \cdots, \ , \,, \;, \:, \!, \>, \thinspace, \quad, \qquad , \hfill, \hfil, \mathstrut, \displaystyle, \textstyle, \scriptstyle, \scriptscriptstyle } { \prg_do_nothing: \__nmc_delim_absorb: } % absorbm \__nmc_fill_class:nn { \vphantom, \hphantom, \phantom, \label } { \__nmc_fpify_absorbm: \__nmc_delim_absorbm: } % absorbom \__nmc_fill_class:nn { \xmathstrut } { \__nmc_fpify_absorbom: \__nmc_delim_absorbom: } % sum, prod \__nmc_fill_class:nn { \sum, \prod } { \__nmc_fpify_sum: \__nmc_delim_sum: } % begin end \__nmc_fill_class:nn { \begin, \end } { \__nmc_fpify_BE: \__nmc_delim_BE: } % font \__nmc_fill_class:nn { \mathrm, \mathit, \mathcal, \mathtt, \mathbf, \mathbb, \mathsf, \mathfrak, \mathscr, \mathnormal, \boldsymbol } { \__nmc_fpify_font: \__nmc_delim_font: } % meta \__nmc_fill_class:nn { \ensuremath, \text, \mbox } { \__nmc_fpify_meta: \__nmc_delim_stop: } % meta2 \__nmc_fill_class:nn { \splitfrac, \splitdfrac } { \__nmc_fpify_metamm: \__nmc_delim_metamm: } % nmcFn \__nmc_fill_class:nn { \eval, \iter, \solve, \recur, \tabulate, \nmcEvaluate, \nmcIterate, \nmcSolve, \nmcRecur, \nmcTabulate } { \__nmc_fpify_cmd: \__nmc_delim_cmd: } \__nmc_fill_class:nn { \nmcInfo } { \__nmc_fpify_info: \__nmc_delim_info: } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % math token replacements for l3fp evaluation % #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 } } \seq_mapthread_function:NNN #2 #3 \__nmc_substitutions:nn } \prop_new:N \g__nmc_subst_fpfn_prop \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, \exp, \ln, \lg, \lb, \sgn, \max, \min, \surd, \sqrt, \abs, \floor, \ceil, \lvert, \lfloor, \lceil, \times, \cdot, \div, \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, 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 % property list for some miscellaneous substitutions \prop_new:N \g__nmc_subst_misc_prop \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, iter, solve } \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, iteration, step } \__nmc_subst:NNN \g__nmc_subst_misc_prop \l_tmpa_seq \l_tmpb_seq % for variables & \reuse \cs \prop_new:N \g__nmc_subst_var_prop %--------------------------------------------------------------------------- % base function variants \cs_generate_variant:Nn \tl_if_head_eq_meaning:nNTF { V } \cs_generate_variant:Nn \tl_if_head_eq_meaning:nNF { V } \cs_generate_variant:Nn \tl_if_head_eq_meaning_p:nN { V } \cs_generate_variant:Nn \tl_if_head_eq_charcode:nNTF { V } \cs_generate_variant:Nn \tl_if_head_eq_charcode:nNT { V } \cs_generate_variant:Nn \tl_if_head_eq_charcode:nNF { 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_eq:nnTF { V } \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 { Nnx } \cs_generate_variant:Nn \tl_count_tokens:n { V } \cs_generate_variant:Nn \int_compare:nNnTF { v } \cs_generate_variant:Nn \int_compare:nNnT { v } \cs_generate_variant:Nn \int_case:nnTF { v } \cs_generate_variant:Nn \clist_pop:NN { cc } \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 \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 } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % general purpose routines \tl_new:N \l__nmc_A_tl \tl_new:N \l__nmc_B_tl \tl_new:N \l__nmc_C_tl \tl_new:N \l__nmc_L_tl \tl_new:N \l__nmc_R_tl % prune head from A, place in B; record new head of A in C \cs_new_protected:Npn \__nmc_next: { \exp_last_unbraced:NV\__nmc_next:w \l__nmc_A_tl\q_stop } \cs_new_protected:Npn \__nmc_next:w #1#2#3\q_stop { \__nmc_assign_vals:nnnN {#1} {#2} {#3} \l__nmc_B_tl } % get |arg| \cs_new_protected:Npn \__nmc_absval_arg:N #1 { \exp_last_unbraced:NV \__nmc_absval_arg:wN \l__nmc_A_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__nmc_A_tl { #2#3 } } { \tl_set:Nn \l__nmc_A_tl { {#2}#3 } } \tl_set:Nn #4 { #1 } \tl_set:Nn \l__nmc_C_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_new_protected:Npn \__nmc_accum_fpify_parenth:NN #1#2 { % fpify #2, wrap in ( ), append to #1 \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{} } \cs_new_protected:Npn \__nmc_fpify_next_braced:N #1 { % fp-ify next braced argument, parenthesize, append to #1 \__nmc_next: \__nmc_accum_fpify_parenth:NN #1 \l__nmc_B_tl } % 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 left delim; #2 <-- arg (delims *not* included) % #3 right delim (*must* differ from #1) \cs_new_protected:Npn \__nmc_get_arg_LR:NNN #1#2#3 { \int_set:Nn \l_tmpa_int { 1 } \tl_map_inline:Nn \l__nmc_A_tl { \str_case:nn { ##1 } { { #1 } { \int_incr:N \l_tmpa_int } { #3 } { \__nmc_get_arg_LR_rdelim: } { \q_nil } { \__nmc_get_arg_LR_qnil:N #1 } } \__nmc_next: \tl_if_single:nTF { ##1 } { \tl_put_right:Nn #2 { ##1 } } { \tl_put_right:Nn #2 { {##1} } } } } \cs_new_protected:Npn \__nmc_get_arg_LR_rdelim: { \int_decr:N \l_tmpa_int \int_if_zero:nT { \l_tmpa_int } { \__nmc_next: \tl_map_break: } } \cs_new_protected:Npn \__nmc_get_arg_LR_qnil:N #1 { \__nmc_error_what:n { Unmatched~\__nmc_verb:n { #1 }{}~in } \tl_map_break: } % #1 <== multi-char num poss. in sci notation % #2 delim only bool \cs_new_protected:Npn \__nmc_get_dec:NN #1#2 { \tl_set:NV #1 \l__nmc_B_tl \__nmc_get_dec_digits:NN #1 \c__nmc_decimals_tl \bool_lazy_and:nnT { \l__nmc_sci_num_in_bool } { \tl_if_eq_p:NN \l__nmc_C_tl \l__nmc_sci_num_in_tl } { \__nmc_get_dec_aux:NN #1#2 } } \cs_new_protected:Npn \__nmc_get_dec_aux:NN #1#2 { % l3fp uses "e" \__nmc_next: \tl_if_eq:VnTF \l__nmc_C_tl { - } { \__nmc_next: \__nmc_get_dec_aux:NNn #1#2 { e- } } { \__nmc_get_dec_aux:NNn #1#2 { e } } } \cs_new_protected:Npn \__nmc_get_dec_aux:NNn #1#2#3 { \tl_if_in:NVTF \c__nmc_digits_tl \l__nmc_C_tl { \bool_if:NTF #2 { \tl_put_right:NV #1 \l__nmc_sci_num_in_tl } { \tl_put_right:Nn #1 { #3 } } \__nmc_get_dec_digits:NN #1 \c__nmc_sdigits_tl } { \tl_set_eq:NN \l__nmc_C_tl \l__nmc_sci_num_in_tl \str_if_in:nnT { #3 } { - } { \tl_put_left:Nn \l__nmc_A_tl { - } } \tl_put_left:NV \l__nmc_A_tl \l__nmc_sci_num_in_tl } } \cs_new_protected:Npn \__nmc_get_dec_digits:NN #1#2 { \tl_map_inline:Nn \l__nmc_A_tl { \tl_if_in:NnTF #2 { ##1 } { \tl_put_right:Nn #1 { ##1 } \__nmc_next: } { \tl_map_break: } } } % for factorial, binom, n-th root, sum/prod \cs_new_protected:Npn \__nmc_intify:Nn #1#2 { % #1 value; #2 lower bound (e.g. 0,1,-1) \int_set:Nn \l_tmpa_int { \l__nmc_intify_round_tl } \fp_compare:nTF { { #2 } <= round(#1+0,\l_tmpa_int) = round(#1+0) } { \tl_set:Nx #1 { \fp_eval:n { round(#1+0) } } } { \fp_compare:nNnTF { #2 } = { -inf } { \__nmc_error_what:n { Integer~required~in } } { \__nmc_error_what:n { Integer~$\ge#2$~required~in } } } } %------------------------------------------------ % explicit/implicit calc. of fn vals (sum/prod, tables, etc.) % #1 var; #2 fn; #3 var val (fp); #4 <= fn val at #3 \cs_new_protected:Npn \__nmc_calc_fn_val:nNnN #1#2#3#4 { \prop_put:Nnx \g__nmc_subst_var_prop { #1 } { \fp_eval:n { #3 } } \__nmc_fpify_set:NN #4 #2 } \cs_new_protected:Npn \__nmc_calc_mode:n #1 { \int_set:Nn \l__nmc_mode_int { #1 } \int_case:nn { #1 } { { 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_fn_val:nNnN { V } \cs_new_protected:Npn \__nmc_calc_fn_vali:nNnN #1#2#3#4 { % mode 1 (all vals in vv-list may change) \prop_put:Nnx \l__nmc_vv_change_prop { #1 } { \fp_eval:n { #3 } } \__nmc_vv_get_vars_vals:NN \l__nmc_calc_fn_seq \l__nmc_vv_change_prop \__nmc_fpify_set:NN #4 #2 } \cs_new_protected:Npn \__nmc_calc_fn_valii:nNnN #1#2#3#4 { % mode 2 (some vals in vv-list held const.) \prop_put:Nnx \l__nmc_vv_change_prop { #1 } { \fp_eval:n { #3 } } \clist_map_inline:Nn \g__nmc_unchanged_clist { \prop_get:NnN \g__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:NN #4 #2 } \cs_new_protected:Npn \__nmc_fpify_set:NN #1#2 { % fp-set #1 to fpified #2 \group_begin: \tl_clear:N \l_tmpa_tl \__nmc_fpify:VN #2 \l_tmpa_tl \exp_args:NNNV \group_end: \tl_set:Nn \l__nmc_fp_exprn_tl { \l_tmpa_tl } \fp_set:Nn #1 { \l__nmc_fp_exprn_tl } \__nmc_error_fpflag: } \cs_generate_variant:Nn \__nmc_fpify_set:NN { cc } \cs_new_protected:Npn \__nmc_verb:n #1 { \texttt{ \tl_trim_spaces:n { \tl_to_str:n { #1 } } } } \cs_generate_variant:Nn \__nmc_verb:n { V } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Error handling \seq_new:N \g__nmc_error_where_seq \bool_new:N \g__nmc_error_bool %-------------------------------------- \cs_new_protected:Npn \__nmc_error_where:n #1 { \seq_gpush:Nn \g__nmc_error_where_seq { #1 } } \cs_new_protected:Npn \__nmc_error_what:n #1 { \bool_gset_true:N \g__nmc_error_bool \tl_gclear:N \g__nmc_reuse_tl \__nmc_error_msg:n { #1 } } \cs_new_protected:Npn \__nmc_error_msg:n #1 { \seq_if_empty:NF \g__nmc_error_where_seq { \seq_gpop:NN \g__nmc_error_where_seq \l_tmpa_tl \hbox:n { !!!~ #1 :~\l_tmpa_tl.~!!! } } } % l3fp exceptions; invalid op triggers a LaTeX *error*, hence: \fp_trap:nn { invalid_operation } { flag } \cs_new_protected:Npn \__nmc_error_fpflag: { % ln(1),cos(90),sin(360) => underflow. Ignored! \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:n { \__nmc_verb:n{l3fp}~error~ \int_case:nnT { #1 } { { 1 } { `Overflow' } { 2 } { `Division~by~zero' } { 3 } { `Invalid~operation' } } { ~in } } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % multi-tok vars (primed, subscripted, ...) to single tok % assumes math delims absent \int_new:N \g__nmc_prep_multitok_int \tl_new:N \l_nmc_multitoka_tl \tl_new:N \l_nmc_multitokb_tl \cs_new_protected:Npn \__nmc_prep_multitok:NN #1#2 { % #1 vv-list (seq); #2 formula (tl) \seq_clear:N \l_tmpa_seq \seq_map_inline:Nn #1 { \seq_set_split:Nnn \l_tmpb_seq { = } { ##1 } \seq_pop:NN \l_tmpb_seq \l_tmpb_tl \int_compare:nNnT { \tl_count_tokens:V \l_tmpb_tl } > { 1 } { \seq_push:NV \l_tmpa_seq \l_tmpb_tl } } \seq_sort:Nn \l_tmpa_seq { % big --> small \int_compare:nNnTF { \tl_count:n {##2} } > { \tl_count:n { ##1 } } { \sort_return_swapped: } { \sort_return_same: } } \seq_map_inline:Nn \l_tmpa_seq { % multitoks => \_nmca, \_nmcb, etc \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_set: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 } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \nmcInfo (no. of terms/loops/steps in "infinite" processes) \tl_new:N \g__nmc_sum_info_tl \tl_new:N \g__nmc_prod_info_tl \NewDocumentCommand \nmcInfo { s m } { \prop_if_in:NnTF \g__nmc_subst_misc_prop { #2 } { \tl_if_empty:cT { g__nmc_#2_info_tl } { \tl_set:cn { g__nmc_#2_info_tl } { 0 } } \tl_use:c { g__nmc_#2_info_tl } \IfBooleanF { #1 } { \prop_get:NnN \g__nmc_subst_misc_prop { #2 } \l_tmpb_tl \ \l_tmpb_tl % pluralise? \int_if_zero:nF { \tl_use:c { g__nmc_#2_info_tl } - 1 } { s } } } { \__nmc_error_where:n { info~command } \__nmc_error_what:n { Unknown~argument~\__nmc_verb:n { #2 }~in } } } \ProvideDocumentCommand \info {} { \nmcInfo } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \int_new:N \l__nmc_mode_int \tl_new:N \l__nmc_formula_tl \tl_new:N \l__nmc_formula_dup_tl \tl_new:N \l__nmc_fp_expr_tl \tl_new:N \l__nmc_fp_exprn_tl \tl_new:N \l_nmc_result_tl \bool_new:N \l__nmc_vv_val_only_bool \clist_new:N \l__nmc_vv_clist \seq_new:N \l__nmc_vv_visible_seq \seq_new:N \l__nmc_vv_all_seq \seq_new:N \l__nmc_calc_fn_seq \prop_new:N \l__nmc_vv_change_prop \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 \int_new:N \l__nmc_round_int \int_new:N \l__nmc_sci_num_int \int_new:N \l__nmc_prime_int \tl_new:N \l__nmc_bool_F_tl \tl_new:N \l__nmc_bool_T_tl \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 \tl_new:N \l__nmc_punc_tl \tl_new:N \l__nmc_math_delimi_tl \tl_new:N \l__nmc_math_delimii_tl \bool_new:N \l__nmc_wraps_math_bool % ##1 = number-only switch, ##2 = keyval settings, % ##3 = formula, ##4 = vv-list, ##5 = number format, % #1 = \nmcCommand, #2 = id, #3 =short-name cmd \cs_new_protected:Npn \nmc_define:nnN #1#2#3 { \NewDocumentCommand { #1 } { s O{} m O{} O{} } { \bool_gset_false:N \g__nmc_error_bool \group_begin: \bool_set_eq:NN \l__nmc_num_only_bool ##1 \__nmc_get_inputs:nnnnn { #2 } { ##2 } { ##3 } {##4 } {##5 } \bool_if:NF \g__nmc_error_bool { \use:c { __nmc_#2_process: } } \int_if_zero:nTF { \l__nmc_debug_int } { \bool_if:NF \g__nmc_error_bool { \use:c { __nmc_#2_display: } } } { \__nmc_debug_display:nn { \l__nmc_debug_int } { #2 } } \group_end: } \ProvideDocumentCommand { #3 } { } { #1 } } \nmc_define:nnN { \nmcEvaluate } { eval } \eval %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \cs_new_protected:Npn \__nmc_get_inputs:nnnnn #1#2#3#4#5 { \__nmc_settings_get:nn { #1 }{ #2 } \use:c { __nmc_#1_settings_digest: } \bool_if:NF \g__nmc_error_bool { \mode_if_math:TF { \tl_set:Nn \l__nmc_formula_tl { #3 } } { \__nmc_math_delims:n { #3 } } \tl_set_eq:NN \l__nmc_formula_dup_tl \l__nmc_formula_tl } \bool_if:NF \g__nmc_error_bool { \tl_if_in:nnTF { #4 } { = } { % vv-list \__nmc_vv_extract_visible:nN { #4 } \l__nmc_vv_clist \use:c { __nmc_#1_vv_digest:N } \l__nmc_vv_clist \bool_if:NF \g__nmc_error_bool { % number format \tl_if_empty:nF { #5 } { \__nmc_get_num_format:nn { #5 } { #1 } } } } { % if empty vv-list \tl_clear:N \l__nmc_vv_inline_tl \tl_clear:N \l__nmc_vv_display_tl \__nmc_get_num_format:nn { #4#5 } { #1 } } } } \cs_new_protected:Npn \__nmc_settings_get:nn #1#2 { % #1 = iter,solve,recur,table; #2 = settings \__nmc_error_where:n { settings } \tl_if_empty:nF { #2 } { \keys_set_known:nn { numerica/generic } { #2 } \keys_set_known:xn { numerica/#1 }{ #2 } } } \cs_new_protected:Npn \__nmc_debug_display:nn #1#2 { \__nmc_debug_display:xnn { \mode_if_math:TF { ed }{ * } } { #1 } { #2 } } \cs_new_protected:Npn \__nmc_debug_display:nnn #1#2#3 { % #2 dbg int #3 fn id \__nmc_if_mod_zero:nnT { #2 } { 5 } { \__nmc_debug_stored:N \l_tmpb_tl } \raggedright \begin{ align#1 } \__nmc_debug_display:xnnn { \seq_use:Nn \l__nmc_vv_all_seq { ,~ } } { #2 } { 2 } { vv-list } \__nmc_debug_display:Vnnn \l__nmc_formula_tl { #2 } { 3 } { formula } \__nmc_debug_display:Vnnn \l_tmpb_tl { #2 } { 5 } { stored } \__nmc_debug_display:Vnnn \l__nmc_fp_expr_tl { #2 } { 7 } { fp-form } \bool_if:nT { !\g__nmc_error_bool && \__nmc_if_mod_zero_p:nn { #2 } { 7 } && !\str_if_eq_p:nn { #3 } { table } } { \text{result:} & \quad \l_nmc_result_tl } \__nmc_debug_display:Vnnn \l__nmc_reuse_retrieved_tl { #2 } { 99991 } { Saved } \end{ align#1 } } \cs_generate_variant:Nn \__nmc_debug_display:nnn { x } \cs_new_protected:Npn \__nmc_debug_stored:N #1 { \tl_clear:N \l_tmpa_tl \tl_if_empty:NF \l__nmc_reuse_retrieved_tl { \clist_map_inline:Nn \l__nmc_reuse_retrieved_tl { \tl_put_left:Nx \l_tmpa_tl { \exp_not:o { \use_i:nn ##1 }; } } \tl_replace_all:Nnn \l_tmpa_tl { ~; } { ; } } \tl_clear:N #1 \prop_map_inline:Nn \g__nmc_subst_var_prop { \str_if_in:NnF \l_tmpa_tl { ##1; } { \tl_put_right:Nn #1 { ##1=##2,~ } } } \tl_set:Nx #1 { \tl_range:Nnn #1 { 1 } { -2 } } } \cs_new:Npn \__nmc_debug_display:nnnn #1#2#3#4 { \__nmc_if_mod_zero:nnT { #2 } { #3 } { \hbox:n { #4:} & \quad \int_compare:nNnTF { #2 } > { 0 } { \vbox_top:n } { \hbox:n } { \tl_to_str:n { #1 } } \\ } } \cs_generate_variant:Nn \__nmc_debug_display:nnnn { V, x } %%%%%%%%% formula, delimiters %%%%%%%%%%% % delimiters % #1(tl) = formula \cs_new_protected:Npn \__nmc_math_delims:n #1 { \tl_set:Nn \l__nmc_formula_tl { #1 } \tl_trim_spaces:N \l__nmc_formula_tl \bool_set_true:N \l__nmc_wraps_math_bool % $ ? \tl_if_head_eq_meaning:VNTF \l__nmc_formula_tl $ { \__nmc_math_delims_aux:n { 1 } } { % \[ ? \tl_if_head_eq_meaning:VNTF \l__nmc_formula_tl \[ { \__nmc_math_delims_aux:n { 1 } } { %\begin{environ} ? \tl_if_head_eq_meaning:VNTF \l__nmc_formula_tl \begin { \__nmc_math_delims_aux:n { 2 } } { \__nmc_math_delims_aux:nn { \[ } { \] } \bool_set_false:N \l__nmc_wraps_math_bool } } } \tl_trim_spaces:N \l__nmc_formula_tl \bool_if:NTF \l__nmc_num_only_bool { \__nmc_math_delims_aux:nn {}{} } { \bool_if:NT \l__nmc_vv_multline_bool { \__nmc_math_delims_mliner:V \l__nmc_eq_num_tl } } } \cs_new:Npn \__nmc_math_delims_mliner:n #1 { \bool_if:nT { \l__nmc_wraps_math_bool || !\mode_if_math_p: } { \tl_set:Nn \l__nmc_math_delimi_tl { \begin{multline#1} } \tl_set:Nn \l__nmc_math_delimii_tl { \end{multline#1} } } } \cs_generate_variant:Nn \__nmc_math_delims_mliner:n { V } \cs_new_protected:Npn \__nmc_math_delims_aux:n #1 { \__nmc_math_delims_aux:xx { \tl_range:Nnn \l__nmc_formula_tl { 1 } { #1 } } { \tl_range:Nnn \l__nmc_formula_tl { -#1 } { -1 } } \int_set:Nn \l_tmpa_int { #1 + 1 } \tl_set:Nx \l__nmc_formula_tl { \tl_range:Nnn \l__nmc_formula_tl { \l_tmpa_int } { -\l_tmpa_int } } } \cs_new_protected:Npn \__nmc_math_delims_aux:nn #1#2 { \tl_set:Nn \l__nmc_math_delimi_tl { #1 } \tl_set:Nn \l__nmc_math_delimii_tl { #2 } } \cs_generate_variant:Nn \__nmc_math_delims_aux:nn { xx } %%%%%%%%%% vv-list routines %%%%%%%%%%% \cs_new_protected:Npn \__nmc_vv_extract_visible:nN #1#2 { % #2 reverses #1 \clist_clear:N #2 \seq_clear:N \l__nmc_vv_visible_seq \clist_set:Nn \l_tmpa_clist { #1 } \mode_if_math:F { \tl_remove_all:Nn \l_tmpa_clist { $ } \tl_if_head_eq_charcode:VNT \l_tmpa_clist \[ { \tl_remove_once:Nn \l_tmpa_clist { \[ } \tl_remove_once:Nn \l_tmpa_clist { \] } } \tl_trim_spaces:N \l_tmpa_clist } \clist_map_inline:Nn \l_tmpa_clist { \tl_if_head_is_group:nTF { ##1 } { % to remove { } \clist_put_left:Nx #2 { \tl_head:n { ##1 } \tl_tail:n { ##1 } } } { \seq_put_right:Nn \l__nmc_vv_visible_seq { ##1 } \tl_if_head_eq_meaning:nNF { ##1 } \\ { \clist_put_left:Nn #2 { ##1 } } } } \tl_replace_once:Nnx \l__nmc_vv_inline_tl { vv } { \seq_use:Nn \l__nmc_vv_visible_seq { , } } \tl_replace_once:Nnx \l__nmc_vv_display_tl { vv } { \seq_use:Nn \l__nmc_vv_visible_seq { , } } } \cs_new_protected:Npn \__nmc_vv_digest:N #1 { \seq_set_from_clist:NN \l__nmc_vv_all_seq #1 \__nmc_error_where:n { variable\,=\,value~list } \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 } \cs_new_protected:Npn \__nmc_vv_get_vars_vals:NN #1#2 { % #1(seq) vv-list;#2(prop) changed vars (implicit-mode) \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 } } \cs_new_protected:Npn \__nmc_vv_record:NnN #1#2#3 { \bool_if:NF \l__nmc_vv_val_only_bool { % record the var \prop_put_if_new:Non \g__nmc_class_prop #1 { \__nmc_fpify_var: \__nmc_delim_var: } } \prop_get:NVNF #3 #1 \l__nmc_vv_fp_expr_tl { % fp-ify & calc. (changed `var=val's in prop #3) \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 } \cs_new_protected:Npn \__nmc_vv_write:nN #1#2 { % #1 = var; #2 = val as fp expr. \tl_if_empty:NF #2 { \tl_if_eq:VnTF #2 { inf } { \prop_put:Nnn \g__nmc_subst_var_prop { #1 } { inf } } { \prop_put:Nnx \g__nmc_subst_var_prop { #1 } { \fp_eval:n { #2 } } \__nmc_error_fpflag: } } } \cs_generate_variant:Nn \__nmc_vv_write:nN { V } % split var=val \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~$\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 } } %%%%%%%%%% number-formatting routines %%%%%%%%%% \cs_new_protected:Npn \__nmc_get_num_format:nn #1#2 { \__nmc_error_where:n { result~format~spec. } \tl_clear:N \l_tmpa_tl \str_map_inline:nn { #1 } { \str_if_in:NnTF \c__nmc_sdigits_tl { ##1 } { \tl_put_right:Nn \l_tmpa_tl { ##1 } } { \str_if_eq:nnTF { ##1 } { * } { \bool_set_true:N \l__nmc_pad_zeros_bool } { \bool_set_true:N \l__nmc_sci_num_out_bool \str_case:nnF { ##1 } { { x } { \bool_set_true:N \l__nmc_sci_num_x_bool \tl_set:Nn \l__nmc_sci_num_out_tl { ##1 } } { t } { \bool_set_true:N \l__nmc_sci_num_table_bool } { ' } { \int_incr:N \l__nmc_prime_int } } { \tl_set:Nn \l__nmc_sci_num_out_tl { ##1 } } } } } \str_if_in:nnT { #1 } { ? } { \bool_set_eq:NN \l__nmc_TF_out_bool \l__nmc_allow_TF_out_bool \bool_set_false:N \l__nmc_sci_num_out_bool } \tl_if_empty:NF \l_tmpa_tl { \int_set:Nn \l__nmc_round_int \l_tmpa_tl } \bool_if:NT \l__nmc_TF_out_bool { \bool_if:NTF \l__nmc_num_only_bool { \__nmc_num_TF_format:n { 1 } } { \__nmc_num_TF_format:n { 1 + \l__nmc_prime_int } } } \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_TF_format:n #1 { \tl_set:Nx \l__nmc_bool_F_tl { \seq_item:Nn \c__nmc_F_out_seq { #1 } } \tl_set:Nx \l__nmc_bool_T_tl { \seq_item:Nn \c__nmc_T_out_seq { #1 } } } \cs_new_protected:Npn \__nmc_num_format:nNnN #1#2#3#4 { % #1=fpf'ied in; #2=tl fmt'ed out; #3=int rnd; #4 sci bool \bool_if:NTF \l__nmc_TF_out_bool { \tl_set:Nx #2 { \fp_compare:nNnTF { 0 } = { #1 } { \exp_not:o \l__nmc_bool_F_tl } { \exp_not:o \l__nmc_bool_T_tl } } } { \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 } } } } \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 { \l__nmc_pad_zeros_bool } { \int_compare_p:nNn { #3 } > { 0 } } { \tl_if_in:NnTF #2 { . } { \__nmc_num_pad:Nnn #2 {} { #3 } } { \__nmc_num_pad:Nnn { #2 } {.} { #3 } } } } } \cs_new_protected:Npn \__nmc_num_pad:Nnn #1#2#3 { % pad with 0s: #1 number; #2 point #3 rounding \tl_set:Nx #1 { \exp_last_unbraced:NV \__nmc_num_pad:wnN #1#2\q_stop{ #3 } } } \cs_new:Npn \__nmc_num_pad:wnN #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_num_int { #2 } \tl_if_eq:VnT #3 { 10 } { \int_incr:N \l__nmc_sci_num_int \tl_set:Nn #3 { 1 } } \bool_if:NT \l__nmc_pad_zeros_bool { \tl_if_in:NnTF #3 {.} { \__nmc_num_pad:Nnn #3 {} { #4 } } { \__nmc_num_pad:Nnn #3 {.} { #4 } } } \bool_lazy_or:nnT { !\int_if_zero_p:n { \l__nmc_sci_num_int } } { \int_compare_p:nNn { \l__nmc_prime_int } > { 0 } } { \__nmc_sci_write:Nx #3 { \int_use:N \l__nmc_sci_num_int } } } \int_set:Nn \l__nmc_num_sgn_int { \fp_sign:n { #1 } } } \cs_new_protected:Npn \__nmc_sci_write:Nn #1#2 { % #1 significand #2 exponent \bool_if:NTF \l__nmc_sci_num_x_bool { \tl_put_right:Nn #1 { \times 10^{#2} } } { \bool_if:NTF \l__nmc_sci_num_table_bool { \tl_set:Nx #1 { \__nmc_sci_num_table:nn { #1 } { #2 } } } { \tl_put_right:Nx #1 { \hbox:n { \l__nmc_sci_num_out_tl {#2} } } } } } \cs_generate_variant:Nn \__nmc_sci_write:Nn { Nx } \cs_new:Npn \__nmc_sci_num_table:nn #1#2 { (#2)\exp_not:n {\,}{#1} } %%%%%%%%%%%%%% eval-specific routines %%%%%%%%%%%%%%% \cs_new:Npn \__nmc_eval_settings_digest: { \bool_set_true:N \l__nmc_allow_TF_out_bool } \cs_set_eq:NN \__nmc_eval_vv_digest:N \__nmc_vv_digest:N \cs_new_protected:Npn \__nmc_eval_process: { \__nmc_error_where:n { formula } \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 { \__nmc_num_format:nNnN { \l__nmc_fp_expr_tl } \l_nmc_result_tl { \l__nmc_round_int } \l__nmc_sci_num_out_bool } } \cs_new_protected:Npn \__nmc_eval_display: { \tl_gset_eq:NN \g__nmc_reuse_tl \l_nmc_result_tl \bool_if:NF \l__nmc_num_only_bool { \tl_set:Nx \l_nmc_result_tl { \exp_not:o \l__nmc_math_delimi_tl \bool_if:NT \l__nmc_wraps_math_bool { \exp_not:o \l__nmc_formula_dup_tl \bool_if:NTF \l__nmc_TF_out_bool { \rightarrow } { = } } \exp_not:o \l_nmc_result_tl \bool_if:NTF \l__nmc_vv_multline_bool { \exp_not:o \l__nmc_vv_display_tl } { \mathchoice{ \exp_not:o \l__nmc_vv_display_tl } { \exp_not:o \l__nmc_vv_inline_tl }{}{} } \l__nmc_punc_tl \exp_not:o \l__nmc_math_delimii_tl } \int_if_zero:nT { \l__nmc_eval_reuse_int } { \tl_gset_eq:NN \g__nmc_reuse_tl \l_nmc_result_tl } } \l_nmc_result_tl } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \__nmc_fpify:nN \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 % 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 \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 \tl_clear:N \l__nmc_accum_tl \tl_clear:N \l__nmc_C_tl \tl_set:Nn \l__nmc_A_tl { #1\q_nil } \tl_if_empty:nT { #1 } { \__nmc_error_what:n { Empty~argument~to~fp-ify~in } } \bool_until_do:nn { \quark_if_nil_p:N \l__nmc_C_tl || \g__nmc_error_bool } { \tl_clear:N \l__nmc_arg_tl \__nmc_next: \prop_get:NVNTF \g__nmc_class_prop \l__nmc_B_tl \l_tmpb_tl { \exp_last_unbraced:NV \use_i:nn \l_tmpb_tl } { \__nmc_fpify_unknown: } } \exp_args:NNNV \group_end: \tl_put_right:Nn #2 \l__nmc_accum_tl } \cs_generate_variant:Nn \__nmc_fpify:nN { V } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \cs_new_protected:Npn \__nmc_fpify_unknown: { \tl_if_in:nVTF { )]\}\rbrace } \l__nmc_B_tl { \__nmc_error_what:n { Unmatched~\__nmc_verb:V \l__nmc_B_tl{}~in } } { \__nmc_error_what:n { Unknown~token~\__nmc_verb:V \l__nmc_B_tl{}~in } } } \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__nmc_C_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 \g__nmc_subst_var_prop \l__nmc_B_tl \l__nmc_subst_tl { \tl_set_eq:NN \l__nmc_fact_arg_tl \l__nmc_subst_tl \tl_if_in:noTF { !' } \l__nmc_C_tl { % \tl_if_eq:VnT \l__nmc_C_tl { ' } % { \__nmc_deriv_dot_from_prime: } } { \__nmc_accum_fn_parenth:NNn \l__nmc_accum_tl \l__nmc_subst_tl {} \bool_set_true:N \l__nmc_insert_aster_bool } } { \__nmc_fpify_unknown: } } \cs_new_protected:Npn \__nmc_fpify_const: { % if const used as var \prop_get:NVNTF \g__nmc_subst_var_prop \l__nmc_B_tl \l__nmc_subst_tl { \__nmc_fpify_var: } { \prop_get:NVN \g__nmc_subst_fpfn_prop \l__nmc_B_tl \l__nmc_subst_tl \tl_if_eq:VnTF \l__nmc_C_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__nmc_B_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__nmc_B_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__nmc_B_tl \l__nmc_B_tl \tl_put_right:NV \l__nmc_accum_tl \l__nmc_B_tl \bool_set_false:N \l__nmc_insert_aster_bool } \cs_new_protected:Npn \__nmc_fpify_comparison: { \tl_if_in:NVTF \c__nmc_comparisons_tl \l__nmc_C_tl { \__nmc_error_what:n { Multi-token~comparison~in } } { \prop_get:NVNF \g__nmc_subst_fpfn_prop \l__nmc_B_tl \l_tmpa_tl { \tl_set_eq:NN \l_tmpa_tl \l__nmc_B_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:NNn \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__nmc_B_tl \l_tmpa_tl \tl_put_right:NV \l__nmc_accum_tl \l_tmpa_tl % \tl_show:N \l__nmc_A_tl \__nmc_delim_arg:Nnn \l__nmc_arg_tl { 1 } { \c__nmc_and_int } % \tl_show:N \l__nmc_arg_tl \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__nmc_B_tl \l__nmc_arg_tl \tl_set_eq:NN \l__nmc_fact_arg_tl \l__nmc_arg_tl \tl_if_eq:VnTF \l__nmc_C_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__nmc_B_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__nmc_B_tl \__nmc_get_arg_L:VN \l__nmc_B_tl \l__nmc_arg_tl } \__nmc_fpify_lvert_aux: } \cs_new_protected:Npn \__nmc_fpify_lvert_aux: { \tl_if_eq:VnTF \l__nmc_C_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__nmc_B_tl \prop_get:NVN \g__nmc_subst_misc_prop \l__nmc_L_tl \l__nmc_R_tl \str_case:on \l__nmc_C_tl { { | } { \__nmc_fpify_lmod_abs:V \l__nmc_L_tl } { . } { \__nmc_fpify_lmod_aux:V \l__nmc_L_tl } { / } { \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__nmc_C_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__nmc_C_tl { . } { \__nmc_next: } } \cs_new_protected:Npn \__nmc_fpify_unary:n #1 { \tl_set:NV \l__nmc_fn_tl \l__nmc_B_tl \tl_if_eq:VnTF \l__nmc_C_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 } % get fn arg \__nmc_delim_arg:Nnn \l__nmc_arg_tl { 1 } { #1 } \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:NNn \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_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__nmc_B_tl \l__nmc_subst_tl \tl_if_eq:VnT \l__nmc_C_tl { * } { \__nmc_next: } \tl_if_eq:VnTF \l__nmc_C_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__nmc_C_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 { [~]~argument~of~\__nmc_verb:n { \sqrt } } \tl_clear:N \l__nmc_arg_tl \tl_clear:N \l__nmc_ubrace_n_tl \__nmc_get_arg_LR:NNN [ \l__nmc_arg_tl ] \__nmc_fpify:VN \l__nmc_arg_tl \l__nmc_ubrace_n_tl \__nmc_intify:Nn \l__nmc_ubrace_n_tl { 1 } \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__nmc_B_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 }} } } } \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__nmc_B_tl } } } } } \cs_new_protected:Npn \__nmc_fpify_unarysub: { % e.g. \log_{10} \str_if_eq:VnTF \l__nmc_C_tl { _ } { \__nmc_next: \__nmc_next: \__nmc_fpify_unarysub:N \l__nmc_B_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:NNn \l__nmc_accum_tl \l_tmpa_tl {} \tl_put_left:Nn \l__nmc_A_tl { \ln } } } \cs_new_protected:Npn \__nmc_fpify_surd: { \prop_get:NVN \g__nmc_subst_fpfn_prop \l__nmc_B_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 \tl_if_eq:VnTF \l__nmc_C_tl { ! } { \__nmc_fpify_fact_repeated: } { \__nmc_intify:Nn \l_tmpa_tl { 0 } \bool_if:NF \g__nmc_error_bool { \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl \__nmc_accum_fn_parenth:NNn \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: { \__nmc_intify:Nn \l_tmpa_tl { -1 } \bool_if:NF \g__nmc_error_bool { \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl \__nmc_fpify_double_fact:N \l_tmpa_tl \tl_set:Nx \l_tmpa_tl { \fp_use:N \l__nmc_fact_fp } \tl_if_eq:VnTF \l__nmc_C_tl { ! } { \tl_set_eq:NN \l__nmc_fact_arg_tl \l_tmpa_tl } { \__nmc_accum_fn_parenth:NNn \l__nmc_accum_tl \l_tmpa_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 % #3 = 1 (!), = 2 (!!) \cs_new_protected:Npn \__nmc_fpify_fact_do:nNn #1#2#3 { \fp_set:Nn \l_tmpa_fp { #1 } \fp_set:Nn \l_tmpb_fp { #2 } \int_set:Nn \l_tmpb_int { #3 } \fp_set_eq:NN \l__nmc_fact_fp \l_tmpa_fp \fp_while_do:nNnn { \l_tmpa_fp } < { \l_tmpb_fp } { \fp_add:Nn \l_tmpa_fp { \l_tmpb_int } \fp_set:Nn \l__nmc_fact_fp { \l__nmc_fact_fp * \l_tmpa_fp } } } \cs_new_protected:Npn \__nmc_fpify_nary: { \bool_set_true:N \l__nmc_comma_nary_bool \str_case:on \l__nmc_B_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 % 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__nmc_B_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 { 2nd~argument~of~\__nmc_verb:n { \binom } } \__nmc_intify:Nn \l__nmc_binom_bot_tl { 0 } \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 \__nmc_fpify_binom_calc_do:nN { #1 - #2 + 1 } #1 \tl_put_right:Nn \l__nmc_accum_tl { / } \__nmc_fpify_binom_calc_do:nN { 1 } #2 % calc. bot. } \tl_put_right:Nn \l__nmc_accum_tl { ) } } \cs_new_protected:Npn \__nmc_fpify_binom_calc_do:nN #1 #2 { \__nmc_fpify_fact_do:nNn { #1 } #2 { 1 } \tl_put_right:Nx \l__nmc_accum_tl { \fp_use:N \l__nmc_fact_fp } } \cs_new_protected:Npn \__nmc_fpify_BE: { \__nmc_next: \tl_if_in:VnT \l__nmc_B_tl { alignat } { \__nmc_next: } } % \cs { m } \cs_new_protected:Npn \__nmc_fpify_absorbm: { \__nmc_next: } % \cs { o m } \cs_new_protected:Npn \__nmc_fpify_absorbom: { \str_if_eq:VnT \l__nmc_C_tl { [ } { \__nmc_next: \__nmc_get_arg_LR:NNN [ \l__nmc_toss_tl ] } \__nmc_next: } \cs_new_protected:Npn \__nmc_fpify_font: { \__nmc_fpify_meta: } \cs_new_protected:Npn \__nmc_fpify_meta: { \__nmc_next: \__nmc_fpify:VN \l__nmc_B_tl \l__nmc_accum_tl } \cs_new_protected:Npn \__nmc_fpify_metamm: { \prg_replicate:nn { 2 } { \__nmc_fpify_meta: } } %%%%%%%%%%%%%%%%%%% % sum/prod \cs_new_protected:Npn \__nmc_fpify_sum: { \__nmc_insert_aster: \group_begin: \tl_if_eq:VnTF \l__nmc_B_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 } \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 } \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~\ limits } \__nmc_sum_get_limits:NNN \l__nmc_sum_var_tl \l__nmc_sum_index_int \l__nmc_sum_end_int } \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__nmc_C_tl { ( } { \__nmc_parenth:N \l__nmc_arg_tl } \tl_set_eq:NN \l__nmc_summand_tl \l__nmc_arg_tl % do the sum/prod; result in \l__nmc_sum_total_fp \__nmc_error_where:n { \l__nmc_sum_type_tl } \__nmc_sum_do:nnN { \l__nmc_sum_index_int } { \l__nmc_sum_end_int } \l__nmc_sum_total_fp \fp_gset_eq:NN \g_tmpa_fp \l__nmc_sum_total_fp \tl_gset_eq:NN \g_tmpa_tl \l__nmc_A_tl \exp_args:NNNV \group_end: \tl_set:Nn \l__nmc_C_tl \l__nmc_C_tl \tl_put_right:Nx \l__nmc_accum_tl { \fp_use:N \g_tmpa_fp } \tl_set_eq:NN \l__nmc_A_tl \g_tmpa_tl \bool_set_false:N \l__nmc_insert_aster_bool } } \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__nmc_C_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__nmc_B_tl \__nmc_prep_multitok:NN \l_tmpc_seq \l__nmc_A_tl \seq_pop:NN \l_tmpc_seq \l__nmc_B_tl } \str_if_in:NnTF \l__nmc_B_tl { = } { \__nmc_vv_get_vars_vals_lims:NN \l__nmc_B_tl \c_empty_prop \tl_set_eq:NN #1 \l__nmc_eq_var_tl \__nmc_sum_limit_assign:NN #2 \l__nmc_vv_fp_expr_tl \seq_if_in:NVF \l__nmc_calc_fn_seq \l__nmc_B_tl { \seq_put_left:NV \l__nmc_calc_fn_seq \l__nmc_B_tl } } { \__nmc_error_what:n { No~\__nmc_verb:V \l__nmc_sum_type_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__nmc_B_tl \c_empty_prop \__nmc_sum_limit_assign:NN #1 \l__nmc_vv_fp_expr_tl } \cs_new_protected:Npn \__nmc_sum_limit_assign:NN #1#2 { \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 } } { \__nmc_intify:Nn #2 { -inf } \bool_if:NF \g__nmc_error_bool { \int_set:Nn #1 { #2 } } } } } \cs_new_protected:Npn \__nmc_sum_do:nnN #1#2#3 { % #1,#2 lower, upper limits (int), #3 <-- total (fp) \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:nTF { #1 <= #2 } { \fp_set:Nn #3 { \l__nmc_sum_total_fp } } { \tl_if_eq:VnTF \l__nmc_sum_op_tl { * } { \fp_set:Nn #3 { 1 } } { \fp_set:Nn #3 { 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_ \tl_range:Nnn \l__nmc_sum_type_tl{1}{4} _info_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 } } \cs_new_protected:Npn \__nmc_fpify_cmd: { \__nmc_insert_aster: \str_case:onT \l__nmc_B_tl { { \eval } { \__nmc_cmd:n { eval } } { \iter } { \__nmc_cmd:n { iter } } { \solve } { \__nmc_cmd:n { solve } } { \recur } { \__nmc_cmd:n { recur } } { \tabulate } { \__nmc_cmd:n { table } } { \nmcInfo } { \nmcInfo } { \nmcEvaluate } { \__nmc_cmd:n { eval } } { \nmcIterate } { \__nmc_cmd:n { iter } } { \nmcSolve } { \__nmc_cmd:n { solve } } { \nmcRecur } { \__nmc_cmd:n { recur } } { \nmcTabulate } { \__nmc_cmd:n { table } } } { \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 { % \cm { s O m O O } \tl_set:Nn \l__nmc_delim_arg_tl { { #1 } } % cmd \tl_if_eq:VnT \l__nmc_C_tl { * } { \__nmc_next: } \__nmc_append_sqbrarg: % settings \__nmc_next: \tl_put_right:Nx \l__nmc_delim_arg_tl { { \exp_not:o \l__nmc_B_tl } } \__nmc_append_sqbrarg: % vv-list \__nmc_append_sqbrarg: % num format \tl_put_right:Nn \l__nmc_accum_tl { ( } \group_begin: \bool_set_true:N \l__nmc_num_only_bool \exp_last_unbraced:No \__nmc_get_inputs:nnnnn \l__nmc_delim_arg_tl \bool_set_false:N \l__nmc_sci_num_out_bool \bool_if:NF \g__nmc_error_bool { \use:c { __nmc_#1_process: } } \exp_args:NNNV \group_end: \tl_put_right:Nn \l__nmc_accum_tl { \l_nmc_result_tl ) } } \cs_new_protected:Npn \__nmc_append_sqbrarg: { \tl_if_eq:VnTF \l__nmc_C_tl { [ } { \__nmc_append_sqbrarg_aux: } { \tl_put_right:Nx \l__nmc_delim_arg_tl { {} } } } \cs_new_protected:Npn \__nmc_append_sqbrarg_aux: { \__nmc_next: \tl_clear:N \l_tmpa_tl \__nmc_get_arg_LR:NNN [ \l_tmpa_tl ] \tl_put_right:Nx \l__nmc_delim_arg_tl { { \exp_not:o \l_tmpa_tl } } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \nmc_delim_arg:Nnn \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:nn #1#2 { p, TF } { \bool_if:nTF { \int_compare_p:nNn { \l__nmc_delim_pos_int } > { #1 } && \int_compare_p:nNn { \l__nmc_delim_pas_int } > { #2 } } { \prg_return_true: } { \prg_return_false: } } %-------------------------------------------------------------------- % #1(tlvar) receives arg (\l__nmc_delim_arg_tl) % #2 (int) initial pos % #3 (int) parsing state \cs_new_protected:Npn \__nmc_delim_arg:Nnn #1#2#3 { \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__nmc_C_tl } { \prop_get:NVNTF \g__nmc_class_prop \l__nmc_C_tl \l__nmc_class_tl { \exp_last_unbraced:NV \use_ii:nn \l__nmc_class_tl } { \__nmc_delim_var: } % unknown; treat as var \int_incr:N \l__nmc_delim_pos_int } \tl_gset_eq:NN \g_tmpa_tl \l__nmc_A_tl \tl_gset_eq:NN \g_tmpb_tl \l__nmc_delim_arg_tl \exp_args:NNNV \group_end: \tl_set:Nn \l__nmc_C_tl \l__nmc_C_tl \tl_set_eq:NN \l__nmc_A_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__nmc_C_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__nmc_B_tl } \cs_new_protected:Npn \__nmc_delim_append_braced: { \__nmc_next: \tl_put_right:Nx \l__nmc_delim_arg_tl { { \exp_not:o\l__nmc_B_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:nnTF { 1 } { \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 } } \cs_new_protected:Npn \__nmc_delim_var: { \__nmc_if_pospas_gtr:nnTF { 1 } { \c__nmc_uny_int } { \__nmc_delim_stop: } { \__nmc_delim_append: } } \cs_new_protected:Npn \__nmc_delim_const: { \__nmc_if_pospas_gtr:nnTF { 1 } { \c__nmc_uny_int } { \__nmc_delim_stop: } { \__nmc_delim_append: } } \cs_new_protected:Npn \__nmc_delim_arith: { \__nmc_if_pospas_gtr:nnTF { 1 } { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_delim_append: } } \cs_new_protected:Npn \__nmc_delim_pm: { \__nmc_if_pospas_gtr:nnTF { 1 } { \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__nmc_A_tl \l__nmc_delim_arg_tl \tl_put_left:Nn \l__nmc_A_tl { \land } \tl_put_left:Nn \l__nmc_C_tl { \land } } \__nmc_if_pospas_gtr:nnTF { 1 } { \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: { \bool_lazy_or:nnTF { \__nmc_if_pospas_gtr_p:nn { 1 } { \c__nmc_trg_int } } { \__nmc_if_pospas_gtr_p:nn { \l__nmc_posi_int } { \c__nmc_sum_int } } { \__nmc_delim_stop: } { \__nmc_next: \str_case:on \l__nmc_B_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:n { \l__nmc_posi_int } } } \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:n #1 { % #1 is first pos. \int_compare:nNnTF { \l__nmc_delim_pas_int } = { \c__nmc_trg_int } { % +1 to prevent ( )( ) \__nmc_delim_arg:Nnn \l__nmc_delim_argi_tl { #1 + 1 } { \c__nmc_trg_int } } { \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:nnTF { 1 } { \c__nmc_cmp_int } { \__nmc_delim_stop: } { \__nmc_next: \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmc_B_tl } } \cs_new_protected:Npn \__nmc_delim_lvert: { \__nmc_if_pospas_gtr:nnTF { 1 } { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_next: \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmc_B_tl \str_case:on \l__nmc_B_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: { \bool_lazy_and:nnT { \int_compare_p:nNn { \l__nmc_posi_int } < { 3 } } { \int_compare_p:nNn { \l__nmc_delim_pas_int } = { \l__nmc_trg_int } } { \int_incr:N \l__nmc_delim_pas_int } \__nmc_if_pospas_gtr:nnTF { \l__nmc_posi_int } { \l__nmc_trg_int } { \__nmc_delim_stop: } { \__nmc_next: \tl_if_in:NVTF \c__nmc_modds_tl \l__nmc_C_tl { \prop_get:NVN \g__nmc_subst_misc_prop \l__nmc_B_tl \l_tmpb_tl \__nmc_delim_lparen:VV \l__nmc_B_tl \l_tmpb_tl \__nmc_next: \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmc_B_tl \tl_if_eq:VnTF \l__nmc_C_tl { | } { \__nmc_delim_lparen_auxi:n { 0 } } { \__nmc_next: \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmc_B_tl \__nmc_delim_stop: } } { \int_decr:N \l__nmc_delim_pos_int \bool_set_true:N \l__nmc_delim_lmod_bool } } } \cs_new_protected:Npn \__nmc_delim_unary:n #1 { \__nmc_if_pospas_gtr:nnTF { 1 } { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \tl_if_eq:VnT \l__nmc_C_tl { ^ } { \__nmc_delim_append: \__nmc_delim_append_braced: } \__nmc_delim_arg:Nnn \l__nmc_delim_argi_tl { 1 } { #1 } \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmc_delim_argi_tl } } \cs_new_protected:Npn \__nmc_delim_power: { \__nmc_if_pospas_gtr:nnTF { 1 } { \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:nnTF { 1 } { \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:nnTF { 1 } { \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:nnTF { 1 } { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \str_case:on \l__nmc_C_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:nnTF { 1 } { \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:NNn \l__nmc_delim_arg_tl \l__nmc_delim_argi_tl {} } } \cs_new_protected:Npn \__nmc_delim_surd: { \__nmc_if_pospas_gtr:nnTF { 1 } { \c__nmc_uny_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \tl_clear:N \l__nmc_delim_argi_tl \tl_if_eq:VnT \l__nmc_B_tl { \prod } { \prg_replicate:nn { 2 } { \__nmc_delim_append: \__nmc_delim_append_braced: } } \__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:nnTF { 1 } { \c__nmc_prn_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \tl_if_eq:VnT \l__nmc_C_tl { ! } { \__nmc_delim_append: } \__nmc_delim_stop_if_gtr:n { \c__nmc_sum_int } } } \cs_new_protected:Npn \__nmc_delim_qleave: { \__nmc_next: \tl_if_eq:VnTF \l__nmc_B_tl { \q } { \int_zero:N \l__nmc_delim_pos_int } % adhere { \bool_set_true:N \l__nmc_delim_stop_bool } % sever \tl_if_eq:VnT \l__nmc_C_tl { ' } { \__nmc_next: } } \cs_new_protected:Npn \__nmc_delim_nary: { \__nmc_if_pospas_gtr:nnTF { 1 } { \c__nmc_sum_int } { \__nmc_delim_stop: } { \__nmc_delim_append: \__nmc_get_arg_LR:NNN ( \l__nmc_B_tl ) \__nmc_put_right_wrap:NnNn \l__nmc_delim_arg_tl { ( } \l__nmc_B_tl { ) } \__nmc_delim_stop_if_gtr:n { \c__nmc_sum_int } } } \cs_new_protected:Npn \__nmc_delim_comma: { \__nmc_if_pospas_gtr:nnTF { 1 } { \c__nmc_cmp_int } { \__nmc_delim_stop: } { \__nmc_delim_append: } } \cs_new_protected:Npn \__nmc_delim_sum: { \__nmc_if_pospas_gtr:nnTF { 1 } { \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: { % \cs \__nmc_next: \int_decr:N \l__nmc_delim_pos_int } \cs_new_protected:Npn \__nmc_delim_absorbm: { % \cs { m } \__nmc_next: \__nmc_next: \int_decr:N \l__nmc_delim_pos_int } \cs_new_protected:Npn \__nmc_delim_absorbom: { % \cs { o m } \__nmc_next: \str_if_eq:VnT \l__nmc_C_tl { [ } { \__nmc_next: \__nmc_get_arg_LR:NNN [ \l__nmc_toss_tl ] } \__nmc_next: \int_decr:N \l__nmc_delim_pos_int } \cs_new_protected:Npn \__nmc_delim_BE: { \__nmc_if_pospas_gtr:nnTF { 1 } { \c__nmc_cmp_int } { \__nmc_delim_stop: } { \__nmc_next: \__nmc_next: \str_if_in:VnTF \l__nmc_B_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_font: { \__nmc_next: \tl_put_left:NV \l__nmc_A_tl \l__nmc_B_tl \int_decr:N \l__nmc_delim_pos_int } \cs_new_protected:Npn \__nmc_delim_metamm: { \__nmc_next: \__nmc_delim_append_braced: \__nmc_delim_append_braced: \int_decr:N \l__nmc_delim_pos_int } \cs_new_protected:Npn \__nmc_delim_cmd: { % \cmd { s O m O O } \__nmc_if_pospas_gtr:nnTF { 1 } { \c__nmc_sum_int } { \__nmc_delim_stop: } { \tl_put_right:NV \l__nmc_delim_arg_tl \l__nmc_C_tl \__nmc_next: \tl_if_eq:VnT \l__nmc_C_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__nmc_B_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__nmc_C_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 } } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % save & retrieve \tl_new:N \g__nmc_reuse_tl \tl_new:N \g__nmc_reuse_filename_tl \tl_new:N \l__nmc_reuse_retrieved_tl \bool_new:N \l__nmc_reuse_retrieved_bool \bool_new:N \g__nmc_lyx_bool \ior_new:N \g__nmc_ior \iow_new:N \g__nmc_iow \tl_gset:NV \g__nmc_reuse_filename_tl \jobname \tl_gput_right:Nn \g__nmc_reuse_filename_tl { .nmc } % \NewDocumentCommand \nmcReuse { s >{ \TrimSpaces } O{} } { % save \eval result to csname #2 \tl_if_empty:nTF { #2 } { \__nmc_reuse_retrieve: } { \tl_if_empty:NTF \g__nmc_reuse_tl { \__nmc_error_where:n { \__nmc_verb:n { \nmcReuse }~command } \__nmc_error_what:n { No~value~to~save~with } } { \__nmc_reuse_result:c { #2 } } } \IfBooleanT #1 { \__nmc_debug_display:nn { 99991 } { reuse } } } \ProvideDocumentCommand\reuse {} { \nmcReuse } \cs_new_protected:Npn \__nmc_reuse_retrieve: { \file_get:VnNT \g__nmc_reuse_filename_tl {} \l__nmc_reuse_retrieved_tl { \bool_lazy_or:nnF { \tl_if_blank_p:V \l__nmc_reuse_retrieved_tl } { \tl_if_head_eq_meaning_p:VN \l__nmc_reuse_retrieved_tl \par } { \seq_set_split:NnV \l_tmpa_seq {,} \l__nmc_reuse_retrieved_tl \seq_map_inline:Nn \l_tmpa_seq { \__nmc_reuse_defcmds:Nnn ##1 { _props } } } } \bool_set_true:N \l__nmc_reuse_retrieved_bool } \cs_new_protected:Npn \__nmc_reuse_result:N #1 { \tl_set:Nn \l_tmpb_tl { #1 } \tl_put_right:Nx \l_tmpb_tl { { \tl_to_str:N \g__nmc_reuse_tl } } \bool_if:NF \l__nmc_reuse_retrieved_bool { \__nmc_reuse_retrieve: } \clist_put_right:NV \l__nmc_reuse_retrieved_tl \l_tmpb_tl \exp_last_unbraced:NV\__nmc_reuse_defcmds:Nnn \l_tmpb_tl {} \tl_gclear:N \g__nmc_reuse_tl } \cs_generate_variant:Nn \__nmc_reuse_result:N { c } \cs_new_protected:Npn \__nmc_reuse_defcmds:Nnn #1#2#3 { \prop_get:NnNTF \g__nmc_subst_var_prop { #1 } \l__nmc_toss_tl { \RenewDocumentCommand #1{}{#2} } { \NewDocumentCommand #1{}{#2} } \tl_set_rescan:Nnn #1 { \ExplSyntaxOn } { #2 } \use:c { __nmc_reuse_write#3:Nn } #1{#2} } \cs_new_protected:Npn \__nmc_reuse_write:Nn #1#2 { \__nmc_reuse_write_props:Nn #1{#2} \file_get:VnNTF \g__nmc_reuse_filename_tl {} \l_tmpa_tl { \tl_if_head_eq_meaning:VNTF \l_tmpa_tl \par { \tl_clear:N \l_tmpa_tl } { \__nmc_reuse_delete:NN #1 \l_tmpa_tl \tl_if_blank:VF \l_tmpa_tl { \tl_trim_spaces:N \l_tmpa_tl \tl_put_right:Nn \l_tmpa_tl {,} } } } { \tl_clear:N \l_tmpa_tl } \tl_put_right:Nn \l_tmpa_tl { #1 {#2} } \iow_open:NV \g__nmc_iow \g__nmc_reuse_filename_tl \iow_now:NV \g__nmc_iow \l_tmpa_tl \iow_close:N \g__nmc_iow } \cs_new_protected:Npn \__nmc_reuse_delete:NN #1#2 { \seq_clear:N \l_tmpb_seq \seq_set_split:NnV \l_tmpa_seq {,} #2 \seq_map_inline:Nn \l_tmpa_seq { \tl_if_head_eq_meaning:nNF { ##1 } #1 { \seq_put_right:Nn \l_tmpb_seq { ##1 } } } \tl_set:Nx #2 { \seq_use:Nn \l_tmpb_seq {,} } } \cs_new_protected:Npn \__nmc_reuse_write_props:Nn #1#2 { \prop_put_if_new:Nnn \g__nmc_class_prop { #1 } { \__nmc_fpify_var: \__nmc_delim_var: } \prop_put:Nnn \g__nmc_subst_var_prop { #1 } { #2 } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % settings \bool_new:N \l__nmc_multitok_bool \bool_new:N \l__nmc_vv_multline_bool \bool_new:N \l__nmc_deg_bool \tl_new:N \l__nmc_eq_num_tl \int_new:N \l__nmc_posi_int \int_new:N \l__nmc_eval_reuse_int \int_new:N \l__nmc_debug_int \tl_new:N \l__nmc_reuse_sep_tl % numerica-plus \int_set_eq:NN \l__nmc_posi_int \c_one_int \cs_new_protected:Npn \__nmc_set_trig_parsing:n #1 { % #1=1,2,3 \int_set:Nn\l__nmc_posi_int { #1 } \int_compare:nNnTF { #1 } > { 1 } { % #1=2,3 \int_set_eq:NN \l__nmc_trg_int \c__nmc_trg_int \int_compare:nNnT { #1 } > { 2 } { % #1=3 \__nmc_fill_class:nn { \frac, \dfrac } { \__nmc_fpify_frac: \__nmc_delim_tfrac: } } } { \int_set_eq:NN \l__nmc_trg_int \c__nmc_uny_int } % #1=1 } \cs_new:Npn \__nmc_deg: { \bool_if:NT { \l__nmc_deg_bool } { d } } \cs_new:Npn \__nmc_int_to_bool:Nn #1#2 { \bool_set:Nn #1 { !\int_if_zero_p:n { #2 } } } \keys_define:nn { numerica } { rounding .int_set:N = \l__nmc_round_int, pad .code:n = \__nmc_int_to_bool:Nn \l__nmc_pad_zeros_bool { #1 }, output-sci-notation .code:n = \__nmc_int_to_bool:Nn \l__nmc_sci_num_out_bool { #1 }, output-exponent-char .tl_set:N = \l__nmc_sci_num_out_tl, input-sci-notation .code:n = \__nmc_int_to_bool:Nn \l__nmc_sci_num_in_bool { #1 }, input-exponent-char .tl_set:N = \l__nmc_sci_num_in_tl, multitoken-variables .code:n = \__nmc_int_to_bool:Nn \l__nmc_multitok_bool { #1 }, logarithm-base .tl_set:N = \l__nmc_log_base_tl, intify-rounding .tl_set:N = \l__nmc_intify_round_tl, vv-display .tl_set:N = \l__nmc_vv_display_tl, vv-inline .tl_set:N = \l__nmc_vv_inline_tl, sum-extra-rounding .int_set:N = \l__nmc_sum_extra_int, sum-query-terms .int_set:N = \l__nmc_sum_query_int, prod-extra-rounding .int_set:N = \l__nmc_prod_extra_int, prod-query-terms .int_set:N = \l__nmc_prod_query_int, eval-reuse .int_set:N = \l__nmc_eval_reuse_int, % rounding .default:n = 6, pad .default:n = 0, output-sci-notation .default:n = 0, output-exponent-char .default:n = e, input-sci-notation .default:n = 0, input-exponent-char .default:n = e, multitoken-variables .default:n = 1, logarithm-base .default:n = 10, intify-rounding .default:n = 14, vv-display .default:n = {,}\mskip 36mu minus 24mu(vv), vv-inline .default:n = {,}\mskip 12mu plus 6mu minus 9mu(vv), sum-extra-rounding .default:n = 2, sum-query-terms .default:n = 0, prod-extra-rounding .default:n = 2, prod-query-terms .default:n = 0, eval-reuse .default:n = 0, } \keys_set_known:nn { numerica } { rounding,pad,output-sci-notation,output-exponent-char, input-sci-notation,input-exponent-char, multitoken-variables,logarithm-base,intify-rounding, vv-display,vv-inline,sum-extra-rounding,sum-query-terms, prod-extra-rounding,prod-query-terms,eval-reuse } \keys_define:nn { numerica/generic } { dbg .code:n = \int_set:Nn \l__nmc_debug_int { \int_compare:nNnTF { \int_abs:n { #1 } } = { 1 } { \int_sign:n { #1 }*2*3*5*7 } { #1 } }, ^ .code:n = \bool_set_true:N \l__nmc_sci_num_in_bool \tl_set:Nn \l__nmc_sci_num_in_tl { #1 }, xx .code:n = \__nmc_int_to_bool:Nn \l__nmc_multitok_bool { #1 }, () .code:n = \__nmc_set_trig_parsing:n { 2+\int_sign:n { #1-1 } }, () .initial:n = 0, o .code:n = \bool_set_true:N \l__nmc_deg_bool, log .tl_set:N = \l__nmc_log_base_tl, vvmode .code:n = \__nmc_calc_mode:n { \int_sign:n { #1*#1 } }, vvd .code:n = \tl_set:Nn \l__nmc_vv_display_tl { #1 } \tl_if_in:NnT \l__nmc_vv_display_tl { \\ } { \bool_set_true:N \l__nmc_vv_multline_bool }, vvi .tl_set:N = \l__nmc_vv_inline_tl, * .code:n = \tl_set:Nn \l__nmc_eq_num_tl { * }, p .tl_set:N = \l__nmc_punc_tl, p .default:n = {,}, S+ .int_set:N = \l__nmc_sum_extra_int, S? .int_set:N = \l__nmc_sum_query_int, P+ .int_set:N = \l__nmc_prod_extra_int, P? .int_set:N = \l__nmc_prod_query_int, } \keys_define:nn { numerica/eval } { reuse .int_set:N = \l__nmc_eval_reuse_int } \keys_define:nn { numerica/package } { plus .code:n = \file_input:n { numerica-plus.def }, tables .code:n = \file_input:n { numerica-tables.def }, % calculus .code:n = \file_input:n { numerica-calculus.def }, lyx .code:n = \file_input:n { numerica-lyx.def } } \ProcessKeysPackageOptions { numerica/package } \file_if_exist:nT { numerica.cfg } { \file_get:nnN { numerica.cfg } {} \l_tmpa_tl \exp_args:NnV \keys_set_known:nn { numerica } \l_tmpa_tl } % end of `numerica.sty'