问题描述
我正在尝试按照我通常在 LaTeX
中使用 groff
的方式对齐一些相当长的方程。我要达到的一般形式:
A = B + C
= D * E
+ F * G
= H + I = J
在 LaTeX
中,我会这样做:
\documentclass[fleqn]{article}
\usepackage{amsmath}
\begin{document}
\begin{alignat*}{3}
A
& = B + C \\
& =
\begin{aligned}[t]
& D * E \\
& + F * G
\end{aligned} \\
& = H + I
&& = J
\end{alignat*}
\end{document}
在 eqn
中,方程对齐是通过 mark 和 lineup 命令完成的。引用 typesetting Mathematics 2nd Ed(找到 here)中的 Kernighan 和 Cherry 来说明它们是如何工作的:
mark 这个词可以在等式中的任何地方出现一次。它记住它出现的水平位置。连续方程可以包含一个词lineup。 lineup 出现的地方尽可能与前面mark标记的地方对齐。
在阅读本文时,我的印象是系统不会禁止将 lineup 与前一个标记对齐以及在同一行内设置新的 标记等式的,例如我希望以下内容:
.PP
.EQ I
A mark =
B + C
.EN
.EQ I
lineup = mark
D * E
.EN
.EQ I
lineup + F * G
.EN
产生这样的东西:
A = B + C
= D * E
+ F * G
然而,事实并非如此。 eqn
将加号与等号对齐:
A = B + C
= D * E
+ F * G
并产生警告:
eqn:test.ms:10: multiple marks and lineups
eqn $1 -Tpdf | groff -ms -Tpdf > ${1/%.ms/.pdf}
我想知道是否有一些宏可以让我存储多个水平偏移(或如何定义一个)。对 mark 和 lineup 宏究竟是如何工作的进行一些说明也会有所帮助。
解决方法
非常令人失望的是,eqn
不允许设置新标记。这是一个可能有用的糟糕解决方法。它包括重复第一个方程,但在新位置使用关键字 mark
,并将输出转移到任何地方,因此它不会出现。 .di
是开始和结束转移的基本 troff。
.EQ I
A mark = B + C
.EN
.EQ I
lineup = D * E
.EN
.di mydump
.EQ I
A = mark B + C
.EN
.di
.EQ I
lineup + F * G
.EN
注意,您还可以使用 fwd 99
等 eqn 命令向右移动 99/100 em,其中 em 大约是字符“m”的宽度。
这是在与 mark
相同的行上有第二个 lineup
的可能解决方案。它使用基本 troff 序列 \k
将当前水平位置标记到寄存器 myposn
中。然后有一个 eqn 宏 mylineup
,它调用 eqn special
命令来运行 troff define MyLineup
,它“返回”一个具有 myposn
单位水平移动的字符。在调用 eqn 之前,使用调用后的字设置一些寄存器,并期望它们被更新为此时所需的任何输出。我们不使用这个虚拟词,它可以是任何东西,但不能省略。例如,
.de MyLineup
. ds 0s "\h'\\n[myposn]u'
. nr 0w \\n[myposn]u
. nr 0h 0
. nr 0d 0
. nr 0skern 0
. nr 0skew 0
..
.EQ I
define mymark '\k[myposn]'
define mylineup 'special MyLineup'
A mark = B + C
.EN
.EQ I
lineup = mymark D * E
.EN
.EQ I
mylineup dummy + F * G
.EN
从 .de
到 ..
的行是 MyLineup
的定义。两条 define
行应该在第一个等式中。此后,可以使用 mymark
和 mylineup dummy
代替 mark
和 lineup
。原始标记和阵容不变。如有必要,可以在带有 mark
的行中再次使用真正的 mylineup
,依此类推。
将此概括为具有许多标记是复杂的。第一个问题是 mymark
只是一个 eqn 定义,不能带数字参数。它不能使用 special
命令,因为它需要内联。一个简单的解决方案就是在开始时创建大量定义:
define mymark1 '\k[myposn1]'
define mymark2 '\k[myposn2]'
第二个问题是当 eqn 调用 MyLineup
时,它没有传递下面的参数(“dummy”,我们打算改为“1”)作为调用的参数,而是在变量 {{ 1}};该字符串也嵌入在格式化代码中,实际上(无论如何在我的测试中)0s
。所以我们需要用 \f[R]\,1\/\fP
将数字从这个子串出来。修改后的宏和测试为:
.substring 0s 7 -6
,
我可能被您的示例中的多个 .EQ
调用误导了。我假设调用和方程之间会有文本。但是,如果打算使用单行多行方程,则可以使用 matrix
(或者也可以使用 lpile
)来完成。例如,
.nr PS 20p
.nr VS 24p
.PP
.EQ
matrix {
lcol { A }
lcol { = above = above ~ above = }
lcol { B + C above D * E above + F * G above H + I }
lcol { ~ above ~ above ~ above = J }
}
.EN