加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

Fortran函数(2):特殊参数:特殊的函数类型(转)

(2009-12-24 16:08:44)
标签:

教育

分类: 专业学习
010: Fortran函数(2):特殊参数:特殊的函数类型  http://hi.baidu.com/jiajunchong/blog/item/08f94d97190c046554fb96cb.html
2009/03/24 10:28 A.M.
From: 《Fortran 95 程序设计》 彭国伦
一:特殊参数的使用方法:
f90中可以赋值函数的属性,设置某些参数是只能读不能改变的。可以输入不定个数的参数,还可以不按照顺序来传递参数。

1.参数属性:

subroutine div(a, b)
    implicit none
    integer, intent (in) :: a    !指定a是只读的
    integer, intent (out) :: b !指定b是在子程序中应该重新设置数值
    b = a/2
end subroutine
指定属性这是避免编写程序时候不小心出错。
还可以指定intent(inout)这个属性,是指参数可读可写。基本和没有指定一样。

2.函数的使用接口:(interface)
interface是一个程序模块,用来清楚说明所要调用函数的参数类型以及返回值类型等等的“使用接口”。一般情况下使用函数时不需要特别说明它们的“使用接口”,不过在下面这些情况是必要的:
(1)函数的返回值为数组时
(2)指定参数位置来传递参数时
(3)所调用的函数参数数目不固定的时候
(4)输入指标参数时
(5)函数返回值为指针时
exmaple:
program ex0825
    implicit none
    interface !定义函数func的使用接口
       function random10 (lbound, ubound)
       implicit none
       real :: lbound, ubound
       real :: random10 (10) !返回值是个数组
       end function
    end interface

    real :: a(10)
    CALL RANDOM_SEED( )   !库存子程序,使用随机数前调用
    a = random10(1.0, 10.0) !生成10个1.0~10.0之间的随机数
    write (*, "(10F6.2)") a   !输出a 的内容
end program ex0825

function random10(lbund, ubound)
    implicit none
    real :: lbound, ubound
    real :: len
    real :: random10(10)   !返回的是一个一维数组
    real    t
    integer i
    len = ubound - lbound ! 计算范围大小
    do i = 1, 10
       call random_number(t) ! t是0~1之间的随机数
       random10(i) = lbound + len * t !转换到范围之间的随机数
    end do
    return
end function random10

声明使用接口一般比较麻烦,如上,每个要调用该函数的都要在其中写清楚函数的interface才行。使用module可以减少这个麻烦。

interface的编写结构很简单,一次可以放入好几个函数的使用接口:
interface   !开始写作interface
    function func_name     !开始定义函数
       implicit none
       real ..... 这里面只能说明参数或返回值类型
       integer .....
    end [function [func_name]] !定义函数func_name 结束

    sub_routine sub_name !定义子程序sub_name
       implicit none
       integer ...
    end [subroutine [sub_name]] !定义子程序结束

end interface !结束interface

3.不定个数参数的传递
f77中函数的参数都是固定的数目。F90中,可以使用optional命令来表示某些参数是“可以省掉的”。
example:
program ex0826
    implicit none
    interface
    subroutine sub(a, b) !定义子程序sub的使用接口
       implicit none
       integer :: a
       integer, optional :: b
    end subroutine sub
    end interface
    !开始编写执行命令
    call sub(1)       ! 使用一个参数
    call sub(2, 3)    !使用两个参数
    stop
end program ex0826

    subroutine sub(a, b)
       implicit none
       integer :: a
       integer, optional :: b
       if (present(b)) then !有b输入时
          write (*, "('a=', I3, ' b=', I3)")   a, b   !
       else                   !没有b输入时
          write (*, "('a=', I3, ' b= unknown')") a
       end if
       return
    end subroutine sub
结果:
a= 1 b= unknown
a= 2 b= 3
!integer, optional :: b !optional 表示b是可以省掉不传入的
!present()可以检查一个参数是否传进来,返回值是布尔变量,传进来则为.true.,没有则返回.false.
!注意:要调用这一类不定数目参数的函数时,一定要先声明出函数的interface,使用module时则可以省掉。

4.改变参数传递位置的方法:
F90中甚至可以不用按照参数的顺序来传递参数。
example:
subroutine sub(a, b, c)
    ...
    ...
end subroutine

调用这个程序的时候可以直接代入子程序中的变量名称来做“变换参数位置”的调用:
call sub(b=2, c=3, a=1)   ! 根据变量名称来传递参数, 仍可以正确的接收到这三个参数。
这个方法可以配合应用在不定个数的参数传递上:
subroutine sub (a, b, c, d, e, f)
    implicit none
    integer, optional :: a, b, c, d, e, f
    ...
end subroutine sub
想要指定输入某几个参数时,就可以用这个方法来特别指定:
call sub (b=3, f=5) !只输入b和f的值,其他的三个都不输入。
!注意:使用这个方法传递参数时,一定要声明interface。
这个做法可以省掉很多不必要的描述,尤其是子程序可以接收多个参数的时候。编写程序时,可以让某些参数有默认值,不输入这些参数的时候就使用参数的默认值。如写一个函数,f(x) = a*x^2 + b*x + c,一定要输入x来计算,a, b, c没有输入的话默认为0。

5.特殊的函数类型:
F90的函数,除了一般正常使用的类型外,还可以特别指定成recursive, pure, elemental这三种类型之一。
recursive是让函数可以自己调用自己,名词上称为“递归”。pure和elemental是用来做并行处理时及设置数组时使用。
递归:函数除了可以让别人调用,自己也可以调用自己来执行,这叫做“递归”。能够递归执行的函数有一个必要条件,就是递归函数每次被调用执行时,函数中所声明的局部变量(指那些不是传递进来的参数,以及没有被save的变量)都会使用不同的内存地址。简单的说,函数中的局部变量在每次调用时都是独立存在的。
example:

recursive integer function fact(n) result(ans)

!开头加上recursive的函数才可以递归调用;result可以用来在程序代码中使用另外一个名字来设置函数的传回值,这里使用ans来代替原来的fact。

!每个自定义函数都可以使用result来改用另外一个名字来设置返回值,fortran90标准中,递归函数一定要使用result来改名。
!关于递归详细的讲解见《Fortran 95程序设计》P194~200

内部函数:
F90中可把函数做一个“归属”,定义出某些函数只能在某些特定的函数中被调用,写法:
program main 或 subroutine sub 或 function func
    ...
    ...
    contains   !contains后面开始写作局部函数
      subroutine localsub      !localsub只能在包含它的函数中被调用
          ...
      end subroutine localsub

      function localfunc       !localfunc只能在包含它的函数中调用
          ...
      end function

end program/subroutine/function
如果将一个函数定义为主程序中的局部函数,那么主程序不声明就可以直接调用到该函数,而其他程序不可以调用它。

pure函数:
在function/subroutine前面加上pure就可以使用pure函数,一般情况下不需要使用pure函数,它是用来配合并行运算使用的。使用pure函数有很多限制:
(1)pure函数的参数必须都是只读intent (in)。
(2)pure子程序的每个参数都要赋值属性。
(3)pure函数中不能使用save。
(4)pure函数中所含的内部函数也都必须是pure类型函数。
(5)pure函数中不能使用stop, print以及跟输入输出相关的命令如:read, write, open, close, backspace, endfile, rewind, inquire等等。
(6)pure函数中只能够读取,不能够改变全局变量的值。

   pure integer function func(...)


elemental函数:
只要在function/subroutine之前加上elemental,就可以使用elemental类型函数。这个类型的函数也可以用来作并行运算,同样有和pure函数一样的限制。它多了一个功能,可以用来做数组的设置,不过也多了一个限制,就是它的参数不能是数组。
integer a(10)
a = func(a)
!如果函数func是elemental函数,这段程序代码执行结果和下面的循环相同:
do i=1, 10
a(i) = func(a(i))
end do

!elemental函数主要就是用来配合F90可以对整个数组操作的语法来设置数组内容的。

使用elemental 函数时要先说明它的使用接口,主程序才会正确的作出设置数组的调用。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有