我听说 Latex 是一种图灵完备语言。所以我继续用 Latex 编写了一个斐波那契程序,并且成功了(没有使用包)。现在我想用 Latex 编写一个阶乘程序(不使用包)。我写了以下代码:-(包括调试文本)
\documentclass{article}
\begin{document}
\typein[\n]{Enter the value of n :-}
\newcommand{\scaleup}[2]{
\newcount\ofac
\ofac #1\relax
\newcount\ntemp
\ntemp \the#2\relax
{
\loop
\ifnum \ntemp>1
\advance#1 \the\ofac\relax
\advance\ntemp -1\relax
nfac(m) = \the#1
\nfac \the#1\relax
\repeat
}
}
\newcommand{\factorial}[1]{
\newcount\num
\newcount\nfac
\newcommand{\nfacinloop}{1}
\num #1\relax
\nfac 1\relax
\loop
\ifnum \num>0
% \huge{\the\num}
% \scaleup{\nfac}{\num}
\newcount\ofac
\ofac \nfac\relax
\newcount\ntemp
\ntemp \the\num\relax
{
\loop
\ifnum \ntemp>1
\advance\nfac \the\ofac\relax
\advance\ntemp -1\relax
nfac(m) = \the\nfac
\nfac \the\nfac\relax
\renewcommand{\nfacinloop}{\the\nfac}
nfacinloop = \nfacinloop
\repeat
}
nfac = \the\nfac
nfacinloop = \nfacinloop
% \huge{\the\num}
\advance\num -1\relax
% \huge{\the\num}
\repeat
}
\factorial{\n}
\end{document}
但是这不会运行,因为每次控件退出内循环时,\nfac 的值都会重置为 1。我找不到任何方法(不使用包)来保留 \nfac 的值。我哪里错了吗?请帮忙。
注意:我使用 pdftex 来编译。
答案1
您可以使用全局分配,\global
但是这里不需要任何组,因此本地分配应该足够了。例如,以下使用递归宏而不是循环
\documentclass{article}
\typein[\n]{Enter the value of n :-}
\def\factorial#1{\ffactorial{#1}1}
\def\ffactorial#1#2{%
\ifnum#1=0 \the\numexpr#2\relax
\else
\ffactorial{\the\numexpr#1-1\relax}{\the\numexpr#1*#2\relax}%
\fi}
\begin{document}
\factorial{\n}
\end{document}
但是,如果输入大于 12 的数字,则会由于整数的大小而导致算术溢出。
当然也可以不使用\numexpr
(这相当于\count
您版本中的寄存器使用),而只是将整数编码为十进制扩展的标记列表并手动编码算术。ctan 上有用于大整数算术的软件包。
答案2
其中有一部分这个答案(靠近下半部分)使用没有包裹并计算二项式系数。阶乘13!
已经超出 TeX 的界限,因此需要扩展 TeX 的算法,代码绕过这一点以便例如binomial(13,6)
进行评估(以及相当大的系数)。但如果最终结果超出,2^31
就会发生算术溢出。
代码使用了 e-TeX \numexpr
(如 David 在此处的回答所示)。这给了编写的机会可扩展代码会进一步给您的编程挑战带来困难。
为了方便起见,这里是从原始位置复制粘贴的。
编辑还复制了有助于理解底层数学的评论
% Expandably computing binomial(n,k)=n choose k
% after having replaced k by the smallest of k and n-k, and checked if
% k=0, either one of the following products produces integers at each
% mutiply/divide steps:
% n * (n-1)/2 * (n-2)/3 * .... * (n-k+1)/k
% or
% (n-k+1) * (n-k+2)/2 * (n-k+3)/3 * ... * n/k
% eTeX \numexpr does multiply/divide in one "double-precision" step,
% thus arithmetic overflow should not happen, as long as the result is <
% 2^31 (and naturally the initial n, binomial (2147483648,0) will not
% work
% For no special reason I chose the second product.
% (notice that as k<n-k+1 also the first product is increasing, no
% intermediate thing can cause overflow if the final thing does not)
% Each (n-k+j)/j step could be seen as (n-k)/j + 1, thus only j would need
% incrementing; up to the price of an extra addition, and I preferred to
% carry around both an u=n-k+j and a v=j
% ALGORITHM
% replace k by the smallest of k and n-k
% if k=0 return 1
% else set w=n-k+1
% u=n-k+2
% v=2
% endif
% if v>k return w
% else
% w<-w*u/v
% u<-u+1
% v<-v+1
% repeatif
% Constraint: expandability. Adding +1 has a cost and fetching a list of
% tokens also has one. To use one macro less, or not do twice u->u+1,
% u and v are shifted from the start by 1 to be usable directly in the
% updating of w.
% no check on validity of inputs
%-----------------------------------------------------------
% expandable macro \binomialb. No package needed.
\catcode`_ 11
\def\binomialb #1#2{\romannumeral0\expandafter
\binomialb_a\the\numexpr #1\expandafter.\the\numexpr #2.}
\def\binomialb_a #1.#2.{\expandafter\binomialb_b\the\numexpr #1-#2.#2.}
\def\binomialb_b #1.#2.{\ifnum #1<#2 \expandafter\binomialb_ca
\else \expandafter\binomialb_cb
\fi {#1}{#2}}
\def\binomialb_ca #1{\ifnum#1=0 \expandafter \binomialb_one\else
\expandafter \binomialb_d\fi {#1}}
\def\binomialb_cb #1#2{\ifnum #2=0 \expandafter\binomialb_one\else
\expandafter\binomialb_d\fi {#2}{#1}}
\def\binomialb_one #1#2{ 1}
\def\binomialb_d #1#2{\expandafter\binomialb_e \the\numexpr #2+1.#1!}
% n-k+1.k! -> u=n-k+2.v=2.w=n-k+1.k!
\def\binomialb_e #1.{\expandafter\binomialb_f \the\numexpr #1+1.2.#1.}
% u.v.w.k!
\def\binomialb_f #1.#2.#3.#4!%
{\ifnum #2>#4 \binomialb_end\fi
\expandafter\binomialb_f
\the\numexpr #1+1\expandafter.%
\the\numexpr #2+1\expandafter.%
\the\numexpr #1*#3/#2.#4!}
\def\binomialb_end #1*#2/#3!{\fi\space #2}
\catcode`_ 8
注1:一些轻微的TeX优化将取代+1
by +\@ne
,>0<space>
by >\z@
,等等......
注2:使用私人信件可能会令人不安,但它很时尚,而且比;-)_
更具可读性。@