为什么普通 TeX 将 \tolerance 设置为大于 \pretolerance?

为什么普通 TeX 将 \tolerance 设置为大于 \pretolerance?

TeX 将段落拆分成行时,会进行三遍。第一遍中,TeX 尝试在不使用连字符的情况下拆分段落,在此期间,它会确保没有一行的 badness(来自 glue 设置)超过\pretolerance。如果第一遍失败(即未找到断点序列),则 TeX 会在启用连字符的情况下尝试第二遍,但这次它会确保没有一行的 badness 超过\tolerance

普通 TeX 格式设置了\pretolerance=100\tolerance=200,它们被 LaTeX 继承。但是为什么 比 大得多\tolerance\pretolerance

在此设置下,TeX 将允许“非常松散”的线条,其中胶水被拉伸到其总拉伸度的约 126%(因为 200/100 的立方根是 1.2599...)启用连字功能时(在第二遍中),而 TeX 在第一遍中只允许胶水拉伸到总拉伸度的 100%。

这没有意义:连字符应该帮助打破段落更好的。启用连字后,TeX 可以选择更多可行的断点。那么,当更合理的设置似乎是保持不变时,为什么要允许“更宽松”的行呢\tolerance=100?(即,保持每行的不良程度相同的限制,但应该不是问题,因为现在 TeX 有更多断点可供选择)


以下代码(LaTeX 友好)说明了我的问题,并部分解决了@UlrikeFischer 的评论。

% There are Unicode characters in the following source.
% Use XeLaTeX or LuaLaTeX to compile.
\documentclass{article}
\begin{document}
\noindent
\vtop{\hsize=250pt \parindent=20pt
\tracingparagraphs=1
When \TeX\ breaks a paragraph into lines, it makes three passes.
In the first pass, \TeX\ tries to break the paragraph without
hyphenation, during which it makes sure that no line has a
badness (from glue setting) exceeding \verb|\pretolerance|.
If the first pass fails (i.e., no sequence of break points is
found), then \TeX\ tries the second pass with hyphenation enabled,
but this time it makes sure that no line has badness exceeding
\verb|\tolerance|.

The plain \TeX\ format sets \verb|\pretolerance=100| and
\verb|\tolerance=200|, which are inherited by \LaTeX. But
why a much larger \verb|\tolerance| than \verb|\pretolerance|?

Under this setting, \TeX\ will allow “very loose” lines where
glues are stretched to about 126\% of their total stretchability
(because the cubic root of 200/100 is 1.2599…) \emph{when
hyphenation is enabled} (in the second pass), while \TeX\ only
allows glues to stretch to 100\%\strut\vadjust{\setbox0\hbox{%
% The baseline of the top-most line in the following margin note
% coincides with the bottom edge of the \strut in the main text.
% Raising \dp\strutbox makes two baselines agree. We then add an
% offset ``-(math-axis ht of 8pt CM)+(math-axis ht of 10pt CM)'',
% so the margin note will share the same axis with the main text
% (i.e., the bars of arrows will be at the same place).
\raise\dimexpr\dp\strutbox-2pt+2.5pt\relax
\vtop{\hsize=90pt \footnotesize\noindent
$\leftarrow$ This line is very loose. The badness is $b=124$
(stretching to $\approx$107.4\%). The paragraph itself has been
hyphenated.}}\ht0=0pt \dp0=0pt \moveright255pt \box0 }
of the total stretchability in the first pass.

This doesn’t make sense: Hyphenation is supposed to \emph{help}
breaking the paragraph \emph{better}. When hyphenation is
enabled, there are much more feasible break points for \TeX\ to
choose from. So why allow the possibility of “looser” lines,
when the more sensible setting seems to be keeping the same
\verb|\tolerance=100|? (i.e., keeping the same limit on badness
of each line, but shouldn’t be a problem because now \TeX\ has
more break points to choose from)
}
\end{document}

宽容度大

答案1

提出的问题确实令人费解,但如果你反过来问,我会发现情况更清楚:不要问“为什么设置\tolerance大于\pretolerance?”,而是问“为什么设置\pretolerance小于\tolerance?”

也就是说,第二遍使用 \tolerance,是“真正的”:它解决了真正的优化问题,考虑了所有可能换行的位置(即有无连字符),\tolerance每行最多为 。连字符可能很好:它可以带来更好的换行效果:请参见示例这个答案,其中第 20 行(倒数第二行)的单个连字符能够改善第 11-19 行的范围。当然,连字符在某种程度上也是不受欢迎的,具体数量为\hyphenpenalty\doublehyphendemerits\finalhyphendemerits,你可以控制它,甚至完全关闭它其他方法。因此,通过考虑所有潜在的解决方案,第二遍能够权衡得失。

在这个“理想”的第二遍之前,为了提高效率,添加了第一遍(前连字符)因为为每个单词寻找连字符点本身就是(或曾经是)一个昂贵的操作。如果 TeX 可以找到一种不带连字符的段落拆分方法,并且每行的 badness 都小于\pretolerance,那么它甚至不会尝试对单词进行连字符处理。现在出现了一个问题:如果我们只考虑解决方案的子集(没有连字符的子集)并选择最佳解决方案,那么我们可能会错过更好的解决方案(可以使用连字符实现)。那么我们应该为 选取什么值\pretolerance

回答:我们应该选择\pretolerance一个明显低于的值\tolerance,这样,即使我们要接受无连字符子集中的最佳解决方案(如果存在的话)(因此它可能不是绝对最佳的),我们保证这将是一个相当好的解决方案。


总而言之,看待这两个数量的另一种方式是:

  • \tolerance:我只接受每行的不良程度低于此值的解决方案。

  • \pretolerance:如果每行的不良程度都低于此,我将接受最佳的无连字符解决方案。


为了完成答案,这里有一个例子,其中,使用\tolerance=200(默认值),设置\pretolerance=100(默认值)而不是\pretolerance=200(或更多)有助于解决问题:

\documentclass{article}
\usepackage{lipsum}
\begin{document}
\tracingonline=1
\tracingparagraphs=2
\message{^^J}
\message{1: global best (at \tolerance= 200):}
\pretolerance=-1
\lipsum[3]

\message{2: no-hyphenation best (at \pretolerance= 200):}
\pretolerance=200
\lipsum[3]

\message{3: no-hyphenation best (at \pretolerance= 100):}
\pretolerance=100
\lipsum[3]

\end{document}

结果(不显示第三段,与第一段相同):

结果

以下是日志文件中的相关行(我不得不查找另一个答案我的复习一下如何读取的输出\tracingparagraphs):

1 global best (at \tolerance = 200):
@@64: line 10.2- t=7657 -> @@61

2 no-hyphenation best (at \pretolerance = 200):
@firstpass
@@15: line 10.2- t=45051 -> @@14

3 no-hyphenation best (at \pretolerance = 100):
@firstpass
@@9: line 7.3 t=4590 -> @@8
@secondpass
@@64: line 10.2- t=7657 -> @@61

— 换句话说,即使全局最佳段落的总缺点为 7657,如果我们设置\pretolerance=200(或更多),我们最终会满足于一个总缺点为 45051 的段落,这要糟糕得多。设置\pretolerance=100使得没有连字符的可接受解决方案,因此将找到全局最佳段落。


当然,有时即使这样也可能还不够:将上述文件中\lipsum[3]的更改为 会出现这样的情况,即与全局最佳值 7444 相比,即使,我们最终还是接受了无连字符解决方案 16460。不过,这并不像上面的情况那么糟糕。\lipsum[2]\pretolerance=200

总体而言,从定性上来说有五种可能性,对lipsum包中的 150 个段落重复此实验会发现每种可能性至少出现一次:

  1. 最好的段落恰好是没有连字符的段落(并且同时\pretolerance=100找到\pretolerance=200它):150 个段落中有 37 个出现这种情况。

  2. 最好的段落是带有连字符的段落,但最终\pretolerance=100\pretolerance=200发现没有连字符的段落相同(略)更糟糕:150 个段落中有 38 个发生这种情况。

  3. \pretolerance=100找不到没有连字符的解决方案,但\pretolerance=200找到了一个比最佳解决方案更差的解决方案:150 个段落中有 40 个出现这种情况。这是(略微)最常见的情况。

  4. \pretolerance=100找不到无连字符解决方案,但\pretolerance=200找到了一个,与全局最佳解决方案相同:150 个段落中有 1 个出现这种情况。这是除案例 1 之外唯一一个最佳解决方案是无连字符解决方案的情况。

  5. \pretolerance=100也没有\pretolerance=200找到不带连字符的解决方案,所以我们最终选择了全局最佳解决方案:在 150 个案例中,有 34 个发生了这种情况。

在情况 1、2 和 5 中,设置\pretolerance=100200不会产生任何影响(对段落的质量而言)。在特殊情况 4 中,设置\pretolerance=100会导致一些额外的计算(第一次传递被丢弃),而会节省计算(连字符),但从质量上来说这并不重要。但情况 3(最常见的情况)表明了为什么设置小于\pretolerance=200是个好主意。\pretolerance\tolerance

答案2

第 1 步的重点是效率,而不是输出更美观的输出。通常我们可以设置段落而不必执行繁重的连字符任务。如果我们能很好地完成连字符任务(使用低的如果我们已经假设一个变量的容忍度 (pretolerance) 为真,那么也许不值得“真正地”这样做 (使用连字符) 来查看是否能得到更好的结果。

但如果没有连字符的结果不是好(虽然不是很糟糕),但通过引入连字符来尝试使其变得更好则更有动力。这并不意味着它太糟糕了,我们不应该容忍它(\tolerance),如果事实证明我们无法真正使它变得更好。

答案3

\tolerance高于,\pretolerance以便第二次传递有更高的机会成功换行。 的值\tolerance给出了 \TeX一个限制:允许使用坏度不超过此限制的行。这并不意味着文本需要此限制。

当然,使用连字符有助于\TeX换行,而且通常坏处比 少得多 \tolerance。但这是\TeX必须打破段落的两个选项之一。如果连字符没有帮助,则\TeX在第二次传递时使用第二个选项以使用更松散的行。

为什么断字并不总是成功?断字可能是因为许多短词通过连线连接在一起,或者用户决定将\uchyph=0\hyphenpenalty增加到 10000 等。对于断行而言,前几行是最关键的。例如,如果无法断掉导致第一行过满的单词,则必须拉伸单词之间的空间。如果这在第一遍中无法实现,即这是必须执行第二遍\TeX的原因,则 太小,应该具有更高的值。\TeX\pretolerance\tolerance

最后,plain \TeX这是一种通用格式,即使对于无法更改参数的新手用户,它也应该能够处理大量文本。对不良程度的容忍度较低的设置可能会产生过多的溢出行。但是,如果有人仔细校对,并愿意重新措辞当前参数设置无法破坏的文本,那么可以\tolerance降低。另一方面,仔细校对应该会发现包含不良设置的、间隔开的行的段落\tolerance=200

相关内容