LaTeX 数学字体选择(newtxmath、unicode-math)

把正文换成 Times,数学部分却仍是 Computer Modern——在 LaTeX 里挑选 数学字体 时人人都会先撞上这个问题。更麻烦的还在后头。载入 mathptmx,以为整篇文档已经统一成 Times,再用 pdffonts 检查这份 PDF:CMEX10 依然被嵌入其中。求和号和积分号至今仍是高德纳的字体。本页把 pdfLaTeX 的数学字体宏包(newtxmathmathpazofourierkpfonts 等)与 XeLaTeX、LuaLaTeX 上的 unicode-math\setmathfont 放在一起比较,每次都数一数究竟有哪些字体真的进了 PDF。数学字母表命令(\mathbb\bm 之类)另有专页;这里要回答的是如何为整篇文档挑定数学书体。

换了正文字体,数学并不会跟着换

在 LaTeX 中,正文字体与数学模式字体由 完全独立的两套体系 管理。所以用一行 \usepackage{...} 换掉正文书体后,变量、运算符和下标在你另行指定之前依旧是 Computer Modern。这是设计,而非疏忽。数学字体必须携带正文字体根本没有的信息——符号的高度与数学轴位置、让根号和括号能够加长的「延伸部件」、下标下移的距离、分数线的粗细,共几十个尺寸。你无法直接拿正文书体来排数学。因此更换数学书体,实际上是 取来一套专为此打造的字体

究竟嵌入了什么 —— 用 pdffonts 数一数

一个数学字体宏包究竟有没有真正替换 Computer Modern,数一数 PDF 中嵌入的字体就一清二楚。把文件交给 Poppler 的 pdffonts(多数环境里随 poppler-utils 提供)即可。用 TeX Live 2024 的 pdfLaTeX 编译同一份短文档——一行正文,加上一个含积分、求和、希腊小写与希腊大写的行间公式——结果整齐地分成三类:彻底替换的newtxnewpxfourierkpfontsmathdesign)、留下 Computer Modern 的mathptmxmathpazoeulervm),以及什么都不做时理所当然的全篇 Computer Modern。

shell
# the only honest way to check which math font you actually shipped
pdflatex paper.tex
pdffonts paper.pdf

# name                                 type              emb sub uni
# ------------------------------------ ----------------- --- --- ---
# QSPJFW+NimbusRomNo9L-Regu            Type 1            yes yes yes
# CZKGAS+CMR10                         Type 1            yes yes yes   <- still Computer Modern
# UYVLXV+CMEX10                        Type 1            yes yes yes   <- the big operators
载入什么pdffonts 报告的数学侧字体CM 是否残留
(none)CMR10 CMMI10 CMSY7 CMEX10 CMMI7 CMR7全是 CM;默认的 Computer Modern math
mathptmxNimbusRomNo9L StandardSymL CMR10 CMSY10 CMMI10 CMEX10会。+= 来自 CMR10,\sum\int 来自 CMEX10
mathpazoURWPalladioL PazoMath CMR10 CMSY10 CMEX10会;大型运算符仍是 CMEX10
newtxmathNewTXMI txsys txmiaX txexs NewTXMI7不会。正文侧得到的是 TeXGyreTermesX-Regular
newpxmathNewPXMI pxsys pxmiaX txexs不会;扩展字体与 newtx 用的是同一个 txexs,嵌入的子集完全相同
fourierFourier-Math-Symbols / -Extension / -Letters不会;正文为 Utopia。真正的一行搞定
kpfontsKp-Regular Kp-Italic Kp-Ex Kp-Sy不会;正文和数学全是 Kp 一族
eulervmEURM10 EUFM10 EUEX10 加 CMR10 CMR7会;字母、符号与大型运算符都换成 Euler,只有 operators 族(数字、直立罗马体)沿用正文书体
mathdesign完整的 MathDesign-CH-Regular 一套不会;用 [charter] 时正文是 CharterBT

传统方式 —— 在 pdfLaTeX 下把正文与数学配对

pdfLaTeX 下更换数学书体的标准做法,是 成对载入正文宏包与数学宏包。今天最容易推荐的是 newtx 系列:把 \usepackage{newtxtext}\usepackage{newtxmath} 并排写上,就得到 Times 风格的正文与相配的数学。不过与名字相反,newtxtext 嵌入的并非 Times 本身,而是 TeX Gyre Termes 的扩展版——pdffonts 显示为 TeXGyreTermesX-Regular。Palatino 则用 mathpazo,或者 newpxtextnewpxmath。想用 Charter 的话请注意:并不存在 xcharter-math.sty ——在 pdfLaTeX 下它是作为选项调用的,写成 \usepackage[xcharter]{newtxmath};而 OpenType 版的 XCharter-Math.otf 要通过下一节的 \setmathfont 使用。同样的写法还能配合 libertinelibertinuscochinealerewhonstix2noto 等众多正文书体,这正是 newtxmath 的长处。

若想用一行同时换掉正文和数学,fourier(Utopia 正文加 Fourier 数学)与 kpfonts(Kepler 一族)是稳妥之选;上文实测中两者都没有留下任何一个 Computer Modern 字体。要提防的错误,是把 只管正文的宏包 当成数学宏包。例如在 pdfLaTeX 下载入 libertinus,数学仍然是 CM:PDF 里 LibertinusSerif-RegularCMMI10CMR10CMEX10 并存。这一项实测记录在西文字体那一页。另一个经典事故是 把不成对的正文与数学混在一起。让 newtxtext(Times 风)搭配 newpxmath(Palatino 风),两套字体都能正常工作,但纸面上字宽与灰度都对不齐,看着别扭。

document.tex
% --- Times-like text and matching math (the easy recommendation) ---
\usepackage{newtxtext}
\usepackage{newtxmath}

% --- Palatino text and math, in one package ---
% \usepackage{mathpazo}

% --- one line for both, with no Computer Modern left behind ---
% \usepackage{fourier}     % Utopia text + Fourier math
% \usepackage{kpfonts}     % the Kepler family

% --- match math to another text face through newtxmath ---
% \usepackage{libertinus}
% \usepackage[libertinus]{newtxmath}

现代方式 —— unicode-math\setmathfont

在 XeLaTeX 或 LuaLaTeX 上,只要载入 unicode-math 并写一行 \setmathfont{…},就能用 一个 OpenType 数学字体 排出全部数学内容,把成堆的宏包一扫而空。引擎限制是实打实的:在 pdfLaTeX 下写 \usepackage{unicode-math} 会停在 ! Package unicode-math Error: Cannot be run with pdftex!,随后是 (unicode-math) Use XeLaTeX or LuaLaTeX instead.。让它成立的是 OpenType 的 MATH 表——字体文件内部的一个标准化区块,装着 TeX 排数学所需的全部尺寸:分数线粗细、下标下移量、根号上方的留白、可伸缩括号如何由部件拼接。正因为这些信息住在字体里,换字体就等于连排版参数一起换。若完全不指定字体,默认载入的是 Latin Modern Math

载入顺序上有一颗地雷。若在 unicode-math 之后 载入 amssymb,就会得到 四条同样形态的错误,以 ! LaTeX Error: Command \eth already defined. 打头,接着是 \smallsetminus\digamma\backepsilon(在 TeX Live 2024 上实测)。原因是 unicode-math 已经从 Unicode 一侧先行定义了这些符号,而 amssymb 试图重新定义时发生冲突。把顺序倒过来,写成 amsmathamssymbunicode-math,同一份文档就能毫无错误地通过。记住「unicode-math 永远放在字体相关宏包 之后」,大部分事故都能避免。

OpenType 数学字体性格及与之相配的正文书体
Latin Modern MathComputer Modern 系谱;默认载入。搭配 Latin Modern Roman
TeX Gyre Termes MathTimes 风;搭配 TeX Gyre Termes。另有 Pagella、Bonum、Schola、DejaVu 版
STIX Two Math面向科学出版,收录极广;搭配 STIX Two Text。macOS 自带该字体
Libertinus MathLibertinus Serif 的数学配套——这是 pdfLaTeX 给不了的组合
XCharter-MathCharter 系。并无 xcharter-math.sty;通过 \setmathfont 使用其 OTF
NewCMMath-RegularNew Computer Modern 的数学版;保留 CM 外观而覆盖面广得多
Fira Math无衬线数学字体;在幻灯片和海报中让数学与正文一致时很有用
Asana-Math偏 Palatino 的数学字体;与 STIX 衍生的 XITS 同为老将

The font "Latin Modern Math" cannot be found —— XeLaTeX 与 LuaLaTeX 的差别

同一句 \setmathfont{Latin Modern Math},在 LuaLaTeX 下通过,在 XeLaTeX 下却以 ! Package fontspec Error: The font "Latin Modern Math" cannot be found. 失败——这是在装有 TeX Live 2024 的 macOS 上实测的结果。原因在于两个引擎解析字体名的方式不同。LuaTeX 可以在 TeX 自己的目录树(TDS)中按名字查找,而 XeTeX 要询问 操作系统的字体数据库,因此随 TeX Live 附带却未在系统中注册的字体就可能「找不到」。同一测试中只有 STIX Two Math 在 XeLaTeX 下也能解析,正是因为 macOS 系统自带该字体。各引擎的名称解析差异在 fontspec 那页有详细说明,这里只给出对策:改用文件名指定\setmathfont{latinmodern-math.otf})、加上 [Path=…],或者 改用 LuaLaTeX

document.tex
% compile with lualatex (or xelatex, but see the note on name lookup)
\documentclass{article}
\usepackage{amsmath}
\usepackage{amssymb}       % must come BEFORE unicode-math
\usepackage{unicode-math}  % always after the font packages
\setmainfont{TeX Gyre Termes}       % text, via fontspec
\setmathfont{TeX Gyre Termes Math}  % the matching OpenType math font
% \setmathfont{latinmodern-math.otf} % by file name, if lookup by name fails
\begin{document}
\[ f(x) = \int_{-\infty}^{\infty} \hat f(\xi)\, e^{2\pi i x \xi}\, d\xi. \]
\end{document}

只从另一套字体取一部分 —— range=

当你选定的数学字体缺少某些字符时,\setmathfontrange= 选项 可以只从另一套字体补上缺的那部分。range= 接受 Unicode 范围、range=\int 这样的单个符号、range=\symbb(也可写作 range=bb)这样的 字母样式,以及 range=bfit/{greek,Greek} 这样样式与字符集的组合。效果是可以测量的:在以 Latin Modern Math 为主字体的基础上加上 \setmathfont{STIX Two Math}[range=\symbb]pdffonts 会同时报告 LatinModernMath-Regular STIXTwoMath-Regular,后者只携带那几个黑板粗体字母。由于只载入所需的槽位,这样混用并不会让 PDF 明显变大。唯一的前提是 必须先按常规方式指定主数学字体

document.tex
\usepackage{amsmath}
\usepackage{unicode-math}
\setmathfont{Latin Modern Math}                                % the main math font
\setmathfont{STIX Two Math}[range=\symbb]                     % blackboard bold only
\setmathfont{TeX Gyre Termes Math}[range=bfit/{greek,Greek}]  % bold-italic Greek only

到底该选哪一种 —— 让正文与数学「成对」

建议可以浓缩成一条:把正文字体与数学字体作为「一对」来选。无论用哪个引擎,这条原则都不动摇。什么都不做,你得到的是 Computer Modern(pdfLaTeX)或 Latin Modern Math(unicode-math 的默认),二者都足够好看;除非投稿规范点名了书体,否则没有更换的理由。若在 pdfLaTeX 下更换,请挑选彼此配套的组合——Times 用 newtxtextnewtxmath,Palatino 用 mathpazonewpx 系,Utopia 用 fourier,Kepler 用 kpfonts。在 XeLaTeX 或 LuaLaTeX 下,按 amsmathamssymbunicode-math 的顺序载入,并给 \setmainfont\setmathfont 传入 同一家族的名字。最后,在把文件发出去之前务必用 pdffonts 核对一遍。你以为交出去的字体,未必就是真正交出去的字体 ——这正是本页的起点。

  • 什么都不做时,得到的是 Computer Modern(pdfLaTeX)或 Latin Modern Math(unicode-math 默认)。没有规范要求时无需更换。
  • 在 pdfLaTeX 下更换:使用成对的宏包。Times 用 newtxtextnewtxmath,Palatino 用 mathpazo;想一行搞定就用 fourierkpfonts
  • 在 XeLaTeX 或 LuaLaTeX 下:按 amsmathamssymbunicode-math 的顺序载入,并让 \setmainfont\setmathfont 属于同一家族。
  • 不要 把不成对的正文与数学混用(Times 正文配 Palatino 数学)。不会报错,但纸面上看得出来。
  • 最后务必pdffonts 检查嵌入结果。mathptmxmathpazo 会留下 CMEX10