現在(2018-04-05 (木) 13:09:14)作成中です。 既に書いている内容も大幅に変わる可能性が高いので、注意。 as of 2024-04-17 (水) 00:32:10 (222)



担当教員

陰山 聡

演習日

  • 2010.05.06
  • 2010.05.13

概要と達成目標

  1. 概要
    1. why f? (なぜFortran95言語か)
    2. f && c (Fotran95とCの同じところ)
    3. [演習]Hello, world. コンパイルと実行
    4. diff f c (Fotran95とCの違うところ)
    5. wonderful f (Fotran95の素晴らしいところ)
    6. practical f (Fotran95によるコーディングの実際)
  2. 目標
    1. この「計算科学演習I」で扱うFotranソースコードが自由に読めること。
    2. 2次元拡散方程式を解くコードをFotran95言語の特性を活かして書けるようになること。

はじめに

エディタとコンパイラ

  • Emacsのmajorモードをf90に設定すると便利(f95モードは用意されていない)
    • ミニバッファでf90-modeと打つ (Esc-x f90-mode)
    • 構文の開始と終了ペアリング入力が簡単。tabキー
    • ^Jで整形改行
  • scalar上でのコンパイルコマンドは pgf95 またはpgf90

Fortran90/95の歴史

  • FORTRAN(全部大文字の)という言語は存在しない。
    • Fortran90Fortran95という言語ならある。
  • FORTRAN66。
    • 1966年に標準化。
  • FORTRAN77
    • 1977年に標準化。
    • if/then/else
    • 広まった
  • Fortran90
    • 1991年に標準化。
    • 大幅な改訂
  • Fortran95
    • F90からのマイナーバージョンアップ

Fortran90はFORTRAN77とは大きく違う。違う言語と考えるべき。

| f95 - f90 | << | f90 - f77 |

why Fortran90/95?

正しい理由

  1. 計算速度が速い
    • スーパーコンピュータは速さが命
    • C/C++でもFortranと同じくらい速いコードは書けるが、遅いコードも書けてしまう。
    • 言語としての自由度の違い。自由度が高いとコンパイラが困る。最適化ができなくなる。
  2. 便利
    • 道具(言語)は目的にあったものを
    • 数学的計算にはFortran90/Fotran95が適している
      • For-mula Tran-slator
    • 数値計算ライブラリの抱負な蓄積。Legacyなコード。財産。

間違った理由

『新しい言語を勉強するのは面倒だ。 FORTRAN77の何の不足もない。これでxx年やってきた。』

・・・Legacyな人間。時代に2010-1977=33年遅れている。

Fortran90/95に対する偏見

以下全てFORTRAN66/77と誤解している。

  • 変数名は6文字までなんでしょう?・・・そんなことはありません。
  • ソースコードは全部大文字なんでしょう?・・・そんなことはありません。
  • ソースコードは固定形式(7列目から72列目まで)なんでしょう?・・・そんなことはありません。
  • 構造体がないんでしょう?・・・あります。普通に使います。
  • ポインタがないんでしょう?・・・あります。あまり使う必要はありませんが。
  • 再帰呼び出しができなんでしょう?・・・できます。あまり使う機会はありませんが。
  • 関数とデータをまとめてひとかたまりにする(クラス化する)ことなんてできないんでしょう?・・・できます。普通にやっています。
  • データ/関数の隠蔽(カプセル化)ができないんでしょう?・・・できます。いつもしています。
  • 演算子を自分で定義することができなんでしょう?・・・できます。いつもしています。
  • 関数や演算子の多重定義ができなんでしょう?・・・できます。いつもしています。

Fortran90/95は現代のプログラミング言語である。

  • スーパーコンピュータ向けの言語としては最先端
  • 特に並列計算機には
  • 数値演算や計算機シミュレーションには最適な言語

まだ納得できないない?では例を一つ

部屋の中の温度場の分布から平均気温を求めよう。

温度場を3次元float配列 f(nx,ny,nz)で表す。3つの整数nx, ny, nzは不定。

平均気温=全ての格子点(i,j,k)上でのfの値を足して格子点の総数で割る

【演習】

任意サイズの3次元単精度実数(浮動小数点数)配列を受け取り、 その平均値を返す関数をC言語(またはC++言語)で作れ。

  • scalar上でのCコンパイラ=cc, gcc

Fortran90/95ではこう書ける。

わずか4行。

 real function mean_value(f)
   real, dimension(:,:,:) :: f
   mean_value = sum(f) / (size(f,1)*size(f,2)*size(f,3))
 end function mean_value

数式の表現が簡単な例(複素数)

$e^{i\pi} = -1$ つまり

e_i_pi.jpg

をFortran95で書くと、

complex :: i = (0.0,1.0)
real :: pi = 3.141593
print *,' exp(i*pi) = ', exp(i*pi)

例(行列の計算)

行列のかけ算はFortran90/95ではmatmulという組み込み関数を使う。 行列の転置をとる組み込み関数transposeも用意されている。 したがって、行列A(例えば10行10列の2次元配列)の転置と別の行列Bの積を計算しそれを行列Cとする計算、つまり

matmul_a_transpose_b.jpg

をFortran90/95で書くと、

 real, dimension(10,10) :: A, B, C
 C = matmul(transpose(A),B)

と一行で書ける。

例(級数)

級数

series_one_forth.jpg

の最初の1000項の和を求めるプログラムも、式をそのまま書けばいい。まさにFormula Translation。

integer, parameter :: nterms = 1000
real, dimension(nterms) :: x, y, z
integer :: i
do i = 1 , nterms
   x(i) = 1.0 / i
   y(i) = 1.0 / (i+1)
   z(i) = 1.0 / (i+2)
end do
print *,'ans = ', sum(x*y*z)

例(3次元ベクトル場のエネルギー)

空間中に分布する磁場(3成分のベクトル場)

Bx(100,100,100),  By(100,100,100),  Bz(100,100,100)

の全磁気エネルギーを計算して出力するには、

print *,' energy = ', sum(Bx**2+By**2+Bz**2)/2

と一行(定義式そのもの)を書けば良い。

diff f && c : C言語との比較によるFortran90/95入門

定番 hello, worldプログラム

C言語では

#include <stdio.h>
main () {
  printf("hello, world.\n");
}

Fortran90/95では

program hello_world
  implicit none
  print *, "hello, world."
end program hello_world
  • Fortran90/95ではmainプログラムは program nameとして宣言する。nameは任意。
  • implicit noneの意味は後述。
  • Fortran90/95では標準入出力は組み込まれている(ヘッダファイルをインクルードする必要はない)。
  • Fortran90/95では print *で標準出力へ。
  • 行末にセミコロン不要。
  • 文字列はダブルクォーテーションマーク(")で囲む。(C言語と同じ)
  • シングルクウォーテーションマーク(')でも同じ意味。(これはC言語と違う)

【演習】

  1. 計算機「scalar」 で、上のFortran90/95プログラムをエディタで入力し、 ファイル名hello_world.f95として保存せよ。
  2. ls -l コマンドでファイルを確認せよ。
  3. hello_world.f95 をコンパイルせよ。
    • pgf95 hello_world.f95
  4. 実行せよ。
    • ./a.out

ソースコード

大文字・小文字

  • Fortran90/95のソースコードではアルファベットの大文字と小文字は区別しない。
    • kobe と Kobe と KOBE は同じ
    • 文字列変数の中では当然区別される。

自由形式。C言語とほぼ一緒。

  • 1行は132文字まで

数字表現

  • 浮動小数点数
    • 1.
    • 0.1
    • 1e-1
    • 3.141593
    • 3.1415926535897932_dp ! 倍精度。dpは整数。通常8
    • 0.31415926535897932e-1_dp ! 上に同じ

【演習】

さきほど作ったhello_world.f95のメッセージ("hello, world.")を自由に変え、 コンパイル&実行せよ。

予約語

Fortran90/95には予約語が存在しない。 それが変数名かどうかコンパイラが賢く判断してくれる。

if (end==else) if=0

は文法的に問題ない。

コメント行の書き方

C言語では

 /* この間がコメント */

である。C99では // から行末までもコメントとなった。

Fortran90/95では

  ! 一行の中でこの文字以降がコメント( C99やC++、JAVAの//と同じ)

型名

C ( C99 )Fortran90/95補註
文字charcharacter
文字列char[n+1]character(len=n)nは文字長
整数intintegerinteger(kind=4)でも可
実数floatrealreal(kind=4)でも可
倍精度実数doublereal(kind=8)kindの整数はシステム依存
「長い」整数longinteger(kind=8でも可)kindの整数はシステム依存
bool( _Bool )logical値は .true. または .false.
複素数( _Complex )complex
構造体structtype詳しくは後述

定数

C言語

#define NX 100

Fortran90/95

integer, parameter :: NX = 100

宣言

C言語では変数の宣言はブロックの先頭にまとめて置く。(C99やC++はもっと自由だが。) Fortran90/95でも同じ。

暗黙の型宣言

Fortran90/95ではimplicit noneを省略すると「暗黙の型宣言」をしたことになる。 暗黙の型宣言とは、次の6つのアルファベット i,j,k,l,m,n で始まる変数は整数である等のルールである。 バグが入りやすいので、暗黙の型宣言は使わない方が良い。 &color(#ff0000){Fortran90/95プログラムでは常にimplicit none宣言をすること。}

暗黙の型宣言はなぜバグが入りやすいか

宣言したつもりのない変数を間違って使っていても気がつかない可能性がある。 例えば、次のプログラムにはバグがある。すぐに見つけられるか?

program use_implicit_none
  integer :: fresh_meat
  flesh_meat = 100 ! yen
  print *, "today's price = ", fresh_meat
end program use_implicit_none

【演習】

上のプログラムをuse_implicit_nene.f95というファイルに書き込み、コンパイル&実行せよ。

  • バグがあるのにコンパイラは教えてくれないだけでなく、 何事もないかのように正常終了する。しかも、それらしい答えを返す。 バグがあることに気がつかない!

【演習】

今作ったuse_implicit_nene.f95の2行目(program ...の次の行)に implicit noneと書いてから、コンパイルせよ。

配列

1次元配列

C言語

int array01[NX];

メモリ上に、array01[0], array01[1], array01[2], ..., array01[NX-1]と並ぶ。

Fortran90/95

integer, dimension(NX) :: array01

メモリ上に、array01(1), array01(2), array01(3), ..., array01(NX)と並ぶ。

配列のインデックスは1から始まる。

【演習】

大きさNXの1次元整数配列array_01を作り、 各要素に1,2,3,...,NXを代入した上で、 全要素の和をとるFortran90/95プログラムを書け。

2次元配列

C言語

int array02[NY][NX];

Fortran90/95

integer, dimension(NX,NY) :: array02

3次元配列

C言語

int array03[NZ][NY][NX];

Fortran90/95

integer, dimension(NX,NY,NZ) :: array03

行の継続

行末に&をつけると継続行

a = b + c + &
       d  + f

セミコロン

セミコロンは改行と同じ

tmp = right
right = left
left = tmp

tmp = right; right = left; left = tmp

は同じ。