目录

  • 前言
  • Fortran函数子程序(FUNCTION)
    • 1) 使用方式
    • 2) 使用INTENT(IN)属性
    • 3) 函数自身作为参数传递
    • 4) 传递数组给函数
    • 5) 可分配函数

前言

Fortran中,有两种不同类型的函数:内部函数和用户定义函数(函数子程序)。
内部函数是程序内置的,直接调用即可。
函数子程序FUNCTION是自定义的,用于解决内部函数无法解决的其它特性需求,同样也是一个过程(process)。


Fortran函数子程序(FUNCTION)


1) 使用方式

FUNCTION name( parameter_list )
...
(声明部分,必须声明name的类型)
type :: name
...
(执行部分)name = expression
RETURN
END FUNCTION [name]  ! []表示可选

注意事项

  • 输入参数:parameter_list ,一个或多个值,可为空(但也有留有());
  • 输出结果:name单个数值、逻辑值、字符串或数组(多个结果则应该使用子例程);
  • 在函数中,函数名name必须至少出现在赋值语句的左侧一次,当将函数返回调用程序单元时,赋给函数名的值就是函数的返回值,因此name需要声明类型;
  • 不同于模块MODULE的继承功能,在定义函数本身任何调用函数的其它程序中都需要声明函数(名)的类型,可将函数名理解成为变量名。函数类型声明:
    INTEGER FUNCTION my_func( i , j )
    

    等效于:

    FUNCTION my_func( i , j )
    INTEGER :: my_func
    

2) 使用INTENT(IN)属性

与子例程相同,函数输入数据通过参数表来传递,因此采用的是地址传递的方式,函数获取的是指向参数内存位置的指针。

因此,如果在函数中的任意一个形参出现在函数中赋值语句的左侧,则对应参数的输入变量(实参)的值将会改变。具体例子如下:求二次方程的解。

PROGRAM func_test   ! 主程序IMPLICIT NONE
REAL :: my_func   ! 记得要声明函数名的类型,因为相当于是变量
REAL ::x1,a1,b1,c1
WRITE(*,*)'分别输入二次方程的a、b、c系数:'
READ(*,*)a1,b1,c1
WRITE(*,*)'输入x值:'
READ(*,*)x1WRITE(*,*) '方程的结果为:',my_func(x1,a1,b1,c1)  ! 调用函数
WRITE(*,*)'c1的结果:',c1END PROGRAM func_test
FUNCTION my_func(x,a,b,c)   ! 函数,对形参c进行修改
IMPLICIT NONEREAL,INTENT(IN)::x,a,b
REAL::my_func
REAL::c
c=c+1        ! 形参修改
my_func = a*x**2 + b*x + c
END FUNCTION my_func

相应的结果为:

 分别输入二次方程的a、b、c系数:
1.,2.,1.,输入x值:
1.方程的结果为:   5.000000c1的结果:   2.000000     ! 发现实参c1的值也发生改变

采用INTENT(IN)属性防止出现形参修改:

FUNCTION my_func(x,a,b,c)  ! 函数,对形参修改进行控制
IMPLICIT NONEREAL,INTENT(IN)::x,a,b
REAL::my_func
REAL,INTENT(IN)::c     ! 采用INTENT(IN)防止修改形参
c=c+1                      ! 对形参进行修改
my_func = a*x**2 + b*x + c
END FUNCTION my_func

运行报错:

error #6780: A dummy argument with the INTENT(IN) attribute shall not be defined nor become undefined.   [C]

报错结果显示输入形参不能进行定义,它一定只能是输入的,不能在函数内部进行其它修改。

因此,函数应该从不修改自身的输入参数(因为可能会使输入参数的值发生改变,使得不符合预先设定的条件)。为了避免在编写函数过程中不经意地修改输入参数,应该总是使用INTENT(IN)属性来声明输入参数,具备友好的检测效果。


3) 函数自身作为参数传递

当函数a作为实参时,传递给过程A(如子例程)一个指向该函数a的指针。执行该过程A时,参数表中的函数a将作为形参进入到过程A的编译当中。

要想实现参数传递功能,必须要使用EXTERNAL属性,将函数声明为外部,此时编译器才会知道参数表中传递的是独立的已编译函数,而不是常规变量。

EXTERNAL属性需要在声明部分中使用,格式如下:

TYPE, EXTERNAL ::func_1 , func_2  !  TYPE是指具体数据类型

或者

EXTERNAL ::func_1 , func_2

4) 传递数组给函数

与子例程相同,共有三种方法,但同样建议使用显式结构和不定结构的形参数组,不使用不定大小的性参数组。具体使用实例不详述,把子例程换成是函数即可。

5) 可分配函数

函数的返回值允许有可分配属性。可以在函数内部中分配和释放,但在函数返回之前必须要分配并包含一个值。同时,需要结合显式接口。

可分配数组可以使用INTENT属性,但INTENT属性的具体参数可能会影响函数中的操作:

  • INTENT(IN),在函数中不允许对可分配数组进行重分配或者释放内存空间;
  • INTENT(INOUT),调用函数时,可以在函数中可以对可分配数组进行修改、释放内存、重分配等操作;
  • INTENT(OUT),调用函数时,可分配数组在入口处被自动释放掉,相应的数据清除掉,可以在函数中对其进行操作。

例子:

取自《Fortran for Scientists and Engineers(4th) by Stephen J. Chapman》中的9-5例题,有少量修改,复制可运行。

PROGRAM test_allocatable_function    ! 主程序USE test_module
IMPLICIT NONEINTEGER :: n = 5            ! 数组要分配的数据个数
REAL,DIMENSION(:),ALLOCATABLE :: res       ! 自动化分配res = test_alloc_fun(n)     ! 调用函数
WRITE (*,'(A,20F4.1)') '调用函数后结果为:', res
END PROGRAM test_allocatable_function
MODULE test_module   ! 显式接口
CONTAINSFUNCTION test_alloc_fun(n)     ! 函数IMPLICIT NONEINTEGER,INTENT(IN) :: n           ! 返回元素的个数REAL,ALLOCATABLE,DIMENSION(:) :: test_alloc_fun    ! 可分配一维数组,旧版分配方式! 局部变量INTEGER :: i              ! 循环下标INTEGER :: istat              ! 分配状态! 获取状态,实际在这里并没有进行大小分配IF ( ALLOCATED(test_alloc_fun) ) THENWRITE (*,'(A)') '数组分配成功!'ELSEWRITE (*,'(A)') '数组分配失败!'END IF! 分配一个有n个元素的一维数组ALLOCATE(test_alloc_fun(n), STAT=istat )! 数组初始化DO i = 1, ntest_alloc_fun(i) = 6 - iEND DO! 显示数组的内容WRITE (*,'(A,20F4.1)') '在函数中结果为:', test_alloc_funEND FUNCTION test_alloc_fun
END MODULE test_module

相应的结果为:

数组分配失败!
在函数中结果为: 5.0 4.0 3.0 2.0 1.0
调用函数后结果为: 5.0 4.0 3.0 2.0 1.0

【Fortran】过程设计之三(函数FUNCTION)相关推荐

  1. VBA学习10_子过程模块化及函数Function()

    子过程和模块化 为什么使用过程 (1) 程序结构清晰 (2) 功能灵活易改 (3) 避免重复代码 代码调用 ⇒ 使用Call关键字 常省略 Sub 的本质 宏 对于代码来说就是一个过程 Sub 合并及 ...

  2. 【Verilog 语法】~ if-else、case、for、generate、函数 function、任务 task、过程块、位宽计算、阻塞/非阻塞、时间尺度、存储器设计、

    文章目录 1. if-else 1.1 设计要点 2. case 2.1 概述 2.2 语法 2.3 注意事项 3. for 3.1 区别与其它语言的for循环 3.2 注意事项 4. generat ...

  3. 【Fortran】过程设计之一(子例程SUBROUTINE)

    目录 前言 Fortran子例程(SUBROUTINE) 1) 使用方式 2) 子例程示意 3) INTENT属性 4) 传递数组给子例程 4) 传递可分配数组给子例程 5) 传递字符变量给子例程 6 ...

  4. PX4模块设计之三十五:MulticopterAttitudeControl模块

    PX4模块设计之三十五:MulticopterAttitudeControl模块 1. MulticopterAttitudeControl模块简介 2. 模块入口函数 2.1 主入口mc_att_c ...

  5. Oracle-存储过程、存储函数、触发器

    Oracle-存储过程.存储函数.触发器 目录 文章目录 1.存储过程 1.1.概念 1.2.创建语法 1.3.实例 2.存储函数 3.out类型参数 4.存储过程与存储函数直接的区别 3.触发器 * ...

  6. BetaFlight模块设计之三十:Cli模块分析

    BetaFlight模块设计之三十:Cli模块分析 Cli模块 Cli接口 Cli框架 Cli命令结构 主要函数分析 cliProcess函数 processCharacterInteractive函 ...

  7. BetaFlight模块设计之三十二:MSP协议模块分析

    BetaFlight模块设计之三十二:MSP协议模块分析 1. MSP协议模块 1.1 MSP描述 1.2 MSP版本优缺点 1.3 MSP代码资源 2. MSP报文解析 2.1 MSP收包状态机 2 ...

  8. PX4模块设计之三十四:ControlAllocator模块

    PX4模块设计之三十四:ControlAllocator模块 1. ControlAllocator模块简介 2. 模块入口函数 2.1 主入口control_allocator_main 2.2 自 ...

  9. Verilog语法之任务Task与函数Function

    目录 1.概述 2.任务 task 2.1.任务的定义 2.2.一个task例子 3.函数 function 3.1.函数的定义 3.2.一个function例子 4.任务与函数的异同 5.总结与参考 ...

最新文章

  1. 在GitHub上管理项目
  2. Gearman的使用
  3. clodeblocks debug断点调试_Intellij IDEA高阶DEBUG大杀器
  4. raid卡的结构示意图
  5. Discuz! 防御CC攻击的设置办法
  6. oracle进程瞬间暴增,oracle goldengate ogg 源段传输进程lag延迟不断增加的原因?
  7. OLTP和OLAP是什么
  8. 修改Imdict做自己的分词器
  9. Android视频会议--彩蛋
  10. Hibernate重附(Reattach)和合并(Merge)操作的比较
  11. MyCat分片规则之固定hash分片
  12. 15+在线网页按钮生成器工具
  13. 计算机的输入和输出设备
  14. 社工小组 计算机小组活动,《社工小组活动常用游戏整理》
  15. 专题详解-5G接入控制:CAG新特性(3)-end
  16. SQL语句 SQL Server中Text类型操作
  17. cents OS7配置 php curl.so方法
  18. vue2+element使用插件导出全部表格数据
  19. VMware vSphere 7 vCenter 7 ESXi 7 正式版下载地址
  20. 天天学JAVA-JAVA基础(3)

热门文章

  1. 安卓rxjava面试,15个经典面试问题及回答思路,已拿offer
  2. 一个 Crash 引发的血案
  3. html5基础入门教程之canvas绘制图形
  4. 如何将word文字间的空格批量删除
  5. 蛋白冠™蛋白质组学技术实现快速深入精确地解析血浆蛋白质图谱
  6. selenium模拟国航滑块验证码
  7. 牛客网 德玛西亚万岁 状压DP
  8. 基础服务器 IO 模型 Proactor 模型 Reactor 模型 IO 多路复用 异步 IO 模型 Linux 服务器开发 网络编程服务器模型
  9. jQuery上传文件夹全部文件
  10. 哈尔滨工程大学自动化学院(四系)复试专业课抽题测试常问知识点!