計算数理A演習では、プログラミング言語としてC言語を用います。必要とするC言語の知識は、2年生後期の計算数学演習で扱った程度とします。計算数学演習では参考書として、
改訂 新C言語入門 スーパービギナー編
林晴比古著 ソフトバンクパブリッシング
1600円 ISBN4-7973-0671-8
を用いましたが、計算数学演習を受講しなかった人でも、この参考書程度のC言語の知識を持っていれば受講に支障はありません。2005年度計算数学演習のHPはこちらにありますので、参考にしてください。
なお,トップページに,次回の演習内容もリンクされていますが,今日のすすみ具合を見て予定を変更する可能性もありますので,そのつもりでいてください.
今日は以下の内容で演習を行います。
小林先生が担当される計算数理Aの講義には毎週必ず出席してください。この演習の内容は計算数理Aの講義内容に強く依存し、講義内容をよく理解している事を前提条件としています。演習のみ登録されている方も、できれば講義にも出てください。
演習の当面の目標は、コンピュータを使ってある種の常微分方程式・偏微分方程式を解くことです。ただし、その為には
といったことが必要となります。このうち、プログラミング言語の習得は、計算数学演習で十分行いましたので、計算数理A演習では、既にC言語をある程度使えるものとして演習を進めます。
計算結果の可視化には、GLSCというグラフィックスライブラリを用います。計算結果の可視化とは,数値計算によって得られた数値の羅列をグラフやアニメーションとして我々に見やすい,理解しやすいものとすることです.この演習のはじめの数回で,GLSCというグラフィクスライブラリの使い方を覚えてもらいます.計算数学演習では,gnuplotというできあいのソフトウェアを用いて,数値データをグラフ化してもらいましたが,今回は,グラフの描画それ自体を自分でやってもらいます.実は,この演習で扱う偏微分方程式については,その解の振る舞いをアニメーションとして見る事がその解に関する理解を助ける事となります.そのような用途には gnuplot は少々不向きです.
演習序盤(今週から2,3回程度)はC言語に関する確認と、GLSCグラフィックスライブラリの使い方の演習を行います。
その後、C言語およびGLSCグラフィックスライブラリを使いこなせるようになりましたら、まずは授業で紹介される常微分方程式を数値計算を用いて解いてもらいます。最終的には、熱方程式(拡散方程式とも呼ばれる)や波動方程式といった偏微分方程式を数値計算で解いてもらい、結果を可視化してもらいます。
演習では、数値計算法の習得も目標の一つではありますが、数値計算の必要性や、それを道具として使うという姿勢について、ある程度理解してもらえればと思います。
演習のホームページのトップに「お知らせ」という項目があります。そこには、レポートの回収状況やその他大事なお知らせを載せますので、毎週必ず見てください。
計算数理A演習では GLSC というグラフィックスライブラリ(画面上に絵を描く為の関数集)を使いますが、利用に先立ちその準備として、次の作業が必要となります。(この作業は情報メディア教育研究センターでGLSCを使う場合の作業であって、一般的なものではありません。)
注意:GLSCという新たなプログラミング言語を使うわけではありません。GLSCはC言語を拡張するライブラリで、C言語から使える紙と鉛筆のイメージです。GLSCを用いると、C言語によるプログラミングで絵を描く事ができます。
まずはホームディレクトリの .bashrc (先頭のピリオドを忘れないように)ファイルをテキストエディターで開きます。(ファイル名がピリオドで始まるファイルは標準状態では見えないようになっていることがあります)。 .bashrc ファイルが無い人は新規に作成します。 .bashrc ファイルが既にある人は以下の一行をそのファイルの最後に挿入し、保存します。 .bashrc ファイルが無かった人は、以下の一行を書き込み、保存します。
PATH=$PATH:/home/user5/daishin/bin
最後に必ず改行を入れてください。
ターミナルを開いている人は一旦を閉じ、再度開いて、
which cglsc
とします。
/home/user5/daishin/bin/cglsc
と表示されれば成功です。
なにも出力されない人は、次の手順に従ってください。
ホームディレクトリの .cshrc (先頭のピリオドを忘れないように)ファイルをテキストエディターで開きます(ファイル名がピリオドで始まるファイルは標準状態では見えないようになっていることがあります)。 .cshrc ファイルが無い人は新規に作成します。 .cshrc ファイルが既にある人は以下の一行をそのファイルの最後に挿入し、保存します。 .cshrc ファイルが無かった人は、以下の一行を書き込み、保存します。
set path=($path . /home/user5/daishin/bin)
最後の閉じカッコの後に必ず改行を入れてください(途中のピリオドも忘れずに)。
ターミナルを開いている人は一旦閉じ、再度開いて、
which cglsc
とします。
/home/user5/daishin/bin/cglsc
と表示されれば成功です。
復習の目安として、次の問題を他人に頼ることなくできるかどうかでチェックしてください。自力でできるようであれば、この演習を受けるのに必要なC言語の知識としては十分です。
問題
1000以下の奇数のうち素数であるものを全て求め、それらを画面に表示しかつそれらの和およびあまり意味はないが平均値(実数値)も画面に表示するCのプログラムを作成せよ。
これができないようであれば、問題ありですので、C言語について復習が必要です。(昨年度の計算数学演習のホームページ全12回など参照し、適宜復習してください。)
計算数学演習を受講していない人で、上記問題ができそうにない人は、各人適当なC言語入門をうたった参考書を用いて、C言語を習得するなり、昨年度の計算数学演習のホームページを参考にするなりしてください。可能であれば、昨年度の計算数学演習のホームページ全12回全てに目を通し、途中にある課題も可能な限りやっていただくのが望ましいです。
この演習では、上記問題程度のプログラミングはできるものとして演習を行います。ですから、C言語の文法であるとか、そういった入門的なことは行いません。
C言語で書かれたソースプログラムをコンピューターは直接実行することはできません(機械語に変換されている必要がある)。そこで、ソースプログラムをコンパイル(翻訳)するという作業が必要となります。
C言語で書かれたソースプログラムのコンパイルにはCコンパイラーというソフトウェアを使います。Cコンパイラーというソフトウェアはターミナルと呼ばれるソフトウェア上で実行します。
このように、コンピューター上で何かする場合、あらゆるものがソフトウェアなわけです。今後、混乱が無いようであれば、ソフトウェアという言葉を省略します。
まず、ターミナルを起動します。(ターミナルは端末とよぶこともあります.)
ターミナル上で(ここでは、ソースプログラムが hello.c というファイル名であるとしています)、
cc hello.c -o hello
とすることで、機械語に翻訳されたプログラム hello が生成されます。ソースプログラム中にエラーがある場合(文法上の誤りが大半)画面上にエラーがあるといったメッセージが表示されます。
ここで cc というのがCコンパイラーです。ターミナルでプログラム名を打ち込むことでそのプログラムを実行できるのですが、つまり、ここでは cc というプログラム(Cコンパイラー)を実行しています。
プログラム hello を実行するには、ターミナル上で、
./hello
とします。作成したプログラムを実行するときには、はじめにピリオド、次にスラッシュをつけます。はじめのピリオド、スラッシュは省略できる場合もありますが、当面は必要だと思っておいてください。
./hello
とすることで、プログラムを実行することができます。
上記手順を試してみるためには hello.c というファイル名のC言語のプログラムソースを用意する必要があります。正しいC言語のプログラムソースであれば何でも良いのですが、用意できない人は、下記のソースプログラムを hello.c というファイル名で打ち込んで試してください。
#include <stdio.h>
main()
{
printf("Hello!\n");
}
GLSCは(Graphic Library for Scientific Computing)の略で、C言語でかかれたグラフィックライブラリです。GLSCを用いれば、科学技術計算(この演習で入門的に扱うもの)の結果をディスプレイに表示したり、プリンターに出力したりすることができます。通常、コンピュータに絵を描かせる場合、その予備知識としてかなり多くのことを学ぶ必要があります。GLSCは機能が限定されている分、使い方が簡単で、覚えることも最小限ですみます。より高度なグラフィックスを表示させたい人は、他のライブラリを用いることになるでしょうが、基本をGLSCで学んでおけば、すんなりと習得できるでしょう。
注意: GLSCという言語があるわけではありません。この演習では cglsc コマンドを用いてコンパイルするため、あたかもGLSCという言語があるかのように錯覚する人もいるようですが、この演習で扱うものは全てC言語のプログラムです。後の「GLSCを使ったプログラムのコンパイルの仕方」にあるように、cglsc コマンドは実際には cc コマンドをオプション付きでよびだしているにすぎません。
次のプログラムは、画面上に白いウィンドウを表示するだけのプログラムです。GLSCでは、このウィンドウ内に絵を描くので、ウィンドウの表示は絶対に必要です。表示されたウィンドウは、ウィンドウ内をマウスで左クリックすると消えます。以下のサンプルプログラムをエディターで打ち込み、ファイル名を 0419-1.c として保存してください。コンパイルの方法がこれまでと異なります.後にある説明を見てください。
1: #include <glsc.h>
2: #include <stdio.h>
3:
4: main()
5: {
6: g_init("GRAPH", 100.0, 100.0);
7: g_device(G_DISP);
8: g_sleep(G_STOP);
9: g_term();
10: }
1行目: GLSCを使う場合にはこの #include 文が必要です
6行目: g_init 関数を用いて、絵を描くウィンドウの初期化を行います。第一引数である "GRAPH" は、画面に表示した絵をファイルとして保存する場合に使いますが、当面はこのように "GRAPH" としてください。その後に続く2つの引数は、実数型で、ウィンドウのサイズを指定します。
7行目: g_device 関数で、何に対して表示するかを指定します。画面に表示したいので、このように G_DISP を引数に指定します。
8行目: g_sleep 関数でプログラムの一時停止を行っています。引数として正の実数値またはG_STOPを受けます。引数が正の実数値である場合、その秒数停止します(例えば g_sleep(1.2); であれば1.2秒停止します)。引数が G_STOP である場合、ウィンドウの内部がマウスで左クリックされるまで停止します。
9行目: g_term 関数にてGLSCの処理を終わります。GLSCプログラムの最後に呼ばれます。
GLSCでは画面上に線を表示したりする必要がある為、様々な非標準ライブラリ(標準関数以外の関数の集まり)を使うようコンパイル時に指定する必要があります。その為には、例えば先のプログラムをコンパイルする場合、次のようなコマンドを打ち込む必要があります。
cc -I/usr/X11/include -I/home/user5/daishin/include 0419-1.c -o 0419-1 -L/home/user5/daishin/lib -lglscd -L/usr/X11R6/lib -lX11 -lm
しかし、これをいちいち打ち込むのは面倒なので、GLSCプログラムを簡単にコンパイルするためのコマンドをこちらで用意しました。そのコマンドを利用すると、上記の長いコマンドを打ち込んだ結果と同様の結果が、次の短いコマンドで得られます(先ほど行ってもらったGLSC利用の為の準備は、このコマンドを利用できるようにする為のものでした)。
cglsc 0419-1.c
これにより、実行可能なファイル 0419-1 が生成されます。プログラムはこれまで同様、
./0419-1
で実行され、この場合、次のような真っ白な正方形ウィンドウが画面に表示されます。
ウィンドウ内(白い部分)をマウスで左クリックすることで、ウィンドウが消えます。
GLSCのマニュアルは、この演習のホームページのトップページからリンクされています。関数の使い方が良く分からない場合は、マニュアルを参照してください。
先のプログラム例の6行目で呼ばれている g_init 関数では、第2、第3引数でウィンドウの大きさを指定することができると説明しました。実際に、その数値を変更してウィンドウのサイズがどうかわるか見てみましょう。
次の各場合についてコンパイル実行してみてください。
g_init("GRAPH", 100.0, 200.0);
g_init("GRAPH", 300.0, 200.0);
GLSCには、標準座標系と仮想座標系という二つの座標系が存在します。ここではまず、標準座標系について説明します。
標準座標系は、例えば g_init("GRAPH", 200.0, 100.0) と初期化されたウィンドウでは次の図のようになります。
つまり、左上が座標 (0.0, 0.0) であり、右下が (200.0, 100.0) となるような座標系です。
GLSCでは g_text 関数にて文字をウィンドウ内に表示することができます(残念ながら漢字は表示できません)。例えば、次のプログラムでは、画面ウィンドウ内に Hello! と表示します。
#include <glsc.h>
#include <stdio.h>
main()
{
g_init("GRAPH", 100.0, 100.0);
g_device(G_DISP);
g_text(0.0, 10.0, "Hello!");
g_sleep(G_STOP);
g_term();
}
g_text 関数の第一、第二引数はウィンドウ上の標準座標系での座標です。コンパイルし実行すると、次のようになります。
実行結果
次のプログラムでは Hello! と GLSC という文字列をそれぞれ異なる場所に表示します。
#include <glsc.h>
#include <stdio.h>
main()
{
g_init("GRAPH", 100.0, 100.0);
g_device(G_DISP);
g_text(0.0, 10.0, "Hello!");
g_text(10.0, 20.0, "GLSC");
g_sleep(G_STOP);
g_term();
}
実行結果
g_text_color 関数を使って、文字に色をつけることもできます。
#include <glsc.h>
#include <stdio.h>
main()
{
g_init("GRAPH", 100.0, 100.0);
g_device(G_DISP);
g_text_color(G_RED);
g_text(0.0, 10.0, "Hello!");
g_text(10.0, 20.0, "GLSC");
g_sleep(G_STOP);
g_term();
}
実行結果
g_text_color 関数を使って、文字の色を変えると、その後 g_text 関数で表示する文字全てに適応されます。例えば GLSC は黒で表示したい場合は次のよう改めて黒と指定する必要があります。
#include <glsc.h>
#include <stdio.h>
main()
{
g_init("GRAPH", 100.0, 100.0);
g_device(G_DISP);
g_text_color(G_RED);
g_text(0.0, 10.0, "Hello!");
g_text_color(G_BLACK);
g_text(10.0, 20.0, "GLSC");
g_sleep(G_STOP);
g_term();
}
実行結果
g_text_color の引数には色を指定しますが、GLSCでは以下の8色を使うことができます。
color | カラーディスプレイ | |
---|---|---|
番号 | マクロ | |
0 | G_BLACK | 黒 |
1 | G_RED | 赤 |
2 | G_GREEN | 緑 |
3 | G_BLUE | 青 |
4 | G_MAGENTA | マゼンタ |
5 | G_YELLOW | 黄 |
6 | G_CYAN | シアン |
7 | G_WHITE | 白 |
例えば、黄色で文字列を描画したい場合は、
g_text_color(G_YELLOW);
または
g_text_color(5);
とします(どちらの指定方法でもよい)。後者の指定方法は、例えば次のようなプログラムでは大変有用です。g_text_color 関数の使い方をよく見てください.
#include <glsc.h>
#include <stdio.h>
main()
{
int i;
g_init("GRAPH", 100.0, 100.0);
g_device(G_DISP);
for(i = 0; i < 8; i++)
{
g_text_color(i);
g_text(0.0 + i*10, 10.0 + i*10 ,"Hello!");
}
g_sleep(G_STOP);
g_term();
}
実行結果
白色で描画された最後の Hello! は背景色と同じである為見えません。
g_cls 関数を用いると、ウィンドウ内を消去することができます(後に紹介する四角形を表示する関数がありますが,g_cls関数は標準座標系全体を覆うような白塗りの四角形を描くのと同様の動作をします)。次のプログラムでは、カラフルに Hello! を表示したのちとまります(一つ目の g_sleep(G_STOP))。マウスのクリックをすることで g_cls 関数が実行され、画面が消去され、再びとまります(二つ目の g_sleep(G_STOP))。動作を確かめてください。
#include <glsc.h>
#include <stdio.h>
main()
{
int i;
g_init("GRAPH", 100.0, 100.0);
g_device(G_DISP);
for(i = 0; i < 8; i++)
{
g_text_color(i);
g_text(0.0 + i*10, 10.0 + i*10, "Hello!");
}
g_sleep(G_STOP);
g_cls();
g_sleep(G_STOP);
g_term();
}
文字列をある位置に表示し、しばらくとまった後、画面を消去し、先ほどとは少し違った場所に再び文字列を表示するという一連の作業を繰り返すと、アニメーション効果を得ることができます。ぱらぱらアニメの要領です.
#include <glsc.h>
#include <stdio.h>
main()
{
int i;
g_init("GRAPH", 100.0, 100.0);
g_device(G_DISP);
for(i = 0; i < 100; i = i + 2)
{
g_text_color(i%8);
g_text(0.0 + i, 10.0 + i, "Hello!");
g_sleep(0.05);
g_cls();
}
g_sleep(G_STOP);
g_term();
}
途中の繰り返し文の中で、表示、停止、消去を繰り返しています。
g_text_color の引数は 0〜7 の整数すから、 % 演算子を用いて、その範囲になるようにしてあります。
途中にある g_sleep(0.05); で約 0.05 秒間停止します。これが無いと早すぎてアニメーションに見えません。
例えば、変数に納められた数値を GLSC ウィンドウに表示したい場合は次のように文字列型(文字型の配列)を用いる必要があります。これは今後よく使う事になります.ここにその情報があることはよく覚えておいてください.
#include <glsc.h>
#include <stdio.h>
main()
{
float a;
char text[256];
a = 3.14;
g_init("GRAPH", 100.0, 100.0);
g_device(G_DISP);
sprintf(text, "a = %f", a);
g_text(0.0, 10.0, text);
g_sleep(G_STOP);
g_term();
}
文字型の配列、および sprintf 関数と g_text 関数を組み合わせて使うことで、色々な文字列を表示することができます。 sprintf 関数は、第一引数に文字型配列の名前(この例では text)を書く以外は、printf 関数と同様です(同じ変換文字列が使える)。