带计数器的递归不重置计数器

带计数器的递归不重置计数器

我正在尝试使用递归在 TikZ 中绘制谢尔宾斯基三角形。我有一些部分可以工作,但不是完全可以。在每个步骤中,我都会画一些东西。然后,如果计数器为正,我会再次调用我的宏。

这是一个稍微简化的例子,没有 TikZ 的内容(因为我很确定这不是我的问题所在):

\documentclass{article}

\newcounter{mycounter}

\newcommand{\example}[1]{%
  \setcounter{mycounter}{#1}%
  \themycounter%
  \ifnum\themycounter>0%
    [%
    \setcounter{mycounter}{#1}%
    \addtocounter{mycounter}{-1}%
    \example\themycounter%
    ,%
    \setcounter{mycounter}{#1}%
    \addtocounter{mycounter}{-1}%
    \example\themycounter%
    ]%
  \fi%
}
    
\begin{document}

\example4

\end{document}

这是输出:

4[3[2[1[0,-1],-2],-3],3[2[1[0,-1],-2],-3]]

我想要的输出是:

4[3[2[1[0,0],1[0,0]],2[1[0,0],1[0,0]]],3[2[1[0,0],1[0,0]],2[1[0,0],1[0,0]]]]

我认为我的问题是\setcounter{mycounter}{#1}扩展为\setcounter{mycounter}{\themycounter},这导致 的值没有变化mycounter,而不是将其重置为宏开始时的值。有没有简单的解决方案?我需要学习如何\expandafter工作吗?

答案1

如果问题出在计数器上,就移除计数器!:)

\documentclass{article}

\def\sierpinski#1{\number\expandafter\sierpaux\number\numexpr#1;}
\def\sierpaux#1;{%
  \ifnum#1=0 0%
  \else
    \expandafter\sierpauxi\number
      \expandafter\sierpaux\number\numexpr#1-1;;#1%
  \fi}
\def\sierpauxi#1;#2\fi{\fi#2[#1,#1]}

\begin{document}

\sierpinski4

\edef\x{\sierpinski{19}}

\end{document}

代码是\sierpaux宏的简单递归。循环开始时,它会向下遍历数字,减一,直到找到零,此时输入流如下所示:

\number\expandafter\sierpauxi
\number\expandafter\sierpauxi
\number\expandafter\sierpauxi
\number\expandafter\sierpauxi 0;1\fi;2\fi;3\fi;4\fi

然后最后一个\sierpauxi开始起作用并被替换0;1\fi\fi1[0,0]然后\fi展开,得到:

\number\expandafter\sierpauxi
\number\expandafter\sierpauxi
\number\expandafter\sierpauxi 1[0,0];2\fi;3\fi;4\fi

然后再次\sierpauxi启动并替换1[0,0];2\fi2[1[0,0],1[0,0]]重复此过程,直到剩下输出。请注意,它只计算一次数字列表,然后使用宏扩展根据需要复制所有内容,因此这是 O(n)。

但是列表很快就会变得很大,因此参数中可以拥有的最大数字是 19。

这是一个很多较慢的版本最多允许 20 个:

\documentclass{article}

\def\sierpinski#1{\sierpauxi{#1}}
\def\sierpauxi#1{\expandafter\sierpaux\number\numexpr#1;}
\def\sierpaux#1;{%
  \ifnum#1=0 0%
  \else #1\expandafter\sierpauxii\romannumeral-`0\sierpauxi{#1-1};%
  \fi}
\def\sierpauxii#1;{[#1,#1]}

\begin{document}

\sierpinski4

\edef\x{\sierpinski{20}}

\end{document}

此版本以递归方式评估树的两侧,因此它是 O(n^2),但它会进行更多的调整,以便您可以获得更大的输入。

答案2

您的解释是正确的,但我认为在这里不使用计数器更简单,尤其是全局的乳胶计数器,并且使用\themycounter打印形式,不能保证适合数字测试。

\documentclass{article}


\newcommand{\example}[1]{%
  \the\numexpr#1\relax
  \ifnum#1>0 %
    [%
    \expandafter\example\expandafter{\the\numexpr#1-1\relax}%
    ,%
    \expandafter\example\expandafter{\the\numexpr#1-1\relax}%
   ]%
  \fi%
}
    
\begin{document}

\example4

\end{document}

这只是直接传递值#1而不使用寄存器

相关内容