Fortran函数(1):子程序、函数——出自《Fortran 95 程序设计》 彭国伦

Fortran 专栏收录该内容
2 篇文章 0 订阅
1.子程序subroutine的使用
program main
...
call sub1()
...
call sub2()
...
end program main

subroutine sub1()
...
end subroutine sub1

subroutine sub2()
...
end subroutine sub2

!子程序最后通常是return命令,返回调用它的地方,注意不是stop,如是stop则程序结束,结果难料。
!return可以省掉,可以出现在子程序的任何地方,提早返回。
exmaple:
subroutine message()
    implicit none
    write (*, *) "hello"
return
end 

子程序之间可以相互调用,子程序可在任何地方被别人调用,甚至可以自己调用自己,即“递归”。
子程序独立的拥有属于自己的变量声明,与其他程序互不相干,同时拥有自己的行代码。
参数传递: fortran 采用的是传址调用(call by address/call by reference),即调用时候传递出去的参数,和子程序中接收的参数使用相同的内存地址来记录数据。因此 在主程序中传过来的参数,在子程序中可以被重新设置,主程序中参数内容跟着子程序中的改变而改变,在程序中可以改变主程序中的变量值。 需要注意!!C采用的是传值调用,混合使用的时候需要注意。

2.自定义函数( FUNCTION)
自定义函数要先声明,再使用,执行后会返回一个数值。

program ex0807
    implicit none
    real :: a = 1
    real :: b = 2
    real, external :: add !声明add是一个函数,而不是变量。调用函数不必使用call命令。
    write (*, *) add(a, b)
    stop
end program ex0807

function add(a, b)
    implicit none
    real :: a, b   !输入的参数
    real :: add   !add跟函数名称一样,这里不是用来声明变量,而是声明这个函数会返回的数值类型。
    add = a+b
    return
end function
!声明中多了一个external这个形容词,用来表示这里要声明的不是一个可以使用的变量,而是一个可以调用的函数。external可以省掉,但是建议不要省,容易辨别是函数而不是变量。

也可以这样声明上面的函数:
real function add(a, b)
    implicit none
    real :: a, b
    add = a+b
    return
end function

使用函数的一个不成文规定:“ 传递给函数的参数,只要读取就好,不要去改变它的数据 ”。如果要改变输入参数的数值时,最好使用子程序,而不是函数。

3.全局变量COMMON :  是f77中使用全局变量的方法,用来定义一块共享内存。
全局变量让不同程序声明出来的变量使用相同的内存位置,是一种不同程序之间传递参数的方法。
(1)common的使用:
program ex0810
    implicit none
    integer :: a, b
    common a, b   !定义a,b是全局变量中的第一和第二个变量
    ...
    call showcommon
    ...
    stop
end program

subroutine showcommon()
    implicit none
    integer :: num1, num2
    common num1, num2 !定义num1, num2是全局变量中的第一和第二个变量
    write (*, *) num1, num2
    return
end suroutine showcommon
!common的变量不可以随便用data的命令来设置他们的初值。取全局变量的时候,根据声明它们时的相对位置关系来作对应,而不是使用变量的名称来对应。任何一个地方改变了全局变量的值,程序中所有的程序都可以观察到这个变动,因为使用的是相同的内存位置。
!可以将变量归类,放在彼此独立的common区间中,避免麻烦。
exmaple:
integer :: a, b
common /group1/ a
common /group2/ b
....
stop
end 

subroutine showgroup1()
....
common /group1/ num1
...
return
end

subroutine showgroup2()
...
common /group2/ num2
...
return
end

!当需要共享的数据不多,而且只有几个少数的程序需要使用这些数据的时候则使用参数传递。需要共享大笔数据,或是很多个不同的程序都需要使用这些数据的时候就使用全局变量。

4. block data
common设置初值:要在block data 程序模块使用data 命令来设置初值。
program ex0812
....
common a,b
common /group1/ c, d
common /group2/ e, f
....
stop
end 


block data
implicit none
    integer a,b
    common a, b
    data a, b /1, 2/
    integer c, d
    common /group1/ c, d
    data c, d /3, 4/
    integer e, f
    common /group2/ e, f
    data e, f /5, 6/
end block data

block data这一段程序是类似于子程序,是一个独立的程序模块,拥有自己的变量声明,不过不需要别人调用就可以自己执行。这段程序在主程序执行之前就会生效,但是功能只在于设置全局变量的初值,不能有其他的执行命令。
block data 的模样结构:
block data name     !name 可以省掉
implicit none
integer ...    !变量声明
real ...
common ...!把变量放到common空间中
common /group1/ ...
data var1, var2...       !同样使用data设定初值
...
end block data name ! 或end或end block data

!全局变量不可以声明成常量,所以block data 中不可以出现parameter.
!注意事项:变量的类型,变量的位置。 (!可以使用f90中的方法使用全局变量!)

5.函数中的变量
传递常数的时候要注意类型的正确性。
数组作为接收用的参数时候,可用变量来赋值它的大小,甚至不去赋值大小。
函数中接受到的参数,事实上它们的内存地址都在执行函数前配置完毕,因此参数在函数中的声明就不会再去配置新的内存来使用,所以可以使用变量来赋值数组的大小。甚至可以不赋值数组的大小,因为数组在进入子程序前就配置到了空间。在函数中赋值数组的大小只是用来方便检查,不会重新配置内存。
函数中使用数组参数时只要不超过它的实际范围就行,可以将一维变成二维(列优先),改变坐标范围等等。
一般传递数组时最好也顺便输入它原来声明的大小,函数中才会知道数组能使用的范围。
!传递字符串变量时也可以不特别赋值它的长度。
!多维数组在传递时只有最后一维可以不赋值大小,其他的都必须赋值大小。
!!建议将数组实际声明的大小全部传递出去是比较好的做法。!!

6.变量的生存周期
在声明中加上save可以增加变量的生存周期,保留住所保存的数据。
subroutine sub()
    implicit none
    integer :: count = 1
    save count
    ....
end subroutine sub

或 integer, save :: count =1
每次子程序被调用时都会记得上次被调用时候留下来的数值。
注意:变量的初值只会设置一次,第一次调用的时候设置初值,不是每次都会去重新设置初值。

7.传递函数:类似于C中的函数指针。
可以把函数名称当作参数传递出去:
example:
program ex0821
    real, external :: func !声明func是自定义函数 !形容词都不能省掉
    real, intrinsic :: sin   !声明sin是库函数

    call ExecFunc (func) !输入自定义函数func
    call ExecFunc (sin)    !输入库函数sin

    stop
end program


subroutine ExecFunc (f)
    implicit none
    real, external :: f   !声明参数f是个函数
    write (*, *) f(1.0)   !执行输入的函数f
    return
end


real function func (num)
    implicit none
    real :: num
    func = num**2
    return
end function


子程序也可以当作参数传递出去:
program ex0822
    implicit none
    external sub1, sub2   !声明sub1和sub2是子程序名称
    call sub(sub1)
    call sub(sub2)
    stop
end program ex0822

subroutine sun (sun_name)
    implicit none
    external sub_name !声明 sub_name是个子程序
    call sun_name ( )    !调用输入的子程序sub_name
    return
end subroutine

subroutine sub1( )
    implicit none
    write (*, *) "sub1"
end subroutine

subroutine sub2( )
    implicit none
    write (*, *) "sub2"

end subroutine


博主认为这篇文章中讲解的子程序和自定义函数非常的清楚明了。。

  • 1
    点赞
  • 0
    评论
  • 5
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

科学院大气所李建平的 线性相关 Linear Correlation mscorrelation_2(n,x,y,r)   Correlations between two anomaly series of 12 calendar months, 4 seasons (DJF, MAM, JJA and SON), monthly, seasonal and annual data from monthly anomaly series x(i,12) and y(i,12) (i=1,...,n) 求逐月异常序列x(n,12)和y(n,12)(n是年)的相关系数r(24),其中j=112是112个月的情形,13~22是冬、春、夏、秋、冬季逐月、春季逐月、夏季逐月、秋季逐月、逐月、年、冬半年逐月(NDJFMA)、夏半年逐月(MJJASO)的序列的情形。 llcorrelation(n,x,y,nt,rt)   Calculating lagged and leading correlation coefficients rt(-nt:nt) between two anomaly series x(i) and y(i). 求(逐日、逐月、逐季、年际)异常序列x(n)和y(n)之间的滞后超前的相关系数rt(-nt:nt),其中nt最大的滞后或超前时间(单位:日、月、季、年等)。 llyear(ny,nm,x,y,ly,rt)   ly-year lagged and leading correlation coefficients rt(-ly:ly,nm) between two anomaly series x(ny,nm) and y(ny,nm). 求逐月异常序列x(n,12)和y(n,12)(n是年)相同月份之间的滞后超前nt年的相关系数rt(-nt:nt,12),其中nt最大的滞后或超前时间(单位:年)。 mllcorrelation(n,nt,x,y,rt)   nt-month (or nt-season, or others) lagged and leading correlation coefficients rt(-nt:nt,nm) between two anomaly series x(ny,nm) and y(ny,nm). 求逐月、逐季或其他异常序列x(n,nm)和y(n,nm)(n是年)不同月份之间的滞后超前nt月的相关系数rt(-nt:nt,nm),其中nt最大的滞后或超前时间(单位:月、季或其他)。 correlationmiss(n,x,y,undef,r,nr)   Correlation coefficient r between two series with missing data 求有缺省资料的两个序列x(n)和y(n)的相关系数r。   谱分析 Spectrum Analysis   一维离散功率谱分析 Discrete Fourier spectrum of one-dimensional series fourier(n,x,a,b,c,s,cta)   The discrete Fourier spectrum of one-dimensional series x(n). 求一维序列x(n)的离散Fourier谱分析,s(0:m)离散功率谱,c(0:m)振幅谱,cta(0:m)位相谱,其中m=[n/2.]。 dspectrum(n,lw,x,tl,sl,st95)   Subroutine for discrete spectrum analysis of an one-dimensional series x(i) (i=1,...,n). 具有噪音检验的一维序列x(n)的离散功率谱分析,ol(lw)频率,tl(lw)周期,sl(lw)离散功率谱,st95(lw)红噪音或白噪音谱的95%置信上限,其中lw=[n/2.]。注意:很多同学在使用这个程序时都问及在计算滞后相关的模块中,求滞后相关为什么用n而不用n-i,其实这是由实际资料的特性和统计学的基本原理决定的(很多统计学书中也谈到这一点)。一是序列的平稳性假设就要求序列的均值和方差保持不变,二是通常资料太短,导致用较短的资料得到的相关结果具有不稳定性,掩盖了事物的真相,因此,用n要好于n-i。一些同学也做了试验证实了这一点(有时n-i还得到错误的结论,需要各自使用者注意的地方)。谢谢大家提出的问题。 一维连续功率谱分析 Continuous spectrum
©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值