有没有办法定义一个可以评估数学表达式的新命令

有没有办法定义一个可以评估数学表达式的新命令

假设我有一个非常复杂的函数,它依赖于ij。所以我定义了一个新命令,比如

\newcommand{\foo}[2]{X_{i+j+1}}. % This might be an complicated expression, but I want to keep it simple

\foo{\alpha}{\beta}使用这个定义,我可以像或一样调用这个命令\foo{2}{3}。现在,我想要得到的是,如果 两个参数都是数值,我想强制它们计算这个表达式的值,即\foo{2}{3}应该生成X_{6}而不是X_{2+3+1}。有时即使我知道完整的表达式,我也必须手动简化它,这很烦人。

我实际上觉得这似乎几乎不可能,但无论如何我还是想问一下是否存在一些解决方法。

答案1

这似乎是一个工作l3regex

\documentclass{article}
\usepackage{xparse,l3regex}

\ExplSyntaxOn
\NewDocumentCommand{\evaluateorprint}{m}
 {
  \regex_match:nnTF { [^0-9+\-] } { #1 }
   { #1 }                 % symbolic expression
   { \int_eval:n { #1 } } % only numbers, + or -
 }
\ExplSyntaxOff

\newcommand\foo[2]{%
  X_{\evaluateorprint{#1+#2+1}}%
}

\begin{document}
\[
\foo{2}{3}+\foo{\alpha}{\beta}
\]
\end{document}

在此处输入图片描述

不带该版本的版本l3regex可能更容易被依赖旧版 TeX 发行版的出版商所接受(由 Bruno Le Floch 提供):

\ExplSyntaxOn
\NewDocumentCommand{\evaluateorprint}{m}
 {
  \group_begin:
  \cs_set_eq:NN \__sungmin_eval:n \int_eval:n
  \tl_map_inline:nn { #1 }
   {
    \tl_if_in:nnF { 0123456789+-*() } { ##1 }
     {
      \cs_set_eq:NN \__sungmin_eval:n \use:n
     }
   }
  \__sungmin_eval:n { #1 }
  \group_end:
 }
\ExplSyntaxOff

函数\__sungmin_eval:n暂时设置为\int_eval:n;然后逐个标记地扫描参数;如果发现数值表达式中不合法的内容,\__sungmin_eval:n则将其更改为\use:n仅输出参数而不进行任何处理。

答案2

我知道我的解决方案乍一看并不优雅(如 egregs),但它只使用 TeX 基元,因此适用于所有人。而且它只使用了 27 行代码(另一方面,加载\usepackage{xparse,l3regex}了数万行代码)。

% \replacestring + \addto from OPmac:
\newcount\tmpnum
\bgroup \catcode`!=3 \catcode`?=3
\gdef\replacestrings#1#2{% 
   \long\def\tmp##1#1##2!{\ifx!##2!\addto\tmpb{##1}\else\addto\tmpb{##1#2}\tmp##2!\fi}%
   \expandafter\def\expandafter\tmpb\expandafter{\expandafter}\expandafter\tmp\tmpb?#1!%
   \def\tmp##1?{\def\tmpb{##1}}\expandafter\tmp\tmpb
}
\egroup
\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}

% \evalindex{text} evaluates text if it is sum of numbers; else the text is printed
\def\evalindex#1{\def\tmpa{#1}\evalindexA#1\evalindexB.\evalindexB\evalindexA}
\def\evalindexA#1#2\evalindexA{%
   \ifx-#1\def\tmpb{#1#2}\else\def\tmpb{+#1#2}\fi
   \replacestrings+{\evalindexB+}\replacestrings-{\evalindexB-}%
   \tmpnum=0 \tmpb
}
\def\evalindexB#1#2\evalindexB{\ifx#1.\the\tmpnum
   \else \setbox0=\hbox{$\tmpnum=0#2$}%
         \ifdim\wd0=0pt \advance\tmpnum by#1#2 \else \evalindexC \fi
   \expandafter\evalindexB \fi
}
\def\evalindexC#1.\evalindexB{\fi\fi \tmpa}

\def\foo#1#2{X_{\evalindex{#1+#2+1}}}

% tests:
$\evalindex{i+j+1} \quad \evalindex{1+2\alpha+3}\quad \evalindex{-1+20-3}$
%           i+j+1                   1+2\alpha+3                  16

$\foo ij \quad \foo\alpha\beta \quad \foo 23$
% X_{i+j+1}     X_{\alpha+\beta+1}    X_6        

\end

这给出的结果与 egregs 解决方案相同。但我知道,你不会投票赞成。玩我的玩具——原始特征只是我的爱好。

答案3

此类命令可以通过包轻松完成calculator,尽管也可以使用计数器方法,只要使用整数索引即可。

在这种情况下,应该将的两个参数\foo相加并增加 1,这可以通过使用

\ADD{#1}{#2}{\resulta}%
\ADD{\resultb}{1}{\resultb}%

通过使用计数器,例如两种可能性——应用\setcounter\addtocounter\numexpr方法。\Foo\FooAgain证明这一点。


\documentclass{scrbook}

\usepackage{calculator}
\usepackage{forloop}

\newcounter{acounter}
\newcounter{bcounter}

\newcommand{\foo}[2]{%
\begingroup
     \def\resultA{}%
     \def\resultB{}%
     \ADD{#1}{#2}{\resultA}%
     \ADD{\resultA}{1}{\resultB}%
        X_{\resultB}
\endgroup%
}%

\newcounter{mydummycounter}
\newcommand{\Foo}[2]{%
  \setcounter{mydummycounter}{#1}%
  \addtocounter{mydummycounter}{#2}%
  \addtocounter{mydummycounter}{1}%
  Y_{\arabic{mydummycounter}}%
}%

\newcommand{\FooAgain}[2]{%
  \setcounter{mydummycounter}{\numexpr #1 + #2 +1}%
  Z_{\arabic{mydummycounter}}%
}%

\begin{document}
Testing:
\[ \foo{2}{3}  \] 

Some playing around: 
\LARGE \bfseries
\forloop{acounter}{1}{\value{acounter} < 11}{%
        \forloop{bcounter}{1}{\value{bcounter} < \value{acounter}}{%
        \( \foo{\number\value{acounter}}{\number\value{bcounter}} \)
        }

}
\end{document}

在此处输入图片描述

相关内容