求和、积分与大型算子

1675 年 10 月 29 日,莱布尼茨在手稿里写下了 ∫。那是把 summa(和)的首字母 s 纵向拉长而成的长 s,这个形状至今仍在诉说:积分号本来就是「求和」的记号。求和号 Σ 则出自欧拉,见于其 1755 年《Institutiones calculi differentialis》第一章。然而在 LaTeX 里,这对兄弟般的符号行为迥异——在陈列公式中,\sum 把范围堆在上下,\int 却把它放在旁边。而且这种不对称就写在 \int 的定义里。本页讨论 \sum\prod\int\oint\bigcup 等大型运算符:限界如何附着、如何用 \limits\nolimits 控制位置、如何用 \substack 写多行条件,以及如何用 \DeclareMathOperator 定义自己的运算符。

什么是大型运算符——「限界」不是普通下标

大型运算符,就是被 TeX 归入 \mathop的符号。\sum\prod\int\bigcup 都属于此类,它们因此具有两个性质。其一,符号会根据周围的样式在大字形和小字形之间切换。其二,附加在它上面的下标 _ 和上标 ^ 不作为普通角标处理,而是作为限界x_i 中的 i 只是放在字母右下方;而 \sum_{k=0}^{n} 中的 k=0n 则可能被堆在符号的正下方和正上方。究竟是哪一种,取决于样式和符号的种类——这正是接下来几节的主题。

核心符号内建于标准 LaTeX(其实是底层的 TeX)之中,无需额外宏包。多重积分 \iint\iiint,构造多行下标的 \substack,以及定义运算符的 \DeclareMathOperator,则都需要 amsmath 宏包。既然 amsmath 已是事实标准,认真排版数学时把 \usepackage{amsmath} 放进导言区就是最省事的做法。

\sum\prod——范围放上下,还是放旁边

陈列公式中放上下,正文中放旁边。求和是 \sum,乘积是 \prod,余积是 \coprod,范围用下标 _ 和上标 ^ 给出。把 \sum_{k=0}^{n} a_k 放进 \[ … \],Σ 会排得很大,k=0 在其正下方,n 在其正上方。把同一个式子用 $ … $ 嵌进正文,Σ 会缩小,k=0n 则上下排在它的右侧。量一量盒子,差别一目了然:陈列版宽 14.54521pt、高 16.51393pt、深 13.02782pt,是竖长的;行内版宽 25.6008pt、高 8.04175pt、深 3.00005pt,是横长的。竖着长就是上下,横着长就是旁边。

latex
% displayed: limits stack above and below
\[
  \sum_{k=0}^{n} a_k = a_0 + a_1 + \dots + a_n,
  \qquad \prod_{k=1}^{n} k = n!
\]

% inline: the same sum keeps its limits at the side
The series $\sum_{k=0}^{n} a_k$ fits inside the line.

这种「上下」与「旁边」的切换是与样式联动的默认行为。求和、乘积、余积一类所谓 sum 类符号,只在陈列样式下把限界堆在上下,在文本样式下则放到旁边;amsmath 把这套方案称为 displaylimits。这是个考虑周到的默认值,避免无谓地撑开行距。若范围只有一端,写一端即可;也可以把条件放在下限,例如 \sum_{i \in S}。需要注意的是:只要内容超过一个记号,就必须用 { } 括起来。写成 \sum_k=1,就只有 k 变成下标,=1 会溢到符号右边。

把条件写在积分号上下——\int 为何等于 \intop\nolimits

积分号 \int 即使在陈列公式中也把限界放在旁边。这个与求和不同的行为并非偶然,而是直接写进了定义。LaTeX 的 fontmath.ltx 第 253–254 行是这样的:\DeclareMathSymbol{\intop}{\mathop}{largesymbols}{"52},紧接着 \DeclareRobustCommand\int{\intop\nolimits}。换句话说,\int 就是积分字形 \intop 贴上了一个 \nolimits——数学惯例被烧进了命令本身。第 260–261 行的 \oint 结构相同,是 \ointop\nolimits。反过来说,这也给了一个出口:直接使用光秃的字形 \intop\ointop,就回到了 sum 类的默认行为。实测也印证:陈列中的 \int_0^1 宽 14.48615pt、高 15.65013pt,而 \intop_0^1 宽 10.00002pt、高 21.12231pt、深 15.789pt——一个向横里铺开,一个向纵向伸展。

latex
\[
  \int_{0}^{\infty} e^{-x}\,dx = 1,
  \qquad \oint_{C} \mathbf{F}\cdot d\mathbf{r},
  \qquad \intop_{0}^{1} x^2\,dx
\]

多重积分也可以写成 \int\int 并排,但符号之间的间距会显得松垮。amsmath 提供了收紧间距的专用命令:二重 \iint、三重 \iiint、四重 \iiiint,以及在两个积分号之间打点的 \idotsint(∫⋯∫)。收紧的幅度是可以量出来的——在陈列公式中,\int\int 宽 21.66666pt,\iint 宽 16.66678pt,正好收紧 5pt,也就是 10pt 排版下的半个 em。实测 \iiint 为 23.33354pt,\iiiint 为 30.0003pt,\idotsint 为 34.9999pt。如果需要物理中常见的闭曲面、闭体积积分号,esint 宏包会补上 \oiint(闭曲面)、\varoiint\sqint\sqiint\ointclockwise\ointctrclockwise\fint 等。\oiiint 并不在其中——需要三重闭积分时得另找字体类宏包。原生 LaTeX 只提供 \oint

latex
% preamble: \usepackage{amsmath}
\[
  \iint_{D} f(x,y)\,dx\,dy,
  \qquad \iiint_{V} f\,dV,
  \qquad \iiiint f, \qquad \idotsint_{A} f\,dV
\]

\limits\nolimits——强制指定位置的两个命令

要覆盖默认行为,就在运算符后面写 \limits(强制上下)或 \nolimits(强制旁边)。想让正文中的求和把范围堆在上下,写 \sum\limits_{k=1}^{n};反过来,想把条件写在陈列积分的上下,写 \int\limits_0^1。如上一节所示,后者与光秃的 \intop 结果相同:实测两者都是宽 10.00002pt、高 21.12231pt、深 15.789pt。要恢复与样式联动的默认行为,请使用 \displaylimits

latex
% force limits above and below inside running text
The partial sum $\sum\limits_{k=1}^{n} k$ sits in the line.

% force limits above and below on a displayed integral
\[
  \int\limits_{0}^{1} x^2\,dx = \frac{1}{3}
\]

位置是有规则的。\limits 必须紧跟一个 \mathop,否则就会以 ! Limit controls must follow a math operator. 中断(TeX 还会补一句 I'm ignoring this misplaced \limits or \nolimits command.)。例如 x\limits^2\frac{1}{2}\limits 都会触发它。不过有一种常见的说法是「写在角标后面就会报错」,这是不对的\sum_{k=1}\limits^{n} 能顺利通过,实测得到的盒子与 \sum\limits_{k=1}^{n} 完全相同:宽 14.54521pt、高 16.51393pt、深 13.02782pt。因为紧邻其前的仍然是那个运算符原子。话虽如此,写在运算符正后方对读者和自己都更清楚,请养成这个习惯。另外,当 \limits\nolimits\displaylimits 连着出现时,最后一个说了算\sum\limits\nolimits_{k=1}^{n} 落在旁边,\sum\nolimits\limits_{k=1}^{n} 则落在上下。不过这条规则有一个例外:在 \log\lim 这类函数名之后,只要载入了 amsmath,\limits 就会被悄悄忽略——amsopn.sty\@ifnextchar\limits{\nolimits\@gobble} 把它吃掉了,既不报错也不警告。实测:不载入 amsmath 时 \log\limits_{k}x 的深度是 9.4722pt,载入后仍是 2.44443pt,与 \log_{k}x 完全一样。想把下标放到函数名下方,请改用 \DeclareMathOperator*

若想在整篇文档层面改变方针,可以不用每次都写命令,而使用 amsmath 的宏包选项amsmath.sty 第 46–49 行声明了 intlimitsnointlimitssumlimitsnosumlimits,第 92–93 行的 \ExecuteOptions 把默认设为 nointlimits, sumlimits——正是前面描述的行为。写 \usepackage[intlimits]{amsmath},文档中所有陈列积分都会把限界堆在上下。实际试验:此时陈列中的 \int_0^1 量得宽 10.00002pt、高 21.12231pt、深 15.789pt,与 \intop_0^1 一致。反过来传入 nosumlimits,求和号的限界就会移到旁边。在逐个公式撒 \limits 之前,值得先把它当作全文档层面的决定来考虑。

符号 / 命令陈列样式行内样式
\sum, \prod, \bigcup堆在上下放在右侧
\int, \oint, \iint放在右侧(定义里内建了 \nolimits放在右侧
\intop, \ointop堆在上下(未附 \nolimits 的光秃字形)放在右侧
\limits强制上下;放在运算符正后方强制上下
\nolimits强制放在旁边;放在运算符正后方强制放在旁边
\displaylimits恢复与样式联动的默认(堆在上下)恢复与样式联动的默认(放在右侧)

\lim 一族——用正体排版,条件写在下面

\lim(极限)、\limsup(上极限)、\liminf(下极限)与函数名一样,都以正体(罗马体)排版,但它们的角标遵循 sum 类的规则:陈列公式中下标落在正下方,行内则落在右下方。\limsup\liminf 会排成「lim sup」「lim inf」两个词,中间留有恰当的空隙。\sup\inf\max\min 属于同一族,也把下标放在下面(函数名清单另见「数学模式基础」页)。箭头 → 是 \to,无穷大是 \infty

latex
\[
  \lim_{n \to \infty} \frac{1}{n} = 0,
  \qquad \limsup_{n \to \infty} a_n \ge \liminf_{n \to \infty} a_n,
  \qquad \sup_{x \in X} f(x)
\]

\bigcup 系的 n 元运算符——给二元运算符加个 big

集合论、逻辑与代数中使用的 n 元运算符,也和 \sum 一样有排得较大的版本。命名很机械:取对应二元运算符的名字,前面加上 big。对应二元并集 \cup(A ∪ B)的可变大小版本就是 \bigcup。它们全都属于 sum 类,因此在陈列公式中把限界堆在上下,在正文中放到旁边。实测中,陈列的 \bigcup_{i=1}^{n} 宽 12.95433pt、高 16.51393pt、深 12.79865pt,与 \sum 几乎是同样竖长的盒子。

命令含义对应的二元运算符
\bigcup并集(n 元)\cup (∪)
\bigcap交集(n 元)\cap (∩)
\bigsqcup无交并(直和)\sqcup (⊔)
\biguplus多重集合并\uplus (⊎)
\bigvee逻辑或 / 上确界\vee (∨)
\bigwedge逻辑与 / 下确界\wedge (∧)
\bigoplus直和(带圈加号)\oplus (⊕)
\bigotimes张量积(带圈乘号)\otimes (⊗)
\bigodot带圈点(n 元)\odot (⊙)
latex
\[
  \bigcup_{i=1}^{n} A_i, \qquad
  \bigcap_{i \in I} A_i, \qquad
  V = \bigoplus_{k} V_k
\]

在求和号下写两行条件——\substacksubarray

amsmath 的 \substack{…} 整个放在下标位置即可。由 \\ 分隔的每一行会居中纵向堆叠,于是可以把「0 ≤ i ≤ m」和「0 < j < n」分两行排在 Σ 的正下方。最后一行后面不要加 \\。若想左对齐,请使用更通用的 subarray 环境:\begin{subarray}{l} … \end{subarray}{l} 表示左对齐,{c} 表示居中,换行同样用 \\。事实上 \substack 的定义就是 \subarray{c}…\endsubarray,两者不过是同一套机制的不同面孔。另外,在符号上方或下方架设括号与横线的 \overbrace\underbrace\overline 是另一个话题,由另一页「上下装饰」负责。这里讨论的始终是运算符的限界

latex
% preamble: \usepackage{amsmath}
\[
  \sum_{\substack{0 \le i \le m \\ 0 < j < n}} P(i,j)
  \qquad
  \sum_{\begin{subarray}{l} i \in \Lambda \\ 0 < j < n \end{subarray}} P(i,j)
\]

自己定义 argmax——\DeclareMathOperator* 里的星号是什么意思

有没有星号,决定条件是放在正下方还是右下方。当你需要一个标准清单之外的运算符名——argmaxargminesssup 等——要求以正体排版,并像 \lim 那样把下标放在正下方时,就用 amsmath 的 \DeclareMathOperator* 在导言区声明一次,正文中当作简短命令调用。不加星号,下标就落在名字的右下方。实测印证了这一点:\operatorname*{argmax}_{\theta} 的盒子深 9.4722pt(向下延伸),而不带星号的 \operatorname{argmax}_{\theta} 宽 37.05215pt、深仅 2.44443pt(改为向右延伸)。若只用一次,也可以不声明而直接写 \operatorname{rank}(要把限界放在下方则写 \operatorname*{…})。

latex
% in the preamble:
\usepackage{amsmath}
\DeclareMathOperator*{\argmax}{arg\,max}
\DeclareMathOperator{\rank}{rank}

% in the body:
\[
  \hat{\theta} = \argmax_{\theta} L(\theta),
  \qquad \rank A \le n,
  \qquad \sideset{}{'}\sum_{n} a_n
\]

名字文本有专门的约定:连字符 - 会排成正文中的连字符(而非减号),星号 * 会排成升起的文本星号(而非居中的二元星号)。arg\,max 中的 \, 是分隔两个词的细空格。函数名应当用 \DeclareMathOperator\mathrm 排版,而不是 \text{…};这样前后的间距会自动调整,即使在定理环境这类斜体语境中也能保持正体。最后,若想在 sum 类符号的四角放置角标——比如给 Σ 加一个撇号(′)——可以使用 amsmath 的 \sideset。写 \sideset{}{'}\sum_{n} a_n,就能在保留下方限界的同时,在 Σ 的右上角加上撇号。第一个参数管左边两角,第二个参数管右边两角,每个参数内部写成 _{下}^{上}。请注意它只适用于 sum 类符号。