Comments
Description
Transcript
Nagoya Institute of Technology
Nagoya Institute of Technology 連続体シミュレーション工学 Fortran 入門 名古屋工業大学 機械工学科 計測プログラム 後藤俊幸 Nagoya Institute of Technology はじめに Fortran (FORmula TRANslator) IBM が数値計算を目的に開発した世界初の高級プログラミング言語 (1950) ・ 数学演算に強い (行列演算、複素数、各種組み込み関数、etc) ・ C、C++などよりも数値計算ではパフォーマンスに優れている ・ 多くの数値計算ライブラリの資産 ・ 並列化も容易 ・ スパコンでのシミュレーションでも高パフォーマンスを発揮 Nagoya Institute of Technology Fortran の歴史 Fortran66 世界初のプログラミング言語の標準 Fortran77 固定形式 広く普及 多くの数値計算ライブラリが充実 (ベクトル型スパコン) Fortran90 抜本的変更 自由形式 構造化 (Fortran77文法を包含) 配列演算の強化 (ベクトル並列型スパコン) Fortran95 マイナーチェンジ Fortran2003 大きく変更 (Fortran90/95 を包含) Fortran2008 並列処理の標準化 (大規模スカラー並列型スパコン) Nagoya Institute of Technology 簡単な例 (自由形式) ! Computation of three kinds of averages 注釈行 Program Example_1_1 プログラム文 (なくてもよい) Real:: a,b,av1,av2,av3 型宣言文 すべての変数には型がある print *, ‘enter two numbers’ 画面(*:標準出力)に表示 Read *, a,b データを読み込む(*:キーボード) av1=(a+b)/2.d0 計算 av2=(a*b)**0.5 av3=2.0/(1.0/a+1.0/b) print *, av1,av2,av3 データを画面に書き出す End Program Example_1_1 End 文 Nagoya Institute of Technology Fortran まずは使ってみよう 手続き 1.エディターでプログラムを書く 各自が好きなエディターで先ほどの例題(教科書 p1)を入力 フォルダーに格納 p11.f90 (例えば「Fortran」という名称のフォルダー) 2.プログラムをFortranでコンパイル コマンドプロンプトを立ち上げる (講義中はこのウィンドウ内でしか使えません) スタート > すべてのプログラム > アクセサリ > コマンドプロンプト コマンドプロンプト: 右クリック > 送る > デスクトップ(ショートカット作成) ここで、cd コマンドで Fortran のあるディレクトリに移動 g95 p11.f90 (PCでは g95 という名称のコマンドになっています) エラーがなければ a.exe という実行ファイルができる 3.実行 a.exe と入力 Nagoya Institute of Technology ディレクトリ変更 コンパイル 実行 Nagoya Institute of Technology Fortran 文法 第1回 Nagoya Institute of Technology 使える文字 英字:A~Z(大文字・小文字どちらも使用可能。大文字と小文字は区別されない) 見やすいことが大事 数字:0~9 下線:_ 特殊文字:(空白) = + - * / ( ) , . ’ : ! ” % & ; < > ?$ 書き方 固定形式: 先頭から7コラム目から書き始め72コラムまで ファイル名は sample.for (Windows) sample.f (Unix) 自由形式: 1行をどこから始めてもよい ファイル名は sample.f90 この講義では自由形式で解説 Nagoya Institute of Technology 自由形式 行: 1行 132文字以内 ; で区切ると1行に複数の文が書ける x=1.d0 ; y=2.d0 ; z=3.d0 注釈行: 先頭が ! で始まる行、または空白行は注釈 文の途中の ! があると、それより右が注釈となる ! This is an example y=sin(x) ! Sine function 継続行: 長い行の場合には 行の最後に & をつけると次の行に継続される y= 1.0+ 2.0*x*x+ cos(x) & + 0.5*sin (2.0*x) 空白: 実行文や命令語 以外では空白を入れてもよい ○ endif ○ end if ○ forall × for all Nagoya Institute of Technology プログラム構成 main program [Program プログラム名] ……. ……. end [Programプログラム名] sub program プログラム単位 省略可 Example Program main ….. call time_advance (u1,u2,u3) ….. End program main プログラム単位 副プログラム種別名 副プログラム名 省略不可 ……. ……. end [副プログラム種別名 [副プログラム名] ] Subroutine time_advance (u1,u2,u3) …… return End Nagoya Institute of Technology 文の種類 宣言文: 実行に必要なメモリ領域の大きさなどを設定 real*8 :: a,b,c ; integer :: i,j,k dimension (10,10):: array 非実行文 実行文: 実行時に計算や処理の流れを制御 do i= 1,10 a(i)=2*I if (I > 3) exit end do 文の順序 プログラム単位開始文 (program 文、subroutine 文, function文) 宣言文 (型宣言文、Common 文) Data 文 実行文 Contains 文 End (1つのプログラム単位内に必ず1つ必要) Nagoya Institute of Technology プログラム単位名、変数名の名前の付け方 英字で始まる31文字以下の 英字、下線、数字で構成 vel1, vel2, stream_function, Potential_1 random_number_generator 変数と定数 変数: プログラムの実行によってデータの値が変わるもの スカラー変数、 ベクトル変数、 配列変数 どの変数がどのような型 (整数、単精度実数、倍精度実数、…)かが大事 定数: プログラムの実行中でもデータの値が変わらないもの 整定数 通常 4バイト (8×4=32bit) -231=-2147483648 ~ 231-1= 2147483647 実変数 単精度 4バイト、、倍精度 8バイト 小数形式 3.141592 指数形式 7.199847e-12 複素定数 2つの4バイト実数の組 論理定数 4バイト .true. 2+3i=(2.e0, 3.e0) .false. 文字定数 1文字が1バイト、 日本語は1文字2バイト ‘Sample’ “例題” の範囲 Nagoya Institute of Technology 構文名 loop1 : loop2 : do j=1,n2 do i=1,n1 ………….. この部分がとても長いときや内部に 多くの do loop が混在するときに有効 ………….. end do: loop2 end do: loop1 Nagoya Institute of Technology 数値計算 代入文 変数=変数、定数、数式 = は右辺の計算値を左辺の変数に代入するという意味 Program summation integer :: sum sum=0 do i=1,100 sum = sum+1 end do print *, sum end 和を計算する典型的な計算スキーム Nagoya Institute of Technology 算術演算 足し算 引き算 掛算 割り算 べき乗 + – * / ** a+b a-b a*b a/b x**3 = x*x*x 演算の優先順位 足し算、引き算 < 掛算、割り算 < べき乗 ( )がなければ左から右に向かって演算、 怪しいときには( )を使う x+y*z= x+(y*z) x/y/z= (x/y)/z x*y**2= x*(y**2) x**y**2=x**(y**2) Nagoya Institute of Technology 実行の順序 文字列の出力 上から順位実行される print *, ` 出力したい文字列‘ integer :: s s=10 s=s+1; print *, s s=s+1; print *, s s=s+1; print *, s end real, parameter :: pi=3.14159265 real:: r,s read *,r s=pi*r*r print *, `radius, area`, r, s end Nagoya Institute of Technology 練習問題 1 正の実数 x と正の整数 n を読みこんで、 x**n と x**(1.e0/n) を求める 練習問題 2 摂氏の温度 C から華氏温度 F を求めること F=1.8C +32.0 練習問題 3 伸長 L (m) と体重 w (kg) から BMI (肥満度指数) を求めること BMI = w / L2 Nagoya Institute of Technology 練習問題 プログラム例 ! ex1 real:: x,xn,xn1 integer:: n read *,x,n x1=x**n xn1=x**(1.e0/n) print *,x,n,x1,xn1 end ! ex2 real::c,f read *,c f=1.8*c +32.0 print *,c,f end ! ex3 real::L,w,bmi print *,'Enter W and L' read *,w,L bmi=w/(L**2) print *,'weight[kg]=',w,', Hight[m]=',L, ', BMI=',bmi end Nagoya Institute of Technology 第2回 Nagoya Institute of Technology 流れを変える if, stop, goto, case 1 if 文 if ( 論理式、関係式、論理演算式 ) 実行文 ( ) の中が真の時だけ実行文を実行する Integer n, s n=32 s=1 if ( n>=10 ) s=2*s +1 2 stop 文 stop [ ‘メッセージ文’] end 文にまで行かなくてもその場で停止 Integer n if ( n<0 ) stop ‘n は正の整数でないといけません’ Nagoya Institute of Technology 3 goto 文 goto 文番号 ( go to でもよい) 指定された文番号の実行文までジャンプする 10 Integer:: n, s, k, sum k=0; s=0; sum=0 print *,’enter students mark (quit, if negative integer)‘ read *, n if ( n<0 ) go to 999 s=s+1 sum=sum+n if ( n >=60) k=k+1 go to 10 999 print *,‘Total and No . of students passed this exam. =‘,s,k print *,’Average of score =‘, sum/s end Nagoya Institute of Technology 関係演算子 > < <= == /= または .gt. .lt. .le. .eq. .ne. 大きい 小さい 小さいか等しい 等しい 等しくない if( n+m>0 ), if( a<4.5 ) 関係演算子の両辺の変数の型は一致していること 論理演算子 .not. .and. .or. .eqv. .neqv. 論理否定 論理積 「かつ」 論理和 「または」 論理等価 論理非等価 n=0 または 1 0 < k < 8 x=y=z (n==0).or.(n==1) (0<k).and.(k<8) (x==y).and.(y==z) Nagoya Institute of Technology 演算子の優先順位 .neqv. と .eqv. < .or. < .and. < .not. < 関係演算子 < 算術演算子 できるだけ ( )を用いる 優先順位が同等なら 左から優先的に判断される x+y> 1.0e0 (x+y) > 1.e0 (x<3.14) .or. (z<sqrt(2.e0)) Nagoya Institute of Technology If 構文 もっと機能的な if 文 [構文名:] if ( 論理式 ) then ……… 実行文 ……… endif [構文名] 構文名を付けたときにはいつもペアで用いる if ( 論理式 ) then ……… else ……… endif 飛出し可 if ( 論理式 ) then ……… else if ( 論理式 ) then ……… else 飛び込み禁止! ……… endif • 分岐はいくらあってもよい • if 構文の中にいくつもの if 構文があってもよい (多重if 構文) • if 構文の中に外から飛び込みがあってはいけない Nagoya Institute of Technology 入れ子構造 block1: if ( 論理式 ) then ……… block2: if ( 論理式 ) then ……… end if blcok2 ……… end if block1 block1: if ( 論理式 ) then ……… block2: if ( 論理式 ) then ……… end if blcok1 ……… end if block2 Nagoya Institute of Technology 例1 ! Calculating various functions real :: x print *,'input a real number:' read *,x if(x>0.0) then print *, sqrt(x), log(x), log10(x) else print *,' Not defined for x<0‘ end if end 組み込み関数 Nagoya Institute of Technology 例2 1 0 ! Triangle pulse real:: x,f print *,'input x:' read *,x if(x<0.0) then f=0.0 else if (x<1.0) then f=x else if (x<2.0) then f=-x+2.0 else f=0.0 end if print *, x,f end 1 2 x<0 はすでに除かれている x<1 まではすでに除かれている x<2 まではすでに除かれている Nagoya Institute of Technology case 構文 多数の場合わけに便利 [構文名:] select case ( 式 ) case ( 式の値、または式の値の範囲 ) !A 実行文 case ( 式の値、または式の値の範囲 ) !B 実行文 case default ! (上のA,B以外すべて) 実行文 end select [構文名] 場合分けに重なりが ないこと Nagoya Institute of Technology 例 integer :: i print *, ‘ Enter mark ‘ read *, I if ( i<0 .or. i>100 ) stop select case (i) case (90: ) print *, ‘秀’ case (80:89) print *, ‘優’ case (70:79) print *, ‘良’ case (60:69) print *, ‘可’ case default print *, ‘不可’ end select end Nagoya Institute of Technology 組み込み関数 数学演算でよく使われる関数 x, y:実数、 z:複素数、 exp (x) 総称名 sqrt(x) abs(x) sin(x) exp(x) log(x) log10(x) 引数 i, j, k : 整数 総称名:引数 xの型に合わせて値を返す x:単精度実数 exp(x):単精度実数 x:倍精度実数 exp(x):倍精度実数 z:単精度複素数 exp (z) :単精度複素数 z:倍精度複素数 exp (z) :倍精度複素数 z=cmplx(x,y) real(z) aimag(z) conjg(z) aint(x) int(x) anint(x) Nint(x) xの整数部 を実数で返す xの整数部を整数で返す xを四捨五入して実数で返す xを四捨五入して整数で返す Nagoya Institute of Technology 例 ! Calculating various functions real :: x,y complex::z print *,'input a real number:' read *,x if(x>0.0) then print *, sqrt(x), log(x), log10(x) else print *,' Not defined for x<0‘ end if print *,'input a complex number x,y (=x+iy):‘ read *, x,y z=cmplx(x,y) print *, sqrt(z), exp(z), log(z) end ノート 複素関数の定義 例えば z= i にとると Nagoya Institute of Technology X=2 と (x,y)=(0,1)を代入した例 Nagoya Institute of Technology 練習問題 1 正の実数 x を読みこんで、 整数部 と小数部 をもとめること 練習問題 2 2次方程式 ax2+bx+c=0 の a,b,c を入力し、判別式の値をもとに 解を実数の範囲で求めよ。 Nagoya Institute of Technology 練習問題 プログラム例 ! ex4 real:: x,y integer:: n read *,x n=int(x) y=x-aint(x) print *,x,n,y end ! ex5 real::a,b,c,d,x1,x2 print *,'Enter a,b,c' read *, a,b,c d=b*b-4.0*a*c if(d>=0) then x1=0.5*(-b+sqrt(d))/a x2=0.5*(-b-sqrt(d))/a print *, x1,x2 else print *, 'No real solution' endif end Nagoya Institute of Technology 第3回 Nagoya Institute of Technology Data の型 すべての変数には型がある integer :: 変数名のリスト (単精度整数 4バイト) real :: 変数名のリスト (単精度実数 4バイト) real*8 :: 変数名のリスト (倍精度実数 8バイト) complex :: 変数名のリスト (単精度複素数 8バイト) complex*16 :: 変数名のリスト (倍精度複素数 16バイト) real :: x,y real*8 ::d1,d2 complex::z integer :: n,m,l Nagoya Institute of Technology 初期値設定 型宣言文の中で変数の初期値を与える (プログラム単位が呼ばれたときに1回だけ行う) Real :: pi=3.14159265,s,r Integer :: n=30 Print * ‘Enter r’ Read *, r S=pi*r*r n=n+1 Print *, n,r,s End Real :: pi=3.14159265,s,r Integer :: n Print * ‘Enter r’ Read *, r S=pi*r*r n=30 n=n+1 Print *, n,r,s End 左は n に1回だけ30という値が設定される 右は n に30という値が代入される Nagoya Institute of Technology 暗黙の型宣言 i,j,k,l,m,n で始まる変数 整数型 それ以外 Kmin, Kmax, jnum, num 型の変換 組み込み関数を用いる x=real(k) n=integer(s) Z=cmplx(a,b) 実数型 Nagoya Institute of Technology !----Solar year ----real ::year,day,jikan,hun,byo integer :: d,h,m year=365.2422 day=aint(year) d=int(day) jikan=24.0*(year-day) h=int(jikan) hun=60.0*(jikan-aint(jikan)); m=int(hun) byo=60.0*(hun-aint(hun)) print*,'1yearis',d,'days',h,'hours',m,'minutes', & byo,'seconds‘ end Nagoya Institute of Technology 暗黙の型宣言の変更 implicit 型 (先頭文字、またはその範囲),・・・・ implicit real*8 (a-h, o-z) implicit complex (z) 先頭文字がa からh, o-zで始まる変数は すべて倍精度実数型 先頭文字がzで始まる変数はすべて複素数型 暗黙の型宣言の無効化 implicit none すべての変数の型宣言をしないとコンパイルエラーになる プログラムミスが減るので、積極的に利用するとよい Nagoya Institute of Technology 文字型と論理型 文字型宣言 文字列データ宣言には型と長さ(文字数)必要 character ([len=]長さ) :: 変数名リスト character :: 変数名1*長さ,変数名2*長さ,・・・・ character (len=8) :: c=‘doraemon’ character (2) :: fname, file, a 論理型宣言 logical :: 変数名リスト logical :: flag, index, range flag=.true. index=.false. range =(8.0<x).and.(x<10.0) cが文字変数 doraemonがその内容 Nagoya Institute of Technology 例題 Program Logical_example Implicit none logical :: hantei real:: a=0.e0, b=1.e0, x read *, x hantei=(a<x).and.(x<=b) print *, hantei End 判定の値は真(ture) なら T 偽(false) なら Fを出力 Nagoya Institute of Technology 名前付き定数 parameter 宣言 プログラム中で用いる定数に名前を付ける 型,parameter :: 定数の名前=定数の値または式 integer, parameter :: mask=2147483467 real , parameter :: pi=3.14159265, pi2=2.e0*pi character(1), parameter :: sp=‘ ‘, ap=“’” character(len=*), parameter :: f=‘This is Fortran95’ * にすると、実際に設定された長さになるので便利 Nagoya Institute of Technology 複素数型, 高精度型 complex :: 変数名リスト complex*16 :: 変数名リスト real*8 :: 変数名リスト real([kind=]8) :: 変数名リスト real(8) :: deg,rad,s,c real(8),parameter :: pi=3.141592653589793 print*,'Input angle variable in degree:‘ read*, deg rad=pi*deg/180.0 s=sin(rad) c=cos(rad) print*,'SIN=',s,', COS=',c print*,'COS^2+SIN^2=',s**2+c**2 end Nagoya Institute of Technology !----Complex number ----real :: x complex :: z integer :: n complex, parameter :: i=(0.0,1.0) ! print*,'Input a real number x and an integer n:' read *,x,n; z=exp(i*x) print*,z**n print*,cos(n*x),sin(n*x) end Nagoya Institute of Technology 異なる型の混合演算と代入 強い方の型に変換して型をそろえたのち、演算、代入を行う 整数型 < 実数型 < 複素数型, 単精度 < 倍精度 < 4倍精度 整数型 / 整数型 は整数型 ・データが短い変数は下位に0が代入される ・実数を複素数にするときには虚数部に0が入る 7/3 2 1/3 0 2**(-2) 1/(2**2) 0 N-m*(n/m) 正の整数nをmで割ったときの余り X**n x*x*....*x X**y exp(y*log(x)) xをn回かける Nagoya Institute of Technology 異なる型の代入 右辺を計算した後左辺の型に変換して代入 real :: a,b real*8 :: x a=0.0 b=2.14 x= a+b a+b は4バイト実数同士の足し算, xには下位に0を付けて8バイトに変換して格納される print *, a,b,x end Real ::x X=1.0e0/3 1.e0/3.e0 xに代入 X=(3.14e0, 2.56e0) X=5 xに3.14e0がはいる xに5.e0 が入る Nagoya Institute of Technology Real::x Real(8) ::y y=1.0e0/3.e0 1.e0/3.e0 単精度計算してさらに下位に0をつけてyに代入 y=2.0d0/3.e0 2.0d0/3.0d0 倍精度計算をしてyに代入 X=(3.14e0, 2.56e0) xに3.14e0が入る X=5 xに5.e0 が入る integer ::i i=-3.623 -3が入る i=(3.14e0, 2.56e0) iに3が入る i=5.0e0/3 iに1が入る complex ::z z=1.0e0 z=(1.0e0, 0.0e0) z=5.e0 z=(5.0e0, 0.0e0) Nagoya Institute of Technology 関数と引数の型 関数が総称名の場合 y=f(x) : 引数xに応じた型が f に当てはまる。その後 yの型に合わせて代入 x: 倍精度 f: 倍精度 x: 倍精度複素数 f: 倍精度複素数 Nagoya Institute of Technology レポート課題1 テキスト p.42, 問題 4-2、4-3,4-4、4-5 自分でプログラムを作成し、これをレポートに書きだす。 値を入力し、得られた計算結果をレポートに書き出す。 表紙と考察を付けること 締切 : 次回の講義時 10:30 まで 提出先 : 2号館B棟4階424B室前の レポート回収箱 レポート課題番号 学籍番号 氏名 提出日 Nagoya Institute of Technology 第4回 Nagoya Institute of Technology 繰り返し 膨大な計算を高速に行う 計算機の最も強力な能力 単純 do ループ [構文名:] do do変数=開始値, 限界値[, 増分値] ・・・・ end do [構文名] 省略すると 1 負の値も可能 ループを抜け出た時点では n=101 開始値が限界値を超えて いるときは実行しない Nagoya Institute of Technology 多重do ループ と 入れ子構造 Nagoya Institute of Technology ループ から抜けでる End do の直後の実行文に移る End do に移る Nagoya Institute of Technology integer :: m,n,mn var1:do m =2,9 var2: do n =1,9 print *,m,'*',n,'?' read *,mn if(mn==m*n)then print *,‘Correct' else print *,‘wrong' end if end do var2 end do var1 end Nagoya Institute of Technology 出力の書式指定 膨大な計算結果を見やすく配置する Print 書式識別子, 出力データリスト Write(*,書式識別子) 出力データリスト 書式識別子 * : 標準の書式 ‘(書式項目のリスト)’ (入力:キーボード、 出力:ディスプレイ) (書式項目のリスト) は文字定数になっている 空白 文番号 書式項目のリスト を含めて 文字 文はプログラム単位の どこにあってもよい Nagoya Institute of Technology 書式 編集記述子 Iw Fw.d w, d, n, r を整数として 整数データ 文字幅w 右詰め I5 : 56789 実数データ 文字幅w 右詰め 少数点以下d桁 w≥ d+2 d F5.2 : □2.35 , -4.12 5 w Ew.d 実数データ 10の指数形式 w≥ d+7 E12.5: -0.23452E-01 12 Dw.d 倍精度実数データ 10の指数形式 Aw 文字データ 文字幅w 右詰め A5 : abcde wを省略:文字データの幅に合わせて書く r ….. …. を r 回繰り返して書く nX n 桁スキップ w≥ d+7 n=1の時でも省略できない ‘……’ 文字定数を書式の中に直接書く “……” 同上 1x : □ 3x : □ □ □ ‘This is an example.’ ‘(1x, I3,1x, “Hx=“, F5.3)’ Nagoya Institute of Technology 編集記述子 つづき / ( 改行 ) 書式項目のリストの一部分を囲む 反復などに利用 ‘(/, 3(1x, e12.5))’ print * write(*,*) 出力行の間に1行の空白行を入れる read * read ‘(A)’ 文字列の時 Golgo13 ‘AKB48’ と ‘ ‘ で囲んで入力する 直接文字列を入力すればよい Nagoya Institute of Technology !ex5-3 !----- Table of SIN and COS ----real, parameter :: rad=3.1415926/180.0 real :: r,s,c,p integer ::k print *,"kakudo SIN COS CHECK“ do k=0,90,10 r=k*rad s=sin(r) c=cos(r) p=s*s+c*c print '(1x,i3,2x,3f10.5)',k,s,c,p end do end Nagoya Institute of Technology !ex5-4 !----- Mean and Standard Deviation ---integer :: n=0,mark real :: w=0.0,v=0.0,mean,sd do print *,'score ( 0<x end)' read *,mark if (mark<0)exit n=n+1 w=w+mark v=v+mark**2 end do if(n>0)then mean =w/n; sd=sqrt(v/n-mean**2) print '("average=",f5.1)',mean print '("sd=",f5.1)',sd end if print '("total=",i5)',n end 平均 標準偏差 Nagoya Institute of Technology 無限 do ループ !ex5-5 !---- saidai kouyaku suu --- integer :: m,n,k print *,'Imput two integer m,n(>0):' read *,m,n if(m>0 .and. n>0)then do k=mod(m,n) do ループから抜け出ることを if (k==0) exit 確かに保証する m=n n=k end do if (n/=1)then print *,'saidai kouyaku suu=',n else print *,'nothing' end if end if end Nagoya Institute of Technology ! --- Prime Number upto 100 --Integer :: n, m, q, max=1000 print *, 2 loop: do n = 3, max, 2 q=Nint(sqrt(real(n))) do m = 3, q, 2 if( mod(n,m)==0 ) cycle loop end do print *, n end do loop end ! 2以外の偶数は調べる必要がない ! q以下のすべての奇数を調べて ! 割り切れたときには素数でないので ! ラベル loop のループへ出る ! ループを通れば素数である ! cycle loop で,ここへ来る m 1 2 3 1 2 3 3からの奇数をqまで虱潰しに調べる. このqは以下のようにして 求めることができる.いま, qまで調べたとすると、このqの整数倍 は素数ではない. すなわち q*1,q*2,q*3,…, q*m は除外さ れる.こうして調べられるmの最大はqまで.mがq以上ならmとqを 取り換えればよい.このq*qがn以上であればすべて網羅したこと になるので、 q*q ≥ nと見積もれる. 3 n q n Nagoya Institute of Technology do while [構文名] : do while ( 論理式 ) ………… end do [構文名] do i=1,100 ……… end do 同等 i=1 do while (i<=100) ……… i=i+1 end do i=i+1 の位置に注意 i=1 do while (i<=100) i=i+1 ……… end do i=101 でも実行される Nagoya Institute of Technology !ex 5.7 ! Computation of sqrt(x) by recursive equation implicit none Real:: r=0.e0, x, d=1.e-5 Do print *,'Input a positive real number' read *, r if(r>0.e0) exit End do x=r do while (abs(x**2-r)/r >d) x=0.5e0*(x+r/x) end do print '(1x,e12.5)’, x end 収束条件: Nagoya Institute of Technology レポート課題2 テキスト p.56, 問題 5-2, 5-3, 5-6 自分でプログラムを作成し、これをレポートに書きだす 得られた計算結果をレポートに書き出す 表紙と考察を付けること 締切 : 次回の講義時 10:30 まで 提出先 : 2号館B棟4階424B室前の レポート回収箱 レポート課題番号 学籍番号 氏名 提出日 Nagoya Institute of Technology 数値積分 f(x) fj 階段公式 h x0 x1 台形公式 Simpson公式 xj xn x Nagoya Institute of Technology レポート課題3 テキスト p.57, 問題 5-5 の数値積分を以下に示す手順に沿って 行うこと 自分でプログラムを作成し、これをレポートに書きだす 得られた計算結果をレポートに書き出す 表紙と考察を付けること 締切 : 次回の講義時 10:30 まで 提出先 : 2号館B棟4階424B室前の レポート回収箱 レポート課題番号 学籍番号 氏名 提出日 Nagoya Institute of Technology 以下の積分を (1) 解析的に実行せよ (計算式をきちんと書くこと) (2) 数値積分を指定された2つの方法で求め、(1)で求めた結果と比較せよ (3) 分点数を変えたとき数値計算結果がどのように変化するかを考察せよ 階段公式と台形公式 台形公式とシンプソン公式 台形公式とシンプソン公式 積分の上端が∞の時には、関数にもよるがある有限な値 L を仮定し、これを少しずつ 大きくしていくことで求める精度内収束するかどうかを確認して積分値を求める。 exp(-x*x/2)の場合 L=5 と取ると exp(-12.5)=3.72e-06だからこの程度のLで十分であ る。Lを変えて積分値がどのように収束していくかをグラフで見てみるのも面白いだろう。 Nagoya Institute of Technology 第5回 Nagoya Institute of Technology 配列 ベクトル、行列などの大量の変数を扱う 数値計算の要 配列宣言文 (1次元) 型, dimension([下限: ]上限) :: 配列名のリスト 型:: 配列名([下限: ]上限) ,配列名([下限: ]上限) , …. 省略すると 1 x,r は配列ではない(スカラー) 寸法=上限ー下限+1 配列要素 添え字で指定する の の 番目の要素 番目の要素 Nagoya Institute of Technology 配列の初期値設定 配列定数 (/定数, 定数, 定数, …/) Do 型反復 配列構成子 (/(データのリスト, do 変数=初期値, 限界値, [増分値])/) データのリスト が配列構成子 実行文中でも使える Nagoya Institute of Technology 配列の演算 配列に対する、代入、足し算、引き算、掛算を同時に行う (1) 部分配列 配列名 ([添え字の開始値]: [限界値][:刻み幅]) は要素数が1の1次元配列とみなす OK NO はスカラー は1次元配列 Nagoya Institute of Technology (2) 配列代入文 配列=同じ形状の他の配列 (形状:寸法と次元数) すべての要素が0 奇数番が1 偶数番が0 Nagoya Institute of Technology 並び替え !----Sorting Array Elements ----integer::m,mark(100),n=0,max,maxi,i,j do while(n<=99) print*,"Input integer,or negative one to stop:" read*,m; if(m<=0) exit n=n+1; mark(n)=m end do !----Sorting do i=1,n-1 1 2 max=mark(i) 1 maxi=i 2 do j=i+1,n if(mark(j)>max) then max=mark(j) i maxi=j end if end do if(maxi/=i) then mark(maxi)=mark(i) mark(i)=max n end if end do !----Output do i=1,n print"(' Rank',i3,' =',i10)",i,mark(i) end do end n i+1 最大値を探索 i j 入れ替え Nagoya Institute of Technology (3) 配列演算式 配列名のままで要素間の演算を一括して書く real::x(0:4)=(/(2.0**n,n=0,4)/) x=x(0:4)*x(4:0:-1) print*,x end Nagoya Institute of Technology (4) ベクトル演算 配列に対する演算を同時に行う と は演算の内容が異なる! A time a(0) a(1) a(2) a(3) a(4) a(5) a(6) a(7) a(8) a(0) a(1) a(2) a(3) a(4) a(5) a(6) a(7) a(8) a(9) 0 0 1 2 3 4 5 6 7 8 B a(9) time a(0) a(1) a(2) a(3) a(4) a(5) a(6) a(7) a(8) a(9) 0 0 0 0 0 0 0 0 0 0 Nagoya Institute of Technology (5) 配列の入出力 配列名でまとめて出力するやり方と do 構文で書くやり方のちがいに注意 1行に10個 1行に1個を10行にわたって書く Nagoya Institute of Technology !----Pascal's Triangle ----integer, parameter::max=12 i integer::i, c(0:max)=0 c(1)=1 0 do i=1,max 1 c(1:i)=c(1:i)+c(0:i-1) print'(i2,":",50i5)',i,c(1:i) max 1 end do end program 1 1 1 1 2 3 4 1 3 6 0 1 4 1 Nagoya Institute of Technology 多次元配列 型, dimension([下限: ]上限, [下限: ]上限, …. ) :: 配列名のリスト 型:: 配列名([下限: ]上限, [下限: ]上限, …. ) , …. または または または 多次元配列要素の順序と構成 a(1,1) a(1,2) a(2,1) a(2,2) a(3,1) a(3,2) メモリー上に記録される仕方 結果は同じだが右のほうが計算が速い Nagoya Institute of Technology 配列の動的割り付け 実行時に必要な分だけ配列を割り当て、いらなくなったら開放する 型, allocatable :: 配列変数名(:, :, ….) のリスト または 型, dimension (:, :, …) , allocatable :: 配列変数名のリスト …… allocate (配列変数名(添え字範囲の指定), …. ) …… deallocate(配列変数名, …. ) Nagoya Institute of Technology !----Matrix Product ----integer,dimension(:,:),allocatable::a,b,c integer::m=0,n=0,k=0,i,j,h ! do while(m<=0.or.n<=0.or.k<=0) print*,"Input Array Size m, n, k ( > 0) :" read*,m,n,k end do allocate(a(m,n),b(n,k),c(m,k)) ! print*,"Input Elements of A in a Matrix Form:" read*,((a(i,j),j=1,n),i=1,m) print*,"Input Elements of B in a Matrix Form:" read*,((b(i,j),j=1,k),i=1,n) ! do i=1,m do j=1,k c(i,j)=0 do h=1,n c(i,j)=c(i,j)+a(i,h)*b(h,j) end do end do end do do i=1,m print"(10i5)",(c(i,j),j=1,k) end do end Nagoya Institute of Technology where 文 配列のある条件を満たした要素の位置だけ、その配列に配列代入文を実行する where (選別式)配列代入文 同時的代入 where 構文 [構文名:] where (選別式) 配列代入文群 elsewhere (選別式) 配列代入文群 end where [構文名] Nagoya Institute of Technology forall 文 forall (添え字範囲式,[選別式])指標の書かれた配列代入文 指標変数=[開始値]:[限界値][:刻み値] 同時的代入 Nagoya Institute of Technology forall 構文 [構文名:] forall (添え字範囲式,[選別式]) 指標のついた配列代入文群 end forall [構文名] Nagoya Institute of Technology Nagoya Institute of Technology 第6回 Nagoya Institute of Technology 文字列データ 人とコンピュータとのインターフェース、 データの効率的、機能的管理 文字型宣言 character ([len=]長さ) :: 変数名リスト character :: 変数名1*長さ,変数名2*長さ,・・・・ character :: 配列名([下限: ]上限) *長さ,・・・・ character (len=8) :: a,b,c=‘doraemon’ character :: fname(1:10)*8 文字部分列 文字列の1部分 文字変数名([文字位置の下限]:[上限]) character (len=8) :: C(3:3) C(4:8) r emon c=‘doraemon’ 1文字 Nagoya Institute of Technology 文字代入 文字は左詰めで代入 はみ出た分は切り捨て character (len=8) :: c 左辺の文字変数の長さ = 右辺の文字列の長さ D o r a e m o n < K o l m o g o r > D i a character (len=8) :: a=‘abcdefgh’ a(1:5)=a(2:6) ‘bcdeffgh’ a(2:6)=a(1:5) ‘aabcdegh’ r c o v Nagoya Institute of Technology 整数の16進表示 !---- Hexadecimal Representation ---Implicit none Integer :: dec, i character(len=1) :: h(0:15)=(/'0','1','2','3','4','5','6','7' & ,'8','9','A','B','C','D','E','F'/) character(len=8) :: hex 232=168=(24)8 ext: do hex=" " print*, "input a positive integer,or 0 to stop:" read*, dec; if(dec<=0) exit ext hxd: do i=0,7 hex(8-i:8-i)=h(mod(dec,16)) dec=dec/16 if(dec==0) exit hxd end do hxd print ‘(1x,A8)’, hex end do ext end 右から埋めていく 次の桁へ行く 4 0 E Nagoya Institute of Technology 文字列の連結 文字列1 // 文字列2 character:: a*9,f*7='Fortran', g*2='95' a=f//g Print '(1x,a9)', a Fortran95 f='boy' g='s' a=f//g boy____s_ print'(1x,a9)', a end Character (1) :: f(9)=(/'1','2','3','4','5','6','7','8','9'/) Character (22):: fmt Integer :: n,k n=2; k=3 Read *, int fmt="( 2x, 'Int = ', "//f(n)//"I"//f(k)//" )" Print fmt, int end Print ( 2x, ‘Int = ’, nIk ), int と書いたことになる Nagoya Institute of Technology 単語の並び替え !---- rearrange characters of a word---character(len=4) :: w0,w1,w2,w(1:24) integer :: i,j,k,n=1 print*,“input a word in 4 letters: " read '(a)',w0 1番目に来る文字を先頭から順に選ぶ do i=1,4 w1=w0(i:i)//w0(1:i-1)//w0(i+1:4) b l u 2番目に来る文字を2番目以降から順に選ぶ do j=2,4 w2=w1(1:1)//w1(j:j)//w1(2:j-1)//w1(j+1:4) do k=3,4 w(n)=w2(1:2)//w2(k:k)//w2(3:k-1)//w2(k+1:4) n=n+1 end do end do end do print '(/12a5))', w end e u l b e Nagoya Institute of Technology ファイル入出力 1.少量の計算データの格納と取り出し コンソール入出力 (キーボードとディスプレイ) print 書式識別子, 出力リスト read 書式識別子, 出力リスト f=‘( A10, F10.5 )’ write(6,f) x write(*,‘( A10, F10.5 )’ ) x print‘( A10, F10.5 )’, x f=‘( 3I10 )’ read(5,f) i,j,k read(*,‘( 3i10 )’) i,j,k read(*,100) i,j,k 100 format(3i10) 同じ 同じ Nagoya Institute of Technology ファイル入出力 2.ハードディスク上での大量の計算データの格納と取り出し 入出力ファイルの割り当て open 文, close 文 ハードディスクとの結合と分離 open([unit=]ファイル装置番号, file=ファイル名 [,制御項目]) close([unit=]ファイル装置番号, file=ファイル名 [,制御項目]) ファイル指定入出力 write([unit=]装置識別子,[fmt=]書式識別子 [,制御項目])出力リスト read([unit=]装置識別子,[fmt=]書式識別子 [,制御項目])出力リスト CPU open(10,file=‘ data1’) open(20,file=‘ data2’) read(10) u1 write(20) u2 close(10) close(20) DISK open(10,file=‘ data1’) data1 u1 data2 u2 open(20,file=‘ data2’) Nagoya Institute of Technology open 文, close 文 open([unit=]ファイル装置番号, file=ファイル名 [,制御項目]) close([unit=]ファイル装置番号, file=ファイル名 [,制御項目]) 装置識別子 • • • unit を省略するときはファイル装置番号を先頭に書く ファイル装置番号 は正の整定数または整数型変数(式) ファイル名は 入力ファイル名を文字定数または文字変数で与える 制御項目 iostat= 整数変数 i 正常 i=0 エラー i > 0 status=‘文字列 ‘ old : 既存のファイルでなければならない new : 同名のファイルが存在してなならない replace : 同名のファイルあれば上書き unknown : 入力ではnew, 出力ではreplace delete : 終了後ファイルを消去(close 文のみ) status= を省略すると unknown position=‘文字列 ‘ rewind : 先頭位置から開始 append : 最終行のあとに追加 Nagoya Institute of Technology ファイル指定入出力 write([unit=]装置識別子,[fmt=]書式識別子 [,制御項目])出力リスト read([unit=]装置識別子,[fmt=]書式識別子 [,制御項目])出力リスト 装置識別子 * 番号 6 文字変数 コンソール入出力 open文で割り当てられるファイル装置番号 コンソール 内部ファイル 制御項目 iostat= 整数変数 i 正常 i=0 エラー i>0 ファイルが終了 i < 0 advance=‘no’ 入出力後に改行しない Nagoya Institute of Technology 書式なし入出力文 書式識別子のない入出力文 バイナリ―データを入出力するので高速 大量のデータの入出力に使う real*8, dimension(-10000:10000) :: a,b,c,d read(10) a,b write(20) c,d 内部ファイルの方法 character::d*10 Integer ::p=123456789 write(d,’(i10)’ ),p d=‘_123456789’ dに数字列が右詰めで入る Nagoya Institute of Technology 例1 Open (8,file=‘result’) Write(8,’(8f10.7)’) (x(i),i=1,8) close(8) character(80) :: line(1:1000) open(11,file=‘../mydata/report.txt’) do j=1,1000 read(11,’(a)’,iostat=io) line(j) if(io<0) exit データの終わりに来たら do を出る end do close(11) character:: filename*10 print*, ‘Input file name?’ read ‘(a)’, filename open(10,file=filename) Nagoya Institute of Technology 例2 iw.m : w桁の整数を右詰で書く m桁より短い時には0を数字の前に書き加える irun=32 のとき 0032 character(4) :: fn . . . . irun=32 write(fn,'(i4.4)') irun 内部ファイルの方法 open(10,file=‘int_'//fn//‘.dat') Int_0032.dat というファイルが新たに作られる open(20,file=‘spect.dat’) . . . . write(10,’(1x, 2(f7.4,1x))’) time,esum . . . . write(20) (energy(i), i=1,kmax) close(10) close(20) spect.dat というファイルが新たに作られる 例3 read(8,’(i10)’,iostat=i) k If(i>0) stop ‘Input file error’ Int_0032.dat に time, esum のデータを書き出す spect.dat にenergy のデータを書き出す Nagoya Institute of Technology その他 ファイル入出力制御文 1つ前の記録の先頭に戻る backspace([unit=]ファイル装置番号, isostat=整数変数) ファイルの先頭に戻る rewind([unit=]ファイル装置番号, isostat=整数変数) ファイル終了記録を書き込む endfile([unit=]ファイル装置番号, isostat=整数変数) Nagoya Institute of Technology !------ Character Code Table -----integer ::i,j open(8,file='Code_table') do i=0,31 write(8,"(7(2x,i3,2x,a))")(i+32*j,char(i+32*j),j=1,7) end do close(8) end Nagoya Institute of Technology 第7回 Nagoya Institute of Technology 副プログラム 構成的プログラムをつくる 主プログラム 副プログラム Subroutine あるまとまった計算・作業のみを行う ….. call sub_A call sub_B ….. call sub_C …. call sub_A …. end sub_A よくできたサブルーチンは他の プログラムでも使える sub_B sub_C call sub_G sub_G routine 決まりきった仕事, 日常の仕事 Nagoya Institute of Technology subroutine example 3つの数字を読んで、大きい順に並び替える 元プログラム サブルーチン implicit none integer :: i,j,k read *,i,j,k if(i<j) call swap(i,j) if(j<k) call swap(j,k) if(i<j) call swap(i,j) print *,i,j,k end ! ! ! subroutine swap(p,q) integer :: p,q,r r=p; p=q; q=r end 実引数 (実際に出入りする変数) 仮引数 (仮に与えられた変数) Nagoya Institute of Technology subroutine文 subroutine サブルーチン名[(仮引数のリスト)] ……….. end subroutine [サブルーチン名] 配列も許される 仮引数のないものもある call 文 call サブルーチン名[(仮引数のリスト)] return 文 return 元プログラムに戻る位置を設定する ……… call sub(…,code) select case(code) case(1) …… case(2) …… default …… end select …… subroutine sub(…,return_code) …… return_code=1 return …… return_code=2 return …… return_code=999 end subroutine sub Nagoya Institute of Technology 副プログラム ・ 主プログラムはただ一つ ・ 副プログラムはいくつあってもよい ・ 副プログラムから他の副プログラムをよんでもよい ・ 副プログラムが自分自身を呼ぶことはできない(再起呼び出し指定があれば別) ・ 実引数と仮引数の型、個数、形状は一致していなければいけない Nagoya Institute of Technology 実引数と仮引数の型、個数、形状は一致していなければいけない integer, parameter::n=100 real, dimension (0:n):: x,y ……… call set_initial(x,y,n) ……… End ! subroutine set_initial(a,b,m) integer :: m,i real, dimension(0:m)::a,b do i=0,m a(i)=0.0 b(i)=0.0 end do end set_initial 実引数の個数、型、形状 仮引数の個数、型、形状 変数の順序に注意! 並んだ順に渡される call set_initial(y,x,n) subroutine set_initial(a,b,m) ・変数の個数、型、形状が一致していること ・変数の順序に注意 ・変数間の対応が取れていればよく、同じ変数名である必要はない Nagoya Institute of Technology 変数の有効範囲 変数名は1つのプログラム単位内でのみ有効 文番号、構文名も1つのプログラム単位内でのみ有効 主プログラム ….. call sub_A …. y=sin(2.0*x) …. print *, x,y end 副プログラム 変数 x,y は 共有しない Subroutine sub_A …. x=2.0*k y=exp(-x) ….. end subroutine sub_A どうやって変数を共有するのか? 文番号、構文名は共有する方法がない (なくても困らない) Nagoya Institute of Technology 変数の共有方法 1 引数として共有する 2 common文を用いる 3 module文を用いる 1.引数として共有 call set_initial(x,y,z,n) (x,y,z,n) (a,b,c,m) 2. common文 subroutine set_initial(a,b,c,m) ・変数の個数、型、形状が一致していること ・変数の順序に注意 ・変数間の対応が取れていればよく、同じ変数名である必要はない common[/共通ブロック名/]変数のリスト プログラム1 common/param1/x,y,z Common/param2/a,pi …. プログラム2 common/param1/p,q,r …. (x,y,z) (p,q,r) プログラム3 common/param2/s,pi …. (a,pi) (s,pi) ・変数の個数、型、形状が一致していること ・変数の順序に注意 ・変数間の対応が取れていればよく、同じ変数名である必要はない Nagoya Institute of Technology save 宣言 副プログラムが1度呼び出されたとき定義された変数の値は、次回にその副プログラム が呼び出されたとき、その値を保持しているかどうかはわからない 確実に保証する場合に save 文を用いる 主プログラム integer :: n real :: z do n=1,100 call sub_A(z,n) …… end do end 副プログラム subroutine sub_A(w,k) real, save :: pi …… if(k==1) then …… pi=3.14159265 save宣言がないと2回目以降 end if piの値が確定しているかどう w=cos(0.1*pi*k) か保障されない …… end subroutine sub_A Nagoya Institute of Technology 仮引数の授受属性 引き渡される変数が、入力(in)、出力(out)、入出力(inout)のいずれかを特定 間違い防止に効果がある intent 宣言 型, intent(in, out, inoutのいずれか)::変数名のリスト implicit none integer :: i,j,k read *,i,j,k if(i<j) call swap(i,j) if(j<k) call swap(j,k) if(i<j) call swap(i,j) print *,i,j,k end subroutine swap(p,q) implicit none integer, intent(inout) ::p,q integer :: r r=p; p=q; q=r end Nagoya Institute of Technology 例題1 !------Drawing a Histogram -------integer :: nn(0:9),j character(len=80) :: cn character(len=30) :: fmt nn=(/1,5,12,22,28,35,48,28,10,3/) fmt='(1x,i2,"-",i2,1x,a50)' do j=0,9 call str(nn(j),cn) 50-59 I############ という具合に書き出す print fmt,10*j,10*j+9,cn end do end ! subroutine str(n,c) integer, intent(in) :: n character(len=80), intent(out) :: c integer ::k コメント文にしてみる ! c=‘ ‘ c=‘ ‘ c(1:1)='I' do k=2,n+1 I######### を書く c(k:k)='#' end do end Nagoya Institute of Technology 例題2 subroutine count(n) implicit none integer, intent(out) :: n integer :: i, sum=0 ! sum=0 do i=1,10 sum=sum+i end do n=sum sum に初期値を設定 (一番最初だけ) 毎回 sum=0 にする end subroutine count ! Program main implicit none integer :: n call count(n) print '(1x,i6)',n n=55 call count(n) print '(1x,i6)',n n=110 end 前のsum=55がそのまま残っているから Nagoya Institute of Technology 外部関数 プログラマが副プログラムを用いて自分で定義する関数 外部手続 : サブルーチン、外部関数 組み込み手続き : Fortran システムであらかじめ用意されている数学関数 関数副プログラム [型] function 関数名(仮引数のリスト)[result(変数名)] ……… end function 関数名 function 関数名(仮引数のリスト)[result(変数名)] 型 :: 関数名 または result 変数名 ……… end function 関数名 関数の値の代入の仕方 関数名 または result 変数名= 関数の値を与える式 Nagoya Institute of Technology 関数の値の代入 関数名 または result 変数名= 関数の値を与える式 外部関数の引用 関数名(実引数のリスト) integer :: n=100 real :: x,dx,sum=0.0,a=1.0 dx=1.0/n do i=1,n-1 x=i*dx sum=sum+fr(x,a) end do 台形公式 sum=(sum+0.5*(fr(0.0,a)+fr(1.0,a)))*dx print ‘(1x,e10.3)’,sum end ! real function fr(x,p) ・変数の個数、型、形状が一致していること ・変数の順序に注意 real :: x,z,p ・変数間の対応が取れていればよく、同じ変数名である必要はない z=(p-x*x)/(p+x*x) fr=log(z) end function fr Nagoya Institute of Technology 例題 16進表現 !-- Generating a Hexadecimal Representation ------function hex(n) character(len=8) :: hex character(len=1) :: h(0:15)=(/ '0','1','2','3','4','5','6','7',& '8','9','A','B','C','D','E','F'/) integer, intent(in) ::n n は入力 integer :: nin,j,nn hex=' ' nin=n do j=8,1,-1 nn=nin/16 hex(j:j)=h(nin-16*nn) hex は文字型変数で出力 右から埋めていく if(nn==0) exit nin=nn end do end function hex !---- Main ---program main implicit none character(len=8) :: hex integer :: i print *, 'Input a positive Integer or negative one to stop:' do read *, i; if(i<0) exit print *,hex(i) end do end Nagoya Institute of Technology 関数属性宣言 使用する関数の名前が外部関数名(組み込み関数名)であることを コンパイラに知らせる external 宣言 型, external :: 関数名のリスト external :: 関数名のリスト intrinsic 宣言 外部関数名がたまたま組み込み関数名と同じになったとき 外部関数の定義が優先される 型, intrinsic :: 関数名のリスト intrinsic :: 関数名のリスト call integral(gamma,0.0,1.0,s) ………… real function gamma(x) ………… 関数が引数として入るときには属性宣言が必要 Nagoya Institute of Technology 例題 implicit none real:: h, phix,err real, external ::Gaussian print *, 'What is your deviation value?' read *, h real function Gaussian(s) implicit none real, parameter :: rn=2.506628e0 real, intent (in) :: s Gaussian=exp(-s*s/2.0e0)/rn end function Gaussian h=(h-50.0e0)/10.e0 call simpson(Gaussian, 0.0e0,h, 16,phix) err=(0.5e0-phix)*100.0e0 print '(1x,a,f6.2,a)', & 'From the top you are ', err, ' %.' end subroutine simpson(func,a,b,kubun,integ) implicit none integer, intent(in)::kubun integer:: i real, external :: func real, intent(in) :: a,b real, intent(out) :: integ real :: x,dx x dx=(b-a)/(2.0e0*kubun) integ=func(a)+4.0e0*func(a+dx)+func(b) do i=1,kubun-1 x=a+(2.0e0*i)*dx integ=integ+2.0e0*func(x)+4.0e0*func(x+dx) end do integ=integ*dx/3.0e0 end subroutine simpson Simpsonの公式 ! \sqrt(2*pi) Nagoya Institute of Technology 内部手続き サブルーチンや関数を1つのプログラム単位の中に含めてしまうこと integer :: n real :: z,g,pi pi=3.14159265 do n=1,100 call sub_A(z,n) …… g=func(z) …… end do ……… Contains subroutine sub_A(x,m) ……… z=log(func(x)) ……… end subroutine sub_A ! real function func(x) ……… func=0.5*exp(-pi***0.25d0) end function func end contains文 サブルーチン、関数の規則が当てはまる 1.親プログラム中で、内部手続き関数名に対する型宣言および 関数属性宣言は不要 real, external :: func エラーとなる 2.親プログラム中で使われている変数名、配列名は内部手続き中でも 有効.親プログラムと同じ値を共有し内部手続き中で宣言する必要なし pi=3.14159265 3.親プログラム中で使われている変数名と同じ名前を内部手続き中で 型宣言すると、その変数は内部手続き中でのみ有効な局所変数と みなされ、親プログラムと共通の値を持たなくなる 4.内部手続き中に contains 文を書くことはできない 5.内部手続きから同じ親プログラム単位中の別の内部手続きを引用する ことは可能 func 6.内部手続きの end 文では、後ろの手続き種別(subroutine, function) などを省略できない(省略すると親プログラムの end 文と区別がつかな くなる) Nagoya Institute of Technology 例題 !----- All Round Calendar -----program main character(len=9) :: name(0:6)=(/'Sunday ', & 'Monday ', 'Tuesday ','Wednesday', & 'Thursday ','Friday ','Saturday '/) integer :: md(1:12)=(/31,28,31,30,31,30,31,31,& 30,31,30,31/) integer :: y,m,d,ld do print *,'year?' read *,y; if(y<=0) exit md(2)=28+leap(y) print *,'month?‘ do read *,m; if(0<m .and. m<=12) exit print *, 'm<=12' end do print *, 'Day?' read *, d if(d<=0 .or. d>md(m)) then print *, 'nothing' else call count(ld) print "(1x,i5,',',i2,',',i2,',',a9,a/)", & y,m,d,name(ld) end if end do ! contains ! 西暦1年1月1日から何日目かを数えて曜日を算出 subroutine count(n) integer, intent(out) :: n n=yday(y)+sum(md(1:m-1))+d n=mod(n,7) end subroutine ! ! 前年の12月31日が西暦1年1月1日から何日目か function yday(x) result(days) integer :: x,days days=365*(x-1)+(x-1)/4-(x-1)/100+(x-1)/400 end function yday ! integer function leap(x) 閏年なら1、平年なら0 integer :: x leap=yday(x+1)-yday(x)-365 end function leap ! end program Nagoya Institute of Technology 配列の共有 数値計算では非常によく出てくる 親プログラム中の配列をその形状や寸法に応じて副プログラムに渡す 1.形状明示配列 添え字の上下限が明示されている配列 (静的) 2.形状引き継ぎ仮配列 副プログラムの宣言文で寸法は指定しないでおき、引用した段階で送られてく る実引数配列の寸法に連動して割り付ける配列 (動的) Nagoya Institute of Technology 形状明示配列 添え字の上下限が明示されている配列 (静的) 添え字の上下限(寸法)の渡し方 1.仮引数になっていて元プログラムから値が送られてくる整数変数 2.仮引数となっている配列から size 関数によって求められる寸法の値 3.Common文により元プログラムと値を共有する整数変数 4.内部手続きにおいては、親プログラム中の整数変数 Subroutine sub(x,n) integer, intent(in):: n integer :: a(1:n),j real, intent(out) :: x real, allocatable ::temp(:) allocate(temp(0:n)) a(1:n),temp(:) 仮引数ではなく、サブルーチン内だけで使用される配列 Nagoya Institute of Technology 例題 応募者 n 人の中から抽選で m 人を選ぶ program main integer, allocatable :: number(:) integer ::n,m,i print *,‘応募者数は?’ read*,n 応募者数 print *, ‘当選者数は?’ read*,m 当選者数 allocate(number(n)) call chusen(number,n,m) ! print *,‘順位 当選番号’ do i=1,min(n,m) print '(2x,i4,i8)',i,number(i) end do end subroutine ran(i,r) (0,1)の一様疑似乱数生成 integer, intent(inout):: i real, intent(out) :: r integer, parameter ::mask=2147483647,a=48828125 i=iand(a*i,mask) r=real(i)/real(mask) end subroutine subroutine chusen(kk,n1,n2) integer, intent(in) :: n1,n2 integer, intent(out) :: kk(n1) integer :: i,ir,j,temp real ::x kk=(/(i,i=1,n1)/) print *,'ir' read *, ir do i=1,min(n1,n2)-1 call ran(ir,x) j=i+int(x*(n1-i+1)) temp=kk(i) kk(i)=kk(j) kk(j)=temp end do end subroutine 乱数の種(任意の正の整数)を入れる (0,1)の乱数 残りから選ぶ i,j を入れ替える Nagoya Institute of Technology 形状引き継ぎ仮配列 副プログラムの宣言文で寸法は指定しないでおき、引用した段階で送られてくる 実引数配列の寸法に連動して割り付ける配列 (動的) 親プログラム 副プログラム integer, parameter:: n=100 real :: u(0:n,0:n),x(0:n),y(0:n) interface subroutine fmake(w,a,b) real, intent(in)::w(0:,0:),a(0:) real, intent(out)::b(0:) end subroutine fmake end interface ………… call fmake(u,x,y) ………… end 実引数の実際の大きさに 合わせて割り付けられる Interface 構文でコンパイラに予め副プログラムの 構造を知らせておく subroutine fmake(w,a,b) real, intent(in)::w(0:,0:),a(0:) real, intent(out)::b(0:) integer ::m Real :: sum m=ubound(w,1) W の第1次元方向の上限値 do i=0,m sum=0.0 do j=0,m sum=sum+w(i,j)*a(j) end do b(i)=sum end do end subroutine fmake Nagoya Institute of Technology interface 構文 Interface 引用する手続き名 その中の仮引数の形状、属性など end interface 例1 Subroutine test(x) implicit none real :: x(:) ! real :: x(0:) print ‘(2i3)’, lbound(x), ubound(x) end subroutine test Program main implicit none integer :: I real :: s(-10:10)=(/(i,i=1,21)/) interface subroutine test(x) real :: x(:) end subroutine test end interface call test(s) call test(s(0:8)) End 1 21 を返す 1 9 を返す Nagoya Institute of Technology 例2 正方行列のトレース program main integer :: n,i real, allocatable :: a(:,:) interface function trace(x) result(tr) real, intent(in) :: x(1:,1:) real :: tr end function end interface print *,'n?' read *,n allocate(a(1:n,1:n)) do i=1,n ! print '(1x,a,i2)','line',i do j=1,n print '(1x,a,i2,a,i2,a)', & 'Enter element a(',i,' ,',j,')' read *,a(i,j) end do end do print '(1x,a,F7.4)','trace=',trace(a) end !----Trace of a Square Matrix function trace(x) result(tr) Implicit none integer :: n1,n2,i real, intent(in) :: x(1:,1:) real :: tr n1=size(x,1) n2=size(x,2) ! テキスト p.82 if(n1/=n2) then print *, 'not square';return else tr=0.0 do i=1,n1 tr=tr+x(i,i) end do end if end function Nagoya Institute of Technology 内部手続き中の配列 親プログラム中で定義されている整数変数を用いて配列の寸法を決めることができる 例 スカラー3重積 ベクトル3重積 implicit none real, dimension(1:3) :: a,b,c,bc real, external :: vector_prod, scalar_prod はいらない print *, "Input three vector's components" read *, a read *, b read *, c bc = vector_prod(b,c) print '( "Sp3 = ",F10.3)', scalar_prod(a,bc) print '( "Vp3 = (",3F10.3,")")', vector_prod(a,bc) b x c a . (b x c) a x (b x c) contains 内部手続き 復習 function vector_prod(x,y) result(z) implicit none real, dimension(1:3), intent(in) :: x,y real, dimension(1:3) :: z intent はいらない z(1)=x(2)*y(3)-x(3)*y(2) z(2)=x(3)*y(1)-x(1)*y(3) z(3)=x(1)*y(2)-x(2)*y(1) end function vector_prod function scalar_prod(x,y) result(sp) implicit none real, dimension(1:3), intent(in) :: x,y real :: sp sp=x(1)*y(1)+x(2)*y(2)+x(3)*y(3) end function scalar_prod end 1.親プログラム中で、内部手続き関数名に対する型宣言および 関数属性 宣言は不要 2.親プログラム中で使われている変数名、配列名は内部手続き中でも 有効.親プログラムと同じ値を共有し内部手続き中で宣言する必要なし 3.親プログラム中で使われている変数名と同じ名前を内部手続き中で 型宣言すると、その変数は内部手続き中でのみ有効な局所変数と みなされ、親プログラムと共通の値を持たなくなる 6.内部手続きの end 文では、後ろの手続き種別(subroutine, function) などを省略できない Nagoya Institute of Technology 再帰的呼び出し 副プログラムが自分自身を呼び出す 無限ループの罠にはまらない! 再帰的手続きの指定 recursive subroutine サブルーチン名(仮引数のリスト) recursive function 関数名(仮引数のリスト) result(変数名) 必須 recursive : 再帰的 繰り返して用いられる Nagoya Institute of Technology ルジャンドル多項式 n=0 n=1 n=2 n=3 n=4 チェビシェフ多項式 n=0 n=1 n=2 n=3 n=4 エルミート多項式 n=4 n=2 n=1 n=0 n=3 Nagoya Institute of Technology 例 ルジャンドル多項式 偏微分方程式の解などによく出てくる代表的な特殊関数 漸化式 program main implicit none integer :: n,i real :: x,y,p character(len=1) :: c(-25:25) print *,'What is the order of Polynomial, n?' read *,n print '( "Legendre Polynomial P(",i2,",x)")',n do i=-20,20 x=0.05*i ! dx=1/n=0.05 y=p(n,x) call presentation print '(f5.2,2x,f10.6,1x,51a1)',x,y,c end do contains subroutine presentation integer ::j if(i/=0) then c=' ' else c=(/('-',j=-25,25)/) end if c(-25)='I';c(0)='I';c(25)='I' c(nint(25*y))='*' end subroutine end recursive function p(n,x) result(pnx) real :: pnx integer, intent(in) ::n real,intent(in) ::x if(n==0) then pnx=1.0 else if(n==1) then pnx=x else pnx=(2.0-1.0/n)*x*p(n-1,x) & -(1.0-1.0/n)*p(n-2,x) end if end function Nagoya Institute of Technology Legendre, Chebyshev, Hermite polynomials 参考例 ! Computation of special functions integer, parameter:: fun_kind=3 ! Choose type of special function ! fun_kind=1: Legendre, =2: Chebyshev, =3: Hermite real*8, parameter:: x_max=1.d0 Integer, parameter:: n_grid=50, n_order=4, k_write=2 character(len=1):: cn(0:9)=(/'0','1','2','3','4','5','6','7','8','9'/) character(len=2):: fn(1:3)=(/'p_','t_','h_'/) real*8 :: dx,x,y,fun integer :: i,n,n_n,n_p,n_extend select case (fun_kind) case(1) ; print *,' case(2) ; print *,' case(3) ; print *,' end select Legendre Polynomial P_n(x) ' Chebyshev Polynomial T_n(x) ' Hermite Polynomial H_n(x) ' dx=x_max/n_grid n_extend=1 if(fun_kind==3) n_extend=4 n_n=-n_grid*n_extend n_p= n_grid*n_extend ! extend the x-domain for Hermite polynomial do n=0,n_order write(6,'(/," n=",i2,/)') n open(10+n,file=fn(fun_kind)//cn(n)//'.dat') do i=n_n,n_p x=i*dx y=fun(fun_kind,n,x) write(10+n,'(1pe10.3, 2x, 1pe10.3)') x, y if(mod(i,k_write)==0) write(6,'(1pe10.3, 2x, 1pe10.3)') x,y end do end do end 1/2 Nagoya Institute of Technology recursive real*8 function fun(kind,n,x) result (sf) integer, intent(in) :: kind, n real*8, intent(in) :: x if(n==0) then sf=1.d0 else if(n==1) then select case(kind) case(1); sf=x case(2); sf=x case(3); sf=2.d0*x end select else select case(kind) case(1); sf=(2.d0-1.d0/n)*x*fun(kind,n-1,x)-(1-1.d0/n)*fun(kind,n-2,x) case(2); sf=2.d0*x*fun(kind,n-1,x)-fun(kind,n-2,x) case(3); sf=2.d0*x*fun(kind,n-1,x)-2.d0*(n-1)*fun(kind,n-2,x) end select end if end 2/2 Nagoya Institute of Technology レポート課題4 サブルーチン、外部関数、再帰的呼び出しの方法を用いて次の積分をそれぞれ指定された 積分法で求めよ 自分でプログラムを作成し、これをレポートに書きだす 得られた数値計算結果をレポートに書き出す また解析計算と比較する 表紙と考察を付けること 締切 : 6月6日(月)10:30 まで 提出先 : 2号館B棟4階424B室前の レポート回収箱 (1) Simpson 公式 (2) 台形公式 レポート課題番号 学籍番号 氏名 提出日 Nagoya Institute of Technology 課題 参考例 ! Integration of special functions implicit none real:: xmin,xmax,int real, external :: func ! kind=1: Legendre, =2: Tshebysheff, =3: Hermite integer :: kind,n,scheme,nmax,i real, parameter :: pi=3.1415926535897, s=sqrt(pi/2.0e0) real, dimension(3) :: P_exact(3)=(/1.0,0.0,0.0/), H_exact(3)=(/s,2.e0*s,12.e0*s/) print * print *, ' *** Integral of Legendre Polynomials on [0,1] *** ' kind=2; scheme=2; xmin=0.e0; xmax=1.0e0; nmax=200 do i=0,2 n=2*i call integral(func,kind,n,xmin,xmax,scheme,nmax,Int) print '(/," n=",i1,1x,", I=",1pe12.5,", I_exact=",1pe12.5 )', n,Int,P_exact(i+1) end do print * print *, ' *** Integral of Hermite Polynomials times exp(-x*x/2) on [0,infinity] *** ' kind=3; scheme=1; xmin=0.e0; xmax=5.e0; nmax=200 do i=0,2 n=2*i call integral(func,kind,n,xmin,xmax,scheme,nmax,Int) print '(/," n=",i1,1x,", I=",1pe12.5,", I_exact=",1pe12.5)', n,Int, H_exact(i+1) end do end Nagoya Institute of Technology subroutine integral(fun,kind,n,a,b,scheme,kubun,integ) implicit none integer, intent(in):: kind,n,scheme,kubun integer:: i real, external :: fun real, intent(in) :: a,b real, intent(out) :: integ real :: x,dx if(scheme==1) then ! Trapezoidal rule dx=(b-a)/kubun integ=0.5*(fun(kind,n,a)+fun(kind,n,b)) do i=1,kubun-1 x=a+i*dx integ=integ+fun(kind,n,x) end do integ=integ*dx else ! Simpson rule dx=(b-a)/(2.0e0*kubun) integ=fun(kind,n,a)+4.0e0**fun(kind,n,x+dx)+fun(kind,n,b) do i=1,kubun-1 x=a+(2.0e0*i)*dx integ=integ+2.0e0*fun(kind,n,x)+4.0e0*fun(kind,n,x+dx) end do integ=integ*dx/3.0e0 endif end subroutine integral Nagoya Institute of Technology real function func(kind,n,x) integer, intent(in) :: kind, n real, intent(in) :: x real, external :: sp_fun func=sp_fun(kind,n,x) if(kind==3) func=sp_fun(kind,n,x)*exp(-0.5e0*x*x) end recursive real function sp_fun(kind,n,x) result (sf) integer, intent(in) :: kind, n real, intent(in) :: x if(n==0) then sf=1.e0 else if(n==1) then select case(kind) case(1); sf=x case(2); sf=x case(3); sf=2.e0*x end select else select case(kind) case(1); sf=(2.e0-1.e0/n)*x*sp_fun(kind,n-1,x)-(1-1.e0/n)*sp_fun(kind,n2,x) case(2); sf=2.e0*x*sp_fun(kind,n-1,x)-sp_fun(kind,n-2,x) case(3); sf=2.e0*x*sp_fun(kind,n-1,x)-2.e0*(n-1)*sp_fun(kind,n-2,x) end select end if end Nagoya Institute of Technology Nagoya Institute of Technology Nagoya Institute of Technology Nagoya Institute of Technology 例題 implicit none real:: h, phix,err real, external ::Gaussian print *, 'What is your deviation value?' read *, h real function Gaussian(s) implicit none real, parameter :: rn=2.506628e0 real, intent (in) :: s Gaussian=exp(-s*s/2.0e0)/rn end function Gaussian h=(h-50.0e0)/10.e0 call simpson(Gaussian, 0.0e0,h, 16,phix) err=(0.5e0-phix)*100.0e0 print '(1x,a,f6.2,a)', & 'From the top you are ', err, ' %.' end subroutine simpson(func,a,b,kubun,integ) implicit none integer, intent(in)::kubun integer:: i real, external :: func real, intent(in) :: a,b real, intent(out) :: integ real :: x,dx dx=(b-a)/(2.0e0*kubun) integ=func(a)+4.0e0**func(x+dx)+func(b) do i=1,kubun-1 x=a+(2.0e0*i)*dx integ=integ+2.0e0*func(x)+4.0e0*func(x+dx) end do integ=integ*dx/3.0e0 end subroutine simpson Simpsonの公式 ! \sqrt(2*pi) Nagoya Institute of Technology