![为什么 \dimexpr 会吞掉 \relax?](https://linux22.com/image/237833/%E4%B8%BA%E4%BB%80%E4%B9%88%20%5Cdimexpr%20%E4%BC%9A%E5%90%9E%E6%8E%89%20%5Crelax%EF%BC%9F.png)
遵循以下评论在 LaTeX 源代码中使用距离值进行数学运算:
+1 教我
\dimexpr
可以选择吞掉\relax
。昨天我尝试使用 来\relax
作为 的分隔符\numexpr
,但我不明白为什么\relax
消失了,尽管它不可扩展。– Hendrik Vogt 2 月 18 日 9:32@Hendrik:是的,我认为你需要两个
\relax
。我发现\relax
吞咽非常有用。它的朋友也喜欢\numexpr
这样做。 – Martin Scharrer♦ 2 月 18 日 9:36
这个问题在 Joseph 和 Martin 的回答中再次被提及维度还是宏观,哪个更好?,我问自己为什么 Etex 会这样做?我发现它不直观,我不明白它如何有助于避免执行无操作命令。
答案1
除了亨德里克所说的,我认为总体观点是\numexpr
,\dimexpr
ETC。可以在完全扩展上下文中使用,不会留下任何残缺\relax
或空格:
\edef\example{\the\dimexpr 10 pt + 20 pt \relax}
给出\example
定义为,30pt
没有意外标记。这在很多方面都比保留原位的替代方案“简洁”得多\relax
。同样的论点不适用于 TeX 的寄存器设置,因为它永远不可扩展,所以不会出现问题。
(当然,要得到明确的答案,您需要询问实际编写此代码的 NTS 团队成员。)
答案2
我想说,这使得\dimexpr
以完全可扩展的方式划分 a 变得很容易。放置 a\relax
是划分 TeX 维度的常用方法,这是我通过痛苦经历学到的\relax
:在之类的后面加上 a 总是一个好主意\hskip1pt
。现在看来 eTeX 只是从中得出了一个原则。
(另一种方法是空间来界定 TeX 维度,但首先,空格\relax
更明显,其次,有时不太容易添加空格,即在控制序列之后。正如 Bruno 在他的评论中指出的那样,空格不能用于划分\dimexpr
和朋友。)
答案3
原因与 TeX 吞掉数字末尾的空格相同。在 TeX 的情况下,这是为了干净地停止数字,并确保在所有情况下它都会终止,而不会进一步扩展任何内容或插入空格。事实上,TeX 可能出于同样的原因跳过控制字(多字母控制序列)后的空格(尽管这发生在不同的处理阶段)。这个想法是应该始终能够“停止而不插入任何内容”。
示例:\ifdigit
下面测试参数是否为数字。后面的空格#1
是为了防止 TeX\expandafter
过早扩展第一个数字。另一方面,我们不希望空格出现在输出中。所以至少在这种情况下,TeX 的空格吞噬是一个功能。
\long\def\ifdigit#1{%
\ifnum 9<1\string #1 %
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi}
eTeX 的设计者可以决定用空格来停止\numexpr
或,因为他们只是使用 TeX 的程序来读取操作数。这些程序已经删除了尾随空格。eTeX 看不到之前\dimexpr
的空格。从技术上讲,可以用+
\numexpr 1 + 2
\numexpr
二连续使用空格标记,并吞噬它们,但这将非常难以输入,因为连续两个空格字符相当于一个。必须选择其他分隔符。它必须是不可扩展的,最好是语言中已经存在的,并且在某种情况之外使用时最好什么也不做\...expr
……无需添加新的原语:\relax
是一个自然的选择。
现在考虑\compareint
如下定义的函数
\long\def\compareint#1#2#3{%
\ifnum\numexpr#1\relax#2\numexpr#3\relax
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi}
\compareint{1+2}<{3-1}{Yes}{No}
在这个特殊情况下,遗留\relax
不会成为问题。但是,想想嵌套这个:
\def\X{345}\def\Y{534}
\compareint {132} < {\compareint{12}>{9}{\X}{\Y}+1} {Yes} {No}
如果\relax
不从内部移除,它会过早地\compareint
停止外部的扩展(实际上,在扩展到或之前,所以这将是一个问题)。\compareint
\X
\Y
答案4
实际上,e-TeX 手册中的文档已经用一个说明性的例子回答了这个问题,令人惊讶的是,这里的答案中没有提到这个例子。那里给出的例子是:
\ifdim\dimexpr (2pt-5pt)*\numexpr 3-3*13/5\relax + 34pt/2<\wd20
相当于\ifdim 32pt < \wd20
。在这种情况下,内部\numexpr 3-3*13/5\relax
扩展为-5
(注意舍入),因此外部\dimexpr
变得相当于(-3pt) * (-5) + 17pt
。如果\relax
没有吞掉 ,而是留在输入流中,那么外部\dimexpr
也会在 处终止\relax
,从而导致错误。
为了完整起见,复制语法文档此处,稍微重新格式化:
e-TeX 引入了数字、dimen、glue 或 muglue 类型的表达式概念,可用于需要该类型数量时。此类表达式由 e-TeX 的扫描机制进行评估;
他们是发起通过命令
\numexpr
、\dimexpr
、\glueexpr
或之一\muexpr
(确定类型吨)以及可选的终止一个\relax
(将被扫描机制吸收)。一个表达:由一个或多个要加或减的相同类型的项组成;
A学期类型吨:由一个因素该类型,可选地乘以和/或除以数字因素; 最后
A因素类型吨: 是括号内的子表达式,或者是该类型的数量(数字等)。
因此,条件
\ifdim\dimexpr (2pt-5pt)*\numexpr 3-3*13/5\relax + 34pt/2<\wd20
当且仅当盒子 20 的宽度超过 时才为真
32 pt
。注意使用
\relax
来终止内部(数字)表达式,外部(dimen)表达式会由<
不适合表达式语法的标记 ₁₂ 自动终止。
然后还有几段关于算术(例如四舍五入)及其扩展的段落。