LaTeX 수식 모드에는 본문처럼 “글꼴을 바꾼다”는 개념이 없습니다. 있는 것은 수식 알파벳입니다. \mathbf, \mathbb, \mathcal처럼 감싼 범위의 글자를 통째로 다른 서체에 배정하는 장치입니다. 문제는 이 자리가 무한하지 않다는 점입니다. 고전적인 엔진에서는 한 수식에 최대 16개까지만 쓸 수 있습니다. 1978년에 정해진 이 상한은 40년이 지난 지금도 살아 있고, ! LaTeX Error: Too many math alphabets used in version normal. 이라는 모습으로 불쑥 나타납니다. 이 페이지는 패키지 없이 쓸 수 있는 일곱 명령에서 시작해 amssymb가 필요한 칠판 굵은체 \mathbb, mathrsfs의 \mathscr, 수식 굵은체 \bm, 그리고 unicode-math의 \sym…까지를 이 16칸을 어떻게 나눠 쓸 것인가라는 하나의 줄기로 이어 갑니다.
수식 알파벳은 서체가 아니라 “족”입니다
수식 모드에 들어간 영문자는 한 글자씩 변수로 간주되어 수식 이탤릭으로 조판됩니다. 이것이 기본 수식 알파벳입니다. \mathbf{v}처럼 명령으로 감싸면 그 범위만 다른 족——TeX 용어로는 \fam——으로 바뀝니다. 본문용 서체 명령과 결정적으로 다른 지점이 여기입니다. TeX는 수식의 문자 하나하나를 “몇 번 족의 몇 번 자리”로 저장하므로, 서체는 본문처럼 이어지는 흐름이 아니라 기호마다 붙은 라벨입니다. 그래서 \mathbf{fit}은 단어 “fit”이 아니라 굵은 기호 f, i, t 세 개의 곱으로 조판되고, 글자 사이에는 변수끼리의 간격이 들어갑니다. 수식 안에 진짜 단어를 직립으로 넣고 싶다면 amsmath의 \text{…}를 씁니다.
표준 LaTeX에는 일곱 개의 수식 알파벳 명령이 처음부터 들어 있습니다. 이름은 모두 \math… 형태이며, 본문용 \textbf・\textsf 등과 짝이 되도록 붙여져 있습니다. 헷갈리기 쉬운 짝은 \mathnormal과 \mathit입니다. \mathnormal(기본)은 글자 하나하나를 변수로 조판해 자간이 넓고, \mathit은 본문용 이탤릭이라 \mathit{diff}처럼 여러 글자 단어를 하나의 기울어진 단위로 만들 때 알맞습니다. \mathrm과 \mathbf는 직립 로만체이고 뒤쪽이 굵은체입니다. \mathsf는 텐서나 범주 이름에, \mathtt는 수식 안에 코드 같은 토큰을 넣을 때 쓰입니다.
| 명령 | 모양 | 비고 |
|---|---|---|
\mathnormal | 기본 수식 이탤릭 | 내장. 변수의 기본 모양이며 자간은 변수 사이 간격 |
\mathrm | 직립 로만체 | 내장. 직립 상수, 연산자, 약어에 사용 |
\mathbf | 직립 굵은체 | 내장. 직립이라 변수에는 부적합하고 그리스 문자에는 효과가 없음 |
\mathsf | 산세리프체 | 내장. 텐서나 범주 이름 등에 사용 |
\mathtt | 등폭(타자기체) | 내장. 수식 안의 코드 같은 토큰에 사용 |
\mathit | 본문용 이탤릭 | 내장. \mathit{diff}처럼 여러 글자 단어를 하나의 기울어진 단위로 |
\mathcal | 캘리그래픽. 대문자만 | 내장. 집합족, 범주, 변환 이름에 사용. 글리프는 Computer Modern의 cmsy |
\mathbb, \mathscr, \mathfrak에는 어떤 패키지가 필요한가
칠판 굵은체 \mathbb과 프락투어 \mathfrak에는 amssymb(또는 더 가벼운 amsfonts)가, 스크립트 \mathscr에는 mathrsfs가 필요합니다. \mathcal만 표준입니다. \mathbb은 세로획 등을 이중선으로 만든 굵은체로, 칠판에서 획을 겹쳐 그어 굵은 글씨를 나타내던 습관에서 왔고, 용도는 실수 ℝ, 복소수 ℂ, 정수 ℤ, 유리수 ℚ, 자연수 ℕ 같은 수의 집합으로 거의 굳어져 있습니다. 수록 범위는 대문자 A–Z뿐이며 소문자도 숫자도 없습니다.
\mathcal과 \mathscr 사이의 선택은 유래를 알면 훨씬 쉬워집니다. \mathscr가 불러오는 rsfs는 “Ralph Smith’s Formal Script”의 줄임말로 1991년 10월에 공개되었습니다. 작성자는 README에서 이것이 18세기 스펜서체・동판체 필기에 바탕을 둔 격식 있는 서체이며, 활자 디자이너 R. Hunter Middleton의 서체를 본떴고 Springer Verlag의 조판에서 보이는 것과 비슷하다고 밝힙니다. 반면 \mathcal은 Computer Modern의 기호 글꼴 cmsy에 들어 있는 더 편안한 장식 대문자입니다. 곧 ℒ과 𝓛은 “격식 있는 필기체”와 “가벼운 장식체”의 대비이지 옳고 그름의 문제가 아닙니다. 함수해석학의 정의역 𝒟나 장론의 라그랑지안 ℒ에 rsfs가 선호되는 이유가 바로 이 격식입니다.
\mathfrak 뒤에 있는 서체에도 이름이 있습니다. amssymb는 \DeclareMathAlphabet{\mathfrak}{U}{euf}{m}{n}이라고 쓰는데, euf가 바로 Euler Fraktur입니다. AMSFonts의 README는 Euler 계열 서체가 헤르만 차프의 설계로 1990년대에 처음 공개되었다고 밝힙니다. 같은 README는 차프가 여러 글자꼴을 다시 다듬은 Euler 3.0이 2008년 1월 10일 커누스의 생일에 본인에게 전달되었다는 사실도 기록하고 있습니다. Lie 대수 𝔤나 아이디얼 𝔭에 쓰는 그 각진 서체는 20세기를 대표하는 활자 디자이너의 손에서 나왔고, \mathbb이나 \mathcal과 달리 대문자와 소문자를 모두 갖추고 있습니다. euscript 패키지가 제공하는 Euler Script(eus)도 같은 집안입니다.
\usepackage{amssymb} % \mathbb and \mathfrak
\usepackage{mathrsfs} % \mathscr (Ralph Smith's Formal Script)
% ...
\[
\mathbb{R} \subset \mathbb{C}, \qquad
\mathcal{F}(f) = \hat{f}, \qquad
\mathscr{L}(f) = F, \qquad
\mathfrak{g} = \operatorname{Lie}(G).
\]| 명령 | 필요한 패키지 | 지원 범위와 대표 용도 |
|---|---|---|
\mathbb | amssymb(또는 amsfonts) | 대문자 A–Z만. 수의 집합 ℝ ℂ ℤ ℚ ℕ |
\mathcal | 표준(불필요) | 대문자만. 집합족, 범주, 변환 이름. 글리프는 cmsy |
\mathscr | mathrsfs(또는 euscript) | 대문자만. 더 격식 있는 필기체. 글리프는 rsfs10 |
\mathfrak | amssymb / amsfonts(euf) | 대문자와 소문자. Lie 대수, 아이디얼. Euler Fraktur |
\mathbb{2}는 오류가 아니라 다른 기호를 냅니다
칠판 굵은 1이나 2를 얻으려고 \mathbb{1}, \mathbb{2}라고 쓰면 경고도 오류도 없이 전혀 다른 기호가 나옵니다. TeX Live 2024의 amssymb로 $\mathbb{2}$를 조판하고 PDF에서 문자를 다시 꺼내 보면 U+22AD(⊭, not true)가 돌아옵니다. 이유는 수식 알파벳의 구조 자체에 있습니다. \mathbb은 msbm 글꼴에서 같은 자리를 가져올 뿐이므로, msbm10의 2 자리에 들어 있는 기호——바로 ⊭——가 그대로 나옵니다. 그 문자가 존재하는지 확인하는 장치는 없습니다. 지시함수 𝟙이 필요하다면 dsfont의 \mathds{1}(Type 1 글꼴 dsrom10)을 쓰거나 mathalpha 패키지로 칠판 알파벳 자체를 교체합니다. bbm의 \mathbbm{1}도 유명하지만, TeX Live에 들어 있는 판에는 Type 1 외곽선이 없어 PDF에 Type 3 비트맵으로 묻힙니다(pdffonts로 확인할 수 있습니다). 비트맵 글꼴을 꺼리는 투고 규정 아래에서는 피하는 편이 안전합니다.
% A blackboard-bold digit is NOT available from amssymb:
% $\mathbb{2}$ -> U+22AD, silently. Use one of these instead.
\usepackage{dsfont} % \mathds{1}, Type 1 outlines
\usepackage[bb=dsserif,scr=rsfs]{mathalpha} % replace the whole \mathbb alphabet
% ...
\[ \mathds{1}_{A}(x), \qquad \mathbb{1}_{A}(x) \]수식 알파벳은 16개까지 — Too many math alphabets
알파벳을 계속 더하다 보면 언젠가 ! LaTeX Error: Too many math alphabets used in version normal.에 부딪힙니다. 상한은 16입니다. TeX의 수식 문자 코드는 족 번호에 4비트만 할당하므로 족은 0부터 15까지밖에 존재할 수 없습니다. latex.ltx에는 \chardef\e@mathgroup@top=16이라고 명시되어 있고, \Umathcode를 갖춘 엔진(XeTeX・LuaTeX)에서는 이 값이 256으로 올라갑니다. 아무것도 없는 article도 시작 시점에 이미 4개 족(operators, letters, symbols, largesymbols)을 쓰고, amssymb와 mathrsfs를 더하면 7개가 됩니다. 남는 것은 아홉 칸 남짓이고, 거기에 \mathbf, \mathsf, \mathtt, \mathit, \mathcal, \mathbb, \mathfrak, \mathscr가 차례로 들어갑니다. 이 예산은 “수식마다”가 아니라 “문서마다”에 가깝습니다. 칸은 처음 쓴 순서대로 채워지고 되돌아오지 않습니다.
같은 16칸을 지키는 두 번째 문지기가 있습니다. 기호 글꼴을 등록하는 \DeclareSymbolFont는 latex.ltx 안에서 하드코딩된 조건 \ifnum\count18<15로 보호되며, 이를 넘으면 ! LaTeX Error: Too many symbol fonts declared.가 납니다. 여기가 중요한 함정입니다. 15라는 숫자는 엔진과 무관하게 적용되므로, LuaLaTeX에서 알파벳은 256개를 쓸 수 있어도 기호 글꼴은 여전히 16개까지입니다. 17번째 \DeclareSymbolFont를 쓰면 pdfLaTeX에서도 LuaLaTeX에서도 같은 오류가 납니다. 저수준 \newfam을 직접 불러 상한을 넘겼을 때에만 TeX 자체의 ! No room for a new \mathgroup.이 나타납니다. \fam이 아니라 \mathgroup인 이유는 LaTeX2e가 \newfam을 \new@mathgroup의 별칭으로 두었기 때문입니다.
숨통도 있습니다. 최근 LaTeX 커널은 16칸 가운데 마지막 두 칸을 “돌려쓰기용”으로 예약합니다(\c@localmathalphabets의 기본값이 2). 본문에서 15번째・16번째 알파벳이 필요해지면 커널이 그 칸을 해당 수식에만 빌려주고 수식이 끝나면 회수합니다. 그래서 한 수식이 필요로 하는 추가 알파벳이 두 개 이하라면 문서 전체로는 14개를 넘겨도 멈추지 않습니다. 실제 시험에서도 카운터는 14에서 멈춘 채 오류가 나지 않았습니다. 뒤집어 말하면 한 수식에 새 알파벳을 세 개 이상 몰아넣으면 바로 거기서 끊깁니다. 오류가 특정 수식에서만 난다면 이것부터 의심하세요. isomath 문서도 이 16개 상한 때문에 자체 \mathsfit을 선택 사항으로 두었다고 분명히 밝히고 있습니다. 아예 계산하고 싶지 않다면 XeLaTeX나 LuaLaTeX로 옮겨 unicode-math를 쓰는 것이 근본적인 해결책입니다.
직접 알파벳을 더하기 — \DeclareMathAlphabet
새 수식 알파벳은 한 줄이면 됩니다. \DeclareMathAlphabet{명령}{인코딩}{패밀리}{시리즈}{셰이프} 형태이며 프리앰블 전용입니다. 텐서용으로 기울어진 산세리프가 필요하다면 \DeclareMathAlphabet{\mathsfsl}{OT1}{cmss}{m}{sl} 한 줄로 끝납니다. 굵은 수식(아래의 \mathversion{bold})에서도 함께 굵어지길 원한다면 \SetMathAlphabet{\mathsfsl}{bold}{OT1}{cmss}{bx}{sl}을 이어 씁니다. 이미 기호 글꼴로 등록된 것에 다른 이름만 붙이고 싶다면 칸을 소비하지 않는 \DeclareSymbolFontAlphabet을 쓰면 됩니다. mathrsfs.sty의 내용은 사실상 그 두 줄뿐입니다. 하나 더, \DeclareMathAlphabet은 선언 시점이 아니라 처음 실제로 쓰일 때 칸을 확보합니다. 그저 읽어들이기만 한 패키지가 예산을 갉아먹지는 않는다는 뜻이라 원인 찾기가 훨씬 수월해집니다.
% preamble only
\DeclareMathAlphabet{\mathsfsl}{OT1}{cmss}{m}{sl}
\SetMathAlphabet{\mathsfsl}{bold}{OT1}{cmss}{bx}{sl}
% costs no slot: just another name for a symbol font already declared
\DeclareSymbolFont{rsfs}{U}{rsfs}{m}{n}
\DeclareSymbolFontAlphabet{\mathscr}{rsfs}
% ...
\[ \mathsfsl{T}_{ij} \]수식을 굵게 — \mathbf, \boldsymbol, \bm의 차이
\mathbf은 직립 굵은체이므로 기울어야 할 변수나 벡터에는 맞지 않고, 그리스 문자에는 전혀 효과가 없습니다. 실측하면 분명해집니다. $\mathbf{\alpha}$만 들어 있는 문서를 pdfLaTeX로 조판하고 pdffonts로 보면 묻힌 글꼴은 딱 하나, CMMI10입니다. 즉 α는 굵은체용 CMMIB10이 아니라 평범한 수식 이탤릭 그대로 나옵니다. 이는 설계대로입니다. \mathbf은 족을 바꾸는 명령이고, α는 족을 바꿔도 글자꼴이 달라지지 않는 자리에 있기 때문입니다. 오류도 경고도 나지 않으므로 모르는 채 제출되기 쉬운 사고입니다.
기울임을 유지한 채 굵게 만들려면 첫 후보가 amsmath(내부의 amsbsy)의 \boldsymbol이고, 실무에서 가장 견고한 것은 bm 패키지의 \bm입니다. bm은 LaTeX 필수 도구 모음 latex-tools에 포함되므로 표준 TeX 배포판이라면 따로 설치할 것이 없습니다. \bm{…}은 주어진 것에 굵기만 더하고 기울임을 비롯한 나머지 모양과 앞뒤 간격을 유지하도록 설계되어, 변수・그리스 문자・기호는 물론 복잡한 입력도 거의 그대로 굵게 만듭니다. bm은 \boldsymbol을 \bm의 별칭으로 다시 정의합니다. 다만 \bm이 공짜는 아닙니다. bm.sty에는 \bmmax(기본 4)라는 상한이 있어 굵은 판을 위해 확보할 족의 수를 제한합니다. 굵은 수식 알파벳도 같은 16칸에서 나오므로 앞 절의 예산표에 함께 올라갑니다. 모자라면 \chardef\bmmax=6처럼 올릴 수 있지만 그만큼 일반 알파벳이 줄어듭니다.
수식 전체를 굵게 해야 할 때——제목 안이나 그림 라벨 등——에는 명령이 아니라 수식 버전을 바꿉니다. \boldmath와 \mathversion{bold}가 그 역할을 하며, 표준 LaTeX에는 normal과 bold 두 버전이 처음부터 있습니다. 세 번째를 만들 수도 있습니다. \DeclareMathVersion{heavy}로 선언하고 \SetMathAlphabet{…}{heavy}{…}를 나열해 두면 \mathversion{heavy}로 통째로 바뀝니다. bm의 \hm(별칭 \heavysymbol)이 이 heavy 버전용 명령이고 \hmmax의 기본값은 3입니다. 다만 heavy 버전을 실제로 정의하지 않았다면 \hm은 그냥 \bm이므로, \hm을 쓴다고 해서 저절로 \bm보다 굵어지지는 않는다는 점에 주의하세요.
\usepackage{amsmath} % \boldsymbol
\usepackage{bm} % \bm -- recommended
% \chardef\bmmax=6 % raise bm's family budget if it runs out
% ...
\[
\mathbf{v} \neq \bm{v}, \qquad
\bm{\beta} = (\beta_1, \dots, \beta_n), \qquad
\nabla \bm{F} = \bm{0}.
\]
\section{\boldmath A whole heading in bold maths: $E = mc^2$}\mathbf— 직립 굵은체. 표준으로 쓸 수 있지만 기울어야 하는 변수에는 부적합하고 그리스 문자에는 효과가 없습니다(위에서 실측).\boldsymbol— amsmath(amsbsy) 제공. 기울임을 유지하며 그리스 문자와 기호도 굵게 만듭니다.\bm— bm 패키지 제공. 권장. 굵기만 더하고 글자 모양과 앞뒤 간격을 유지합니다. 족 소비는\bmmax(기본 4)로 제한됩니다.\boldmath/\mathversion{bold}— 한 구간이 아니라 수식 버전 전체를 바꿉니다. 제목이나 그림 라벨의 수식에 씁니다.
unicode-math의 \sym… — 알파벳이 Unicode에 대응합니다
XeLaTeX나 LuaLaTeX에서 unicode-math를 읽어들이면 알파벳 명령이 \sym… 계열로 바뀝니다. \symbf(굵은체), \symbb(칠판 굵은체), \symcal(캘리그래픽), \symscr(스크립트), \symfrak(프락투어), \symup(직립), \symit(이탤릭), \symsf(산세리프)입니다. 기존 이름도 남지만 실제로 \mathbb은 \symbb의, \mathcal은 \symcal의 별칭으로 다시 정의됩니다. 결정적인 차이는 \sym…이 족 전환이 아니라 Unicode의 수학 영숫자 기호로의 매핑이라는 점입니다. LuaLaTeX에서 STIX Two Math로 $\symbb{2}\ \symbb{r}\ \symcal{L}$을 조판하고 PDF에서 문자를 꺼내면 U+1D7DA(𝟚), U+1D563(𝕣), U+2112(ℒ)가 돌아옵니다. 앞 절에서 ⊭가 되었던 \mathbb{2}가 여기서는 진짜 칠판 굵은 2이고 소문자까지 갖추어져 있습니다. PDF에서 복사한 문자가 의미를 유지하는 것도 이 매핑 덕분입니다.
이 매핑에는 미리 알지 못하면 반드시 걸려 넘어지는 귀결이 하나 있습니다. \symcal과 \symscr은 같은 Unicode 문자로 대응합니다. Unicode의 수학 영숫자 기호에는 스크립트 알파벳이 한 벌뿐이라 \symcal{L}도 \symscr{L}도 U+2112입니다. 둘을 겉모습으로 구분하려면 range=를 통해 글꼴의 OpenType 스타일 세트를 지정합니다. STIX Two Math라면 주 \setmathfont 뒤에 \setmathfont{STIX Two Math}[range=\symscr,StylisticSet=1]을 이어 쓰면 됩니다. 실측하면 이 한 줄로 \symcal{L}의 너비가 6.99pt인 데 비해 \symscr{L}은 8.63pt——다른 글리프가 선택되었음이 숫자로 확인됩니다. 기존 방식이 알파벳 두 칸을 써서 해결하던 문제를, unicode-math는 글꼴 기능을 지정하는 것으로 해결합니다.
% compile with xelatex or lualatex
\usepackage{amsmath}
\usepackage{unicode-math}
\setmathfont{STIX Two Math}
\setmathfont{STIX Two Math}[range=\symscr,StylisticSet=1] % a second script shape
% ...
\[
\symbb{R} \subset \symbb{C}, \qquad \symbb{2}, \qquad
\symcal{F} \neq \symscr{F}, \qquad \symfrak{g}, \qquad
\symbfit{v} = \symbf{0}.
\]마지막으로 unicode-math 환경에서 \symbf를 쓸 때의 주의 하나. 기본 설정(bold-style=TeX)에서는 \symbf{v}가 굵은 “직립체”가 됩니다. 실측에서 \symbf{v}는 U+1D42F(굵은 로만 v), \symbfit{v}는 U+1D497(굵은 이탤릭 v)이었습니다. 벡터를 굵은 이탤릭으로 쓰는 관례라면 \symbfit을 쓰거나 bold-style=ISO를 지정하세요. 문서 전체의 수식 글꼴을 어떻게 고를지——\setmathfont에 무엇을 넘길지, 본문 서체와 어떻게 맞출지——는 다른 페이지의 주제입니다.