1 Fortran 90 概述 |
图 1显示了Fortran90的主要组成部分[1],[2]。这个“馅饼”的每一片同用来描述与该片相连的特征所需的文法规则大致成比例,因此它是对这些特征的结构复杂性的度量。(但是不能把这些特征看作是概念或文法的复杂性的暗示,也不能看成是实现效果语法复杂性可能或者不可能和其它形式的复杂性相关的指示)
Fortran77
Fortran90是Fortran77 的超集-所有标准的Fortran77程序都是标准的Fortran90 程序,因此Fortran90包含现存的Fortran77并且在计算科学的低级结构上与之完全兼容。
Source form (源格式)
与Fortran77固定的源格式相比,Fortran90增加了另一种没有列依赖的源格式,叫作‘自由’源格式。在自由源格式中注释不必从第一列开始且不必保留第六列作为继续的标志,而是在第一行由一个trailing ampersand作为标志。在这两种源格式中,都可以用‘!’表示行末注释的开始(例如,在行末加上说明),用分号来分开同一行的两个说明。和Fortran77一样,Fortran90对变量,过程等的命名规则是以字母开头,包括字母和数字;另外名字最多可以有31个字符,可以包括下划线‘_’,字符以及大小写字母。
控制结构
Fortran77的缺陷是没有现代控制结构全集(Fortran77只有IF-THEN-ELSE-END IF结构);在Fortran90中通过增加DO-END
DO 和SELECT CASE-END SELECT控制结构弥补了这一点. CASE结构具有如下形式:
SELECT CASE (expression)
CASE (expression)
...
CASE (value_list)
...
...
END SELECT
它提供了并行选择控制,虽然它在语法上没有提供比IF(“顺序的”)更多的功能,但是在适合问题的情况下,CASE比IF更具计算优势,因为只需评价一个表达式。
新的DO结构在计算科学的应用程序中可能相当有用,原因在于为了实现数据并行计算上的优势,大量带索引的do循环将由数组操作代替。因此循环语句使用的重点将从对数组的处理转到非确定的重复操作,比如“read-test-process”和“while”循环。因此Fortran90中增加的两种新的DO结构如下
DO
... IF(逻辑表达式) EXIT ... END DO |
DO WHILE(逻辑表达式)
... END DO |
索引循环也可以用END DO终止,这种情况下不需要循环标号。(在DO结构的三种形式中都允许使用标号。)
数字处理
这将在第三节具体讨论。这一范畴的主要特征是数字表示模块,许多返回有用的模块值的内部函数,数字kind系统,返回kind值的内部函数和一般的操作
数组处理
这将在第四节具体讨论。数组操作是Fortran90中最重要的方面之一。
指针
Fortran90中指针提供了两个重要的功能-动态数据结构和动态数组。后者对计算科学尤为重要,因为它允许数组以适当大小动态分配(和重分配),而且提供了一种当对变量数组序列执行操作时,使得数据转换极小化的方法。
由于指针对优化的不利影响,Fortran90的指针只能指向(a)明确定义为指针的数据对象,(b)动态产生的对象,或(c)另外一个指针。这使得将静态存储器优化技术应用到既没有指针也没有目标属性的数据中成为可能。
这种指针可以应用于运行时才确定大小的数组,例如动态分配数组;这种数组被叫做“定型延期(defered shape)”数组,它的维数被指定,因而是固定的,但是每一维的范围是动态不定的,将在以后动态建立。下面的例子说明了这种动态行为。(“=>”是Fortran90的指针赋值符号,ALLOCATE语句用来说明动态存储器分配。)
REAL,TARGET :: B(100,100) !Array B has the target attribute.
REAL,POINTER :: U(:,:),V(:),W(:,:) !Declaration of 3pointerarrays.
...
U=>B(I:I+2,J:J+2) !U points to a 3x3 section of B.
ALLOCATE (W(M,N)) !Dynamically allocate W,size MxN.
V=>B(:,J) !V points to the Jth column of B.
V=>W(I-1,1:N:2) !V changed to point to (part of)
! the I-1st row of W.
数据结构
虽然数组对计算科学来说也许是最重要的复合数据对象,但是其它异构对象,包括动态链接结构,也是必须的。在Fortran90的术语中,结构是用户定义类型的对象,这下面简要介绍一下,更具体的说明将在第5节和第6节介绍。动态链接结构由基本的递归用户定义类型提供:
下面是能用于doubly-liked表结构的类型的一个例子。递归部分(在本例中是PREVIOUS和NEXT)必须是指针。一般地,被定义类型的组成部分其数量和类型可以是任意的。
TYPE LIST
REAL :: DATA
TYPE(LIST) , POINTER :: PREVIOUS,NEXT
END TYPE LIST
用户定义的类型和操作符
用户定义的类型和操作符,加上模块,赋予了Fortran90一个杰出的数据抽象工具,从而支持面向对象编程。用户定义的类型用TYPE-END TYPE结构来定义,对象说明与基本类型的对象说明类似。如下是类型定义和相应的对象说明的一个简单例子:
TYPE RATIONAL !This define the type RATIONAL.
INTEGER :: NUMERATER
INTEGER :: DENOMINATOR
END TYPE RATIONAL
...
TYPE(RATIONAL) :: X,Y(100,100) !X and Y are variables of type RATIONAL.
( ----------------------------------------------------------------) 这种抽象除了需要类型定义以外,还需要适当的操作符集合的定义。这通过指定用户定义函数的操作符接口来完成。下面的例子说明了如何将操作符“+”附加到两个类型为RATIONAL的对象之间。
INTERFACE OPERATOR (+)
FUNCTION RAT_ADD(X,Y)
TYPE (RATIONAL) :: RAT_ADD
TYPE (RATIONAL) :: X,Y
END FUNCTION RAT_ADD
END INTERFACE
关于用户定义的类型和操作符的更详细的内容将在本章下一节介绍。
过程
Fortran90在ortran77的过程功能上增加了以下新特点:函数结果可以是数组类型的值或是结构类型的值(或二者兼有),过程可以递归,参数可以是可选择的或"intent_in"的(在过程中不能被改变),过程可以在其它程序单元内部定义,等等。
Fortran90的一个重要的新概念是它具有显式过程接口。这意味着一个过程的接口,即哑元或函数结果(如果此过程是一个函数)的数据类型和其它特性,在调用点是已知的。显式接口提供了许多优点和功能。例如,当(且仅当)函数接口在被调用时是显式的情况下,函数结果可以是数组类型的值。过程的接口可以通过为过程提供一个接口块或把过程定义放在调用该过程的程序内部或它所使用的模块中来显式化。
从历史上看, 编程最常出错的地方之一是穿过过程边界的参数数据类型. 这种错误影响结果的正确性且极难调试. 使用显式接口比较简单, 而且完全解决了这个问题; 这可能是接口块最重要的一种实际应用之一.
模块(modules)
Fortran 90 有一种新的编程单元: 模块. 它既不是Fortran 77的一部分, 也不包括在多数Fortran 90之前的编译器中. 由于它缺少实现的历史, 而且它在实现时强迫更复杂的名字管理, 模块引起了一些争议. 然而当这些争议平息下去之后, 模块成为Fortran 90最重要和最有用的特性之一.
不同于主程序和外部子程序, 模块本身不是可执行单元. 然而它们含有可以被可执行程序单元方便地访问和使用的定义. 例如, 一个模块可能含有一个外部过程库所需的接口块, 并且用于使这些库过程在使用它们的应用中显式化. 一个可能的增长趋势是把整个库重新包装到一个模块中, 即在一个模块中存放所有的过程定义(假设这些过程可以用Fortran书写), 这样对一个应用带来双重好处: 不需要接口块就可以使过程接口显式化; 给应用程序开发者提供了一个强有力的名字空间管理工具.
模块相关的数据和过程相关的数据同样重要. 用户类型的定义可以放在一个模块内部是一个应用中的其它程序单元可以访问它, 这确实是一种比包装多数类型定义更好的方法. 任何不同类型(type), kind, 和形状(shape)的数据对象可以在模块中申明, 这样就成为使用该模块的应用程序的全局对象. 它提供了一个可以替代COMMON的非存储器相关的全局数据, 可以用在存储器关联有问题的场合(例如在分布式存储环境中). 模块中的数组可以是可分配的, 于是提供了一种手段, 使动态数组可以被应用程序中的任何程序单元方便地访问.
一个模块可以同时含有数据相关和过程相关的入口. 这种模块的一个典型应用是包装一个数据抽象, 即含有一个类型定义, 用于关联这种类型的定义操作符的接口, 甚至定义这种类型操作的过程. 例如, RATIONAL的类型定义和对RATIONAL"+"的扩充可以被包装到一个模块中:
MODULE RATIONAL_ARITHMETIC
TYPE RATIONAL
INTEGER :: NUMERATOR
INTEGER :: DENOMINATOR
END TYPE RATIONAL
INTERFACE OPERATOR (+)
FUNCTION RAT_ADD(X,Y)
TYPE (RATIONAL) :: RAT_ADD
TYPE (RATIONAL) :: X, Y
END FUNCTION RAT_ADD
END INTERFACE
... !完整的rational 算法工具的其它部分
END MODULE RATIONAL_ARITHMETIC
在下一版中将更详细地介绍模块的这种综合的应用.
输入和输出
Fortran 90 给 Fortran 77 的综合文件联接能力增加了几个选项. 一个重要的例子是ACTION=打开说明, 它允许一个文件以 READ 或 WRITE 或 READWRITE 方式被联接. 不过Fortran 90主要的I/O增加是NAMELIST和non-advancing I/O. NAME-LIST在很多Fortran编译器里面已经被包含很长时间了; 最终标准被引入这里, 从各种现存的版本中规定了NAMELIST的一个标准形式. 除了说明了一个标准NAMELIST, 它包含在Fortran 90中将确保所有的Fortran 90 编译器中支持NAMELIST.
Fortran 90 中的另一个主要的I/O增加是non-advancing I/O, 它提供了一种只读或者写部分记录的功能. 回忆一下在Fortran 77中每一个格式化的串行READ 或 WRITE--nonadvancing 应用的唯一的I/O形式--引起(至少)一个完整记录的读或者写; 也就是说, 在执行一个READ 或 WRITE 语句之后, 文件总是处在记录之间. Non advancing I/O的区别在于, 在传送最后一个字符(实际上在一个记录中的字符之间, 而不是不同记录之间)之后文件保持定位: 一个non-advancing READ 不会"跳"到记录末尾, 一个non-advancing WRITE 不会终止一个记录(即不写记录结束标记). 对这个文件的下一个 READ 或者 WRITE 从上一次操作离开的地方开始. non-advancing I/O的说明是在 READ 或 WRITE 语句的控制列表中包含 ADVANCE="NO". 例如, 下面的non-advancing READ 语句可以用于从输入终端上获得下一个字符:
CHARACTER :: C
...
READ(*,'(A)',ADVANCE='NO',IOSTAT=IOS) C
...
其它Fortran 90 考虑过但是后来没有采纳的输入/输出形式有异步和并行I/O以及各种加密访问.在Fortran 90 中也没有直接的数据库支持.
荒废的特性
Fortran 90 向有计划的语言进化模型的方向迈出了第一步. 和多数的"第一步"一样, 它是一个小的, 试验性的, 而且结果也不明确. 这种思想是最终去除那些随着语言的发展而成为累赘的特性, 但是在实际去除它们之前要官方确认它们是"荒废的". 这是为了使Fortran 领域(a)有机会检查建议和避免错误(b)获得时间有秩序地为改动做好准备. 按照当前的惯例, 在一个Fortran标准版本中被列为荒废的特性, 在下一个版本中是可能被去除的对象.
Fortran 90的下面10个特性被列为荒废的(obsolescent):
Copyright: NPACT |