我想创建一组这样的宏:
\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
答案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