FORTRAN程序单元.ppt_第1页
FORTRAN程序单元.ppt_第2页
FORTRAN程序单元.ppt_第3页
FORTRAN程序单元.ppt_第4页
FORTRAN程序单元.ppt_第5页
已阅读5页,还剩33页未读 继续免费阅读

下载本文档

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

文档简介

第10章 Fortran程序单元,一个Fortran程序中通常不是只由一个主程序组成,而是由几个按某种方式划分的不同程序单元来共同组成。尽管Fortran程序中允许只有主程序而没有子程序,但绝不允许只有子程序而没有主程序。在Fortran中,程序的执行总是从主程序开始的。 Fortran中的程序单元可以大体划分为主程序、子程序两种,其中子程序又可以进一步划分为函数子程序、子例行子程序和数据块子程序。数据块子程序通常用于实现变量的初始化赋值,函数子程序和子例行子程序在用途上基本是一致的,但是也有许多不同之处。本章将详细介绍Fortran中的程序单元和它们的基本用法。,10.1 主程序,顾名思义,主程序是一个实际程序中的主体,其他类型的程序单元都是以某种方式来辅助主程序的执行。在Fortran语言中,一个程序的执行始终是从主程序的第一条可执行语句开始的,所以每个完整的Fortran程序都必须有且只允许有一个主程序。主程序定义的一般语法形式如下: PROGRAM 程序名 说明部分 可执行部分 CONTAINS 内部过程 END PROGRAM程序名,10.2 语句函数,语句函数通过一句代码定义来实现某种特定的处理功能,它是Fortran 77时代的遗留产物。严格来说,语句函数不属于程序单元的范畴。但是在实际应用中,语句函数以其灵活的应用、小巧的结构在程序中发挥着重要的作用。 在实际的编程过程中,程序员往往会遇到这种情况:一些简单的函数会在一个程序单元中的不同地方重复用到,而Fortran系统并不提供这种内部函数;如果采用函数子程序的形式来描述这些简单的函数又会觉得没有这种必要。例如,要求解函数的值,将其编写成函数子程序可以顺利解决。但是,Fortran语言提供了一种更为简单的手段语句函数。,10.2.1 语句函数的定义,在Fortran中定义一个语句函数的形式如下: fun (d-arg , d-arg .) = expr 1Fun 2d-arg 3Expr 4语句函数示例 5需要注意的问题:在使用语句函数进行编程时,下面一些问题是需要引起注意的: 语句函数通常在函数比较简单,能够用一条语句(包括换行)就能进行定义时才使用; 语句函数是一种非执行语句,需要放置在所有可执行语句之前和相关的类型说明语句之后; 语句函数的作用范围仅限于定义它的程序单元之内,不允许跨程序单元进行语句函数的调用; 语句函数不能作为子程序调用时的实参,也不允许在EXTERNAL语句中出现; 语句函数中出现的虚参必须是变量名,不能是常量、表达式或是数组元素; 语句函数通过表达式得到的函数值的类型必须与函数名的类型一致。,10.2.2 语句函数的引用,语句函数在完成定义后,就可以在程序单元中进行引用了。实际上,在前一小节的例程中已经演示了语句函数引用的一般方式。本小节将对语句函数的引用方式进行具体的说明。 语句函数的引用方式与Fortran中内部函数的引用方式完全一致,就是用程序中定义的实参替换掉语句函数定义中的虚参。实参必须是与虚参类型相同的常量、变量或表达式。,10.3 函数子程序,函数子程序和子例行子程序是子程序的两种常用基本形式。它们的共同特征就是作为数据处理过程的集合。但是这两种子程序也不完全相同,函数子程序会返回一个函数值,且通常不会改变哑元的数值。因此,函数子程序更像是数学上的一个函数。而子例行子程序通常用于完成一项更为复杂的任务,通过哑元或者其他手段返回几个结果,哑元的数值通常会在程序的执行过程中改变。,10.3.1 定义函数子程序,下面给出函数子程序的一般形式为: prefix FUNCTION name (d-arg-list) RESULT (r-name) . END FUNCTION name 1prefix说明项 prefix说明项是一个可选参数,可以使用如下两种形式来书写: type keyword 或 keyword type 2d-arg-list d-arg-list表示函数的哑元列表。如果函数子程序不包含哑元,则哑元列表可以省略,但是函数名后的括号不能省略。 3RESULT关键字 RESULT关键字用于声明将函数的返回值保存在其后的变量名中,称为函数结果名。,10.3.2 调用函数子程序,函数子程序的调用与内在函数的调用形式一样。在主调程序的任意位置,可以通过下面的语句形式将函数子程序的计算结果赋值给变量: V = 函数名(实元表) 其中,V表示用于接收函数计算结果的变量;实元表是程序中实际传入函数子程序的变量列表,除非有特殊说明,变量列表中的实元个数以及类型必须与函数子程序定义时的虚参在个数和类型上一致。如果函数不包含哑元,则调用形式是在表达式中直接写上函数名再跟空括号即可: V = 函数名(),10.3.3 函数子程序示例进制转换,下面来看一段函数子程序的实例,代码将一个4字节的整数用16进制的形式表示出来。首先给出的是程序的函数子程序单元HEX。 FUNCTION HEX(n) IMPLICIT NONE CHARACTER(LEN=8) : HEX CHARACTER(LEN=1) : H(0:15)=(/0,1,2,3,4,5,6, 7,& 8,9,A,B,C,D,E,F/) INTEGER : n, j, nn HEX= DO j=8,1,-1 nn = n/16 HEX(j:j) = H(n - 16*nn) IF(nn = 0) EXIT n = nn END DO END FUNCTION,10.3.4 函数子程序示例分形,在数学上有一个特殊的分支分形(fractal),所谓分形是Mandelbrot将自然界的一些特殊复杂图形(如海岸线、树叶外形、雪花结晶类型等)进行数学理想化后提出的一种概念,其核心思想是图形的任意细小部分都与图形的整体具有自相似性,这种图形的维数不是整数,而是分数维。分形的一个典型例子就是Koch曲线,它具有雪花的外形,可以通过对一段直线反复进行某一简单的操作而得到。把这个过程用数学语言来描述,就是在复空间内定义的一种简单迭代过程,它是一个图形的缩小映射,从而产生自相似曲线。,10.4 子例行子程序,同函数子程序相比,子例行子程序通常用于完成更为复杂的任务。子例行子程序接受外界传入的参数并对其进行处理,子例行程序名不会用来返回处理结果。形象一点来说,函数子程序像检验机,它不改变参数的值但会告诉外界一个检测结果;而子例行子程序更像一个加工机器,外界来的参数经过它的加工会以新的形象出现。本节主要介绍子例行子程序的相关知识。,10.4.1 定义子例行子程序,子例行子程序同函数子程序非常相似,但是子例行子程序不会有返回值。这种形式的子程序是以SUBROURTINE语句开始,END语句结束的过程。其一般语法形式如下: 前缀 SUBROUTINE子程序名 (哑元列表) END SUBROUTINE子程序名 1哑元列表 2前缀 3子程序名 4END语句,10.4.2 子例行子程序示例,下面直接来看一段例子,这段代码依次读入三个实数,并按它们的大小重新开始排序。 程序的执行结果如下: 请输入三个实数: 1.345 2.71828 2.71827 三个实数的先后次序如下: 2.718280 2.718270 1.345000 调用子例行子程序时的实元必须是与哑元类型相同的变量、数组、数组元素和常数。当用CALL语句进行调用时,哑元和实元才按哑元列表中的顺序一一对应,取得同一数值。,10.5 子程序的多入口点和多折返点,尽管子程序中不允许直接定义其他的子程序,但是在Fortran 77时代,可以通过特殊的方式在同一个子程序中定义多个不同的过程入口。通过调用不同的过程定义来实现调用同一个子程序中的不同执行段。除了提供多入口点外,Fortran 77时代也提供特殊的多折返点来实现特定条件的子程序调用返回方式。,10.5.1 ENTRY语句与多入口点,Fortran语言中的子程序中可以通过ENTRY语句来提供多个入口点。 程序的执行效果如下: 请任意输入一个实数: -30.0 这是一个负数 它的立方根为: -3.107233 在上面的代码中,子程序SIGN内部通过ENTRY语句为一段执行代码定义为一个入口点Negative(A)。在主调程序中,可以根据情况选择子程序SIGN中的不同执行段:直接调用SIGN将会执行入口点Negative(A)前的执行代码,并在ENTRY语句前的RETURN语句返回主调过程;如果调用Negative将执行入口点Negative(A)后的执行代码,并在下一个RETURN语句返回主调过程。,10.5.2 子程序的多折返点,一般来说,当子程序执行完成之后,通常会直接返回主调程序的调用处继续进行执行。关于这一点,Fortran语言中也提供了一种特殊的返回方式来改变子程序的折返点,将子程序的返回点指定到主调程序的其他位置。 程序的执行结果如下: 请输入一个正整数负数-退出:0 计算结果S = 0.0000000E+00 =0 请输入一个正整数负数-退出:2 计算结果S = 0.9092974 0 请输入一个正整数负数-退出:5 计算结果S = -0.9589243 0 请输入一个正整数负数-退出:0 需要注意,能够实现多折返点的子程序仅限于子例行子程序,不包括函数子程序,函数子程序通过RETURN语句只能返回到主调程序中的调用点处。,10.6 Fortran 90/95中的特殊子程序类型,在Fortran 90/95标准中,除了继续对前述的一般子程序类型提供支持外,还新增了三种特殊的子程序类型。这三种子程序类型就是前述章节中曾经提到过的RECURSIVE、PURE和ELEMENTAL三种属性。RECURSIVE属性允许过程进行自身调用,也就是常说的递归调用;PURE和ELEMENTAL属性都用于数组的并行处理。,10.6.1 RECURSIVE属性,在Fortran 90/95标准之前,Fortran中的子程序是不允许进行自身调用的。在新标准中,Fortran子程序开始允许进行自身调用,也就是经常在编程中听到的“递归”。能够进行递归调用的一个前提条件就是递归过程在被调用时,其中的局部变量会使用不同的内存地址,以便在完成递归后能够依次统计不同内存地址上的结果。 1递归函数子程序 2递归子例行子程序,10.6.2 PURE属性,在函数子程序或是子例行子程序的定义语句前添加PURE语句,将使子程序具有PURE属性。一般来说,并不需要使用这种属性,它通常适用于并行计算并在使用上有较多的限制。 具有PURE属性的子程序,其参数必须是只读的,即INTENT(IN)。 具有PURE属性的子程序,其参数都必须有赋值属性。 具有PURE属性的子程序,其中的变量不允许具有SAVE属性。 具有PURE属性的子程序,其包含的内部过程也必须具有PURE属性。 具有PURE属性的子程序,不能够使用STOP以及输入输出相关语句,如READ、WRITE等。 具有PURE属性的子程序,只能够读取而不能改变全局变量的值。,10.6.3 ELEMENTAL属性,ELEMENTAL属性与PURE属性非常相似,只不过它是一个针对数组的应用。在具有ELEMENTAL属性的过程中,不允许出现数组参数。该属性主要用于配合Fortran 90/95中对于数组的整体操作。 程序的执行结果如下: 1.000000 3.000000 5.000000 7.000000 9.000000 0.5403023 -1.714717 0.6342880 1.994638 -2.733391,10.7 数据块程序单元,由于COMMON语句中的变量不能够在子程序或主程序中通过DATA语句来直接设置初始值,需要在一个统一的程序单元中进行数据的初始化工作。这种统一的程序单元就是数据块程序单元。 数据块子程序单元是一种为有名公用块中的变量定义初始值的程序单元。它只允许包含变量声明和变量初始值,不可以包含可执行语句。数据块程序单元是一种落后的程序设计手段,在新的Fortran 90/95标准中已经有新的模块程序单元可以完全提供数据块的所有功能。但是一些早期的大型Fortran程序往往会使用这种程序单元来进行变量的初始化工作,因此有必要对这种过时的语法进行简单的介绍。,10.7.1 定义数据块子程序,数据块子程序的一般形式如下: BLOCK DATA 块数据名 说明部分 END BLOCK DATA 块数据名 数据块子程序中的变量一般通过DATA语句来进行初始化。公共块中命名的变量只能在数据块子程序单元或某个过程中初始化一次。更好的编程方法是使用模块程序单元而不是数据块单元来进行全局变量的声明和变量的初始化工作。,10.7.2 使用数据块子程序,数据块子程序在整个程序结构中是一个独立的单元,不能出现在其他的程序单元之中。同时,数据块子程序也不需要进行显示的引用,编译程序会在编译阶段根据数据块子程序的定义为其中的变量做好赋初值的工作。,10.7.3 数据块子程序示例,下面来看一段数据块程序单元的代码实例。这段代码没有什么实际的用途,主要用于说明数据块在实际编程中如何应用。 程序的运行结果非常简单,如下所示: This is a demo of BLOCK DATA 1.000000 -34.00000 0.7800000 3.141593 1.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 1.00000000000000 -1 -2 -2 -2 -1,10.8 子程序的参数,函数子程序和子例行子程序在有些时候都会涉及到大量外部传递的参数。这些参数在传递过程中的行为如何?有些什么特性?在过程中如何发挥作用?这就是本节将要介绍的基本内容。,10.8.1 参数传递规则,子程序中的哑元在与实元进行哑实结合时的一条基本规则就是对应位置上的数据要类型正确。参数类型如果不一致,则很可能发生不可预料的结果。由于Fortran语言在进行参数传递时采用的是传地址的方式,即传递变量所占的第一个地址。进行参数传递的哑元和实元会用自身的数据类型规则来解读同一片存储单元,一旦数据类型不一致就很容易发生解读错误的问题。 1参数传递错误示例 2类型不匹配解决方法,10.8.2 子程序的接口,在前一节的最后一个例程中,介绍了一种新的程序单元接口。通过ITERFACE语句可以向调用程序单元说明过程的某些信息。 1显示接口 2隐式接口 3接口块 4过程接口块,10.8.3 接口块使用情况,在实际编程中,接口块并不是每个主调程序都具有的。如果仅使用Fortran 77语言编写子程序,则无需在主调程序单元中编写接口块;但是如果使用Fortran 90/95中提供的一些现代化手段来编写程序,通常需要在主调程序单元中写入调用程序的接口块,否则在编译过程中很容易出错。此外,Fortran 90/95中不提倡使用COMMON语句进行程序单元间的数据传递和共享,该语句的功能已经由模块中的接口块代替。确切一点,如果遇到下列情况时,在主调程序中必须声明被调过程的接口块。 (1)如果外部过程具有以下特征: 过程的哑元有可选择属性。 过程的哑元是假定形数组、指针变量、目标变量。 过程的结果是数组或指针。 对于字符型函数过程的结果,其长度不是常数,也非假定长度。 (2)如果调用过程时出现下列情况: 使用了变元关键字(如范例TEST1009)。 使用类属名来进行调用。 使用超载赋值号(对于子程序)。 使用超载操作符(对于函数)。 在要求纯过程的上下文中。 (3)如果过程前缀关键词是ELEMENTAL。,10.8.4 INTENT属性应用,在Fortran语言中,虚实结合是在不同程序单元之间进行数值传递的主要手段。例如,主程序中实元A与子程序中的哑元X结合,就是将实元A在内存中的地址传递给哑元X,也就是将主程序中A的值传递给子程序中的X,该值可供子程序运算;反之,如果子程序中的变量Y在子程序执行完后有值M,则Y与实元R结合后会使主调程序单元中的实元变量R的值也变成M。 在Fortran 77时代,在编写程序时无法确切地说明过程中哑元的目的。过程中的哑元到底是用来将数据传入到过程中的,还是用来将数据传出到主调程序单元中,或者是两种功能都兼而有之。这个概念是含糊的。在进行调用时只能由程序员自行记住过程中各个哑元的性质。进入到Fortran 90/95时代,为了避免当过程内部变量的值发生变化后返回到主调程序单元时可能造成的混淆情况,在过程的变量类型定义中,可以为哑元指定INTENT属性(字面信息就是意图属性)。哑元按照其在参数传递过程中的作用可以分为输入输出两用、仅用于输入和仅用于输出。,10.8.5 关键字变元,关键字变元其实已经在前面提到过了,这里单独进行更详细一点的讲解。一般来说,哑实结合必须遵循三个一致的原则,否则会出现错误。所谓三个一致,是指:哑元与实元的位置一致;哑元与实元的个数一致;哑元与实元的类型一致。 上述要求需要程序员记住每个哑元的名称及位置,在书写或阅读过程中的实元表时要对其中每个表达式追溯到它原来的哑元是什么,非常不方便。针对这一问题,Fortran 90/95中通过三种方法来放宽这三个一致的原则: 用关键字变元放宽位置一致; 用可选择变元放宽个数一致; 用类属过程放宽类型一致。,10.8.6 可选择变元与OPTIONAL属性,在调用的三个一致原则中,实元与哑元个数一致是另一个比较严格的要求。但在某些过程中,虽然哑元列表中列出了好几个哑元,但在实际调用时不一定每次都需要全部用到。对于这种情况,Fortran 90/95标准中允许只对哑元表中的部分哑元进行哑实结合,另一部分哑元则按需要进行有选择的结合,这部分哑元又被称为可选择变元。例如Fortran语言中的内在数组函数SUM,它的完整函数及哑元表如下: SUM(ARRAY,DIM,MASK),10.8.7 哑元改名,广泛的通用性是过程的一大优点。一旦针对某个通用处理操作的过程被编好,求解具体问题的主程序就可以对它进行调用。但是在应用于不同的目的时,具体问题的物理名称可能是不同的。为了加强程序的可读性与可维护性,在不同的场合使用某一个过程时,需要将哑元名称改为与该领域械奈锢砻埔恢隆Fortran 90/95中,允许改变过程中变元的名称。变元名称的改变是在接口块中进行的,所以在主调程序中需要写出相应的接口块。 例如上面求多边形边长的子程序,如果调用时想要将表示边长的哑元名A、B、C和D改为物理意义明确的名称Upper、Down、Left和Right,只需在主调程序中编写相应的接口块,在接口块的哑元表中使用新的哑元名称就可以了。,10.8.8 INTRINSIC属性,与EXTERNAL语句或属性说明的实元是外部过程相对应,INTRINSIC语句或属性用来说明实元实际上是内在过程。说明一个对象名具有INTRINSIC属性可以有两种方法,一种就是在类型说明语句中加入INTRINSIC属性,具体的形式如下: 类型说明语句, INTRINSIC : 内在函数名,内在函数名 另一种方法是直接使用INTRINSIC语句进行说明,具体的形式如下: INTRINSIC : 内在过程名,内在过程名,10.8.9 数组作为参数,除了将单独的变量作为过程的参数以外

温馨提示

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

评论

0/150

提交评论