- ベストアンサー
FORTRAN subroutineと配列と繰り返し
以下のように二次元配列の場合でsubroutineを使うときに、主プログラムで2重Doループ(iとj)で繰り返しをしているのですが、すでにsubroutineでDoループ(i)を用いて計算しています。これではsubroutineの利点をうまく使えていないと思うのですが、subroutineを使って配列、Doループをきれいにする方法をどなたか教えていただけませんか。 実際は4重ループ、4次元配列なので、プログラムをわかりやすくするためにサブルーチンを使いたいと思っています。 -------------------------------------------------------------- program S real,dimension(5,5) :: B real,dimension(5) :: A integer :: i,j do j=1,5 CALL sub1(A) do i=1,3 B(i,j)=A(i)*j write(*,*) B(i,j) end do end do end program S subroutine sub1(A) real,dimension(5) :: A integer :: i do i=1,3 A(i)=3.*i end do end subroutine sub1
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
subrountine に限らないんだけど, 基本的に主プログラムと副プログラム (サブルーチンや関数) とは同じ名前であっても違う変数となります (contains で含まれている副プログラムはそれが含むプログラムの変数が使えます). だから, メインの I, F, L などは副プログラム中では全く使っていません. ... っと, 変数が自動生成されているのか. なるほど, サンクスです>#3. とりあえず, 全てのプログラムで implicit none を付けることを強くお勧めします.
その他の回答 (3)
- ue-30
- ベストアンサー率0% (0/1)
subroutineを使う場合には引数に注意しないと予想と全く結果が異なることになります。フォートランの参考書はあれば、subroutineの引数についての部分を一度読まれるのがいいでしょう。 call test(a1,a2,a3) subroutine test(b1,b2,b3) 上の場合には 1、a1,a2,a3をsubroutine testに渡す 2、subroutineはb1=a1,b2=a2,b3=a3として計算 3、subrouine内で計算後のb1,b2,b3をa1,a2,a3として返す。 という流れにになります。注意してほしいのはa1,a2,a3以外の変数はsubrutine内で定義しないといけません(0またはとんでもない数字になります)。つまりsubroutineに渡した変数しかmainには返ってきません。なのでsubroutine内で使いたい変数はすべて渡さないとおかしな結果が返ってきます。結果がおかしい原因はここにあると思います。 これはアドバイスですが、sub1をmainや他のsubroutineで呼んでいますがこういうのは慣れてないときはあまりしないほうがいいように思います。処理のフローチャートが非常に複雑になるためです。
お礼
ご指摘ありがとうございます。もう一度subroutineについて参考書で勉強します。
- Tacosan
- ベストアンサー率23% (3656/15482)
メインプログラムにおける 3重ループの意味が見えないんだけど.... write 以外はループの中にいる意味ないのでは? あと, sub4 で使ってる DIS2 とか DEPTH とかってどこから出てきたんだろう. そもそもメインから呼び出している sub1, sub4, sub5 などに対する引数が全部違ってるから, 「それぞれ別個に実行しているだけ」ですよね. 「あるsubroutineでDoループで計算したものを受け渡す」ということは全くしていないように見えます.
補足
おっしゃる通りです。まさに「それぞれ別個に実行しているだけ」になっています... >メインプログラムにおける 3重ループの意味が見えないんだけど.... write 以外はループの中にいる意味ないのでは? CALLするときは3重ループの中に書く、書かないで処理の速度は変わってくるのでしょうか。ループの中でCALLしないと変数の(I,F,L)が定まらないと思い、中に書いていました。 >sub4 で使ってる DIS2 とか DEPTH とかってどこから出てきたんだろう sub4では DIS2、 DEPTHは使わないのですが、どうせほかのルーチンで使うからと思って、sub1に入れてしまいました。 私はsubroutineの使い方を完全に間違っているみたいですね... 「あるsubroutineでDoループで計算したものを受け渡す」ということをしたいのですが、どうしたらそうなるのでしょうか。お手数お掛けして申し訳ありませんが、指南のほどよろしくお願い致します。
- Tacosan
- ベストアンサー率23% (3656/15482)
あなたのいう「この例では使えていない subrountine の利点」とは何なのでしょうか? この例だと「j が変わるごとにサブルーチンを呼び出す意味はない」し「サブルーチンの中で do を使う必然性はない」とも言えるので確かに「サブルーチンの利点を使えていない」とはいえそうですが....
補足
実際は以下のようなプログラムを書いています。 各subroutine内で3重ループ、2重ループを頻繁に用いているのですが、受け渡しがうまくいってないようで、実行しても結果がでるのに半日かかったりします。そして答えも変です。subroutineの利点はただプログラムを見やすくするためであって、あるsubroutineでDoループで計算したものを受け渡すときにはその受け渡されるsubroutineでもまたDoループで計算しなければいけないものなのでしょうか? program sub_1030_2 real :: SL3=10. integer :: YR=1 integer :: F,I real :: L real,dimension(100) :: DIS2,FE,DEPTH real,dimension(5,100) :: MTD real,dimension(10,5,100) :: DR OPEN(11, FILE='C:\Users\\Documents\究\FORTRAN\fortranopenfile\fortranresult.txt') do I=1,YR do F=1,2 do L=1.,SL3 CALL sub1(KE,DIS2,FE,DEPTH) CALL sub4(MTD) CALL sub5(DR) CALL sub11(topPD) write(11,'(5F15.5)') DIS2(L),FE(L),DEPTH(L),MTD(F,L),DR(I,F,L) end do end do end do CLOSE(11) end program sub_1030_2 !----------------------------------------------------- subroutine sub1(KE,DIS2,FE,DEPTH) real :: KE real :: RAIN real,dimension(100) :: DIS2 real :: L real :: SL1=100. real :: DIS1=6. real,dimension(100) :: FE,DEPTH RAIN=129. KE=(12.+9.*LOG10(RAIN))*RAIN/3600. do L=1.,SL1 DIS2(L)=DIS1*L FE(L)=(((1./1000.)*10.*DIS2(L)*0.1)/1.) DEPTH(L)=0.0001*DIS2(L)+0.3 end do end subroutine sub1 !----------------------------------------------------- SUBROUTINE sub4(MTD) real,dimension(5,100) :: MTD real,dimension(100) :: FE real :: L integer :: F real :: SL1=100. real,dimension(5) :: P P(1)=1. P(2)=2. do F=1,2 do L=1.,SL1 call sub1(KE,DIS2,FE,DEPTH) MTD(F,L)=16.*EXP(-0.8*P(F))*FE(L) end do end do end SUBROUTINE sub4 !------------------------------------------------------------ SUBROUTINE sub7(PD) !0年めの粒度分布 real,dimension(10,5,100)::pLEFTw,PD integer :: F,I real :: L real :: SL1=100. ! integer :: YR=1 do I=0,0 !I=0年(侵食される前の初期値) do L=1.,SL1 do F=1,2 pLEFTw(0,1,L)=200. pLEFTw(0,2,L)=200. PD(0,F,L)=pLEFTw(0,F,L)/(pLEFTw(0,1,L)+pLEFTw(0,2,L)) end do end do end do end subroutine sub7 !------------------------------------------------------------- SUBROUTINE sub5(DR) real,dimension(100) :: DEPTH real,dimension(10,5,100) :: DR integer :: F,I real :: L,KE,DU real :: SL1=100. real,dimension(5) :: P integer :: YR=1 real,dimension(10,5,100)::PD P(1)=1. P(2)=2. DU=600. do I=1,YR do F=1,2 do L=1.,SL1 CALL sub1(KE,DIS2,FE,DEPTH) CALL sub7(PD) DR(I,F,L)=((((-1.*LOG(P(F))+2.)/1.6)*KE*DU*EXP(-2.*DEPTH(L)))*0.1)*1.6/1000.*PD(I-1,F,L) end do end do end do end subroutine sub5 !---------------------------------------------------------- 以下省略
お礼
ご指摘ありがとうございます。 このプログラムではsubrotineは使わないほうがいい気がしてきました...もう一度subroutineについて勉強してみます。あと、implicit noneも付けてみます。 また、何かあれば質問させていただくと思いますのでその時はどうぞ宜しくお願い致します。