03-Fortran基础--Fortran函数和子程序

news2025/1/18 9:01:22

03-Fortran基础--Fortran函数和子程序

  • 0 引言
  • 1 各函数介绍
    • 1.1 函数(Functions)
    • 1.2. 子程序(Subroutines)
    • 1.3 递归函数(Recursive Functions)
    • 1.4. 泛型函数(Generic Functions)
    • 1.5. Pure 函数
    • 1.6 逐元(Element)函数
    • 1.7 抽象函数
  • 2 结语


0 引言

  在Fortran中,函数和子程序(也称为过程)是实现重复使用代码的重要方式。这部分介绍下几类函数,并提供相应的示例。

1 各函数介绍

1.1 函数(Functions)

一般形式:

FUNCTION function_name(argument1, argument2, ...)result(result_value)
    ! 声明变量
    TYPE,[intent(in/out/inout)] :: argument1, argument2, ...
    TYPE :: result_value
    TYPE :: variable1, variable2, ...
    
    ! 执行的代码
    result_value = [过程中返回]
END FUNCTION function_name

调用形式

result_value = function_name(argument1, argument2, ...)
  • FUNCTION 关键字用于声明函数。
  • function_name 是函数的名称。
  • argument1, argument2, ... 是函数的参数。
  • intent(in/out/inout) intent声明函数参数的输入、输出属性,可以省略。 如果是intent(in)表明输入参数不允许被改;intent(out)表明参数为输出参数,是要被赋值的;intent(inout)表明输入参数可被修改,也是默认参数;
  • variable1, variable2, ... 是在函数中使用的局部变量。
  • result_value 是函数的返回值。

示例:

	program test_fun
	implicit none
	real(8) :: x,y ! 函数主体中声明两个变量,x作为函数输入变量要赋初值
    
    x = 5.d0
    y = Square(x) ! 调用函数返回结果y
    print *,x,"的平方=",y ! 打印函数返回结果

contains ! 关键字:包含关系,上面program过程可以调用函数square,该写法不唯一
    
    function square(x)result(y) ! 函数部分
    real(8),intent(in) :: x     ! 声明函数输入变量x
    real(8) :: y 				! y为函数返回
    
    y = x * x
    end function Square

    end program Console1

运行结果:

  在这个示例中,Square 函数接受一个实数参数 x,并返回 x 的平方赋值给y。

1.2. 子程序(Subroutines)

一般形式:

SUBROUTINE subroutine_name(argument1, argument2, ...)
    ! 声明变量
    TYPE,intent(in/out/inout) :: variable1, variable2, ...
    ! 执行的代码
END SUBROUTINE subroutine_name

调用形式

call subroutine_name(argument1, argument2, ...)
  • SUBROUTINE 关键字用于声明子程序。
  • subroutine_name 是子程序的名称。
  • intent(in/out/inout) 声明变量输入、输出属性。
  • argument1, argument2, ... 是子程序的参数。
  • variable1, variable2, ... 是在子程序中使用的局部变量。

示例:

program test_subroutine
	implicit none
	character(len=:),allocatable :: str ! 定义一动态字符串
	str = "Li Ming"  ! 给动态字符串赋值,'='对于动态字符串或动态数组有分配空间和赋值的含义;
	call PrintHello(name)  ! 调用子过程,打印结果
	
contains

	SUBROUTINE PrintHello(name) ! 子过程
    	CHARACTER(LEN=*) :: name ! 输入参数,LEN=* 实质是传入的指针数组,获取的是传入参数的地址;
    	PRINT *, "Hello, ", name, "!"
	END SUBROUTINE PrintHello

end program

  在这个示例中,PrintHello 子程序接受一个字符串参数 name,并打印出问候语。

1.3 递归函数(Recursive Functions)

  递归函数是指调用自身的函数。它们通常用于解决可以通过反复将问题分解为更小的子问题来解决的问题,递归可以对function递归,也可以对subroutine递归。

递归函数的一般形式:

! function 递归的一般形式
recursive FUNCTION recursive_function_name(argument1, argument2, ...)result(result)
    ! 声明变量
    TYPE,intent(in/out/inout) :: argument1, argument2, ...
    TYPE :: result
    TYPE :: variable1, variable2, ...
    
    ! 基本情况(递归终止条件)
    IF (base_case_condition) THEN
        result = base_case_value
    ELSE
        ! 递归情况
        result = recursive_function_name(recursive_call_arguments)
    END IF
END FUNCTION recursive_function_name

! subroutine 递归的一般形式
recursive subroutine recursive_subroutine_name(argument1, argument2, ...)
	call recursive_subroutine_name(recursive_call_arguments)
end subroutine recursive_subroutine_name
  • recursive 关键字,声明该函数为递归函数。
  • recursive_function_name 是递归函数的名称。
  • argument1, argument2, ... 是递归函数的参数。
  • variable1, variable2, ... 是在递归函数中使用的局部变量。
  • base_case_condition 是递归函数的终止条件。
  • base_case_value 是递归函数在终止条件下返回的值。
  • recursive_call_arguments 是递归调用时传递给函数的参数。
  • result 递归函数的返回值。

以阶乘的递归函数调用过程为例:

program test_recursive
implicit none
integer :: n,fibo

n = 5
fibo = fact(n) ! 调用递归函数
print *,n,"的阶乘=",fibo

contains

recursive function fact(n)result(res)  ! 计算阶乘的递归函数
  implicit none
  integer, intent(in) :: n ! 输入参数
  integer :: res ! 返回参数
  
  if (n == 0) then 
    res = 1
  else
    res = n * fact(n-1)
  end if
end function fact

end program

1.4. 泛型函数(Generic Functions)

  在Fortran中,泛型函数允许你为相同的函数名称定义多个具有不同特征(参数类型或数目)的版本。这样可以根据参数的不同调用不同的函数版本。下面是泛型函数的一般形式和使用教程:

泛型函数的一般形式:

MODULE generic_module
    INTERFACE generic_function
        MODULE PROCEDURE :: specific_function1, specific_function2, ...
    END INTERFACE generic_function

    CONTAINS
	! 函数1
    FUNCTION specific_function1(arg1, arg2, ...)
        ! 具体实现
    END FUNCTION specific_function1
	
	! 函数2
    FUNCTION specific_function2(arg1, arg2, ...)
        ! 具体实现
    END FUNCTION specific_function2

    ! 其他具体函数的定义
END MODULE generic_module
  • MODULE 关键字用于定义模块。
  • INTERFACE 关键字用于定义泛型接口。
  • generic_function 是泛型接口的名称。
  • specific_function1, specific_function2, ...是具体函数的名称,每个具体函数都应该有特定的参数列表。

实例: 定义泛型模块和具体函数

MODULE MathFunctions
    INTERFACE GenericFunction
        MODULE PROCEDURE Add, Multiply
    END INTERFACE GenericFunction

    CONTAINS

    FUNCTION Add(a, b)
        REAL :: a, b
        Add = a + b
    END FUNCTION Add

    FUNCTION Multiply(a, b)
        REAL :: a, b
        Multiply = a * b
    END FUNCTION Multiply
END MODULE MathFunctions

使用泛型函数:

PROGRAM TestGenericFunction
    USE MathFunctions

    REAL :: x, y, result

    x = 5.0
    y = 3.0

    result = GenericFunction(x, y)
    PRINT *, "Result:", result
END PROGRAM TestGenericFunction

  在这个例子中,GenericFunction 是泛型接口,它可以根据参数类型自动选择调用 Add 还是 Multiply 函数。在 result = GenericFunction(x, y) 中,根据 x 和 y 的类型,编译器会自动选择调用适当的函数。

  泛型函数在处理不同数据类型或不同参数个数的情况下非常有用,它们提高了代码的可重用性和灵活性。

1.5. Pure 函数

  在Fortran中,PURE 函数是指不改变任何全局状态(如模块变量、共享内存等)且只依赖于其输入参数的函数。这种函数对于给定相同输入参数时始终返回相同结果,因此具有很好的可重复性和可测试性。下面是 PURE 函数的一般形式和实例:

PURE 函数的一般形式:

PURE FUNCTION pure_function_name(arg1, arg2, ...)
    ! 参数声明
    TYPE :: arg1, arg2, ...
    ! 函数体
    ! 返回值赋值
END FUNCTION pure_function_name
  • PURE 关键字用于声明函数是纯函数,即不修改全局状态。
  • pure_function_name 是纯函数的名称。
  • arg1, arg2, ... 是函数的参数。

  函数体中不能修改任何全局状态,包括不得对模块变量进行更改或调用具有SAVE属性的子程序。
实例:

program test_pure
real(8) :: x,y

x = 3.14
y = square(x) ! 函数调用
print *,x,"的平方是",y

contains
    
pure function square(x)result(res) ! 纯函数定义
    real(8),intent(in) :: x
    real(8) :: res
    
    res = x * x
end function square

end program

  这是一个简单的纯函数,计算输入参数的平方。在这个例子中,函数 Square 不改变任何全局状态,只是根据输入参数 x 计算并返回其平方。使用纯函数的好处包括:

  • 可重复性:对于相同的输入参数,纯函数始终返回相同的结果。
  • 可测试性:因为纯函数不依赖于全局状态,所以更容易进行单元测试。
  • 优化机会:编译器可以更容易地进行优化,因为它们不必考虑全局状态的影响。
  • 在编写纯函数时,要确保遵循纯函数的定义,不要修改任何全局状态,并且要确保函数的输出只依赖于其输入参数。

1.6 逐元(Element)函数

  Element 函数用于逐元素操作数组。这种函数允许对整个数组进行操作而不需要显式循环,在定义函数或子程序的时候添加Element 关键字即可,注意逐元函数的输入实际为数组的每一个元素,所以类型要一致。

示例:

program test_element
implicit none
integer :: i,j
real(8) :: x(3,3),y(3,3) ! 定义两个数组

call RANDOM_SEED()
call RANDOM_NUMBER(x) ! 给数组每一个元素赋值0-1的随机数

y = square(x) ! 调用逐元函数,给x的所有元素开平方

print *,"x"
do i = 1,size(x,1)
    print *,(x(i,j),j=1,size(x,2)) ! 打印输出
enddo
    
print *,"y"
do i = 1,size(y,1)
    print *,(y(i,j),j=1,size(y,2)) ! 打印输出
enddo

contains
    
elemental function square(x)result(res) ! 逐元函数体
    real(8),intent(in) :: x
    real(8) :: res
    
    res = x * x
end function square

end program

  上面是一个将数组中的每个元素都翻倍的 Element 函数示例。

1.7 抽象函数

  在Fortran中,抽象函数是一种允许定义函数签名但不提供具体实现的机制。抽象函数通常与抽象接口结合使用,允许编写代码时指定函数的预期行为,而不必提供具体实现。这种机制对于构建可扩展和灵活的代码库非常有用,因为它允许用户根据需要提供自定义实现,而不必修改现有代码。

下面是Fortran中抽象函数的详细介绍:

1.7.1 抽象接口
  抽象函数通常与抽象接口一起使用。抽象接口定义了函数的签名,但没有实现。这样,任何函数只要符合抽象接口定义的签名,就可以被视为抽象函数的候选实现。

abstract interface
    function MyAbstractFunction(x)
        real :: MyAbstractFunction
        real, intent(in) :: x
    end function MyAbstractFunction
end interface

1.7.2 模块化
  抽象接口通常包含在模块中,以便在程序中其他地方使用。这种模块化的方法使得抽象函数能够在整个程序中被调用和实现。

module AbstractFunctions
    implicit none

    ! 定义抽象接口
    abstract interface
        function MyAbstractFunction(x)
            real :: MyAbstractFunction
            real, intent(in) :: x
        end function MyAbstractFunction
    end interface

contains

    ! 其他子程序可以使用抽象函数
    subroutine UseAbstractFunction(func, x)
        procedure(MyAbstractFunction) :: func
        real, intent(in) :: x
        real :: result
        
        result = func(x)
        print *, "Result:", result
    end subroutine UseAbstractFunction
    
end module AbstractFunctions

1.7.3 实现调用
  具体的函数实现了抽象接口定义的签名,以满足抽象函数的要求。这些具体实现可以在程序的任何地方定义。

program test_abstract
    use AbstractFunctions
    implicit none
    
    real :: input_value = 2.0
    
    ! 将抽象函数作为参数传递
    call UseAbstractFunction(ConcreteFunction, input_value)
    
    contains
    
    ! 具体实现的函数
    function ConcreteFunction(x)result(res)
        real, intent(in) :: x
        real :: res
        
        res = x ** 2
    end function ConcreteFunction
    
end program

  通过这种方式,Fortran中的抽象函数提供了一种灵活的机制,使得代码能够轻松地适应不同的需求和实现。

2 结语

  这些是 Fortran 中常见的函数和子程序的类型和示例。它们可以帮助你编写模块化、可重用的代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1658746.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

blender 制作圆角立方体模型,倒角实现。cocos 使用。导出fbx

图片: 步骤: 1.首先创建一个立方体,这里可以使用默认的立方体。 2.在属性面板选择如“扳手”图标一样的修改器工具。 3.设置数量和段数实现圆角的圆滑效果,没有菱角。 保存导出相关的教程:

短信平台群发服务有什么优点

短信平台群发服务有什么优点 提高营销效率 短信平台群发服务利用自动化技术,可以帮助企业迅速向大量潜在客户营销信息。相比传统的逐一方式,群发服务可以同时大批目标客户,大大提高了营销效率。企业可以轻松地在短时间内覆盖更多的潜在客户&…

开源免费的定时任务管理系统:Gocron

Gocron:精准调度未来,你的全能定时任务管理工具!- 精选真开源,释放新价值。 概览 Gocron是github上一个开源免费的定时任务管理系统。它使用Go语言开发,是一个轻量级定时任务集中调度和管理系统,用于替代L…

Python 2.x与Python 3.x:初学者该如何选择?

自从Python在1994年首次发布以来,已经经历了多个版本的更新和改进。Python 1.x虽然在发展史上具有重要意义,但早已过时,不再用于实际开发。2000年发布的Python 2.x和2008年发布的Python 3.x则成为了Python家族中最常用的两个版本,形成了一个重要的分界线。特别是Python 3.x…

FPGA+HDMI转换方案,用于网络直播切换直播画面,客户应用:直播,自媒体

FPGAHDMI转换方案,用于网络直播切换直播画面 客户应用:直播,自媒体 主要功能: 1.支持多路HDMI高清输入/输出 2.支持各路输入输出灵活切换 3.支持USB接口 4.支持网口 5.支持音频输出接口 6.支持serders

吴恩达机器学习笔记:第 9 周-17大规模机器学习(Large Scale Machine Learning)17.3-17.4

目录 第 9 周 17、 大规模机器学习(Large Scale Machine Learning)17.3 小批量梯度下降17.4 随机梯度下降收敛 第 9 周 17、 大规模机器学习(Large Scale Machine Learning) 17.3 小批量梯度下降 小批量梯度下降算法是介于批量梯度下降算法和随机梯度下降算法之间的算法&…

【SRC实战】利用APP前端加密构造数据包

挖个洞先 https://mp.weixin.qq.com/s/ZnaRn222xJU0MQxWoRaiJg “ 以下漏洞均为实验靶场,如有雷同,纯属巧合” 01 — 漏洞证明 “ 参数加密的情况,不会逆向怎么办?” 1、新用户首次设置密码时抓包,此处设置为0000…

【最大公约数 唯一分解定理 调和级数】2862. 完全子集的最大元素和

本文涉及知识点 质数、最大公约数、菲蜀定理 组合数学汇总 唯一分解定理 调和级数 LeetCode2862. 完全子集的最大元素和 给你一个下标从 1 开始、由 n 个整数组成的数组。你需要从 nums 选择一个 完全集,其中每对元素下标的乘积都是一个 完全平方数,例…

《系统架构设计师教程(第2版)》第10章-软件架构的演化和维护-06-大型网站系统架构演化实例

文章目录 第一阶段:单体架构第二阶段:垂直架构第三阶段:使用缓存改善网站性能第四阶段:使用服务集群改善网站并发处理能力第五阶段:数据库读写分离第六阶段:使用反向代理和CDN加速网站响应第七阶段&#xf…

Java | Leetcode Java题解之第80题删除有序数组中的重复项II

题目&#xff1a; 题解&#xff1a; class Solution {public int removeDuplicates(int[] nums) {int n nums.length;if (n < 2) {return n;}int slow 2, fast 2;while (fast < n) {if (nums[slow - 2] ! nums[fast]) {nums[slow] nums[fast];slow;}fast;}return sl…

Sarcasm detection论文解析 |基于语义知识和辅助信息增强讽刺检测方法

论文地址 论文地址&#xff1a;https://www.sciencedirect.com/science/article/abs/pii/S0306457322000139?via%3Dihub 论文首页 笔记框架 基于语义知识和辅助信息增强讽刺检测方法 &#x1f4c5;出版年份:2022 &#x1f4d6;出版期刊:Information Processing & Managem…

CTF-Web Exploitation(持续更新)

CTF-Web Exploitation 1. GET aHEAD Find the flag being held on this server to get ahead of the competition Hints Check out tools like Burpsuite to modify your requests and look at the responses 根据提示使用不同的请求方式得到response可能会得到结果 使用…

正则表达式-前瞻和后顾

正则表达式中的前瞻和后顾。 前瞻(Lookahead) 前瞻是一种断言,它会检查在当前位置之后是否存在某种模式,但不会实际匹配该模式。前瞻有两种形式: 正向前瞻 (?pattern) 检查当前位置之后是否存在指定的模式如果存在,则匹配成功,但不会消耗该模式例如 \w(?\d) 将匹配后面跟数…

反转链表(C语言)———链表经典算法题

题目描述​​​​​​206. 反转链表 - 力扣&#xff08;LeetCode&#xff09;&#xff1a; 答案展示: 迭代&#xff1a; 递归&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* rev…

探索大型语言模型(LLM)的世界

​ 引言 大型语言模型&#xff08;LLM&#xff09;作为人工智能领域的前沿技术&#xff0c;正在重塑我们与机器的交流方式&#xff0c;在医疗、金融、技术等多个行业领域中发挥着重要作用。本文将从技术角度深入分析LLM的工作原理&#xff0c;探讨其在不同领域的应用&#xff0…

Spark云计算平台Databricks使用,创建workspace和Compute计算集群(Spark集群)

Databricks&#xff0c;是属于 Spark 的商业化公司&#xff0c;由美国加州大学伯克利 AMP 实验室的 Spark 大数据处理系统多位创始人联合创立。Databricks 致力于提供基于 Spark 的云服务&#xff0c;可用于数据集成&#xff0c;数据管道等任务。 1 创建workspace 点击创建wor…

[前后端基础]图片详解

[前后端基础]图片传输与异步-CSDN博客 https://juejin.cn/post/6844903782959022093#heading-3 base64、file和blob用JS进行互转的方法大全【前端】_js base64转blob-CSDN博客 后端存储方式 对于第一种存储方式&#xff0c;我们前端直接将存储路径赋值给 src 属性即可轻松显示。…

每天五分钟计算机视觉:使用极大值抑制来寻找最优的目标检测对象

本文重点 在目标检测领域,当模型预测出多个候选框(bounding boxes)时,我们需要一种方法来确定哪些候选框最有可能表示真实的目标。由于模型的不完美性和图像中目标的重叠性,往往会有多个候选框对应于同一个目标。此时,极大值抑制(Non-Maximum Suppression,NMS)技术就…

基于BP神经网络的16QAM解调算法matlab性能仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ........................................................... % 第一部分&#xff1a;加载并…

TMS320F280049 CLB模块--总览(0)

CLB模块是可配置的逻辑块&#xff0c;和FPGA的CLB有些不同。 下图是CLB模块在系统中的交互&#xff0c;图中CLB XBAR和TILE是CLB。从049中有4个CLB&#xff0c;也就是TILE1-4。 下图是CPU和CLB交互的示意图。 下图是CLB的时钟。 参考文档&#xff1a; TMS320F28004x Real-Tim…