在 Latex 中不使用任何包进行阶乘程序

在 Latex 中不使用任何包进行阶乘程序

我听说 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优化将取代+1by +\@ne>0<space>by >\z@,等等......

注2:使用私人信件可能会令人不安,但它很时尚,而且比;-)_更具可读性。@

相关内容