yhyhyh
2023/01/14阅读:27主题:默认主题
Fortran学习笔记丨函数、子例行程序与模块
Fortran学习笔记丨函数、子例行程序与模块
目录:
函数与子程序
函数:FUNCTION
子(例行)程序:SUBROUTINE
语句函数
语句函数的一般形式为:
F(X1, X2, X3, ..., XN) = EXPRESSION
函数名:函数名的命名规则与变量名相同。需要先指明函数名的类型(即返回值的类型)
形式参数列表:以圆括号()
包围,里面可以没有内容,但是不能删除圆括号()
。
EXPRESSION
:不能出现函数名本身,但可以使用定义过的函数。只能有一个返回值。只能一个语句定义完。
例子:
PROGRAM E61
IMPLICIT NONE
! 检测语句函数
! 实现三角形面积的计算(海伦公式)
REAL*8 A,B,C,S,AREA
REAL*8 F1, F2
! F1是计算三角形半周长
! F2是计算三角形面积
REAL*8 X1,X2,X3,XS
! 需要在程序声明部分定义语句函数
F1(X1, X2, X3) = (X1+X2+X3)/2.0
F2(XS, X1,X2,X3) = SQRT(XS*(XS-X1)*(XS-X2)*(XS-X3))
PRINT*, "PLEASE INPUT A,B,C OF THE TRIANGULAR:"
READ(*,*) A,B,C
S = F1(A,B,C)
AREA = F2(S,A,B,C)
WRITE(*,"('THE AREA IS:',F15.8)") AREA
END PROGRAM E61
内部函数
内部函数的一般格式为:
FUNCTION <func_name>(<argument_list>)
! specification of <func_name> and <args>
! some executation...
END FUNCTION <func_name>
内部函数的特点:
-
只能被本程序调用,函数的定义与调用在
PROGRAM
以内; -
函数的返回值等于函数名,必须指定函数名的类型;或者可以另外指定返回值的名称,请检索
result
关键字的用法。 -
指定函数类型可以在函数体中进行,也可以在函数头进行;
-
函数的执行语句中不能出现函数名本身(即不能出现递归调用)
-
形式变量可以声明三种属性:
-
INTENT(IN)
:函数可以从变量获得值,但是不能改变内容 -
INTENT(OUT)
:函数可以改变变量的内容 -
INTENT(INOUT)
:函数即可以获得值、也可以改变内容
-
-
形式变量列表可以为空。(这是显而易见的、合理的)
! 在函数头定义了函数的返回值类型是REAL类型
REAL FUNCTION LARGER_VALUE()
...
END FUNCTION
! 在函数体中声明函数的返回类型
FUNCTION LARGER_VALUE()
...
REAL::LARGER_VALUE
...
END FUNCTION
内部函数举例:
PROGRAM E62
! 内部函数举例;海伦公式计算三角形面积
IMPLICIT NONE
REAL*8 A,B,C,AREA
PRINT*, "PLEASE INPUT THE A,B,C OF THE TRIANGULAR: "
READ(*,*) A,B,C
AREA = F(A,B,C)
WRITE(*,"('AREA = ',F9.3)") AREA
READ(*,*)
CONTAINS
! FUNCTION F(A,B,C)的定义
FUNCTION F(A,B,C)
REAL*8 F,A,B,C
REAL*8 S
S = (A+B+C)/2.0
F = SQRT(S*(S-A)*(S-B)*(S-C))
END FUNCTION F
END PROGRAM E62
外部函数
所谓“外部函数”,与“内部函数”对比:定义在PROGRAM
以外,且在PROGRAM
调用之前需要做声明,可以调用其他函数或调用自己。
在主程序中声明外部函数,可以用EXTERNAL
关键字,或者INTERFACE
接口块。
举例:定义了CAL_AVERAGE
与CAL_TRI_AREA
函数。在主函数的变量声明部分,需要声明函数名变量。
(1)用EXTERNAL
关键字:
REAL, EXTERNAL :: CAL_AVERAGE, CAL_TRI_AREA
或者:
EXTERNAL CAL_AVERAGE, CAL_TRI_AREA
REAL :: CAL_AVERAGE, CAL_TRI_AREA
(2)使用INTERFACE
接口块:
...
INTERFACE
REAL FUNCTION CAL_AVERAGE(A,B,C)
REAL, INTENT(IN) :: A,B,C
END FUNCTION CAL_AVERAGE
REAL FUNCTION CAL_TRI_AREA(A,B,C)
REAL, INTENT(IN) :: A,B,C
REAL :: S ! 注意,声明所有的变量,不仅是形参
END FUNCTION CAL_TRI_AREA
END INTERFACE
...
子例行程序
子例行程序的特点:
-
子例行程序常用来打印、输入、输出等操作,或者数组运算、交换数据等产生多个处理结果的操作; -
子例行程序的程序名不能作为返回值;但是可以通过形式变量对传入的值进行改变。形式变量的 INTENT
属性与函数相同。 -
外部子例行程序在 PROGRAM
中同样需要声明,声明方法与函数相同(用EXTERNAL
关键字,或者INTERFACE
接口块)。 -
子例行程序的形参列表也是用圆括号 ()
包围,但是如果没有形参,那么定义与调用时都可以省略圆括号()
。
子例行程序的调用需要用到关键字CALL
。例如:
PROGRAM E63
! 子例行程序学习;交换两个数
IMPLICIT NONE
INTERFACE
SUBROUTINE SWAP(A,B)
REAL*8,INTENT(INOUT)::A,B
REAL*8::TMP
END SUBROUTINE SWAP
END INTERFACE
REAL*8 A,B,C
PRINT*, "PLEASE INPUT 3 NUMBERS: "
READ(*,*) A,B,C
! 从小到大输出三个数
IF (A.GT.B) CALL SWAP(A,B)
IF (B.GT.C) CALL SWAP(B,C)
IF (A.GT.B) CALL SWAP(A,B)
PRINT*, 'THE NUMBERS FROM SMALL TO LARGE: '
WRITE(*,"(3(F9.3))") A,B,C
READ(*,*)
END PROGRAM E63
! 外部子例行程序SWAP
SUBROUTINE SWAP(A,B)
REAL*8,INTENT(INOUT)::A,B
REAL*8::TMP
TMP = A
A = B
B = TMP
END SUBROUTINE SWAP
模块(Module)
模块一般放在单独的源文件里面。模块的一般格式为:
MODULE <module_name>
IMPLICIT NONE
[SPECIFICATION_PART]
! 例如一些变量的声明
CONTAINS
[INTERNAL_SUBPROGRAMS]
! 例如一些function与subroutine的定义
END MODULE <module_name>
模块的使用:USE
关键词与ONLY
关键字
USE <module_name>
或者
USE <module_name>, ONLY : name_1, name_2, ...
其中的name
可以是变量或子程序。
举例(一个极简单的例子):
工作区的源文件包括:
the_modules.f90
MODULE FACT_MODULE
IMPLICIT NONE
CONTAINS
FUNCTION FACTORIAL(N)
IMPLICIT NONE
INTEGER*8,INTENT(IN)::N
INTEGER*8::FACTORIAL
INTEGER*8::FACT, I
FACT = 1
DO I=1,N
FACT = FACT * I
END DO
FACTORIAL = FACT
END FUNCTION FACTORIAL
FUNCTION C(N,R)
! 计算组合数C(N,R)
IMPLICIT NONE
INTEGER*8::C
INTEGER*8,INTENT(IN)::N,R
INTEGER*8::C_TMP
IF (0 .LT. R .AND. R .LT. N) THEN
C_TMP = FACTORIAL(N)/&
(FACTORIAL(N-R)*FACTORIAL(R))
ELSE
C_TMP = 0
! 对于无效的参数
END IF
C = C_TMP
END FUNCTION C
END MODULE FACT_MODULE
以及,
main.f90
PROGRAM MAIN
! 使用模块的方法,计算组合数
! 先引入模块,再写implicit none
USE FACT_MODULE
IMPLICIT NONE
INTEGER*8 :: N,R
INTEGER :: MASK
MASK = 1
DO
READ(*,*) N,R
IF (N>=0 .AND. R>=0) THEN
WRITE(*,"(I9,'! = ',I9)") N,FACTORIAL(N)
WRITE(*,"(I9,'! = ',I9)") R,FACTORIAL(R)
ELSE
EXIT
END IF
IF (R<=N) THEN
WRITE(*,"('C(',I6,',',I6,') = ',I9)") &
N,R,C(N,R)
ELSE
WRITE(*,*) "ERROR! C = -1"
END IF
END DO
END PROGRAM
在Windows平台用以下的命令编译:
gfortran -c the_modules.f90
gfortran -o main.exe main.f90 the_modules.o
可以得到可执行文件。
作者介绍