アプリ版:「スタンプのみでお礼する」機能のリリースについて

 以下のように二次元配列の場合で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

A 回答 (4件)

subrountine に限らないんだけど, 基本的に主プログラムと副プログラム (サブルーチンや関数) とは同じ名前であっても違う変数となります (contains で含まれている副プログラムはそれが含むプログラムの変数が使えます). だから, メインの I, F, L などは副プログラム中では全く使っていません.


... っと, 変数が自動生成されているのか. なるほど, サンクスです>#3.
とりあえず, 全てのプログラムで
implicit none
を付けることを強くお勧めします.
    • good
    • 0
この回答へのお礼

ご指摘ありがとうございます。
このプログラムではsubrotineは使わないほうがいい気がしてきました...もう一度subroutineについて勉強してみます。あと、implicit noneも付けてみます。
また、何かあれば質問させていただくと思いますのでその時はどうぞ宜しくお願い致します。

お礼日時:2009/11/30 11:31

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で呼んでいますがこういうのは慣れてないときはあまりしないほうがいいように思います。処理のフローチャートが非常に複雑になるためです。
    • good
    • 0
この回答へのお礼

ご指摘ありがとうございます。もう一度subroutineについて参考書で勉強します。

お礼日時:2009/11/30 11:23

メインプログラムにおける 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ループで計算したものを受け渡す」ということをしたいのですが、どうしたらそうなるのでしょうか。お手数お掛けして申し訳ありませんが、指南のほどよろしくお願い致します。

補足日時:2009/11/28 20:30
    • good
    • 0

あなたのいう「この例では使えていない 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
!----------------------------------------------------------
以下省略

補足日時:2009/11/27 18:57
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!