我该如何在 TeX 中实现一个函数来添加任意数量的数字?阅读注释\def
,似乎它最多只能接受九个参数。我该如何创建一个函数来将任意大的数字列表相加?
答案1
我将假设输入的形式为
\addintegers{1 + 2 + 3}
IE由一系列由+
符号和(可能)空格分隔的整数组成。我还假设解决方案不需要可扩展,我们只有 TeX3 基元可用,并且我们不必担心“大”值(大于寄存器可以容纳的值\count
)。
为了在这里找到总和,我们需要对输入设置一个循环,一次抓取一个数字。我们知道+
每个数字之间都有,所以这样做的方法是使用以下形式的宏
\def\foo#1+{% Code
因为这样会抓取到下一个 之前的所有内容+
。然后我们需要确保+
在用户输入之后有一个 ,并且我们有一些“标记”,我们可以将其测试为“循环结束”。为了进行实际的数学运算,TeX 提供了\count
寄存器:我将在组内使用划痕,并使用 将结果发送到组外\expandafter
:
\catcode`\@=11 %
\def\addintegers#1{%
\begingroup
\count0=0\relax
\addintegers@aux#1+\relax+\relax
}
\def\addintegers@aux#1+{%
\ifx\relax#1\relax
\expandafter\addintegers@end
\else
\advance\count0 by #1\relax
\expandafter\addintegers@aux
\fi
}
\def\addintegers@end#1\relax{%
\expandafter\endgroup
\number\count0 %
}
\catcode`\@=12 %
\addintegers{1}
\addintegers{1 + 2 + 3}
\addintegers{1 + 22 + 333}
\bye
这当然是一个相当受限的解决方案(例如,除非有符号,否则不会涉及减法+
),但问题需要更多细节才能更进一步。完整的错误检查需要更复杂的东西。
如果 e-TeX 基元可用,则几乎不费吹灰之力就可以实现相同的扩展
\def\inteval#1{\number\numexpr#1\relax}
\inteval{1}
\inteval{1 + 2 + 3}
\inteval{1 + 22 + 333}
\bye
在这种情况下,计算可以包括+
、、、和,正如 e- TeX所支持的(因此名称不同)。(e-TeX 还允许表达式中使用空格。-
)*
/
(
)
如果您希望可扩展地工作并且只使用 Knuth 的 TeX,那么这是可行的,尽管有点乏味。Heiko Oberdiekbigintcalc
可以可扩展地对任意整数进行计算,而无需使用 e-TeX,因此我们可以利用它(它相当大):
\input bigintcalc.sty %
\catcode`\@=11 %
\def\addintegers#1{%
\addintegers@auxi#1+\relax+\stop{0}%
}
\def\addintegers@auxi#1+{%
\ifx\relax#1%
\expandafter\addintegers@end
\else
\expandafter\addintegers@auxii
\fi
{#1}%
}
\def\addintegers@auxii#1#2\stop#3{%
\addintegers@auxi#2\stop{\bigintcalcAdd{#1}{#3}}%
}
\def\addintegers@end#1\stop#2{#2}
\catcode`\@=12 %
\addintegers{1}
\addintegers{1 + 2 + 3}
\addintegers{1 + 22 + 333}
\bye
细节在于将输入分成单独的数字,如果不可用则bigintcalc
“手动”进行计算。\numexpr