yhyhyh
2023/01/14阅读:46主题:默认主题
Fortran学习笔记丨基本语法、数组与文件操作
Fortran学习笔记丨基本语法、数组与文件操作
目录
基本语法
Fortran 90 程序的基本结构(举例说明):
program main
! 注释内容,感叹号需要用英语环境
implicit none ! 去掉隐式声明,即所有变量必须先声明类型,再使用
real*8 a ! 定义一个实数变量【程序声明部分】
write(*,*) "hello world!" ! 【程序执行部分】
end program main
续行标志为&
,例如:
a = total_number + a_part_number &
+ b_part_number
! 两行语句,一行命令
尽量不要定义“太长”的变量。如果变量太长,一行写不完,也可用续行标志进行换行:
a = 1.0 + a_very_Long&
&Variable_Name
变量名最长31个字符(?)
变量名不区分大小写
变量名只能包括:字母、数字、下划线,且必须以字母开头
定义常量(或,给常量指定一个名字):
INTEGER, PARAMETER::MAX_INDEX = 100
REAL*8, PARAMETER::PI = 3.14159265, g=9.8D0
CHARACTER(LEN=4), PARAMETER::NAME1='JOHN', NAME2='SMITH'
! 实际上 NAME1='JOHN' 而 NAME2='SMIT'
! 注意 CHARACTER(LEN=4) 与 CHARACTER(4) 等效
CHARACTER(LEN=*),PARAMETER::NAME3='SHERLOCK'
! NAME3 没有字符串长度的限制
定义变量(一行语句可以定义多个变量):
INTEGER::MONTH, YEAR
REAL*8::AREA, VOLUME
CHARACTER(77)::BUF
CHARACTER::CH ! 等价于 character(len=1)::ch
变量的初始化:在定义变量的时候赋值(或者在第一次使用变量前赋值)
一些运算符:
-
+, -, *, /, **
分别表示:加、减、乘、除、乘方 -
==, /=
分别表示:等于,不等于,都是关系运算符 -
.NOT, .AND., .OR., .XOR., .EQV., .NEQV.
都是逻辑运算符,分别表示:非、与、或、异或、等同、不等同
不同类型变量之间进行运算时,有自动类型转换。以REAL
与INTEGER
为例:两种类型的变量进行运算时,结果自动转换为REAL
类型。
Fortran 90 的部分内建函数:
-
数学函数: ABS(X), SQRT(X), SIN, COS, TAN, ASIN, ACOS, ATAN, EXP(X), LOG(X)(自然对数,以e为底数), LOG10(X)(常用对数,以10为底数)
-
类型转换函数: INT, NINT, FLOOR(X)(小于或等于X的最大整数), FRACTION(X)(X的小数部分), REAL
-
其他常用运算函数: MAX, MIN, MOD(X,Y)(等价于C语言中的 X%Y)
READ(*,*)
语句读取多个数据时,从新的一行开始读取(键盘或文件),以空格分界。例如:
program example_101
implicit none
INTEGER::I,J,K,L,M,N
READ(*,*) I,J,K
READ(*,*) L,M
READ(*,*) N
WRITE(*,*) "I = ",I,", J = ",J,", K = ",K
WRITE(*,*) "L = ",L,", M = ",M,", N = ",N
WRITE(*,*) ! WRITE A BLANK LINE
end program example_101
输入文件为:
100 200 300 400
500,600,700 800
900
结果为:
I = 100 , J = 200 , K = 300
L = 500 , M = 600 , N = 900
也可以结合格式化输出的方法,实现更加规范化的输入输出。
选择语句
逻辑型变量
逻辑型变量的声明方式:
LOGICAL::MASK
逻辑型变量只有两个值:.TRUE.
与 .FALSE.
逻辑型变量输入输出可以用T或F代替。
IF结构
IF结构的表达式举例:
IF (MOD(NUMBER,2) == 0) THEN
PRINT*, "EVEN NUMBER!"
ELSE IF (MOD(NUMBER, 3) == 0) THEN
PRINT*, "NUMBER DIVIDED BY 3 IS ZERO!"
ELSE
PRINT*, "OTHER NUMBERS."
END IF
上述结构中,ELSE IF
以及ELSE
语句都可以省略。
如果判断之后只有一条语句执行,则IF
后面的THEN
关键字可以省略。例如:
REAL*8 :: X, ABS_X
READ(*,*) X
ABS_X = X
IF (X < 0.0D0) ABS_X = -X
PRINT*, "ABS(",X,") = ",ABS_X
IF
语句可以嵌套……
SELECT-CASE结构
select-case结构的一般表达式为:
INTEGER::SELECTOR_1
CHARACTER(LEN=1)::SELECTOR_2
LOGICAL::SELECTOR_3
! SELECTOR只能是整型、字符型或逻辑型,不能是实数型
! LABEL_LIST的形式包括:
! v1, v2, v3 // v1, v2, v3 之一
! v1:v2 // v1 <= selector <= v2
! v1: // selector >= v1
! :v2 // selector <= v2
SELECT CASE (SELECTORS)
CASE (LABEL_LIST_1)
STATEMENT_1
CASE (LABEL_LIST_2)
STATEMENT_2
! ......
CASE DEFAULT
STATEMENT_DEFAULT
END SELECT
例子:
PROGRAM EXAMPLE_201
IMPLICIT NONE
CHARACTER(LEN=1)::CH
READ(*,*) CH
SELECT CASE (CH)
CASE ('A','E','I','O','U')
PRINT*, CH,' BELONGS TO VOWELS.'
CASE ('a','e','i','o','u')
PRINT*, CH,' BELONGS TO VOWELS.'
CASE ('B':'D','F':'H','J':'N','P':'T','V':'Z')
PRINT*, CH,' BELONGS TO SEMIVOWELS.'
CASE ('b':'d','f':'h','j':'n','p':'t','v':'z')
PRINT*, CH,' BELONGS TO SEMIVOWELS.'
CASE DEFAULT
PRINT*, 'PLEASE INPUT ALPHABETA CHARACTERS!'
END SELECT
READ(*,*)
END PROGRAM EXAMPLE_201
循环语句
do循环
do循环的一般格式是:
INTEGER::START_VALUE, END_VALUE, STEP_LENGTH
INTEGER::COUNTER
READ(*,*) START_VALUE, END_VALUE, STEP_LENGTH
DO COUNTER = START_VALUE, END_VALUE, STEP_LENGTH
PRINT*, "HELLO WORLD!"
END DO
! *STEP_LENGTH* 可以删除, 此时步长默认为1
举例:计算N的阶乘。
PROGRAM EXAM_302
! CALCULATE N!=N*(N-1)*...*3*2*1
IMPLICIT NONE
INTEGER*8::N, N_FACT,I
PRINT*, "PLEASE INPUT AN INTEGER N: "
READ(*,*) N
N_FACT = 1
DO I=1,N
N_FACT = N_FACT * I
END DO
PRINT*, N,"! = ",N_FACT
PRINT*,"PRESS ANY KEY TO EXIT..."
READ(*,*)
END PROGRAM EXAM_302
DO循环可以不带计数变量,代之以EXIT语句。其一般格式为:
DO
CALL STATEMENT_1 ! DO SOMETHING...
IF CONDITION THEN
EXIT ! EXIT THE DO-LOOP
END IF
END DO
举例:输入多个非零整数,直到遇到0停止;求和。
PROGRAM EXAM_301
IMPLICIT NONE
INTEGER*8::VAL, THE_SUM
THE_SUM = 0
VAL = 0
DO
PRINT*, "PLEASE INPUT A NON-ZERO INTEGER: "
READ(*,*) VAL
IF (VAL .EQ. 0) THEN
PRINT*, "END PROGRAM."
EXIT
END IF
THE_SUM = THE_SUM + VAL
END DO
PRINT*, "THE SUM OF THE INTEGERS IS ", THE_SUM
PRINT*, "PRESS ANY KEY TO EXIT..."
READ(*,*)
END PROGRAM EXAM_301
又一例:从键盘输入非负整数,求出其中的最大值与最小值;输入0则停止。
源代码参考:
PROGRAM EXAM_303
IMPLICIT NONE
INTEGER*8::N, MAX_NUMBER, MIN_NUMBER
INTEGER::COUNT_VAL
COUNT_VAL = 0
DO
READ(*,*) N
IF (N .EQ. 0) THEN
EXIT
ELSE
! 如果是第一次输入非零数据
IF (COUNT_VAL .EQ. 0) THEN
MAX_NUMBER = N
MIN_NUMBER = N
ELSE
IF (N .GT. MAX_NUMBER) MAX_NUMBER = N
IF (N .LT. MIN_NUMBER) MIN_NUMBER = N
END IF
COUNT_VAL = COUNT_VAL + 1
END IF
END DO
IF (COUNT_VAL .EQ. 0) THEN
PRINT*,"NO DATA INPUT!"
ELSE
PRINT*, "MAX = ", MAX_NUMBER
PRINT*, "MIN = ", MIN_NUMBER
END IF
PRINT*, 'PRESS ANY KEY TO EXIT...'
READ(*,*)
END PROGRAM EXAM_303
隐式DO循环
隐式DO循环举例。以下是部分代码与程序执行结果:
代码:
INTEGER*8 :: I
WRITE(*, "(I3, I6)") (I,I**2,I=1,20,3)
执行结果:
1 1
4 16
7 49
10 100
13 169
16 256
19 361
一维数组
基本概念
数组:相同类型的数据的集合;
数组的下标是整数常量,默认从1开始;注意不要越界……
数组的定义
! FORTRAN-77
! <TYPE>, DIMENSION(<LOWER_BOUND>:<UPPER_BOUND>)::<ARRAY_NAME_LIST>
REAL, DIMENSION(-1:1)::ARR_1
INTEGER, DIMENSION(0:100)::ARR_2, ARR_22
! FORTRAN-90
REAL*8::ARR_11(-1:1), ARR_12(0:10),ARR_13(20)
REAL::ARR_3(100) ! MEANS ARR_3(1:100)
! 数组范围可以用常量表示
INTEGER, PARAMETER :: MAX_INDEX = 100
REAL*8 :: NUMBERS(MAX_INDEX)
数组的引用
-
引用单个数组元素:可以用常量下标或者变量下标,如: ARR_1(3)
、ARR_2(I)
-
使用数组名赋值,等价于对数组的每个元素进行赋值。如: ARR = 0
-
切片;是闭区间,包含起点与终点。如: ARR(2:4) = 0
等价于ARR(2)=0, ARR(3)=0, ARR(4)=0
;又如,ARR(:10)=0
等价于ARR(1:10)=0
多维数组
数组的下标的范围默认从1开始。不同维度之间用逗号,
隔开。例如:
INTEGER::M
INTEGER::A(M,M) ! 2-D ARRAY
REAL*8::POINT(M,M,M) ! 3-D ARRAY
多维数组的存储方式:按列存储。详见技术文档Fortran多维数组。对多维数组进行操作时,建议按列操作。例如:
INTEGER :: A(30,3), I, J
DO J=1,3
DO I=1,30
!DO SOMETHING FOR A(I,J)
END DO
END DO
如何从文件中读取数组?举例:如需要从文件中读取5行5列的上三角矩阵,矩阵的非零元素等于行坐标乘以列坐标。输入文件可以写作:
1 0 0 0 0
2 4 0 0 0
3 6 9 0 0
4 8 12 16 0
5 10 15 20 25
注意文件中的矩阵看上去是原矩阵转置后的形式。源文件参考:
PROGRAM EXAM_401
IMPLICIT NONE
INTEGER, PARAMETER :: M=5, N=5
INTEGER :: I,J,A(M,N)
! 读取数据。
OPEN(9, FILE='input_401.txt')
DO J=1,N
READ(9, "(5(I4))") (A(I,J),I=1,5)
END DO
CLOSE(9)
! 按照“正常模式”输出矩阵
DO I=1,M
WRITE(*,"(A3,I2,A2,5(I4))") "Row",I,": ",(A(I,J),J=1,5)
END DO
END PROGRAM EXAM_401
输出的结果为:
Row 1: 1 2 3 4 5
Row 2: 0 4 6 8 10
Row 3: 0 0 9 12 15
Row 4: 0 0 0 16 20
Row 5: 0 0 0 0 25
动态数组
动态数组在定义使需要使用关键字ALLOCATABLE
,在确定数组规模时使用函数ALLOCATE
。具体用法:
REAL*8, ALLOCATABLE :: A(:), B(:,:)
! A 是一维数组, B 是二维数组
INTEGER::M,N
READ(*,*) M,N
ALLOCATE(A(N), B(M,N))
! 为A和B数组分配内存
内部文件
所谓的内部文件(internal file),指的是字符型变量、字符数组或字符串等存放在内存上的文件。内部文件不能长期保存数据,程序运行结束后就会“消失”。
内部文件的应用之一:从字符串中解析数据
PROGRAM EXAM_501
IMPLICIT NONE
CHARACTER*40 STR1, STR2
! MEANS CHARACTER(LEN=40)
INTEGER*8 NA,NB,NC,ND
STR1 = "314, 278, 69, 0"
! 将字符串中的数据拆分并存储到几个整型变量中
READ(STR1,*) NA,NB,NC,ND
WRITE(*,"('A=',I3,', B=',I3,', C=',I3,', D=',I3)") &
NA,NB,NC,ND
! 将数据信息写到字符串中
WRITE(STR2,"('a=',I3,', b=',I3,', c=',I3,', d=',I3)") &
NA,NB,NC,ND
PRINT*, STR2
END PROGRAM EXAM_501
运行结果为:
A=314, B=278, C= 69, D= 0
a=314, b=278, c= 69, d= 0
外部文件
外部文件,一般指磁盘数据文件。
外部文件分类:3种文件格式(有格式、无格式、二进制),2种存取方式(顺序存取、直接存取)的排列组合。
文件基本操作(概述)
打开文件并对文件进行读写操作,首先要用到OPEN
语句,格式为:
OPEN([UNIT=]9, FILE='FILE.TXT'[,...])
文件处理完成后,使用CLOSE
语句关闭文件
CLOSE([UNIT=]9)
UNIT
号码可以任意指定,但要注意防止混淆或歧义。
此外,
命令 | 作用 |
---|---|
READ() |
从文件中读取数据 |
WRITE() |
向文件内写入数据 |
REWIND() |
将文件指针指向起始位置 |
BACKSPACE() |
当前指针回退一个记录位置 |
OPEN命令
OPEN
命令的必选参数包括:
-
UNIT
:设备号,可任意设置(正整数变量或常量、表达式)。如果放在第一个参数位置上,则“UNIT=
”可以省略。 -
FILE
:文件名,是字符串常量或变量、表达式。“FILE=
”不可以省略。
OPEN
命令的可选参数包括:
-
ERR
选项:为OPEN
语句指定一个错误处理的转移标号(正整数变量或常量、表达式);当OPEN
语句执行出错时,程序并不终止,而是转移到对应的语句处执行。例如:100 WRITE(*,*) "THE FILE CANNOT OPEN!" OPEN(1,FILE='INP.dat', ERR=100)
当文件不能正确打开时,屏幕上打印
"THE FILE CANNOT OPEN!"
-
ACTION
选项:设置文件的读写属性。-
ACTION=READWRITE
:缺省。读写模式,打开的文件可读可写 -
ACTION=READ
:只读模式。 -
ACTION=WRITE
:只写模式。
-
-
ACCESS
选项:指定文件的存取方式。-
ACCESS=APPEND
:追加模式。 -
ACCESS=SEQUENTIAL
:顺序存取。缺省值。 -
ACCESS=DIRECT
:直接存取。
【各个方式的区别?】
-
-
STATUS
选项:设置文件的状态属性。-
OLD
:文件已存在。 -
NEW
:文件不存在。创建不存在的文件,并将文件属性变为OLD
。若文件已存在,则报错。 -
SCRATCH
:文件为临时文件,文件关闭或程序结束后,该文件被删除。 -
REPLACE
:文件替换已存在的同名文件;若文件不存在,则创建文件。 -
UNKNOWN
:缺省模式。先用OLD
模式打开文件,若打开失败则使用NEW
模式。
-
CLOSE命令
CLOSE
命令的常用用法为:
OPEN([UNIT=]1,FILE='INP.dat')
! DO SOMETHING...
CLOSE([UNIT=]1)
READ与WRITE命令
当从键盘读入(无格式)数据时,用法为:
READ(*,*) A_VARIABLE
WRITE(*,*) A_VARIABLE
当从某一文件中读取或向其中写入(无格式)数据时,应先打开文件,并用UNIT
号进行读写操作。例如:
OPEN(UNIT=99, FILE='INP.dat')
READ(99,*) A_VAR
WRITE(99,*) "HELLO WORLD!"
CLOSE(99)
REWIND与BACKSPACE命令
REWIND
命令:将文件指针指回文件开头。
BACKSPACE
命令:将文件指针回退一个记录位置(一般是回到上一行)
两个命令的参数均为UNIT
号。
例子:从文件读数据
一个例子:从文件中读取数据。数据分三行,第1行有5个整数、第2行3个、第3行2个。我们使用隐式DO循环读入数据。
PROGRAM EXAM_502
IMPLICIT NONE
INTEGER*8 T_SUM,A(10)
INTEGER I
REAL*8 T_AVE
! 读取数据
OPEN(9, FILE='IPT.dat')
READ(9,*) (A(I),I=1,10)
CLOSE(9)
! 计算总和与平均值
T_SUM = 0
DO I=1,10
T_SUM = T_SUM + A(I)
END DO
T_AVE = T_SUM/10.0
! 将计算结果写入文件
OPEN(10,FILE='OPT.dat')
WRITE(10,"('THE SUM IS: ',I6)") T_SUM
WRITE(10,"('THE AVERAGE IS: ',F9.3)" T_AVE
CLOSE(10)
END PROGRAM EXAM_502
输入文件为:
5 7 4 8 12
2 10
3 9 11
输出文件为:
THE SUM IS: 71
THE AVERAGE IS: 7.100
End of File.
作者介绍