計算物理学基礎テキスト - osaka city...

76
計算物理学基礎テキスト (2007年度版) 大阪市立大学 工学部 応用物理学科

Upload: others

Post on 26-Jun-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

計算物理学基礎テキスト

(2007年度版)

大阪市立大学

工学部 応用物理学科

Page 2: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

目 次

1 計算機入門 I 1

1.1 計算物理学 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.2 プログラミング実習 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.3 レポート課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2 計算機入門 II 6

2.1 UNIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2.2 C言語 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.3 xemacs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.4 プログラムの翻訳と実行 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.5 レポート課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

3 グラフィックス入門 12

3.1 gnuplot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

3.1.1 関数のグラフ化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

3.1.2 数値データのグラフ化 . . . . . . . . . . . . . . . . . . . . . . . . . 13

3.2 レポート課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

4 C言語の文法 I 17

4.1 配列 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

4.2 IF文 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

4.3 レポート課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

5 C言語の文法 II 22

5.1 関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

5.2 引数のほかに持ち帰る値がない場合 . . . . . . . . . . . . . . . . . . . . . . 24

5.3 配列の受け渡し . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

5.4 C++によるプログラムの翻訳の方法 . . . . . . . . . . . . . . . . . . . . . 26

5.5 レポート課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

6 一階常微分方程式 28

6.1 常微分方程式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

6.2 関数プロトタイプ (原型)宣言 . . . . . . . . . . . . . . . . . . . . . . . . . 30

6.3 レポート課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

7 二階常微分方程式 33

7.1 連立微分方程式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

7.2 シンプレクティック数値積分法 . . . . . . . . . . . . . . . . . . . . . . . . . 34

7.3 2次元運動 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

7.4 レポート課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

i

Page 3: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

8 モンテカルロ法 I 40

8.1 乱数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

8.2 モンテカルロ積分 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

8.3 レポート課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

9 モンテカルロ法 II 46

9.1 カノニカル分布 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

9.2 インポータンス・サンプリング . . . . . . . . . . . . . . . . . . . . . . . . 46

9.3 メトロポリス法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

9.4 自由スピン系のモンテカルロ・シミュレーション . . . . . . . . . . . . . . 48

9.4.1 パラメータの定義 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

9.4.2 スピン変数の配列宣言と初期化 . . . . . . . . . . . . . . . . . . . . 48

9.4.3 モンテカルロ・ステップ . . . . . . . . . . . . . . . . . . . . . . . . 48

9.4.4 エネルギーの測定 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

9.4.5 統計平均の算出 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

9.5 レポート課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

10 データ処理 52

10.1 ファイル入出力 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

10.2 最小二乗法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

10.3 レポート課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

A 値渡し 58

A.1 関数で作業を分担 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

A.2 レポート課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

B アドレス渡し 65

B.1 ポインタ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

B.2 配列の受け渡し . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

B.3 レポート課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

参 考 書 73

ii

Page 4: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

1 計算機入門 I

1.1 計算物理学

 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

(Computational Physics)という第3の新しい分野が登場してきた。理論物理学では、物質

のもつ特徴を抽出してモデル化し、結論を演繹的に導き出す。実験物理学では、物質その

ものを対象として、測定データを集め、それを理論と照合する。これらに対して、計算物

理学では、物質をモデル化する点は理論物理学と同じであるが、計算データを集めそれを

理論と照合する点は実験物理学に似ている。

 計算物理学の役割としては、次のことが考えられよう。通常の実験では、試料の不均一

性や、測定誤差などの影響で、完璧に正しい結果を得ることは不可能であるが、計算物理

学は理想的な実験環境を計算機上に作り上げることができる。また、実験室では超高圧や

超低温などの環境を作ることには限界があるが、計算機上では極限環境を仮想的に作るこ

とができる。また、理論的推論を進めるときには、難しい問題の場合には、なかなか見通し

がつかないものである。そんな時には、先ず計算機で数値的な答えを出すことにより、解

析的な答えに対して”当たりをつける”ことができる。

 プログラミングに慣れてくれば、下図に示すような「樹氷成長のシミュレーション」1)の

プログラムも割合簡単に作成できるようになる。

1)計算機上での仮想実験のことをシミュレーションと呼ぶ。

1

Page 5: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

1.2 プログラミング実習

計算機に仕事をさせるには、プログラムの作成 (編集)、翻訳、実行という手順をふみます。

まず

xemacs & Enter

と入力してみてください。新しいウインドウが開き、プログラムの編集をするためのエディ

タが起動されます。ここで、Ctrlキーと xを同時に押し、次に Ctrlキーと fを同時に押し

て下さい。エディタの最下行に Find file:∼/ と表示されたら、編集したいファイル名 (例

えば example1.c) を入力して下さい。エディタの下から2行目に Emacs: example1.c と表

示されれば OKです。

このエディタで次のようなプログラムを作成してみて下さい。

#include <math.h>

#include <stdio.h>

int main(void)

{

int i;

for ( i = 0; i < 10; i++ ) {

printf( "%d %d \n", i, i*i );

}

}

行頭をずらすには Tabキーを使うのが良いでしょう。プログラムを保存するには、Ctrlキー

と xを同時に押し、次にCtrlキーと sを同時に押して下さい。ウインドウの最下行にWrote

... と表示されれば OKです。

次にプログラムの翻訳をしましょう。最初のウインドウで

cc example1.c -lm Enter

と打てばいいです。何も表示されなければ翻訳は成功です。エラーメッセージが表示され

たら、プログラムのどこかにミス (バグ)があるはずなので、チェックしてみて下さい。

最後はプログラムの実行です。やはり、最初のウインドウで

./a.out Enter

2

Page 6: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

と打てばいいです。正しい結果が画面に表示されましたか?

次に、下記のような三角関数の表を作ってみましょう。

x sin(x) cos(x) tan(x)

0 0.000000 1.000000 0.000000

5 0.087156 0.996195 0.087489

10 0.173648 0.984808 0.176327

15 0.258819 0.965926 0.267949

20 0.342020 0.939693 0.363970

25 0.422618 0.906308 0.466308

30 0.500000 0.866025 0.577350

35 0.573576 0.819152 0.700208

40 0.642788 0.766044 0.839100

45 0.707107 0.707107 1.000000

50 0.766044 0.642788 1.191754

55 0.819152 0.573576 1.428148

60 0.866025 0.500000 1.732051

65 0.906308 0.422618 2.144507

70 0.939693 0.342020 2.747477

75 0.965926 0.258819 3.732051

80 0.984808 0.173648 5.671282

85 0.996195 0.087156 11.430052

90 1.000000 0.000000 557135115.020977

先程のプログラムを別のファイルにコピーします。最初のウインドウで

cp example1.c example2.c Enter

とタイプします。これで example1.c の中身がそのまま example2.c にコピーされました。

エディタの画面でファイル example2.c を開きます。そのためには、Ctrlキーと xを同時に

押し、次に Ctrlキーと fを同時に押すのでしたね。エディタの最下行に Find file:∼/ と表

示されたら、example2.c と打ちます。では、このエディタ画面で次のプログラムを編集し

て下さい。

3

Page 7: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

#include <math.h>

#include <stdio.h>

int main(void)

{

int i;

double x, pi;

pi = 3.14159265;

for ( i = 0; i <= 90; i = i + 5 ) {

x = i * pi / 180;

printf( "%2d %f %f %f\n", i, sin(x), cos(x), tan(x) );

}

}

プログラムを保存するのは、Ctrl+x, Ctrl+s でした。

翻訳するには、最初のウインドウで

cc example2.c -lm Enter

と入力するのでした。

プログラムの実行は

./a.out Enter

でした。うまく表示されましたか?

4

Page 8: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

1.3 レポート課題

課題 下図のような 1 から i までの総和 sum(i) と i の階乗 fact(i) の表を作って下さい。

sum, fact は C の関数にはありません。sum を求めるには、まず初期値に sum = 0 と置

き、それに i = 1 から 10 まで加えていきます。fact を求めるには fact = 1 と置き、そ

れに i = 1 から 10 までかけていきます。

i sum(i) fact(i) <-- この行は印字しなくてよいです

1 1 1

2 3 2

3 6 6

4 10 24

5 15 120

6 21 720

7 28 5040

8 36 40320

9 45 362880

10 55 3628800

発展課題 台形公式を用いて積分 Z π/2

0sin xdx

の近似値を計算して下さい。区間 [0,π/2] を 100等分ぐらいするのが良いでしょう。

印刷の方法report1.c というファイルを印刷するには、最初の画面で

a2ps -1 report1.c Enter

とタイプします。2)プログラムを印刷して提出して下さい。

2)a2ps はテキストファイルを印刷するコマンド (命令)です。 -1 のようにコマンドに付け足してコマンド

の動作を制御するものをオプション (付録)といいます。この例の場合、1枚の用紙に1ページだけ印刷する

という意味です。

5

Page 9: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

2 計算機入門 II

2.1 UNIX

計算機と人間の橋渡しをするのがオペレーティングシステムです。略して OSです。昔は、

大型計算機の OSは IBM互換 OS、ワークステーション (中型計算機)は UNIX、パソコン

はMS-DOSでした。最近のパソコンはWindowsやMacが多いですね。一方、UNIXは大

型計算機からパソコンまで幅広く使われるようになってきました。UNIX は 1969 年にア

メリカの AT&T ベル研究所で誕生しました。生みの親は Ken Tompson、Dennis Ritchie

の2人です。計算機実習で使っている LINUX は UNIX の一種で、フィンランドの Linus

Torvalds を中心とする多数のボランティアにより開発されました。LINUX は無料配布さ

れているにもかかわらず、非常に良くできた OSになっています。

では、UNIXの命令 (コマンド)について少し説明をしておきましょう。まず、画面の形を

したアイコンをダブルクリックして、ターミナルウィンドウを開きます。次に、

ls Enter

と入力してみて下さい。3)いくつかのファイル名が表示されましたね。そうです、lsはファ

イル名を表示するためのコマンドなのです。

次に、別のコマンドを試してみましょう。

cat report1.c Enter

と入力してみて下さい。4) report1.cのファイルの中身が表示されましたね。cat はファイ

ルの中身を表示するコマンドです。

先週使った、cp もコマンドの一つです。

cp report1.c report2.c Enter

と打つと、report1.c の中身がそのまま report2.c にコピーされます。

その他に、rm というコマンドもよく使います。

rm report2.c Enter

3)LSではエラーになります。UNIXでは大文字と小文字は別の文字として区別します。4)”report1.c”の部分には存在するファイル名をタイプして下さい。

6

Page 10: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

と打つと、ファイル report2.c が消えます。rm はファイルを消去するコマンドなのです。

でも、うっかりrmを使って、大切なファイルを消してしまわないようにしましょう。いっ

たん消去してしまったファイルを復元させることはできませんので。

ここで UNIXの主要コマンドをまとめておきましょう。

ファイル名を表示する (list) ls

file の中身を表示する (catenate) cat file

file1 を file2にコピーする (copy)   cp file1 file2

file を消去する (remove) rm file

file1 を file2 に移動する (move) mv file1 file2

ディレクトリ dir を作成する (make directory) mkdir dir

ディレクトリ dir に移動する (change directory) cd dir

2.2 C言語

プログラムを作成するには言語を用います。普通の言語に日本語、英語、ドイツ語などた

くさんの種類があるのと同じように、計算機の言語にもいくつかの種類があります。1年

生の時に応物概論で習った BASICは比較的簡単な言語です。物理の研究者は FORTRAN

という言語をよく使います。この講義では、しょうらい大規模なプログラムを開発すると

き役立つように、Cという言語を使うことにします。またC言語を学んでおくことは、情

報処理関連の国家資格を取得を目指すときにも有利になります。

7

Page 11: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

それでは、C言語の文法を少し勉強することにしましょう。前回の例1のプログラムをも

う一度調べてみましょう。

#include <math.h>

#include <stdio.h>

main() (1) プログラム単位 main の開始

{

int i; (2) 整数型変数 i を宣言します

for ( i = 0; i < 10; i++ ) { (3) ループを繰り返します

printf( "%d %d \n", i, i*i); (4) i と i*i を端末に表示します

}

}

1. プログラム単位 main の開始を表します。main のすぐ下の { から 最終行の } までが

プログラムの1単位になります。 C言語のプログラムには main という名前のプロ

グラム単位が必ず1つ含まれていなければなりません。

2. プログラムに登場する変数はプログラムの先頭で必ず宣言しておきます。変数には大

きく分けて、整数型 (小数点をもたない数)と実数型 (小数点をもつ数)の2種類があ

ります。文の終りには必ず ; (セミコロン) を付けて下さい。

3. { と } で囲まれた部分を繰り返します。最初は i = 0 で、一回繰り返す度に、i に 1

を加えます。 i++ の部分は i = i + 1 と書いてもかまいません。 i < 10 を満たす

間は、ループを繰り返します。この場合の繰り返し回数は10回ですね。

4. ” と ” で挟まれた部分を書式といいます。 このスタイルで表示しなさいということ

です。 %d は整数型変数の数値を表示するときに用います。上の例では%dと%dの

間に空白が4個あるので、9____81のように表示されます。5) 書式の最後の \n は改

行を表すための特別な表記です。6)\n を付け忘れたらどうなるか試してみて下さい。

C言語のプログラムには、空白や空行をどれだけ入れても構いません。空白や空行を適度

に入れて、見やすいプログラムを書くように心がけましょう。次に、例2のプログラムを

見てみましょう。

5) は画面では空白です。6)日本語キーボードでは、\を打つには¥をタイプします。

8

Page 12: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

#include <math.h>

#include <stdio.h>

main()

{

int i; (1) 整数型変数 i を宣言します

double x, pi; (2) 実数型変数 x と pi 宣言します

pi = 3.14159265; (3) pi に値を代入します

for ( i = 0; i <= 90; i = i + 5 ) { (4) ループを繰り返します

x = i * pi / 180; (5) x に i * pi / 180 を代入します

printf("%2d %f\n", i, sin(x)); (6) i, sin(x) の値を端末に表示します

}

}

1. プログラムで使う変数はプログラムの先頭で宣言します。

2. 小数点をもつ実数型の変数は double と宣言します。変数名は先頭の文字がアルファ

ベットでなければなりません。x0 は良いですが、 0x は駄目です。

3. これはいいですよね。

4. { と } で囲まれた部分を繰り返します。最初は i=0 で、ループを一回繰り返す度に、

i に 5 を加えます。i が 90 以下である間はループを繰り返します。”以下” は <= で

表します。”以上” は >= ですね。

5. 180 は整数型の定数です。右辺は整数型 i, 180 と 実数型 pi が混じっていますね。こ

のような場合は、整数型は実数型に昇格して、実数型どうしとして演算されます。で

すから i * pi / 180 の値は実数型です。

6. %f は実数型変数の数値を表すとき使います。7) %2dは出力のためのスペースを2文

字ぶん確保して、右詰めで数値を出力します。書式の最後には \n を忘れずに付けま

しょう。

7)実数型の場合には %15.7e のような書式もあります。この場合は、出力のためのスペースを15文字ぶ

ん確保して、有効数字7桁で右詰めで出力します。例えば 1.2345678 × 1019 の場合は 1.2345678e+19と

表示されます。

9

Page 13: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

2.3 xemacs

この講義ではエディタとして xemacs を使用します。xemacs は多くの機能を備えている

ため、UNIX の標準エディタになっています。xemacs を起動してエディタ画面を開くため

には、

xemacs & Enter

と入力して下さい。次に、xemacs のコマンドをまとめておきましょう。8)

ファイルを読み込む Ctrl+x Ctrl+f

カーソルの位置に別のファイルを差し込む   Ctrl+x i

ファイルを保存する Ctrl+x Ctrl+s

カーソルの現在位置から行末までを削除する Ctrl+k

Ctrl+kで削除した行を現在位置に復活させる Ctrl+y

2.4 プログラムの翻訳と実行

計算機に仕事をさせるにはプログラムの作成 (編集)、翻訳、実行という手順を踏みます。

ここでは翻訳と実行の方法をまとめておきましょう。

report2.c という名のプログラム翻訳   cc report2.c -lm Enter

プログラムの実行 ./a.out Enter

8) Ctrl+k と Ctrl+y を組み合わせれば、テキストのカット・アンド・ペーストができます。

10

Page 14: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

2.5 レポート課題

課題 1µ1 +

1

n

¶nの値を n = 10, 20, 30, · · · 100 の場合に計算せよ。C言語では、べき関数

ai を pow(a,i) と表す。9)

課題 2 矩形公式を用いて積分 Z 1

0

4

1 + x2dx

の近似値を計算せよ。区間 [0, 1] を 20等分ぐらいするのが良い。余裕があれば台形公式を

用いた計算も行え。

課題 3 nÀ 1 のときに成り立つスターリングの近似公式

log n! ≈ n log n− n+ 12log(2πn)

を n = 100 のときに確かめよ。左辺を計算するときには、階乗そのものを計算するのでは

なく、10)

log n! =nXi=1

log i

を使って、log(i) の総和を計算するのが良い。

発展課題

次の漸化式で与えられるフィボナッチ数列を第3項から第25項まで求めよ。さらに、隣

り合った項の比の値 ai+1/ai が黄金比 (1 +√5)/2 = 1.618 · · · に近づくことを確かめよ。

ai+2 = ai+1 + ai, a2 = a1 = 1

印刷の方法report2.c というファイルを印刷するには、ターミナル・ウインドウで

a2ps -1 report2.c Enter

とタイプします。プログラムを印刷して提出して下さい。

9)べき関数は、BASIC では aˆi、FORTRANでは a∗∗i である。10)階乗の値はとてつもなく大きくなってしまう。

11

Page 15: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

3 グラフィックス入門

3.1 gnuplot

今回はグラフィックスの練習をします。ここではワークステーションや PCでよく利用さ

れている gnuplot というソフトを使うことにします。まず、ターミナル・ウインドウを1

つ余分に開いてください。そして、

gnuplot Enter

と入力してみてください。11) そうすると、数行のメッセージのあとで

gnuplot>

というプロンプト (入力促進記号)が表示されるはずです。

3.1.1 関数のグラフ化

それでは、三角関数 sinx を表示してみましょう。

gnuplot> plot sin(x)

と入力してください。うまく表示されましたか? xの範囲を —6 から 6 までにするには

gnuplot> plot [-6:6] sin(x)

とします。12)さらに、縦軸を —2 から 2 までにするには

gnuplot> plot [-6:6] [-2:2] sin(x)

と入力します。y = sin x と y = x− x3/6 を同時に表示するためには

gnuplot> plot [-6:6] [-2:2] sin(x), x - x**3 / 6

とします。13)

gnuplot を終了するには

gnuplot> quit

と打ちます。14)

11)xemacsの場合と違って、gnuplot の後ろに & を付けるとエラーになります。12)以前に打ったコマンドを再び表示するには ↑ キーを押します。 Ctrl+p でも同じ動作をします。13)gnuplot では、x3 を フォートランのように x**3 と書きます。14)gnuplot> exit と打っても構いません。

12

Page 16: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

3.1.2 数値データのグラフ化

gnuplot は数値データをグラフ化することもできます。そのために、まず、数値データを書

き込んだファイルを作成します。例2のプログラムを書き直すことにします。

#include <math.h>

#include <stdio.h>

main()

{

int i;

double x, pi;

FILE *fp; /* (1)ファイル型構造体 fp を宣言します */

pi = 3.14159265;

fp = fopen( "a.dat", "w" ); /* (2)ファイルを開きます */

for ( i = 0; i <= 180; i++ ) {

x = i * pi / 180;

fprintf( fp, "%f %f\n", x, sin(x) ); /* (3)ファイルに出力します */

}

fclose(fp); /* (4)ファイルを閉じます */

}

1. ファイルを操作するには、ファイル1つに対してファイル型の構造体を1つ宣言しま

す。∗ はポインタを表しますが、今はおまじないと思っておいて下さい。fp を2つ

以上宣言すると、複数のファイルに書き込むことができます。

2. 関数 fopen でファイル a.dat を開きます。"w" は書き込みモードであることを表し

ます。書き込みモードの場合、ファイルが既に存在すれば上書きし、存在しなければ

新規に作成します。読み込みモードは "r"、追加モードは "a" です。

3. 関数 fprintf でファイルに出力します。fprintf の第一引数はファイル・ポインタ

です。そのほかの引数は、先週まで出てきた関数 printf と同じです。15)

4. ファイル出力が終ったら、関数 fclose でファイルを必ず閉じて下さい。

プログラムが作成できたら、翻訳と実行を行って下さい。

15)出力先を画面に指定するファイル・ポインタ stdoutがデフォルトで用意されています。ですから、fprintf(

stdout, "%f %f\n", x, sin(x) ) は printf( "%f %f\n", x, sin(x) ) と同じ働きをします。

13

Page 17: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

cc example3.c -lm Enter

./a.out Enter

コマンド ls で a.dat というファイルが作成されていることを確認して下さい。さらに、

cat でファイル a.dat の中身を画面に表示してみて下さい。

ls Enter

cat a.dat Enter

データファイル a.dat をグラフに表示するには、まず、gnuplot を起動します。16) 次に、

gnuplot のプロンプトに対して、

gnuplot> plot "a.dat"

と入力して下さい17)。データポイントを直線で結ぶには

gnuplot> plot "a.dat" w l

とします。うまく表示されましたか?18)

16)ターミナル・ウインドウで gnuplot と打ちます。17)"a.dat" は ’a.dat’ でも構いません。18) w l は with lines の省略形です。

14

Page 18: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

3.2 レポート課題

課題 1

y = sin(x) + sin(3x)/3 + sin(5x)/5 を2通りの方法でグラフ化して下さい。

• 関数を直接グラフ化する。

• 数値データを書き込んだファイルを作成後、グラフ化する。

数値データを用いる方法では、−10 < x < 10 を 200 等分くらいするのがよいでしょう。

課題 2

次の関数をグラフにして下さい。for ループは二重構造にすることができます。

1. y =100Xj=0

sin ((2j + 1)x)

2j + 1(−10 < x < 10)

2. y = x100Yj=1

(1− x2

j2π2) (−4π < x < 4π)

3. y =12Xj=0

xj

j!(0 < x < 4)

15

Page 19: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

印刷の方法y = sin(x) のグラフをファイルに出力したり、画面表示に戻したりするには次のようにし

ます。

|gnuplot> set terminal postscript

|gnuplot> set output "report3.ps"

|gnuplot> plot sin(x)

ファイル report3.ps に出力19)

|gnuplot> set terminal x11

|gnuplot> plot sin(x)

画面に出力

|gnuplot> set terminal postscript

|gnuplot> set output "report3_2.ps"

|gnuplot> plot "a.dat" w l

ファイル report3_2.ps に出力

ポストスクリプト・ファイルをプリントするには、ターミナル・ウインドウで

ls Enter

と打って、report3.ps というファイルが存在することを確認します。次に、

ghostview & Enter

で 画像表示ソフト ghostview を起動します。マウスで Open をクリックして、表示した

いポストスクリプト・ファイル (report3.ps) をダブルクリックで選びます。グラフを印

刷するには Print All ボタンをクリックします。

16

Page 20: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

4 C言語の文法 I

今回は配列と if文について学習します。

4.1 配列

まず、配列について学習します。5人の学生の平均点を計算するプログラムは次のように

なります。

プログラム例4-1

#include <math.h>

#include <stdio.h>

int main(void)

{

double x, y, z, w, u; /* (1) 学生の人数分の変数を宣言します */

double sum, mean;

x = 80;

y = 70;

z = 60;

w = 90;

u = 70;

sum = x + y + z + w + u; /* (2) 合計点を計算します */

mean = sum / 5;

printf( "%f\n", mean );

}

1. もし 人数が 100人になったら、100個の変数を宣言しなければなりません。

2. 人数が増えると、この式も長くなって、書くのが面倒になります。

人数が増えると面倒になりますね。そんなとき、複数の変数を一つにまとめてしまう方法

があります。それが「配列」です。配列は、同じタイプの変数を、一つの「チーム」にまと

め、ひとつひとつの変数を「背番号」で区別するようなものです。具体例を見てみましょ

う。配列を使ってさきほどのプログラムを書き直すと次のようになります。

17

Page 21: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

プログラム例4-2

#include <math.h>

#include <stdio.h>

int main(void)

{

double x[5]; /* (1) 5個の変数をまとめて宣言します */

double sum, mean;

int i;

x[0] = 80; /* (2) 配列に数値を代入します */

x[1] = 70;

x[2] = 60;

x[3] = 90;

x[4] = 70;

sum = 0; /* (3) 変数 sum を初期化します */

for ( i = 0; i < 5; i++ ) {

sum = sum + x[i]; /* (4) 合計点を計算します */

}

mean = sum / 5;

printf( "%f\n", mean );

}

1. 5個の実数型変数をまとめて宣言します。いまの「チーム名」は x です。 100個の

変数を宣言したければ、 double x[100]; と書きます。

2. x の後ろの [ ] の中の数字が「背番号」です。この「背番号」のことを添字 (そえじ)

と呼びます。添字は 0 から始まることに注意してください。20) この例のように配列

のサイズが 5 のときは、x[0] x[1] x[2] x[3] x[4] の 5個の変数を使えます。

3. sum に 0 を代入して初期化します。

4. x[i] は配列の i+1 番目の要素を表します。添字 i は整数型でなければなりません。

この式は sum += x[i]; と書いても構いません。

20)BASIC や FORTRAN では添字は 1 から始まりますが、C言語では 0 から始まります。

18

Page 22: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

4.2 IF文

次に、if文について説明します。これも具体例を挙げたほうが早いので、次のプログラム

を見てみて下さい。これは整数の絶対値を求めるプログラムです。

プログラム例4-3

#include <math.h>

#include <stdio.h>

int main(void)

{

int a;

a = - 10;

if ( a < 0 ) { /* (1) a < 0 ならば { } の中の文を実行します */

a = - a; /* (2) a の符号を変えます */

}

printf( "%5d\n", a );

}

1. もし ( ) の中の条件式が真ならば (この例では a が負の場合)、{ } の中の文を

実行します。この例のように実行文が1つだけのときは、両カッコ{ }を省略して

も構いませんが、if文の範囲をはっきりさせるためにカッコをつける習慣をつけてお

いたほうが良いでしょう。

2. a = - a は a = ( - 1 ) * a と同じ意味です。

プログラム例をもうひとつ挙げてみましょう。2つの整数を比較して、大きい方を出力す

るプログラムは次のようになります。

19

Page 23: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

プログラム例4-4

#include <math.h>

#include <stdio.h>

int main(void)

{

int a, b, c;

a = 10;

b = 20;

if ( a > b ) { /* (1) a > b ならば { } の中の文を実行します */

c = a;

}

else { /* (2) そうでなければ ( a < b または a = b ならば)

else の次の { } の中を実行します */

c = b;

}

printf( "%10d\n", c );

}

1. もし、 ( ) の中の条件式が真ならば、 { } の文が実行されます。条件式には、

他に a == b (aと bが等しい)21)、 a != b (aと bが等しくない)、 a >= b 、

a <= b などがあります。

2. ( ) の中の条件式が偽ならば、 else の後ろの { } が実行されます。プログラム

例4-3のように、 ( ) の中が偽のときに何も実行しなくてよいのであれば、else

以下の文を省略します。

21) a = b ではありません。間違えやすいので注意してください。

20

Page 24: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

4.3 レポート課題

課題 1 プログラム例4-2のデータについて、標準偏差と分散を計算せよ。確率変数 X

の平均を X̄ ≡ hXi と略記すると、h(X − X̄)2i = hX2i − hXi2 となる。 C言語では a の

平方根は sqrt( a ) で計算できる。

課題 2 次の漸化式で表される数列を第20項まで計算せよ。

xi+1 = (yi + zi)/2, yi+1 = (zi + xi)/2, zi+1 = (xi + yi)/2

初期値 x0, y0, z0 は好きな値にとってよい。i が大きくなるに連れて xi, yi, zi がすべて同じ

値 (x0 + y0 + z0)/3 に収束することを確かめよ。 x, y, z の3種類の実数型配列を使うのが

良いでしょう。配列のサイズは多少おおきめに宣言しておいても大丈夫です。

課題 3 方程式 tan x− 1 = 0 の解として π/4 の値を求めてみましょう。f(x) = tan x− 1とすると、 f(0) = −1 < 0, f(1) = tan 1 − 1 = 1.557 − 1 > 0 なので、f(x) = 0 の解は 0

と 1 の間にあることがわかります。解の存在範囲の下限を x min、上限を x max とします。

最初は x min=0, x max=1 です。x min と x max の中点を x mid とします。

f(x min)× f(x mid) < 0 f(x min)× f(x mid) ≥ 0

もし左側の図のようになっていれば、f(x) = 0 の解は x min と x mid の間にあるわけで

すから、 x max を x mid で置き換え、一方 x min の方はそのままにします。逆に右側の図

のようになっていれば、f(x) = 0 の解は x mid と x max の間にあるので、x min を x mid

で置き換え、x max はそのままにします。こうすると、計算を1回するたびに解の存在範

囲が半分になるので、この方法は二分法 (bisection method) と呼ばれています。このプロ

グラムを作成して、π の値の存在範囲を求めて下さい。繰り返し回数は 20 回位でよいで

しょう。

21

Page 25: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

5 C言語の文法 II

5.1 関数

今回は関数について学習します。プログラムが短いうちは良いのですが、プログラムが長

くなってくると、全体のプログラムをいくつかの部品に分割した方が読みやすくなります。

C言語ではこの部品のことを「関数」と言います。22)例として2つの変数のうち大きい方

を出力するプログラムを考えましょう。「2つの変数のうち大きい方を選ぶ」という部分を

ひとつの部品にしてみます。

#include <math.h>

#include <stdio.h>

int max_of ( int& a, int& b ) /* (1) 関数 max_of を宣言します */

{

int max; /* (2) 局所変数 max を宣言します */

if ( a > b ) {

max = a;

}

else {

max = b;

}

return ( max ); /* (3) 変数 maxの値を持ち帰ります */

}

int main ( void ) /* (4) main も一つの関数です */

{

int a, b, c;

a = 2;

b = 5;

c = max_of ( a, b ); /* (5) 関数 max_ofを呼び出します */

printf( "%10d\n", c );

}

22)BASIC や FORTRAN では 「関数副プログラム」や「サブルーチン」と呼ばれています。

22

Page 26: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

1. 関数 max_of を宣言します。main プログラムから関数を呼び出すときに、二つの変

数 a と b を関数に渡します。関数側での変数を仮引数といいます。仮引数は、( )

の中に、型名を付して宣言します。23) & はおまじないと思っておいて下さい。

この関数が終了して main プログラムに戻るときには、整数型変数 max の値を持ち

帰るので、関数宣言 max_of の先頭に変数 max の型である int を付けておきます。

この例では a と b の値も持ち帰ります。

2. 関数 max_of の中だけで有効である局所変数 max を宣言します。局所変数は、main

プログラムから関数が呼ばれるときに生まれ、関数が終了すると同時に消滅します。

3. 関数が終了して main プログラムに戻るときに、整数型変数 max の値を持ち帰りま

す。この持ち帰る値のことを「戻り値」と言います。

4. 講義の当初から説明せずにきましたが、main も一つの関数なのです。main は特別な

関数で、C言語のプログラムを実行するときには、この main 関数の部分が最初に実

行されます。ですからC言語のプログラムには main 関数がただ一つあります。

5. 関数 max_of を呼び出します。main プログラムから関数に移るときに二つの変数 a

と b の値を持って行きます。この変数を実引数と言います。実引数と仮引数の変数

名は違っていても構いません。24)

main プログラムの中の実引数 a, b と関数プログラムの中の仮引数 a, b (または x, y ) は強

く結びついています。うっかり関数プログラムの中で a, b (または x, y ) の値を書き換え

てしまうと、main プログラムの a, b も書き変えられてしまうので、注意が必要です。局

所変数については、たとえ変数名が同じであっても、まったく別個のものです。

23)仮引数がないときには ( void ) と宣言します。24)関数を呼ぶ側の変数が実引数、呼ばれる側の変数が仮引数です。この例では実引数と仮引数の変数名は

同じになっていますが、変数名が違っていても結果は変わりません。

23

Page 27: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

5.2 引数のほかに持ち帰る値がない場合

引数以外に持ち帰る値がない場合は関数の先頭に void と宣言しておけばよいです。一つ

の例として、2つの変数を大きい順に並べ変えるプログラムを作成してみましょう。この

プログラムでは、関数の中で仮引数の値を書き換えてしまうと main の実引数の値も書き

変わってしまう、ということを逆手に取って利用しています。

#include <math.h>

#include <stdio.h>

void sort ( int& a, int& b ) /* (1) 関数 sort を宣言します */

{

int c; /* (2) 局所変数 c を宣言します */

if ( a < b ) {

c = a;

a = b; /* (3) 仮引数の値を書き換えます

実引数の値も自動的に書き

b = c; 変えられます */

}

}

int main ( void )

{

int a, b;

a = 2;

b = 5;

sort ( a, b ); /* (4) 関数 sort を呼びます */

printf( "%10d %10d\n", a, b );

}

1. 関数 sort を宣言します。関数の仮引数は a と b です。& はおまじないと思っておい

てください。この関数が終了してmainプログラムに戻るときに a と b の値以外は何

も持ち帰らないので、関数の先頭にvoidと書いてあります。

2. 関数 sortの中だけで有効な局所変数 cを宣言します。これは通常の整数型変数です。

3. 仮引数 a, b の値を書き換えます。同時に実引数 a, b の値も書き換えられます。

4. main プログラムから関数 sort を呼び出します。関数 sort へは、変数 a と b を渡

します。

24

Page 28: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

5.3 配列の受け渡し

次に、配列を受け渡しする例を挙げてみることにします。5人の学生の平均点を求めるプ

ログラムを、関数を使って書くと次のようになります。

#include <math.h>

#include <stdio.h>

double average ( double x[ ] , int& n ) /* (1) 関数 average を宣言 */

{

double sum, mean; /* (2) 局所変数 sum, meanを宣言 */

int i;

sum = 0;

for ( i = 0; i < n; i++ ) {

sum = sum + x[i];

}

mean = sum / n;

return ( mean ); /* (3) 平均値を持ち帰ります */

}

int main ( void )

{

double x[5]; /* (4) 配列を宣言します */

double mean;

int n;

n = 5;

x[0] = 80;

x[1] = 70;

x[2] = 60;

x[3] = 90;

x[4] = 70;

mean = average ( x, n ) /* (5) 関数 averageを呼びます */

printf( "%f\n", mean );

}

25

Page 29: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

1. 関数 average を宣言します。関数が終了してmain プログラムに戻るときに実数値を

持ち帰るので、関数の先頭に double を付けてあります。関数の ( ) の中の仮引数

x[ ] は配列を受け取ることを表します。25)

2. 関数 average の中だけで有効である局所変数 sum と mean を宣言します。

3. 関数が終了して main プログラムに戻るときに、mean の値を持ち帰ります。

4. 大きさ 5の整数型配列を宣言します。こうすれば、5個の整数型変数 x[0], x[1], x[2],

x[3], x[4] を使えるのでしたね。

5. 関数 average を呼び出します。関数には、配列 x と 配列のサイズ n を渡します。関

数 average が終了したときに持ち帰った値を mean に代入します。

配列の場合は、仮引数の宣言に & を付けないことと、配列であることを表すために [ ] を

付けることを覚えておけばいいです。

5.4 C++によるプログラムの翻訳の方法

関数への変数の受け渡しには、C言語の拡張版のC++言語の文法を用いています。この

ため、これまでと違ってプログラムの翻訳は次のようにします。

c++ example5.c -lm Enter

プログラムの実行方法は今まで通り

./a.out Enter

でいいです。

25)配列の型宣言に & を付けるとエラーになります。

26

Page 30: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

5.5 レポート課題

課題 1

次の関数を計算する関数プログラムを作成して、それぞれの右側に書いている関数と一致

することを、適当な x の時に確かめて下さい。

1. f(x) =100Xi=1

(−1)i+1i

xi log(1 + x) (−1 < x < 1)

2. f(x) =100Yi=0

Ã1− x2

(i+ 12)2π2

!cosx

課題 2

n 次元のベクトル x[i] (i=0,1,2,...,n-1) を規格化する関数プログラムを作成し、 n=6

の時を実際に確かめてください。ベクトルを規格化するとは、

n−1Xi=0

x2i = 1

となるように、ある定数をベクトル全体にかけることです。ベクトルのそれぞれの成分に

は好きな値を使って構いません。

課題 3

5人の学生の物理の得点 x と 数学の得点 y

x[0] = 80 y[0] = 90

x[1] = 70 y[1] = 80

x[2] = 60 y[2] = 70

x[3] = 90 y[3] = 80

x[4] = 70 y[4] = 60

の相関係数 ρxy を計算する関数プログラムを作成して下さい。 x の分散 Vx、 y の分散 Vy、

x と y の共分散 Vxy を

Vx = h(x− hxi)2i = hx2i− hxi2Vy = h(y − hyi)2i = hy2i− hyi2Vxy = h(x− hxi) (y − hyi)i = hxyi− hxihyi

と定義すると、相関係数は ρxy = Vxy/qVxVy で与えられます。相関係数は x と y の相関

の強さを表し、その値が 1 に近いときは相関が強く、 0 に近いときは相関が弱いです。

27

Page 31: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

6 一階常微分方程式

6.1 常微分方程式

今回から二回に渡って、常微分方程式の数値解法を扱います。まず、例として微分方程式

dx

dt= −x

を考えてみましょう。これは原子核の崩壊を表す方程式です。t は時刻、x は放射性原子核

の数を表します。時刻 t0 での x の値 x0 が与えられているとします。ほんの僅かに進んだ

時刻 t1 = t0 +∆t での x の値 x1 を計算で求めようと思います。t = t0 から t = t1 の間、

上式の右辺はほとんど変化しないと考えて良いので、26)

x1 = x0 − x0 ∆t

となります。27)この考えを繰り返し使って、

xi+1 = xi − xi ∆t (i = 0, 1, 2, 3, · · ·)

という漸化式が得られます。時刻は ∆t ずつ進むので

ti+1 = ti +∆t または ti = t0 + i ∆t

となります。このような解法を Euler(オイラー) 法と呼びます。

もし微分方程式が、f(x, t) を x と t の任意の関数として

dx

dt= f(x(t), t)

の形であれば、x に対する漸化式は

xi+1 = xi + f(xi, ti) ∆t (i = 0, 1, 2, 3, · · ·)

となります。28)

微分方程式dx

dt= −x を Euler法で解くプログラムを作成すると次のようになります。

26)時間間隔∆t が短いので、右辺は定数と考えて構いません。27)この式は次のようにも出せます。

x1 − x0∆t

' dx

dt

¯̄̄t=t0

= −x0

28)この式も次のように出せます。xi+1 − xi

∆t' dx

dt

¯̄̄t=ti

= f(xi, ti)

28

Page 32: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

#include <math.h>

#include <stdio.h>

void Euler_method ( double& x, double& dt ) /* (1) 戻り値がないので void

{ と宣言しています */

x = x - x * dt; /* (2) x の値を更新します */

}

int main ( void )

{double x, t_min, t_max, t, dt;

int i, imax;

FILE *fp;

fp = fopen ( "a.dat", "w" );

x = 1000; /* (3) x の初期値を定義します */

t_min = 0; /* (4) 最初の時刻を定義します */

t_max = 10; /* (5) 最後の時刻を定義します */

t = t_min;

dt = 0.01; /* (6) 時間の刻み幅 dtを定義します */

i_max = ( t_max - t_min ) / dt; /* (7) 繰り返し回数を計算します */

fprintf ( fp, "%f %f\n", t, x ); /* (8) tと xの値をファイルに

書き込みます */

for ( i = 0; i < i_max ; i++ ) {

Euler_method ( x, dt );

t = t + dt; /* (9) 時刻を進めます。*/

fprintf ( fp, "%f %f\n", t, x );

}

fclose ( fp );

}

29

Page 33: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

6.2 関数プロトタイプ (原型)宣言

前回、関数の項目で説明していなかったことがあります。関数プログラムが main プログ

ラムより前に出てきていれば問題はありません。しかし、順番が逆のときには、mainプロ

グラムの前に「関数プロトタイプ宣言」をしておく必要があります。これは、戻り値の型、

関数名、および引数の数と型を明確にするためのものです。29)前ページのプログラムを例

に取ると次のようになります。

#include <math.h>

#include <stdio.h>

void Euler_method ( double&, double& ); /* 関数プロトタイプ宣言 */

int main ( void )

{double x, t_min, t_max, t, dt;

*************** 省略 *****************

Euler_method ( x, dt );

*************** 省略 *****************

}

void Euler_method ( double& x, double& dt )

{

x = x - x * dt;

}

関数プロトタイプ宣言には変数(仮引数)を書く必要はありません。引数が配列のときに

は ( double [ ] ) のように宣言しておきます。関数プロトタイプ宣言の文の最後には、

セミコロン ; を付けることを忘れないでください。30)

29)今まで述べてきませんでしたが、プログラムの先頭の math.h や stdio.h は関数プロトタイプ宣言の集

まりです。この中では数学関数 (expなど)や入出力関数 (printfなど)のプロトタイプが宣言されています。30)一方、関数にはセミコロン ; を付けません。間違えやすいので注意して下さい。

30

Page 34: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

プログラムの翻訳と実行の方法

c++ example6.c -lm Enter

./a.out Enter

ファイル出力の方法

FILE *fp; /* (1)ファイル型構造体 fp を宣言します */

fp = fopen( "a.dat", "w" ); /* (2)ファイルを開きます */

fprintf( fp,"%f %f\n", x, y ); /* (3)ファイルに出力します */

fclose(fp); /* (4)ファイルを閉じます */

グラフ作成の方法

データファイル a.dat をグラフに表示するには、まず、gnuplot を起動します。

次に、gnuplot のプロンプトに対して、

gnuplot> plot "a.dat"

と入力して下さい。データファイルと関数 exp(-x) と同時にプロットするには

gnuplot> plot "a.dat", exp(-x)

と打ちます。データポイントを直線で結ぶには

gnuplot> plot "a.dat" w l

とします。

31

Page 35: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

6.3 レポート課題

課題 1

1階微分方程式dx

dt= −x+ sin t

を初期条件 x(0) = 2 の下で Euler法 で解いて下さい。31)関数を用いてプログラムを作成

して下さい。引数には 時刻 t も加えておきましょう。時刻 t は 0 から 10 までにしましょ

う。時間刻み dt は 0.01 で良いでしょう。

課題 2

連立微分方程式を考えてみましょう。2種類の放射性原子核 x と y があって次のような核

反応をする場合がこれに対応します。

x→ y

y → z

ここで z は安定な原子核であるとします。原子核 x, y の数 x, y に関する微分方程式は

dx

dt= −αx

dy

dt= αx− βy

(α, β は原子核 x, y の1秒あたりの崩壊確率)

で与えられます。この場合の漸化式は次のようになります。

xi+1 = xi − αxi ∆t

yi+1 = yi + (αxi − βyi) ∆t

初期条件 x(0) = 1000, y(0) = 0 の下で、微分方程式を Euler 法で解いて下さい。パラメー

タの値は α = 1, β = 1 として下さい。時刻 t は 0 から 5 までにしましょう。時間刻み dt

は 0.01 で良いでしょう。放射性原子核 y の数の時間変化 y(t) をグラフにして下さい。

課題 3

微分方程式の解法には Euler法の他にもいろいろな方法が考案されています。Euler法より

計算精度の良い方法として、修正 Euler法 があります。これは、一時変数 xtmp を使って

xtmp = xi + f(xi, ti) ∆t

xi+1 = xi + {f(xi, ti) + f(xtmp, ti+1)} ∆t/2

と表す方法です。修正 Euler 法を用いて、微分方程式dx

dt= −x を初期条件 x(0) = 1000

の下で解いて下さい。

31)これは、抵抗とコイルを直列に繋いだ回路に交流電圧を印加したとき、回路に流れる電流を表します。

32

Page 36: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

7 二階常微分方程式

7.1 連立微分方程式

2階常微分方程式は、古典力学のニュートン方程式、電気回路の方程式など、物理学の広

範な分野に現われる重要な方程式です。今日は、2階常微分方程式の数値解法を学びます。

考える方程式は次式です。d2x

dt2= f

Ãt, x,

dx

dt

!2階微分は取り扱いが面倒ですね。1階微分ならば、前回やったように数値計算ができま

す。ですから、2階微分を1階微分に落とすことができれば嬉しいですね。実は、これが

できるのです。2階常微分方程式は、2元連立の1階常微分方程式に書き直せます。

上の微分方程式は、時刻 t が独立変数で、”位置” x が従属変数です。そこで、”速度” v(t)

をもう一つの従属変数として

v(t) =dx

dt

のように定義します。そうすると、上の2階微分方程式は

dv

dt= f(t, x(t), v(t))

dx

dt= v(t)

という2元連立の1階微分方程式に書き換えられます。第2式の両辺を t で微分して v を

消去すれば、xについてもとの2階の微分方程式に戻ることは容易に確かめられます。

前回やった Euler法を用いて、この連立方程式を解きましょう。時刻 t0 での位置 x0 と速

度 v0 が与えられているとします。ほんの僅かに進んだ時刻 t1 = t0 +∆t での位置 x1 と速

度 v1 を計算します。t = t0 から t = t1 までの間、上の連立方程式の右辺はほとんど変化

しないと考えて良いので、 (v1 = v0 + f(t0, x0, v0)×∆tx1 = x0 + v0 ×∆t

となります。この考えを繰り返し使って、(vi+1 = vi + f(ti, xi, vi)×∆txi+1 = xi + vi ×∆t

という漸化式が得られます。

33

Page 37: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

7.2 シンプレクティック数値積分法

数値計算には数値誤差が避けられません。Euler 法では連続関数の微分を離散的な差分で

置き換えましたので、1時間ステップあたりの数値誤差は (∆t)2 です。この誤差は時間経

過とともに拡大し、N ステップ後の誤差は N(∆t)2 になってしまいます。さきほどの調和

振動子の例ですと、理論的には系の全エネルギー (=運動エネルギー+位置エネルギー)は

一定のはずなのですが、数値計算では時間とともに増大 (または減少)してしまいます。こ

れでは長時間のシミュレーションをやっても信頼性がありません。

ここ10年位の間に、長時間のシミュレーションに耐えられる新しい計算方法が開発され

ました。それが表題のシンプレクティック数値積分法です。アルゴリズムは Euler 法を少

しだけ変更して (vi+1 = vi + f(ti, xi, vi)×∆txi+1 = xi + vi+1 ×∆t

↑注目

とすればいいです。位置 x を進めるときに、もとの時刻の速度 vi ではなくて、新しい時

刻の速度 vi+1 を使うわけです。こうしても、1時間ステップあたりの計算誤差は相変わら

ず (∆t)2 です。しかしながら、エネルギーの誤差は時間とともに拡大することはなく、N

ステップ後でも (∆t)2 です。従って長時間のシミュレーションができるわけです。

もっと精度のよい計算法も開発されています。詳しく知りたい人は脚注の本を調べてみて

下さい。32) 調和振動子の場合を考えると、f(t, x, v) = −x ですので、33)プログラムは次の

ようになります。34)

32)鈴木増雄著:岩波講座 現代の物理学4「統計力学」33)振動数を ω = 1 としました。34)ホームページ (http://www.a-phys.eng.osaka-cu.ac.jp/terai/index.html) のプログラム例1

(pendulum.c) にプログラムがあります。

34

Page 38: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

#include <math.h>

#include <stdio.h>

double f ( double& x ) /* (1) 力を計算します */

{

return ( - x );

}

void SI_method ( double& x, double& v, double& t, double& dt )

{

v = v + f(x) * dt; /* (2) v の値を更新します */

x = x + v * dt; /* (3) x の値を更新します */

t = t + dt; /* (4) 時間 t を更新します */

}

int main ( void )

{

double x, v;

double t_min, t_max, t, dt;

int i, i_max;

FILE *fp;

fp = fopen( "a.dat", "w" );

x = 1; /* (5) x の初期値を 1 とします */

v = 0; /* (6) v の初期値を 0 とします */

t_min = 0;

t_max = 10;

t = t_min; /* (7) 時刻 t を初期化します */

dt = 0.01; /* (8) 時間刻み幅を 0.01とします */

i_max = int( ( t_max - t_min ) / dt ); /* (9) int は小数点以下切り捨て */

for ( i = 0; i < i_max ; i++ ) {

SI_method ( x, v, t, dt );

fprintf( fp, "%f %f\n", t, x );

}

fclose ( fp );

}

35

Page 39: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

ホームページ (http://www.a-phys.eng.osaka-cu.ac.jp/terai/index.html) のプログ

ラム例1 (pendulum.c) にプログラムがあります。ダウンロード35)して翻訳、実行をして

みてください。さらに gnuplot を使って結果をグラフ化して下さい。この微分方程式の解

は単振動で表されますから、x(t) = cos t となります。

gnuplot> plot "a.dat", cos(x)

とタイプして、数値解と厳密解を同時にプロットしてみてください。

7.3 2次元運動

次に、ニュートン方程式を2次元に拡張しよう。位置、速度、力がそれぞれ2次元ベクト

ルになります。位置を (x, y)、力を (fx, fy) とすると、ニュートンの運動方程式は

d2x

dt2= fx

d2y

dt2= fy

となります。先程やったのと同じように、速度 (vx, vy) を用いて、1階微分方程式に書き

直すと

dvxdt

= fx

dvydt

= fy

dx

dt= vx

dy

dt= vy

となります。今回は4元の連立微分方程式です。

まず、太陽を回る惑星の運動を考えることにしよう。太陽の位置を原点として、惑星と太

陽の距離を r とすると、ポテンシャルエネルギーは V = −1rです。惑星に作用する力は

fx = −∂V∂x

= − xr3

fy = −∂V∂y

= − yr3

となります。惑星の位置の初期値を (1, 0)、初速度を (0, vinit) としましょう。vinit = 1 の

場合について、惑星の軌道をシンプレクティック法で求めるプログラムを作成すると、次

ページのようになります。このプログラムでは、惑星の位置ベクトル、速度ベクトル、力

のベクトルをそれぞれ配列 x[ ], v[ ], f[ ] で表しています。プログラムはホームペー

ジのプログラム例2 (kepler.c) にあります。

35)プログラムを右クリックしてから「リンク先を名前を付けて保存」を選択します。

36

Page 40: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

#include <math.h>

#include <stdio.h>

void force ( double x[ ], double f[ ] )

{

double r;

int i;

r = 0;

for ( i = 0; i < 2; i++ ) {

r = r + x[i] * x[i];

}

r = pow ( r, 1.5 );

for ( i = 0; i < 2; i++ ) {

f[i] = - x[i] / r;

}

}

void SI_method ( double x[ ], double v[ ], double& t, double& dt )

{

double f[2];

int i;

force ( x, f );

for ( i = 0; i < 2; i++ ) {

v[i] = v[i] + f[i] * dt;

x[i] = x[i] + v[i] * dt;

}

t = t + dt;

}

37

Page 41: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

int main ( void )

{

double x[2], v[2];

double r, t, dt, t_min, t_max;

int i, i_max;

FILE *fp;

fp = fopen ( "a.dat", "w" );

x[0] = 1;

x[1] = 0;

v[0] = 0;

v[1] = 1;

t_min = 0;

t_max = 10;

t = t_min;

dt = 0.001;

i_max = int ( ( t_max - t_min ) / dt );

for ( i = 0; i < i_max ; i++ ) {

SI_method ( x, v, t, dt );

fprintf ( fp, "%f %f\n", x[0], x[1] );

}

fclose ( fp );

}

結果をグラフ化して、惑星の軌道が円になることを確かめよう。vinit を変えると、軌道が

どのよう変化するかを調べてみよう。特に vinit が√2 を越えるかどうかで、軌道の形が大

きく変わることに注意しよう。

38

Page 42: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

7.4 レポート課題

課題 1 2階微分方程式

d2x

dt2= − sin x− α

dx

dt

を初期条件 x(0) = 0、(dxdt)t=0 = 1 の下でオイラー法で解け。漸化式は

vi+1 = vi − (sin xi + αvi)×∆txi+1 = xi + vi+1 ×∆t

とせよ。α = 0.1 とする。この方程式は、速度に比例する抵抗が加わった振り子の運動を

表す。時間刻みは∆t = 0.01 として、時刻は 0 から 50 までとるのが良い。

課題 2 連星の周りを運動する惑星の軌道を計算せよ。連星を構成する恒星の質量を 1, 恒

星間の距離を 1 とする。恒星はじっと動かないとする。初期条件の決め方が適当であると、

惑星は周期的運動をしないことを確かめよ。惑星の初期条件をうまく調節してやると、惑

星が8の字軌道を描くことを確かめよ。

発展課題 惑星の軌道計算プログラムをもう一度考えよう。全エネルギー E = 12v2init − 1

が負であれば、軌道は楕円になる。楕円の長軸の長さ ` と運動の周期 T とを求めるプログ

ラムを作成して、ケプラーの第3法則「T は ` の 3/2乗に比例する」を確かめよ。vinit は

0.5 から 1.4 まで 0.01 刻みにとると良い。

` と T は質点の位置の y 座標が初めて負になったときの x 座標とその時刻 t とから 計算

できる。forループから脱出するには、

if ( y < 0 ) break;

のように、if 文の最後に break; 文をつける。 ` を横軸、T を縦軸にした両対数グラフを

作成せよ。両対数グラフを得るには、

gnuplot> set log

と入力する。 log を解除して通常のスケールに戻すには

gnuplot> set nolog

とすればよい。

39

Page 43: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

8 モンテカルロ法 I

8.1 乱数

さいころを次々に振って出た目を並べたような、でたらめな数の並びを乱数列といいます。

では、同じ計算であれば何度繰り返しても同じ答えを出してしまうコンピュータは、でた

らめな数を発生してくれるのでしょうか?厳密にいうと、答えはNoです。でも、乱数そっ

くりの「疑似」乱数で良ければコンピューターは作ってくれます。

コンピュータで疑似乱数列を発生させる方法として、乗算合同法があります。36) a と M

を整数として、整数列 I1, I2, I3, · · · を漸化式

Ii = a× Ii−1 (mod M)

に従って順番に作っていきます。 ここで、右辺の値は M の剰余系37)で表しておきます。

ですから、Ii は 0 から M − 1 までの値をとります。a 、M と初期値 I0 をうまく選んでや

れば、整数列 Ii (i = 0, 1, 2, 3, · · ·) は乱数列に近くなります。良い疑似乱数列を得るための

条件がいくつか知られています。その一つが、「a と M は互いに素であること」です。32

ビットの計算機の場合によく使われるのが、a = 511 = 48828125、M = 231 = 2147483648

の組合せです。初期値 I0 は奇数に選んだ方が良いです。Ii の最大値は M − 1 ですので、

Ii を M で割った Ii/M は 0 と 1 の間の (正確には [0, 1)の)一様乱数になります。

0 と 1 の間の一様乱数を10個発生させるプログラムは次のようになります。

#include <math.h>

#include <stdio.h>

double drand ( int& seed ) /* (1) 関数 drand を宣言します */

{

double x;

seed = seed * 48828125; /* (2) 整数 seed に a をかけます */

seed = seed % 2147483648U; /* (3) M の剰余系で seed を計算 */

x = seed / 2147483648.0; /* (4) x を区間 [0,1) に入れます */

return ( x );

}

/* 次のページに続く */

36)もっと良い乱数を発生させる方法として、Tausworth(トーズワース)法があります。37)M で割ったときの余りです。0 から M − 1 までの値をとります。

40

Page 44: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

int main ( void )

{

int i, seed;

seed = 20061207; /* (5) 初期値を与えます */

for ( i = 0; i < 10 ; i++ ) {

printf( "%f\n", drand(seed) ); /* (6) 発生させた乱数を出力します */

}

}

1. 0 から 1 までの乱数を発生させる関数 drand を宣言します。関数が終了してmain プ

ログラムに戻るときに、1個の乱数を持ち帰ります。その値 (戻り値)は実数ですの

で、関数宣言の先頭には double と宣言してあります。関数の引数は整数 seed です。

2. seed に 511 (= 48828125) をかけます。計算機が表せる整数の値には上限があります

ので、511 を掛けると桁溢れを起こしてしまいます。しかし乱数発生プログラムでは

桁溢れを気にしません。

3. % は余りを表します。整数 m を整数 n で割ったときの商は m / n で 余りは m % n

です。ですから、この行では seed を 231 (= 2147483648) で割ったときの余りを計

算しています。数値の最後につけた記号 U は この定数が「符号なし整数型」である

ことを意味しています。32ビット計算機では、「符号つき整数型」で表せる整数の最

大値は 231− 1 ですので、38) これより大きい値は「符号なし整数型」にしなければな

りません。39)

4. seed を 231 で割って、x が区間 [0,1) に入るようにします。

5. 初期値 I0 を与えます。ここには奇数であれば好きな値を代入して構いません。40)こ

の初期値のことを乱数の ”種” と言います。乱数の種を変えると、まったく別の乱数

列が得られます。

6. 関数 drandを呼び出します。この関数は区間 [0,1)に入る1個の乱数を持ち帰ります。

このプログラムはホームページ (www.a-phys.eng.osaka-cu.ac.jp/terai/index.html)

のプログラム例1 (random.c)にあります。ダウンロードして下さい。

38)1ビット目は符号 ± を区別するのに用います。2ビット目から 32ビット目までが数字を表すのに用いら

れます。39)符号なし整数型で表すことの出来る最大の整数は 232 − 1です。40)誕生日を使うのもいいです。

41

Page 45: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

8.2 モンテカルロ積分

それでは、もうちょっと役に立つプログラムを考えてみましょう。乱数を使って、円周率 π

を計算してみます。下の図のような1辺の長さが1の正方形を考えます。この正方形の中

にランダムにたくさんの点を打ちます。そのためには、0 と 1 の間の一様乱数を2個発生

させて、そのうちの一方を点の x座標、もう一方を点の y座標とします。その点が4分円

の中に入ったかどうかを判断します。点の総数を N、そのうち4分円の中に入った点の個

数を m とします。点の総数を多くすれば

limN→∞

m

N=

4分円の面積

正方形の面積=π

4

となるはずです。従って、円周率は π = 4 limN→∞

m

Nで計算できるはずです。

この方法は、次の積分値

S =Z 1

0dx

Z 1

0dy θ(1− x2 − y2) θ(x) =

(1 (x > 0)

0 (x < 0)

を求めたのと同じですので、モンテカルロ積分と呼ばれています。このプログラムは次ペー

ジのようになります。プログラムはホームページのプログラム例2 (pi random.c)に載せ

てあります。

42

Page 46: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

#include <math.h>

#include <stdio.h>

double drand ( int& seed )

{

/* この部分は先程のプログラムの drand と同じです */

}

int main ( void )

{

int i, seed, m, N;

double x, y, pi;

seed = 20061207;

N = 10000; /* (1) 点の数 (サンプル数) */

m = 0;

for ( i = 0; i < N ; i++ ) {

x = drand ( seed );

y = drand ( seed );

if ( x * x + y * y < 1 ) {

m = m + 1;

}

}

pi = 4.0 * double ( m ) / double ( N ); /* (2) double は整数を

実数に変換します */

printf( "%f\n", pi );

}

43

Page 47: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

8.3 レポート課題

課題 1

モンテカルロ積分は高次元積分で威力を発揮します。半径が1である10次元の球の体積

をモンテカルロ積分で計算してください。サンプル数は 100000 で良いでしょう。半径1

の n 次元球の体積 Vn は解析的に

Vn =πn/2

Γ(n2+ 1)

と書けます。n = 10 のときは

V10 =π5

Γ(6)=π5

5!= 2.55016

です。数値解と解析解を比較してください。

課題 2

平面上を運動する虫を考えよう。この虫は1秒間にきっちり1 cmの長さの線分に沿って

動きます。ただ運動 (線分)の方向はランダムだとします。つまり、i 秒後の虫の位置の x

座標を xi、y 座標を yi とすると

xi+1 = xi + cos θi

yi+1 = yi + sin θi

であり、θi は 0 と 2π の間の一様乱数で与えられます。時刻 0 のときに虫は原点にいたと

します。

1. (xi, yi) をプロットしたグラフを作成して、虫の軌跡を図示して下さい。時刻は 1000

秒位まで計算するのがいいでしょう。

2. n 秒後の虫の位置と原点の距離を Rn =qx2n + y

2n とします。このシミュレーション

を 10000 回繰り返して、Rn の 平均 hRni を計算して下さい。n の値は、25, 50, 100,

200, 400, 800, 1600, 3200 とします。横軸に n, 縦軸に hRni をプロットしたグラフを

作成して下さい。 hRni ∼ nν のような依存性をもつことを確かめ、ν の値を決定し

て下さい。このようにベキ関数の依存性があるときは両対数グラフにプロットするの

がよいです。gnuplot では

gnuplot> set log

とします。もとのスケールに戻すためには

gnuplot> set nolog

と打ちます。

44

Page 48: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

プログラムの翻訳と実行の方法

c++ example8.c -lm Enter

./a.out Enter

ファイル出力の方法

FILE *fp; /* (1)ファイル型構造体 fp を宣言します */

fp = fopen( "a.dat", "w" ); /* (2)ファイルを開きます */

fprintf( fp,"%f %f\n", x, y ); /* (3)ファイルに x と y を出力します */

fclose( fp ); /* (4)ファイルを閉じます */

グラフ作成の方法

データファイル a.dat をグラフに表示するには、まず、gnuplot を起動します。

次に、gnuplot のプロンプトに対して、

gnuplot> plot "a.dat"

と入力して下さい。データポイントを直線で結ぶには

gnuplot> plot "a.dat" w l

と打ちます。

プログラム印刷の方法

report8.c というファイルを印刷するには、ターミナル画面で

a2ps -1 report8.c Enter

とタイプします。

45

Page 49: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

9 モンテカルロ法 II

9.1 カノニカル分布

考えている体系が温度 T の熱平衡状態にあるとします。熱平衡状態とは、じっと留まった

静的な状態ではなく、外界とエネルギーをやりとりすることにより、エネルギーの異なる

微視的状態の間を動き回っている動的な状態です。基本的にはエネルギーの低い微視的状

態に滞在している時間が長いのですが、エネルギーの高い微視的状態にいるときもありま

す。統計力学では、この”滞在時間”を”確率”と考えなおします。体系がエネルギーEi の微

視的状態に見出される確率は

Pi =exp(−βEi)MXi=1

exp(−βEi)(β =

1

kBT)

で与えられます。この式で表される確率分布をカノニカル分布と呼びます。エネルギーの

低い微視的状態に見出される確率が高いのですが、エネルギーの高い微視的状態にいる確

率もゼロではありません。カノニカル分布での物理量 A の期待値は

hAi =MXi=1

AiPi =

MXi=1

Ai exp(−βEi)MXi=1

exp(−βEi)

で与えられます。M は許される微視的状態の総数です。41)スピン N 個から成る体系の場

合、M = 2Nです。この数は N が大きくなるにつれて、爆発的に増大します。たとえば、

スピン 100個の場合、M = 2100 ≈ 1030 ですので、上式の和を計算するには、現在の世界

最高速のスーパーコンピュータ42)を使ったとしても10億年かかってしまいます。

9.2 インポータンス・サンプリング

というわけで、全ての微視的状態についての総和を計算することは不可能です。そこで、

我慢できる程度の範囲内の計算時間で、総和を推定しようというのが、今日の本題のモン

テカルロ法です。もちろん、この方法では 100%厳密に計算するわけではありませんので、

計算結果には誤差が必ずついてきます。

M個の全微視的状態の中から、少数の m 個の状態だけを選んできて、そのサンプルだけ

を使って物理量を計算します。m¿M (通常は m ∼ Nα ) なので、厳密計算に比べて計算

時間はぐっと短くて済みます。しかし、うまくサンプルを選んでやらなければ、誤差が大

41)ここでは、粒子数を一定とします。外界と粒子の行き来を許す場合はグランド・カノニカル分布になり

ます。42)世界最高速の計算機は 2002年に横浜に設置され、地球シミュレータと呼ばれて、地球環境の研究に利用

されています。この計算機は1秒間に 40兆回 (40テラ)の計算ができます。このスーパーコンピュータが日

本で完成したことを、米国では「コンピュートニク・ショック」(1950年代の人工衛星打ち上げでソ連に遅れ

をとってしまったときに流行った「スプートニク・ショック」という言葉をもじった言葉)と呼んで、巻き返

しのため国家を挙げて高速計算機の開発を行い、2004年になって地球シミュレータを上回る性能の計算機を

稼働させることに成功しました。日本でも 2006年から国家プロジェクトとして1秒間に1京回 (10ペタ)の計算性能をもつ「京速計算機」の開発を始めました。2010年完成が目標です。

46

Page 50: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

きくなって、計算結果の信頼性が乏しくなってしまいます。最も簡単なサンプリングの方

法はランダム・サンプリングと呼ばれる方法で、M 個の全微視的状態から完全にランダム

に m 個の状態を選んできます。43)このとき、物理量の期待値は

hAi '

mXk=1

Ai[k] exp(−βEi[k])mXk=1

exp(−βEi[k])

となります。カノニカル分布の項で説明したように、エネルギーの高い状態から期待値 hAiへの寄与は小さいはずです。ところが、ランダムサンプリングの方法では、エネルギーの

高い状態も、低い状態と同じ確率で選んできます。あまり重要でないのにかかわらず、エ

ネルギーの高い状態の計算も頻繁にしてしまいますので、この方法は効率的とは言えませ

ん。つまり、この方法で誤差を小さくするには、サンプル数 m をかなり大きくとらなけれ

ばならないわけです。

サンプリングの方法を改良するには、乱数の重みを変えて、総和への寄与が大きな微視的

状態 (エネルギーの低い状態)を重点的に取り込むようにするのが良さそうです。なるべく

少ない m で期待値 hAi を精度良く推定するには、全微視的状態の中から各微視的状態 i

を exp(−βEi) に比例する確率で抽出すれば良いことがわかっています。各微視的状態をカ

ノニカル分布に比例した確率で生じるようにするわけです。このインポータンス・サンプ

リングと呼ばれる方法を採用すれば、物理量 A の期待値は次式で得られます。

hAi '

mXk=1

Ai[k]

mXk=1

1

=1

m

mXk=1

Ai[k]

9.3 メトロポリス法

インポータンス・サンプリングを実現させる方法として代表的なものに「熱浴法」と「メ

トロポリス法」があります。メトロポリス法の方が計算時間が短くなる場合が多いですの

で、メトロポリス法を扱うことにします。44) メトロポリス法とは次のようなものです。

1. まず、初期の微視的状態 i から出発します。

2. 次に、この微視的状態 i から別の微視的状態 j への試行変化を考えます。ここで、試

行変化によるエネルギーの変化分 ∆E = Ej − Ei を計算します。

3. もし、∆E が 0 以下ならば、新しい微視的状態 j を受け入れます。

4. 反対に、∆E > 0であれば、乱数 p (0 < p < 1)を生成します。もし、p < exp(−β∆E)ならば、新しい微視的状態 j を受け入れ、そうでないときには新しい微視的状態は

受け入れないで元の微視的状態 i のままにしておきます。

5. (2) から (4) までを m 回繰り返します。45)

43)前回の π の計算はこのランダム・サンプリングの方法を用いていました。44)1953年に原子炉のシミュレーションをするために Metropolis らによって開発されました。45)初期状態としてエネルギーの高い状態を選んだときには、熱平衡に達するまでのサンプルは捨てて、平

均の計算には取り入れません。

47

Page 51: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

9.4 自由スピン系のモンテカルロ・シミュレーション

スピン 1/2の原子が N 個ある系を考えます。それぞれの原子は、他の原子とは独立に2つ

の状態をとることができます。一様な磁場をかけると、2つの状態のエネルギーはそれぞ

れ −1 と 1 をとるようになります。エネルギーが −1 の状態を down, 1 の状態を up と呼

ぶことにします。この系が温度 T の熱浴と接していて、熱平衡状態にあるとします。スピ

ン系は熱浴とエネルギーのやりとりをしていますので、系のエネルギーは一定ではありま

せん。系のエネルギーの期待値をモンテカルロ法で計算してみましょう。計算のアルゴリ

ズムは以下のようになります。これを参考にしてプログラムを作成してください。

9.4.1 パラメータの定義

main関数や drand関数 (乱数発生の関数)の前に、スピン数 N の値を定義します。ついで

にサンプリングの回数 (モンテカルロの繰り返し回数) MS も定義しておきます。

#define N 20

#define MS 10000

こうすると、N, MS の値はそれぞれ 20, 10000 になります。

9.4.2 スピン変数の配列宣言と初期化

各スピンが up 状態か down 状態にあるかを、配列 S に記憶させます。i 番目のスピンの

状態が down であれば S[i] = −1, up であれば S[i] = 1 です。初期条件は全部のスピンが

down であるとします。main関数の冒頭で、以下のようにスピン変数を初期化します。つ

いでに、乱数の種 seed と逆温度 β も定義しておきましょう。

int i, seed;

double beta;

double S[N];

seed = 20061213;

beta = 1.0;

for ( i = 0; i < N; i++ ) {

S[i] = -1;

}

9.4.3 モンテカルロ・ステップ

試行変化として i 番目のスピンを反転させたときのエネルギー変化 dE を計算します。も

し、dE が 0 以下であれば試行変化を受け入れて、スピンを反転させます。

48

Page 52: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

dE = -S[i] - S[i]

if ( dE <= 0 ) {

S[i] = -S[i];

}

それ以外 (dE > 0) の場合には、乱数を生成して、その値が exp(−βdE) より小さければ、

試行変化を受け入れます。

else if ( drand(iseed) < exp( -beta * dE ) ) {

S[i] = -S[i];

}

以上のことを全てのスピン (i = 1, 2, · · · , N) について計算します。

9.4.4 エネルギーの測定

全てのスピンについての更新作業が一通り済んだら、全エネルギー E を計算します。i番

目のスピンのエネルギーは S[i] ですので、系全体のエネルギーを求めるには S[i] を足しあ

げます。

E = 0.0;

for ( i = 0; i < N; i++ ) {

E = E + S[i]; または E += S[i];

}

エネルギーの平均値や分散を計算するために、E とその2乗を積算しておきます。

sum = sum + E; または sum += E;

sum2 = sum2 + E * E;

9.4.5 統計平均の算出

4.3 から 4.4 まで MS 回繰り返します。その後で、sum と sum2 からエネルギーの平均値

と比熱を計算します。比熱 C は

C =hE2i− hEi2

T 2

から求めます。46)

46)ボルツマン定数 kB は 1 としました。

49

Page 53: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

9.5 レポート課題

1. 温度 T = 1 のときに、エネルギーの平均値と比熱を求めて下さい。

2. 温度 T を 0.1 < T < 4 の範囲で 0.1 刻みでかえて、エネルギーの平均値と比熱を計

算して、グラフにして下さい。

50

Page 54: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

プログラムの翻訳と実行の方法

c++ example9.c -lm Enter

./a.out Enter

ファイル出力の方法

FILE *fp; /* (1)ファイル型構造体 fp を宣言します */

fp = fopen( "a.dat", "w" ); /* (2)ファイルを開きます */

fprintf( fp,"%f %f\n", x, y ); /* (3)ファイルに出力します */

fclose( fp ); /* (4)ファイルを閉じます */

グラフ作成の方法

データファイル a.dat をグラフに表示するには、まず、gnuplot を起動します。

次に、gnuplot のプロンプトに対して、

gnuplot> plot "a.dat"

と入力して下さい。データポイントを直線で結ぶには

gnuplot> plot "a.dat" w l

と打ちます。

プログラム印刷の方法

report9.c というファイルを印刷するには、最初の画面で

a2ps -1 report9.c Enter

とタイプします。プログラムを出力して提出して下さい。

51

Page 55: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

10 データ処理

10.1 ファイル入出力

今回はファイルから数値を読み取る方法に慣れることにします。まず、データを書き込ん

だファイルを作成します。エディタ (xemacs)でファイル test.dat を作成し、test.dat の中

に次のような数値を書き込んでください。

test.dat の中身

1.0 2.0

3.0 4.0

5.0 6.0

隣り合った数値の間には、空白を入れます。空白は何文字分あっても構いません。ファイ

ルから数値を読み取るプログラムは以下のようになります。

#include <math.h>

#include <stdio.h>

main()

{

double x1, x2, x3, y1, y2, y3;

FILE *fp; /* (1)ファイル型構造体 fp を宣言する */

fp = fopen( "test.dat", "r" ); /* (2)ファイルを開く */

fscanf( fp, "%lf %lf", &x1, &y1 ); /* (3)ファイルから読み取る*/

printf( "%f %f\n", x1, y1 ); /* (4)画面に出力する */

fscanf( fp, "%lf %lf", &x2, &y2 );

printf( "%f %f\n", x2, y2 );

fscanf( fp, "%lf %lf", &x3, &y3 );

printf( "%f %f\n", x3, y3 );

fclose( fp ); /* (5)ファイルを閉じる */

}

52

Page 56: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

1. ファイルを操作するには、ファイル1つに対してファイル型の構造体を1つ宣言しま

す。∗ はポインタを表しますが、今はおまじないと思っておいて下さい。fp を2つ

宣言すると、1つのファイルから数値を読み取って、もう1つのファイルに結果を書

き込むことができます。

2. 関数 fopen でファイル test.dat を開きます。"r" は読み取りモードであることを

表します。読み取りモードの場合、ファイルが存在しなければエラーを出して止まり

ます。書き込みモードは "w" でしたね。

3. 関数 fscanfでファイルからデータを読み取ります。fscanfの引数は、ファイル出力

の関数 fprintf とほとんど同じです。ただし、倍精度実数型変数 (doubleで宣言さ

れた変数)の数値を読み取るための書式は "%lf" です。47) これまで使ってきた "%f"

では、数値が正しく読み取れませんので注意して下さい。また、変数の先頭の & は

アドレスを表しますが、今はおまじないと思っておいて下さい。48)

4. 結果を画面に出力します。倍精度実数型の書式は "%f" または "%lf" です。

5. ファイルからの読み取りが終ったら、関数 fclose でファイルを必ず閉じて下さい。

プログラムが作成できたら、翻訳と実行を行って下さい。このプログラムでは test.datか

ら変数を2個ずつ読み取りました。もし1個ずつ読み取ったらどうなるか確かめてみて下

さい。

大量のデータを読み取るには配列を用いればいいです。データファイルはホールページに

載せてありますのでダウンロードして下さい。データファイル linear.dat には、1行に

2個ずつ、100行のデータが入っています。これを読み取るプログラムは次のようになり

ます。

47)lf は long float の略です (floatは実数型を表します)。48)ポインタやアドレスについて詳しく知りたい人は、65 ページの B 「アドレス渡し」の項目をみて下さ

い。

53

Page 57: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

#include <math.h>

#include <stdio.h>

#define N 100 /* (1) データの行数を定義する */

main()

{

int i;

double x[N], y[N];

FILE *fp;

fp = fopen( "linear.dat", "r" ); /* (2) ファイルを開く */

for ( i = 0; i < N; i++ ) {

fscanf( fp, "%lf %lf", &x[i], &y[i] ); /* (3) 数値を読み取る */

}

for ( i = 0; i < N; i++ ) {

printf( "%f %f\n", x[i], y[i] );

}

fclose( fp );

}

1. パラメータ N の値を定義します。

2. 読み取りモードは "r" でした。

3. 読み取りの関数 fscanf では、変数に & をつけておきます。変数が配列の場合でも &

をつけます。

54

Page 58: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

ファイルからデータを読み取る方法は次のようになります。

FILE *fp; /* (1)ファイル型構造体 fp を宣言する */

fp = fopen( "a.dat", "r" ); /* (2)ファイルを読み取りモードで開く */

fscanf( fp, "%lf %lf", &x, &y ); /* (3)ファイルから入力する */

fclose( fp ); /* (4)ファイルを閉じる */

データを書き込む方法を以下に示しておきますので、比較して下さい。

FILE *fp; /* (1)ファイル型構造体 fp を宣言する */

fp = fopen( "a.dat", "w" ); /* (2)ファイルを書き込みモードで開く */

fprintf( fp, "%f %f\n", x, y ); /* (3)ファイルに出力する */

fclose( fp ); /* (4)ファイルを閉じる */

10.2 最小二乗法

測定値を理論曲線にあてはめることを考えます。既に、理論から測定値は y = f(x; a, b) に

のることが分っているとします。ここで、a, b は未知のパラメータで、例えば一次関数の

ときは f(x; a, b) = ax + b です。測定値にはノイズ等による誤差が必ず含まれていますの

で、理論値 f(x; a+ b) と完全には一致しません。測定値と理論値が最も良く合うようにパ

ラメータ a, b の最適値を決めるのが最小二乗法です。49)

理論値が測定値をいかにうまく再現するかの目安は

F (a, b) =NXi=1

{yi − f(xi; a, b)}2

で表せます。 N は測定値の個数です。これが最小になるようにパラメータ a, b を決めま

す。f(x; a, b) = ax+ b の場合には、その最適条件は次のようになります。

49)パラメータは何個あっても構いません。f(x; a1, a2, · · · , an) = a1f1(x) + a2f2(x) + · · ·+ anfn(x) のよう

に表されていればいいです。

55

Page 59: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

∂F

∂a= −2

NXi=1

xi(yi − axi − b) = 0

∂F

∂b= −2

NXi=1

(yi − axi − b) = 0

これを整理すると a, b についての連立方程式が得られます。

aNXi=1

x2i + bNXi=1

xi =NXi=1

xiyi

aNXi=1

xi + bNXi=1

1 =NXi=1

yi

ここで、N 回あたりの平均を

hxi = 1

N

NXi=1

xi, hyi = 1

N

NXi=1

yi, hx2i = 1

N

NXi=1

x2i , hxyi = 1

N

NXi=1

xiyi

と表すと、a, b についての連立方程式は次のように書き換えられます。hx2ia+ hxib = hxyi

hxia+ b = hyi

この連立方程式の解は以下のようになります。

a =hxyi− hxihyihx2i− hxi2

b =hx2ihyi− hxihxyihx2i− hxi2

56

Page 60: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

10.3 レポート課題

課題 1

1. ファイル linear.dat のデータを 直線 y = ax+ b でフィッティングして、パラメー

タ a, b の最適値を決定して下さい。

2. データとフィッティング直線を一つのグラフにかいてください。

課題 2

1. ファイル parabolic.dat のデータを 曲線 y = ax2 + b でフィッティングして、パラ

メータ a, b の最適値を決定して下さい。

2. データとフィッティング曲線を一つのグラフにかいてください。

57

Page 61: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

A 値渡し

本文では関数への変数の引渡しは C++の「参照渡し」という方法で行いました。ここでは

Cの「値渡し」という方法を説明することにします。

A.1 関数で作業を分担

今回はC言語で重要な関数について学習します。プログラムが短いうちは良いのですが、プ

ログラムが長くなってくると、全体のプログラムをいくつかの部品に分割した方が読みや

すくなります。例として2つの変数のうち大きい方を出力するプログラムを考えましょう。

#include <math.h>

#include <stdio.h>

int main(void)

{

int a, b;

int max;

a = 2;

b = 5;

if ( a > b ) {

max = a;

}

else {

max = b;

}

printf( "%10d\n", max );

}

次に、「2つの変数のうち大きい方を選ぶ」という部分をひとつの部品にしてみましょう。

C言語ではこの部品のことを「関数」と言います。50)関数を使うと、このプログラムは次

のように書き換えられます。

50)BASIC や FORTRAN では 「関数副プログラム」や「サブルーチン」と呼ばれています。

58

Page 62: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

#include <math.h>

#include <stdio.h>

int max_of ( int a, int b ) /* (1) 関数 max_of を宣言します */

{

int max; /* (2) 局所変数 max を宣言します */

if ( a > b ) {

max = a;

}

else {

max = b;

}

return ( max ); /* (3) 変数 maxの値を持ち帰ります */

}

int main ( void ) /* (4) main も一つの関数です */

{

int a, b;

a = 2;

b = 5;

printf( "%10d\n", max_of ( a, b ) ); /* (5) 関数 max_ofを呼び出します */

}

1. 関数 max_of を宣言します。main プログラムから関数を呼び出すときに、二つの変

数 a と b の値を関数に渡します。関数側では、受け取った値を変数に代入します。こ

の変数を仮引数といいます。仮引数は、( ) の中に、型名を付して宣言します。51)

この関数が終了して main プログラムに戻るときには、整数型変数 max の値を持ち

帰るので、関数宣言 max_of の先頭に変数 max の型である int を付けておきます。

持ち帰る変数がないときは、void と書きます。

51)仮引数がないときには ( void ) と宣言します。

59

Page 63: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

2. 関数 max_of の中だけで有効である局所変数 max を宣言します。局所変数は、main

プログラムから関数が呼ばれるときに生まれ、関数が終了すると同時に消滅します。

3. 関数が終了して main プログラムに戻るときに、整数型変数 max の値を持ち帰りま

す。この持ち帰る値のことを「戻り値」あるいは「返却値」と言います。

4. 講義の当初から説明せずにきましたが、main も一つの関数なのです。main は特別な

関数で、C言語のプログラムを実行するときには、この main 関数の部分が最初に実

行されます。

5. 関数 max_of を呼び出します。main プログラムから関数に移るときに二つの変数 a

と b の値を持って行きます。この変数を実引数と言います。実引数と仮引数は全く

別個のものです。ですから実引数と仮引数の変数名は違っていても構いません。52)

関数から持ち帰った値を printf で出力します。

別の例を挙げてみましょう。1から10までの総和を計算するプログラムは、関数を使わ

なければ、次のようになります。

#include <math.h>

#include <stdio.h>

int main ( void )

{

int i;

int sum;

sum = 0;

for ( i = 1; i <= 10; i++) {

sum = sum + i;

}

printf( "%10d\n", sum );

}

関数を使って書き換えると、次のようになります。

52)この例では実引数と仮引数の変数名は同じになっています。

60

Page 64: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

#include <math.h>

#include <stdio.h>

int total_sum ( void ) /* (1) 関数 total_sum を宣言します */

{

int i; /* (2) 局所変数 i を宣言します */

int sum; /* (3) 局所変数 sum を宣言します */

sum = 0;

for ( i = 1; i <= 10; i++) {

sum = sum + i;

}

return ( sum ); /* (4) 整数型 sum の値を持ち帰ります */

}

int main ( void )

{

int sum; /* (5) 局所変数 sumを宣言します */

sum = total_sum(); /* (6) 持ち帰った値を sum に代入します。*/

printf( "%10d\n", sum ); /* (7) sum の値を出力します */

}

1. 関数 total_sum を宣言します。この関数が終了して main プログラムに戻るときに

整数型の値を持ち帰るので、 total_sum の前に int と宣言してあります。仮引数は

ないので、( void ) とします。

2. 関数 total_sum の中だけの局所変数 i を宣言します。関数が終了すると同時に、こ

の変数も消滅します。

3. 関数 total_sum の中だけで有効な局所変数 sum を宣言します。関数が終了すると同

時に、この変数の命も消滅します。ですから、関数 total_sum の中の sum と main

プログラムの中の sum は全く別の変数です。

4. 関数が終了して main プログラムに戻るときに、変数 sum の値を持ち帰ります。

61

Page 65: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

5. この整数型変数 sumは main関数の中だけで行き延びる局所変数です。ですから main

関数 の中の sum と 関数 total_sum の中の sum は別の変数です。

6. 関数 total_sum を呼び出します。実引数はないので、total_sum の後ろにはカッコ

() だけを付けておきます。関数から持ち帰った値を sum に代入します。

7. 項目 (5)~(7)は、ひとまとめにして printf( "%10d\n", total_sum() );としても

構いません。その場合は total_sum から持ち帰った値をそのまま出力します。

しかし、このプログラムでは1から10までの総和しか計算できません。1からnまでの

総和を計算できるように、もっと汎用性のあるプログラムに変えると次のようになります。

#include <math.h>

#include <stdio.h>

int total_sum ( int n ) /* (1) 仮引数を n とします */

{

int i;

int sum;

sum = 0;

for ( i = 1; i <= n; i++) { /* (2) 1 から n までの総和を計算 */

sum = sum + i;

}

return ( sum );

}

int main ( void )

{

int n, sum;

n = 10;

sum = total_sum ( n ); /* (3) n の値を関数に渡します */

printf( "%10d\n", sum );

}

62

Page 66: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

次に、配列を受渡しする例を挙げてみることにします。5人の学生の平均点を求めるプロ

グラムを、関数を使って書くと次のようになります。

#include <math.h>

#include <stdio.h>

int average ( int x[ ] ) /* (1) 関数 average を宣言します */

{

int sum, mean;

sum = 0;

for ( i = 0; i < 5; i++ ) {

sum = sum + x[i];

}

mean = sum / 5;

return ( mean );

}

int main ( void )

{

int x[5]; /* (2) 配列を宣言します */

x[0] = 80;

x[1] = 70;

x[2] = 60;

x[3] = 90;

x[4] = 70;

printf( "%10d\n", average(x) ); /* (3) 関数 average を呼び出します */

}

63

Page 67: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

A.2 レポート課題

課題 関数

f(x) =nXi=0

xi

を計算するプログラムを作成して、この関数をグラフにして下さい。実数 x と整数 n を

引数として main プログラムから関数 series_f に引き渡します。関数からの返却値は実

数型ですので、関数の宣言の先頭には double を付けましょう。 n = 20 とします。x の

値としては、0 から 0.9 まで 0.01 刻みにとるのが良いでしょう。整数型変数 i を用いて

x = 0.01 * i としましょう。

発展課題 関数

f(x) =nXi=0

(−1)i(2i)!

x2i

を計算するプログラムを作成して、この関数をグラフにしてください。 n = 10 とします。

x の値としては、0 から 10 まで 0.1 刻みにとるのが良いでしょう。

64

Page 68: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

B アドレス渡し

「アドレス渡し」という変数の引渡し方法について説明します。

B.1 ポインタ

今回はC言語で重要なポインタについて学習します。変数は記憶域と呼ばれる広い空間の

中の一つの地点に存在します。その地点のことをアドレス (日本語に訳すと番地です)と言

います。変数のアドレスの値を格納するのがポインタです。前回に学習した関数を用いて、

2つの変数を大きい順に並べ変えるプログラムを作成してみましょう。

#include <math.h>

#include <stdio.h>

void sort ( int a, int b ) /* (1) 関数 sort を宣言します */

{

int c; /* (2) 局所変数 c を宣言します */

if ( a < b ) {

c = a; /* (3) a の値を変数 c に 保存します */

a = b;

b = c;

}

}

int main ( void )

{

int a, b;

a = 2;

b = 5;

sort ( a, b ); /* (4) 関数 sort を呼びます */

printf( "%10d %10d\n", a, b );

}

65

Page 69: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

1. 関数 sort を宣言します。main プログラムから関数を呼び出すときに、二つの変数

a と b の値を関数に渡します。関数側では、受け取った値を変数に代入します。この

変数を仮引数といいます。仮引数は、( ) の中に、型名を付して宣言します。

この関数には return 文がありませんので、この関数が終了して main プログラムに

戻るときに、何の値も持ち帰りません。ですから、関数宣言 sort の先頭に void と

書いてあります。

2. 関数 sort の中だけで有効である局所変数 c を宣言します。局所変数は、main プロ

グラムから関数が呼ばれるときに生まれ、関数が終了すると同時に消滅します。

3. 次の文 a = b; で変数 a の値を書き換えてしまうので、前もって a の値を変数 c に

書いて保存しておきます。

4. 関数 sort を呼び出します。main プログラムから関数に移るときに二つの変数 a と

b の値を持って行きます。この変数を実引数と言います。実引数と仮引数は全く別個

のものです。ですから実引数と仮引数の変数名は違っていても構いません。

プログラムを実行してみて下さい。いかがですか? 残念ながら望ましい結果が得られませ

んね。じつは、関数 sortの中の変数 a, bは sortの中だけで有効な局所変数であり、main

プログラムの中の変数 a, b は main の中だけで有効な局所変数なのです。ですから、関数

sortの中の変数 a, b と main プログラムの中の変数 a, b は全く別の変数なのです。よっ

て、sort の中で a や b の値を書き換えても、main プログラムの中の a や b の値は書き

換わらないのです。

今日のテーマである「ポインタ」を使うと、関数 sort の変数の値を書き換えることによっ

て main プログラムの中の変数の値も書き換えることができるようになります。プログラ

ムは次のようになります。

66

Page 70: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

#include <math.h>

#include <stdio.h>

void sort ( int *a, int *b ) /* (1) 関数 sort を宣言します */

{

int c; /* (2) 局所変数 c を宣言します */

if ( *a < *b ) { /* (3) *a は ポインタ a が指す変数です */

c = *a; /* (4) a の値を変数 c に 保存します */

*a = *b;

*b = c;

}

}

int main ( void )

{

int a, b;

a = 2;

b = 5;

sort ( &a, &b ); /* (5) 関数 sort を呼びます */

printf( "%10d %10d\n", a, b );

}

1. 関数 sort を宣言します。関数の仮引数 a と b は「整数へのポインタ型変数」です。

ポインタ型変数の型宣言には * をつけて、int *a とします。53) a には、変数の値で

はなく、変数のアドレスの値が格納されています。この関数が終了してmainプログ

ラムに戻るときに何の値も持ち帰らないので、関数の先頭にvoidと書いてあります。

2. 関数 sortの中だけで有効な局所変数 cを宣言します。これは通常の整数型変数です。

3. ポインタが指す変数は、ポインタの先頭に * をつけて、*a のように表します。54) a

が整数へのポインタ型変数であれば、*a は整数型変数です。*a も *b もともに整数

53)int* a と宣言しても構いません。54)この * 印には、「積 (掛け算)」の意味は全くありません。注意して下さい。

67

Page 71: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

型変数ですから、これら2つの値の比較ができるのです。

4. c も *a もともに整数型変数ですから、*a の値を c へ代入できるのです。

5. main プログラムから関数 sort を呼び出します。関数 sort へは、変数の値ではな

く、変数のアドレスの値を渡します。変数のアドレスは、変数の先頭に & をつけて、

&a のように表します。関数sort を呼び出すときに、main プログラムの中の a のア

ドレスの値 &a を 関数 sort の中のポインタ型変数 a にコピーします。55)

もう一つ別の例を挙げてみましょう。次のプログラムは、2つの整数の和と差を計算する

プログラムです。

#include <math.h>

#include <stdio.h>

void sum_diff ( int a, int b, int sum, int diff )

{

sum = a + b;

diff = a - b;

}

int main ( void )

{

int a, b;

int sum, diff;

a = 6;

b = 2;

sum_diff ( a, b, sum, diff );

printf( "%10d 10%d\n", sum, diff );

}

どうですか? やっぱり、うまく行きませんね。では、ポインタを使って、プログラムを書

き直してみましょう。

55)関数との間で、変数のアドレスを受け渡すので、アドレス渡しと言います。前回の方法は、変数の値そ

のものを受け渡したので、値渡しと呼びます。

68

Page 72: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

#include <math.h>

#include <stdio.h>

void sum_diff ( int a, int b, int *sum, int *diff ) /* (1) 関数宣言 */

{

*sum = a + b; /* (2) *sum はポインタ sum が指す変数です */

*diff = a - b; /* (3) *diff はポインタ diffが指す変数です */

}

int main ( void )

{

int a, b;

int sum, diff;

a = 6;

b = 2;

sum_diff ( a, b, &sum, &diff ); /* (4) 関数 sum_diff を呼び出します */

printf( "%10d 10%d\n", sum, diff );

}

1. 関数 sum_diff を宣言します。sum と diff は整数へのポインタ型変数です。

2. ポインタ sum が指す整数型変数 *sum に a + b を代入します。*sum は main プログ

ラムの中の sum と全く同じものです。ですから、main プログラムの中の sum の値も

書き変わるのです。

3. ポインタ diff が指す整数型変数 *diff に a - b を代入します。

4. 関数 sum_diff を呼び出します。4つの変数のうち、a と b は整数型ですが、&sum

と &diff はポインタ型です。関数 sort へは、a, b の値と、sum, diff のアドレスの

値を渡します。仮引数 sum の指す変数56)と実引数 &sum の指す変数57)は全く同じ変

数ですので、関数 sum_diff の中の *sum を書き換えることにより、main プログラ

ムの中の sum も書き換わるのです。

56)関数 sum diff の中の *sum のことです。57)main プログラムの中の sum のことです。

69

Page 73: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

B.2 配列の受け渡し

次に、配列を受け渡しする例を挙げてみることにします。5人の学生の平均点を求めるプ

ログラムを、関数を使って書くと次のようになります。

#include <math.h>

#include <stdio.h>

int average_of ( int x[ ] ) /* (1) 関数 average_of を宣言 */

{

int sum, mean; /* (2) 局所変数 sum, mean を宣言 */

int i;

sum = 0;

for ( i = 0; i < 5; i++ ) {

sum = sum + x[i]; /* (3) x[i] は *( x + i ) と同じ */

}

mean = sum / 5;

return ( mean ); /* (4) 平均値の値を持ち帰ります */

}

int main ( void )

{

int x[5]; /* (5) 配列を宣言します */

x[0] = 80;

x[1] = 70;

x[2] = 60;

x[3] = 90;

x[4] = 70;

printf( "%10d\n", average_of ( x ) ); /* (6) 関数average_ofを呼びます */

}

70

Page 74: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

1. 関数 average_of を宣言します。関数が終了してmain プログラムに戻るときに整数

値を持ち帰るので、関数の先頭に int を付けてあります。関数の ( ) の中の仮引数

x[ ] は配列を受け取ることを表します。58)

2. 関数 average_of の中だけで有効である局所変数 sum と mean を宣言します。

3. 配列の各要素のアドレスは連続しています。例えば x[0] のアドレスが 100番地であ

れば、x[1] のアドレスは 101番地です。ですから、x[0] のアドレス x59) から i 進

んだアドレス x + i に対応する変数 *( x + i ) のことを x[i] と書きます。これ

は配列変数の書き方と同じです。

4. 関数が終了して main プログラムに戻るときに、mean の値を持ち帰ります。

5. 大きさ5の整数型配列を宣言します。こうすれば、5個の整数型変数 x[0], x[1],

x[2], x[3], x[4] を使えるのでしたね。

6. 関数 average_of を呼び出します。添字なしで現われた配列変数 x は、その配列の

第一要素 x[0] のアドレスを表します。ですから、関数 average_of の実引数である

x は &x[0] と同じです。この場合の実引数はポインタ型変数です。よって、main プ

ログラムから関数 average_of へ引き渡されるのは配列変数の先頭要素のアドレスの

値です。関数 average_of が終了したときに持ち帰った値を printf で出力します。

この例から判るように、配列変数を受け渡すときには、配列の値を受け渡すではなく、ア

ドレスを受け渡します。ですから、配列変数の書き換えは容易にできるのです。

58)この引数はポインタですから、この仮引数の宣言は int *x あるいは int* x としても構いません。59)&x[0] のことを x と書きます。項目 (6)を参照して下さい。

71

Page 75: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

B.3 レポート課題

課題 5人の学生の得点

x[0] = 80;

x[1] = 70;

x[2] = 60;

x[3] = 90;

x[4] = 70;

の平均点と標準偏差を求めるプログラムを作成して下さい。平均点と標準偏差を計算する

関数 statisticsを作成します。配列 x、平均点 meanと標準偏差 sigmaを引数にしましょ

う。main プログラムから関数に引き渡す実引数は、配列 x[5] の第一要素のアドレスであ

る x、変数 mean のアドレスである &mean、変数 sigma のアドレスである &sigma としま

す。x は整数型、mean と sigma は実数型にしましょう。関数からの返却値はありませんの

で、関数の先頭には void を付けましょう。

発展課題 5人の学生の物理の得点 x と 数学の得点 y

x[0] = 80;

x[1] = 70;

x[2] = 60;

x[3] = 90;

x[4] = 70;

y[0] = 90;

y[1] = 80;

y[2] = 70;

y[3] = 80;

y[4] = 60;

の分散 Vx, Vy と共分散 Vxy を計算するプログラムを作成して下さい。これらは

Vx = < (x− < x >)2 >Vy = < (y− < y >)2 >Vxy = < (x− < x >) (y− < y >) >

で与えられます。引数としては配列 x, y、分散 var_x, var_y、および 共分散 covar_xy と

しましょう。関数を呼んだあとで、相関係数 ρxy = Vxy/qVxVy を計算して下さい。ρxy は

x と y の相関の強さを表し、−1 から 1 の間にあります。

72

Page 76: 計算物理学基礎テキスト - Osaka City Universitya-phys.eng.osaka-cu.ac.jp/terai/comp_phys/comp.pdf1 計算機入門I 1.1 計算物理学 従来、物理学では理論と実験がはっきりと区別されていたが、最近になって計算物理学

参 考 書

[1] C言語 に関するもの

柴田望洋 「明解 C言語 入門編」 SOFT BANK Publishing

B.W. Kernighan and D.M. Ritchie: The C programming Language

石田晴久 (訳) 「プログラミング言語 C」 共立出版

W.H. Press et al.: Numerical Recipes in C

丹慶勝市 他 (訳) 「Numerical Recipes in C 日本語版」 技術評論社

[2] UNIX に関するもの

山口和紀 (監修) 「The UNIX Super Text」 技術評論社

[3] Emacs に関するもの

矢吹道郎 (監修) 「初めて使う Mule/Emacs」 テクノプレス

[4] 計算物理学 に関するもの

H. Gould and J. Tobochnik: An Introduction to Computer Simulation Methods

鈴木増雄 (監訳) 「計算物理学入門」 Pearson Education Japan

J.M. Thijssen: Computational Physics

谷村吉隆 他 (訳) 「計算物理学」 Springer-Verlag Tokyo

R.H. Landau et al.: Computational Physics —Problem solving with Computers —

小柳義夫 (監訳) 「計算物理学」 朝倉書店

早野龍五、高橋忠幸 「計算物理」 共立出版

[5] 数値計算に関するもの

伊理正夫、藤野和建 「数値計算の常識」 共立出版

73