アドベントカレンダーの 3 日目の記事「TeXを電卓として使おう」(k16.shikano さん)では TeX の処理系(= TeX 言語のインタプリタ)を電卓として使うという技が紹介されています。なかなか面白いアイデアですが、しかしこの方法には弱点が存在すると考えています。
例えば、100 円のハンバーガー 2 個と 150 円のコーヒーを 6 人で買って割り勘の支払い金額を求めたいという状況を考えます。「TeX で電卓」を使うと次のような入力をする必要があります。
>pdftex This is pdfTeX, Version 3.1415926-2.4-1.40.13 (TeX Live 2012/W32TeX) restricted \write18 enabled. **\relax entering extended mode *\newcount\ct *\ct=100 \multiply\ct 2 \advance\ct 150 *\divide\ct 6 \showthe\ct > 58. <*> \divide\ct 3 \showthe\ct ?
これはただ単に面倒であるという問題もありますが、何より、私たちが普段使っている数式の姿から大きく離れているため、操作法を直感的に把握しにくいという大きな問題を抱えています。同じ計算を行うのに、例えば Scheme の処理系(Gauche)なら
>gosh gosh> (/ (+ (* 100. 2) 150) 6) 58.333333333333336 gosh>
という入力で可能ですし、また PostScript の処理系(GHostscript)なら
>gswin32c GPL Ghostscript 9.05 (2012-02-08) Copyright (C) 2010 Artifex Software, Inc. All rights reserved. This software comes with NO WARRANTY: see the file PUBLIC for details. GS>100 2 mul 150 add 6 div = 58.3333 GS>
という極めて自然な形式で式を入力できるのと比較すると、TeX での入力の複雑さは大きな弱点と言わざるを得ません。
非常に残念な気持ちになったので、30 分ほどかけて作ってみました。
この tccalc.tex を普通に latex
でコンパイルする(lualatex
とか --shell-escape
とかじゃないよ!)と普通に式を入力して計算できるようになります。
<latex tccalc.tex This is pdfTeX, Version 3.1415926-2.4-1.40.13 (TeX Live 2012/W32TeX) ……(中略)…… ) *=(100*2+150)/6 ->58.33333333333333 *=
とても自然ですね!
もっと高度な演算もサポートされています。例えば、たまたま道端に落ちていた、半径 15、中心角 42°の弓形*1の面積を知りたいと思った時でも簡単に答えが得られます。
(先の続き)
*=15^2*42deg/2 - 15^2*sin(42deg)/2
->7.18961394136055
また、ある時ふと 1000 の階乗の近似値をスターリングの公式で求めようと思った場合も楽勝です。
*=(2pi*1000)^.5*(1000/exp1)^1000
->4.023537292037633e2567
(結果は指数表記での表示。つまり 4.02×102567。)
また IEEE 754 の仕様に準じた非有限数(無限大、NaN)もサポートされているので、安心してゼロで割ることができます。(ただし答えが NaN になる場合はエラーが発生する。)
*=9/0 ->inf *=+9/-0 ->-inf *==0/0 + ln(42) ! Undefined control sequence. <argument> \LaTeX3 error: Invalid operation (0)/(0) l.27 } ? ->nan
サポートされている演算を優先順位の降順に挙げると以下のようになります。
- 連接による乗算(
2pi
、30deg
等)((この書式が可能なのは「数字×定数」「数字×関数適用」等の一部の組み合わせに限られるようで、例えば「6/2(1+2)
」はエラーになる。)) - 関数の適用。関数の一覧は次の通り:
abs
,exp
,ln
,max
,min
,round
,round0
,round+
,round-
,sin
,cos
,tan
,cot
,csc
,sec
- べき乗
^
(又は**
) - 単項演算子
+
,-
,!
(論理否定) - 乗除
*
,/
- 加減
+
,-
- 比較
<
,<=
,>
,>=
,=
,!=
等 - 論理積
&&
- 論理和
||
- 三項
? :
また次の定数が定義されています。
inf
,nan
,pi
(= π),deg
(= π/180),true
(= 1),false
(= +0)((自然対数の底 e に対する定数はなくexp1
とする必要がある。e
とすると3e-5
等の指数表記との混同が起こるためである))
pdfTeX の有効な長さ単位、pt
,cm
,in
,em
等。これらは pt 単位での数値を表し、例えば32768sp
は 0.5 に等しい。
単位の定数を使うと、例えば、「A4 縦、和文サイズ 10pt スケール 95 %で 1 行 42 文字とする場合の左右のマージン(1in のオフセット込み)を cm で表した数値」を次のようにして求められます。
*=((210mm - 10pt*0.95 * 42) / 2 - 1in) / cm
->0.9483769198837687
便利ですね! というわけで、これからの時代は、計算したくなった時には Ghostscript ではなくて LaTeX を起動しましょう!!
* * *
*「こんな高機能なものが 30 分で作れるわけがないだろjk」
ZR「え?」
*「どうせまた裏で何か TeX でないものを動かしているんだろう?」
ZR「いや違いますよ。だって LuaLaTeX じゃなくて単なる LaTeX だし、--shell-escape
つけてないから \write18
も使えないし……。ちなみに 30 分でできるのはそんなに不思議じゃなくて、ソースはたったのこれだけなので」
\documentclass{minimal} \batchmode % suppress terminal output \usepackage{expl3}[2012/09/05] \errorstopmode % resume terminal output \ExplSyntaxOn %% calculator repl loop \tl_new:N \l_tchcl_input_tl \tl_new:N \l_tchcl_answer_tl \bool_new:N \l_tchcl_quit_bool \group_begin: \char_set_catcode_active:N \* \cs_gset:Nn \tchcl_readin: { \ior_get_str:NN \c_term_ior * \tl_set_eq:NN \l_tchcl_input_tl * } \group_end: \bool_until_do:Nn \l_tchcl_quit_bool { \tchcl_readin: \tl_if_blank:VTF \l_tchcl_input_tl { \bool_set_true:N \l_tchcl_quit_bool } { \tl_set:Nf \l_tchcl_answer_tl { \fp_to_tl:n { \l_tchcl_input_tl } } \iow_term:x { -> \l_tchcl_answer_tl } } } \ExplSyntaxOff \stop % quit immediately \begin{document} \end{document}
*「………………」
ZR「ん?」
*「なんだこのプログラムのようななにかおそろしいものは……」
ZR「expl3ですが何か?」
*「……何ソレおいしいの?」
ZR「まあ詳しい話はどこかのZRさんのブログで『expl3』を検索してもらうとして……、まあこういうことですね」
LaTeX2eむかつく!レイアウトいじるのに何でワケワカランTeX言語せなあかんねん! ↓ せや、新しいLaTeXを作ればええんや! ↓ LaTeX3作るで! ↓ (コード書き中) TeX言語ワケワカラン! むかつく! どないしよ? ↓ (考え中) せや、TeXを使うてもっと書きやすい言語を実装して、それを使うたらええんや! えらいええこと考えたもんや! ↓ (expl3実装中) でけた!!! ↓ よっしゃぁ! これからLaTeX3作るでぇ! ↓ イマココ
*「……ヒィィィィィTeXな人こわい…」(((;゚Д゚))ガクガクブルブル
ZR「コワクナイヨー」
* * *
今年は、色んな人の色んな TeX 芸を見ることができて非常に充実した一年となりました。
来年は「TUG 2013 日本開催」「美文書第 6 版出版(多分)」と日本の TeX コミュニティにとって重要なイベントが待ち構えています。日本に、そして世界に、より多くの TeX 芸人が現れることを心から願いつつ、今年のブログを締めくくりたいと思います。
*1:円 O の周上に点 A, B があったときに扇形 OAB から三角形 OAB を取り除いた図形のこと。