Fortran77-90-95入门
来源于:https://www.doczj.com/doc/2d6312403.html,/yourtommy/article/details/7036301
Fortran语言的历史
Fortran是英文FORmula TRANslation的缩写, 意为"公式翻译". 为科学, 工程问题中那些能够用数学公式表达的问题而设计的语言, 主要用于数值计算. Fortran至今已经有四十多年历史. 第一代Fortran是1954年提出来的, 称为FortranI. 它于1956年在IBM 704计算机上实现的. 是由IBM的John Backus提出并开发的一种容易理解, 简单易学而又像汇编一样高效运行的语言. 1958年出现的FortranII对FortranI进行了很多扩充(如引进了子程序). FortranII在很多机器上实现了. 其后出现的FortranIII因为存在严重的缺陷, 所以没有在任何计算机上实现. 1962年出现的FortranIV并不与FortranII完全兼容.
由于Fortran满足现实需要,所以传播很快, 从而出现了很多的Fortran的版本. 各种版本间语法和语义并不完全一致,所以给用户造成极大不变. 为此, 1962年5月, 当时的美国标准化协会ASA(American Standard Association, 后面改名为ANSI -- American National Standard Institute, 现名为NIST -- National Institute of Standard and Technology)成立工作组开始统一各个版本, 并于1966年正式公布了两个美国标准文本: 标准基本FortranX3.10-1966(相当于FortranII) 和标准FortranX3.9-1966(相当于FortranIV).
由于Fortran在国际上的广泛使用, 1972年国际化标准组织ISO(International Standard Organization)公布了ISO Fortran标准, 即<程序设计语言FortranISO 1953-1972>. 它分为三级: 一级相当于FortranIV,二级介于FortranII和FortranIV之间,三级相当于FortranII.
FortranIV(即Fortran66)流行了十几年,几乎统治了所有的数值计算领域。但它不是结构化语言,没有实现三种基本结构的语句,程序中需要使用GOTO语句来实现特定的算法,美国标准化协会在1976年对FortranX3.9-1966进行修订,把各个版本有效的功能都加入了进来,并加入了新的功能。并在1978年正式公布为美国国家标准ANSI X3.9-1978 Fortran,称作Fortran77。1980年Fortran77被接受成为国际化标准。Fortran77扩充了一些结构化的语句,但不是完全的结构化语言。由于扩充了字符处理功能,Fortran77不仅适用于数值领域,还适用于非数值领域。
之后经过十多年的标准化过程,1991年通过了Fortran90的新标准ANSI X3.198-1991,相应的国际化标准为
ISO/IECI1539:1991。Fortran90保证了Fortran77的兼容性,Fortran77是Fortran90的严格子集。
现在有各种程序设计语言,而且在一些特殊领域使用其它语言会更为合适,但在数值计算、科学和工程领域,Fortran仍然具有强大的优势。随着巨型计算机(向量机和并行机)的异军突起,出现了新的高性能Fortran语言(HPF)。它是Fortran90的一个扩展子集,主要用于分布式内存计算机上的编程,以减轻用户编写消息传递程序的负担。HPF-1.0的语言定义在1992年的超级计算国际会议作出的,正式文本在1993年公布的。1997年发布了HPF-2.0语言定义。Fortran95包含了许多HPF的新功能。在Fortran90出现之前,在并行机上运行程序需要结合专门的矢量化子程序,或者信赖Fortran编译系统进行自动矢量化。而Fortran90之后,程序员可在程序中有目的地控制并行化。Fortran90具有C++的所有重要功能,然而C语言主要用于微机上的廉价开发,而Fortran的目的是产生高效最优化运行的可执行程序。用Fortran编写的大型科学软件较C语言编写的通常要快一个量级。当今不仅大型机,微机和工作站也有了多处理器。高性能并行计算已成必然,串行机上的线性内存模式已不再适用。Fortran作为具有处理相应问题的标准并行化语言,其独特的数组操作充分体现了它的先进性。
第一个Fortran程序
Fortran的程序用.f后缀表示(表示固定格式),下面是一个求算术平均数与几何平均数的代码:
[plain]view plaincopyprint?
1. C-----Fortran固定格式用C开头(必须在行首)表示注释------
2. C每行必须用tab缩进,否则编译错误(严格来说是6个空格)
3. C程序大小写不分
4. C用PROGRAM表示程序开头
5. PROGRAM first_program
6. C定义四个实数
7. real a, b, av1, va2
8. C从标准输入中得到a和b的值
9. READ (*,*) a, b
10. C--av1为a和b的算术平均数
11. av1 = (a+b)/2
12. C--av2为a和b的几何平均数
13. av2 = sqrt(a*b)
14. C在标准输出中显示结果
15. WRITE(*,*) av1, av2
16. C用END表示程序结尾
17. END
1. !-----Fortran自由格式中只能用!开头表示注释,C不能用于注释------
2. PROGRAM first_program !行前不必用tab缩进,但缩进仍然合法
3. REAL a, b, av1, va2
4. rEAd (*,*) a, b !大小写不分
5. av1 = (a+b)/2
6. av2 = sqrt(a*b)
7. WRITE(*,*) av1, av2
8. END
卡片上明示了0~9行,在0行上面为第11行,再上面为第12行。卡片的编码方式与机器以及应用有关。此处11行和12行都不打孔时,0~9行中的一个孔表示一个数字;第11,12,0行中打一个孔以及1~9行中打一个孔表示一个大写字母;第11,12,0行中打一个孔或不打孔、2~7行中打一个孔同时第8行也打一个孔表示一个特殊字符;不打任何孔的列被视为一个空格。正是因为早期的卡片只支持大写字母,所以如今Fortran程序中不区分大小写。
从上面的打孔卡片可以看到,一行Fortran程序(即一张卡片)代表了一条Fortran语句。有时会出现一张卡打不下一行语句,这时再第二张卡片的第6列打一个非0的孔,可以表示该程序行是上一个程序行的续行。前5列是标号区,可以输入5位整数,通常情况下标号区是不允许输入非数字的,但注释除外,第一列为C的语句不会被编译器处理。第7~72列是语句区。而最后8列是在卡片时代方便程序员查找的注释区,不会被编译器处理。
之后的Fortran90格式更加自由。它一行有132列,可以有多条语句,语句之间用分号隔开,语句也没有固定位置的限制。在程序行中字符“!”后的内容都被视为注释(字符串中的“!”除外)。空格也变得有意义了(Fortran77会忽略行中的空格,关键字和变量中可以有空格)。此外如果132列还写不完一行语句的话,可以在末尾加“&”字符表示有续行,续行的开始则用“&”字符来承接上一行。F77里前面5列的10进制整型数由来表示编号,可用于之后的跳转;F90里还可以用英文名加冒号来表示标签,用于跳转。
文件名后缀.f或.for表示固定格式,而.f90表示自由格式。
一个Fortrant程序的组成结构有:
主程序
[PROGRAM 程序名] ←语句可省略
.....
END [PROGRAM [程序名]] ←END必须有
辅程序(过程)
SUBROUTINE 子程序
FUNCTION 函数
BLOCK DATA 块数据
MODULE 模块(F90)
内部过程CONTAINS (F90)
常量与变量
Fortran的常量类型有整型、实型、复型、逻辑型和字符型:
[plain]view plaincopyprint?
1. PROGRAM VARIABLES
2. INTEGER I !整型声明语句
3. REAL F !实型声明语句
4. DOUBLE PRECISION D !双精度声明语句
5. COMPLEX C !复型声明语句
6. LOGICAL B !逻辑型声明语句
7. CHARACTER S !字符型声明语句
8. !整型常量
9. I = -1234 !整型默认为4字节
10. I = -324_8 !8字节整型。下划线加数字表示精度,只允许1,2,4,8个字节
11. I = 123_1 !1字节整型
12. I = 2343_2 !2字节整型
13. I = 238_4 !4字节整型
14. !实型常量
15. F = 23. !以小数点表示实型数,默认为4字节
16. D = 87234.42343256_8 !8字节实型,只允许4或8个字节
17. F = 32.16_4 !4字节实型
18. F = 7.8E9 !指数表示(E字母)
19. D = 8.2384D12 !双精度的指数表示(D字母)
20. !复型常量(C语言里没有的)
21. C = (8.3, 98) !括号里面分别表示实部与虚部
22. !逻辑型常量
23. B = .TRUE. !只能有.TRUE.和.FALSE.两个值
24. B = .FALSE.
25. !字符型常量
26. S = 'a'
27. S = "x" !Fortran90开始允许使用双引号
28. END
上面的代码中可以看到变量的显式声明,在不显式声明的时候,变量名遵循I~N规则,即以I、J、K、L、M、N开头的(未声明的)变量都视为整型变量;其它未声明的变量都被视为实型。比如:
[plain]view plaincopyprint?
1. program implicit_type
2. imax = 85; ! i开头的变量被视为整型
3. nmin = 23; ! n开头的变量也被视为整型
4. phigh = 28.8 ! 其它变量都被视为实型
5. end
1. program implicit_type
2. implicit real (i-k) !i,j,k开头的变量都会被视为实型
3. implicit integer (a,d,x-z) !a,d,x,y,z开头的变量都会被视为整型
4. implicit complex (c) !c开头的变量会被视为复型
5. end
1. read *, iValue
2. !单行if语名
3. if (iValue > 0) print *, iValue, " is greater than 0"
4. !if then else语句块
5. if (ivalue > 5) then
6. iValue = 5
7. else if (ivalue > 0) then
8. iValue = 0
9. else
10. iValue = -5
11. end if
12. print *, iValue
1. !整型case,不支持实型case和复型case
2. read *, iValue
3. select case (iValue)
4. case (3) !当值为3时
5. print *, "It's 3!"
6. case (6:) !当下界为6时(大于等于)
7. print *, "above 6"
8. case (:0) !当上界为0时(小于等于)
10. case (4:5) !当在4到5之间时(小于等于下界大于等于上界)
11. print *, "between 4 and 5"
12. case default !其它情况
13. print *, "default"
14. end select
15. !字符型case
16. read *, cValue
17. select case (cValue)
18. case ("x")
19. print *, "it's x!"
20. case ("a":"g")
21. print *, "between a~g"
22. case default
23. print *, "other"
24. end select
25. !逻辑型case
26. read *, iValue
27. select case (iValue > 0)
28. case (.true.)
29. print *, "positive"
30. case (.false.)
31. print *, "negtive or zero"
32. end select
1. !固定循环次数的do循环
2. !不带标号的do
3. do i=1, 20, 1 !类似于C里的for(i=1,i<=20,i+=1)
4. print *, i
5. end do
6. !省略最后的增量
7. do i=1, 20 !仍然每次递增1
8. print *, i
9. end do
10. !带标号的do
11. do 123, i=20, 0, -2 !do后是标号,即从123处开始循环
12. print *, i
13. 123 continue !循环终端。该行有标号。可以用end do代替,比较过时
15. !在读写语句里可以控制读写的次数
16. print *, (i*5, i=1,20)
17. !可以嵌套循环
18. write (*,*) ((i,j,i=1,5),j=6,9) !i为内层循环,j为外层循环
19. !无限循环
20. do
21. print *, "I'm here!"
22. read *, i
23. if (i > 5) cycle !cycle回到循环起点,类似于C的continue
24. print *, "not greater than 5!"
25. if (i < 0) exit !exit用于退出循环,类似于C的break
26. end do
27. !用标签来控制嵌套循环的流程
28. outer: do
29. print *, "I'm in outer!"
30. inner: do
31. print *, "I'm in inner!"
32. read *, i
33. if (i > 0) exit inner !跳出内循环
34. if (i < 0) exit outer !直接跳出外循环
35. end do inner !必须接标签名
36. end do outer
37. !do while循环
38. i = 0
39. do while (i < 20)
40. print *, "in while", i
41. i = i+1
42. end do
1. !程序退出
2. stop 1 !类似于C的exit(1)
3. print *, "skipped" !这行不会被执行
1. program string
2. character c
3. character*8 :: s
4. !字符与数值的转换
5. iValue = ichar("a") !97-返回字符的序号值
6. iValue = iachar("a"); !97-返回字符的ascii码
7. !iValue = iachar("ab") !Error: Argument of IACHAR at (1) must be of length one
8. c = char(97) !a-返回序号值对应的字符
9. c = achar(97) !a-返回ascii码对应的字符
10. !字符串的长度
11. iLen = len("abcdefg"); !7
12. iLen = len("abcdefg "); !9
13. iLen = len_trim("abcdefg "); !7 去除尾部空格后的长度
14. !查找子串,找不到返回0
15. iIndex = index("abcdefg", "cde"); !3
16. iIndex = index("abcdefg", "abcxyz"); !0
17. !验证第一个参数里的所有字符是否属于第二个参数表示的字符集,如果都属于则返回0,否则返回
18. 第一个不属于字符集的索引。
19. iIndex = verify("bcd", "abcdefg"); !0
20. iIndex = verify("bcdxyz", "abcdefg"); !4
21. !去除末尾的空格
22. s = trim("abcd ") // "efg" !abcdefg
23. end
1. program type_demo
2. type one
3. integer a
4. character*16 s
5. end type
6.
7. type :: two
8. sequence !表示按定义的顺序储存各个成员
9. logical(8):: b
10. complex :: c = (23, 9.8) !可以缺省初始化
11. end type
12.
13. type(one):: o1, o2 = one(18, "xyz");
14. type(two):: t1;
15. t1%b = .true.
16. print *, o2%a, o2%s
17. end
1. !声明数组
2. real a(10) !下标从1到10的一维数组
3. integer b(-5:8) !下标从-5到8的一维数组
4. dimension iArray(4) !根据i~n规则确定为是整型或实型数组
5. character*8, dimension(2:5) :: sa !类型声明形式
6. integer indices(3)
7.
8. !赋初值
9. data a /10*3/ !赋成10个3
10. data b(-3), b(0), b(3) /1, 2, 3/ !把选中的三个元素分别赋成1,2,3
11. data (iArray(i),i=1,4) /4*2/ !把所有元素赋为2
12.
13. !数组的存取
14. print *, "input 10 elements:"
15. read *, (a(i), i=1,10) !读入数组a的所有元素
16. a(1) = a(1) + 2
17. a(2:4) = 5 !把a(2)、a(3)和a(4)都设为5。a(2:4)等价于a(2:4:1)
18. print *, (a(i), i=1,5) !打印前5个值
19.
20. !三元下标
21. b(:) = 8 !打b中的所有元素都设为8
22. b(1:6:2) = 7 !把b(1)、b(3)、b(5)设为7,三元下标(起始:终止:增量)
23. b(:-3) = 3 !把b(-5)、b(-4)、b(-3)设为3.默认起始为数组开头。
24. b(6::2) = 9 !把b(6)和b(8)设为9,默认终止为数组末尾
25. print *, b
26.
27. !向量下标
28. indices = (/3, 8, 6/)
29. a(indices) = 13 !把a(3)、a(8)、a(6)设为13
30. print *, a
1. integer :: a(10, 5) = 77 !大小为10x5的数组,所有的元素值都为77
2. a(:,2:3) = 8 !把每行的2,3列都设为8
3. print *, ((a(i,j), i=1,10), j=1,5)
1. subroutine automatic_array(N)
2. integer a(N)
3. a(:) = 8
4. print *, a
5. end
1. subroutine adjustable_array(A, N)
2. integer A(N)
3. print *, A
4. end
1. interface
2. !假定形状(assumed-shape)数组
3. subroutine assumed_shape_array(A)
4. integer A(:,:) !假定是个二维数组
5. end subroutine
6. end interface
[plain]view plaincopyprint?
1. subroutine assumed_size_array(A)
2. integer A(2,2,*)
3. print *, A(:,:,1)
4. end
1. integer a(6)
2. integer b(8)
3. a = (/1,2,3,4,5,6/) !长度必须一样,否则编译会出错
4. print *, a
5. a = (/3,2,3,4,7,8/) !可以多次对数组进行赋值
6. print *, a
7. a = [4,8,9,2,1,5] !方括号与(/.../)方式等价
8. print *, a
9.
10. b = (/1,2,a(1:4),8,9/) !数组方式
11. print *, b
12. b = (/(i*2,i=1,4),a(3:6)/) !隐do方式
13. print *, b
1. integer :: a(9) = (/(i,i=1,9)/)
2. a(2:9) = a(1:8) !并行方式
3. print *, a ! 1 1 2 3 4 5 6 7 8
4.
5. a = (/(i,i=1,9)/)
6. do i=2,9
7. a(i) = a(i-1) !串行方式
8. end do
9. print *, a ! 1 1 1 1 1 1 1 1 1
1. integer b(2,3)
2. b = reshape((/1,2,3,4,5,6/), (/2,3/))
3. print *, b
4. b = reshape((/1,2,3/), (/2,3/), (/8,9/))
5. print *, b !1,2,3,8,9,0。补充数组的元素仍不够的情况下补0
6. b = reshape((/1,2,3,4,5/), (/2,3/), (/8,9/), (/2,1/))
7. print *, b !1,4,2,5,3,8。顺序2,1说明先填满第一个维度(即行),再来填第二个维度(即列)。
1. integer A(5), B(5), C(5)
2. A = (/1,2,3,4,5/)
3. B = (/3,3,3,3,3/)
4. C = (/0,0,0,0,0/)
5. where (A >= B) C = A
6. print *, C ! 0,0,3,4,5
7.
8. where (A < B)
9. C = -1
10. elsewhere (A == B)
11. C = 0
12. elsewhere
13. C = 1
14. end where
15. print *, C ! -1,-1,0,1,1
1. integer A(5, 5)
2. A = reshape((/(i,i=1,25)/), (/5,5/))
3. forall(i=2:3,j=1:5:2) A(i,j) = 0
4. print *, A
1. integer A(2,3), B(2,3), C(2,3)
2. logical P(2,3), Q(2,3), R(2,3)
3. real X(2,2), Y(2,2)
4.
5. !算术运算
6. A = reshape((/(i,i=1,6)/), (/2,3/))
7. B = 2
8. C = A + B
9. print *, C
10. C = A - B
11. print *, C
12. C = A * B
13. print *, C
14. C = A / B
15. print *, C
16.
17. !比较运算
18. P = A < B
19. print *, P
20. Q = A > B
21. print *, Q
22.
23. !逻辑运算
24. R = P .and. Q
25. print *, R
26. R = P .or. Q
27. print *, R
28. R = .not. P
29. print *, R
30.
31. !基本内在函数
32. X = reshape((/1.,2.,3.,4./), (/2,2/))
33. Y = cos(X)
34. print *, Y
35. Y = sin(X)
36. print *, Y
37. Y = sqrt(X)
38. print *, Y
1. INTEGER, ALLOCATABLE :: A(:),B(:)
2. INTEGER ERR_MESSAGE
3. ALLOCATE(A(10:25),B(SIZE(A)),STAT=ERR_MESSAGE)
4. IF(ERR_MESSAGE.NE.0) PRINT *,'ALLOCATION ERROR'
1. program procedures
2. implicit none
3. integer:: x=5,y=6,res=0