% 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{l3keys2e}
\RequirePackage{amsmath,mathtools,etoolbox}
\ProvidesExplPackage
  {numerica}
  {2021/12/07}
  {2.0.0}
  {Numerically evaluate mathematical expressions in their LaTeX form}
% needs amsmath
\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} }
% needs 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\, }
\NewDocumentCommand \Q {} { \prg_do_nothing: } % Qleave apart
\NewDocumentCommand \q {} { \prg_do_nothing: } % qleave to 
%
\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 }
\int_new:N \l__nmc_trg_int
\int_new:N \l__nmc_num_sgn_int % tables
\tl_new:N \l__nmc_toss_tl
\seq_new:N \l_tmpc_seq
% 
\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: }
\prop_put:Nnn \g__nmc_class_prop { \tfrac }
  { \__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, \bigl, \Bigl, \biggl, \Biggl }
  { \__nmc_fpify_lmod: \__nmc_delim_lmod: } 
% right
\__nmc_fill_class:nn { \right, \bigr, \Bigr, \biggr, \Biggr }
  { \prg_do_nothing: \__nmc_delim_rparen: } 
% unary fns: f 
\__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 } } 
  }
% f!
\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: }
\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
    }
  { \__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,
      \displaystyle, \textstyle, \scriptstyle, \scriptscriptstyle,
    }
  { \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: }
% 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, \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 } }
    \seq_mapthread_function: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,
    \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,
    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, \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, reuse, reuse
    }
\__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: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 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__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 ) } }
% (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__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 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_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: vs fpify: 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 { 1234567890. }
    \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 { 123456789 } \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 { -1234567890 }
      }
      { 
        \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: }
      }
  }
% intify fp (for !, binom, n-th root, sum/prod)
% #2(e.g. = 0,1,-1) <= #1(tl) <-- int 
\cs_new_protected:Npn \__nmc_intify:Nn #1#2
  { 
    \fp_compare:nTF 
        { { #2 } <= round(#1+0,\l__nmc_intify_round_tl) = 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 } }
      }
  }
% 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
        \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{\string #1} }
\cs_generate_variant:Nn \__nmc_verb:n { V }
\cs_new:Npn \__nmc_verb:N #1
  { \texttt{\string #1} }
\cs_generate_variant:Nn \__nmc_verb:N { c }
% 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
        \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
    \__nmc_error_msg:n { #1 }
  }
\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
        \hbox:n { !!!~  #1 :~\l_tmpa_tl.~!!! }
      }
  }
% 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:n 
      { 
        \__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
\cs_new_protected:Npn \__nmc_prep_multitok:NN #1#2
  { 
    \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 => \nmc_a, \nmc_b, 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
      }
  }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\int_new:N \l__nmc_depth_int
\tl_new:N \l__nmc_mode_tl
\tl_new:N \l_nmc_formula_tl
\fp_new:N \l__nmc_result_fp
\tl_new:N \l_nmc_result_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
\bool_new:N \l__nmc_dbg_count_bool
\tl_new:N \l__nmc_dbg_vv_tl
\tl_new:N \l__nmc_dbg_idii_tl
\tl_new:N \l__nmc_dbg_idiii_tl
\tl_new:N \l__nmc_dbg_idv_tl
\seq_new:N \l__nmc_dbg_stored_seq
\int_new:N \l__nmc_round_int
\int_new:N \l__nmc_sci_expon_int
\int_new:N \l__nmc_num_alt_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
\bool_new:N \l__nmc_vv_val_only_bool
\bool_new:N \l__nmc_vv_invisible_bool
\clist_new:N \l__nmc_vv_clist
\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
\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
\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 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:
        \__nmc_initialize:Nn ##1 { #2 }
        \__nmc_inputs_get:nnnnn { #2 } { ##2 } { ##3 } {##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, settings_digest, process, display }
      { \cs_new_protected:cpn { __nmc_#2_##1: } { \prg_do_nothing: } }
  } 
\nmc_define:NnN \nmcEvaluate { eval } \eval
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\cs_new_protected:Npn \__nmc_initialize:Nn #1#2
  {
    \bool_gset_false:N \g__nmc_error_bool
    \bool_set_eq:NN \l__nmc_num_only_bool #1
    \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
    \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
    \tl_set:Nn \l__nmc_dbg_idii_tl { vv-list }
    \use:c { __nmc_#2_initialize: }
  }
\cs_new_protected:Npn \__nmc_inputs_get:nnnnn #1#2#3#4#5
  { 
    \__nmc_error_where:n { settings }
    \tl_if_empty:nF { #2 } 
      { 
        \keys_set_known:nn { numerica/generic } { #2 } 
        \keys_set_known:xn { numerica/#1 }{ #2 }
      }
    \use:c { __nmc_#1_settings_digest: }
    \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl
    \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_get_num_format:n { #5 } 
            \__nmc_error_where:n { variable\,=\,value~list }
            \__nmc_vv_extract_visible:nN { #4 } \l__nmc_vv_clist
            \use:c { __nmc_#1_vv_digest:N } \l__nmc_vv_clist
          }
          { % empty vv-list
            \__nmc_get_num_format:n { #4#5 }
            \use:c { __nmc_#1_vv_digest:N } \c_empty_clist
            \tl_clear:N \l__nmc_vv_inline_tl
            \tl_clear:N \l__nmc_vv_display_tl
            \bool_set_true:N \l__nmc_vv_invisible_bool
          }
        \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl  
      }
  }
%%%%%%%%%%%%%%%%% debug routines %%%%%%%%%%%%%%%%
\cs_new_protected:Npn \__nmc_dbg_display:nn #1#2
  { \__nmc_dbg_display:xnn { \mode_if_math:TF { ed }{ * } } { #1 } { #2 } }
\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_dbg_vv_tl { #2 } \l__nmc_dbg_idii_tl } 
      \__nmc_if_mod_zero:nnT { #2 } { 3 }
        { \__nmc_dbg:Nnn \l_nmc_formula_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 }
          \bool_if:nT { !\g__nmc_error_bool 
                        && !\str_if_eq_p:nn { #3 } { table } }
            { \\ \text{result:} & \quad \text{\l_nmc_result_tl } }
        }
    \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 { #2 } > { 0 }
      { \vbox_top:n } { \hbox: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 }
%%%%%%%%%%%%%% formula, delimiters %%%%%%%%%%%%%%
\cs_new_protected:Npn \__nmc_math_delims:n #1
  { % #1 formula 
    \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 } }
            { % \[ ?
              \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_eqn_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 }

%%%%%%%%%% number-formatting routines %%%%%%%%%%%
\cs_new_protected:Npn \__nmc_get_num_format:n #1
  {
    \__nmc_error_where:n { result~format~spec. }
    \str_set:Nn \l_tmpa_str { #1 }
    \tl_clear:N \l_tmpa_tl
    \int_zero:N \l__nmc_num_alt_int
    \str_if_in:NnTF \l_tmpa_str { ? }
      { \__nmc_num_bool_spec: }
      {
        \str_if_in:NnT \l_tmpa_str { * }
          { 
            \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_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 rnd; #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 } }
      { 
        \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_bool_out:nNn #1#2#3
  {
    \fp_compare:nNnTF { 0 } = { #1 }
      { \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_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 } } 
          { \__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} } 
          { \hbox:n { \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
    \clist_set:Nn \l_tmpa_clist { #1 } 
    \mode_if_math:F
      {
        \__nmc_vv_remove_delims:N \l_tmpa_clist
        \tl_trim_spaces:N \l_tmpa_clist
      }
    \clist_clear:N #2 
    \clist_map_inline:Nn \l_tmpa_clist % to remove { }
      { 
        \tl_if_head_is_group:nTF { ##1 }
          { \clist_put_left:Nx #2 { \tl_head:n { ##1 } \tl_tail:n { ##1 } } }
          { 
            \seq_put_right:Nn \l__nmc_vv_visible_seq { ##1 } 
            \clist_put_left:Nn #2 { ##1 }
          }
      }
    \__nmc_vv_subst_style:
  }
\cs_new_protected:Npn \__nmc_vv_remove_delims:N #1 
  {
    \exp_args:Nx\str_case:nn { \tl_head:N #1 }
      {
        { $ } { \tl_remove_all:Nn #1 { $ } }
        { \( } { \tl_map_inline:nn {\(\)} { \tl_remove_once:Nn #1 { ##1 } } }
        { \[ } { \tl_map_inline:nn {\[\]} { \tl_remove_once:Nn #1 { ##1 } } }
      }
  }
\cs_new_protected:Npn \__nmc_vv_subst_style:
  {
    \seq_if_empty:NTF \l__nmc_vv_visible_seq
      { \bool_set_true:N \l__nmc_vv_invisible_bool }
      { 
        \tl_map_inline:nn { \l__nmc_vv_inline_tl \l__nmc_vv_display_tl }
            { \tl_replace_once:Nnx ##1 { 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
    \seq_concat:NNN \l__nmc_vv_all_seq 
        \g__nmc_consts_vv_seq \l__nmc_vv_all_seq 
    \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~$\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_gset_protected:Npn \__nmc_eval_initialize:
  {
    \tl_set:Nn \l__nmc_dbg_idiii_tl { formula }
    \tl_set:Nn \l__nmc_dbg_idv_tl { stored }
  }
\cs_gset_protected:Npn \__nmc_eval_settings_digest: 
  { \bool_set_true:N \l__nmc_allow_TF_out_bool }

\cs_gset_eq:NN \__nmc_eval_vv_digest:N \__nmc_vv_digest:N

\cs_gset_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
      {
        \tl_set:Nx \l_nmc_result_tl { \fp_to_tl:n { \l__nmc_fp_expr_tl } }
        \__nmc_error_fpflag:
      }
    \int_if_zero:nF \l__nmc_dbg_int
      { \__nmc_dbg_get_data: }
  }
\cs_gset_protected:Npn \__nmc_eval_display:
  {
    \__nmc_num_format:nNnN { \l_nmc_result_tl } \l_nmc_result_tl
        { \l__nmc_round_int } \l__nmc_sci_num_out_bool
    \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 }
              { 
                \bool_if:NF \l__nmc_vv_invisible_bool
                  { 
                    \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
  }  
% 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
% 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_var: }
      } 
    \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 } }
  }
% to avoid e.g. 34 instead of 3*4
\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 \l__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:noF { ! } \l__nmc_C_tl
          { 
            \__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 \l__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:noTF { <=> } \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
    \__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__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_font:
  { 
    \__nmc_next:
    \__nmc_accum_fpify_parenth:NN \l__nmc_accum_tl \l__nmc_B_tl
  }
\cs_new_protected:Npn \__nmc_fpify_splitfrac:
  {
    \__nmc_next:
    \tl_set_eq:NN \l_tmpb_tl \l__nmc_B_tl
    \__nmc_next:
    \tl_put_right:NV \l_tmpb_tl \l__nmc_B_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__nmc_C_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__nmc_C_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
  }
\cs_new_protected:Npn \__nmc_fpify_BE:
  { 
    \__nmc_next: 
    \tl_if_in:VnT \l__nmc_B_tl { alignat }
      { \__nmc_next: }
  }
\cs_new_protected:Npn \__nmc_fpify_cmd:
  { 
    \__nmc_insert_aster:
    \prop_get:NoNT \g__nmc_subst_misc_prop \l__nmc_B_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
  { % \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: }
    \bool_set_true:N \l__nmc_num_only_bool
    \__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:
      \int_add:Nn \l__nmc_depth_int { 2 }
      \exp_last_unbraced:No \__nmc_inputs_get:nnnnn \l__nmc_delim_arg_tl
      \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
      \tl_put_right:Nn \l__nmc_accum_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 } }
  }
% 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 { prod }
        \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
        \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__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
        \__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__nmc_A_tl
        \tl_gset_eq:NN \g_tmpb_tl \l__nmc_C_tl
        \exp_args:NNNV
        \group_end:
            \fp_set:Nn \l__nmc_sum_total_fp { \l__nmc_sum_total_fp }
        \tl_set_eq:NN \l__nmc_A_tl \g_tmpa_tl 
        \tl_set_eq:NN \l__nmc_C_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__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
    \bool_if:NF \g__nmc_error_bool
      { \__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 } }
          }
      }
  }
% #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: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 <-- \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: } 
        \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 { |./ } \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
  { 
    \int_compare:nNnTF { \l__nmc_posi_int } = { 3 }
      { \__nmc_delim_tfrac: }
      {
        \__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_cleave:
  { 
    \__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
  }
\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:
  { 
    \__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__nmc_B_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__nmc_C_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__nmc_A_tl \l__nmc_B_tl
    \tl_set:Nx \l__nmc_C_tl { \tl_head:N \l__nmc_B_tl }
    \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_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 }
      }
  }
%%%%%%%%% 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 }
  }
\clist_new:N \g__nmc_info_proc_clist 
\clist_gset:Nn \g__nmc_info_proc_clist { sum, prod }
\cs_gset_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_tmpa_seq
            { ##1~{ \use:c { g__nmc_info_##1_tl } } }
      }
    \tl_set:Nx \l__nmc_dbg_vv_tl { \seq_use:Nn \l_tmpa_seq {,~} }
  }
\cs_gset_protected:Npn \__nmc_info_process:
  { \tl_set_eq:Nc \l_nmc_result_tl { g__nmc_info_\l_nmc_formula_tl _tl } 
  }
\cs_gset_protected:Npn \__nmc_info_display:
  { 
    \bool_if:NTF \l__nmc_num_only_bool
      { \l_nmc_result_tl }
      {
        \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_result_tl { 0 } }
            \tl_use:N \l_nmc_result_tl
            \prop_get:NVN \g__nmc_subst_misc_prop \l_nmc_formula_tl \l_tmpb_tl
            \ \l_tmpb_tl % pluralise?
            \int_if_zero:nF { \l_nmc_result_tl - 1 } { s } 
            \seq_gpop:NN \g__nmc_error_where_seq \l__nmc_toss_tl
          }
          {
            \__nmc_error_where:n { \__nmc_verb:n {\nmcInfo}~command }
            \__nmc_error_what:n 
                { Unknown~process~\__nmc_verb:V \l_nmc_formula_tl\ in }
          }
      }
  }
%%%%%%%%%%%%% user-defined macros %%%%%%%%%%%%%%%
\clist_new:N \g__nmc_macros_clist
\bool_new:N \l__nmc_macros_free_bool

\nmc_define:NnN \nmcMacros { macros } \macros

\cs_gset_protected:Npn \__nmc_macros_initialize:
  {
    \tl_set:Nn \l__nmc_dbg_idiii_tl { macros }
    \tl_set:Nn \l__nmc_dbg_idv_tl { stored }
  }
\cs_gset_protected:Npn \__nmc_macros_vv_digest:N #1
  { 
    \__nmc_error_where:n {  \__nmc_verb:n { \nmcMacros }\ command }
    \clist_set:No \l_tmpa_clist \l_nmc_formula_tl
    \clist_clear:N \l_tmpb_clist
    \clist_map_inline:Nn \l_tmpa_clist
      { 
        \cs_if_exist:NTF ##1
          {
            \clist_put_right:Nx \l_tmpb_clist 
                {\exp_not:N ##1 {~\exp_not:f ##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_tmpb_clist
        \__nmc_vv_digest:N #1
        \int_if_zero:nF \l__nmc_dbg_int
          { \__nmc_dbg_vv_view:n { 0 } }
        \clist_set:No \l_tmpb_clist \l_nmc_formula_tl
      }
  }
\cs_gset_protected:Npn \__nmc_macros_process:
  {
    \bool_if:NTF \l__nmc_macros_free_bool
      { \__nmc_macros_deregister:N \l_tmpa_clist }
      { \__nmc_macros_register:N \l_tmpb_clist  }
    \clist_gremove_duplicates:N \g__nmc_macros_clist
    \bool_if:NT \l__nmc_num_only_bool
      { 
        \tl_set:Nx \l_nmc_result_tl 
            { \int_eval:n { \clist_count:N \g__nmc_macros_clist } }
      }
  }
\cs_gset:Npn \__nmc_macros_display:
  { \bool_if:NT \l__nmc_num_only_bool { \l_nmc_result_tl } }
%%%%%%%%%%
\cs_gset_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_gset_protected:Npn \__nmc_macros_register:N #1
  { 
    \__nmc_error_where:n { \__nmc_verb:n { \nmcMacros } }
    \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_tmpa_clist \g__nmc_macros_clist
    \clist_remove_duplicates:N \g__nmc_macros_clist
    \clist_map_inline:Nn \l_tmpa_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_tmpb_clist
        \clist_map_inline:Nn \g__nmc_macros_clist 
          { 
            \clist_put_right:Nx \l_tmpb_clist 
              { \exp_not:N ##1 {~\exp_not:f ##1} }
          }
        \tl_set:No \l_nmc_formula_tl \l_tmpb_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_idiii_tl { #2 }
    \bool_if:NT #1
      { 
        \int_if_zero:nF { \l__nmc_dbg_int }
          { \int_set:Nn \l__nmc_dbg_int { 3*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
\int_new:N \g__nmc_consts_vv_int % count multitok + 1
\bool_new:N \l__nmc_consts_add_bool
\nmc_define:NnN \nmcConstants { consts } \constants

\cs_gset_protected:Npn \__nmc_consts_initialize:
  {
    \__nmc_error_where:n { \__nmc_verb:n { \nmcConstants } }
    \tl_set:Nn \l__nmc_dbg_idiii_tl { added }
    \tl_set:Nn \l__nmc_dbg_idv_tl { constants }
  }
\cs_gset_protected:Npn \__nmc_consts_vv_digest:N #1
  { % #1=*reversed* vv-list
    \bool_if:nT { !\l__nmc_consts_add_bool &&
                  !\tl_if_empty_p:N \l_nmc_formula_tl }
      { \__nmc_consts_clear: }
    \clist_set:NV \l_tmpa_clist \l_nmc_formula_tl
    \clist_reverse:N \l_tmpa_clist
    \clist_concat:NNN \l_tmpb_clist #1 \l_tmpa_clist
    \__nmc_vv_digest:N \l_tmpb_clist
    \clist_set:No \l_nmc_formula_tl \l_nmc_formula_tl
    \clist_reverse:N \l_nmc_formula_tl
    \int_if_zero:nF \l__nmc_dbg_int
      { \__nmc_dbg_vv_view:n { \clist_count:N \l_tmpa_clist } }
  }
\cs_gset_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_gset_protected:Npn \__nmc_consts_process:
  { 
    \tl_if_empty:NF \l_nmc_formula_tl
      {
        \seq_set_from_clist:NN \l_tmpa_seq \l_nmc_formula_tl
        \seq_map_inline:Nn \l_tmpa_seq
          { 
            \__nmc_split_eq:w ##1\q_stop
            \prop_get:NVN \l__nmc_subst_var_prop \l__nmc_eq_var_tl \l_tmpb_tl
            \clist_pop:NN \l_tmpa_clist \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_put_right:Nn \l__nmc_eq_var_tl { = }
                \tl_put_right:NV \l__nmc_eq_var_tl \l_tmpb_tl
              }
              {
                \tl_put_right:Nn \l__nmc_eq_var_tl { = }
                \tl_set:Nx \l_tmpa_tl 
                    { \exp_not:o\l__nmc_eq_var_tl { \fp_eval:n \l_tmpb_tl } }
                \tl_put_right:NV \l__nmc_eq_var_tl \l_tmpb_tl
                \seq_gput_right:NV \g__nmc_consts_vv_seq \l_tmpa_tl
              }
            \seq_gput_right:NV \g__nmc_consts_seq \l__nmc_eq_var_tl
          }
        \int_gset:Nn \g__nmc_consts_vv_int
            { 1 + \seq_count:N \g__nmc_consts_vv_seq }
      }
    \bool_if:nT 
        { 
          (\tl_if_empty_p:N \l_nmc_formula_tl) && 
          (\int_compare_p:nNn { \l__nmc_dbg_int } = { 30 })
        }
      { \int_set:Nn \l__nmc_dbg_int { 5 } }
    \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 
            { \int_eval:n { \seq_count:N \g__nmc_consts_seq }  }
      }
  }
\cs_gset_protected:Npn \__nmc_consts_display:
  { \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
\tl_new:N \l__nmc_reuse_loaded_tl
\bool_new:N \l__nmc_reuse_loaded_bool
\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 last \eval-uation to \#1
\nmc_define:NnN \nmcReuse { reuse } \reuse

\cs_gset_protected:Npn \__nmc_reuse_settings_digest:
  { 
    \tl_set:Nn \l__nmc_dbg_idii_tl { saved }
    \__nmc_reuse_load: 
  }
\cs_gset_protected:Npn \__nmc_reuse_process:
  {
    \__nmc_error_where:n { \__nmc_verb:n { \nmcReuse }~command }
    \tl_if_empty:NTF \l_nmc_formula_tl
      {
        \int_if_zero:nTF { 1 + \l__nmc_reuse_mode_int }
          { \__nmc_reuse_delete_all: }
          { \__nmc_reuse_load: }
      }
      { \__nmc_reuse_mode:Nn \l_nmc_formula_tl { \l__nmc_reuse_mode_int } }
    \bool_if:NT \l__nmc_num_only_bool
      { 
        \tl_set:Nx \l_nmc_result_tl
          { \int_eval:n { \clist_count:N \l__nmc_reuse_loaded_tl } }
      }
    \__nmc_reuse_dbg_display:Nn \l_nmc_formula_tl { \l__nmc_dbg_int }
  }
\cs_gset_protected:Npn \__nmc_reuse_display:
  { \bool_if:NT \l__nmc_num_only_bool { \l_nmc_result_tl } }
%%%%%%%%%%
\cs_new_protected:Npn \__nmc_reuse_load:
  { 
    \bool_if:NF \l__nmc_reuse_loaded_bool
      { 
        \file_get:VnNT \g__nmc_reuse_filename_tl {} \l_tmpa_tl
          { 
            \clist_set:No \l__nmc_reuse_loaded_tl \l_tmpa_tl
            \bool_lazy_or:nnTF 
                { \tl_if_blank_p:V \l__nmc_reuse_loaded_tl }
                { \tl_if_head_eq_meaning_p:VN \l__nmc_reuse_loaded_tl \par }
              { \tl_clear:N \l__nmc_reuse_loaded_tl }  
              { 
                \seq_set_split:NnV \l_tmpa_seq {,} \l__nmc_reuse_loaded_tl
                \seq_map_inline:Nn \l_tmpa_seq
                    { \__nmc_reuse_write_props:Nn ##1 }
              }
          }
        \bool_set_true:N \l__nmc_reuse_loaded_bool
      }
  } 
\cs_new_protected:Npn \__nmc_reuse_mode:Nn #1#2
  { 
    \int_if_zero:nTF { 1 + #2 } % if #2=-1
      { \__nmc_reuse_delete_one:c #1 }
      {
        \tl_if_empty:NTF \g__nmc_reuse_tl
          { \__nmc_error_what:n  { No~result~available~for~\__nmc_verb:V #1\ in } }
          { 
            \exp_args:NNc \tl_set:Nn \l_tmpa_tl #1
            \prop_if_in:NVTF \g__nmc_subst_var_prop \l_tmpa_tl
              {
                \int_if_zero:nTF { #2 }
                  { \__nmc_reuse_already_def:N \l_nmc_formula_tl }
                  { 
                    \__nmc_reuse_delete_one:c #1 
                    \__nmc_reuse_save:c #1
                  }
              }
              { \__nmc_reuse_save:c #1 }
        }
      }
  }
\cs_new_protected:Npn \__nmc_reuse_dbg_display:Nn #1#2
  {
    \bool_if:nTF 
        { 
          !\int_if_zero_p:n { #2 } && 
          ( \int_if_zero_p:n { 1 + \l__nmc_reuse_mode_int } 
            || \tl_if_empty_p:N #1 ) 
        }
      {
        \tl_set:Nx \l__nmc_dbg_vv_tl 
            { \clist_use:Nn \l__nmc_reuse_loaded_tl {,~} }  
      }
      { \clist_pop:NN \l__nmc_reuse_loaded_tl \l__nmc_dbg_vv_tl }
  }
\cs_new_protected:Npn \__nmc_reuse_save:N #1
  {
    \__nmc_reuse_load:
    \tl_set:Nn \l_tmpb_tl { #1 } 
    \tl_put_right:Nx \l_tmpb_tl { { \exp_not:o \g__nmc_reuse_tl } }
    \prop_get:NnNTF \l__nmc_subst_var_prop { #1 } \l_tmpa_tl
      { \exp_last_unbraced:NV\__nmc_reuse_defcmds:Nn \l_tmpb_tl }
      { 
        \cs_if_exist:NTF #1
          { \__nmc_reuse_already_def:N \l_nmc_formula_tl }
          { \exp_last_unbraced:NV\__nmc_reuse_defcmds:Nn \l_tmpb_tl }
      }
  }
\cs_generate_variant:Nn \__nmc_reuse_save:N { c }

\cs_new_protected:Npn \__nmc_reuse_defcmds:Nn #1#2
  { 
    \tl_set_rescan:Nnn #1 { \ExplSyntaxOn } { #2 }
    \__nmc_reuse_write_props:Nn #1{#2}
    \tl_if_empty:NF \l__nmc_reuse_loaded_tl
      { \__nmc_reuse_delete:N #1 }
    \clist_put_left:Nn \l__nmc_reuse_loaded_tl { #1 {#2} }
    \iow_open:NV \g__nmc_iow \g__nmc_reuse_filename_tl
    \str_set:NV \l_tmpa_str \l__nmc_reuse_loaded_tl
    \iow_now:NV \g__nmc_iow \l_tmpa_str
    \iow_close:N \g__nmc_iow
  }
\cs_new_protected:Npn \__nmc_reuse_write_props:Nn #1#2
  {
    \prop_gput:Nnn \g__nmc_subst_var_prop { #1 } { #2 }
    \tl_gset:Nn #1 { #2 }
  }
\cs_new_protected:Npn \__nmc_reuse_delete:N #1
  {
    \seq_clear:N \l_tmpb_seq
    \seq_set_split:NnV \l_tmpa_seq {,} \l__nmc_reuse_loaded_tl
    \seq_map_inline:Nn \l_tmpa_seq
      { 
        \exp_args:No\str_if_eq:nnF { \use_i:nn ##1 } { #1 }
          { \seq_put_right:Nn \l_tmpb_seq { ##1 } }
      }
    \tl_set:Nx \l__nmc_reuse_loaded_tl { \seq_use:Nn \l_tmpb_seq {,} }
  }
\cs_new_protected:Npn \__nmc_reuse_delete:Nn #1#2
  { 
    \prop_gremove:Nn \g__nmc_subst_var_prop { #1 }
    \cs_undefine:N #1
  }
\cs_new_protected:Npn \__nmc_reuse_delete_one:N #1
  { 
    \__nmc_reuse_load:
    \tl_if_empty:NF \l__nmc_reuse_loaded_tl
      { \__nmc_reuse_delete:N #1 }
    \__nmc_reuse_delete:Nn #1 {}
    \iow_open:NV \g__nmc_iow \g__nmc_reuse_filename_tl
    \iow_now:NV \g__nmc_iow \l__nmc_reuse_loaded_tl
    \iow_close:N \g__nmc_iow
  }
\cs_generate_variant:Nn \__nmc_reuse_delete_one:N { c }

\cs_new_protected:Npn \__nmc_reuse_delete_all:
  {
    \__nmc_reuse_load:
    \tl_if_empty:NF \l__nmc_reuse_loaded_tl
      {
        \seq_set_split:NnV \l_tmpa_seq {,} \l__nmc_reuse_loaded_tl
        \seq_map_inline:Nn \l_tmpa_seq { \__nmc_reuse_delete:Nn ##1 }
        \tl_clear:N \l__nmc_reuse_loaded_tl
      }
    \iow_open:NV \g__nmc_iow \g__nmc_reuse_filename_tl
    \iow_close:N \g__nmc_iow  
  }
\cs_new_protected:Npn \__nmc_reuse_already_def:N #1
  { \__nmc_error_what:n { \__nmc_verb:c #1\ already~defined~in } }
%%%%%%%%%%%%%%%%%%% 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_eqn_num_tl
\int_new:N \l__nmc_posi_int
\int_set:Nn \l__nmc_posi_int { 1 }
\int_new:N \l__nmc_eval_reuse_int
\int_new:N \l__nmc_dbg_int
\cs_new_protected:Npn \__nmc_dbg_int:nn #1#2
  { 
    \int_set:Nn \l__nmc_dbg_int 
        { 
          \int_compare:nNnTF { \int_abs:n { #1 } } = { 1 } 
            { \int_sign:n { #1 }*#2 } { #1 } 
        }
  }
\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 }
      { \int_set_eq:NN \l__nmc_trg_int \c__nmc_trg_int } % #1=2,3
      { \int_set_eq:NN \l__nmc_trg_int \c__nmc_uny_int } % #1=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 } } 
\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 },
    use-degrees            .code:n = \__nmc_int_to_bool:Nn
                                       \l__nmc_deg_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,
    use-degrees          .default:n = 0,
    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,use-degrees,
    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 = \__nmc_dbg_int:nn { #1 } { 2*3*5*7 },
    dbg .initial:n = 0,
    view   .code:n = \__nmc_dbg_int:nn { 1 } { 2*3*5*7 },
    ^      .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 = \__nmc_int_to_bool:Nn \l__nmc_deg_bool { #1 },
    o   .default:n = 1,
    log  .tl_set:N = \l__nmc_log_base_tl,
    vvmode .code:n = \__nmc_calc_mode:n { \int_sign:n { #1*#1 } },
    vv@    .code:n = \__nmc_calc_mode:n { \int_sign:n { #1*#1 } },
    vv@ .initial:n = 0,
    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_eqn_num_tl { * },
    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 }
  { 
    p      .tl_set:N = \l__nmc_punc_tl,
    p     .default:n = {,},
    reuse .int_set:N = \l__nmc_eval_reuse_int
  }
\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 } { 2 },
    delete .code:n = \int_set:Nn \l__nmc_reuse_mode_int { -1 },
    renew  .code:n = \int_set:Nn \l__nmc_reuse_mode_int { 1 }
  }
\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 file `numerica.sty'