数理解析研究所講究録
第 1674 巻 2010 年 89-9889

PostScript を用いた数学関係の図の作成について

神奈川工科大学情報学部情報メディア学科 平野照比古

Department of Information Media
Kanagawa Institute of Technology

1

はじめに数学の教材を作成するときには数式の記述が楽なソフトウェアが必要である。著者は
このような教材は $BTffi[3]$ を用いて作成し、 結果を pdf 形式のファイルにしている。 出
力結果を PDF 形式にするため聾 TBX で書かれた文書内の図は PostScript で記述している。 こうすることで出版社に渡す書籍は図も含めた単一の pdf ファイルとすることが出来た ([6])。 また、授業で配布する資料も授業時には解答がないものを配布し、解答がついたものは後日 WEB 上で公開するということも容易に出来るようになった ([7] 参照)。
ここでは関数のグラフを多数 PDF ファイルに取り込むために採用した方法について簡単に解説をする。 また、 より正確な図を描くために数式処理を用いる方法についても述べる。

2

PostScript とはPostScript は Adobe Systems が開発したプログラミング言語で、 言語仕様の中にグラフィックスに関するものが含まれていることが特徴である [1]。名称の由来はプログラ
ムの記述が逆ポーランド記法を用いていることである。 PostScript の入門書としては [2]がある。

PostScript では通常の言語における関数は operator とよばれる

operator はスタック上にあるデータをいくつか引数として使い、 結果をスタックの上に置く。

2.1$\circ$スタックの処理と変数

PostScript では数字などの単純なものを記述するとそれはスタック上に順次置かれる。
置かれた順序を入れ替えたりするための基本的な operator は次の通りである。

90

2.2

演算

PostScript では四則演算や関数も引数を先に記述する。 なお、 PostScript で扱う数はすべて実数である。

このほかにも $sin$ や $\cos$ の三角関数、 平方根をとる sqrt など通常必要な関数はそろっている。詳しくは [1] を参照のこと。

2.3

論理演算と制御構造

PostScript には通常のプログラミング言語にある論理演算と制御構造が用意されている。論理演算は一部の制御構造で用いられる。
論理演算は次の通りである。

91
制御構造は次の通りである。

2.4

PostScript におけるグラフィックスの特徴

PostScript におけるグラフィックスの特徴は次の通りである。
$\bullet$

初期状態の座標系-左下が原点 $(0,0)$ である。

$-$

水平方向が$x$軸で右に行くほど値が大きい。

一垂直方向が$y$軸で上に行くほど値が大きい。

$-$

1

座標系の単位はーインチである。 .

これらの座標系は通常の数学で用いられている座標系と同じである。
$\bullet$$\bullet$$\bullet$

原点を移動 (translate) したり、原点を中心に回転 (rotate)、拡大・縮小 (scale)の operator がある。

回転の角度の単位は 60 分法であり、 弧度法ではない。 三角関数の引数も同様である。
ある時期のグラフィックスの環境を保存し (gsave)、その後、復元する (grestore)
operator がある。

$\bullet$

図形を描くためには道のり (path) を定義し、 道のりを描く (stroke) か、 それによって囲まれた部分を塗る fill 。これらの operator により道のりのデータは消える。
$($$)$

92

3

PostScript を利用した教材の開発
数学関係の教科書で図を扱う場合には次のような点に注意する必要がある。
$\bullet$$\bullet$$\bullet$

教科書には多数の関数のグラフがある。
これらのグラフは同じような体裁で表す必要がある。
したがって、 Postscript で図を作成するためには PostScript 用のライブラリーを用意する必要がある。
$\bullet$

PostScript のなかに記述された他のファイルを呼び出す (foo.ps) run は PDF
フォーマットの中では正しく動かない。

$\bullet$

したがって、 個々のファイル内にライブラリー関数を埋め込む必要がある。

[6] では出版社から提供されたスタイルファイルを元に原稿の入力は PDF ファイルで行った。 関数のグラフを記述するに当たり、 ライブラリーの関数を埋め込むために次のような処理を行った。
$\bullet$関数のグラフは関数の値だけを計算する部分と、 グラフを表示する範囲を指定する値程度の指定だけで済ませるようにし、 体裁の部分はライブラリーを読み込むこととした。

$\bullet$$\bullet$$\bullet$

EPS 形式に直すのには Ghostview を用いた。
ライブラリーファイルを変換後の EPS ファイルに埋め込むために PHP([5]) のプログラムを作成した。

グラフ上に現れる原点の記号などは作成した図の上に載せている。 このためにpicture 環境を用いている。

93
次のリストはライブラリーファイルを埋め込むために作成した PHP ファイルである。
123456789101112131415161718192021222324252627282930313233$<?php$$dname $=11./ps/lI$ ;$tmpfname $=|Itmp000$ . eps“ ;$FILENAME opendir ($dname) ;$=$while($fname$=$readdir($FILENAME)){

if(ereg(’. eps$’ , $fname)) {$fp $=f$ open $dname$fnam ,$ftmp $=f$ open $tmpfnam ,echo “$dname$fname n”;$(^{t1}$$e^{}$$(^{I1}$$e^{}$$||r^{1\mathfrak{l}})$$w^{lI}$;) ;$\backslash$while($line$=$fgets($fp, 1024)) {if(ereg(’ %’, $line)) {fputs($ftmp, $line);} else {run’, $line, $incfname)) {if(ereg($f incp $=f$ open (” $dname$incfname [1] ”, ” ) ;;fputs $ftmp,$\hat\backslash$$\backslash ((.*)\backslash ).*$$r^{||}$$||\%\%\backslash n\%\% 1ine\%\%\backslash n^{I1})$$($fgets($fincp, 1024)) {fputs($ftmp, $line);

while($line$=$}fputs($ftmp,fclose($fincp);} elsefputs($ftmp, $line);$|I0/u\%\backslash n\%^{l}/0$

end of $incfname[l] n%% n );$\backslash$$\backslash$}}fclose($ftmp);
fclose($fp);
copy($tmpfname, 11$dname$fname);
unlink($tmpfname);}}
CloSedir($FILENAME);$?>$$\bullet$$\bullet$$\bullet$

今回の教科書では PostScript ファイルはすべて ps の下に置いた。 3 行目でその値を変数$dname に格納している。

4 行目ではそのフォルダを開いている。

PHP の関数 readdir $()$ は opendir $()$ で開いたフォルダのファイルを順番に示す

94関数である。 すべて提示したときには false を返すので while でノレーフ を回すことができる 6 行目$\circ$$($$\bullet$$\bullet$$)$

与えられたファイル名が.eps で終わっていれば 8 行目から 31 行目までの処理をする (7 行目)。
12 行目では読み込んだ行が% で始まっていればそのまま出力し (13 行目)、 そうでない場合には ( filename ) run の行であるかをチェックする (15 行目)。
$<$$\bullet$$\bullet$$\bullet$。

$>$

この形式の場合にはこの行の先頭に%を追加した行を出力し (17 行目)、 その後、ライブラリーファイルを読み込んでそのまま出力する (18 行目から 20 行目)。
その後、 ライブラリーファイルの終了位置を示す行を書き込む (21 行目)。

これらの処理は一時ファイルに書き込んでいるので (4 行目、 9 行目参照)、 最後に一時ファイルを元のファイルに上書きコピーし (29 行目)、 一時ファイルを消去する (30 行目)。

図

図 1:

$\frac{x+2}{x^{2}-1}$のグラフ

このグラフは次のように作成した。
$\bullet$

グラフは$x$の値を小さく変化させながら関数の値を計算し、 それらの問を線分での値の変化はす結ぶことで描いている。 なお、 浮動小数点の誤差を避けるためべて整数で計算し、 最後に 10 や 100 で割ることで浮動小数点に直している。
$x$95$\bullet$$\bullet$$\bullet$

関数の値はすべて PostScript プログラムで計算してある。

関数の特異点の部分は手動で計算しないようにしてある。

関数のグラフに書き入れる文字は次のような啓 IEX のマクロを作成した。
$\backslash newcommand\{\backslash ShowGraph\}[7]${%$\backslash setlength\{\backslash unitlength\}\{\# 1cm\}^{0}/\Phi$$\backslash$begin{picture}#2#3{$\backslash put\# 3$$\backslash put$$\backslash scalebox\{\# 1\}\{\backslash$includegraphics $\{\# 7\}\}$ }$(\# 4,\# 4)\{0\}$$\backslash put(\# 5,0)${$x$}$\backslash put(0,\# 6)\{\backslash makebox$[Oem] {$y$}$\}$$\backslash end\{picture\}\}$

この関数は $x<-2$ のところに極小値をもつが、 その値が小さいため正確な位置がわからないことが見て取れる。

4

数式処理を用いた教材の例

前節の例では関数が定義できない点を手動で与えていたが、 このような有理関数であれば与えられた関数を分子と分母にわけ、分母が になる点は計算しないという方法で計算結果を PostScript のプログラムで出すことが可能である。
このほかに数式処理を用いて関数の値を計算する例としてはけた落ちを意識しないでいつも正しい関数の近似値が得られるという利点がある例を示す。
$\sin x$ のテイラー展開では原点のあたりでの振る舞いが強調された話が多い。 学生に対して与えられたテイラー展開が見慣れた $\sin x$ のグラフになることを示すためには 1周期や 2 周期にわたってマクローリン展開による式の結果が見慣れた形になることを示すのが良いのではないだろうか。次のような単純な 言語のプログラムではこの要請にこたえられないことがわかる。
$0$

$C$

#include $<stdio.h>$double func(doubledouble func2(double$x$, int$x$, int$\deg$);$\deg$ );int main(void) {int $i,$ $\deg=45$ , scale $=10,$ $xL=-19,$
double ;$x$$xH=-xL$ ;$xLS=xL*scale$ ;$xHS=xH*$ scale;$xH,$$xLS,$$xHS$;

96
$f$

or $(i=xLS;i<=xHS;i++)$ {$x=(i*1.0)/scale$ ;printf$(^{||0}/*f$%f$l/lf\backslash n^{1t}$,$x$, func $(x, \deg)$ ,func2 $(x, \deg))$ ;

$\}$

$\}$

double func(double
double sin, px;int ;$\sin=x$ ;px $=x$ ;$x$, int$\deg$ ){$j$

for $(j=3;j<=deg;j+=2)$ {px $*=-x*x/(j*(j-1))$ ;$\sin+=$

px;

$\}$

return sin;$\}$double func2(doubledouble sin, px;int ;$x$, int$\deg$ ){$j$

if $((\deg \ 1) ==0)\deg--$ ;$\sin=1$ ;px $=x*x$ ;for $(j=deg;j>2;j-=2)$ {$\sin=1-px/(j*(j-1))*sin$ ;$\}$return $sin*x$ ;$\}$この出力の一部は次のようになった。

18.600000 1.317148 1.317148
18.700000 1.860588 1.860588
18.800000 2.528902 2.528902
18.900000 3.354320 3.354320
19.000000 4.377756 4.377756
このようにかなり大きな次数で計算した この場合には 45 次の項 にもかかわらず $\sin x$の値が常識の範囲を超えている。 計算の次数を下げるともっと前から値は正しくない。
これは桁落ちによるものであり、 浮動小数点で計算している限りでは避けられないものである。数式処理での値を有理数で与えておけば関数の結果も有理数で求められ、桁落ちを心配することはない。 最終的に 1.0 をかけて浮動小数点として結果を出力させればよい。
$($$x$$)$

97
次のプログラムは Risa $/Asir$ による例である。
ldef func(Deg, Scale , R) {2output $(^{11}sin$ -asir“)$
3print $(^{\dagger\dagger}722.54div3div$ dup scale“)$4print $(^{1I}0.04$ setlinewidt )$5print $(R$ , 0 $6print $(^{11}2$ add 3 translate”)$
78print $(R, 1)$
9print $(^{||}0.5$ add dup neg
moveto Olineto stroke“)$
10setlinewidt )$print11moveto”$
12
for $(I=-R*Scale;I<=R*Scale;I++)$$h^{}$$)$$0$$(^{I\dagger}0.06$$h^{}$$C=^{\mathfrak{l}1}$

$\{$

X

$13$

14
15
16
17
18
19
20

$S=$

Px$=$

X$
X$

for $(J=3;J<=Deg;J+=2)$ {Px$*=$$S+=$-X X/(J (J-I))$
$*$

$*$

Px$}
print $(X*1.O, 0)$
print $(^{1I}||,$ $0)$
print $(S*1.O, 0)$

21
22

23
24
25
26
27
28
29

I/Scale$$=$print(C)$$C=11$

lineto Il$}
print strok
output O$$(^{11}$$e^{1I}$)

}$
end$$
$\bullet$

3 行目は図形の大きさの単位を lcm に設定するための PostScript のコマンドを出力している。

$\bullet$

4 行目から 9 行目ではグラフの軸を描くための PostScript のコマンドを出力している。

$\bullet$

12 行目から 25 行目で $\sin x$ の値を有理数で計算した後 (14 行目から 20 行目)、 値を有理数に直し (20 行目と 22 行目)、 PostScript のコマンドをその後に付け加えている。

98
なお、 出力ファイルのサイズを小さくする書き方としては repeat を用いる方法もある

がここではわかりやすい方法をえらんである。
出力ファイルを原稿に取り込むことでより正確なグラフが容易にかける。

参考文献[1] Adobe Systems Incorporated, PostScript Language Reference Manual third edition,
http: $//www$ . adobe. cOm/deVnet/poStSCript/pdf $s/PLRM$ . pdf[2] Adobe Systems Incorporated, Adobe Systems Incorporated, PostScript(R) Language Tutorial and Cookbook,
http: $//www$ -cdf. fnal. gov/offline/PostScript/BLUEB00K. PDF[3] H. Kopka and P. W. Daly, Guide to $BTM$ Fourth Edition, Addison-Wesley, 2004

[4] F. Mittelbach and M. Goossens, TheWesley, 2004

$B\mathcal{I}M$Companion Second Edition,Addison-[5] 日本 PHP ユーザー会, http: $//www.php$ . gr. $jp/$$[$$[$

6 平野照比古, 工科のための微分積分学第 3 版, 学術図書出版, 2009 年$]$

7 平野研究室のホームページ http: $//www$ .hilano.org $/hilmo$ -lab$]$