含蓄的自行车 · 不断深化对文化建设的规律性认识--党建-中国 ...· 5 月前 · |
谦和的手术刀 · 京九高铁阜阳至黄冈段预可研审查已延期,拟年内 ...· 1 年前 · |
憨厚的饭盒 · 【图】长城公关总经理离职,近年有多位高管离职 ...· 1 年前 · |
打酱油的西装 · 联想拯救者Y7000P 2022版 ...· 1 年前 · |
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 plain
gfortran可以用来编译fortran程序。
早期的fortran程序(Fortran77)是写在一张12行80列的卡片上的。每一张卡片表示程序中的一行。卡片上的一列可以表示一个字符。当时允许输入的字符只有0-9,A-Z,以及特殊符号“+ - * / ( ) , . ':”。通过在一列中打1~3个孔来表示一个字符:
卡片上明示了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 plain上面的代码中可以看到变量的显式声明,在不显式声明的时候,变量名遵循I~N规则,即以I、J、K、L、M、N开头的(未声明的)变量都视为整型变量;其它未声明的变量都被视为实型。比如:
[plain] view plain变量类型的优先级为显式声明>隐式声明>I~N规则。显式声明和隐式声明的作用范围仅限于当前程序。
整数常量可以用B开头表示二进制(比如B'101011')、用O开头表示八进制(比如O'34761')、用Z表示十六进制(比如Z'23af8')。
常用的Fortran77库函数
如下表所示:
算术运算符
有5种:
+ 表示“加”(或正号)
- 表示“减”(或负号)
* 表示“乘”
/ 表示“除”
** 表示“乘方”
关系运算符
有6种:
关系运算符 |
英语含义 |
所代表的数学符号 |
|
.GT. .GE. .LT. .LE. .EQ. .NE. |
> >= < <= == /= |
Greater Than Greater than or Equal to Less Than Less than or Equal to EQual to Not Equal to |
> (大于) ≥ (大于或等于) < (小于) ≤ (小于或等于) = (等于) ≠ (不等于) |
逻辑运算符
有5种:
逻辑运算符 |
含义 |
逻辑运算例 |
例子含义 |
.AND. .OR. .NOT. .EQV. .NEQV. |
逻辑与 逻辑或 逻辑非 逻辑等价 逻辑不等价 |
A.AND.B A.OR.B .NOT.A A.EQV.B A.NEQV.B |
A,B为真时,则A.AND.B为真 A,B之一为真,则A.OR.B为真 A为真,则.NOT.A为假 A和B值为同一逻辑常量时,A.EQV.B为真 A和B的值为不同的逻辑常量,则A.NEQV.B为真 |
各种运算符的优先级别 :
运算类别 |
运算符 |
优先级 |
括号 |
( ) |
1 |
算术运算 |
** |
2 |
* / |
3 |
|
+ - |
4 |
|
关系运算 |
.GT. .GE. .LT. .LE. .EQ. .NE. |
5 |
逻辑运算 |
.NOT. |
6 |
.AND. |
7 |
|
.OR. |
8 |
|
.EQV. .NEQV. |
9 |
程序流程控制
if选择结构 :
[plain] view plain类型声明语句 的格式为: 类型说明[(种别说明)][,属性说明表] :: 变量名表[=初值] ,方括号中的可以被省略,所以最简形式为 类型说明:: 变量名表
类型说明 有五种:integer, real, complex, character, logical
种别说明 表示变量所占用的字节数。integer(kind=8)表示8字节的整型。kind可以省略,写成integer(8)。其它类型也可以用相同的方式指定种别。整型种别可以是1、2、4、8,实型种别可以是4、8、16,复型种别可以是8、16、32,逻辑型种别可以是1、2、4,字符型种别只能是1。
在类型后加上“*”号与数字也可以表示变量的字节数,比如integer*8等同于integer(8)。值得注意的是complex*32等同于complex(16),因为复数包含两个部分。character*8表示长度为8的字符串,虽然字符型类别只能是1。
F90中关于种别选择的内部函数有:
KIND(X) :函数KIND用于查询变量的种别,它返回X的种别值,当X取值为0时,返回标准种别值即缺省值。如:KIND(0)返回值是整型的标准种别值,KIND(0.)、KIND(.FALSE.)、 KIND(“A”)分别返回实型、逻辑型、字符型的标准种别值。
SELECTED_REAL_KIND([n][,m]) :该函数返回实型变量对所取的值范围和精度恰当的种别值。其中n是指明十进制有效位的位数,m指明值范围内以10为底的幂次。例如: SELECTED_REAL_KIND(6,70)的返回值为8,表示一个能表达6位精度、值范围在-10 70 —+10 70 之间实型数的种别值为8。但该机型上不能提供满足要求的种别值时,它的返回值是:-1(当精度位数达不到时),-2(当数值范围达不到时),-3(两者都达不到时)。对给定的实型和复型量X,它的精度和范围可通过内部函数PRECISION(X)和RANGE(X)查出。
SELECTED_INT_KIND([m]) :该函数返回整型变量对所取的值范围恰当的种别值。m指明值的范围是-10 m —+10
属性说明
可以是下表的某个或某几个的组合:
属性关键字 |
描述 |
适用范围 |
ALLOCATABLE |
说明动态数组 |
数组 |
AUTOMATIC |
声明变量在堆栈中而不是在内存中 |
变量 |
DIMENSION |
说明数组 |
数组变量 |
EXTERNAL |
声明外部函数的名称 |
过程 |
INTENT |
说明过程哑元的用意 |
过程哑元 |
INTRINSIC |
声明一个内部函数 |
过程 |
OPTIONAL |
允许过程被调用时省略哑元 |
过程哑元 |
PARAMETER |
声明常量 |
常量 |
POINTER |
声明数据对象为指针 |
变量 |
PRIVATE |
限制模块中的实体访问于本块内 |
常量、变量或模块 |
PUBLIC |
允许模块中的实体被外部使用 |
常量、变量或模块 |
SAVE |
保存过程执行后其中的变量值 |
变量或公共块 |
STATIC |
说明变量为静态存储 |
变量 |
TARGET |
声明变量为目标 |
变量 |
VOLATILE |
声明对象为完全不可预测并在编译时无优化 |
数据对象或公共块 |
初值
可以在声明语句中赋值,也可以用data语句(F77)。data语句的形式为:
DATA 变量名表1/初值表1/[[,]变量名表2/初值表2/…]
比如data i/3会给i赋个初值3。data i,f /4,3.5/ 分别给i和赋值。如果变量已经被赋过值了,那么data语句不会再改变这个变量的值。data语句还可以给数组赋初值(后面介绍)。
字符串
的声明方式如下:
CHARACTER[(LEN=整型字符长度表达式[,KIND=种别值])][,属性说明] :: 变量名表[=初始值]
前面已经提到字符的种别只能是1,但是它有一个len的选项。比如:CHARACTER(LEN=12,KIND=1) :: A,B或CHARACTER(KIND=1,LEN=12) :: A,B,len和kind可以省去,但len值必须在前面,如character(12, 1) :: A, B,种别值也可以省略:character(12) :: A, B,它等价于character*12 :: A, B。
字符的长度在声明时可以用*表示为不确定,比如character(len=*), parameter :: c = "abcde"。这行等同于C语言里的const char[] c = "abcde";。只有声明为parameter属性或者过程哑元(dummy argument)时,才可以使用不确定的长度。(哑元在后面介绍)。
字符子串
可以通过s(a:b)方式得到,比如s为“abcdefg”,s(3:5), s(:3), s(5:), s(:), s(4:4)分别返回:cde、abc、efgh、abcdefgh和d。注意fortran中索引从1开始,而不是从0开始。子串可以进行赋值,比如s(3:5) = "xyz"。赋值时,如果左边变量的长度更小,则只取右边字符串的前面一部分;如果左边变量长度更大,则在多出的部分补空格。
//操作符 可以把两个字符串拼接,比如s//"tommy",可以产生一个新的字符串。
可以用 <、>、==和\= 来 比较两个字符串 ,区分大小写。"Tommy"和"tommy"是不等的。字符串末尾的空格会被忽略,比如"tommy "与"tommy"是相等的,但字符串开头的空格不会被忽略,比如" tommy"和"tommy"就是不等的。 此外还有比较字符大小的函数:LGE、LGT、LLE、LLT :
引用方式 |
含 义 |
例 |
LGE(a1,a2) |
a1是否≥a2 |
LGE(‘A’,‘B’)值为假 |
LGT(a1,a2) |
a1是否>a2 |
LGT(‘A’,‘B’)值为假 |
LLE(a1,a2) |
a1是否≤a2 |
LLE(‘A’,‘B’)值为真 |
LLT(a1,a2) |
a2是否<a2 |
LLT(‘A’,‘B’)值为真 |
其它与字符串相关的函数 :
[plain] view plain
TYPE[,访问属性说明::] 派生类型名
成员1类型说明
……
成员n类型说明
END TYPE [派生类型名]
其中TYPE是关键字,表示派生类型定义开始。访问属性说明关键字是PUBLIC或PRIVATE,默认值是PUBLIC,即访问方式是共用的。PRIVATE表示该类型是专用的,这个关键字只有当TYPE块写在模块说明部分中时,才允许使用。下面是一个例子:
数组 在程序中的表现如下:
[plain] view plain自动(automatic)数组 根据过程哑元(函数参数)来确定数组的形状与大小:
[plain] view plain可调(adjustable)数组 根据传入的哑元数组以及维度信息来确定数组的大小:
[plain] view plain假定形状(assumed-shape)数组 可以先假定数组的维度,传入的数组必须有相同的维度。假定形状数组必须定义在interface里:
[plain] view plain数组的赋值 可以用下面这种便利的方式:
[plain] view plainFortran90对元素的处理是并行的,哪怕不是在并行计算机上,操作在形式上也是并行的。看下面的例子:
[plain] view plain源 是用来转变的一维数组; 形状 是一个一维整型数组,各元素表示结果数组的各个维度的大小;补充是和源一样类型的一维数组,当源比结果数组小时,其元素用来补充缺少的元素;顺序也是一维数组,其元素为1到n的一个排列,其中n为形状数组的大小,默认情况下顺序数组的元素为(1,2,...,n),表示源数组中的元素先填充顺序为n的维度,最后填充顺序为1的维度。下面是一个例子:
[plain] view plain
where语句
可以用来进行带条件的数组赋值,它的形式为
WHERE(屏蔽表达式) 赋值语句 或
[构造名:]WHERE(屏蔽表达式1)
[块]
[ELSEWHERE(屏蔽表达式2) [构造名]
[块]]
[ELSEWHERE [构造名]
[块]]
END WHERE [构造名]
下面是where的一个例子:
[plain] view plainFORALL(循环三元下标[,循环三元下标]…[,屏蔽表达式]) 赋值语句 或
[构造名:]FORALL(循环三元下标[,循环三元下标]…[,屏蔽表达式])
[块]
END FORALL [构造名]
下面是forall的一个例子:
[plain] view plain
函数名称 |
描述 |
ALL(mask[,dim]) |
判断全部数组值在指定维上是否都满足mask的条件 |
ANY(mask[,dim]) |
判断是否有数组值在指定维上满足mask的条件 |
COUNT(mask[,dim]) |
统计在指定维上满足mask的条件的元素个数 |
CSHIFT(array,shift[,dim]) |
进行指定维上的循环替换 |
DOT_PRODUCT(vector_a,vector_b) |
进行两个向量的点乘 |
EOSHIFT(array,shift[,boundary][,dim]) |
在指定维上替换掉数组末端,复制边界值到数组末尾 |
LBOUND(array[,dim]) |
返回指定维上的下界 |
MATMUL(matrix_a,matrix_b) |
进行两个矩阵(二维数组)的乘积 |
MAXLOC(array[,dim][,mask]) |
返回数组的全部元素或指定维元素当满足mask条件的最大值的位置 |
MAXVAL(array[,dim][,mask]) |
返回在指定维上满足mask条件的最大值 |
MERGE(tsource,fsource,mask) |
按mask条件组合两个数组 |
MINLOC(array[,dim][,mask]) |
返回数组的全部元素或指定维元素当满足mask条件的最小值的位置 |
MINVAL(array[,dim][,mask]) |
返回在指定维上满足mask条件的最小值 |
PACK(array,mask[,vector]) |
使用mask条件把一个数组压缩至vector大小的向量 |
PRODUCT(array[,dim][,mask]) |
返回在指定维上满足mask条件的元素的乘积 |
RESHAPE(source,shape[,pad][,order]) |
使用顺序order和补充pad数组元素来改变数组形状 |
SHAPE(source) |
返回数组的形状 |
SIZE(array[,dim]) |
返回数组在指定维上的长度 |
SPREAD(source,dim,ncopies) |
通过增加一维来复制数组 |
SUM(array[,dim][,mask]) |
返回在指定维上满足mask条件的元素的和 |
TRANSPOSE(matrix) |
转置二维数组 |
UBOUND(array[,dim]) |
返回指定维上的上界 |
UNPACK(vector,mask,field) |
把向量在mask条件下填充field的元素解压至数组 |
对于allocable的数组,可以用allocate来分配一块内存:
ALLOCATE(
数组名
[
维界符
][,
数组名
[(
维界符
[,
维界符
...])]] ...[,STAT=
状态值
])
。
STAT用来接受返回值,如果不设置STAT的话,如果分配出错,程序会中止。下面是个例子:
[plain] view plainALLOCATED( 数组名 ) 可以判断一个数组是否已被分配 。
过程和模块
F90中,共有四种程序单元:
主程序
、
过程或辅程序
、
块数据单元
和
模块
。下表是对它们的概括描述:
程序单元 |
定义 |
主程序 |
主程序是程序开始执行的标志,其第一条语句不能是SUBROUTINE,FUNCTION,MODULE和BLOCK DATA。主程序可以用PROGRAM语句作为第一条语句,但不是必需的 |
过程 |
子程序或函数 |
块数据单元 |
在命名的公共块中提供变量初始值的程序单元 |
模块 |
包含数据对象定义、类型定义、函数或子程序接口和其它程序可访问的函数或子程序 |
主程序
是整个程序的入口,类似于C里的main函数。它的格式为:
[PROGRAM [程序名]]
[说明部分]
[可执行部分]
[CONTAINS
内部过程]
END [PROGRAM[程序名]]
过程 类似于C语言里的函数。它分为 外部过程 、 内部过程 和 内在过程 。
外部过程
独立于其它的程序单元,它的形式有两种:
外部函数
:
FUNCTION语句
[说明部分]
[可执行部分]
[CONTAINS
内部过程]
END [FUNCTION函数名]
外部子程序
:
SUBROUTINE语句
[说明部分]
[可执行部分]
[CONTAINS
内部过程]
END [SUBROUTINE子程序名]
内部过程
是(通过contains语句)包含在宿主单元(
外部过程、模块或主程序单元
)内的过程,它的形式也有两种:
内部函数
:
FUNCTION语句
[说明部分]
[可执行部分]
END [FUNTION函数名]
内部子程序
:
SUBROUTINE语句
[说明部分]
[可执行部分]
END [SUBROUTINE子程序名]
可以看到内部过程不能再包含其它的内部过程。
内在过程 就是Fortran的库函数,比如sin、abs等。Fortran90中定义了113个内在过程。
下面是子程序与过程(外部与内部)的例子:
[plain] view plain变元的 save属性 类似于c的static,而且在未声明的情况下变量也都是save的。(而且我的gfortran(gcc4.5.2)根本不支持automatic属性,哪怕是用-fautomatic和-frecursive的命令参数。这样所有的变量都只能是save的……fortran95本应该支持static关键字的,但我的gfortran也不支持……)。
在调用子过程或函数时,可以使用 关键字变元 ,使用关键字改变传入实参的顺序。比如:
[plain] view plain另一个有趣的特性是 可选变元 ,它用 optional属性 表示。代码如下:
[plain] view plain通过接口可以把几个子过程合并成一个 类属过程 ,类似于C里的模板的作用:
[plain] view plain
块数据单元
用来存放公共数据,它的形式为:
BLOCK DATA[块数据名]
[说明部分]
END [BLOCK DATA[块数据名]]
Fortran中所有程序单元都是分别编译的,所以它们的作用域都是独立的。也就是说,一个程序单元内部的局部变量是不会被其它程序单元使用的。Fortran77使用了 COMMON 和 EQUIVALENCE 来 共享数据 。
COMMON 用于在不同的程序单元中共享数据的用法如下:
[plain] view plain输入输出和文件
文件分为
外部文件
和
内部文件
。外部文件包括外部设备(如键盘和屏幕)以及磁盘上的文件,而内部文件指在内存中可以像磁盘文件一样进行操作的数据块。
为了对文件进行操作,需要使用逻辑设备与它们连接。
外部文件
可以通过open(unit=id,file='filename')的方式打开,id便是逻辑设备的标识符,可以用来读写,也能用close关闭文件。设备号的取值范围为
-32768
到
32767
。
Fortran预定义了4种外部文件(设备):
设备号 |
连接的设备 |
星号(*) |
总是键盘和显示器 |
0 |
缺省状态下是键盘和显示器 |
5 |
缺省状态下是键盘 |
6 |
缺省状态下是显示器 |
此前所有的 print *, ... 语句就是表示向显示器输出。*设备不能被关闭。
内部文件 对应的逻辑设备可以用一个变量名来表示:
[plain] view plain外部文件的 访问方式有两种:顺序访问和直接访问 ;而 文件结构有三种:格式化文件、无格式文件和二进制文件 。这样组合出来的文件有六种。
1、
格式化顺序文件
以可读的字符串形式进行(顺序)读写。文件打开时在文件开头写入(文件原有数据会被清空),之后每次在文件末尾处写入一条记录。所有记录的大小不定,且由回车符加换行符(即\r\n)分隔。下面是一个例子:
6、
二进制直接文件
与无格式直接文件类似,所有记录的大小一样,其大小由open函数的recl参数指定。记录中未被使用的部分由未定义的字节填充。
下面贴出四类 文件操作语句 :
b) ENDFILE语句
ENDFILE语句的功能是在文件上写一条文件结束记录,这时文件定位在结束记录的后面。它的一般形式为:
ENDFILE{unit|([UNIT=]unit[,ERR=err][,IOSTAT=iostat])}
由于用ENDFILE语句在文件中写入一条结束记录后,文件的指针被定位在结束记录之后,所以若再想向同一个文件中添加更多的记录,就必须使用BACKSPACE或REWIND语句对文件进行文件指针定位的操作。在直接访问文件中使用ENDFILE语句在文件中写入一条结束记录后,新的结束记录后的所有老的记录都将被删除掉。
c) CLOSE语句
CLOSE语句解除设备号与文件的连接,又称关闭文件。它的一般形式为:
CLOSE([UNIT=]unit[,ERR=err][,IOSTAT=iostat][,STATUS|DISPOSE|DISP=status])
其中除STATUS以外的各项参数的意义及取值与OPEN语句中的相同。STATUS是文件关闭后状态说明,其值是一字符串:
DELETE 与设备连接的文件不保留,被删除
KEEP(或SAVE) 与设备号连接的文件保留下来不被删除
PRINT 将文件递交给打印机打印并被保留(仅对顺序文件)
PRINT/DELETE 将文件递交给打印机后被删除
SUBMIT 插入一个进程以执行文件
SUBMIT/DELETE 插入一个进程以执行文件,当插入完成后被删除
默认设置将删除带有SCRATCH属性的临时文件,对其它文件为KEEP。
在程序中,没有必要显示的进行文件的关闭,—般情况下,当程序退出时将以各个文件的默认状态关闭所有的文件。CLOSE语句不必与OPEN语句出现存同一程序单元中。
d) 文件指针定位语句
REWIND
语句:称为反绕语句,它使指定设备号的文件指针指向文件的开头,通常用于顺序文件的操作。它的一般形式为:
REWIND{unit|([UNIT=]unit[,ERR=err][,IOSTAT=iostat])
BACKSPACE
语句:称为回退语句,它使指定设备号的文件指针退回一个记录位置,一般用于顺序文件。它的一般形式为:
BACKSPACE{unit|([UNIT=]unit[,ERR=err][,IOSTAT=iostat])
除了以下几种情况外,使用BACKSPACE语句正好使文件的指针向前移动一条记录:本条记录前再没有记录时文件指针的位置不变;文件指针的位置在一条记录的中间时,文件指针移到本条记录的开始处;本记录的前—记录是文件结束记录时,文件指针移到文件结束记录之前。
使用硬件设备
在Fortran中标准的输入设备是键盘,标准的输出设备是显示器(控制台)。—般的输入输出语句都是针对标准设备进行操作的,如果想对除键盘和显示器以外的其他的物理设备进行读写操作,就应该把物理设备名描述为文件名,这样就可以像操作文件一样对其进行操作,绝大多数设备名没有扩展名。以下是WinNT/9x下的一些设备名。
设备 |
描述 |
CON |
控制台(即屏幕,标准输出设备) |
PRN |
打印机 |
COMl |
1#串行通信口 |
COM2 |
2#串行通信口 |
COM3 |
3#串行通信口 |
COM4 |
4#串行通信口 |
LPTl |
1#并行通信口 |
LPT2 |
2#并行通信口 |
LPT3 |
3#并行通信口 |
LPT4 |
4#并行通信口 |
NUL |
空(NLTLL)设备。放弃输出,不包含任何输入 |
AUX |
1#串行通信口 |
LINE1 |
1#串行通信口 |
USER1 |
标准输出 |
ERRl |
标准错误 |
CONOUT$ |
标准输出 |
CONIN$ |
标准输入 |
输入输出的方式 ,包括 格式化 的方式和 非格式化 的方式。
非格式输入输出 ,包括 直接列表I/O 和 名称列表I/O 。直接列表输出便是之前常看到的 write (*), var1, var2, var3 的形式。这些直接附在write语句后,用逗号分隔的就是直接列表。而直接列表输入以 read (*,*), var1, var2, var3 的形式。括号里的星号分别对应于设备单元(stdin)和输出格式。输入可以用星号(*)表示重复,比如10*3表示输入10个3。用斜杠(/)表示输入流的结束。
名称列表 以 NAMELIST/名称列表组名/变量列表[[,]/组名/变量列表]... 的形式表示。比如名称列表输出的代码可以是:
[plain] view plain格式化输入输出 要更复杂些,下面是 格式化输出 的例子:
[plain] view plain不可重复编辑描述符 可以改变解释重复编辑符的方式,还可以改变完成输入输出的方式。
形式 |
名称 |
用途 |
可否用于输入 |
可否用于输出 |
’ ’或” ” |
撇号编辑 |
传递string到输出单元 |
否 |
是 |
nH |
Hollerith编辑 |
传递下n个字符到输出单元 |
否 |
是 |
Q |
字符计数编辑 |
返回记录中剩余字符的数目 |
是 |
否 |
T,TL,TR |
位置编辑(Tab) |
指定记录的位置 |
是 |
是 |
nX |
位置编辑 |
指定记录的位置 |
是 |
是 |
SP,SS,S |
可选加号的编辑 |
控制加号的输出 |
否 |
是 |
/ |
斜杠编辑 |
指向下一个记录或写记录结束符 |
是 |
是 |
\ |
反斜杠编辑 |
延续相同的记录 |
否 |
是 |
$ |
美元符号编辑 |
延续相同的记录 |
否 |
是 |
: |
格式控制结束 |
如果I/O列表中没有其它记录则结束语句 |
否 |
是 |
kP |
指数比例编辑 |
设置后面的F和E编辑符的指数比例 |
是 |
是 |
BN,BZ |
空格解释 |
指定对数值空格的解释 |
是 |
否 |
格式说明的首字符 |
纵向间隔控制功能 |
常用形式 |
(空格) |
移到下一行开头 |
1X, ’ ’,1H |
0(数字0) |
移到下面第二行开头 |
’0’,1H0 |
1(数字1) |
移到下一页第一行开头 |
’1’,1H1 |
+(加号) |
移到当前行开头 |
’+’,1H+ |
其它字符 |
移到下一行开头 |
(非标准规定) |
要使这些功能在VisualFortran上实现,必须按以下步骤修改默认值:对于输出到终端的情形,在菜单选项中Project -> Setting -> Fortran-> Compatibility选取Enable VMS Compatibility项。对于输出到文件的情形,在打开文件的OPEN语句中加上说明项CARRIAGECONTROL='FORTRAN'。这时每行记录的第一个字符被当作控制符,可能产生输出的数字或字符被吃掉的情形。另外重叠印刷功能仅对于行式打印机有效,对于终端和文件的输出其效果是覆盖。
5、
斜杠(/)编辑符
的作用是结束记录在本行的输出并从下一行开始输出下一个记录。如果有两个连续的斜杠,相当于增加一个空行输出。如果在编辑符的最后出现斜杠,也是再输出一个空行。用n个连续的斜杠,可以达到输出n-1个空行的效果。如WRITE(*,’(I3,I4/I1,I2//3F8.2/)’) I,J,M,N,X,Y,Z 的输出第一行为I,J的值,第二行为M,N的值,第三行为空行,第四行是X,Y,Z的值,第五行为空行。
6、
反斜杠(\)编辑符和美元($)编辑符
的作用相同,都是在输出一个记录行后取消回车符。常用于输出字符串与输入数据显示于屏幕同一行的情形。
例:Write(*,’(”Please Enter Your Age =”,$)’)
Read(*,*) My_age
当屏幕上输出字符串PleaseEnter Your Age =后没有换行,My_age的数值可紧接在=号后输入。
7、
位置编辑符(T,TL,TR)
在用于输出时,指出将要输出到记录上的下一个字符的位置。它们的一般形式为:Tn,TLn,TRn。n是非零正整数。
T指明记录相对于左Tab端的位置,记录上的下一个字符输出第n个字符的位置上。对于行式打印输出,因为记录的第一个字符作为纵向控制符不被打印,所以Tn是定位在打印记录的第n-1个字符的位置上。在这个位置之前若没有字符输出,则填满空格。
TL用于输出时,指明把记录上的下一个字符输出到从当前位置向左移n个字符的位置上。如果左移已到记录的第一列,则不再向左移,即向左移至多回退到第一列。TR用于输出时,指明把记录上的下一个字符传输到从当前位置向右移n个字符的位置上。如WRITE(*,’(TR10,F6.2,TL16,F6.2)’) 4.25, -21.46语句的输出结果是-21.46 4.25。
8、
冒号编辑符
,当I/O列表中没有更多的数据顶时,冒号(:)编辑符使格式控制结束。此编辑将常常用于FORMAT语句中没有要输出的数据项时的输出结束。
9、
P编辑符
设置比例因子以改变小数点位置,它用于实数变量编辑描述符如F、E和G编辑符。其作用范围延续到下一个比例因子的设置处。它的一般形式是:kP。k是一有符号整数以指定小数点向左或向右移几位,k取值范围在-128至127之间。在每一个输入输出语句开始时,这个比例因子被初始化为O。输出时,正k向右移,负k向左移(输入时相反)。比例因子对下面格式编辑符的影响:在用F编辑符输出时,这个要输出的值在显示以前将乘以10
k
。在用E编辑符输出时,这个要输出的值的实数部分在显示以前将乘以10
k
,其指数部分减k。
例:Format Value Output
1PE12.3 -270.139 -2.701E+02
1P,E12.2 -270.139 -2.70E+02
-1PE12.2 -270.139 -0.03E+04
例:dimension a(6)
a=25.;write(*, "(' ',f8.2,2pf8.2,f8.2)") a
其输出是: 25.00 2500.00 2500.00
2500.00 2500.00 2500.00
10、
SP,SS和S编辑符
在数字输出字段中控制着任选加号(+)的打印。SP在其后所有正数值域的位置输出加号,SS为不输出加号,S重新储存SS使其后不输出加号。
下面贴两段格式与I/O列表的关系:
输出格式指定和I/O列表
在输出语句执行时,I/O列表中的每一项都和一个可重复编辑符联系(I/O列表中的复型数据需要两个编辑符),非重复编辑符不和I/O列表中的数据项联系。如果I/O列表包含一个或多个数据项,则在格式指定时至少有一个可重复编辑符。空的编辑指定()只能用在I/O列表没有数据项的情况。一条编辑指定为空的FORMAT()格式WRITE语句输出的是回车换行。
在格式输入输出过程中,格式控制器从左向右扫描格式数据项。下面列出了格式控制器可能碰到的具体情况及相应的解释:
1) 如果I/O列表中出现了可重复编辑符和相应的数据项,该数据项和编辑符是互相联系的,该数据项的输出会在编辑符的格式控制下执行。如果没有相应的数据项格式控制器将中止输出,即多余的编辑符无效。
2) 如果I/O列表中项数多于格式说明中的可重复编辑符个数,即WRITE语句中的输出项表列中还有末输出的元素,而格式说明中的编辑符已用完,则重新使用该格式说明,但从下一行开始产生一个新记录。
3) 如果在格式说明中包含有重复使用的编辑符组,则当格式说明用完后再重新使用时,只有最右面的一个编辑符组(包括其重复系数)和它右面的编辑符被重复使用。
4) 遇格式说明的右括号(即最后面一个括号)或斜杠“/”时,结束本记录的输出,但不意味停止全部输出。只要I/O列表中还有未输出的量,将重复使用格式说明或按斜杠右面的格式说明组织输出。右括号与斜杠的不同是:当扫描到右括号而列表中已无数据项时,输出即告结束。而斜杠只表示结束本行输出,即使此时已无输出变量要输出,输出并未停止,它会重新开始一个新记录,直到遇到右括号或非重复编辑符为止。
5) 如果出现冒号编辑符(中止格式控制)且I/O列表中没有其它项,则格式控制器将中止输入输出。
输入格式指定和I/O列表
一条编辑指定为空的FORMAT()格式READ语句将跳过相邻的下一个记录,除非输入输出设置成ADVANCE=’NO’,这时文件位置将保持不变。记录中的字符如果少于编辑符指定的长度,在右侧会填以空格,除非在OPEN语中指定PAD=’NO’。用户输入的空格的解释取决于空格编辑描符(BN或BZ)的作用或OPEN语句中的BLANK=选项。BN和BZ的优先级比BLANK=选项要高。
总结起来,
输入输出的语句包括
:
语句 |
功能 |
ACCEPT |
输入数据,和格式化顺序READ语句类似 |
BACKSPACE |
定位到文件上一个记录开始处 |
CLOSE |
断开和一个单元(文件和设备)的连接 |
DELETE |
从相关文件中删去一条记录 |
ENDFILE |
写一个文件结束记录 |
INQUIRE |
返回一个单元或外部文件的属性 |
OPEN |
使一个单元号和一个文件或设备相连接 |
|
向星号单元(屏幕)输出数据 |
READ |
从一个文件向I/O列表中的项目输入数据 |
REWIND |
重新定位于文件的开头 |
REWRITE |
覆盖当前记录 |
UNLOCK |
释放先前被READ语句锁定的相关或顺序文件中的一个记录 |
WRITE |
从一个I/O列表中的项目向文件输出数据 |
刚开始看fortran介绍时,它被描述为从语言这一层便支持并行,生成的代码要比c还快。而且工程计算还是应该使用fortran而非c。通过对fortran的大致了解,总体感觉对于向量或矩阵操作,fortran较c要占优。fortran语言比较严谨,语言模块分类也比较丰富,比如C的函数调用可以对应于fortran的子过程、函数,内部过程等。对于文件的操作的方式也很其全。最大的不足可能是编译器的支持并不充分(gcc4.5.2不支持一些fortran标准,而且还有一些bug);以及用户群太小(碰到问题在google上很难找到相应的答案。)
作为史上第一门高级编程语言,了解下fortran总归是有益的,虽然现实中能用到的机会可能不多。但是从其它语言,如perl中也能依稀看到fortran的影子。
当同事发现我在学习fortran时,说道:“你竟然看这么老的语言,涉猎真是广”。其实fortran也一直在与时俱进,在95后,还有03标准和08标准。作为高级语言的史祖,fortran绝对含有巨大的能量。让我联想到生化5里的始祖病毒,呵呵。“涉猎”一词还让我联想到盛大三国杀里的神吕蒙的配音(有点恶心)。