第四章: 数据结构
本节主要介绍F90的类型说明中新的种别和属性等概念,并且引进派生数据类型等数据结构用基本语句。
4.1.1 类型说明语句
第一章中我们简单地按照F77的传统方法介绍了数据类型和说明语句,这里将介绍具有现代特性的类型说明语句的书写形式。F90程序中的数据都有三个特征:类型、种别、属性,由类型说明语句来定义说明。其一般形式是:
类型说明[(种别说明)][,属性说明表] :: 变量名表[=初值]
例:REAL(KIND=2), DIMENSION(
说明变量X,Y都是实型,种别是2,属性是一维数组。这样X、Y实际上是两个种别参数为2的一维实型数组,各具有10个元素。在某些场合下,种别说明与属性说明可以省略,此时它的一般形式是最基本形式:
类型说明:: 变量名表
下面逐一介绍变量在说明语句中说明类型、种别、属性的方法。
内部类型一共有五种,三种数值型:整数型、实数型、复数型;两种非数值型:逻辑型、字符型。三种数值型变量的定义关键字分别是:INTEGER,REAL,COMPLEX。例:
INTEGER:: X,Y
REAL:: A,B
COMPLEX:: C,D
F77中的隐式说明不利于程序的可读性与可维护性,在F90中不提倡使用。在F90中,每个变量名都应该在说明部分中说明其类型,不应该使用隐式说明、为了抑制隐式说明发生作用,应该在程序说明部分开始就写出语句:
IMIPLlCIT NONE
既声明不使用隐式说明。
初值是指不需要在程序执行中赋值,当程序开始时变量已有初始的量,立即可以参加运算。F90中置初值不需要专门语句,只需在类型说明语句的变量表中,把要置的初值写在指定的变量名后即可。它的形式为:
类型说明:: 变量名1=初值1[,变量名2=初值2,…]
例如,要让实型变量X有初值1.1,Y有初值2.2,Z不置初值,W置初值3.3,写类型说明语句:
REAL:: X=1.1, Y=2.2, Z,
W=4.4
这样,既说明了类型,也为X、Y、W置了初值。变量赋初值后,其值在执行过程中仍可改变。需要注意到,在过程中这种赋初值的方法实际上是对变量赋于了SAVE属性,即当过程被调用以后,变量的新值将被保存下来,过程再次被调用时变量的初值不再是类型说明语句中的初值,而是上次被保留下来的值。例如,如果希望上面的变量X在过程每次被调用时都有相同的初值,则应该写成:
REAL, SAVE :: X, Y=2.2, Z,
W=4.4
X=1.1
在F77中,有一个专门给变量赋初值的说明语句,即DATA语句。它的一般形式为:
DATA 变量名表1/初值表1/[[,]变量名表2/初值表2/…]
变量名表可以是隐DO循环,初值表中的常数之间须用逗号分开,重复的常数表值可以采用如下表示方法:重复次数*常数值。在DATA语句中赋值的变量都有SAVE属性,除非变量名又出现在COMMON语句中,可以通过SAVE语句或类型说明中的SAVE属性对其显式说明。例如,可以对数组作以下的初始化:
DIMENSION A(10,10)
DATA A/100*1.0/ !
按数组变量名统一初始化
DATA A(1,1), A(10,1), A(3,3)
/2*2.5, 2.0/ ! 按数组元素逐个初始化
DATA
((A(I,J),I=1,5,2),J=1,5) /15*1.0/ !
按隐DO循环初始化
对字符串作初始化:
CHARACTER
(LEN=10) name
CHARACTER
CHARACTER*8
help
DATA
name,STARS /'Zhang Fei','****'/
DATA
BELL,TAB,LF,FF /7,9,10,12/ !
用ACSII控制字符码赋于字符变量
DATA help(1:4),help(5:8) /2*'HELP'/ ! 用字符子串分段赋值
对数值型数据作初始化:
INTEGER
n, order, list(100)
REAL
coef(4),eps(2),pi(5),x(5,5)
COMPLEX*8
cstuff
DATA n/0/, order/3/, list/100*0/
DATA coef/1.0,2*3.0,1.0/, eps(1)/.00001/
DATA pi/5*3.14159/
DATA ((x(j,i),i=1,j),j=1,5)/15*1.0/
DATA cstuff/(-1.0,-1.0)/
4.1.2 种别说明
种别是F90的新概念。一个数据,不仅有一个类型,并在同一类型下可分为若干种别,种别值确定了数据的大小范围和精度。有了种别说明后,程序更易于移植。因为在不同的计算机系统上,同一种变量类型可以有不同的精度,因此当程序在另一种机子上运行时可能出现溢出或下溢。规定种别后可以避免这种情况的出现。
我们知道,一个数据通常在内序中占一个存贮单元。对整型数而言,如果该变量在程序中使用值范围很小,则只需半个存贮单元。如果变量的整数变化范围很大,则存贮时有必要占两个内存单元。实型数更复杂,除了存贮的数值范围大小不同外,要求精度也会不同,有的只要8位有效值即满足,有的则可能要24位有效值。这样,它们要求的存贮单元数量不同。为了提高效率,节约内存,按照该变量表达的值范围与表达的精度范围,把同一类划分成几个种别,不同种别分配不同数目的内存单元。
国际标准FORTRAN90版本没有规定每个类型必须有哪些种别,具体的种别划分由FORTRAN软件开发商自行设置。因此程序员在设计变量时,按该变量表达值的范围、精度要求范围,查阅手册,确定合适的种别,在说明语句中加以说明。
种别由种别选择符说明,写在类型关键字后括号内,其关键字是KIND,后跟'='号及种别值。其形式为:类型说明([KIND=]种别值)。
例如要说明变量X是实型,种别值是2,说明语句是:
REAL(KIND=2)::
X
一个变量必有一个种别,如果变量的类型说明语句中没有种别说明符,如:
REAL::
X, Y
则表示变量X,Y的种别缺省,这时采用系统规定的标准值。
Compaq Fortran 提供了如下几类种别值:
整数:有4种,种别值即为字节数n。
种别值n |
取值范围 (-28n-1—28n-1-1) |
|
INTEGER([KIND=]1) 或 INTEGER*1 |
-128—127 |
|
INTEGER([KIND=]2) 或 INTEGER*2 |
-32768—32767 |
|
INTEGER([KIND=]4) 或 INTEGER*4
|
-2147483648—2147483647 |
缺省值 |
INTEGER([KIND=]8) 或 INTEGER*8 |
-9223372036854775808—9223372036854775807 |
仅用于Alpha芯片机型 |
实型数:有3种。F90标准没有规定指数的允许范围和有效位数,。
REAL([KIND=]4) or REAL*4 |
通常实数的范围是10-38—1038之间的7位有效数字 |
缺省值 |
|
REAL([KIND=]8) or REAL*8 |
|
等价于双精度型DOUBLE PRECISION |
|
REAL([KIND=]16) or REAL*16 |
|
仅用于OpenVMS、Tru64 UNIX、Linux操作系统 |
|
复型数:有3种。每种表示整型数据或实型数据的方法都可以用来表示复型数据的实部和虚部。注意简写与完整写法之间的差别。
COMPLEX([KIND=]4) or
COMPLEX*8 |
缺省值 |
COMPLEX([KIND=]8) or
COMPLEX*16 |
等价于双精度复型DOUBLE COMPLEX |
COMPLEX([KIND=]16) or
COMPLEX*32 |
仅用于OpenVMS、Tru64 UNIX、Linux操作系统 |
逻辑型:有4种
LOGICAL([KIND=]1) or
LOGICAL*1 |
|
LOGICAL([KIND=]2) or
LOGICAL*2 |
|
LOGICAL([KIND=]4) or
LOGICAL*4 |
缺省值 |
LOGICAL([KIND=]8) or
LOGICAL*8 |
仅用于Alpha芯片机型 |
字符型:有1种
CHARACTER([KIND=]1)
字节型BYTE:取值为1个字节,等价于INTEGER([KIND=]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位精度、值范围在-1070—+1070之间实型数的种别值为8。但该机型上不能提供满足要求的种别值时,它的返回值是:-1(当精度位数达不到时),-2(当数值范围达不到时),-3(两者都达不到时)。对给定的实型和复型量X,它的精度和范围可通过内部函数PRECISION(X)和RANGE(X)查出。
SELECTED_INT_KIND([m]):该函数返回整型变量对所取的值范围恰当的种别值。m指明值的范围是-10m—+10m。
可以用SELECTED_REAL_KIND或SELECTED_INT_KIND定义一个PARAMETER常数以备后用,例如下面的语句定义了有9位数的整型数。
INTEGER,
PARAMETER :: MY_INT_KIND = SELECTED_INT_KIND(9)
INTEGER(MY_INT_KIND)
:: HILL
程序中的常数如要标明种别,方法有二。若是数值型常数或逻辑型常数则用后辍法,即后加一下划线,再跟种别值。当实数型数据的指数字母是D时,禁止说明种别值。如果复型数据的实部和虚部都是整数,则它的精度和范围与缺省的实型相同。如果两部分都是实型,则它的精度和范围按如下的方法确定:两部分有相同的种别,为该种别,两部分中有不同的种别,则由较大的种别值确定。例如:
21_2+7.6_4 表示整型种别为2的数21与实型种别为4的数7.6相加。
3.8E-5_4
0.87D-16 禁止说明种别值
(4.7_8,5) 复型数据表示用括号,逗号分开前面的实部(种别值为8的实数)和后面的虚部(缺省种别值的整数)。
.FALSE._4 表示逻辑型,其常数值是假,种别值是4。
例:用语句:
INTEGER,PARAMETER
:: LONG=SELECTED_REAL_KIND(9,99)
REAL
:: A=2.8_LONG, B=1.23456789E60_LONG
来保证常数有需要的9位有效数字和-10-99—1099的指数范围。PRECISION(A)和RANGE(A)的返回值应是9和99。
若是字符型常数,则用前辍法,把种别值列在字符常数之前,其间用下划线连接。例如:
5_‘αβγ’ 表示希腊字符串αβγ的种别值是5。
6_‘计算数学’ 表示汉字字符串‘计算数学’的种别值是6。
这里假定该机系统支持希腊字字母与汉字,并已规定它们的种别参数是5和6。对Compaq Fortran,只有一种字符型,因此上面的字符常数应写成:1_‘计算数学’, 1_‘αβγ’,或:‘计算数学’, ‘αβγ’。字符串的字符不只限于Fortran字符集内,处理系统支持的图形符号也是允许的。
在F90中,还可以根据需要定义二进制、八进制和十六进制正整数常量。二进制常量的表示方法是以字母B开头,后跟定界符括起来的数字串,定界符可以是撇号或括号,数字是0或1,如:B’01011’,B(01011)。八进制常量的表示方法是以字母O开头,后跟定界符括起来的数字串,数字范围是0至7,如:O’10472’。十六进制常量的表示方法是以字母Z开头,后跟定界符括起来的数字或字母串,数字范围是0至9,字母范围为A至F,如:Z’18E2D’。但要注意,整数的这些形式,仅限于出现在DATA赋值语句中。
在Compaq Fortran中,还可以这样定义非十进制数:数字#数字串,最前面的数字表示进制,省略式表示十六进制。如:
2#01011011 -> 二进制
8#43051472 -> 八进制
#A92D80EF -> 十六进制
4.1.3 属性说明
说明语句除说明对象的类型、种别外,还可说明对象的属性。一个对象被说明具有某一属性时,就使该对象具有某种附加功能、特殊的使用方式与适用范围。一个被说明对象可以没有附加的属性说明,此时它只是最基本的变量,与F77中的变量相同。它也可以有多个属性说明,分别对被说明对象附加各件功能,规定它在各种场合下的使用方式。每种属性说明都有专门的关键字,各属性关键字间用逗号分开,全部属性关键字写在说明语句种别说明符之后,双分隔号::之前,各属性关键字之间次序任意。属性不仅用于说明数据,还用于说明过程。
属性说明关键字有很多,将在有关章节中详细说明。一般来说,数据属性描述了一个对象是如何在程序中被应用的,可以使用一个或多个语句来规定某个数据对象的属性。Visual Fortran的数据属性如下表所示。
属性关键字 |
描述 |
适用范围 |
ALLOCATABLE |
说明动态数组 |
数组 |
AUTOMATIC |
声明变量在堆栈中而不是在内存中 |
变量 |
DIMENSION |
说明数组 |
数组变量 |
EXTERNAL |
声明外部函数的名称 |
过程 |
INTENT |
说明过程哑元的用意 |
过程哑元 |
INTRINSIC |
声明一个内部函数 |
过程 |
OPTIONAL |
允许过程被调用时省略哑元 |
过程哑元 |
PARAMETER |
声明常量 |
常量 |
POINTER |
声明数据对象为指针 |
变量 |
PRIVATE |
限制模块中的实体访问于本块内 |
常量、变量或模块 |
PUBLIC |
允许模块中的实体被外部使用 |
常量、变量或模块 |
SAVE |
保存过程执行后其中的变量值 |
变量或公共块 |
STATIC |
说明变量为静态存储 |
变量 |
TARGET |
声明变量为目标 |
变量 |
VOLATILE |
声明对象为完全不可预测并在编译时无优化 |
数据对象或公共块 |
PARAMETER属性也称常数名属性。被说明对象一旦附加了PARAMETER属性,就不再是变量名,而是一个常数的名字,它的形式虽与变量名形式一样,但在程序中不能改变值,只能当常数使用。例如:
INTEGER,PARAMETER :: K=20
REAL(8),PARAMETER
:: PI=3.141592654, K_PAI=K*PI, Light_Speed=2.99654E10
常数名被说明后,在程序中就不可再更改值,如要更改,则系统提示出错信息。这一性质,有助于防止程序中误改不可改的常数。使用常数名可以加强可读性,也有助于程序维护。设原编程序是解四阶方程以后要扩充为能解五阶方程,修改时必须把所有反映阶数,写在程序各处的4改成5,这就难免修改时有逃漏,甚至把不该改的4也误改为5,造成程序混乱。使用常数名就可避免这种维护上的困难,当编四阶方程解的程序时,先定义Order是整型数4的常数名;
INTEGER,
PARAMETER :: Order=4
在程序中所有规定阶数4的场合都不写4而用常数名Order代替,以后只要把Order由4改为5即可。
说明一个符号名是数组名,只要在说明语句中附加数组属性关键字。数组属性关键字是:DIMENSION(数组形状说明)。
括号内数组形状说明规定数组有几维,以及每维下标的变化界限,这将在下一章中详述。例如:
INTEGER(KIND=2),DIMENSION(-2:8)
:: X
说明了X是种别为2的整型一维数组名,数组下标以-2为下界,8为上界,共有11个元素。