数式の技巧

LaTeX の数式微調整で使う道具は、ほとんどが同じ一つの発想からできています——見た目と、その要素が占める寸法(高さ・深さ・幅)を切り離す\smash は背の高いものの高さをゼロと数えさせ、\vphantom は何も印刷せずに高さだけを確保し、\rlap は文字を印刷しながら幅をゼロにします。だから「根号が入った行だけ行間が広がる」「隣り合う \sqrt の天井がそろわない」「総和の下の条件が式を横に広げる」といった症状は、どれも同じ考え方で直せます。このページは 症状から引く形 で、\smash\phantom\mathstrut\rlap\raisebox、そして \mathrm\operatorname の違いを、実測値つきで並べます。

症状から道具を引く

まず一覧です。どれも 印刷結果を最後に整えるための道具 で、式の意味は一切変えません。だから手順としては、まず数式を素直に書き、目に見えるあらが出た箇所にだけ後から当てるのが正解です。先回りして \smash\phantom を撒くと、フォントや本文幅を変えたときに逆にずれます。第一列のコマンド名がそのまま検索語になるので、症状を思い浮かべてから引いてください。

コマンド直せる症状出どころ
\smash背の高い要素がその行だけ行間を押し広げるLaTeX カーネル([t][b] は amsmath)
\vphantom隣り合う根号や行の高さがそろわないplain TeX(LaTeX からそのまま使える)
\mathstrut同じことを引数なしで。丸括弧一つぶんの高さを確保するplain TeX。定義はそのまま \vphantom(
\phantom複数行で桁をそろえたいが、左側の長さが違うplain TeX。幅だけなら \hphantom
\mathclap総和や積の下の長い条件が、式全体を横に広げるmathtools(\mathllap\mathrlap も同じ組)
\rlap文字を印刷しつつ、幅としては数えさせたくないplain TeX。左に張り出す \llap も同じ
\overset= などの真上に任意の記号を載せたいamsmath(真下は \underset
\operatorname自作の多文字演算子の前後に間隔が入らないamsmath。極限を下に出すなら \operatorname*
\raiseboxある要素だけを決まった量だけ上下に動かしたいLaTeX カーネル。高さ・深さも上書きできる
\!記号どうしが離れすぎている(重積分の \int\int など)plain TeX。\, の正反対で −3mu

根号を入れた行だけ行間が広がる — \smash

\smash{...} は中身を 高さも深さもゼロの箱として扱わせます。インクは変わらず印刷されるのに、TeX は縦方向の寸法をゼロと見なすので、行送りを広げる判断をしなくなります。実測すると、$\sqrt{1-x^2}$ は高さ 9.13329pt・深さ 1.26668pt・幅 35.75691pt。これを \smash で包むと 高さ 0.0pt・深さ 0.0pt、そして 幅は 35.75691pt のまま でした。縦だけがゼロになり、横は一切触られていないことが数字で分かります。

latex
% the radical inside the fraction pushes this line away from the one above
$y = \frac{1}{\sqrt{1 - x^2}}$

% zero its vertical size, and the leading returns to normal
$y = \frac{1}{\smash{\sqrt{1 - x^2}}}$

amsmath を読み込むと \smash省略可能引数 が付き、上下を別々に扱えるようになります。\smash[t]{...}高さだけ をゼロにして深さを残し、\smash[b]{...}深さだけ をゼロにして高さを残します。測ってみると \smash[t]{\sqrt{1-x^2}} は高さ 0.0pt・深さ 1.26668pt、\smash[b]{\sqrt{1-x^2}} は高さ 9.13329pt・深さ 0.0pt でした——狙った側だけがきれいに消えています。この [t][b] は LaTeX カーネルの \smash にはなく、amsmath が上書きして追加したもの です(引数なしの \smash 自体は plain TeX の時代からあり、LaTeX カーネルにも入っています)。

latex
% the descender of y drops the middle radical below the other two
$\sqrt{x} + \sqrt{y} + \sqrt{z}$

% smash away only the depth of y, and all three line up
$\sqrt{x} + \sqrt{\smash[b]{y}} + \sqrt{z}$

amsmath 自身が挙げている例が、この違いをきれいに示します。\sqrt{x} + \sqrt{y} + \sqrt{z} では、y にディセンダ(下に伸びる部分)があるため、真ん中の根号だけがわずかに下がります。数字で見ると $\sqrt{y}$ は高さ 7.0305pt・深さ 3.36946pt、$\sqrt{x}$ は高さ 8.00272pt・深さ 2.39725pt。ところが $\sqrt{\smash[b]{y}}$ を測ると 高さ 8.00272pt・深さ 2.39725pt——$\sqrt{x}$小数点以下まで完全に一致 しました。深さだけを消すことで、根号が x のときとまったく同じ寸法に戻ったわけです。

注意点が二つ。まず、消えるのは 寸法だけでインクは残る ので、潰した要素が上の行に食い込むことがあります。行間が詰まっている本文では、直した結果を必ず目で確かめてください。もう一つ、古い解説には「段落の先頭で \smash を使うときは \leavevmode を前置せよ」と書かれていることがありますが、現在の LaTeX カーネルではその必要はありませんlatex.ltx\finsm@sh\leavevmode@ifvmode\box\z@ で終わっており、垂直モードの処理を自分で行います。実際に段落先頭で \smash を使ってもエラーは出ませんでした。

隣り合う根号の天井がそろわない — \vphantom\mathstrut

\smash が「高いものを下げる」なら、\vphantom「低いものを上げる」正反対の操作 です。\vphantom{...} は引数と同じ高さ・深さを持ち、幅がゼロで何も印刷しない 箱を作ります。実測すると $\vphantom{a^2}$ は高さ 8.14003pt・幅 0.0pt。対になる $\hphantom{a^2}$ は高さ 0.0pt・幅 9.77202pt、両方を持つ $\phantom{a^2}$ は高さ 8.14003pt・幅 9.77202pt でした。縦だけ・横だけ・両方 の三つがきれいに揃っているのが分かります。低いほうの要素に、高いほうの中身を \vphantom で入れてやれば、何も見えないまま高さだけが一致します。

latex
% level the tops of several radicals with one strut each
$\sqrt{\mathstrut a}\;\sqrt{\mathstrut a^2}\;\sqrt{\mathstrut b}$

% or match a specific height by passing the taller content
$\sqrt{a} \;\sqrt{\vphantom{a^2}\,a}$

毎回そろえ先の中身を書くのが面倒なときのために、引数なしの近道 \mathstrut があります。その定義は plain TeX にこう書かれています——\def\mathstrut{\vphantom(}中身は「見えない開き丸括弧」ただ一つ です。数式の中で丸括弧はほどよく背が高く、しかも文字サイズに追随するので、行の高さをそろえる基準としてちょうどよいというわけです。実測でも符合します。$($ は高さ 7.5pt・深さ 2.5pt。$a$ は高さ 4.30554pt・深さ 0.0pt ですが、$\mathstrut a$ にすると 高さ 7.5pt・深さ 2.5pt——丸括弧の寸法そのもので、幅は 5.28589pt のまま変わりません。各要素の頭に一つ置くだけで、丸括弧一つぶんの高さにそろいます。

align= の位置をそろえる — \phantom\MoveEqLeft

そろえたい式そのものを \phantom に渡します。 変形を続けて書くとき、二行目以降は左辺を省いて = から始めたくなりますが、素の空白で押し出すとフォントや式が変わった瞬間にずれます。\phantom{f(x)} と書けば、f(x) を実際に組んだのとまったく同じ幅の空白ができるので、= が自然に縦にそろいます。手で数えた \quad の並びと違い、中身が変われば空白の幅も一緒に変わる のが利点です。

latex
\begin{align*}
  f(x)           &= x^2 + 2x + 1 \\
  \phantom{f(x)} &= (x + 1)^2
\end{align*}

% mathtools: when the first line is too long to keep on one row
\begin{align*}
  \MoveEqLeft f(x, y, z) = a + b \\
              &= c + d
\end{align*}

逆に、一行目の左辺が長すぎて = の位置に収まらない ときは、mathtools の \MoveEqLeft が使えます。一行目を揃え位置より左へ吐き出し、二行目以降がその下に自然に並ぶよう桁を作ります。行頭に置くだけで、& を自分で数える必要がありません。なお \phantom\hphantom の一般的な仕組み、および数式の空き全般については「添字と間隔」のページが詳しく扱っています。

幅を持たせずに置く — \rlap\llap\mathclap

\smash横方向版 がこの一群です。\rlap{...} は中身を印刷しつつ、箱の幅をゼロにして右側へはみ出させます。plain TeX の定義は一行で、\def\rlap#1{\hbox to\z@{#1\hss}}——「幅ゼロの箱を作り、余った分は無限に伸びるグルーで右へ逃がす」という、それだけの仕掛けです。実測でも \rlap{XX} の幅は 0.0pt、素の XX は 15.00003pt でした。左へ逃がす \llap\hss の位置が前になるだけです。表の桁からはみ出す注記や、行番号を版面の外へ出す用途で使われます。

数式のなかで同じことをしたいときは、mathtools の \mathclap(左右対称にはみ出す)、\mathllap(左へ)、\mathrlap(右へ)を使います。典型は総和の下の長い条件で、\sum_{\mathclap{1 \le i \le j \le n}} a_{ij} と包むだけで、式の幅が演算子ぶんに戻ります。この一群と \smashoperator、それに文章用の \clap は mathtools のページで詳しく扱っています。なお、条件を横に詰めるのではなく 複数行に積みたい ときは、amsmath の \substack{...} が正解です——\sum_{\substack{0<i<m \\ 0<j<n}} と書けば、二つの条件が \\ で区切られた二行として総和記号の下に置かれます。

数式の中に文字を書く — \text\mathrm\operatorname の違い

三つの違いは、周囲の書体を受け継ぐか演算子としての空きが入るかの二点に尽きます。まず書体。\text(amsmath 同梱の amstext が定義)は 周囲の本文書体をそのまま受け継ぎ\mathrm常に立体のローマン体に固定 します。実測が明快です。\textit{...} の中では \text{ab} が 14.24867pt に対し \mathrm{ab} は 14.61809pt。\textbf{...} の中では \text{ab} が 15.64928pt に対し \mathrm{ab} はやはり 14.61809pt——\mathrm は文脈が変わっても寸分違わず同じでした。地の文と同じ調子で読ませたい語には \text、常に立体で組みたい単位や添字のラベルには \mathrm を使います。

もう一点の空きが、\mathrm\operatorname を分けます。\operatorname(amsmath 同梱の amsopn が定義)は中身を 演算子(\mathop)として扱う ので、前後に自動でひと呼吸ぶんの空きが入ります。測ると $\mathrm{max} x$ が 24.32645pt、$\operatorname{max} x$ が 25.99307pt——差は 1.66662pt、ちょうど 3mu の細い空き 一つぶんです。両側に演算対象がある $a \mathrm{mod} b$$a \operatorname{mod} b$ では 28.74428pt 対 32.07753pt、差は 3.33325pt すなわち 6mu(左右に 3mu ずつ)。おもしろいことに、後ろに ( が続く $\mathrm{max}(x)$$\operatorname{max}(x)$どちらも 32.10425pt で完全に同じ でした。TeX は演算子と開き括弧のあいだには空きを入れない規則だからです。だから括弧付きの例だけを見て「同じだ」と結論するのは早計です。極限を記号の下に出したいときは、星付きの \operatorname*{max}_{x} を使います(実測 18.61118pt に対し、星なしは 23.6459pt と横に添えられます)。

latex
\[
  x_{\text{total}} \quad x_{\mathrm{total}}
  \qquad
  a \operatorname{mod} b \quad a \mathrm{mod} b
\]

% define it once in the preamble instead of repeating \operatorname
\DeclareMathOperator{\rank}{rank}
\DeclareMathOperator*{\argmax}{arg\,max}

同じ演算子を何度も書くなら、その都度 \operatorname を打つより プリアンブルで一度定義する ほうが確実です。amsmath の \DeclareMathOperator{\rank}{rank}\rank を演算子として作り、星付きの \DeclareMathOperator*{\argmax}{arg\,max} は極限を下に出す版を作ります。名前と綴りが一か所に集まるので、後から表記を変えるのも一行で済みます。

上下に動かす・詰める — \raisebox\!

\raisebox{量}{中身} は中身を 指定した量だけ持ち上げます(負の値を渡せば下げます)。実測すると、X は高さ 6.83331pt、\raisebox{2pt}{X} は高さ 8.83331pt——ぴったり 2pt 上がっています。さらに \raisebox{量}[高さ][深さ]{中身} と省略可能引数を二つ与えると、周囲に申告する高さと深さを上書き できます。\raisebox{2pt}[0pt][0pt]{X} を測ると高さ 0.0pt・深さ 0.0pt でした——動かしたうえで \smash と同じ「寸法ゼロ」にする、という合わせ技です。記号の位置をほんの少し直したいとき、フォントを差し替えて上下がずれたときに効きます。

最後に、記号どうしが離れすぎている場合です。負の細空き \! は plain TeX で \def\!{\mskip-\thinmuskip} と定義されており、\,(3mu)の 正確な逆、−3mu です。実測で $ab$ が 9.57755pt、$a\,b$ が 11.24417pt(+1.66662pt)、$a\!b$ が 7.91092pt(−1.66663pt)——きれいに対称でした。典型的な出番は重積分で、$\int\int$ は 14.99997pt と間が空きすぎて二つの別々の積分に見えます。ここに \! を二つ挟んだ $\int\!\!\int$ を測ると 11.66672pt。そして amsmath の専用命令 $\iint$11.66672pt——小数点以下まで完全に一致 しました。つまり昔ながらの \int\!\!\int は、専用命令と寸分違わぬ結果を出しています。とはいえ意図が明確な \iint\iiint があるならそちらを使うのが読みやすく、\! は既製の命令がない場面のための道具と考えるのがよいでしょう。

latex
\[
  \int\int f \, dA
  \qquad
  \int\!\!\int f \, dA
  \qquad
  \iint f \, dA
\]

% an arbitrary symbol set squarely above another
\[
  a \overset{!}{=} b, \qquad x \overset{?}{=} y,
  \qquad A \overset{f}{\longrightarrow} B
\]

最後の一つ、= の真上に記号を載せる話です。^_ は記号の 右肩・右足 に付くので、真上や真下には来ません。amsmath の \overset{上}{土台}\underset{下}{土台} がその役目を担い、\overset{!}{=} は「等しくあるべし」を、\overset{?}{=} は「これは等しいか」を表す慣用表記になります。第二引数が土台、第一引数が載せるものです。矢印への適用や入れ子といった踏み込んだ使い方は「上下の装飾」のページで扱っています。