如何跳出循环

如何跳出循环

我一直在尝试自动生成包含各种转换因子的阶梯表。(见表格中分数的突出)。

作为其中的一部分,我有一个相当复杂的宏来将小数转换为分数。该算法运行良好,示例输出如下所示:

在此处输入图片描述

当我尝试捕捉传统单位中的常见分数(1/12、3/4、1/60、1/3 等)时,我希望能够在达到限制后跳出循环。我已经使用FPifgt或类似程序对其进行了测试,但在 double 方面遇到了问题fi。有办法解决吗?

代码如下所示(抱歉太长):

\documentclass{article}
\usepackage{amsmath,fp}
\begin{document}
\makeatletter
\count@=1
\def\DecimalToFraction#1{
%helper macro
\FPset\zero{0}
\FPset\X{#1}

%% Set initial values
\FPadd\X{\X}{0.0000000001} % avoid overflows and divisions by zero
\FPset\Zi{\X}
\FPset\Di{1}
\FPset\Dprevious{0}
%% begin loop
\loop\ifnum\count@<13
%% numerator term
\FPtrunc\temp{\Zi}{0} 
\FPsub\temp{\Zi}{\temp}
%% inverse
\FPdiv\Znext{1}{\temp}
%% Find Dnext
\FPtrunc\IntZnext{\Znext}{0}
%% Di x Int{Zi+1}
\FPmul\temp{\Di}{\IntZnext}
\FPadd\temp{\Di}{\Dprevious}
\FPset\Dnext{\temp}
\FPround\Dnext{\Dnext}{0}

%%% Find Ni+1
\FPmul\temp{\X}{\Dnext}
\FPround\temp{\temp}{0}
\FPset\Nnext{\temp}

\FPdiv\ratio{\Nnext}{\Dnext}

\(Z_i=\Znext\to \Nnext/\Dnext =\ratio\)

\FPset{\Dprevious}{\Dnext}
\FPset{\Di}{\Dprevious}
\FPset{\Zi}{\Znext}

\advance\count@ by1
\repeat
%% end of loop

\gdef\NUM{\Nnext}
\gdef\DEN{\Dnext}

\makeatother
}

\def\Test#1{%
\DecimalToFraction{#1}
The number $#1=\frac{\NUM}{\DEN}$

}
\Test{0.375}
\end{document}

答案1

要在当前迭代后中止循环,只需将\let内部\iterate宏设置为\relax即可。如果您想跳过循环的其余部分代码,可以使用\fi\iffalse为此定义的宏(正如 Bruno 所说)。


在当前迭代结束时中止:

\documentclass{article}

\begin{document}

\newcount\mycount

\mycount=1

\loop\ifnum\mycount<13

 % Do calculation
 \typeout{Loop: \the\mycount}

 \ifnum\mycount>5
    \let\iterate\relax
 \fi
 \advance\mycount by 1\relax
\repeat

\end{document}

立即中止:

\documentclass{article}

\def\breakloop{\fi\iffalse}
\begin{document}

\newcount\mycount

\mycount=1

\loop\ifnum\mycount<13

 % Do calculation
 \typeout{Loop: \the\mycount}

 \ifnum\mycount>5
    \expandafter\breakloop
 \fi

 \typeout{ more }
 \advance\mycount by 1\relax
\repeat

\end{document}

解释:

\loop首先让我们看一下和的(LaTeX)定义\repeat

\loop:
\long macro:#1\repeat ->\def \iterate {#1\relax \expandafter \iterate \fi }\iterate \let \iterate \relax . 

\repeat:
\fi. 

如您所见,\loop它将所有内容存储在它和调用自身的中间\repeat\iterate此递归实现了循环。确保不会累积\expandafter任何悬空\fi。只要循环\if...为真,就会执行文本,然后\iterate再次调用\fi如果条件为假,则\fi跳过直到的所有内容,包括\expandafter。但是,如果\iterate更改为,则\relax递归将独立于条件停止。因为这发生在之后,因此\fi不需要进行清理。

生成\breakloop一个\fi\iffalse\fi关闭循环条件,并使\iffalseTeX 跳过所有内容直到最后,\fi就像循环条件一样。


如果你需要在循环中使用 FP 条件,你必须先让它们“跳过保存”。问题是 FP 将自己的if开关定义为当 TeX 跳过错误的路径。要修复此问题,请定义如下宏

\def\xFPiflt#1#2{%
  \FPiflt{#1}{#2}%
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}

然后使用\xFPiflt\x\y{<true>}{<false>}而不是\FPiflt\x\y <true> \else <false> \fi

答案2

循环具有以下结构

\loop
...
\if...
...
\repeat

如果您在\if和之间\repeat,您可以发出 来\fi\iffalse关闭当前\if并跳过所有文本直到\repeat(或者更确切地说,直到\fi产生的\loop...\repeat)。如果您的循环是 ,这将不起作用\loop...\if...\else...\repeat

更强大的解决方案是将其放置\@gobble\mysentinel在之前\repeat,然后使用以下宏退出循环:

\def\Iwanttobreakfree#1\mysentinel{\iffalse}

这将丢弃所有标记,直到\mysentinel,包括\@gobble,并且\iffalse确保循环停止。

相关内容