y

yhyhyh

V1

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. 都是逻辑运算符,分别表示:非、与、或、异或、等同、不等同

不同类型变量之间进行运算时,有自动类型转换。以REALINTEGER为例:两种类型的变量进行运算时,结果自动转换为REAL类型。

Fortran 90 的部分内建函数:

  1. 数学函数:ABS(X), SQRT(X), SIN, COS, TAN, ASIN, ACOS, ATAN, EXP(X), LOG(X)(自然对数,以e为底数), LOG10(X)(常用对数,以10为底数)
  2. 类型转换函数:INT, NINT, FLOOR(X)(小于或等于X的最大整数), FRACTION(X)(X的小数部分), REAL
  3. 其他常用运算函数: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.

分类:

数学

标签:

数学编程

作者介绍

y
yhyhyh
V1