关系符号

数学中最常用的关系符号是有作者的,而且他把理由也写了下来。1557 年,罗伯特·雷科德在《The Whetstone of Witte》里第一次把 = 排进铅字,他选择两条平行线的理由是:再没有两样东西能比它们更相等。在 LaTeX 中,这个记号是一族之长:=\neq\leq\approx\equiv 都是关系符,而真正起作用的与其说是字形,不如说是它们所属的类别。TeX 把它们归入同一个类,统一给出比二元运算符更宽的间距。本页沿着一条线索走完这一族——等号及其近亲、大小记号、否定写法,以及如何把自己的符号提升为关系符——那条线索是:含义由惯例决定,间距却是在源码里声明出来的,而这份声明你可以自己写。

为什么 = 两侧比 + 空得更宽

因为 TeX 是按类别而不是按字形来决定间距的。公式里的每个符号都属于某一类——普通符号、二元运算符、关系符、开括号、闭括号、标点、内部——相邻两者之间的空白,是从一张「类别配对表」里查出来的。像 + 这样的二元运算符两侧填入 \medmuskip,plain TeX 的默认值是 4mu plus 2mu minus 4mu;像 = 这样的关系符则填入 \thickmuskip,默认值是 5mu plus 5mu。也就是说,等号本来就更宽,而且与加号不同,它还留有在需要撑行时伸展的余地。这一切都不需要你手动输入:即使写成一个空格都没有的 a+b=c,排出来的间距依然是对的。

要证明起作用的是类别而不是字形,最干净的例子是一对画出完全相同字符的命令。在 LaTeX 声明数学符号的 fontmath.ltx 里,| 写作 \DeclareMathDelimiter{|}{\mathord}…{symbols}{"6A},而 \mid 写作 \DeclareMathSymbol{\mid}{\mathrel}{symbols}{"6A}——同一套字体的同一个槽位 "6A,区别只在于一个被声明为普通符号、另一个被声明为关系符。把 a | ba \mid b 并排排出来,就会看到同一根竖线周围的空白不同。\|\parallel 也是同样的一对,都在槽位 "6B\parallel(∥)是关系符,可以陈述「平行于」;而 \| 是普通符号性质的定界符,用于 \|x\| 这样的范数。在这类成对的符号里选错,正是「间距总觉得不对却说不出哪里不对」的最常见原因。

latex
% same glyph, different class: | is ordinary, \mid is a relation
\[ a | b \qquad a \mid b \]
% a bare letter is ordinary; \mathrel promotes it
\[ A R B \qquad A \mathrel{R} B \]
% the colon trap: ":" is a relation, \colon is punctuation
\[ f : A \to B \qquad f\colon A \to B \]

所以实用的做法是:自己声明类别。\mathrel{...} 把内容变成关系符,\mathbin{...} 把内容变成二元运算符,二者都是标准 LaTeX 命令。裸写的字母属于普通符号,所以 A R B 会让 R 紧贴两侧;写成 A \mathrel{R} B,它就获得了与 = 相同的间距。反方向的陷阱是冒号。LaTeX 把字符 : 声明为关系符,于是 f : A \to B 会在一个本质上只是标点的冒号两侧塞进关系符的宽间距。\colon 正是为此被声明为 \mathpunct,这也是 f\colon A \to B 成为推荐写法的原因。顺带一提,箭头同样属于关系符类——\to 之所以必须待在数学模式里就是这个缘故——不过它有自己的专页。

\approx\sim\simeq\cong 该用哪一个

一个够用的准则:数值上几乎相等用 \approx(≈),等价关系或「同一数量级」用 \sim(∼),渐近相等与同胚用 \simeq(≃),几何上的全等与代数上的同构用 \cong(≅)。四者都是标准 LaTeX,无需任何宏包。它们长得像并非巧合——每一个都是把等号的严格程度松开了不同的幅度——也正因如此,读者靠的是命令名而不是字形。围绕在它们旁边的还有:表示恒等以及整数同余 a \equiv b \pmod n\equiv(≡)、表示成比例的 \propto(∝)、表示「量级相当」的 \asymp(≍),以及 \doteq(≐)——它的 Unicode 名称是「approaches the limit(趋于极限)」,但不少作者把它读作「按定义等于」。由于 \doteq\asymp 在不同领域读法不一,第一次用到时最好交代清楚。

命令字形意义/用途
==等号;直接输入——属关系符类
\neq不等于;\ne 相同——标准 LaTeX
\equiv恒等相等;同余 a \equiv b \pmod n
\approx约等于;数值近似 \pi \approx 3.14
\sim等价关系,或「同一数量级」
\simeq渐近相等;同胚
\cong全等;同构——由 \sim 叠在 = 上拼成
\propto成正比于
\asymp量级相当(分析、数论)
\doteq= 上加一点;「趋于极限」或「按定义等于」

刚才列出的符号里,有三个在任何字体中都不存在。打开 fontmath.ltx 就会看到:\cong 其实是 \mathrel{\mathpalette\@vereq\sim},即把 \sim 叠在 = 上;\doteq\buildrel\textstyle.\over=,把一个句点架在等号上方;\notin 则是在 \in 上重叠打印一道斜线。高德纳的 Computer Modern 里根本没有这几个字形,于是 LaTeX 在排版时现场拼装。这个小知识很有实用价值:拼装出来的符号在更换数学字体时位置会略微移动,而且它们在 PDF 里并不是真正的字符,无法通过复制粘贴取出。如果你在意无障碍阅读或读者要摘录文字,就用 LuaLaTeX 或 XeLaTeX 配合 unicode-math 与 OpenType 数学字体——\cong 会变成真正的 U+2245,\doteq 会变成 U+2250。

\leq\leqslant:≤ 该用哪种字形

两者含义完全相同,区别只在于版式风格,而 \leqslant 要额外付出一个宏包的代价。\leq(≤)与 \geq(≥)属标准 LaTeX,短别名 \le\ge 指向的是同一个字符。\leqslant(⩽)与 \geqslant(⩾)由 amssymb 提供,把下方那一横画成倾斜的,使它与上方的夹角平行。Unicode 并没有把它们当作「同一字符的两种字体」,而是给了各自的码位——U+2264 less-than or equal to 与 U+2A7D less-than or slanted equal to——可见这份偏好是一项真实存在的惯例,而非一时兴起。因此请为整份文档一次性定下来:同一页里 ≤ 与 ⩽ 混用,在读者眼中不过是排错了字。

表示「远小于」「远大于」的是 \ll(≪)与 \gg(≫),同样是标准 LaTeX。它们各自都是一个整体符号,而不是两个 < 拼出来的,所以别动手去凑。<> 可以直接输入,但只能在数学模式里。若在正文中以默认的 OT1 字体编码写 A<B>C,排出来的会是 A¡B¿C——因为在 OT1 里,这两个位置上放的是倒感叹号和倒问号。若你要表达的顺序不是数值大小——偏序、优先级、加细——惯例上用 prec/succ 一族:\prec(≺)、\succ(≻)以及带等号的 \preceq(⪯)、\succeq(⪰),全部属于标准命令。最后,如果已经决定采用倾斜的不等号,不必逐处改写:在导言区写一行 \let\leq\leqslant,整份文档随即切换,而源码依然清爽可读。

命令字形意义/用途
<<小于;在数学模式中直接输入
>>大于;写在正文里会变成 ¿
\leq小于等于;\le 是同一字符——标准 LaTeX
\geq大于等于;\ge 是同一字符——标准 LaTeX
\ll远小于;单个符号
\gg远大于;单个符号
\leqslant≤ 的倾斜变体——需要 amssymb
\geqslant≥ 的倾斜变体——需要 amssymb
\prec先于;用于非数值大小的顺序
\preceq先于或等于;\succ ≻ 与 \succeq ⪰ 是其镜像
latex
\usepackage{amssymb}   % \leqslant, \geqslant, \nleq, \nmid ...
% decide the shape once, in the preamble
\let\leq\leqslant
\let\geq\geqslant
\[ 0 \leq x \leq 1, \qquad n \ll N, \qquad a \prec b \preceq c \]

否定怎么写:\neq\not 与 amssymb

有专用命令就用专用命令——\neq\notin,以及 amssymb\nleq\nmid\nsubseteq 一族——只有在没有专用命令时才退回 \not。不过这里有个意外:在标准 LaTeX 中,\neq 根本不是一个独立字形。fontmath.ltx 里写着 \DeclareRobustCommand\neq{\not=}\ne 的定义与之相同,因此 \not=\neq 的输出连一个字节都不差。所以「宁用 \neq 而不用 \not=」这条老建议,谈的是源码而不是 PDF:\neq 表明了意图,能被搜索命中,也是合作者预期看到的写法。它在迁移到 unicode-math 时也表现更好——在那里 \ne 会变成真正的字符 U+2260,而不是叠印出来的形状。

\not 真正失手的地方,是那些它从未被适配过的符号。它本身是一个字符——符号字体的槽位 "36——以固定的大小、斜度和位置压在后随符号之上,而这套尺寸是按照与 = 差不多宽的记号调校的。遇到较宽的关系符,斜杠就划不到头;遇到较高或形状特别的符号,又会从错误的部位穿过。把 \not\leq\nleq(≰)、\not\subseteq\nsubseteq(⊈)并排一看,专门绘制的 AMS 字形每次都胜出。不过对于没人画过的组合,\not 依然真正有用:并不存在 \nequiv,所以表示不同余的标准写法就是 x \not\equiv y \pmod p。另外要注意,\notin(∉)看着像 AMS 符号,其实完全不需要宏包。

命令字形意义/所需宏包
\neq不等于;标准 LaTeX(其实展开为 \not=
\notin不属于;标准 LaTeX(在 \in 上重叠打印斜线)
\nleq不小于等于;amssymb
\ngeq不大于等于;amssymb
\nsim不相似;amssymb
\ncong不全等/不同构;amssymb
\nsubseteq不是子集;amssymb
\nparallel不平行;amssymb
\nmid不整除;amssymb
\nprec不先于;amssymb

:= 排好,并定义自己的关系符

表示「按定义等于」时,请加载 mathtools 并使用 \coloneqq(≔),而不要直接敲 :=。直接输入的问题不在间距:LaTeX 把 : 声明为关系符,而 TeX 在相邻的两个关系符之间不插入任何空白,所以 := 排出来本就是紧挨着的。问题出在高度上。字符 : 取自正文字体,两点的位置偏低,而 = 跨在数学轴线上,于是冒号看上去像滑下去了。mathtools 提供了抬高冒号的 \coloneqq、左右镜像的 \eqqcolon(=:),以及把文档中所有冒号统一抬高的 centercolon 选项。要注意 \coloneqq 来自 mathtools 而非 amssymb——当 ! Undefined control sequence 指向 \coloneqq 时,多半就是弄混了这一点。

要在关系符上方加东西,经典写法是 \stackrel{\mathrm{def}}{=}latex.ltx 把它定义为 \mathrel{\mathop{#2}\limits^{#1}},所以无论叠上什么,结果一定是关系符。amsmath\overset 做同样的事,但它不强制变成关系符,而是保留底座符号原本的类别——当底座是二元运算符时,你要的正是它(下方则用 \underset)。至于任何用到两次以上的符号,正确做法是只定义一次,让类别跟着它走:写下 \newcommand{\divides}{\mathrel{|}},你就得到一个间距永远正确的整除记号;日后想改字形,所有出现之处都会跟着变。这一整页其实可以浓缩成一句话——不要在使用处用 \,\; 去补间距,声明类别,把算术交给 TeX。

latex
\usepackage{mathtools}  % \coloneqq and \eqqcolon (loads amsmath too)
\newcommand{\divides}{\mathrel{|}}
\[ f(x) \coloneqq x^2 + 1, \qquad y \eqqcolon g(t) \]
% \stackrel always yields a relation; \overset keeps the base class
\[ a \stackrel{\mathrm{def}}{=} b, \qquad a \overset{\mathrm{def}}{=} b \]
\[ 2 \divides 10, \qquad x \not\equiv y \pmod{p} \]