【Fortran】过程设计之三(函数FUNCTION)
目录
- 前言
- 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)相关推荐
- VBA学习10_子过程模块化及函数Function()
子过程和模块化 为什么使用过程 (1) 程序结构清晰 (2) 功能灵活易改 (3) 避免重复代码 代码调用 ⇒ 使用Call关键字 常省略 Sub 的本质 宏 对于代码来说就是一个过程 Sub 合并及 ...
- 【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 ...
- 【Fortran】过程设计之一(子例程SUBROUTINE)
目录 前言 Fortran子例程(SUBROUTINE) 1) 使用方式 2) 子例程示意 3) INTENT属性 4) 传递数组给子例程 4) 传递可分配数组给子例程 5) 传递字符变量给子例程 6 ...
- PX4模块设计之三十五:MulticopterAttitudeControl模块
PX4模块设计之三十五:MulticopterAttitudeControl模块 1. MulticopterAttitudeControl模块简介 2. 模块入口函数 2.1 主入口mc_att_c ...
- Oracle-存储过程、存储函数、触发器
Oracle-存储过程.存储函数.触发器 目录 文章目录 1.存储过程 1.1.概念 1.2.创建语法 1.3.实例 2.存储函数 3.out类型参数 4.存储过程与存储函数直接的区别 3.触发器 * ...
- BetaFlight模块设计之三十:Cli模块分析
BetaFlight模块设计之三十:Cli模块分析 Cli模块 Cli接口 Cli框架 Cli命令结构 主要函数分析 cliProcess函数 processCharacterInteractive函 ...
- BetaFlight模块设计之三十二:MSP协议模块分析
BetaFlight模块设计之三十二:MSP协议模块分析 1. MSP协议模块 1.1 MSP描述 1.2 MSP版本优缺点 1.3 MSP代码资源 2. MSP报文解析 2.1 MSP收包状态机 2 ...
- PX4模块设计之三十四:ControlAllocator模块
PX4模块设计之三十四:ControlAllocator模块 1. ControlAllocator模块简介 2. 模块入口函数 2.1 主入口control_allocator_main 2.2 自 ...
- Verilog语法之任务Task与函数Function
目录 1.概述 2.任务 task 2.1.任务的定义 2.2.一个task例子 3.函数 function 3.1.函数的定义 3.2.一个function例子 4.任务与函数的异同 5.总结与参考 ...
最新文章
- 在GitHub上管理项目
- Gearman的使用
- clodeblocks debug断点调试_Intellij IDEA高阶DEBUG大杀器
- raid卡的结构示意图
- Discuz! 防御CC攻击的设置办法
- oracle进程瞬间暴增,oracle goldengate ogg 源段传输进程lag延迟不断增加的原因?
- OLTP和OLAP是什么
- 修改Imdict做自己的分词器
- Android视频会议--彩蛋
- Hibernate重附(Reattach)和合并(Merge)操作的比较
- MyCat分片规则之固定hash分片
- 15+在线网页按钮生成器工具
- 计算机的输入和输出设备
- 社工小组 计算机小组活动,《社工小组活动常用游戏整理》
- 专题详解-5G接入控制:CAG新特性(3)-end
- SQL语句 SQL Server中Text类型操作
- cents OS7配置 php curl.so方法
- vue2+element使用插件导出全部表格数据
- VMware vSphere 7 vCenter 7 ESXi 7 正式版下载地址
- 天天学JAVA-JAVA基础(3)