Fortran95第5章-准备数据.docx_第1页
Fortran95第5章-准备数据.docx_第2页
Fortran95第5章-准备数据.docx_第3页
Fortran95第5章-准备数据.docx_第4页
Fortran95第5章-准备数据.docx_第5页
已阅读5页,还剩29页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第5章 准备数据从本章开始,我们将赋予语言实质性的语义,也就是规定上章所描述的语言的每一个细节所具有的涵义。这种涵义与其说是我们对于一种语言细节的定义,不如说是算法的要求,要求语言具有足够多的细节,用来表达在算法当中有可能出现的精细情节。对于任何的问题,站在计算机的角度来看,总是可以把它抽象为如下图所示的结构:输入数据 计算过程输出数据因此要准备通过计算来解决一个问题,首先要作到的是把该问题所涉及到的数据整理好,也就是列出所有的数据,然后根据数据的数学属性进行分类,这个分类的过程就是对数据施加足够的标记的过程,将来把这些数据输入到计算机,计算机将能够依据这些标记,辨识出数据所应该具有的数学属性,从而施加相应的合法数学运算。所以作为向计算机描述计算问题的FORTRAN语言,它首先要作到的是约定如何给数据施加足够详细的标记。对这个标记过程的第一个要求是保证准确性,也就是说这个语言的标记系统必须正确地反映真实世界的问题里面,数据所具有的数学属性,因此这个标记系统必然是与数据的数学分类结构保持一致的。从数学的观点来看,世界上的所有数据,总是可以被表示为整数,实数,复数等等基本的数据种类,因此本章的内容就是讨论: FORTRAN语言如何把数据归结为一些基本数据类型; 然后为了足够详尽地描述每一个数据类型的属性,FORTRAN是如何施加相应的标记的; FORTRAN语言对于这些标记(语法形式)所约定的语义是什么。然后我们就可以知道,要想用FORTRAN来描述一个问题的算法,并进而以问题算法的FORTRAN语言版本为媒介,通过计算机来得到计算结果,第一个步骤,就是准备好数据的FORTRAN描述。5.1 数据是什么在上一章里,据称计算机能够使用语言,而且是非常类似于人类的语言,至少从形式上看很象,这难免会令某些人(特别是看过KUBRICK的影片2001: A Space Odyssey的观众们)感到恐惧:)别怕!且先不讨论FORTRAN作为语言是否具有与人类语言等价的表达能力,至少从自然语言的语义学的角度来看,FORTRAN说出来的话其实是绝对空洞的,因为FORTRAN语言的全部语义基础就只是数据,而数据对机器而言,只是意味着经过编码的符号。一台计算机其实是由以下6个部分组成: 数据-也就是基本数据元素以及数据结构; 基本操作-也就是一个对上述数据进行操作的基本操作集; 顺序控制-也就是一个控制针对数据的基本操作执行的时间顺序的机制; 数据存取-也就是一个如何给操作提供数据的机制; 存储管理-也就是一个数据存储分配机制; 操作环境-也就是一个支持程序和外部环境进行数据通讯的机制。因此一台计算机 在程序的使用者看来,就是给它输入数据,它再给你加工过的结果数据; 在程序的编制者看来,就是把对数据的处理过程表示为计算机有限的一系列基本操作(指令)的集合,使得计算机能够处理相应的数据;因此,计算机的一切可以说都是围绕着数据-如何表达数据,如何处理数据。而计算机语言所要具备的两个部分的功能,首先就是完备的描述数据的性质,然后就是描述数据的处理过程。那么,什么是数据呢? 数据就是符号化了的信息!对于计算机来说,任何信息都只有表示为符号,才能被认可;反过来说,计算机只能输入符号,而不会也不能理解符号的含义,它的能力只是体现在按照既定规则来处理符号。然后,就是给出数据的表示,即如何用符号来明确而无歧义地表达数据。要使得符号具备数据的含义,需要经过这么几个步骤: 处理符号的第一步:给符号分类,并给出描述符号性质的方法。这个分类是人作为设计者给符号规定语义的第一步,因为对于人来说,数据不能只是符号,而是具有来自真实世界的语义,设计者正是根据符号的这种语义,制定相应的处理符号的规则,而计算机要想能够正确地处理符号,基本的前提,就是每当引入一个数据,都得由人向机器声明这个数据是什么类型,这个数据具备什么性质,而且假设计算机已经被引入处理该种数据类型的规则。 处理符号的第二步:区分常量与变量。这一对范畴反映了最基本的人类抽象能力,也正是人类思维的基本模式。要想让机器模拟这种能力,最简单的做法就是:任何时候都必须首先声明,哪些符号表示常量,哪些符号表示变量,而变量相应的取值范围必须规定好,也就是说必须描述其取值为具有何种属性的常量值的集合;或至少已经被机器默认。 处理符号的第三步:给每一类数据规定相应的合法运算。对于一种数据可以执行什么样的运算,来自于语言设计者对数据语义的规定,只有当运算被表示为相应的机器指令或指令集合,这时在表面看来,机器才开始真正“理解”了数据的“涵义”。因此可以说,数据的定义构成了计算机的“灵魂”。按照上面讨论的步骤,说明一个数据类型包括四个方面: 命名的语法 取值的范围与属性说明 该数据类型的常量的表示方法 定义合法的运算因此相应的一个数据类型的四个要素就是:(1) 名字; (2) 值的集合;(3) 表示值(相应的常量)的方法;(4) 操作值的运算的集合。对于这四个要素,FORTRAN一方面要约定它们的语法形式,从而可以构成符号描述的唯一性标记,保证相应的描述语句能够被FORTRAN编译系统无歧义的辨识,另一方面就是要给出这些语法形式所对应的含义。5.2 用FORTRAN来说明数据的性质真实世界的数据显然是多种多样的,几匹马,轴承的内径,圆周长与直径的比值,电子的波函数,非各向同性电介质的电极化率,10个被试每日的最高血压等等,这些数据都具有非常不同的形式与性质,如果我们每针对一种数据形式,都把它定义为某一种新的数据类型,则肯定是烦不胜举,因此合理的途径是找到一种统一的数据描述方式,而对于科学计算问题来说,自然的数据分类方式是数学对数值数据的分类,再加上非数值型数据,会是非常适合于科学计算的数据表达方式。当然,如果是以描述其他类型的问题为目的,如事务处理,符号演算等,则选用另外的数据分类方式会更有效。至少从数学的观点来看,我们常常需要处理的数据,都可以表示为一些基本数据类型的组合,例如我们知道向量实际上就是一个数组,数组的每个元素为标量,因此应用数组这种结构,就可以自然地表示向量,另外复数尽管也可表示为一个二元数组,但是这种二元数组的乘法不同于二维向量,因此为了避免这种歧义, FORTRAN把复数当成一个基本数据类型。而几种基本标量里面,整数和实数都同样必须构成基本的数据类型。由此可以建立FORTRAN的对数据的类似描述。由于真实世界问题的要求的不同,对数据的描述也有程度不等的情况,最基本的情况就是直接说明数据的类型以及其他属性,又由于数据表示的实现具有一个重要的参数,即存储空间,所以当问题要求的数据,不能满足于默认的存储空间的时候,这时,就需要进一步给出数据的种别参数,这是更加详细的数据描述。如果在真实世界问题当中出现的的数据对象,干脆不符合已有的固有数据类型以及数组的定义,这时就还需要根据用户的要求构造一个依赖于问题的特定的数据结构,这就是数据描述时会遇到的第三种情况。对于这三种情况,FORTRAN的解决方式如下:第一种情况:确定数据的类型以及相应的可能具有的属性。首先,FORTRAN所能辨识的数据类型首先分为两大类: 固有数据类型 派生数据类型根据语义上的基本差别,数据首先具有一些基本的类型,这些基本类型一般是和构成真实世界里的信息的那些基本元素相对应,比方说数字,字符等。然后其他情况下遇到的数据都可以由这些基本数据类型组合得到。不过一种语言具体的规定哪些基本的数据类型,往往受到该种语言主要应用的场合的影响,由于FORTRAN主要用来进行科学计算,因此它所定义的基本数据类型,正是与我们在科学计算问题当中遇到的数据类型相契合的。 所谓固有类型,是FORTRAN语言所定义的最基本的数据类型,每一种固有类型是和该种数据类型相应的各种运算一起隐式定义的,也就是说一旦声明引入某种固有数据类型,则系统总是默认为对它进行相应的运算是合法的,并且总是可访问的。这样就做到了每种数据类型都和它相应的运算捆绑在一起,使得问题的描述非常自然。 固有类型包括五种:整型(INTEGER)、实型(REAL)、复型(COMPLEX)、逻辑型(LOGICAL)和字符型(CHARACTER)。这个分类完全是遵循数据的数学分类,即整型指整数,实型指实数,复型指复数,逻辑型指逻辑值,字符型则是语言的基本元素。这样就可以把基本的数学语言一一对应的直接翻译为FORTRAN语言。 所谓派生类型是由用户定义的,非隐式定义的类型,只要用一个类型定义来声明其成员是何种固有类型,或者是何种其它已经定义过的派生类型,就能够被FORTRAN认可为一种数据类型。 由于派生数据类型正是由固有数据类型充当成员而构成的,因此在结构关系上,可以把固有数据类型看成原子,而把派生数据类型看成分子。由于语言的根本目的就是为描述算法服务的,因此从这个角度出发,派生数据类型本质上体现了非常重要的数据抽象与数组合的思想,由于我们需要运用语言来描述的问题是开放性,我们很难划定需要FORTRAN来描述的问题的范围,因此通过构造派生数据类型,使得我们可以很自然而简洁地建立新的数据类型。这是FORTRAN在FORTRAN77标准之后的一个重大进步。派生类型数据最重要的用途就是扩充了数组这种重要的数据结构,由于数组在科学计算领域,是一种极端重要的数据结构类型,FORTRAN除了能够直接描述数组,同时还能描述更为广泛的派生数据类型,也就可以直接对一个数据集合的各个成员同时施加运算,拥有了这种自然的数据类型,就避免了象FORTRAN的早期版本那样,需要通过特别设计的算法来实现这种运算。所谓固有数据类型的固有,对于FORTRAN来说,就是为每一种固有数据类型规定了它的存储模式。在FORTRAN77及其之前的标准里,整型,实型,逻辑型数据都是使用了一个数值存储单元,而复型和双精度数据则使用了两个数值存储单元,字符型数据使用一个字符存储单元。由于存储模式是非常底层的语言实现结构,因此FORTRAN后续的标准要想保持兼容,只有继承这个约定。因此在FORTRAN90与95当中,默认的整型,实型,逻辑型数据都是使用了一个数值存储单元,而默认的复型和双精度数据则使用了两个数值存储单元,默认的字符型数据使用一个字符存储单元。而作为语言的一个发展,在FORTRAN90之后的标准里,开始允许在一个程序单元内,由用户定义特定的不依赖于固有数据存储模式的数据类型,这就是第6章的派生数据类型。建立一种数据类型,最大的好处就是可以把相关的运算和数据捆绑在一起,对于一个特定问题当中的数据对象,是否应该被明确地看成数据类型,属于语言设计的权宜,因为建立一种数据类型所能带来的好处可以用算法来补偿,而FORTRAN77之后的版本的选择是增加派生数据类型,这样使得我们可以在进行科学计算时,有更为自然的描述方式。数据类型的全部分类总结如下:固有数据类型 数值型数据 整型 实型 复型 非数值型数据 逻辑型 字符型 派生数据类型就数据的属性而言,类型当然是最重要的属性了。在指定类型之后,紧接着的就是根据实际情况,看需要描述的数据是否还具有其他需要说明的属性。对于数组来说,具有一个基本的属性,就是数组的大小,相应的就是如何指定数组的存储空间的大小的问题。由于FORTRAN具备可分配数组与指针的功能,因此在程序开头并不一定需要指定数组的大小(维度),在程序执行过程当中,数组的大小会作为输入或计算结果被读入,这个指标可以针对具体的问题的要求,以及运行的状况而定。在FORTRAN还不具备这种动态功能的时候,就需要在数组声明里指定数组的维度,而在事先又很难准确预料程序运行过程当中对数组储存空间的要求,因此如果指定的数组过大,就会大量地浪费当时非常宝贵的内存空间,而如果指定的数据组过小,则肯定会在程序运行过程当中导致错误。所以为了避免这些问题,现在一般不会在数据声明的时候精确指定数组大小,而是把数组处理成一个动态对象,从而有效地回避了这个问题。数据的一个重要属性,就是它的可访问性。在FORTRAN语言里,模块提供了对数据的访问控制。任何数据对象只要想把自己局限在模块内使用,模块就能够提供足够的保护,使得外部程序无法访问该数据对象。模块的这个功能使得FORTRAN成为一种安全可靠的语言。是否打开数据的其他许多具体的属性,取决于具体的数据应用环境,因此要讨论数据的每一种属性,在这里不太现实,我们只有等到下面具体地说明每一种声明语句时再具体说明,因为属性指定总是在出现在声明语句当中。第二种情况:指定固有数据类型的种别参数。对于计算机来说,在确定数据的类型,从而可以引导到相应的运算之后,进一步就需要为数据在内存指定存储位置和存储空间,实际上对于冯纽曼型计算机来说,这个步骤是非常关键的,因为冯纽曼型计算机的要点,就是硬件之外的一切,都必须表示为数据,都必须存储在内存当中,然后在程序的运行当中,随时与CPU进行通讯,因此在程序的开头就明确数据在内存当中的位置与每个数据所占有空间的大小,是保证程序运行非常基本的要求。 用来指定程序当中需要使用的每一种固有数据类型所要求占据的内存空间大小的属性由种别参数表示。给这个变量(参数)指定一个数值,就可以说明数据所需要的存储空间的大小,也就是程序允许的数值数据的位数和字符串的字符数目。 KIND(种类种别参数)分别说明整数类型的十进指数范围,实数类型和复数类型的十进制精度和指数范围,字符类型和逻辑类型的表示方法。 LEN(长度种别参数)对字符类型规定了字符的个数。【例5-1】 REAL(KIND3):ABC,X,LONG CHARACTER(LEN40,KINDGREECE):NAME具体的种别参数的约定是与语言的具体实现相关的,因此具体的取值还是得参考编译器的文档。 如果没有声明数据的种别,那么程序就会采用默认的参数,由于FORTRAN的早期版本没有引入种别参数,因此对于有不同精度要求的实型变量,直接采用了两种不同的数据类型,这就是REAL和DOUBLE PRECISION,从FORTRAN90以来的版本里,通过引入种别参数,对种别参数的不同取值,就足够表达不同的精度,而同时为了保证和早期版本的兼容,单独的数据类型声明DOUBLE PRECISION还是被保存下来了,这样一来,就产生了一个有一定任意性的后果,即新的语言标准对不同精度的实型数据,可以通过使用同一个数据类型的不同的种别参数值来表示,而同时用DOUBLE PRECISION作为数据声明也是有效的,这样就保证了源码向前的兼容性,却不具备向后的兼容性。 对于在指定种别参数的数值时,一般是以字为单位,这样对于字长不同的机器而言,相互之间就会出现程序移植的困难,下面分情况予以说明: 实型-由于DOUBLE PRECISION是属于老式标准的遗留物,因此使用DOUBLE PRECISION作为数据声明的程序就不具备良好的可移植性,因为所谓双精度是针对具体的机器的字长而言的,对于32位的机器,双精度就是64位,而对于64位机器,双精度就意味着128位,这样在不同字长的机器环境里,双精度就具有不同的位数,使得程序无法在不同字长的平台之间进行直接的移植。因此在这种情况下,最好还是统一使用REAL的种别参数来表达算法所要求的实数精度。可以说种别参数一劳永逸地解决了实数精度的可移植性问题。 复型-由于所谓复型本质上就是由两个实数表达的,因此按道理复型同样应该能够具有表达多种精度的能力,而实际上早期的版本在这方面是有欠缺的,不过随着FORTRAN90引入种别参数,就可以在COMPLEX的声明语句里通过运用种别参数来实现多种精度的表达,对于任何FORTRAN的实现,至少能表达两种精度,而一般来说是多于两种的。 字符型-对于字符,一般的机器都是用单字节8bits来表示一个字符,这样就可以总共表示28=256个不同的字符,这对于任何以字母写出来的语言都是足够的了,不过对于汉语,日语这样一些语言就不够用了,一般得需要双字节,即16bits,这样就可以表达216个字符。因此字符型数据同样需要附加种别参数,以便除了使用默认的基本字符之外,还可以使用辅助字符集里的字符,从而实现程序的本地化。不过某个具体的编译器是否支持双字节字符,必须参考相应的手册。因为FORTRAN 95标准也没有强制要求FORTRAN的任何实现都必须支持双字节字符。 逻辑型-由于一切逻辑型数据都只有两个值,因此如何确定逻辑型数据的存储空间应该是非常好办的,不过不幸的是,FORTRAN的早期版本规定逻辑型数据使用和实型数据一样大小的机器存储单位,这样当机器的字长很大时,就会非常的浪费机器的存储空间。因此到了FORTRAN90和FORTRAN 95,除了作为默认的情形,和旧的语言标准保持兼容之外,还可以通过指定种别参数,使得逻辑型数据的存储空间大小只有一个字,甚至一个bit。当然具体的使用方法需要参考相应编译器的说明。 整型-显然在程序应用当中会出现几乎任何大小的整型数据,因此无法在语言标准里面统一的规定整型数据的存储空间大小,这就同样需要依靠种别参数来指定应该给具体问题当中的整型数据确定多大的存储空间。具体地指定方式属于编译器设计者的选择,需要参考相应编译器的语言说明。第三种情况:派生数据类型。数据的本义就是对真实世界里的事物的描述。这种描述可以是简单的,如一个标量,也可以是复杂的,如一个张量,对于更复杂的对象,在自然语言里有一种自然的描述方法,就是使用一系列的词汇,每个词汇都是对象在某个方面的属性的度量;在计算机语言里,可以采用类似的解决方案,即把对象的每一个需要描述的性质用一个适当的基本数据类型来表示,这样用一组基本数据类型就可以描述该对象。而这一组数据可以看成是一个新的数据类型,表示了一个变量。这样构造出来的数据类型称为派生数据类型,和固有数据类型一样,在声明派生数据类型时,需要给出名称,描述它的每一个元素的固有数据类型以及相应属性和种别参数(如果非默认的话),当然也需要适当地定义其运算。既然这种派生数据类型是由一组数组成,就会出现两种情况: 这组数据都是属于一个数据类型这样构成的派生数据类型就是数组,显然对于数组的元素的描述就可以统一进行。具体的用法会在后面专门说明。 这组数据的各个元素属于不同的数据类型这样构成的派生数据类型称为结构,这时就需要对每个数据元素进行分别的说明, 即每一个元素的数据类型,可能有的属性,种别参数等等。上面对派生数据类型的描述实际上是递归式的,即一个派生数据类型的元素同样可以是另一种派生数据类型,而没有限定必须是固有数据类型。【例5-2】 下面是一个典型的派生数据类型。 TYPE SAMPLE REAL CURRENT COMPLEX (KIND = QUAD) PHASE CHARACTER (LEN = 50) SOURCE END TYPE SAMPLE TYPE (SAMPLE) SI401,SI402,SI403,SI404在上面的例子里,首先定义了一个名称为SAMPLE的数据类型,每一个SAMPLE类型的数据由三个分量组成,它们的名称分别为CURRENT,PHASE,SOURCE,分别属于实型,复型和字符型,其中复型和字符型还分别说明了种别参数和字符长度属性,然后给出了程序当中需要使用的四个属于该种数据类型的变量:SI401,SI402,SI403,SI404。上面例子当中派生数据类型的定义,以TYPE开始,以END TYPE结束。5.3数据不同种类的存储模式对于计算机来说,数据分类的第一个反应就是针对不同类型的数据约定不同的存储模式。由于存储模式的规定涉及到编译环境的设置,因此存储模式的约定是与系统环境相关的,鉴于Compaq Visual Fortran的广泛应用,本节特别针对Compaq Visual Fortran系统而言的说明了数据的各种存储模式。下表5-1列出了Compaq Visual Fortran所有的固有数据类型的存储空间要求,和相应的能够在这个空间里表达的数据规模。表5-1 固有数据类型的存储模式:数据类型单位存储空间能表示的数据规模BYTEINTEGER(1) 1 byte (8 bits) BYTE表示等价于INTEGER(1)的带符号的整型数据类型。 INTEGER 参见INTEGER(2), INTEGER(4), 以及 INTEGER(8). 带符号的整型数据, 包括INTEGER(2), INTEGER(4), or INTEGER(8)。数据规模由编译器选项/integer_size:nn 控制。默认的规模控制选项为/integer_size:32 (等价于INTEGER(4)。INTEGER(1)1 byte (8 bits)从-128到127带符号的整数。INTEGER(2)2 bytes (16 bits)从-32,768到32,767带符号的整数。INTEGER(4) 4 bytes (32 bits) 从-2,147,483,648到2,147,483,647带符号的整型数据。INTEGER(8) 8 bytes (64 bits) 从-9,223,372,036,854,775,808到9,223,372,036,854,775,807带符号的整型数据。 REAL(4)REAL 4 bytes (32 bits) 从1.17549435E-38到 3.40282347E38的按照IEEE S_floating格式的单精度实型浮点值。在1.17549429E-38和1.40129846E-45之间的值是非常态的。REAL(8)DOUBLE PRECISION8 bytes (64 bits)从2.2250738585072013D-308到1.7976931348623158D308的按照IEEE T_floating格式的双精度实型浮点值。在2.2250738585072008D-308和4.94065645841246544D-324之间的值是非常态的。COMPLEX(4)COMPLEX8 bytes (64 bits)由一对从1.17549435E-38到 3.40282347E38的按照IEEE S_floating格式的单精度实型浮点值组成的单精度复型浮点值。在1.17549429E-38和1.40129846E-45之间的值是非常态的。COMPLEX(8)DOUBLE COMPLEX16 bytes (128 bits)由一对从2.2250738585072013D-308到1.7976931348623158D308的按照IEEE T_floating格式的双精度实型浮点值组成的双精度复型浮点值。在2.2250738585072008D-308和4.94065645841246544D-324之间的值是非常态的。LOGICAL参见LOGICAL(2), LOGICAL(4), 以及LOGICAL(8).逻辑型值, 包括LOGICAL(2), LOGICAL(4),以及 LOGICAL(8). 数据规模由编译器选项/integer_size:nn 控制。默认的规模控制选项为/integer_size:32 (等价于LOGICAL(4)。LOGICAL(1)1 byte (8 bits)逻辑型值.TRUE. 或.FALSE.LOGICAL(2) 2 bytes (16 bits)逻辑型值.TRUE. 或.FALSE.LOGICAL(4) 4 bytes (32 bits)逻辑型值.TRUE. 或.FALSE.LOGICAL(8) 8 bytes (64 bits)逻辑型值.TRUE. 或.FALSE.CHARACTER每个字符1 byte (8 bits) 根据约定的字符编码表示的字符数据,通过字符数据的声明形式:CHARACTER(LEN=n)或 CHARACTER*n,其中n 表示byte数,来表示数据规模。 HOLLERITH每个Hollerith 字符1 byte (8 bits) Hollerith 常量。 表中的INTEGER(4)等价于INTEGER(KIND=4)以及INTEGER*4.5.4 FORTRAN数据类型描述的四个基本属性一个数据如何才是被完备描述了,以及FORTRAN所要求的描述一个数据的要素是哪些,是一个问题的两面。这个问题对于程序的作者是很重要的,因为FORTRAN现在允许用户自己定义合乎自己需要的派生数据类型,这就要求我们知道一个派生数据类型的定义是否完备。FORTRAN的数据类型必须包含如下四个部分: 数据类型的名称 数据取值的集合 可以施加于数据的值的运算 该数据类型的常量的表示形式5.4.1 数据类型的名称要能够说明数据的类型所属,首先每种数据类型本身得有个名称,才能在描述数据对象的时候,说某个数据对象属于某个数据类型。固有数据类型就只有5种,它们的名称:INTEGER,REAL,COMPLEX,LOGICAL,CHARACTER是语言标准的规定。但派生数据类型则完全是程序作者自定义的,因此必须由作者使用TYPE来给出其构造的派生数据类型的名称,也就是说只要一个数据或一个变量的取值符合TYPE与END TYPE之间的定义,就被该程序单元识别为属于该数据类型,就可以应用相应的运算。如果一个程序单元里出现的数据不能被识别为该程序单元的数据声明里的诸种类型,那么FORTRAN还会尝试运用一种方式来试图确定它的数据类型,就是根据数据名称的第一个字符来进行判别,这种方式属于FORTRAN的古老传统,因为早期FORTRAN所处理的数据类型比较单纯,顾可以如此简化处理,FORTRAN90与FORTRAN 95都继承了这点。5.4.2 数据取值的集合对于每种数据类型,存在一个允许的具体取值的集合。而属于该数据类型的变量的取值范围必定是在这个集合内。表面看起来数据类型的取值集合都是明确的数学意义,但是由于本质上计算机的任何具体取值,都必须是有限的,因此数据类型表面的所谓数学涵义并不是很符合实际的。固然整型必定是取整数值,但只能取有限的整数值,而且这个值还有上限,即一个整型数据能够取多大的整数不仅在机器的硬件方面有制约,在语言的具体实现上也进行了约束。同样,对于实型来说,更不可能就是和实数集合等价,实型数据的具体取值同样只能取可有限表示的实数,即有限小数。至于某些软件(如MATHEMATICA)声称可以精确的引用无理常数,例如欧拉常数,实际上是使用了一个收敛级数来表达无理常数,只有当用户指定有理表示的精度后,计算机才对级数做相应的截断,给出相应精度的有理表示,而并不是说该常数的无限位表示完全存储在计算机里面。 逻辑型数据能够取得的值的个数是完全确定的,即仅有真和假两个值(即两个元素)。由此可见所有逻辑型变量都是某种判断,而对该判断的取值只能或真或假,这里实际上就规定了FORTRAN语言只能用来表述满足排中律的数学。 对于整型和实型来说,既然只可能取有限值,那么剩下的问题就是如何给某个具体取值分配存储空间了,由于程序单元是根据数据声明当中对数据取值的规划来确定如何为数值分配存储空间的, 因此对于具有极大处理能力的现代计算机而言,最好针对数值占用空间的大小进行分级,以做到在保证数值表达需求的前提下,尽量避免存储空间的浪费。FORTRAN为了给数值占用空间的大小分级,引入了种别参数(K1ND),使得在数据声明的时候,就可以一致地规定该类数据在表达时,允许占用空间的大小。例如整型除了默认表示之外,还可以标志以种别参数“SHORT”,这个参数意味着在整型的默认取值范围了划出了一个子集,只要是属于这个子集的数据,允许系统给它分配较为小的,但更为合算的存储空间。对于实型来所,则完全可以根据算法的需要,在开始的数据声明里,就给程序单元里可能出现的数据划出三流九等,使得程序对存储空间的占用更为合理。当然FORTRAN语言标准只是规定了实型必须至少在默认精度种别之外,还需要有一个双精度种别,而在FORTRAN的各种编译实现里,还可以规定更多的精度种别。 对于字符型数据来说,它的存储空间完全和字符串长度成正比,因此只要直接规定字符串的字符个数,就可以一致地得到其存储空间分配标准。 至于复型和派生类型,则完全以其他数据类型作为成员,自身没有什么特别的规定,因此也就没有独特的针对这两种数据类型的种别参数。显然,FORTRAN通过运用种别参数来明确地规定数据的表示,使得Fortran的标准化程度得到了进一步提高,从而提高了程序的可移植性。5.4.3 数据类型的合法运算允许施加于数据的运算同样可以分为两类,即与固有数据类型相应的固有运算,还有自定义运算。由于在FORTRAN里面,运算的主要语法功能是构成表达式,因此详细的关于运算的讨论,参见有关表达式的章节。 1. 固有运算固有运算就是固有数据类型在FORTRAN里面指定了表示符从而可以直接引用的那些固有运算,根据运算所能施加的算元据的不同,一共分为四类:1. 算术运算2. 串联运算3. 关系运算4. 逻辑运算简述如下: 算术运算针对三种数值型数据,可以直接引用7种固有的算术运算: 2种一元运算:求反运算,其运算符为-;求同运算,其运算符为+。这两种一元运算可以施加于任意数值型数据和种别参数的组合,其运算结果的数据类型与种别参数和算元的数据类型和种别参数保持一致。 5种二元运算是:加法运算,其运算符为+;减法运算,其运算符为-;乘法运算,其运算符为*;除法运算,其运算符为;乘幂运算,其运算符为*。这5种运算的两个算元可以是数值型数据的任意数据类型与任意种别参数的任意组合。如果参与运算的两个算元不是同一个类型或种别参数不同,那么FORTRAN如何决定结果的数据类型或种别参数呢?基本的原则就是向需要存储空间大的操作数看齐,以免损失算元的信息。具体地说,就是: 若两个算元是相同类型和相同种别参数,则运算结果的类型与种别参数就是算元的类型与种别参数。 若两个算元都是整型但种别参数不同,则运算结果的种别参数是取十进制幂范围大的那个算元的种别参数;若范围一样大,则由系统决定。 当一个算元是整型、另一算元是实型或复型,则运算结果的种别参数就取那个实型或复型的算元的种别参数。 若两个算元属于不同种别参数的实型或复型数据,则运算结果的种别参数取十进制精度高的那个算元的种别参数;若精度一样,则由系统决定取舍。规定了运算结果的属性,具体的值就是通常的算术运算的结果,即 加法为两个算元之和; 减法为两个算元之差; 乘法为两个算元之积; 除法为两个算元之商,如果两个算元都是整型数据,它们相除时称为整除,其结果商就是首先进行算术上的除法运算,得到的商去掉小数部分,取得的整数值即为整除的结果。这是为了满足上面关于保持类型一致性的规则。例如:99/100的值为0;(-99)/100的值为0;58/3的值为19;(-58)/3的值为-19。 乘幂为以第一个算元为底,第二个算元为指数的乘幂值。 串联运算针对相同种别参数的字符型数据定义了串联运算,其运算符是/。串联运算的结果为保持种别参数不变的字符型数据。运算结果的值为第一算元的字符值,在右边紧接第二个算元的字符值。例如:ABC/RTY的值为ABCRTY 关系运算关系运算是分别针对整型、实型、复型和字符型数据来定义的二元运算。关系运算的结果为逻辑型数据,即只能取.TRUE.和.FALSE.两个值之一。FORTRAN 95定义了六种固有关系运算,这六种固有关系运算根据其可以施加的操作数的不同,又可以分为两类:可以施加于除复型之外的数值类型,种别参数以及字符型的第一类: 大于,其运算符为.GT.,或; 大于等于,其运算符为.GE.,或=; 小于,其运算符为.LT.,或; 小于等于,其运算符为.LE.,或=;可以施加于所有数值型与字符型的第二类: 等于,其运算符为.EQ.,或=; 不等于,其运算符为.NE.,或/=。对于数值型数据来说,关系运算具有通常的涵义,并且两个算元可以是任意的数值型类型与任意种别参数的组合。当然只有复型不能比较大小,而只能比较是否相等。对于字符数据来说,关系运算具有独特的涵义。首先要求两个算元具有相同的种别类型参数,但是可以具有任意的长度。其关系运算的执行可以理解为执行下列几个步骤:(1)首先使两个作为算元的字符串的字符长度变为一致,如果相对来说有个字符的长度较短,就在右边以空格字符填充,直到两个算元长度相同为止。(2)然后对两个算元按字符位置从左边第一个字符开始逐个进行比较判别,直到足够判别关系是否成立为止。(3)而字符的比较是按字符在字符集中排列序列的位置的先后来进行的: 若字符1在字符2之前,则认为满足小于关系,小于等于关系和不等于关系; 若字符1在字符2之后,则认为满足大于关系,大于等于关系和不等于关系; 如果位置相同,即为同一个字符,则认为满足等于关系。 所有空串都是相等的。 等于关系和不等于关系的运算结果与字符集序列无关,而其它四种关系的运算结果是依赖于字符集排列序列的。由于ASCII的排列序列对于任何系统都是一致的,所以一般而言可移植性是能得到保证的。 如果参与运算的默认字符数据值全是字母或全是数字,则按语言的规定,其顺序是严格确定的; 如果参与运算的默认字符数据值参杂了字母与数字,则把其中的数字看成字符,而排序则依赖于系统的具体规定。所以在使用时要注意这点。 如果参与运算的字符数据值包含了非默认的字符型数据,则同样依赖于系统的规定。 逻辑运算针对任意种别参数的逻辑型数据定义五种逻辑运算。我们知道数值型数据和字符型数据进行关系运算后的结果是逻辑型数据,此外还 可以根据算法的需要自定义逻辑型数据,逻辑运算就是施加于逻辑型数据,而得到逻辑型数据值的运算。根据算元的数目,逻辑运算包含两种,其中一元运算为: 非运算,运算符为.NOT.;非运算的运算结果定义如下表5-2:表5-2非运算的运算结果.NOT.的算元.TRUE.FALSE.NOT.的运算值.FALSE. .TRUE. 二元运算包括: 与运算,运算符为.AND.; 或运算,运算符为.OR.; 逻辑等价运算,运算符为.EQV.; 逻辑不等价运算,运算符为.NEQV.;各运算的结果定义如下列各表:表5-3 与运算的运算A.AND.B A B .TRUE. .FALSE.A .TRUE.TRUE.FALSE.B.FALSE.FALSE.FALSE. 表5-4 或运算的运算A.OR.BAB.TRUE.FALSE.A.TRUE.TRUE.TRUE.B.FALSE.TRUE.FALSE.表5-5 逻辑等价运算的运算A.EQV.BAB.TRUE.FALSE.A.TRUE.TRUE.FALSE.B.FALSE.FALSE.TRUE.表5-6 逻辑不等价运算的运算A.NEQV.BAB.TRUE.FALSE.A.TRUE.FALSE.TRUE.B.FALSE.TRUE.FALSE.逻辑运算的结果的种别参数的约定: 当两个算元的种别参数相同时,则结果的种别参数与算元的相同; 当两个算元的种别参数不同时,则结果的种别参数依赖于系统的约定。2. 自定义运算由于上面列出的固有运算,并不能满足我们在构造表达式时对运算的全部需求。显然,要使得语言具有开放性,就不可能期望通过指定有限的对象来概括任意需求,因此必然需要制定一个构造规则,以便允许程序作者自定义运算。所谓自定义运算就是需要程序作者根据算法的需要自己来定义的运算。从语法的角度来讲,一个运算的定义包括三个部分: 符号的表示;所谓符号的表示就是给出运算的名称,命名规则为一个字符串的左右分别加一个小数点(句点)。【例5-3】.REMAINDER.REVERSE.INTEGRAL.固有运算的表示符号除了通常的数学表示符号之外,同时还有一套等价的字符串加左右句点的表示方法,这就和自定义运算的符号表示统一起来了。这样做的好处就是可以用符号串直接作为文字来表示运算的涵义,(例如上面的三个名称就可以用来表示求余,反号,求积分这三种运算),从而便于程序的写作和阅读。这是一个值得遵循的良好的写作风格。 运用固有运算的组合给出的自定义运算的定义; 自定义运算的定义是通过函数用OPERATOR来完成的,具体的说明见有关过程的章节。 自定义运算的算元集合的描述。 数学上定义一个函数,必定要指出函数的定义域,同样一种自定义的运算也需要指定能够施加于其上的算元的范围,这里包括如下几种情况: 定义在某个固有数据类型的真子集上;如果对一个固有运算也做这样的限制,那么就把这个固有运算看成自定义运算了。 定义在不止一个固有数据类型上,例如数值型数据和字符型数据的某种组合上;可以针对某个固有运算做这样的扩展,同样视之为自定义运算。 定义在派生数据类型上;这样得首先定义该派生数据类型。 定义在上述任意情形的组合而成的集合上。5.4.4 数据类型的常量的表示形式数据在程序当中的行为,除了以指定数据类型的变量形式出现之外,还有就是以常量形式出现,也就是给出某个数据类型的具体取值的形式。因此对于数据类型的说明,还包括给出该数据类型的常量的书写语法。【例5-4】 下面给出每一种数据类型的说明常量的例子:例子 数据类型 例子的取值345 INTEGER 345713.2或7.132E2 REAL 713.2(2.77,5.38) COMPLEX 2.77+5.38i .TRUE. LOGICAL TRUE“SPACE_A” CHARACTER SPACE_ASAMPLE(1.582,(3.2,5.5),”CHENG”) 派生类型 SAMPLE(1.582,3.2+5.5i,”CHENG”)可以看出,对于数值型数据,直接给出常量数据,就可以了,而对于字符型数据则需要写在定界符里面,对于派生类型则需要遵循派生数据类型的说明语法。当然一个数据类型里的常量同样具有种别参数的属性,只要给出的常量不是属于默认的种别,就需要给常量加上种别参数,而种别参数有两种情况: 一种是采用整数,由于不同的编译器对于这些整数的具体解释有可能是不同的,因此会妨碍程序的可移植性; 一种是采用命名常量来作为种别参数,那么只要这些命名常量一直被使用,就能保证对它的解释的一致性。【例5-5】 类型 例子INTEGER 2_SHORTREAL 3.14159267895632_QUADCOMPLEX (3.14159_HIGH, 56.2)LOGICAL .TRUE._BYTECHARACTER CHINESE_”例子”例子里SHORT,QUAD,HIGH,BYTE,CHINESE都是命名常量。对于整型,实型,复型和逻辑型来说,种别参数写在数据的右边,以下划线隔开,而字符型则是写在数据的左边,同样以下划线隔开。5.5 数据的基本类型:固有数据类型对于计算机来说,数据的意义无非就是要知道在存储空间为一个特定的数据划出多大的空间来装载它,然后才谈得上给每一个数据编制地址,从而随时可以对数据进行读入读出操作。确定数据占用空间大小的自然方式就是统一地给一类数据指定固定的存储模式,这就是FORTRAN早期的做法,即整型,实型,逻辑型统一地用一个数值存储单位来存储,而双精度实型与复型则统一采用两个数值存储单位来存储,字符型数据则统一采用一个字符存储单位来存储。由于数值存储与字符存储具有不一样的情况,因此这两种存储单元的字节数大小不一样。不过语言的进步,毋宁说是算法的进步,要求语言能够提供更加灵活的存储模式的可选择性,这就是FORTRAN90引进的种别参数,这样就扩充了固有数据类型的存储模式。同时为了使得程序能够与旧的标准兼容,一般采取在默认的情况下采取旧的存储模式,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论