分式、根式与指数

根号 √ 的钩,和横跨其上的那道横线,相隔 112 年才凑到一起。只有钩的符号 1525 年出现在克里斯托夫·鲁道夫的《Die Coss》中;把它与上方横线(vinculum)连成今天这个样子的,是 1637 年的笛卡儿。分数线更古老,可追溯到 12 世纪马格里布数学家阿尔-哈萨尔,由斐波那契带入欧洲。LaTeX 至今仍然分别拼装这些分别诞生的部件。本页从一个事实出发来梳理分数、根号与指数:\frac 的底层就是 \over。内容包括 \dfrac\tfrac\cfrac\binom\genfrac 的分工,何时该选 \nicefrac\sfrac,以及“分数变小了”“根号指数位置不对”这类实际症状的处理办法。

\frac 的真身就是 \over——差别只在有没有花括号

\fracLaTeX 内核的命令,不需要 amsmath。定义就明明白白写在 latex.ltx 第 12700 行:\DeclareRobustCommand\frac[2]{{\begingroup#1\endgroup\over#2}}。翻译过来就是:把整体用 { } 括住,把分子封进 \begingroup … \endgroup,中间放上 TeX 的原始命令 \over。因此 \frac{a+b}{c}{a+b \over c} 输出相同。在 TeX Live 2024、10pt、Computer Modern 下实测盒子尺寸,两者都是宽 24.19968pt、高 13.70952pt、深 6.85951pt,完全一致。

那么,为什么大家一直说“用 \frac,别用 \over”?差别就在花括号。\over 是原始命令,它会把当前分组内自己左边的一切都吞进去当分子。所以 {x + y \over 2} 得到的不是“x 加上 y/2”,而是 (x+y)/2;而同样意图写成的 x + \frac{y}{2} 才正确地得到 x + y/2。\frac 通过把分子作为显式参数接收,从结构上杜绝了这个事故。此外,在同一个分组里写两个 \over,TeX 无法判断先处理哪个,会以 ! Ambiguous; you need another { and }. 停下。

latex
% same shape in the source, two different formulas
\[
  {x + y \over 2} \qquad x + \frac{y}{2}
\]

% error: Ambiguous; you need another { and }.
% \[ 1 \over 2 \over 3 \]

加载 amsmath 之后,这条方针被写进了代码。amsmath.sty 先用 \@saveprimitive\over\@@over 把原始命令保存起来,再替换 \over\atop\above(以及它们的 …withdelims 版本),使用时便会发出 Package amsmath Warning: Foreign command \over; \frac or \genfrac should be used instead。接着它在第 234 行把 \frac 本身重新定义为 {{\begingroup#1\endgroup\@@over#2}}——为的是调用此前保存下来的真正的 \over。一个副作用是:旧写法 {n \choose k} 会经由 \atopwithdelims 触发同样的警告。这只是警告而非错误,输出仍会生成,但正确的做法是改用 \binom

分数为什么变小了——\dfrac\tfrac

因为 \frac 会根据自己所处的样式自动改变大小。在正文的 $ … $(文本样式)中,它被排得较小以免撑破行高;在 \[ … \](陈列样式)中,则排得宽松而大。测量同一个 \frac{a+b}{c}:陈列版宽 24.19968pt、高 13.70952pt,行内版宽 16.39322pt、高 8.79842pt,相差约一半。要关掉这个自动判断,就用 amsmath\dfrac(永远陈列大小)和 \tfrac(永远文本大小);它们的真身不过是 \genfrac 的别名——定义分别是 \genfrac{}{}{}0\genfrac{}{}{}1。实测也印证了这一点:陈列公式中的 \tfrac 与正文中的 \frac 尺寸精确到十万分之一 pt 都相同。

latex
% preamble: \usepackage{amsmath}
Small in running text: $\frac{a+b}{c}$, forced large: $\dfrac{\partial f}{\partial x}$.

\[
  \frac{a+b}{c} \qquad \tfrac{a+b}{c} \qquad \dfrac{1}{1 + \dfrac{1}{x}}
\]

一旦嵌套,问题就更紧迫了。TeX 只有陈列、文本、上标、次上标四级样式,而分数的分子分母永远比外层低一级。所以叠用 \frac 会依次缩小 display → text → script → scriptscript,并在第四级触底。实测也是如此:\frac{1}{2} 的宽度在 displaystyle 下是 7.40001pt,textstyle 下 6.38612pt,scriptstyle 下 5.80283pt,scriptscriptstyle 下同样是 5.80283pt——第三级和第四级尺寸相同,再往下也无法更小。当然,到那时早已看不清了。若想让各层保持同样大小,请改叠 \dfrac,或使用下一节的 \cfrac

  • \frac — 默认选择。希望大小自然地交给上下文时使用,不需要额外宏包。
  • \dfrac — 希望正文中的分数不被压小而保持全尺寸,或希望嵌套的每一层大小一致时使用。它会撑高行高,用得太多整页的行距就会跳动。
  • \tfrac — 希望陈列公式中的某一个分数保持小巧时使用。适合系数中的分数和上下标附近的分数。
  • \cfrac — 连分数专用。无论嵌套多少层,大小都不变。

连分数 \cfrac 与把分子靠左右的 [l] / [r]

连分数请使用 amsmath 的 \cfrac。如上一节所示,嵌套 \frac 会逐层缩小;而 \cfrac 把每一层都排成陈列大小,因此叠多少层字号都不变。amsmath.sty 第 913 行的定义把机制说得清清楚楚:\DeclareRobustCommand{\cfrac}[3][c]{{\displaystyle\frac{\strut\ifx r#1\hfill\fi#2\ifx l#1\hfill\fi}{#3}}\kern-\nulldelimiterspace}。它在内部显式声明 \displaystyle,用 \strut 让各层高度一致,并以末尾的 \kern-\nulldelimiterspace 抵消分数线右侧残留的空白。

正如定义中的 [3][c] 所示,\cfrac 的第一个参数是一个可选的对齐参数,默认为 c(居中)。\cfrac[l] 让分子左对齐,\cfrac[r] 让分子右对齐。手法很简单:若为 r,就在分子前插入一个 \hfill;若为 l,则插在分子之后。连分数越往下分母越长,分数线宽度逐层变化,想让分子在左端对齐时 [l] 就派上用场。

latex
% preamble: \usepackage{amsmath}
\[
  x = 1 + \cfrac{1}{2 + \cfrac{1}{2 + \cfrac{1}{2 + \cdots}}}
  \qquad
  \cfrac[l]{1}{2 + \cfrac[l]{1}{2 + \cfrac[l]{1}{2}}}
\]

二项系数 \binom——一条粗细为 0pt 的分数

\binom{n}{k}amsmath)把“从 n 中取 k”的二项系数排成没有横线的纵向排列,外面套一对圆括号。不画横线并不是因为它被特殊对待,而是因为它本来就是把分数线粗细设为 0pt 的分数amsmath.sty 第 240 行写着 \DeclareRobustCommand{\binom}{\genfrac()\z@{}}:一个以 () 为定界符、以 \z@(即 0pt)为线宽、样式留空(随上下文)的 \genfrac。若要固定大小,还有 \dbinom(永远陈列)和 \tbinom(永远文本),它们同样不过是 \genfrac(){0pt}0\genfrac(){0pt}1

\genfrac 是前面所有命令的共同基础,它接受六个参数:\genfrac{左定界符}{右定界符}{线宽}{样式}{分子}{分母}。第四个参数“样式”是 03 的整数,依次对应 \displaystyle\textstyle\scriptstyle\scriptscriptstyle;留空则随上下文。所以写 \genfrac[]{1pt}{0}{a}{b} 就得到一个用方括号包住、画 1pt 粗线、永远为陈列大小的分数。当标准命令给不出你要的外观时,这里就是出口。至于旧写法 {n \choose k},如前节所述会引发 amsmath 警告,请换成 \binom

latex
% preamble: \usepackage{amsmath}
\[
  \binom{n}{k} = \frac{n!}{k!\,(n-k)!}
  \qquad \dbinom{n}{k} \qquad \tbinom{n}{k}
  \qquad \genfrac[]{1pt}{0}{a}{b}
\]

\sqrt 与 n 次根——指数其实骑在 \root … \of

\sqrt{内容}LaTeX 内核 的命令,不需要 amsmath。根号与从其右上方伸出的横线(vinculum)会随内容的高度和宽度自动伸缩。n 次根通过方括号里的可选参数传入指数,写作 \sqrt[3]{x+y}。这两者是两套实现。latex.ltx 第 12701 行是 \DeclareRobustCommand\sqrt{\@ifnextchar[\@sqrt\sqrtsign}——若下一个字符是 [ 就走 \@sqrt,否则用光秃秃的字形 \sqrtsign;紧接着第 12702 行的 \def\@sqrt[#1]{\root #1\of} 把带指数的分支引向 \root … \of。指数以 \scriptscriptstyle 排版,前面留出 \mkern5mu 的空隙,并被抬高到记号高度的 0.6 倍处——鲁道夫的钩与笛卡儿的横线分别诞生这件事,至今仍留在实现里。

明白了机制,也就明白了那个经典抱怨——被开方式很高时,指数会落在一个别扭的位置。指数是按根号记号的高度成比例抬起的,所以内容越高,它就越往记号左边飘远。amsmath 为此提供了 \leftroot{n}\uproot{n},写在指数正前方,例如 \sqrt[\leftroot{2}\uproot{3}\beta]{x}。单位是 mu(数学单位,1em 的 1/18)。实测中 \sqrt[3]{x} 的盒子高 8.00272pt,加上 \uproot{10} 后伸到 12.14214pt。而 \leftroot 完全不改变宽度——amsmath.sty\r@@t 成对插入了 \mkern-\leftroot@ mu\mkern\leftroot@ mu 相互抵消,所以进给宽度不变,只有指数左右移动。只有当结果确实难看时才动手;多数情况下默认位置就够了。

latex
% \sqrt is core LaTeX; \leftroot and \uproot need amsmath
\[
  \sqrt{x^2 + y^2} \qquad \sqrt[3]{x+y} \qquad \sqrt[n]{a}
  \qquad \sqrt[\leftroot{2}\uproot{3}\beta]{\frac{a}{b}}
\]

指数(幂)与 ! Double superscript

指数用抑扬符 ^ 排成上标:x^2 就是“x 的平方”。这是内核功能,无需宏包。陷阱在于超过一个字符的指数,因为 ^ 只会取紧随其后的一个记号。x^10 会被排成“x 的一次方”后面跟着一个孤零零的 0,而且不报错,很难察觉。请务必加花括号:x^{10}。同一个底上写两个上标,例如 x^2^3,则会以 ! Double superscript. 中断,TeX 还会好心给出自己的解读:I treat x^1^2 essentially like x^1{}^2.。如果你真的想要双重指数,请嵌套写成 x^{2^3}。给同一个字母同时加上下标的做法,以及数学间距的单位,属于另一页“上下标与间距”的范围。

latex
% braces decide the scope; x^10 is x-to-the-first followed by 0
\[
  x^{10} \qquad x^{2^3} \qquad
  x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
\]

斜线分数 \nicefrac\sfrac——不撑坏正文行的分数

如果只是想在正文里说“大约 3/4 小时”,用小号斜线分数比纵向堆叠更不扰乱行。老资格是 nicefrac 宏包的 \nicefrac{a}{b},作为 units 套件的一部分自 1998 年沿用至今。较新的选择是 xfrac 宏包的 \sfrac{a}{b},它属于 LaTeX3 的 l3packages;TeX Live 2024 随附版本的日期是 2024-02-13。CTAN 对 nicefrac 的说明本身就写着:nicefrac 的功能由 xfrac 宏包以更整洁的方式提供。因此对新文档而言,\usepackage{xfrac}\sfrac 是稳妥的默认选择。

把它们量一量,差别就出来了。在正文(文本模式)中,\sfrac{3}{4} 的盒子宽 9.00314pt、深 0.13495pt,而 \nicefrac{3}{4} 宽 11.30565pt、深 2.5pt。\sfrac 会调用字体自带的真正分子分母数字,所以更窄,也几乎不跌到基线以下——正因如此它更不容易扰乱行距。不过一旦进入数学模式($ … $),两者的盒子完全相同,都是宽 11.30565pt、深 2.5pt:\sfrac 的优势体现在正文里。分工很简单——想纵向堆叠的分数用 \frac\dfrac,句子中想小巧收场的用 \sfrac(若已有文档在用则保留 \nicefrac)。

latex
% \usepackage{nicefrac}  (the older one)
It takes about \nicefrac{3}{4} of an hour.

% \usepackage{xfrac}  (recommended for new documents)
That is roughly \sfrac{1}{2} of the total, or $\sfrac{1}{2}$ in math mode.
命令所需宏包输出
\frac{a}{b}无(LaTeX 内核)带横线的分数;大小随上下文;内部就是 \over
\dfrac{a}{b}amsmath永远陈列大小;\genfrac{}{}{}0 的别名
\tfrac{a}{b}amsmath永远文本大小;\genfrac{}{}{}1 的别名
\cfrac{a}{b}amsmath连分数;各层大小相同;[l] [r] 让分子靠左或靠右
\binom{n}{k}amsmath带圆括号、无横线的二项系数;另有 \dbinom \tbinom
\genfracamsmath通用形式:用六个参数指定定界符、线宽与样式
\over无(TeX 原始命令)把分组内左侧的一切当作分子;在 amsmath 下会发出警告
\sqrt{x}无(LaTeX 内核)平方根;\sqrt[n]{x} 为 n 次根;用 \leftroot \uproot(amsmath)微调指数
\nicefrac{a}{b}nicefrac小号斜线分数 a/b;来自 1998 年的 units 套件
\sfrac{a}{b}xfrac小号斜线分数;在正文中调用字体自带数字,几乎不扰乱行