Fortran学习的一些建议
2006-8-6
相信大家都对C语言有一定的了解,其实Fortran跟C相差不是很多。
我把自己认为比较合理快速学习Fortran的方法说下。
学习Fortran,会遇到Fortran77&Fortran90等等,两者差别不大,建议学习Fortran90或更
高,更加自由些(仅对一般用而言,其他优势可能体现不出来),对自己以后学习他
的程序包也会有好处。
大家一般只是为了编程为了计算而学Fortran,而不是为了学习Fortran而学Fortran,所以
我的建议是学习Fortran不要像学C那样拿一本很详细的教材从头至尾学下来,一个大家都
有不错的C语言基础,而且也没有太多的精力去专门研究这些,倒不如看些简易的教材(我
会附上),掌握基本语句之后直接从看最简单的程序开始。这样,很快就会体会到Fortra
n的格式,可以开始自己写程序了。学习的顺序我建议如下:
1、 编一些仅含输入输出的程序,然后可以尝试把输入输出同文件结合起来(从文件里读
数据、写数据);
2、 然后可以学条件判断、循环语句,通过几个实例也可以很快掌握;
3、 再往后就是写子程序,就是程序的调用,相信那个时候,看了我的第一个例子(PROG
RAM A)就应该能写出简单的含函数调用的程序,到了这里,基本上可以算告一段落,可以
进行结构上复杂的程序的编写;
4、 最后,可以学一下多个程序的编译甚至是多种语言程序的混编(如既有C又有Fortran
的多个程序一起编译)。多个程序的编译我不并不熟悉,就留给siriusbobo同志来解说吧
:-)
在编程中遇到困难然后再去查找资料和用法不失为一种好的方法,不必刻意去求学全。
当然,有足够时间和精力的同学强烈建议好好看教材,不必急于求成,有一个好的基础总
是一件很好的事。
Fortran相比C的优势的话在于它丰富的资源,C的优势可能是更加简洁,编译效率更高。但
对于我的平时使用来说,这两者的优势、劣势都体现不出来,自己的感觉是Fortran更接近
平时的科学语言,比较严谨些,更容易读懂不出错,比较符合习惯,变量、函数的声明上
也比C更方便灵活,以外函数的使用为例:
******************************************************************************
PROGRAM A
real z
read *,z
call f(z)
y=z
print *,y
end
subroutine f(x)
x=x**2
return
end
******************************************************************************
只需要加一个"subroutine"程序段,主函数即可用"call"调用,当然也可以写多个子程序
,其中一个子程序也可以通过"call"来调用其他子程序。
就一般学习而言,除了子程序的编写,另外一个用得比较多的是文件的读写操作,读用
"read",写用"write",如下:
******************************************************************************
PROGRAM B
real x
open (1,file='in.dat',status='unknown')
open (2,file='out.dat',status='unknown')
read (1,100) x
100 format (1e12.7)
close(1)
write (2,200) x
200 format (1e15.8)
close(2)
end
******************************************************************************
如果用"*"的话,就为默认形式,更具体的可以查看帮助或有关资料,比较好的方法是随时
做一个test程序,用来检测所学或所想。
对于上程序,出现的"100","200"是语句标号,这些标号为方便语句的跳转而出现,可以实
现循环、条件控制等,但也为了使程序结构化而不推荐使用,用goto语句和语句标号实现
语句的跳转如下:
******************************************************************************
PROGRAM C
integer n
real z
n=0
read *,z
1 call f(z)
y=z
n=n+1
if (n<10) goto 1
print *,y
end
subroutine f(x)
x=x**2
return
end
******************************************************************************
这类跳转在F77里经常用到,F90以后并不多见,但对于"100 format (1e12.7)"之类还是经
常用到,这是用来表示存储读取的数据的格式的,可以放在程序任何位置,更具体的用法
要参看说明。
有关注释:
Fortran里注释用"!"或"C",其中,一般在Windows下使用"Compad Visual Fortran"编译,
有两种格式,一个是"Free Format",生成".f90",另外一个"Fixed Format",生成".for
",只有".for"里两种注释都可用("!"或"C"),但在".f90"里只能用"!"。
有关学习的困难:
算法是语言的灵魂没错,是最麻烦的,但想必大家都学过C,遇到过不少算法,这些可以用
C实现的,用Fortran实现都不是很困难,所以这里不主要讨论这个“灵魂”性质的东西。
常量、变量、数组的数据类型,以及数据类型的读写控制倒是经常容易出错的。下面主要
讲一些我认为需要注意的和我曾经犯过和看到过的错误。
Fortran跟C一样,也分整型(INTEGER),实型(REAL),双精度(REAL*8或REAL(8)或DOUBLE
PRECISION),这些在科学计算中还是比较重要的,以实型数为例:
一般REAL等价于REAL*4或REAL(4),是单精度的;
而双精度在F77中表示为DOUBLE PRECISION,在F90中可以表示为REAL*8或REAL(8),在高精
度计算中,双精度的变量是很有必要的,对于一般实数可以表示为小数形式或指数形式,
而双精度都表示成指数形式,但指数E要改成D,如:
REAL:100.0或1e2,双精度下就得表示成1D2
由于Fortran中不需要对每个变量都进行声明,所以有时候会在每个程序或子程序开头做个
说明,如下:
IMPLICIT DOUBLE PRECISION(A-H,O-Z)
代表以A-H以及O-Z字母开头的变量默认(在不声明的情况下)是双精度的,否则则是整型
的,如下:
******************************************************************************
PROGRAM D
IMPLICIT DOUBLE PRECISION(A-H,O-Z)
J1=1D-2
J2=-0.5D-1
x=J1+J2
print *,x
end
******************************************************************************
PROGRAM E
implicit double precision (A-I,O-Z)
double precision a,i,e1,e2
data j2 /0.87450547081842D-3/
data j3 /-0.11886910646016D-4/
data j5 /-0.17242068505339D-5/
data j7 /0.10566966079622D-6/
write(*,*) "please input a"
read(*,*) a
write(*,*) "please input i"
read(*,*) i
e1=(j3*sin(i)/(2*a*j2)-5*j5*sin(i)*(1-7*sin(i)**2/2+21*sin(i)**4/8)&
&/(2*a**3*(2-5*sin(i)**2/2))+35*j7*sin(i)*(1-27*sin(i)**2/4+99&
&*sin(i)**4/8-429*sin(i)**6/64)/(3*a**5*(2-5*sin(i)**2/2)))
e2=-(j3*sin(i)/(2*a*j2)-5*j5*sin(i)*(1-7*sin(i)**2/2+21*sin(i)**4/8)&
&/(2*a**3*(2-5*sin(i)**2/2))+35*j7*sin(i)*(1-27*sin(i)**2/4+99&
&*sin(i)**4/8-429*sin(i)**6/64)/(3*a**5*(2-5*sin(i)**2/2)))
write(*,"(E9.2E3)") e1,e2
stop
end
******************************************************************************
第一个程序输出不是-0.4而是0.000000000000000E+000
第二个程序任意输入a、i,并未得到希望得到的结果,而是输出NAN和NAN,关于NAN这个错
误,有时候函数定义域不符合的时候,运行并不报错而是输出NAN,这个时候检查程序这些
地方是检查的重点,当然,会有其他情况,但我碰到的不多,只好就我所知跟大家交流一
下。
这两个程序都因为J开头的变量不属于默认双精度变量,而用双精度表示给它们赋值了,导
致结果跟预期不一致,在程序中把这些以J开头的变量用REAL*8声明一下,或把
implicit double precision (A-I,O-Z)改为:
implicit double precision (A-J,O-Z),或把这个语句去掉
就可以得到预期的结果了。
对于数组,可以用DIMENSION定义,但需要注意的是,若在程序头未做声明(implicit
none)时,用DIMENSION定义数组时,当数组名首字母不属于(A-J,O-Z)里时,其值输出时
为整型,当然做了如下声明情况也会如此:(implicit double precision (A-I,O-Z))
如下:
******************************************************************************
PROGRAM F
dimension m(2)
m(1)=1.5
m(2)=2.5
print *,m(1),m(2)
end
******************************************************************************
输出的结果是“1,2”而不是“1.500000,2.500000”
当把程序中m改为a时,输出“1.500000,2.500000”
所以,比较好的方法是尝试用REAL来定义数组(当然也可以用REAL*8):
******************************************************************************
PROGRAM G
real m(2)
m(1)=1.5
m(2)=2.5
print *,m(1),m(2)
end
******************************************************************************
另外,要说的是,变量可以不定义而直接赋值,但会出现如上面PROGRAM D-E的问题,所以
建议大家在编程的时候对非整型变量声明一下,尽管麻烦,但不容易出错,有时候正是这
类错误会让初学者困扰好久。
定义变量时,经常会看到两种定义的写法:以REAL为例:
可以有
real m
和 real:: m
第一种方式不可以直接赋值,必须写成这样:
******************************************************************************
PROGRAM H
real m
m=1.0
print *,m
end
******************************************************************************
第二种则可以:
******************************************************************************
PROGRAM I
real:: m=1.0
print *,m
end
******************************************************************************