如何从 ConTeXt 或 Plain TeX 中的宏中获取和、差、积和商?

如何从 ConTeXt 或 Plain TeX 中的宏中获取和、差、积和商?

我想创建一组这样的宏:

\addnumbers{2}{5}

\subtractnumbers{3}{5}

\multiplynumbers{2}{-2}

\dividenumbers{2}{8}

第一个将显示数字 7,加上#1#2

第二个将显示-2,#2从中减去#1

第三个将显示 -4,#1乘以#2

最后将显示 4,#2除以#1

我曾尝试在 ConTeXt 甚至 Plain TeX 中寻找进行这些计算的方法,但由于数学是该软件中常见的显示内容,因此搜索结果仅返回显示数学的方法,而不是计算数学的方法。

我怎样才能让这些宏进行计算?

答案1

在 ConTeXt 中您可以使用 lua 接口:

\starttext
  The first will display the number \ctxlua{context(2+5)}
\stoptext

在此处输入图片描述

答案2

您可以使用 ε-TeX 原语\numexpr来表示可扩展的整数表达式。唯一的限制是它无法在没有 ε-TeX 扩展的引擎(现在主要是 Knuth TeX)中工作,在这种情况下您需要使用 siracusa 的解决方案。

这些宏是可扩展的,允许您在任何 TeX 需要数字的地方使用它们,例如\ifnum\ifcase\ifdim(使用适当的单位)测试、寄存器分配等。

下面是您想要的四个接口(我交换了参数的顺序,\dividenumbers因为我认为这样更有意义),加上一个泛型\inteval,它接受整数表达式,如2+5*(3-4),作为参数:

\def\addnumbers#1#2{\number\numexpr#1+#2\relax}
\def\subtractnumbers#1#2{\number\numexpr#1-#2\relax}
\def\multiplynumbers#1#2{\number\numexpr#1*#2\relax}
\def\dividenumbers#1#2{\number\numexpr#1/#2\relax}
\def\inteval#1{\number\numexpr#1\relax}

\def\test#1#2#3#4{$#2#3#4 = #1{#2}{#4}$\par}
\test\addnumbers{2}+{5}
\test\subtractnumbers{3}-{5}
\test\multiplynumbers{2}\times{-2}
\test\dividenumbers{8}\div{2}

$2+5\times(3-4) = \inteval{2+5*(3-4)}$
\bye

在此处输入图片描述

如果您不想将自己限制为整数,则可以使用expl3的 FPU,它与格式无关,并且可扩展。它允许您进行更大范围的操作。下面的代码定义了您要求的四个接口,以及\fpeval通用浮点表达式(在 LaTeX 中,该包xfp提供相同的\fpeval):

\input expl3-generic.tex
\ExplSyntaxOn
\cs_new:Npn \addnumbers #1 #2
  { \fp_eval:n { #1 + #2 } }
\cs_new:Npn \subtractnumbers #1 #2
  { \fp_eval:n { #1 - #2 } }
\cs_new:Npn \multiplynumbers #1 #2
  { \fp_eval:n { #1 * #2 } }
\cs_new:Npn \dividenumbers #1 #2
  { \fp_eval:n { #1 / #2 } }
\cs_new:Npn \fpeval #1
  { \fp_eval:n { #1 } }
\ExplSyntaxOff
\def\test#1#2#3#4{$#2#3#4 = #1{#2}{#4}$\par}
%
\test\addnumbers{2}+{5}
\test\subtractnumbers{3}-{5}
\test\multiplynumbers{2}\times{-2}
\test\dividenumbers{8}\div{2}

$2^2+5\times(\cos(3)-4) = \fpeval{2^2+5*(cos(3)-4)}$
\bye

在此处输入图片描述

答案3

由于您尚未指定解决方案是否应该可扩展,因此这是一个不可扩展的纯 TeX 解决方案。

我们首先定义一个通用\docalc宏,它接受一个计算命令,该命令作用于计数寄存器(\advance\multiply\divide)和两个操作数。该操作应用于本地寄存器,之后立即输出其值。基于此,\docalc我们定义了四个宏来执行基本的算术运算:

\def\docalc#1#2#3{%
    \begingroup
    \count0=#3
    #1\count0 by #2\relax
    \the\count0
    \endgroup
}

\def\addnumbers       {\docalc\advance}
\def\subtractnumbers#1{\docalc\advance{-#1}}
\def\multiplynumbers  {\docalc\multiply}
\def\dividenumbers    {\docalc\divide}

$2 + 5 = \addnumbers{2}{5}$

$5 - 3 = \subtractnumbers{3}{5}$

$2 \cdot (-2) = \multiplynumbers{2}{-2}$

$8 \div 2 = \dividenumbers{2}{8}$
\bye

在此处输入图片描述

答案4

\addnumbers这是一个 Plain-LuaTeX 解决方案。 、等的参数\subtractnumbers可以是数字,也可以是使用简单算术运算(但不是指数运算,因为^TeX 和 Lua 之间的 含义截然不同)计算结果为数字的东西。如果计算结果为整数,则不会打印小数部分,这得益于myprint下面定义的 Lua 实用函数。

在此处输入图片描述

% !TEX TS-program = luatex
\directlua{% Define a utility function:
  function myprint (u) 
    if u==math.floor (u) then 
      tex.sprint ( math.floor (u) )
    else 
      tex.sprint (u) 
    end
  end
}
\def\addnumbers#1#2{\directlua{myprint((#1)+(#2))}}
\def\subtractnumbers#1#2{\directlua{myprint((#1)-(#2))}}
\def\multiplynumbers#1#2{\directlua{myprint((#1)*(#2))}}
\def\dividenumbers#1#2{\directlua{myprint((#2)/(#1))}}

$\addnumbers{8-6}{5} \quad
 \subtractnumbers{3}{6-1} \quad
 \multiplynumbers{2}{-6+4} \quad
 \dividenumbers{3-1}{4+2+4/2}$
\bye

相关内容