外循环提前终止

外循环提前终止

我正在尝试在 LaTeX 中实现欧几里得算法。是的,我知道在 Python 中可以更轻松地做到这一点,但这不是重点。我有一个内部循环(提取到宏)来计算一个计数器除以另一个计数器的余数。外循环应该执行内循环,交换计数器的值,然后重复,直到其中一个计数器为 0。

\documentclass{article}
\usepackage{calc}
\setlength{\parskip}{\baselineskip}
\setlength{\parindent}{0pt}

\newcommand{\computeRemainder}[2]{%
  \loop
    \relax
  \ifnum \value{#1} > \value{#2}
    \addtocounter{#1}{-\value{#2}}
  \repeat
  \loop
    \relax
  \ifnum \value{#1} < 0
    \addtocounter{#1}{\value{#2}}
  \repeat}

\newcommand{\swapCounters}[2]{%
  \addtocounter{#1}{\value{#2}} % cA = A + B
  \addtocounter{#2}{\value{#1}} % cB = A + 2B
  \addtocounter{#1}{-\value{#2}} % cA = -B
  \setcounter{#2}{2*\value{#1}+\value{#2}} % cB = A
  \setcounter{#1}{-\value{#1}} % cA = B
}

\begin{document}

\newcounter{counterA}
\setcounter{counterA}{45}
\newcounter{counterB}
\setcounter{counterB}{27}

Before: \( A = \thecounterA, \; B = \thecounterB \) \\
\loop
  \computeRemainder{counterA}{counterB}
  \swapCounters{counterA}{counterB}
\ifnum \value{counterB} > 0
  Since this is true, shouldn't the loop continue? \\
\repeat
End: \( A = \thecounterA, \; B = \thecounterB \)

\end{document}

上述代码产生以下输出:

代码输出

我对循环的理解是,如果它打印\ifnum \value{counterB} > 0和之间的文本\repeat,它应该重复循环。但是,执行后,和counterAcounterB大于 0。知道为什么外循环不会继续吗?

答案1

你不能嵌套\loop在同一级别分组中嵌套,请参阅Tex 嵌套循环

>=对于你可以使用的问题

\loop\unless\ifnum \value{#1} < \value{#2}

您可能还对完全可扩展版本感兴趣。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\euclid}{mm}
 {
  \int_compare:nTF { \int_abs:n { #1 } < \int_abs:n { #2 } }
   {
    \egreg_euclid:ff { \int_abs:n { #2 } } { \int_abs:n { #1 } }
   }
   {
    \egreg_euclid:ff { \int_abs:n { #1 } } { \int_abs:n { #2 } }
   }
 }

\cs_new:Nn \egreg_euclid:nn
 {
  \int_compare:nTF { #2 = 0 }
    { #1 } % end
    { \egreg_euclid:nf { #2 } { \int_mod:nn { #1 } { #2 } } }
 }
\cs_generate_variant:Nn \egreg_euclid:nn { nf , ff }
\ExplSyntaxOff

\begin{document}

\euclid{45}{27}

\euclid{45}{-27}

\euclid{27}{45}

\euclid{10}{0}

\euclid{0}{0}

\edef\temp{\euclid{2345}{356}}

\texttt{\meaning\temp}

\end{document}

\egreg_euclid:nn以递归方式调用自身(在后续调用中使用变体以便使用“显式”值来提高效率)。

在此处输入图片描述

另外,在启动时会接受并规范化负值,因此 gcd 始终是非负的。

这里附有\fulleuclid显示步骤的宏(仅非负数)。

\documentclass{article}
\usepackage{xparse,amsmath}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\euclid}{mm}
 {
  \int_compare:nTF { \int_abs:n { #1 } < \int_abs:n { #2 } }
   {
    \egreg_euclid:ff { \int_abs:n { #2 } } { \int_abs:n { #1 } }
   }
   {
    \egreg_euclid:ff { \int_abs:n { #1 } } { \int_abs:n { #2 } }
   }
 }

\cs_new:Nn \egreg_euclid:nn
 {
  \int_compare:nTF { #2 = 0 }
    { #1 } % end
    { \egreg_euclid:nf { #2 } { \int_mod:nn { #1 } { #2 } } }
 }
\cs_generate_variant:Nn \egreg_euclid:nn { nf , ff }

\NewDocumentCommand{\fulleuclid}{mm}
 {
  \tl_clear:N \l_egreg_fulleuclid_swap_tl
  \seq_clear:N \l_egreg_fulleuclid_steps_seq
  \int_compare:nTF { #1 < #2 }
   {
    \tl_set:Nn \l_egreg_fulleuclid_swap_tl { #1 &\leftrightarrow #2 \\ }
    \egreg_fulleuclid:nn { #2 } { #1 }
   }
   {
    \egreg_fulleuclid:nn { #1 } { #2 }
   }
  \begin{align}
  \tl_use:N \l_egreg_fulleuclid_swap_tl
  \seq_use:Nn \l_egreg_fulleuclid_steps_seq { \\ }
  \end{align}
 }

\tl_new:N \l_egreg_fulleuclid_swap_tl
\seq_new:N \l_egreg_fulleuclid_steps_seq

\cs_new_protected:Nn \egreg_fulleuclid:nn
 {
  \int_compare:nF { #2 = 0 }
   {
    \seq_put_right:Nx \l_egreg_fulleuclid_steps_seq
     {
      #1 &= #2 \exp_not:N \cdot
      \int_div_truncate:nn { #1 } { #2 } +
      \int_mod:nn { #1 } { #2 }
     }
    \egreg_fulleuclid:nf { #2 } { \int_mod:nn { #1 } { #2 } }
   }
 }
\cs_generate_variant:Nn \egreg_fulleuclid:nn { nf }
\ExplSyntaxOff

\begin{document}

\euclid{45}{27}

\euclid{45}{-27}

\euclid{27}{45}

\euclid{10}{0}

\euclid{0}{0}

\edef\temp{\euclid{2345}{356}}

\texttt{\meaning\temp}

\fulleuclid{356}{2345}

\end{document}

在此处输入图片描述

相关内容