20170303 - 命令行参数
一般我们在编程的时候都会遇到如此情况:每次程序执行之后需要修改某些参数变量,然后再进行编译连接,如此往复。要是参数比较多的话,我们可以使用namelist来设置变量;但是要是参数不是很多,那么我们就可以通过Fortran中获取命令行参数的方法获得。
一般我们我们可以通过以下两种来实现获取命令行参数:
GET_COMMAND_ARGUMENT(number [, value, length, status] )
作用:获取命令行中的第number个参数的值
适用:Fortran 2003以及之后版本
参数:
- number:in,整型标量>=0
- value:out,optional,字符型标量
- length:out,optional,整型标量
- status:out,optional,整型标量
返回:调用子程序,然后
- value参数保留第number个参数的值,若其不能容纳,则适当截断以适应value长度;
- 若命令行上指定参数个数小于number参数,则value被赋值为空白,若number=0,则返回程序名;
- length参数包含第number个参数的长度;
- 若参数获取失败,则status为正值;若value中的参数是被截断的,则status为-1;否则其为0。
拓展:
GETARG(pos, value)
作用:得到命令行中第pos个参数,可以兼容fortran 77,建议使用第一种子函数获取参数
参数:
- pos:in,整型标量>=0
- value:out,字符型标量
返回:调用子程序,然后
- value保留第pos个参数的值,若无法容纳,则需要截断,若pos参数大于实际命令行参数个数,则value赋值为空,若pos=0,则返回程序名
拓展:
- IARGC():获取命令行参数个数,可兼容fortran 77,建议使用COMMAND_ARGUMENT_COUNT()
延伸:数据类型转换
由于通过以上子程序获得参数都是字符型数据,因而在需要使用整型或是实型时,就需要进行适当的数据类型转换。
我们可以利用Fortran内部文件实现数据类型转换。
彭国伦建议将内部文件(Internal File)称为“字符串变量文件”,这个叫法比较贴切。 我猜测Fortran中写入文本文件实际经过两个过程:首先将数据转换为字符类型,然后将字符符 号写入文件中。读文件则是先将文件中数据以字符类型读入,然后根据赋给的变量类型进行相应 类型转化。这样看的话,内部文件方法是将字符串变量看成一个“文件”,然后写操作将数据转化为字符类型,然后“写入”字符串变量这个“文件”中,从而间接实现类型转换。
12345!字符型转换为数值型,in-str;out-numericread(str, *) numeric!数值型转换为字符型,可以使用格式化控制字符串write(str, *) numeric,str-out;numeric-in
参考:
20170304 - Fortran中的数组
【了解】
Fortran中的数组可以大致分为2类6种
显式数组
显式形状(Explicit-shape)数组:固定的秩、每一维的长度和形状,其中下界可以忽略,如下:
INTEGER M(10,10,10),K(-3:6,4:13,0:9)
自动(Automatic)数组:一种特殊显形数组,只能是过程中的局部变量。
自动数组必须在过程中加以声明,并且它至少有一维的上下界是不定的表达式,通过整型变量或整型表达式求出
过程中其后的变量或表达式值的变化不会对数组的上下界产生影响
1234SUBROUTINE EXAMPLE(N,R1,R2)DIMENSION A(N,5),B(10*N)……N=IFIX(R1)+IFIX(R2)理解:在子函数中声明数组,其中的某几维是变量
可调(Adjustable)数组:一种特殊显形数组,只能是过程中的一个哑元。
可调数组中至少有一维的上下界不是常数,这个维的上下界只有当过程被调用时才能最终确定。
该维的上下界表达式中的整型变量可以是通过过程传递的哑元,也可以是通过COMMON语句中传递的整型常量或变量。
12345678910111213141516171819DIMENSION A1(10,35),A2(3,56)……!实参中必须要有数组名SUM1=THE_SUM(A1,10,35)SUM2=THE_SUM(A2,3,56)END!过程中也要有数组名FUNCTION THE_SUM(A,M,N)DIMENSION A(M,N)SUMX=0.0DO J=1,NDO I=1,MSUMX=SUMX+A(I,J)END DOEND DOTHE_SUM=SUMXEND FUNCTION理解:参数传递需要包含数组名,可以通过这种方式改变数组内部数值,而自动数组是局部变量,过程内改变不会产生任何影响。
隐式数组
假定形状(Assumed-shape)数组:一种在过程中使用的特殊类型数组,这种数组是过程中的哑元,它从实际传递过来的数组获得形状参数。
假定形状数组的秩由冒号的个数决定。它的一般形式是:([下界]:[,[下界]:]…)。
如果不指定下界,则默认值为1。上界值=过程调用时实参数组对应维的长度+下界值-1。
注意它与可调数组的区别在于,可调数组属于显型数组(必须指定上界,尽管这个上界可以是变量或表达式)的范围,而假定形状数组的上界是不能指定的。
应用假定形状数组为哑元的过程时必须有显式的接口INTERFACE语句。
12345678INTERFACESUBROUTINE SUB(M)INTEGER M(:,1:,5:)END SUBROUTINEEND INTERFACEINTEGER L(20,5:25,10)CALL SUB(L)! 在此例中数组M的维界是(1:20,1:21,5:14)理解:与可调数组十分类似,但区别在于可调数组必须指定上界,但是假定形状数组不能指定上界,没有传递维度参数
假定大小(Assumed-size)数组:一种在过程中使用的特殊类型数组的哑元,这种数组是在过程中的哑元,它从实际传递过来的数组获得数组大小
除了最后一维的上界以外,其它所有特征(秩,长度和维界)都必须指定
声明一个假定大小数组时,最后一个的上界用星号*表示。它的一般形式是:([显型维界,][显型维界,]…[下界:],*),其中数组A的最后一维没有必要成为完整的维。
假定大小数组的秩和形状可以和实际传入的数组不同,传入的数组只确定它的大小。实际数组的元素按列传递给假定大小数组,假定大小数组也按列接收。接受的过程中假定大小数组的最后一维的长度会改变来接受所有传递进来的数组元素,于是最终给出数组的大小。如上例子中的ASSUME子程序,如果以数组X为哑元来调用的话,
12345678910REAL X(7)CALL ASSUME(X)! 则数组X的元素与数组A的对应顺序是:X(1):A(1,1,1)X(2):A(2,1,1)X(3):A(1,2,1)X(4):A(2,2,1)X(5):A(1,1,2)X(6):A(2,1,2)X(7):A(1,2,2)
延迟形状(Deferred-shape)数组:可分配数组必须以延迟形状的形式来声明。它每一维的长度只有在分配数组才被确定。声明迟形数组时,秩由冒号确定,但长度是未知的。
可分配数组可由下列方式声明:使用ALLOCATABLE语句、DIMENSION语句、TARGET语句或在类型声明中使用ALLOCATABLE属性。
如果迟形数组以DIMENSION语句或TARGET语句声明,则在其它语句中必须给出ALLOCATABLE属性。在迟形数组的大小、形状和维界没有确定之前,其任何部分都不能被引用,可分配数组的大小、形状和维界在ALLOCATE语句执行时才被确定。
123INTEGER,ALLOCATABLE:: A(:,:)REAL,ALLOCATABLE,TARGET:: B(:,:),C(:)ALLOCATE(A(2,3),C(5),B(SIZE(C),12))
【掌握】
Fortran中的动态数组:Fortran90中有三种动态数组。这三种动态数组允许在运行时创建,数组大小由计算或输 入得到的值决定。
自动数组 && 可调数组【不建议使用】
这需要用到过程的概念和良好的程序设计结构。如果碰到有些数组需要作为全局变量在不同的过程中进行处理的情况,就只好采用开一个大数组的办法来解决。
可分配数组【推荐】
- 一个可分配数组使用ALLOCATABLE显式声明,用 ALLOCATAE语句显式分配,用DEALLOCATE语句显式销毁或当其为未指定SAVE属性的局部数组时,退出程序时自动销毁。一个全局可分配数组一直存在直到显式销毁(deallocate语 句可能与allocate语句不在同一个程序中)。
- 一个可分配数组可以是一个程序局部变 量,也可以放在模块变量中,对模块中所有程序来说是全局的。
- 如果数组大小取决于一个计算的值,而不是 哑元或模块变量、common或主程序,使用可分配数组。可用ALLOCATED内置函数测试一个 可分配数组的分配状态。
123456789101112131415161718subroutine Peachuse Recipe ! Accesses global allocatable array, Jam.real, allocatable :: Pie(:,:) ! Pie is a 2-dimensional allocatable array....allocate ( Pie(N,2*N ) ) ! Allocate a local allocatable array.if (.not.allocated(Jam)) allocate ( Jam(4*M) )! Allocate a global allocable array if! it is not already allocated.... deallocate ( Pie )...end subroutine Peachmodule Recipe ! Jam is a global allocatable array, andreal, allocatable :: Jam(:) ! can be allocated and deallocated in... ! any procedure(s) using this module.end module Recipe指针数组
指针数组类似于可分配数组,他们用ALLOCATE语句显式分配,拥有任意计算大小并且用 DEALLOCATE语句显式销毁。
另:
- 过程:过程是在程序的执行中可被直接调用的、封装在一起的、进行计算或处理的语句序列。它是任何一种过程型程序设计语言的重要组成部分,对Fortran语言也不例外。F90中,一个过程的定义就是指它是一个函数或是一个子程序。
- 哑元:通常过程是带有参数的,在Fortran中把参数称为变元(实元或哑元),过程定义中的变元是哑元,过程引用中的变元是实元。在调用过程时,要用实元代替哑元,这就是哑实结合。(类似C中的虚变量)
*.mod
文件通常是使用了 module 的源代码经过编译后产生的,用于标记该模块的接口。你可以认为是头文件,只不过是自动生成的头文件。其实现为.o
文件
参考: