FortranWord文档格式.docx
《FortranWord文档格式.docx》由会员分享,可在线阅读,更多相关《FortranWord文档格式.docx(31页珍藏版)》请在冰豆网上搜索。
●课程验收要求
a.判定算法设计的合理性,运行相关程序,获得正确的数值结果。
b.回答有关问题。
c.提交报告。
d.依内容的创新程度,完善程序情况及对程序讲解情况打分。
理学院课程设计评分表
课程名称:
专业软件与模块化程序设计
项目
评价
设计方案的合理性与创造性
设计与调试结果
设计说明书的质量
答辩陈述与回答问题情况
课程设计周表现情况
综合成绩
教师签名:
日期:
目录
任务一……………………………………………………………
任务二……………………………………………………………
任务三……………………………………………………………
任务四……………………………………………………………
任务五……………………………………………………………
任务六……………………………………………………………
任务七……………………………………………………………
任务八……………………………………………………………
流程图……………………………………………………………
实习体会……………………………………………………………
算法附件……………………………………………………………
一、调用子程序,实现算法
1.问题描述:
1.函数子程序的结构及调用
函数子程序是用户根据需要编写的一个程序段,是独立的FORTRAN的程序单位,函数子程序的第一个语句必须是function.最后一个语句必须是end语句.函数子程序的一般结构为:
[类型说明]function函数子程序名(虚参1,虚参……..)
函数名=表达式
return
end
例如:
求N!
的函数子程序可以写成如下:
realfunctionfac(N)
fac=1,0
do10i=1,N
fac=fac*1
10continue
2.子程序调用是以subroutine开头,以end结尾的程序单元。
其定义的一般格式为:
subroutineF(X1,X2,……Xn)
子程序体
其中:
F为子例程序名,它的命名规则与变量名相同,但它不具有值,也无类型;
X1,X2,X3…….Xn为虚参表,可以是变量名,数组名或过程名,若无参表,则括号可有可无。
Return以上就是子程序的说明,本课题中的任务1就是在模块中完成对子程序的调用,即子程序sub1(nx,ny),以下是对函数子程序的调用应注意的问题.
(1)序是独立的程序块,它可以被主程序或其他子程序调用,但不能被自己调用.程序总是从主程序开始执行,所以没有主程序,函数子程序就无法执行.正如聂老师上课所讲的那样.
(2)return语句是只允许出现在子程序中,在子程序中return语句与end语句区别是return语句可以多次出现,也可以省略.它不一定是子程序的最后一个语句.当执行到某一个)return时,立即返回调用单位.而end语句只能是有一条,它是必不可少的.而且必须放在程序最后,当执行该语句时也即返回调用单位.
(3)函数体中的执行语句用来完成函数的运算.所以在返回调用单位之前,必须把所求得的函数值赋给函数名.
(4)在函数子程序中,虚参可以是变量名,数组名和子程序名.当函数具有多个虚参时,它们之间用逗号隔开,没有虚参时,一对括号也必不可少.
(5)函数子程序是一个独立的编译单位,所以函数体内的变量语句标号等的作用范围只局限于子程序块内,除了函数名和虚参以外与其它序单位没有任何联系.
以上便是一个函数子程序的有关内容.如果实现对它的调用,直接在主模块中用call函数名(参数1,参数2…….)来实现.所以任务一就是在write(*,*)'
任务1:
调用子程序1,实现算法1(自己设计)后面加callsub1(nx,ny).此时函数值将会被调出.详见附表程序.
2.算法设计:
subroutinesub1(nx,ny)
implicitreal*8(a-h,o-z)
implicitinteger*4(i-n)
integerA(10),p
dataA/1,2,3,4,5,6,7,8,9,0/
write(*,*)(A(i),I=1,10)
write(*,*)'
输入P的值:
'
read(*,*)P
do10,I=P,9
A(I)=A(I+1)
10continue
write(*,*)(A(I),I=1,9)
return
3.设计思想:
此程序是写出一个数列,然后做运算,即输入任意一个数p,将对应数列中的数值的下一位赋值与此对应的位置p.即通过A(I)=A(I+1)来实现,此语句也是一循环句,通过do10,I=P,9来运行,随后将运行结果写出。
其主要是实现对它的调用,其语句分析已经在上面说明了。
二、调用子程序2(独立生成1个文件,并加入(insert)workspace),实现算法
其实任务2与任务1相差不多,只是在所调用的子程序中加入以下语句:
open(1,file='
wang.dat'
status='
unknown'
).意思是打开一个dat文件,然后将运行结果写入该文件中,即write(1,*)函数名.最后再加上close
(1).此时任务2的子程序已经完成.只要在write(*,*)'
任务2:
调用子程序2(独立生成1个文件,并加入(insert)workspace),实现算法2调用callsub2(nx,ny),任务2变完成了.
2.算法设计
subroutinesub2()
implicitreal*8(a-h,o-z)
implicitinteger*4(i-n)
write(*,*)'
输入3个不同的数,并进行排序(从大到小)输入要比较的三个数'
)read(*,*)i,j,k
if(j.GT.i)then
m=i
i=j
j=m
else
endif
if(k.gt.i)then
i=k
k=m
endif
if(k.le.j)then
else
m=j
j=k
write(1,*)i,j,k
write(*,*)i,j,k
close
(1)
endsubroutinesub2
3.设计思想
此程序是运用if循环语句实现比较三个数的大小,先将其中的两个数比较大小,将大的数始终放在最前面,依次类推完成其他数字之间的比较。
然后用write(1,*)i,j,k来实现对运算结果写入对应的dat文件,即程序中的wang.dat文件.当运算结束后,里面就会出现三个数且按从大到小排列.而要完成此过程还需要open语句来实现。
即:
)。
三、设计子程序,实现module-模块化程序设计,在子程序3(sub3)中用module,并调用其中的2个子程序
这个任务其实也是子程序的调用,只不过是使用了moudle.与上面几个任务的区别就是,要使用moudle就必须在主程序开始时用use函数名来实现.然后用call函数名将moudle中的子程序的内容调到相应位置.子程序的算法结构以及各种注意问题与任务1中的都一样.即对应于本任务中的subsub1subsub2.
modulebase
!
implicitnone
contains
subroutinesubsub1(nx,ny)
integer*4nx,ny,sum,i
第1题:
计算1+2+....+100的值'
sum=0
doi=1,100
sum=sum+i
enddo
sum='
sum
endsubroutinesubsub1
subroutinesubsub2()
integer*4nx,ny,factor,i
integer*4nx,ny,m
判断一个数能否被3整除,输入数值'
read(*,*)m
m='
m
if(mod(m,3).eq.0)then
能被3整除'
不能被3整除'
endsubroutinesubsub2
调用模块
subroutinesub3()
usebase
callsubsub1(nx,ny)
callsubsub2()
算法subsub
(1)是运用do循环实现1加到100的运算,算法其实很简单在语句sum=sum+i中就可以实现类加。
而subsub
(2)是运用if循环语句实现判断一个数是否被3整除,只要满足mod(m,3).eq.0即表明次数字是三的整数倍,然后输出结果是“能被3整除”。
反之亦然。
然后加入调用子程序模块中,本任务中还运用sub(3)实现对两个子程序的再一次调用。
与上面几个任务相差不多。
四、动态数组开设,并使用该动态数组,输出数组中的值,最后释放该数组的空间
(1)ALLOCATE语句
ALLOCATE语句动态创建可分配数组,使内存和对象相联系。
分配的对象可以被命名为任何有ALLOCATABLE属性的变量。
它的一般形式为:
ALLOCATE(数组名[维界符][,数组名[(维界符[,维界符...])]]...[,STAT=状态值])。
例:
REALA(:
),B(:
:
)
ALLOCATABLEA,B
ALLOCATE(A(-2:
40),B(3,3,3))
当数组被分配时,内存分配给指定大小的数组。
ALLOCATE语句中的秩必须和可分配数组的秩相同。
在分配的同时,ALLOCATE语句中的上下界决定了数组的大小和形状。
边界的值可以是正数、负数或零,缺省的下界为1。
如果维上界比下界小,则该维的长度为零,并且数组的大小为零。
大小为零的数组不能被赋值。
当前被分配的数组不能被再分配,否则会引起运行错误。
错误状态可以由ALLOCATE语句中的STAT值获得。
如果指定STAT选项,语句的成功执行时将返回0,否则返回正值。
若未指定STAT选项且出现错误时,程序将中止执行。
INTEGER,ALLOCATABLE:
:
A(:
INTEGERERR_MESSAGE
ALLOCATE(A(10:
25),B(SIZE(A)),STAT=ERR_MESSAGE)
IF(ERR_MESSAGE.NE.0)PRINT*,'
ALLOCATIONERROR'
可以用内在函数ALLOCATED来判断一个数组是否已被分配。
它的形式为:
ALLOCATED(数组名)。
返回值是逻辑标量,已被分配时为真,现在还未被分配时为假,当数组的分配状态未定义时它也是未定义的。
REAL,ALLOCATABLE:
...
IF(.NOT.ALLOCATED(A))ALLOCATE(A(5))
(2)DEALLOCATE语句
DEALLOCATE语句用来释放已分配数组的内存。
DEALLOCATE(数组名[,数组名]...[,STAT=状态值])。
25),B(SIZE(A)))
DEALLOCATE(A,B,STAT=ERR_MESSAGE)
DEALLOCATIONERROR'
INTEGER,DIMENSION(:
),ALLOCATABLE:
freq
READ*,limit
ALLOCATE(freq(1:
limit))
DEALLOCATE(freq)
只有被ALLOCATE语句分配的内存空间才可以被DEALLOCATE语句释放,否则产生运行错误。
可以使用ALLOCATED语句判断数组是否被分配,错误状态可以由ALLOCATE语句中的STAT值获得。
当过程的执行被RETURN或END语句中止时,除非可分配数组是有SAVE属性的,否则它的分配状态变成未定义的。
但是,RETURN和END语句并不释放数组分配的内存,所以应该在退出子程序前主动释放数组分配的内存。
可分配数组的联合状态可以是已分配的(该数组被ALLOCATE语句分配,可以被引用、定义或释放)或是目前未联合(该数组从未分配或上一个操作是释放,数组不能被引用或定义)。
当可分配数组赋值时就被定义。
ALLOCATE(A(100))!
A被分配但未定义,A的分配状态是己分配
A(1:
100)=1!
A被定义
DEALLOCATE(A)!
A被释放,A的分配状态是未分配
subroutinesub4(nx,ny)
integer*4,dimension(:
),allocatable:
nd
integer*4:
i
allocate(nd(100))
nd(i)=i
write(*,*)nd
deallocate(nd)
此算法就是实现了开设一个动态数组,即allocate(nd(100)).开设数组后即要对数组释放,deallocate(nd)即实现了对此数组的释放.此时,任务便完成.要严格按照上面所述的要求。
五、从当前文件夹中的input2中,动态读取其中数据,并将读出的数据保存在2个数值中
此任务其实就是前面几个任务的进一步深化,在某种算法的基础上要在指定的文件夹中读取数据,也就是任务中input2的有关数据,将读出的数据做一定的运算。
在此任务中还用到了调用子函数的语句,将任务一中的有关内容也结合起来了。
在此一定要注意区分与任务2中将结果写入dat文件中区别,但语句相差不多。
关键任务2中是将结果写入,而此处刚好相反。
subroutinesub5(nx,ny)
计算input2/hunan.dat文件中数值的平方'
open(2,file='
./input2/hunan.dat'
read(2,*)a
b=a**2
write(*,*)b
close
(2)
eturn
我在这里做的算法很简单,就是运算一个数的平方。
在程序语句开始定义了有关类型后,打开指定文件夹input2,我在此文件夹中建立了一个文件名为hunan的dat文件,并在里面写入了一个数字保存。
然后用open语句打开指定的文件夹,动态读取dat文件中的内容,赋值给a,此时将a做平方运算后将结果赋值与b,最后write语句写出运算结果。
六、使用if---then-----else----endif语句实现某一算法
If结构的一般格式:
Ifthen
程序块1
程序块2
Endif
执行过程如下:
(1)首先执行块if语句,对逻辑表达式求值,如果为真,则将流程转向执行程序块1的各个语句执行,执行完以后跳过else语句和程序块2,直接转到endif语句.
(2)如果块if语句的逻辑表达式值为假,则跳过程序块1转到else语句,else语句不执行任何操作,然后执行程序块2的各个语句,再转到endif语句.
任务6,使用if---then-----else----endif语句实现某一算法
判断一个人考试是否通过,60分以上即可通过'
输入考试成绩'
read(*,*)grade
if(grade.ge.60.0)then
通过考试'
未通过考试'
pause
如上面的if语句,当输入的数值大于60时就执行书处语句”通过考试”否则执行输出”未通过考试”此时运算结束.任务也就结束了.其中,pause是表示暂停的意思.在设计类似的算法时,关键就是弄清楚if条件语句的判断与执行语句,只要逻辑上设计正确,则便可以实现所期望的算法。
七、使用do---enddo语句实现某一算法
一个do循环语句称为一个do循环,由三个部分组成:
do语句,循环体和enddo语句。
Do语句是do循环体执行的有关参数,决定是否执行循环体。
Enddo是终端语句,表明do循环语结束。
计算1-10的阶乘'
factor=1
doi=1,10
factor=factor*i
write(*,*)i,factor
此算法是利用do——enddo语句计算1到10的阶乘,先将factor赋初始值1,然后做连乘运算,即factor=factor*i,其中i的值就是doi=1,10,然后将结果写出来,用write语句就可以实现。
八、生成网格,并用Fa画图
此算法是实现生成网格,然后再用fa画图,其中dx=20.0/nx_Li;
dy=10.0/ny_Li表示生成网格的行数和列数。
nod_Li(ne_1,1)=nl_1-1,nod_Li(ne_1,2)=nl_1nod_Li(ne_1,3)=nl_1+(nx_Li+1),nod_Li(ne_1,4)=nl_1+(nx_Li+1)-1表示网格中各格的颜色,调整算法中的数字就可以实现对颜色和格数的改变。
(算法中用到了do循环语句以及前面提到的读取文件中的数值等算法)
subroutinegetmesh(nx_Li,ny_Li,nnm_li,nem_li)
real*8:
x_Li(nnm_Li),y_Li(nnm_Li)
integer:
nod_Li(nem_Li,4),mater_Li(nem_Li)
real*8:
yn(nnm_Li)
dx=20.0/nx_Li;
dy=10.0/ny_Li
doj=1,ny_Li+1
doi=1,nx_Li+1
nn=(j-1)*(nx_Li+1)+i
x_Li(nn)=(i-1)*dx
y_Li(nn)=(j-1)*dy
write(*,*)'
选择Aok1'
doj=1,ny_Li
doi=1,nx_Li
dok=1.,10
ne_1=(j-1)*nx_Li+i
nl_1=(j-1)*(nx_Li+1)+i+1
nod_Li(ne_1,1)=nl_1-1
nod_Li(ne_1,2)=nl_1
nod_Li(ne_1,3)=nl_1+(nx_Li+1)
nod_Li(ne_1,4)=nl_1+(nx_Li+1)-1
if(i.le.nx_Li/4)then
mater_Li(ne_1)=1
elseif((i.le.nx_Li/2).and.(i.gt.nx_Li/4))then
mater_Li(ne_1)=2
mater_Li(ne_1)=3
endif
enddo
callpostproc_quad(x_Li,y_Li,nnm_Li,nem_Li,nod_Li,mater_Li,yn)
ok'
./output/col1.dat'
doi=1,nnm_Li
write(1,1)x_Li(i)
close
(1)
1format(1x,e23.15e4)
yns=gf(x_Li(i),y_Li(i))
yn(i)=yns
functiongf(x,y)
gf=x+y+1.0
integer:
nnm,nem,i
real*8x(nnm),y(nnm),yn(nnm)
integer*4nod_s(nem,4),mater(nem)
Inpostproc-quadrilateralgrids...'
Para_quadrilateral.prj'
form='
formatted'
open(2,file='
Para_quadrilateral.cor'
open(3,file='
Para_quadrilateral.elm'
unknow