Fortran-基础语法详解


Fortran简介

Fortran语言来自公式翻译系统,是一种通用的,命令式编程语言。它可用于数字和科学计算。Fortran语言最初是由IBM公司在20世纪50年代的科学和工程应用开发。 FORTRAN统治这个规划计算面积很长一段时间,因其高性能计算能力而很受欢迎。

它支持:

  • ​ 数值分析和科学计算
  • ​ 结构化程序设计
  • ​ 数组编程
  • ​ 模块化编程
  • ​ 泛型编程
  • ​ 超级计算机高性能计算
  • ​ 面向对象编程
  • ​ 并行编程
  • ​ 计算机系统之间的可移植性的合理程度

关于Fortran语言事实

  • ​ Fortran语言是由一个团队,由约翰·巴克斯带头于1957年在IBM创建。
  • ​ 最初将编写所有投资所使用的名称,但是目前的标准和实现只需要第一个字母要大写。
  • ​ Fortran语言表示的公式转换器。
  • ​ 最初是为科学计算开发的,它必须为字符串,需要通用编程等结构的支持非常有限。
  • ​ 后来延伸和发展使其成为一个高层次的编程语言,可移植性好度。
  • ​ 原来的版本,Fortran语言I,II和III 现在认为是过时的。
  • ​ 最早的版本仍然在使用 Fortran IV和Fortran 66。
  • ​ 最常用的版本,现在用的是:Fortran 77,Fortran 90,和Fortran95。
  • ​ Fortran 77 添加字符串作为一个独立的类型。
  • ​ Fortran 90 加入形形色色的线程,并直接数组处理。

Fortran语言环境设置

在Windows上设置Fortran语言环境

G95是GNU Fortran语言多架构的编译器,用于建立Fortran语言在Windows中。 Windows版本的模拟使用MingW平台下的Windows UNIX环境。安装完成这个功能,并自动添加G95到Windows PATH变量。

可以从G95的稳定版这里得到:

installer setup

mini installer setup

如何使用G95

在安装过程中,G95会自动添加到PATH变量中,如果选择“RECOMMENDED”选项。这意味着,可以简单地打开一个新的命令提示符窗口,输入“G95”,弹出的编译器。找到一些基本的命令,我们现在就开始吧。

命令 描述
g95 –c hello.f90 编译hello.f 90到目标文件命名为hello.o
g95 hello.f90 编译hello.f 90并链接到生成可执行的a.out 文件
g95 -c h1.f90 h2.f90 h3.f90 编译多个源文件。如果一切顺利的话,目标文件h1.o,h2.o和h3.o创建
g95 -o hello h1.f90 h2.f90 h3.f90 编译多个源文件并将它们链接在一起,命名为’hello’的可执行文件

G95的命令行选项:

-c Compile only, do not run the linker.
-o Specify the name of the output file, either an object file or the executable.

多个源文件和目标文件可以一次指定。 Fortran文件由名称”.f”, “.F”, “.for”, “.FOR”, “.f90”, “.F90”, “.f95”, “.F95”, “.f03” and “.F03”.“。对于”结尾表示多个源文件可以被指定。目标文件可以被指定为良好,将被链接以形成一个可执行文件。

Fortran基本语法

Fortran程序是由程序单元,如一个主程序,模块和外部子程序或程序的集合。

每个程序包括一个主程序和可以或可以不包含其它程序单元。主程序的语法如下:

program program_name
implicit none      

! type declaration statements      
! executable statements  

end program program_name

一个简单的Fortran程序

让我们来写一个程序,相加了两个数字,并打印出结果:

program addNumbers

! This simple program adds two numbers     
   implicit none

! Type declarations
   real :: a, b, result 

! Executable statements 
   a = 12.0
   b = 15.0
   result = a + b
   print *, 'The total is ', result                   

end program addNumbers        

当编译并执行上述程序,它会产生以下结果:

The total is 27.0000000    

请注意:

  • ​ 所有Fortran程序start关键字程序和end关键字结束程序,然后是该程序的名称。
  • ​ 隐无语句允许编译器检查所有的变量类型是正确声明。必须始终使用无隐在每个程序的开始。
  • ​ 在Fortran语言注释开始使用感叹号(!),因为在这之后的所有字符(除字符串)被编译器忽略。
  • ​ print*命令在屏幕上显示数据。
  • ​ 代码行缩进,是保持一个程序读取一个很好的做法。
  • ​ Fortran语言允许大写和小写字母。 Fortran语言是区分大小写的,除了字符串常量。

基础知识

Fortran语言的基本字符集包括:

  • ​ 字符包括 A … Z 和 a … z
  • ​ 数字 0 … 9
  • ​ 下划线(_)字符
  • ​ 特殊字符 = : + 空格- * / ( ) [ ] , . $ ‘ ! “ % & ; < > ?

令牌Tokens基本字符集中的字符。令牌可以是一个关键字,标识符,常量,字符串文字或符号。

程序语句作出标记。

标识符

一个标识符是用于标识一个变量,过程或任何其它用户定义的项目的名称。在Fortran语言中名称必须遵循以下规则:

  • ​ 它不能超过31个字符长。
  • ​ 它必须由字母数字字符(字母的所有字母,以及数字0到9)和下划线(_)。
  • ​ 名称第一个字符必须是字母。
  • ​ 名称是区分大小写

关键字

关键字是特殊的词语,这些是语言预留的。这些保留字不能用作标识符或名称。

下表列出了Fortran关键字:


非I/O相关关键字
allocatable allocate assign assignment block dat
call case character common complex
contains continue cycle data deallocate
default do double precision else else if
elsewhere end block data end do end function end if
end interface end module end program end select end subroutine
end type end where entry equivalence exit
external function go to if implicit
in inout integer intent interface
intrinsic kind len logical module
namelist nullify only operator optional
out parameter pause pointer private
program public real recursive result
return save select case stop subroutine
target then type type() use
Where While
I/O相关的关键字
backspace close endfile format inquire
open print read rewind Write

Fortran数据类型

Fortran语言提供了五种内在数据类型,但是,也可以得到自己的数据类型。这五个固有的类型有:

  • ​ 整型
  • ​ 实型
  • ​ 复杂类型
  • ​ 逻辑类型
  • ​ 字符类型

整型

整数类型只能容纳整数值。下面的示例中提取,可以在通常为4字节整数保存最大值:

program testingInt
implicit none

   integer :: largeval
   print *, huge(largeval)

end program testingInt

当编译并执行上述程序也将产生以下结果:

2147483647

需要注意的是huge()函数,可以通过特定的整数数据类型可以保持的最大数目。还可以指定使用的字节数。下面的例子说明了这一点:

program testingInt
implicit none

   !two byte integer
   integer(kind=2) :: shortval

   !four byte integer
   integer(kind=4) :: longval

   !eight byte integer
   integer(kind=8) :: verylongval

   !sixteen byte integer
   integer(kind=16) :: veryverylongval

   !default integer 
   integer :: defval

   print *, huge(shortval)
   print *, huge(longval)
   print *, huge(verylongval)
   print *, huge(veryverylongval)
   print *, huge(defval)

end program testingInt

当编译并执行上述程序,它会产生以下结果:

32767
2147483647
9223372036854775807
170141183460469231731687303715884105727
2147483647

实型

它存储的浮点数,例如2.0,3.1415,-100.876等

传统上有两种不同的实际类型,默认实型和双精度型。

然而,Fortran语言90/95提供了更多的控制权实数和整数数据类型,通过种类说明,我们将在对数的章节研究精度。

下面的例子展示了如何使用实数类型:

program division   
implicit none  

   ! Define real variables   
   real :: p, q, realRes 

   ! Define integer variables  
   integer :: i, j, intRes  

   ! Assigning  values   
   p = 2.0 
   q = 3.0    
   i = 2 
   j = 3  

   ! floating point division
   realRes = p/q  
   intRes = i/j

   print *, realRes
   print *, intRes

end program division  

当编译并执行上述程序也将产生以下结果:

0.666666687    
0

复杂类型

这被用于存储复数。一个复杂的数字有两部分,实数部分和虚数部分。两个连续的数字存储单元存储两个部分。

例如,该复数(3.0,-5.0)等于3.0 - 5.0i

我们将更详细地讨论复杂类型,在数字章节。

逻辑类型

只有两个逻辑值:.true. 和.false

字符类型

字符类型存储字符和字符串。字符串的长度可以通过len个符来指定。如果没有指定长度,它是1。

例如,

character (len=40) :: name  
name = “Zara Ali”

表达式name(1:4)将得到的子串“Zara”。

隐式类型

Fortran语言的旧版本允许一个叫做隐式类型,也就是说,不必在使用前声明变量的功能。如果一个变量没有声明,则其名称为第一个字母,将确定其类型。

其中i的变量名以 i, j, k, l, m, 或 n 开始,被认为是为整数变量,其余都是实型变量。但是,必须声明所有的变量,因为它是良好的编程习惯。开始程序如下:

implicit none

这条语句将关闭隐式类型。

Fortran变量

变量是只不过给定到存储区域,我们的程序可以操作的名称。每个变量都应该具有特定的类型,它决定了大小和变量的存储器的布局; 存储器内存储的值的范围; 和设置操作,可以变化应用。

一个变量名可以由字母,数字和下划线字符。在Fortran语言的名称必须遵循以下规则:

  • ​ 它不能超过31个字符长度。
  • ​ 它必须由字母数字字符(字母的所有字母,以及数字0到9)和下划线(_)。
  • ​ 名称第一个字符必须是字母。
  • ​ 名称是区分大小写的。

基于基本类型前一章介绍,以下是该变量的类型:

类型 描述
整型 它只能容纳整数值
实型 它存储浮点数
复数 它被用于存储复数.
逻辑 它存储逻辑布尔值
字符 它存储的字符或字符串。

变量声明

变量是在一个程序(或子程序)的类型声明语句的开头声明。

变量声明语法如下:

type-specifier :: variable_name

例如,

integer :: total      
real :: average 
complex :: cx  
logical :: done 
character(len=80) :: message ! a string of 80 characters

稍后,可以将值分配给这些变量一样,

total = 20000  
average = 1666.67   
done = .true.   
message = “A big Hello from Tutorials Point” 
cx = (3.0, 5.0) ! cx = 3.0 + 5.0i

也可以使用内部函数cmplx,把值赋给一个复杂的变量:

cx = cmplx (1.0/2.0, -7.0) ! cx = 0.5 – 7.0i 
cx = cmplx (x, y) ! cx = x + yi

例子

下面的例子演示了变量声明,赋值显示在屏幕上:

program variableTesting
implicit none

   ! declaring variables
   integer :: total      
   real :: average 
   complex :: cx  
   logical :: done 
   character(len=80) :: message ! a string of 80 characters

   !assigning values
   total = 20000  
   average = 1666.67   
   done = .true.   
   message = "A big Hello from Tutorials Yiibai" 
   cx = (3.0, 5.0) ! cx = 3.0 + 5.0i

   Print *, total
   Print *, average
   Print *, cx
   Print *, done
   Print *, message

end program variableTesting

让我们编译和运行上面的程序,这将产生以下结果:

20000
1666.67004    
(3.00000000, 5.00000000 )
T
A big Hello from Tutorials Yiibai    

Fortran常量

常量指的是该程序不能在其执行期间改变的固定值。这些固定的值也被称为文字。

常量可以是任何像一个整数的基本数据类型的常量,浮点常量,字符常量,复杂的常量或一个字符串字面量。只有两个逻辑常量:.true. 和 .false.

常量被视为就像普通的变量,但它们的值无法定义后进行修改。

命名常量和文字

有两种类型的常量:

  • ​ 字面常量
  • ​ 命名常量

一个字面常量有值,但没有名字。

例如,以下是文字常量:

类型 例子
整型常量 0 1 -1 300 123456789
实型常量 0.0 1.0 -1.0 123.456 7.1E+10 -52.715E-30
复数常量 (0.0, 0.0) (-123.456E+30, 987.654E-29)
逻辑常量 .true. .false.
字符常量 “PQR” “a” “123’abc$%#@!” “ a quote “” “ ‘PQR’ ‘a’ ‘123”abc$%#@!’ ‘ an apostrophe ‘’ ‘

命名常量的值和名称。

命名常量应该在程序或过程的开始声明,就像一个变量的类型声明,说明其名称和类型。命名常量与参数属性声明。例如,

real, parameter :: pi = 3.1415927

例子

下面的程序计算的位移,由于重力作用下垂直运动。

program gravitationalDisp

! this program calculates vertical motion under gravity 
implicit none  

   ! gravitational acceleration
   real, parameter :: g = 9.81   

   ! variable declaration
   real :: s ! displacement   
   real :: t ! time  
   real :: u ! initial speed  

   ! assigning values 
   t = 5.0   
   u = 50  

   ! displacement   
   s = u * t - g * (t**2) / 2  

   ! output 
   print *, "Time = ", t
   print *, 'Displacement = ',s  

end program gravitationalDisp

当上述代码被编译和执行时,它产生了以下结果:

Time = 5.00000000    
Displacement = 127.374992    

Fortran运算符

运算符是一个符号,它告诉编译器执行特定的数学或逻辑操作。 Fortran语言为运算符提供了以下几种类型:

  • ​ 算术运算符
  • ​ 关系运算符
  • ​ 逻辑运算符

让我们一个接一个来看看所有这些类型的运算符。

算术运算符

下表列出了所有Fortran语言支持的算术运算符。假设变量A=5和变量B=3则:

运算符 描述 例子
+ 加法运算符,相加两个操作数。 A + B = 8
- 减法运算,第一减去第二操作数。 A - B = 2
* 乘法运算符,相乘两个操作数。 A * B = 15
/ 除法运算符,通过分子除以分母。 A / B = 1
** 乘方运算,计算一个操作数的幂。 A ** B = 125

关系运算符

下表列出了所有Fortran语言支持的关系运算符。假设变量A=10和变量B=20,则:

操作符 等量 描述 示例
== .eq. 检查两个操作数的值相等与否,如果是,则条件变为真。 (A == B) 不为 true.
/= .ne. 检查,两个操作数的值相等与否,如果值不相等,则条件变为真。 (A != B) 为 true.
> .gt. 检查,左操作数的值是否大于右操作数的值,如果是的话那么条件为真。 (A > B) 不为true.
< .lt. 检查,左操作数的值是否小于右操作数的值,如果是的话那么条件为真。 (A < B) 为 true.
>= .ge. 检查,左边的操作数的值是否大于或等于右操作数的值,如果是,则条件变为真。 (A >= B) 不为 true.
<= .le. 检查,左边的操作数的值是否小于或等于右操作数的值,如果是,则条件变为真。 (A <= B) 为 true.

逻辑运算符

逻辑运算符在Fortran语言工作只能在逻辑值.true. 和.false。

下面的表列出了所有由Fortran语言支持的逻辑运算符。假设变量A=.true。和变量B=.false ,则:

操作符 描述 示例
.and. 所谓逻辑与运算符。如果这两个操作数都为非零,则条件变为真。 (A .and. B) 为 false.
.or. 所谓逻辑OR运算符。如果有两个操作数不为零,则条件变为真。 (A .or. B) 为 true.
.not. 所谓逻辑非运算符。使用反转操作数的逻辑状态。如果条件为真,则逻辑非运算符将返回false。 !(A .and. B) 为 true.
.eqv. 所谓逻辑上相当于运算符。用于检查两个逻辑值等价。 (A .eqv. B) 为 false.
.neqv. 所谓逻辑非对等操作。用于检查两个逻辑值的非对等。 (A .neqv. B) 为 true.

Fortran语言运算符优先级

运算符优先级来确定条件的表达式中的分组。这会影响一个表达式的求值。某些运算符的优先级高于其他;例如,乘法运算符的优先级比加法运算符更高。

例如x= 7+ 3* 2;这里,x被赋值13,而不是20,因为运算符*的优先级高于+,所以它首先被乘以3 * 2,然后再加上7。

这里,具有最高优先级运算符出现在表的顶部,那些具有最低出现在底部。在一个表达式,更高的优先级运算符将首先计算。

分类 运算符 关联
逻辑NOT和负号 .not. (-) 从左到右
** 从左到右
* / 从左到右
+ - 从左到右
关系 < <= > >= 从左到右
相等 == != 从左到右
逻辑与 .and. 从左到右
逻辑或 .or. 从左到右
赋值 = 从右到左

Fortran选择决策

决策结构需要程序员指定的一个或多个条件进行评估计算或由程序进行测试,如果该条件被确定为真,则一条或多条语句将被执行,如果要被执行的其它语句条件被确定为假的则选择其它语句块。

以下是在大多数编程语言中的一个典型的决策结构的一般形式:

Decision Making

Fortran提供决策构建以下类型。

语句 描述
If… then 结构 if… then… end if 语句由一个逻辑表达式后跟一个或多个语句。
If… then…else 结构 if… then语句可以后跟一个可选的 else statement, 它执行时,逻辑表达式为假。
if…else if…else 结构 if 语句构建体可具有一个或多个可选的 else-if 结构。当 if 条件不满足,则紧跟 else-if 执行。当 else-if 还失败,其继续 else-if 语句(如果有的话)被执行,依此类推。
内嵌 if 结构 可以使用一个 ifelse if 语句在另外一个 ifelse if 语句内部
select case 语句 Select Case语句允许一个变量的值对的列表,平等进行测试。
内嵌select case 结构 可以使用一个SELECT CASE语句中的另一个选择case语句。

Fortran if…then语句结构

if … then 语句由一个逻辑表达式后跟一个或多个语句和终止 end if 语句。

语法

if… then 语句的基本语法:

if (logical expression) then      
   statement  
end if

但是可以给一个名称,if 块,那么语法命名 if 语句如下:

[name:] if (logical expression) then      
   ! various statements           
   . . .  
end if [name]

如果逻辑表达式的计算结果为true,那么块代码内的 if … then 语句会被执行。如果在结束后的逻辑表达式计算为false,那么第一个代码块之后的 if 语句会被执行。

流程图:

示例 1

program ifProg
implicit none
   ! local variable declaration
   integer :: a = 10

   ! check the logical condition using if statement
   if (a < 20 ) then

   !if condition is true then print the following 
   print*, "a is less than 20"
   end if

   print*, "value of a is ", a
 end program ifProg

当上述代码被编译和执行时,它产生了以下结果:

a is less than 20
value of a is 10

示例 2

这个例子说明了命名的 if 块:

program markGradeA  
implicit none  
   real :: marks
   ! assign marks   
   marks = 90.4
   ! use an if statement to give grade

   gr: if (marks > 90.0) then  
   print *, " Grade A"
   end if gr
end program markGradeA   

当上述代码被编译和执行时,它产生了以下结果:

Grade A

Fortran if…then…else 结构

if… then 语句可以后跟一个可选的 else 语句, 它执行时,逻辑表达式为假。

语法

if… then… else 的基本语法:

if (logical expression) then      
   statement(s)  
else
   other_statement(s)
end if

但是,如果给定 if 块一个名字,然后命名 if-else 语句的语法是,这样的:

[name:] if (logical expression) then      
   ! various statements           
   . . . 
   else
   !other statement(s)
   . . . 
end if [name]

如果逻辑表达式的计算结果为代码里面的 if … then 语句会被执行,对 else 块中的代码,否则该块将被执行 else 块。

流程图

示例

program ifElseProg
implicit none
   ! local variable declaration
   integer :: a = 100

   ! check the logical condition using if statement
   if (a < 20 ) then

   ! if condition is true then print the following 
   print*, "a is less than 20"
   else
   print*, "a is not less than 20"
   end if

   print*, "value of a is ", a

end program ifElseProg

当上述代码被编译和执行时,它产生了以下结果:

a is not less than 20
value of a is 100

Fortran if…else if…else 语句

Fortran if…else if…else 语句

if语句构建体可具有一个或多个可选的 else-if 结构。当 if 条件不满足,则紧跟的 else-if 被执行。当 else-if 还是失败,其继续下一个 else-if 语句(如果有的话)被执行,依此类推。

可选的 else 被放置在末端,当上述条件不为真时则执行。

  • ​ 所有 else 语句 (else-if 和 else)都是可选的。
  • ​ else-if 可以使用一次或多次
  • ​ else 必须始终被放置在构建体的末端,应该只出现一次。

语法:

if…else if…else 语句的语法是:

[name:] 
if (logical expression 1) then 
   ! block 1   
else if (logical expression 2) then       
   ! block 2   
else if (logical expression 3) then       
   ! block 3  
else       
   ! block 4   
end if [name]

示例

program ifElseIfElseProg
implicit none

   ! local variable declaration
   integer :: a = 100

   ! check the logical condition using if statement
   if( a == 10 ) then

      ! if condition is true then print the following 
      print*, "Value of a is 10" 

   else if( a == 20 ) then

      ! if else if condition is true 
      print*, "Value of a is 20" 

   else if( a == 30 ) then

      ! if else if condition is true  
      print*, "Value of a is 30" 

   else

      ! if none of the conditions is true 
      print*, "None of the values is matching" 

   end if

   print*, "exact value of a is ", a

end program ifElseIfElseProg

当上述代码被编译和执行时,它产生了以下结果:

None of the values is matching
exact value of a is 100

Fortran嵌套if结构

可以使用一个 if 或else if 在另一个if或else if语句中。

语法

嵌套if语句的语法如下:

if ( logical_expression 1) then
   !Executes when the boolean expression 1 is true if(logical_expression 2)then 
   ! Executes when the boolean expression 2 is true end if
end if

例子

program nestedIfProg
implicit none
   ! local variable declaration
   integer :: a = 100, b= 200

   ! check the logical condition using if statement
   if( a == 100 ) then

   ! if condition is true then check the following 

   if( b == 200 ) then

   ! if inner if condition is true 
   print*, "Value of a is 100 and b is 200" 

   end if
   end if

   print*, "exact value of a is ", a
   print*, "exact value of b is ", b

end program nestedIfProg

当上述代码被编译和执行时,它产生了以下结果:

Value of a is 100 and b is 200
exact value of a is 100
exact value of b is 200

Fortran select case结构

select case 语句允许一个变量,列表进行相等测试。每个值被称为一个情况,在该变量上检查每个选择的情况 select case 。

语法

select case结构的语法如下:

[name:] select case (expression) 
   case (selector1)          
   ! some statements          
   ... case (selector2)           
   ! other statements           
   ...       
   case default          
   ! more statements          
   ...   
end select [name]

以下规则适用于select语句:

  • ​ 在select 语句中使用的逻辑表达式可以是逻辑型,字符型或整型(但不是实型)的表达式。
  • ​ 可以有任意数量的范围内选择一个case语句。每一种情况下后跟的值进行比较,以及可能是合乎逻辑的,字符或整数(但不是真正的)的表达,并确定哪个语句被执行。
  • ​ 恒定表达的情况下,必须具有相同的数据类型,如在选择的变量,并且它必须是一个常量或文字。
  • ​ 当被选择的变量等于以下这种情况的某一情况,该语句将执行,如果没有匹配,那直到下一个case语句为止。
  • ​ 如果在选择的情况下(表达式)表达式不匹配任何的选择了,那么 default 块被执行。

流程图

示例 1

program selectCaseProg
implicit none

   ! local variable declaration
   character :: grade = 'B'

   select case (grade)

      case ('A') 
      print*, "Excellent!" 

      case ('B')

      case ('C') 
         print*, "Well done" 

      case ('D')
         print*, "You passed" 

      case ('F')
         print*, "Better try again" 

      case default
         print*, "Invalid grade" 

   end select

   print*, "Your grade is ", grade 

end program selectCaseProg

当上述代码被编译和执行时,它产生了以下结果:

Your grade is B

指定一个范围的选择

可以选择指定一个范围,通过指定上限和下限由冒号分隔:

case (low:high) 

下面的例子说明了这一点:

示例 2

program selectCaseProg
implicit none

   ! local variable declaration
   integer :: marks = 78

   select case (marks)

      case (91:100) 
         print*, "Excellent!" 

      case (81:90)
         print*, "Very good!"

      case (71:80) 
         print*, "Well done!" 

      case (61:70)
         print*, "Not bad!" 

      case (41:60)
         print*, "You passed!"  

      case (:40)
         print*, "Better try again!"  

      case default
         print*, "Invalid marks" 

   end select
   print*, "Your marks is ", marks

end program selectCaseProg

当上述代码被编译和执行时,它产生了以下结果:

Well done!
Your marks is 78

Fortran嵌套select case结构

可以在一个select case语句内嵌另一个选择case语句。

语法

select case(a) 

   case (100) 
      print*, "This is part of outer switch", a 

   select case(b) 
      case (200)
         print*, "This is part of inner switch", a 

   end select

end select

​ 例子

program nestedSelectCase
   ! local variable definition 
   integer :: a = 100
   integer :: b = 200

   select case(a) 
      case (100) 
         print*, "This is part of outer switch", a 

      select case(b) 
         case (200)
            print*, "This is part of inner switch", a 
      end select

   end select

   print*, "Exact value of a is : ", a 
   print*, "Exact value of b is : ", b 

end program nestedSelectCase

当上述代码被编译和执行时,它产生了以下结果:

This is part of outer switch 100
This is part of inner switch 100
Exact value of a is : 100
Exact value of b is : 200

Fortran循环

可能有一种情况,当需要执行代码块多数。在一般情况下,语句顺序执行:在一个函数的第一条语句,首先执行,然后是第二个。。。等等。

编程语言提供了多种控制结构,使更复杂的执行路径。

循环语句允许我们执行语句的语句多次或组,然后下面是在大多数的编程语言中的循环语句的一般形式为:

If Conditional

Fortran语言提供了循环结构的以下类型的循环处理的要求。点击以下链接,查看其详细信息。

循环类型 描述
do循环 该构建体使得语句或一系列语句迭代进行,当一个给定的条件为真。
do while循环 重复声明语句或一组,当给定的条件为真。它测试的条件执行循环体之前。
内嵌循环 可以使用一个或多个循环结构在其他循环结构里面。

循环控制语句

循环控制语句改变其正常的顺序执行。当执行离开循环范围,在该范围内创建的所有对象自动销毁。

Fortran语言支持以下控制语句。点击以下链接,查看其详细信息。

控制语句 描述
exit 如果被执行exit语句则会退出该循环,并且该程序的继续执行第一个可执行语句结束之后的语句执行。
cycle 如果执行了一个循环语句,则程序继续到下一次迭代的起始位置。
stop 如果想执行的程序停止,可以插入声明一个stop语句

Fortran do循环结构

do循环结构使得一个语句或一系列语句,以进行迭代,当一个给定的条件为真。

语法

do循环的一般形式是:

do var = start, stop [,step]    
   ! statement(s)end do

这里,

  • ​ 循环变量var应该是一个整数
  • ​ start 是初始值
  • ​ stop 是最终值
  • ​ 步骤step是递增,如果此被省略,则变量var以单位增加

例如:

! compute factorials
do n = 1, 10
   nfact = nfact * n  
   ! printing the value of n and its factorial
   print*,  n, " ", nfact   
end do

流程图

这里是控制 do 循环结构的流程:

  • ​ 初始步骤首先被执行,并且仅一次。这一步可以声明和初始化任何循环控制变量。在我们的例子中,变量var被初始化开始的值。
  • ​ 接下来,计算条件。如果为true,则执行循环体。如果是假,则循环体不执行,只是在循环之后流量控制跳转到下一个语句。在我们的情况下,该条件就是在变量var达到其最终值stop。
  • ​ 所述循环体执行后,控制流跳转回至increment 语句。这个语句可以更新循环控制变量var。
  • ​ 条件现在重新评估。如果为true,循环执行的过程重复(循环体,再递增一步,然后再条件)。直到条件为假,循环终止。

Do Loop

示例 1

这个例子将输出数字11到20:

program printNum 
implicit none  

   ! define variables
   integer :: n

   do n = 11, 20     
      ! printing the value of n 
      print*,  n 
   end do 

end program printNum  

让我们编译和运行上面的程序,这将产生以下结果:

11
12
13
14
15
16
17
18
19
20

实例 2

这个程序计算数字1到10的阶乘:

program factorial  
implicit none  

   ! define variables
   integer :: nfact = 1   
   integer :: n  

   ! compute factorials   
   do n = 1, 10      
      nfact = nfact * n 
      ! print values
      print*,  n, " ", nfact   
   end do 

end program factorial  

让我们编译和运行上面的程序,这将产生以下结果:

1         1
2         2
3         6
4        24
5       120
6       720
7      5040
8     40320
9    362880
10  3628800

Fortran do…while循环结构

它重复语句或一组语句,当给定的条件为真。它测试的条件执行在循环体之前。

语法

do while (logical expr) 
   statements
end do

流程图

do while

示例

program factorial  
implicit none  

   ! define variables
   integer :: nfact = 1   
   integer :: n = 1 

   ! compute factorials   
   do while (n <= 10)       
      nfact = nfact * n 
      n = n + 1
      print*,  n, " ", nfact   
   end do 
end program factorial  

当上述代码被编译和执行时,它产生了以下结果:

1         1
2         2
3         6
4        24
5       120
6       720
7      5040
8     40320
9    362880
10  3628800

Fortran嵌套循环

可以在一个或多个循环结构嵌套任何另一个循环结构。也可以把标签放到循环中。

语法

iloop: do i = 1, 3
   print*, "i: ", i

   jloop: do j = 1, 3         
      print*, "j: ", j         

      kloop: do k = 1, 3
         print*, "k: ", k

      end do kloop
   end do jloop  
end do iloop

实例

program nestedLoop 
implicit none

   integer:: i, j, k

   iloop: do i = 1, 3      
      jloop: do j = 1, 3         
         kloop: do k = 1, 3              

            print*, "(i, j, k): ", i, j, k               

         end do kloop       
      end do jloop
   end do iloop

end program nestedLoop  

当上述代码被编译和执行时,它产生了以下结果:

(i, j, k): 1  1  1
(i, j, k): 1  1  2
(i, j, k): 1  1  3
(i, j, k): 1  2  1
(i, j, k): 1  2  2
(i, j, k): 1  2  3
(i, j, k): 1  3  1
(i, j, k): 1  3  2
(i, j, k): 1  3  3
(i, j, k): 2  1  1
(i, j, k): 2  1  2
(i, j, k): 2  1  3
(i, j, k): 2  2  1
(i, j, k): 2  2  2
(i, j, k): 2  2  3
(i, j, k): 2  3  1
(i, j, k): 2  3  2
(i, j, k): 2  3  3
(i, j, k): 3  1  1
(i, j, k): 3  1  2
(i, j, k): 3  1  3
(i, j, k): 3  2  1
(i, j, k): 3  2  2

Fortran exit语句

Exit语句终止循环或select case语句,并将执行立即循环或select 下面的语句。

流程图

Exit Statement

例子

program nestedLoop 
implicit none

integer:: i, j, k
   iloop: do i = 1, 3      
      jloop: do j = 1, 3         
         kloop: do k = 1, 3    

         print*, "(i, j, k): ", i, j, k               

         if (k==2) then
            exit jloop 
         end if

         end do kloop       
      end do jloop  
   end do iloop 

end program nestedLoop  

​ 当上述代码被编译和执行时,它产生了以下结果:

(i, j, k): 1  1  1
(i, j, k): 1  1  2
(i, j, k): 2  1  1
(i, j, k): 2  1  2
(i, j, k): 3  1  1
(i, j, k): 3  1  2

Fortran Cycle语句

cycle语句使循环跳过它的主体的其余部分,并立即重新测试其条件在声明之前。

流程图

Cycle Statement

例子

program cycle_example     
implicit none      

   integer :: i     

   do i = 1, 20          

      if (i == 5) then 
         cycle          
      end if         

   print*, i      
   end do  

end program cycle_example

​ 当上述代码被编译和执行时,它产生了以下结果:

1
2
3
4
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Fortran Stop语句

如果想执行的程序停止,可以插入一个stop语句。

示例

program stop_example     
implicit none

   integer :: i     
   do i = 1, 20          

      if (i == 5) then 
         stop          
      end if         

      print*, i      
   end do  

end program stop_example

当上述代码被编译和执行时,它产生了以下结果:

1
2
3
4

Fortran数字

Fortran的数字由三个内部数据类型来表示:

  • ​ 整型
  • ​ 实型
  • ​ 复杂类型

整型

整数类型只能容纳整数值。下面的例子中提取的是持有一个通常的4字节整数的最大值:

program testingInt
implicit none

   integer :: largeval
   print *, huge(largeval)

end program testingInt

当编译并执行上述程序,将产生以下结果:

2147483647

请注意,huge()函数给出能够由特定的整数数据类型可以保持的最大数字。还可以指定使用的那种符的字节数。下面的例子说明了这一点:

program testingInt
implicit none

   !two byte integer
   integer(kind=2) :: shortval

   !four byte integer
   integer(kind=4) :: longval

   !eight byte integer
   integer(kind=8) :: verylongval

   !sixteen byte integer
   integer(kind=16) :: veryverylongval

   !default integer 
   integer :: defval

   print *, huge(shortval)
   print *, huge(longval)
   print *, huge(verylongval)
   print *, huge(veryverylongval)
   print *, huge(defval)

end program testingInt

​ 当编译并执行上述程序,将产生以下结果:

32767
2147483647
9223372036854775807
170141183460469231731687303715884105727
2147483647

实型

它存储的浮点数,例如 2.0,3.1415,-100.876等

传统上有两种不同类型的实型:缺省的实型和双精度型。

然而,Fortran 90/95提供了更多的控制权实数和整数数据类型,通过一种说明,我们将在较短期内学习研究精度。

下面的例子展示了如何使用实型的数据类型:

program division   
implicit none

   ! Define real variables   
   real :: p, q, realRes 

   ! Define integer variables  
   integer :: i, j, intRes  

   ! Assigning  values   
   p = 2.0 
   q = 3.0    
   i = 2 
   j = 3  

   ! floating point division
   realRes = p/q  
   intRes = i/j

   print *, realRes
   print *, intRes

end program division  

当编译并执行上述程序,将产生以下结果:

0.666666687    
0

复杂类型

这被用于存储复数。一个复杂的数字有两部分:实部和虚部。两个连续的数字存储单元存储两个部分。

例如,该复数(3.0,-5.0)等于3.0 - 5.0i

通用函数cmplx() 创建一个复数。它产生的结果是实部和虚部,不论输入参数的类型的单精度。

program createComplex
implicit none

   integer :: i = 10
   real :: x = 5.17
   print *, cmplx(i, x)

end program createComplex

当编译并执行上述程序,将产生以下结果:

(10.0000000, 5.17000008)

下面的程序演示的复杂数字运算:

program ComplexArithmatic
implicit none

   complex, parameter :: i = (0, 1)   ! sqrt(-1)   
   complex :: x, y, z 

   x = (7, 8); 
   y = (5, -7)   
   write(*,*) i * x * y

   z = x + y
   print *, "z = x + y = ", z

   z = x - y
   print *, "z = x - y = ", z 

   z = x * y
   print *, "z = x * y = ", z 

   z = x / y
   print *, "z = x / y = ", z 

end program ComplexArithmatic

当编译并执行上述程序,将产生以下结果:

(9.00000000, 91.0000000)
z = x + y = (12.0000000, 1.00000000)
z = x - y = (2.00000000, 15.0000000)
z = x * y = (91.0000000, -9.00000000)
z = x / y = (-0.283783793, 1.20270276)

范围,精度和数字的大小

整数的范围内,精度和浮点数的大小取决于分配给该特定数据类型的比特数。

下表显示的位数和范围的整数:

比特数 最大值 原因
64 9,223,372,036,854,774,807 (2**63)–1
32 2,147,483,647 (2**31)–1

下面的表格显示了位,最小和最大的值的数量,并且为实数的精度。

比特数 最大值 最小值 精确
64 0.8E+308 0.5E–308 15–18
32 1.7E+38 0.3E–38 6-9

下面的例子演示了这一点:

program rangePrecision
implicit none

   real:: x, y, z
   x = 1.5e+40
   y = 3.73e+40
   z = x * y 
   print *, z

end program rangePrecision

当编译并执行上述程序,将产生以下结果:

x = 1.5e+40
    1
Error : Real constant overflows its kind at (1)
main.f95:5.12:

y = 3.73e+40
    1
Error : Real constant overflows its kind at (1)

现在让我们用一个较小的数字:

program rangePrecision
implicit none

   real:: x, y, z
   x = 1.5e+20
   y = 3.73e+20
   z = x * y 
   print *, z

   z = x/y
   print *, z

end program rangePrecision

当编译并执行上述程序,将产生以下结果:

Infinity
0.402144760   

现在,让我们看看溢出:

program rangePrecision
implicit none

   real:: x, y, z
   x = 1.5e-30
   y = 3.73e-60
   z = x * y 
   print *, z

   z = x/y
   print *, z

end program rangePrecision

当编译并执行上述程序,将产生以下结果:

y = 3.73e-60
    1
Warning : Real constant underflows its kind at (1)

Executing the program....
$demo 

0.00000000E+00
Infinity

Kind说明符

在科学程序设计,人们往往需要知道硬件平台上的工作正在进行中的数据的范围和精度。

函数kind() 允许运行一个程序之前查询的硬件的数据表示的细节。

program kindCheck
implicit none

   integer :: i 
   real :: r 
   complex :: cp 
   print *,' Integer ', kind(i) 
   print *,' Real ', kind(r) 
   print *,' Complex ', kind(cp) 

end program kindCheck

当编译并执行上述程序,将产生以下结果:

Integer 4
Real 4
Complex 4

还可以检查所有类型的数据类型:

program checkKind
implicit none

   integer :: i 
   real :: r 
   character*1 :: c 
   logical :: lg 
   complex :: cp 

   print *,' Integer ', kind(i) 
   print *,' Real ', kind(r) 
   print *,' Complex ', kind(cp)
   print *,' Character ', kind(c) 
   print *,' Logical ', kind(lg)

end program checkKind

当编译并执行上述程序,将产生以下结果:

Integer 4
Real 4
Complex 4
Character 1
Logical 4

Fortran字符

Fortran语言可以把字符作为单个字符或连续的字符串。

字符可以是从基本的字符集,即从字母,十进制数字,下划线和21特殊字符所采取的任何符号。

字符常量是一个固定的值的字符串。

内部数据类型的字符存储字符和字符串。字符串的长度可以通过len个符来指定。如果没有指定长度,它是长度是1. 可以将字符串按位置指的是指在单个字符;最左边的字符的位置是1。

字符声明

声明一个字符类型的数据是一样的其他变量:

type-specifier :: variable_name

例如,

character :: reply, sex

可以指定一个值类似,

reply = ‘N’ 
sex = ‘F’

下面的例子演示了声明和使用字符数据类型:

program hello
implicit none

   character(len=15) :: surname, firstname 
   character(len=6) :: title 
   character(len=25)::greetings

   title = 'Mr. ' 
   firstname = 'Rowan ' 
   surname = 'Atkinson'
   greetings = 'A big hello from Mr. Beans'

   print *, 'Here is ', title, firstname, surname
   print *, greetings

end program hello

当编译并执行上述程序,将产生以下结果:

Here is Mr. Rowan Atkinson       
A big hello from Mr. Bean

字符串接

连接运算符//符,连接字符。

下面的例子说明了这一点:

program hello
implicit none

   character(len=15) :: surname, firstname 
   character(len=6) :: title 
   character(len=40):: name
   character(len=25)::greetings

   title = 'Mr. ' 
   firstname = 'Rowan ' 
   surname = 'Atkinson'

   name = title//firstname//surname
   greetings = 'A big hello from Mr. Beans'

   print *, 'Here is ', name
   print *, greetings

end program hello

当编译并执行上述程序,将产生以下结果:

Here is Mr.Rowan Atkinson       
A big hello from Mr.Bean

一些字符函数

下表显示描述一些常用字符的函数:

函数 描述
len(string) 它返回字符串的长度
index(string,sustring) 在一个字符串找出子串的位置,如果没有找到则返回0。
achar(int) 将整数转换成一个字符
iachar(c) 它可将一个字符转换为整数
trim(string) 它返回去掉尾随空格的字符串。
scan(string, chars) 它会搜索“string”由左到右(除非back=.true)包含在“string”任何字符的第一次出现。它返回一个整数,该字符,或零的位置,如果没有文字的“字符”已被找到。
verify(string, chars) 它扫描“string”由左到右(除非back=.true)不包含在“string”任何字符的第一次出现。它返回一个整数,该字符的位置,如果只在“字符”的字符被找到,或者没有找则返回零。
adjustl(string) 它留下左截于“string”包含的字符
adjustr(string) 它留下右截于“string”包含的字符
len_trim(string) 它返回一个整数等于“string”(len(string))减去尾随空白的数量
repeat(string,ncopy) 它返回一个字符串长度等于“ncopy”次数“string”的长度,并含有“string”的“ncopy”串联拷贝

实例 1

这个例子显示使用index函数:

program testingChars
implicit none

   character (80) :: text 
   integer :: i 

   text = 'The intrinsic data type character stores characters and   strings.'
   i=index(text,'character') 

   if (i /= 0) then
      print *, ' The word character found at position ',i 
      print *, ' in text: ', text 
   end if

end program testingChars

当编译并执行上述程序,将产生以下结果:

The word character found at position 25
in text : The intrinsic data type character stores characters and strings.  

示例 2

这个例子演示了如何使用trim函数:

program hello
implicit none

   character(len=15) :: surname, firstname 
   character(len=6) :: title 
   character(len=25)::greetings

   title = 'Mr.' 
   firstname = 'Rowan' 
   surname = 'Atkinson'

   print *, 'Here is', title, firstname, surname
   print *, 'Here is', trim(title),' ',trim(firstname),' ', trim(surname)

end program hello

当编译并执行上述程序,将产生以下结果:

Here is Mr. Rowan Atkinson       
Here is Mr. Rowan Atkinson

示例 3

这个例子演示了如何使用achar函数

program testingChars
implicit none

   character:: ch
   integer:: i

   do i=65, 90
      ch = achar(i)
      print*, i, ' ', ch
   end do

end program testingChars

当编译并执行上述程序,将产生以下结果:

65  A
66  B
67  C
68  D
69  E
70  F
71  G
72  H
73  I
74  J
75  K
76  L
77  M
78  N
79  O
80  P
81  Q
82  R
83  S
84  T
85  U
86  V
87  W
88  X
89  Y
90  Z

检查词法顺序字符

下面的函数确定的字符的词法序列:

函数 描述
lle(char, char) 进行比较的第一个字符是否是词汇上小于或等于所述第二字符
lge(char, char) 进行比较的第一个字符是否是词汇上大于或等于所述第二字符
lgt(char, char) 进行比较的第一个字符是否是词汇上比第二字符大
llt(char, char) 比较第一个字符是否是词汇上比小于第二字符

示例 4

下面的函数演示了如何使用:

program testingChars
implicit none

   character:: a, b, c
   a = 'A'
   b = 'a'
   c = 'B'

   if(lgt(a,b)) then
      print *, 'A is lexically greater than a'
   else
      print *, 'a is lexically greater than A'
   end if

   if(lgt(a,c)) then
      print *, 'A is lexically greater than B'
   else
      print *, 'B is lexically greater than A'
   end if  

   if(llt(a,b)) then
      print *, 'A is lexically less than a'
   end if

   if(llt(a,c)) then
      print *, 'A is lexically less than B'
   end if

end program testingChars

当编译并执行上述程序,将产生以下结果:

a is lexically greater than A
B is lexically greater than A
A is lexically less than a
A is lexically less than B

Fortran字符串

Fortran语言可以把字符作为单个字符或连续的字符串。

字符串可以是只有一个长度的字符,或者它甚至可以是零长度。在Fortran语言,字符常量是一对双引号或单引号之间字符内容。

内部数据类型的字符存储字符和字符串。字符串的长度可以通过len个符来指定。如果没有指定长度,它是长度是1. 可以将字符串按位置指的是指在单个字符;最左边的字符的位置是1。

字符串声明

声明一个字符串跟其他变量是一样的:

type-specifier :: variable_name

例如,

Character(len=20) :: firstname, surname

可以指定一个值类似,

character (len=40) :: name  
name = “Zara Ali”

下面的例子演示了声明和使用字符数据类型:

program hello
implicit none

   character(len=15) :: surname, firstname 
   character(len=6) :: title 
   character(len=25)::greetings

   title = 'Mr.' 
   firstname = 'Rowan' 
   surname = 'Atkinson'
   greetings = 'A big hello from Mr. Beans'

   print *, 'Here is', title, firstname, surname
   print *, greetings

end program hello

当编译并执行上述程序,将产生以下结果:

Here is Mr. Rowan Atkinson       
A big hello from Mr. Bean

字符串连接

连接运算符//,连接字符串。

下面的例子说明了这一点:

program hello
implicit none

   character(len=15) :: surname, firstname 
   character(len=6) :: title 
   character(len=40):: name
   character(len=25)::greetings

   title = 'Mr.' 
   firstname = 'Rowan' 
   surname = 'Atkinson'

   name = title//firstname//surname
   greetings = 'A big hello from Mr. Beans'

   print *, 'Here is', name
   print *, greetings

end program hello

当编译并执行上述程序,将产生以下结果:

Here is Mr. Rowan Atkinson       
A big hello from Mr. Bean

提取子串

在Fortran中,可以通过索引的字符串,开始和子串一对括号的结束索引,从字符串中提取一个子字符串。这就是所谓的范围说明。

下面的示例显示了如何提取字符串’Hello World’的子字符串“world”:

program subString

   character(len=11)::hello
   hello = "Hello World"
   print*, hello(7:11)

end program subString 

当编译并执行上述程序,将产生以下结果:

World

例子

下面的示例使用 date_and_time 函数,得到日期和时间的字符串。我们使用范围说明符单独提取年份,日期,月份,小时,分钟和秒的信息。

program  datetime
implicit none

   character(len = 8) :: dateinfo ! ccyymmdd
   character(len = 4) :: year, month*2, day*2

   character(len = 10) :: timeinfo ! hhmmss.sss
   character(len = 2)  :: hour, minute, second*6

   call  date_and_time(dateinfo, timeinfo)

   !  let’s break dateinfo into year, month and day.
   !  dateinfo has a form of ccyymmdd, where cc = century, yy = year
   !  mm = month and dd = day

   year  = dateinfo(1:4)
   month = dateinfo(5:6)
   day   = dateinfo(7:8)

   print*, 'Date String:', dateinfo
   print*, 'Year:', year
   print *,'Month:', month
   print *,'Day:', day

   !  let’s break timeinfo into hour, minute and second.
   !  timeinfo has a form of hhmmss.sss, where h = hour, m = minute
   !  and s = second

   hour   = timeinfo(1:2)
   minute = timeinfo(3:4)
   second = timeinfo(5:10)

   print*, 'Time String:', timeinfo
   print*, 'Hour:', hour
   print*, 'Minute:', minute
   print*, 'Second:', second   

end program  datetime

当编译并执行上述程序,它提供了详细的日期和时间信息:

Date String: 20140803
   Year: 2014
   Month: 08
   Day: 03
   Time String: 075835.466
   Hour: 07
   Minute: 58
   Second: 35.466

字符串修整

trim函数接受一个字符串,并删除所有尾随空格后返回输入字符串。

例子

program trimString
implicit none

   character (len=*), parameter :: fname="Susanne", sname="Rizwan"
   character (len=20) :: fullname 

   fullname=fname//" "//sname !concatenating the strings

   print*,fullname,", the beautiful dancer from the east!"
   print*,trim(fullname),", the beautiful dancer from the east!"

end program trimString

​ 当编译并执行上述程序,将产生以下结果:

Susanne Rizwan, the beautiful dancer from the east!
Susanne Rizwan, the beautiful dancer from the east!

字符串左右调整

函数 adjustl 需要一个字符串,并通过去除前导空格,并追加其作为尾随空白返回。

函数 adjustr 需要一个字符串,并通过删除尾随空格和追加作为前导空格返回。

例子

program hello
implicit none

   character(len=15) :: surname, firstname 
   character(len=6) :: title 
   character(len=40):: name
   character(len=25):: greetings

   title = 'Mr. ' 
   firstname = 'Rowan' 
   surname = 'Atkinson'
   greetings = 'A big hello from Mr. Beans'

   name = adjustl(title)//adjustl(firstname)//adjustl(surname)
   print *, 'Here is', name
   print *, greetings

   name = adjustr(title)//adjustr(firstname)//adjustr(surname)
   print *, 'Here is', name
   print *, greetings

   name = trim(title)//trim(firstname)//trim(surname)
   print *, 'Here is', name
   print *, greetings

end program hello

当编译并执行上述程序,将产生以下结果:

Here is Mr. Rowan  Atkinson           
A big hello from Mr. Bean
Here is Mr. Rowan Atkinson    
A big hello from Mr. Bean
Here is Mr.RowanAtkinson                        
A big hello from Mr. Bean

搜索字符串的子串

index 函数有两个字符串,并检查是否第二个字符串的第一个字符串的子串。如果第二个参数是第一个参数的子字符串,然后返回一个整数,是第一个字符串第二个字符串的开始索引,否则返回零。

例子

program hello
implicit none

   character(len=30) :: myString
   character(len=10) :: testString

   myString = 'This is a test'
   testString = 'test'

   if(index(myString, testString) == 0)then
      print *, 'test is not found'
   else
      print *, 'test is found at index: ', index(myString, testString)
   end if

end program hello

当编译并执行上述程序,将产生以下结果:

test is found at index: 11

Fortran数组

数组可以存储相同类型的元件的固定大小的连续集合。数组是用来存储数据的集合,但它往往是更加有用认为数组为相同类型的变量的集合。

所有数组由连续的存储单元。最低的地址对应于所述第一元件和所述最高地址的最后一个元素。

Numbers(1) Numbers(2) Numbers(3) Numbers(4)

数组可以是一维的(如向量),二维(如矩阵),Fortran允许最多创建7维数组。

声明数组

数组的尺寸属性声明。

例如,声明含有5个元素的实数的一个一维阵列命名号编写,

real, dimension(5) :: numbers

数组的各个元素通过指定其下标引用。数组的第一元件具有一个的下标。数组数字包含五个实变量- numbers(1), numbers(2), numbers(3), numbers(4), 和numbers(5)。

要创建一个5×5的二维矩阵命名的整数数组:

integer, dimension (5,5) :: matrix  

也可以声明某些明确的下限,例如数组:

real, dimension(2:6) :: numbers
integer, dimension (-3:2,0:4) :: matrix  

赋值

可以将值分配给各个成员一样,

numbers(1) = 2.0

或者,可以使用一个循环,

do i=1,5
   numbers(i) = i * 2.0
end do

一维数组元素可直接分配其值使用短手形符号,被称为数组构造,如,

numbers = (/1.5, 3.2,4.5,0.9,7.2 /)

请注意,不存在括号“(”和背斜杠“/”之间所允许有空格

例子

下面的例子演示了上面讨论的概念。

program arrayProg

   real :: numbers(5) !one dimensional integer array
   integer :: matrix(3,3), i , j !two dimensional real array

   !assigning some values to the array numbers
   do i=1,5
      numbers(i) = i * 2.0
   end do

   !display the values
   do i = 1, 5
      Print *, numbers(i)
   end do

   !assigning some values to the array matrix
   do i=1,3
      do j = 1, 3
         matrix(i, j) = i+j
      end do
   end do

   !display the values
   do i=1,3
      do j = 1, 3
         Print *, matrix(i,j)
      end do
   end do

   !short hand assignment
   numbers = (/1.5, 3.2,4.5,0.9,7.2 /)

   !display the values
   do i = 1, 5
      Print *, numbers(i)
   end do

end program arrayProg

当上述代码被编译和执行时,它产生了以下结果:

 2.00000000    
 4.00000000    
 6.00000000    
 8.00000000    
 10.0000000    
         2
         3
         4
         3
         4
         5
         4
         5
         6
 1.50000000    
 3.20000005    
 4.50000000    
0.899999976    
 7.19999981    

数组相关某些术语

下表给出了一些阵列相关的术语:

术语 意思
Rank 它的尺寸数组具有的数目。例如,对于数组命名矩阵,秩为2,并且对数组命名号,秩为1。
Extent 它是沿一维中的元素的数量。例如,阵列数字具有范围5和命名矩阵阵列具有在两个维度范围3。
Shape 数组的形状是一维整数数组,包含在每一维的元素(程度)的数量。例如,对于数组基质,形状为(3,3)和数组数字它是(5)。
Size 它是元素的数组中包含的数量。对于数组矩阵,它是9,而对于数字阵列,其为5。

数组传递给过程

可以传递一个数组到过程作为参数。下面的例子演示了这一概念:

program arrayToProcedure      
implicit none      

   integer, dimension (5) :: myArray  
   integer :: i

   call fillArray (myArray)      
   call printArray(myArray)

end program arrayToProcedure


subroutine fillArray (a)      
implicit none      

   integer, dimension (5), intent (out) :: a

   ! local variables     
   integer :: i     
   do i = 1, 5         
      a(i) = i      
   end do  

end subroutine fillArray 


subroutine printArray(a)

   integer, dimension (5) :: a  
   integer::i

   do i = 1, 5
      Print *, a(i)
   end do

end subroutine printArray

让我们编译和运行上面的程序,这将产生以下结果:

1
2
3
4
5

在上面的例子中,此子程序 fillArray 和 printArray 只能被称为带维度 5 的数组,当子程序可用于任何尺寸的阵列,则可以使用下面的技术来重写:

program arrayToProcedure      
implicit  none    

   integer, dimension (10) :: myArray  
   integer :: i

   interface 
      subroutine fillArray (a)
         integer, dimension(:), intent (out) :: a 
         integer :: i         
      end subroutine fillArray      

      subroutine printArray (a)
         integer, dimension(:) :: a 
         integer :: i         
      end subroutine printArray   
   end interface 

   call fillArray (myArray)      
   call printArray(myArray)

end program arrayToProcedure


subroutine fillArray (a)      
implicit none      
   integer,dimension (:), intent (out) :: a      

   ! local variables     
   integer :: i, arraySize  
   arraySize = size(a)

   do i = 1, arraySize         
      a(i) = i      
   end do  

end subroutine fillArray 


subroutine printArray(a)
implicit none

   integer,dimension (:) :: a  
   integer::i, arraySize
   arraySize = size(a)

   do i = 1, arraySize
     Print *, a(i)
   end do

end subroutine printArray

请注意,该程序正在使用size函数,以获得阵列的大小。

让我们编译和运行上面的程序,这将产生以下结果:

1
2
3
4
5
6
7
8
9
10

数组部分

到目前为止,我们已经提到了整个数组,Fortran语言提供了一种简单的方法来引用几个元素,或者一个数组的一部分,使用单条语句。

访问一个数组片段,需要提供的下限和上限的部分,以及一个跨度(增量),对于所有的尺寸。这种表示法被称为下标三元组:

array ([lower]:[upper][:stride], ...)

当没有下限和上限提及,它默认为声明的范围,并且跨度值默认为1。

下面的例子演示了这一概念:

program arraySubsection

   real, dimension(10) :: a, b
   integer:: i, asize, bsize

   a(1:7) = 5.0 ! a(1) to a(7) assigned 5.0
   a(8:) = 0.0  ! rest are 0.0 
   b(2:10:2) = 3.9
   b(1:9:2) = 2.5

   !display
   asize = size(a)
   bsize = size(b)

   do i = 1, asize
      Print *, a(i)
   end do

   do i = 1, bsize
      Print *, b(i)
   end do

end program arraySubsection

让我们编译和运行上面的程序,这将产生以下结果:

5.00000000    
5.00000000    
5.00000000    
5.00000000    
5.00000000    
5.00000000    
5.00000000    
0.00000000E+00
0.00000000E+00
0.00000000E+00
2.50000000    
3.90000010    
2.50000000    
3.90000010    
2.50000000    
3.90000010    
2.50000000    
3.90000010    
2.50000000    
3.90000010 

数组内部函数

FORTRAN 90/95提供了一些固有的程序。它们可分为7类。

  • ​ 向量和矩阵乘法
  • ​ 还原
  • ​ 查询
  • ​ 结构
  • ​ 重塑
  • ​ 处理
  • ​ 位置

Fortran向量和矩阵乘法函数

下表描述了向量和矩阵乘法函数:

函数 描述
dot_product(vector_a, vector_b) 函数返回两个输入向量,它必须具有相同长度的标量积。
matmul (matrix_a, matrix_b) 它返回两个矩阵的矩阵乘积,它必须是一致的,即具有相似大小 (m, k) 和 (k, n)

实例

下面的例子演示了内积:

program arrayDotProduct

   real, dimension(5) :: a, b
   integer:: i, asize, bsize

   asize = size(a)
   bsize = size(b)

   do i = 1, asize
      a(i) = i
   end do

   do i = 1, bsize
      b(i) = i*2
   end do

   do i = 1, asize
      Print *, a(i)
   end do

   do i = 1, bsize
      Print *, b(i)
   end do

   Print*, 'Vector Multiplication: Dot Product:'
   Print*, dot_product(a, b)

end program arrayDotProduct

当上述代码被编译和执行时,它产生了以下结果:

1.00000000    
2.00000000    
3.00000000    
4.00000000    
5.00000000    
2.00000000    
4.00000000    
6.00000000    
8.00000000    
10.0000000    
Vector Multiplication: Dot Product:
110.000000   

实例

下面的例子演示了矩阵乘法:

program matMulProduct

   integer, dimension(3,3) :: a, b, c
   integer :: i, j

   do i = 1, 3
      do j = 1, 3
         a(i, j) = i+j
      end do
   end do

   print *, 'Matrix Multiplication: A Matrix'

   do i = 1, 3
      do j = 1, 3
         print*, a(i, j)
      end do
   end do

   do i = 1, 3
      do j = 1, 3
         b(i, j) = i*j
      end do
   end do

   Print*, 'Matrix Multiplication: B Matrix'

   do i = 1, 3
      do j = 1, 3
         print*, b(i, j)
      end do
   end do

   c = matmul(a, b)
   Print*, 'Matrix Multiplication: Result Matrix'

   do i = 1, 3
      do j = 1, 3
         print*, c(i, j)
      end do
   end do

end program matMulProduct

​ 当上述代码被编译和执行时,它产生了以下结果:

Matrix Multiplication: A Matrix
2
3
4
3
4
5
4
5
6
 Matrix Multiplication: B Matrix
1
2
3
2
4
6
3
6
9
Matrix Multiplication: Result Matrix
20
40
60
26
52
78
32
64
96

Fortran还原功能

下表描述了还原功能:

函数 描述
all(mask, dim) 它返回一个逻辑值,指明掩码的所有关系是 .true。以及只有所需的维度,如果第二个参数是给定的。
any(mask, dim) 它返回一个逻辑值,指明掩码的任何关系是.true。以及只有所需的维度,如果第二个参数是给定的。
count(mask, dim) 它返回一个数字值,该值为掩码为 .true 关系的数目。以及所需的维数,如果第二个参数给出。
maxval(array, dim, mask) 它返回 的数组的数组中最大的值,那些遵守于第三个参数掩码的关系,如果一个给定的,以及具有只有所需的维数,如果第二个参数 dim给出的。
minval(array, dim, mask) 它返回数组的数组中那些遵守于第三个参数掩码的关系的最小值,如果一个给定的,以及具有仅在第二个参数 dim 给出所期望的维度。
product(array, dim, mask) 它返回该产品遵守于第三个参数掩码的关系,如果一个给定的,以及具有只有所需的维数,如果第二个参数 dim 给出的所有数组的数组中的元素,。
sum (array, dim, mask) 它返回 遵守于第三个参数掩码关系的总和,如果给定以及具有只有所需的维数,如果第二个参数 dim给出的所有数组的数组中的元素。

例子

下面的例子演示了这一概念:

program arrayReduction

   real, dimension(3,2) :: a 
   a = reshape( (/5,9,6,10,8,12/), (/3,2/) ) 

   Print *, all(a>5)
   Print *, any(a>5)
   Print *, count(a>5)
   Print *, all(a>=5 .and. a<10)

end program arrayReduction

当上述代码被编译和执行时,它产生了以下结果:

F
T
5
F

实例

下面的例子演示了这一概念:

program arrayReduction
implicit none

   real, dimension(1:6) :: a = (/ 21.0, 12.0,33.0, 24.0, 15.0, 16.0 /)
   Print *, maxval(a)
   Print *, minval(a)
   Print *, sum(a)
   Print *, product(a)

end program arrayReduction 

当上述代码被编译和执行时,它产生了以下结果:

33.0000000    
12.0000000    
121.000000    
47900160.0 

Fortran查询函数

下表描述了查询功能:

函数 描述
allocated(array) 它是一个逻辑功能,它指示该阵列被分配。
lbound(array, dim) 它返回的数组的维数较低的限制。如果dim(尺寸)不给出一个参数,会得到一个整数向量,如果dim计算在内,得到的整数值正好具有较低维数的限制。
shape(source) 它返回一个阵列源为一个整数向量的形状。
size(array, dim) 它返回在数组元素的数目。如果dim没有给出,并在相关维数的元素个数,如果dim也包括在内。
ubound(array, dim) 它返回尺寸的限制。

例子

下面的例子演示了这一概念:

program arrayInquiry

   real, dimension(3,2) :: a 
   a = reshape( (/5,9,6,10,8,12/), (/3,2/) ) 

   Print *, lbound(a, dim=1)
   Print *, ubound(a, dim=1)
   Print *, shape(a)
   Print *, size(a,dim=1)

end program arrayInquiry

当上述代码被编译和执行时,它产生了以下结果:

1
3
3 2
3

Fortran构造函数

下表介绍了结构功能:

函数 描述
merge(tsource, fsource, mask) 该功能连接两个阵列。它给出了tsource及元素,如果mask条件是.true。如果掩码的条件是.false。这两个字段tsource 和fsource 必须是相同的类型并具有相同的形状。其结果也就是这种类型和形状。还掩码必须具有相同的形状。
pack(array, mask, vector) 它包一个阵列,以使用掩码的控制向量。逻辑阵列掩模的形状,具有以符合一个用于阵列,要不然掩码必须是一个标量。如果载体被包括在内,它必须是秩1与至少一样多的元素是在掩码为真,并且具有相同的类型的数组的数组(即一个向量)。如果掩码的值为.true。然后矢量代替必须的元件阵列的数量相同。
spread(source, dim, ncopies) 它返回相同类型作为参数源与秩增加一个阵列。参数dim 和ncopies都是整数。如果ncopies是负则用零值来代替。如果source是一个标量,然后扩散变得所有具有相同值 ncopies 元素的向量。参数dim 指示哪个索引将被延长。它必须是范围为1和1+(源级)中,如果 source 是一个标量,dim 必须是1。参数 ncopies 是在新的尺寸元素的数量。
unpack(vector, mask, array) 它散射一个载体,掩码下的控制阵列。逻辑阵列掩模的形状具有以符合一个用于数组。阵列载体必须具有等级1(即它是一个向量)与至少一样多的元素是那些掩码内值都为true,并且还必须具有相同类型阵列。如果阵列被给定为一个标量,然后它被认为是使用相同形状的掩码,并在同一标量元素无处不在的阵列。 其结果将是具有相同形状的掩码和类型相同的矢量阵列。该值将是那些从所接受的载体,而在阵列的剩余位置的旧值被保留。

示例

下面的例子演示了这一概念:

program arrayConstruction
implicit none
   interface
      subroutine write_array (a)
         real :: a(:,:)
      end subroutine write_array

      subroutine write_l_array (a)
         logical :: a(:,:)
      end subroutine write_l_array
   end interface

   real, dimension(2,3) :: tsource, fsource, result
   logical, dimension(2,3) :: mask

   tsource = reshape( (/ 35, 23, 18, 28, 26, 39 /), &
                    (/ 2, 3 /) )
   fsource = reshape( (/ -35, -23, -18, -28, -26, -39 /), &
                    (/ 2,3 /) )
   mask = reshape( (/ .true., .false., .false., .true., &
                 .false., .false. /), (/ 2,3 /) )

   result = merge(tsource, fsource, mask)
   call write_array(tsource)
   call write_array(fsource)
   call write_l_array(mask)
   call write_array(result)

end program arrayConstruction



subroutine write_array (a)

   real :: a(:,:)
   do i = lbound(a,1), ubound(a,1)
      write(*,*) (a(i, j), j = lbound(a,2), ubound(a,2) )
   end do
   return

end subroutine write_array


subroutine write_l_array (a)

   logical :: a(:,:)
   do i = lbound(a,1), ubound(a,1)
      write(*,*) (a(i, j), j= lbound(a,2), ubound(a,2))
   end do
   return

end subroutine write_l_array

当上述代码被编译和执行时,它产生了以下结果:

35.0000000   18.0000000   26.0000000    
23.0000000   28.0000000   39.0000000    
-35.0000000  -18.0000000  -26.0000000    
-23.0000000  -28.0000000  -39.0000000    
T F F
F T F
35.0000000   -18.0000000  -26.0000000    
-23.0000000  28.0000000   -39.0000000  

Fortran重塑函数

下表描述了重塑函数:

函数 描述
reshape(source, shape, pad, order) 它构造一个特定形状的形状,从一个给定source阵列中的元素开始的数组。如果垫不包含则soure的尺寸必须至少为产物(形状)。如果pad包括在内,它必须具有相同的类型的soure。如果order被包括,它必须使用相同的形状的形状的整数数组,值必须是一个排列(1,2,3,…,n),其中n是在形状要素的数量,它必须小于或等于7。

示例

下面的例子演示了这一概念:

program arrayReshape
implicit none

interface
   subroutine write_matrix(a)
   real, dimension(:,:) :: a
   end subroutine write_matrix
   end interface

   real, dimension (1:9) :: b = (/ 21, 22, 23, 24, 25, 26, 27, 28, 29 /)
   real, dimension (1:3, 1:3) :: c, d, e
   real, dimension (1:4, 1:4) :: f, g, h

   integer, dimension (1:2) :: order1 = (/ 1, 2 /)
   integer, dimension (1:2) :: order2 = (/ 2, 1 /)
   real, dimension (1:16) :: pad1 = (/ -1, -2, -3, -4, -5, -6, -7, -8, &
                                 & -9, -10, -11, -12, -13, -14, -15, -16 /)

   c = reshape( b, (/ 3, 3 /) )
   call write_matrix(c)

   d = reshape( b, (/ 3, 3 /), order = order1)
   call write_matrix(d)

   e = reshape( b, (/ 3, 3 /), order = order2)
   call write_matrix(e)

   f = reshape( b, (/ 4, 4 /), pad = pad1)
   call write_matrix(f)

   g = reshape( b, (/ 4, 4 /), pad = pad1, order = order1)
   call write_matrix(g)

   h = reshape( b, (/ 4, 4 /), pad = pad1, order = order2)
   call write_matrix(h)

end program arrayReshape


subroutine write_matrix(a)
   real, dimension(:,:) :: a
   write(*,*)

   do i = lbound(a,1), ubound(a,1)
      write(*,*) (a(i,j), j = lbound(a,2), ubound(a,2))
   end do
end subroutine write_matrix

​ 当上述代码被编译和执行时,它产生了以下结果:

21.0000000  24.0000000  27.0000000    
22.0000000  25.0000000  28.0000000    
23.0000000  26.0000000  29.0000000    

21.0000000  24.0000000  27.0000000    
22.0000000  25.0000000  28.0000000    
23.0000000  26.0000000  29.0000000    

21.0000000  22.0000000  23.0000000    
24.0000000  25.0000000  26.0000000    
27.0000000  28.0000000  29.0000000    

21.0000000  25.0000000  29.0000000   -4.00000000    
22.0000000  26.0000000  -1.00000000  -5.00000000    
23.0000000  27.0000000  -2.00000000  -6.00000000    
24.0000000  28.0000000  -3.00000000  -7.00000000    

21.0000000  25.0000000  29.0000000   -4.00000000    
22.0000000  26.0000000  -1.00000000  -5.00000000    
23.0000000  27.0000000  -2.00000000  -6.00000000    
24.0000000  28.0000000  -3.00000000  -7.00000000    

21.0000000  22.0000000  23.0000000   24.0000000    
25.0000000  26.0000000  27.0000000   28.0000000    
29.0000000  -1.00000000 -2.00000000  -3.00000000    
-4.00000000 -5.00000000 -6.00000000  -7.00000000 

Fortran操作函数

处理函数平移功能。移位函数返回一个数组不变的形状,但移动元素。

函数 描述
cshift(array, shift, dim) 它执行循环移位由移位置的左边,如果移位是正和到右侧,如果它是负的。如果阵列是一个矢量移位正在做以自然的方式中,如果它是一个较高级的阵列则移是沿着维数dim的所有部分。若dim缺少它被认为是1,在其它情况下它必须是1和n(其中n等于阵列的等级)之间的标量整数。该参数换档是一个标量整数或秩n-1个整数的数组和形状相同的阵列中,除沿维数dim(在较低级的,因为它被移除)。不同的部分,因此可以转移在各个方向上,并与各种数目的位置。
eoshift(array, shift, boundary, dim) 这是端关闭的转变。它执行向左移动,如果移位是正和到右侧,如果它是负的。相反的元素移出新元素均取自边界。如果阵列是一个矢量移位正在做以自然的方式中,如果它是一个较高级的阵列,在所有各节中的移位是以及该维度暗淡。若 dim 丢失,它被认为是1,但在其它情况下,它为1和n(其中n等于阵列的秩)之间有一个标量的整数值。该参数换档是一个标量整数,如果阵列具有秩1,在其他情况下,它可以是一个标量整数或秩n-1和形状相同的阵列排列的与除沿维数dim 的整数数组(其被取出因为较低级的)。
transpose (matrix) 其转置矩阵,这是秩2的阵列它取代了的行和列矩阵。

示例

下面的例子演示了这一概念:

program arrayShift
implicit none

   real, dimension(1:6) :: a = (/ 21.0, 22.0, 23.0, 24.0, 25.0, 26.0 /)
   real, dimension(1:6) :: x, y
   write(*,10) a

   x = cshift ( a, shift = 2)
   write(*,10) x

   y = cshift (a, shift = -2)
   write(*,10) y

   x = eoshift ( a, shift = 2)
   write(*,10) x

   y = eoshift ( a, shift = -2)
   write(*,10) y

   10 format(1x,6f6.1)

end program arrayShift

当上述代码被编译和执行时,它产生了以下结果:

21.0  22.0  23.0  24.0  25.0  26.0
23.0  24.0  25.0  26.0  21.0  22.0
25.0  26.0  21.0  22.0  23.0  24.0
23.0  24.0  25.0  26.0   0.0   0.0
0.0    0.0  21.0  22.0  23.0  24.0

示例

下面的例子演示了转置矩阵:

program matrixTranspose
implicit none

   interface
      subroutine write_matrix(a)
         integer, dimension(:,:) :: a
      end subroutine write_matrix
   end interface

   integer, dimension(3,3) :: a, b
   integer :: i, j

   do i = 1, 3
      do j = 1, 3
         a(i, j) = i
      end do
   end do

   print *, 'Matrix Transpose: A Matrix'

   call write_matrix(a)
   b = transpose(a)
   print *, 'Transposed Matrix:'

   call write_matrix(b)
end program matrixTranspose


subroutine write_matrix(a)

   integer, dimension(:,:) :: a
   write(*,*)

   do i = lbound(a,1), ubound(a,1)
      write(*,*) (a(i,j), j = lbound(a,2), ubound(a,2))
   end do

end subroutine write_matrix

当上述代码被编译和执行时,它产生了以下结果:

Matrix Transpose: A Matrix

1  1  1
2  2  2
3  3  3
Transposed Matrix:

1  2  3
1  2  3
1  2  3

Fortran位置函数

下表描述了位置函数:

函数 描述
maxloc(array, mask) 它返回数组中的最大元素的位置上,如果掩码仅包含那些其中满足条件的掩码,则返回位置,其结果是一个整数向量。
minloc(array, mask) 它返回数组的数组中的最小元素的位置,如果掩码仅包含那些其中满足条件的掩码,则返回位置,其结果是一个整数向量。

示例

下面的例子演示了这一概念:

program arrayLocation
implicit none

   real, dimension(1:6) :: a = (/ 21.0, 12.0,33.0, 24.0, 15.0, 16.0 /)
   Print *, maxloc(a)
   Print *, minloc(a)

end program arrayLocation   

当上述代码被编译和执行时,它产生了以下结果:

3
2

Fortran动态数组

动态数组是一种数组,其尺寸在编译时不知道,而是在执行时才已知/确定的。

动态数组的属性使用 allocatable 声明。 .

例如,

real, dimension (:,:), allocatable :: darray    

数组的秩,即尺寸,必须提到但是,分配内存以这样的阵列,可以使用allocate函数。

allocate ( darray(s1,s2) )      

该阵列使用后,在该程序中,所创建的存储器应该使用 deallocate 函数解除

deallocate (darray)  

示例

下面的例子演示了上面讨论的概念。

program dynamic_array 
implicit none 

   !rank is 2, but size not known   
   real, dimension (:,:), allocatable :: darray    
   integer :: s1, s2     
   integer :: i, j     

   print*, "Enter the size of the array:"     
   read*, s1, s2      

   ! allocate memory      
   allocate ( darray(s1,s2) )      

   do i = 1, s1           
      do j = 1, s2                
         darray(i,j) = i*j               
         print*, "darray(",i,",",j,") = ", darray(i,j)           
      end do      
   end do      

   deallocate (darray)  
end program dynamic_array

当上述代码被编译和执行时,它产生了以下结果:

Enter the size of the array: 3,4
darray( 1 , 1 ) = 1.00000000    
darray( 1 , 2 ) = 2.00000000    
darray( 1 , 3 ) = 3.00000000    
darray( 1 , 4 ) = 4.00000000    
darray( 2 , 1 ) = 2.00000000    
darray( 2 , 2 ) = 4.00000000    
darray( 2 , 3 ) = 6.00000000    
darray( 2 , 4 ) = 8.00000000    
darray( 3 , 1 ) = 3.00000000    
darray( 3 , 2 ) = 6.00000000    
darray( 3 , 3 ) = 9.00000000    
darray( 3 , 4 ) = 12.0000000   

使用data语句

data 语句可用于初始化多个阵列,或用于阵列部分的初始化。

data 语句的语法是:

data variable / list / ...

示例

下面的例子演示了这一概念:

program dataStatement
implicit none

   integer :: a(5), b(3,3), c(10),i, j
   data a /7,8,9,10,11/ 

   data b(1,:) /1,1,1/ 
   data b(2,:)/2,2,2/ 
   data b(3,:)/3,3,3/ 
   data (c(i),i=1,10,2) /4,5,6,7,8/ 
   data (c(i),i=2,10,2)/5*2/

   Print *, 'The A array:'
   do j = 1, 5                
      print*, a(j)           
   end do 

   Print *, 'The B array:'
   do i = lbound(b,1), ubound(b,1)
      write(*,*) (b(i,j), j = lbound(b,2), ubound(b,2))
   end do

   Print *, 'The C array:' 
   do j = 1, 10                
      print*, c(j)           
   end do      

end program dataStatement

当上述代码被编译和执行时,它产生了以下结果:

The A array:
7
8
9
10
11
The B array:
1  1  1
2  2  2
3  3  3
The C array:
4
2
5
2
6
2
7
2
8
2

使用where语句

where语句可以使用数组中的某些元素在一个表达式,根据一些逻辑条件的结果。它允许表达的执行在一个元素上,如果给定的条件为真。

例子

下面的例子演示了这一概念:

program whereStatement
implicit none

   integer :: a(3,5), i , j

   do i = 1,3
      do j = 1, 5                
         a(i,j) = j-i          
      end do 
   end do

   Print *, 'The A array:'

   do i = lbound(a,1), ubound(a,1)
      write(*,*) (a(i,j), j = lbound(a,2), ubound(a,2))
   end do

   where( a<0 ) 
      a = 1 
   elsewhere
      a = 5
   end where

   Print *, 'The A array:'
   do i = lbound(a,1), ubound(a,1)
      write(*,*) (a(i,j), j = lbound(a,2), ubound(a,2))
   end do   

end program whereStatement

当上述代码被编译和执行时,它产生了以下结果:

The A array:
0   1   2  3  4
-1  0   1  2  3
-2  -1  0  1  2
The A array:
5   5   5  5  5
1   5   5  5  5
1   1   5  5  5

Fortran导出数据类型

Fortran语言可以定义导出的数据类型。导出的数据类型也被称为一个结构,它可以包含不同类型的数据对象。

导出的数据类型被用来代表一个记录。例如要跟踪在图书馆的书,可能希望跟踪的每本书有如下属性:

  • ​ 标题- Title
  • ​ 作者 - Author
  • ​ 科目 - Subject
  • ​ 编号 - Book ID

定义一个导出的数据类型

定义一个派生数据类型,类型和端类型的语句被使用。类型语句定义了一个新的数据类型,项目不止一个成员。类型声明的格式是这样的:

type type_name      
   declarations
end type 

这里是会声明书的结构方式:

type Books
   character(len=50) :: title
   character(len=50) :: author
   character(len=150) :: subject
   integer :: book_id
end type Books

访问结构成员

一个派生数据类型的对象被称为结构

类型书籍(Books) 的结构像一个类型声明语句创建如下:

type(Books) :: book1 

结构的组成部分可以使用该组件选择字符(%)进行访问 :

book1%title = "C Programming"
book1%author = "Nuha Ali"
book1%subject = "C Programming Tutorial"
book1%book_id = 6495407

请注意,%符号前后没有空格。

示例

下面的程序说明了上述概念:

program deriveDataType

   !type declaration
   type Books
      character(len=50) :: title
      character(len=50) :: author
      character(len=150) :: subject
      integer :: book_id
   end type Books

   !declaring type variables
   type(Books) :: book1 
   type(Books) :: book2 

   !accessing the components of the structure

   book1%title = "C Programming"
   book1%author = "Nuha Ali"
   book1%subject = "C Programming Tutorial"
   book1%book_id = 6495407 

   book2%title = "Telecom Billing"
   book2%author = "Zara Ali"
   book2%subject = "Telecom Billing Tutorial"
   book2%book_id = 6495700

   !display book info

   Print *, book1%title 
   Print *, book1%author 
   Print *, book1%subject 
   Print *, book1%book_id  

   Print *, book2%title 
   Print *, book2%author 
   Print *, book2%subject 
   Print *, book2%book_id  

end program deriveDataType

当上述代码被编译和执行时,它产生了以下结果:

 C Programming                                     
 Nuha Ali                                          
 C Programming Tutorial            
     6495407
 Telecom Billing                                   
 Zara Ali                                          
 Telecom Billing Tutorial            
     6495700

结构数组

还可以创建一个派生类型的数组:

type(Books), dimension(2) :: list

数组的单个元素,可以访问如下:

list(1)%title = "C Programming"
list(1)%author = "Nuha Ali"
list(1)%subject = "C Programming Tutorial"
list(1)%book_id = 6495407

下面的程序说明了这个概念:

program deriveDataType

   !type declaration
   type Books
      character(len=50) :: title
      character(len=50) :: author
      character(len=150) :: subject
      integer :: book_id
   end type Books

   !declaring array of books
   type(Books), dimension(2) :: list 

   !accessing the components of the structure

   list(1)%title = "C Programming"
   list(1)%author = "Nuha Ali"
   list(1)%subject = "C Programming Tutorial"
   list(1)%book_id = 6495407 

   list(2)%title = "Telecom Billing"
   list(2)%author = "Zara Ali"
   list(2)%subject = "Telecom Billing Tutorial"
   list(2)%book_id = 6495700

   !display book info

   Print *, list(1)%title 
   Print *, list(1)%author 
   Print *, list(1)%subject 
   Print *, list(1)%book_id  

   Print *, list(1)%title 
   Print *, list(2)%author 
   Print *, list(2)%subject 
   Print *, list(2)%book_id  

end program deriveDataType

当上述代码被编译和执行时,它产生了以下结果:

C Programming                                     
Nuha Ali                                          
C Programming Tutorial               
   6495407
C Programming                                     
Zara Ali                                          
Telecom Billing Tutorial                                      
   6495700

Fortran指针

在大多数编程语言中,一个指针变量存储对象的内存地址。然而,在Fortran中,指针是具有不是仅仅存储存储器地址多功能性的数据对象。它包含有关特定对象的详细信息,如类型,等级,扩展和存储器地址。

指针是通过分配或指针赋值的目标相关联。

声明一个指针变量

一个指针变量与指针属性声明。

下面的实施例示出了声明指针变量:

integer, pointer :: p1 ! pointer to integer  
real, pointer, dimension (:) :: pra ! pointer to 1-dim real array  
real, pointer, dimension (:,:) :: pra2 ! pointer to 2-dim real array

指针可以指向:

  • ​ 动态分配的内存区域
  • ​ 数据对象与目标属性相同类型的指针

分配指针的空间

allocate语句可以分配指针对象空间。例如:

program pointerExample
implicit none

   integer, pointer :: p1
   allocate(p1)

   p1 = 1
   Print *, p1

   p1 = p1 + 4
   Print *, p1

end program pointerExample

当上述代码被编译和执行时,它产生了以下结果:

1
5

应该解除分配语句清空该分配的存储空间当它不再需要,并避免未使用的和不可用的存储器空间的积累。

目标和关联

目标是另一个正态变量,空间预留给它。目标变量必须与目标属性进行声明。

一个指针变量使用的关联操作符使目标变量相关联(=>)。

让我们重写前面的例子中,以说明这个概念:

program pointerExample
implicit none

   integer, pointer :: p1
   integer, target :: t1 

   p1=>t1
   p1 = 1

   Print *, p1
   Print *, t1

   p1 = p1 + 4

   Print *, p1
   Print *, t1

   t1 = 8

   Print *, p1
   Print *, t1

end program pointerExample

当上述代码被编译和执行时,它产生了以下结果:

1
1
5
5
8
8

指针可以是:

  • ​ 未定义的
  • ​ 关联的
  • ​ 未关联的

在上面的程序中,我们使用associated的指针p1与目标t1时,使用=>运算符。相关的函数,测试指针的关联状态。

这个声明无效的关联从一个目标一个指针。

无效非空目标,因为可能有多个指针指向同一个目标。然而空指针指也是无效的。

示例 1

下面的例子演示了概念:

program pointerExample
implicit none

   integer, pointer :: p1
   integer, target :: t1 
   integer, target :: t2

   p1=>t1
   p1 = 1

   Print *, p1
   Print *, t1

   p1 = p1 + 4
   Print *, p1
   Print *, t1

   t1 = 8
   Print *, p1
   Print *, t1

   nullify(p1)
   Print *, t1

   p1=>t2
   Print *, associated(p1)
   Print*, associated(p1, t1)
   Print*, associated(p1, t2)

   !what is the value of p1 at present
   Print *, p1
   Print *, t2

   p1 = 10
   Print *, p1
   Print *, t2

end program pointerExample

当上述代码被编译和执行时,它产生了以下结果:

1
1
5
5
8
8
8
T
F
T
952754640
952754640
10
10

请注意,每次运行该代码时,内存地址会有所不同。

示例 2

program pointerExample
implicit none

   integer, pointer :: a, b
   integer, target :: t
   integer :: n

   t= 1
   a=>t
   t = 2
   b => t
   n = a + b

   Print *, a, b, t, n 

end program pointerExample

当上述代码被编译和执行时,它产生了以下结果:

2  2  2  4

Fortran基本输入输出

到目前为止,我们已看到,我们可以使用打印print语句,以及读取键盘使用read语句,并显示数据输出到屏幕上。这种形式的输入输出是自由格式的I/O,它被称为列表控制的输入输出。

自由格式简单I/O的形式为:

read(*,*) item1, item2, item3...
print *, item1, item2, item3
write(*,*) item1, item2, item3...

然而,格式化I/O使数据传输有更多的灵活性。

格式化输入输出

格式化输入输出有语法如下:

read fmt, variable_list 
print fmt, variable_list 
write fmt, variable_list 

其中,

  • ​ fmt 是格式规范
  • ​ variable-list 要被从键盘读或写在屏幕上的变量的列表

格式规范定义了在其上显示格式化的数据的方式。它由一个字符串,包含了编辑描述符在括号中的列表。

编辑描述符指定的确切格式,例如宽度,其中字符和数字被显示小数点后等,数字位数。

例如:

Print "(f6.3)", pi

下表描述了描述:

描述符 描述 示例
I 这是用于整数输出。此采用的形式为“rIw.m’,其中 r, w 和m 的含义在下面的表格中给出。真正的值在它们字段右侧适应。如果字段宽度不足以容纳一个整数则用星号代替。 print “(3i5)”, i, j, k
F 这是用于实数输出。此采用的形式为“rFw.d’,其中r, w 和 d 的含义在下面的表格中给出。真正的值在它们字段右侧适应。 如果字段宽度不足够大以容纳所述实数则字段用星号表示。 print “(f12.3)”,pi
E 这是用于指数形式实时输出。在“E”描述语句的形式为’rEw.d’,其中r,w和d的含义如下表中给出。真正的值在它们字段右侧适应. 如果字段宽度不足够大以容纳所述实数则字段用星号表示。 请注意,打印出与三位小数,实数至少10需要一个字段宽度。一个用于尾数,2为零,4为尾数部分和两个用于指数本身的符号。在一般情况下,w≥ d +7。 print “(e10.3)”,123456.0 gives ‘0.123e+06’
ES 这是用于实时输出(科学计数法)。此采用的形式为“rESw.d’,其中 r, w 和 d的含义在下面的表格中给出。上述的“E”描述从传统的众所周知的“科学表示法”略有不同。科学表示法具有尾数范围为1.0至10.0对E描述符,它具有在范围0.1到1.0的尾数不同。真实的值在字段的右侧。如果字段宽度不足够大以容纳所述实数则字段用星号表示。这里,字段宽度必须满足 w ≥ d +7 print “(es10.3)”,123456.0 gives ‘1.235e+05’
A 这是用于字符输出。 此采用的形式为“rAw”,其中r和w的含义在下面的表格中给出。字符类型是在它们的字段右侧。如果字段宽度不足于以容纳该字符串则字段的第一个“w”字符的字符串。 print “(a10)”, str
X 这是用于空间输出。这需要形式’nX’,其中“n”是所需的空间数量。 print “(5x, a10)”, str
/ 斜杠描述 - 用于插入空行。这需要的形式’/‘,并强制下一个数据输出为一个新行。 print “(/,5x, a10)”, str

以下符号用于格式描述符:

符号 描述
c 列数
d 右侧的小数位数为真正的输入或输出
m 要显示的最小位数
n 跳过的空格数
r 重复次数 - 使用描述或组描述符的次数
w 字段宽度- 字符数用于输入或输出

示例 1

program printPi

   pi = 3.141592653589793238 

   Print "(f6.3)", pi 
   Print "(f10.7)", pi
   Print "(f20.15)", pi 
   Print "(e16.4)", pi/100 

end program printPi

​ 当上述代码被编译和执行时,它产生了以下结果:

3.142
3.1415927
3.141592741012573
0.3142E-01

实例 2

program printName
implicit none

   character (len=15) :: first_name
   print *,' Enter your first name.' 
   print *,' Up to 20 characters, please'

   read *,first_name 
   print "(1x,a)",first_name

end program printName

当上述代码被编译和执行时,它产生了以下结果:(假设用户输入的名称为 Zara)

Enter your first name.
Up to 20 characters, please
Zara 

实例 3

program formattedPrint
implicit none

   real :: c = 1.2786456e-9, d = 0.1234567e3 
   integer :: n = 300789, k = 45, i = 2
   character (len=15) :: str="Tutorials Point"

   print "(i6)", k 
   print "(i6.3)", k 
   print "(3i10)", n, k, i 
   print "(i10,i3,i5)", n, k, i 
   print "(a15)",str 
   print "(f12.3)", d
   print "(e12.4)", c 
   print '(/,3x,"n = ",i6, 3x, "d = ",f7.4)', n, d

end program formattedPrint

当上述代码被编译和执行时,它产生了以下结果:

45
045
300789 45  2
300789 45  2
Tutorials Point
123.457
0.1279E-08

n = 300789 d = *******

Format语句

format语句允许混合并匹配字符,整数和实际输出在一条语句中。下面的例子说明了这一点:

program productDetails 
implicit none 

   character (len=15) :: name
   integer :: id 
   real :: weight
   name = 'Ardupilot'
   id = 1
   weight = 0.08

   print *,' The product details are' 

   print 100
   100 format (7x,'Name:', 7x, 'Id:', 1x, 'Weight:')

   print 200, name, id, weight 
   200 format(1x, a, 2x, i3, 2x, f5.2) 

end program productDetails

当上述代码被编译和执行时,它产生了以下结果:

The product details are
Name:       Id:    Weight:
Ardupilot   1       0.08

Fortran文件输入输出

Fortran语言可以读取数据,并将数据写入到文件中。

可以读取和写入到一个或多个文件。OPEN, WRITE, READ 和 CLOSE语句可以实现这一目标。

打开和关闭文件

使用文件之前,必须打开该文件。 open命令用于打开文件进行读取或写入。命令的最简单的形式是:

open (unit = number, file = "name").

然而,open 语句的一般形式:

open (list-of-specifiers)

下表介绍了最常用的修饰符:

修辞符 描述
[UNIT=] u 单元数u可以是任何数量范围内9-99,它表明该文件,可以选择任何号码,但在程序中每一个打开的文件必须有一个唯一的数字
IOSTAT= ios 它是在I/O状态标识符和应为整数的变量。如果打开的语句是成功,则返回IOS值为零,否则为一个非零值。
ERR = err 它是一个标签到该控制跳以防有错误。
FILE = fname 文件名,一个字符串。
STATUS = sta 它示出了该文件的先前状态。一个字符串,可以有三个值NEW, OLD 或 SCRATCH。一个临时文件被创建和删除,当关闭或程序结束。
ACCESS = acc 它是该文件的访问模式。可以有两个值SEQUENTIAL 或 DIRECT。默认值是SEQUENTIAL。
FORM= frm 它给该文件的格式的状态。可以有FORMATTED 或UNFORMATTED两个值。默认值是UNFORMATTED
RECL = rl 它指定的每个记录中的一个直接访问文件的长度。

该文件已被打开后,它由read 和 write语句访问。一旦完成,就应该使用close语句关闭。

close语句的语法如下:

close ([UNIT=]u[,IOSTAT=ios,ERR=err,STATUS=sta])

请注意,括号中的参数是可选的。

示例

这个例子演示了写一些数据到一个新的打开文件。

program outputdata   
implicit none

   real, dimension(100) :: x, y  
   real, dimension(100) :: p, q
   integer :: i  

   ! data  
   do i=1,100  
      x(i) = i * 0.1 
      y(i) = sin(x(i)) * (1-cos(x(i)/3.0))  
   end do  

   ! output data into a file 
   open(1, file='data1.dat', status='new')  
   do i=1,100  
      write(1,*) x(i), y(i)   
   end do  

   close(1) 

end program outputdata

当上述代码被编译和执行时,它创建文件data1.dat和x和y数组值写入到其中。然后关闭该文件。

读取和写入文件

读取和写入的语句分别用于读取和分别写入到文件中。

它们有以下语法:

read ([UNIT=]u, [FMT=]fmt, IOSTAT=ios, ERR=err, END=s)
write([UNIT=]u, [FMT=]fmt, IOSTAT=ios, ERR=err, END=s)

大部分的修饰符的已在上表中讨论。

END= S说明是程序跳转,当它到达文件结束,声明标签。

示例

这个例子演示了读取和写入到文件。

在这个程序中,从文件中读取,在最后一个例子创建data1.dat,并在屏幕上显示出来。

program outputdata   
implicit none   

   real, dimension(100) :: x, y  
   real, dimension(100) :: p, q
   integer :: i  

   ! data  
   do i=1,100  
      x(i) = i * 0.1 
      y(i) = sin(x(i)) * (1-cos(x(i)/3.0))  
   end do  

   ! output data into a file 
   open(1, file='data1.dat', status='new')  
   do i=1,100  
      write(1,*) x(i), y(i)   
   end do  
   close(1) 

   ! opening the file for reading
   open (2, file='data1.dat', status='old')

   do i=1,100  
      read(2,*) p(i), q(i)
   end do 

   close(2)

   do i=1,100  
      write(*,*) p(i), q(i)
   end do 

end program outputdata

让我们编译和运行上面的程序,这将产生以下结果:

0.100000001  5.54589933E-05
0.200000003  4.41325130E-04
0.300000012  1.47636665E-03
0.400000006  3.45637114E-03
0.500000000  6.64328877E-03
0.600000024  1.12552457E-02
0.699999988  1.74576249E-02
0.800000012  2.53552198E-02
0.900000036  3.49861123E-02
1.00000000   4.63171229E-02
1.10000002   5.92407547E-02
1.20000005   7.35742599E-02
1.30000007   8.90605897E-02
1.39999998   0.105371222    
1.50000000   0.122110792    
1.60000002   0.138823599    
1.70000005   0.155002072    
1.80000007   0.170096487    
1.89999998   0.183526158    
2.00000000   0.194692180    
2.10000014   0.202990443    
2.20000005   0.207826138    
2.29999995   0.208628103    
2.40000010   0.204863414    
2.50000000   0.196052119    
2.60000014   0.181780845    
2.70000005   0.161716297    
2.79999995   0.135617107    
2.90000010   0.103344671    
3.00000000   6.48725405E-02
3.10000014   2.02930309E-02
3.20000005  -3.01767997E-02
3.29999995  -8.61928314E-02
3.40000010  -0.147283033    
3.50000000  -0.212848678    
3.60000014  -0.282169819    
3.70000005  -0.354410470    
3.79999995  -0.428629100    
3.90000010  -0.503789663    
4.00000000  -0.578774154    
4.09999990  -0.652400017    
4.20000029  -0.723436713    
4.30000019  -0.790623367    
4.40000010  -0.852691114    
4.50000000  -0.908382416    
4.59999990  -0.956472993    
4.70000029  -0.995793998    
4.80000019  -1.02525222    
4.90000010  -1.04385209    
5.00000000  -1.05071592    
5.09999990  -1.04510069    
5.20000029  -1.02641726    
5.30000019  -0.994243503    
5.40000010  -0.948338211    
5.50000000  -0.888650239    
5.59999990  -0.815326691    
5.70000029  -0.728716135    
5.80000019  -0.629372001    
5.90000010  -0.518047631    
6.00000000  -0.395693362    
6.09999990  -0.263447165    
6.20000029  -0.122622721    
6.30000019   2.53026206E-02
6.40000010   0.178709000    
6.50000000   0.335851669    
6.59999990   0.494883657    
6.70000029   0.653881252    
6.80000019   0.810866773    
6.90000010   0.963840425    
7.00000000   1.11080539    
7.09999990   1.24979746    
7.20000029   1.37891412    
7.30000019   1.49633956    
7.40000010   1.60037732    
7.50000000   1.68947268    
7.59999990   1.76223695    
7.70000029   1.81747139    
7.80000019   1.85418403    
7.90000010   1.87160957    
8.00000000   1.86922085    
8.10000038   1.84674001    
8.19999981   1.80414569    
8.30000019   1.74167395    
8.40000057   1.65982044    
8.50000000   1.55933595    
8.60000038   1.44121361    
8.69999981   1.30668485    
8.80000019   1.15719533    
8.90000057   0.994394958    
9.00000000   0.820112705    
9.10000038   0.636327863    
9.19999981   0.445154816    
9.30000019   0.248800844    
9.40000057   4.95488606E-02
9.50000000  -0.150278628    
9.60000038  -0.348357052    
9.69999981  -0.542378068    
9.80000019  -0.730095863    
9.90000057  -0.909344316    
10.0000000  -1.07807255  

Fortran过程

过程是一组执行一个明确定义的任务,可以从程序调用语句。信息(或数据)被传递给调用程序,以过程作为参数。

有两种类型的程序:

  • ​ 函数
  • ​ 子程序

函数

​ 函数是返回一个数量的过程。函数不修改其参数。

​ 返回数值被称为函数值,并将其表示为函数名。

语法:

函数的语法如下:

function name(arg1, arg2, ....)  
   [declarations, including those for the arguments]   
   [executable statements] 
end function [name]

下面的示例演示一个函数名为area_of_circle。它计算半径为 r 的圆的面积。

program calling_func

   real :: a
   a = area_of_circle(2.0) 

   Print *, "The area of a circle with radius 2.0 is"
   Print *, a

end program calling_func


! this function computes the area of a circle with radius r  
function area_of_circle (r)  

! function result     
implicit none      

   ! dummy arguments        
   real :: area_of_circle   

   ! local variables 
   real :: r     
   real :: pi

   pi = 4 * atan (1.0)     
   area_of_circle = pi * r**2  

end function area_of_circle

当编译并执行上述程序,它会产生以下结果:

The area of a circle with radius 2.0 is
   12.5663710   

请注意:

  • ​ 必须指定隐含都不在这两个在主程序和过程中。
  • ​ 在被调用函数的参数r被称为 dummy argument.

结果选项

如果想返回的值存储在函数名的其他名称,则可以使用result选项。

可以根据指定返回变量名:

function name(arg1, arg2, ....) result (return_var_name)  
   [declarations, including those for the arguments]   
   [executable statements] 
end function [name]

子程序

子程序没有返回值,但可以修改其参数。

语法

subroutine name(arg1, arg2, ....)    
   [declarations, including those for the arguments]    
   [executable statements]  
end subroutine [name]

调用子程序

需要使用call语句来调用一个子程序。

下面的例子演示了一个子程序交换,改变其参数值的定义和使用。

program calling_func
implicit none

   real :: a, b
   a = 2.0
   b = 3.0

   Print *, "Before calling swap"
   Print *, "a = ", a
   Print *, "b = ", b

   call swap(a, b)

   Print *, "After calling swap"
   Print *, "a = ", a
   Print *, "b = ", b

end program calling_func


subroutine swap(x, y) 
implicit none

   real :: x, y, temp   

   temp = x  
   x = y 
   y = temp  

end subroutine swap

当编译并执行上述程序,它会产生以下结果:

Before calling swap
a = 2.00000000    
b = 3.00000000    
After calling swap
a = 3.00000000    
b = 2.00000000   

指定参数的意图

意图属性允许指定与参数的过程中使用的意向。下表提供intent属性的值:

使用为 解释
in intent(in) 用作输入值,而不是在函数中改变
out intent(out) 用作输出值,它们将被覆盖
inout intent(inout) 参数都使用和覆盖

下面的例子演示了这一概念:

program calling_func
implicit none

   real :: x, y, z, disc

   x= 1.0
   y = 5.0
   z = 2.0

   call intent_example(x, y, z, disc)

   Print *, "The value of the discriminant is"
   Print *, disc

end program calling_func


subroutine intent_example (a, b, c, d)     
implicit none     

   ! dummy arguments      
   real, intent (in) :: a     
   real, intent (in) :: b      
   real, intent (in) :: c    
   real, intent (out) :: d   

   d = b * b - 4.0 * a * c 

end subroutine intent_example

当编译并执行上述程序,它会产生以下结果:

The value of the discriminant is
   17.0000000    

递归过程

递归发生在一个编程语言可以调用同一个函数在函数内。这就是所谓的函数的递归调用。

当一个过程调用本身,直接或间接地被称为递归过程。应该通过其声明之前的字前面递归声明这种类型的程序。

当一个函数被递归使用,则 result 选项要被使用。

以下是一个例子,它计算阶乘用于使用一个递归过程:

program calling_func
implicit none

   integer :: i, f
   i = 15

   Print *, "The value of factorial 15 is"
   f = myfactorial(15)
   Print *, f

end program calling_func

! computes the factorial of n (n!)      
recursive function myfactorial (n) result (fac)  
! function result     
implicit none     

   ! dummy arguments     
   integer :: fac     
   integer, intent (in) :: n     

   select case (n)         
      case (0:1)         
         fac = 1         
      case default    
         fac = n * myfactorial (n-1)  
   end select 

end function myfactorial

内部过程

当一个过程被包含在程序中,它被称为程序的内部程序。包含一个内部程序的语法如下:

program program_name     
   implicit none         
   ! type declaration statements         
   ! executable statements    
   . . .     
   contains         
   ! internal procedures      
   . . .  
end program program_name

下面的例子演示了这一概念:

program mainprog  
implicit none 

   real :: a, b 
   a = 2.0
   b = 3.0

   Print *, "Before calling swap"
   Print *, "a = ", a
   Print *, "b = ", b

   call swap(a, b)

   Print *, "After calling swap"
   Print *, "a = ", a
   Print *, "b = ", b

contains   
   subroutine swap(x, y)     
      real :: x, y, temp      
      temp = x 
      x = y  
      y = temp   
   end subroutine swap 

end program mainprog   

当编译并执行上述程序,它会产生以下结果:

Before calling swap
a = 2.00000000    
b = 3.00000000    
After calling swap
a = 3.00000000    
b = 2.00000000  

Fortran模块

模块就像一个包,可以包含函数和子程序,如果正在编写一个非常大的项目,或者函数或子程序需要在多个程序中使用。

模块提供拆分多个文件之间程序的方式。

模块用于:

  • ​ 包装子程序,数据和接口块。
  • ​ 定义,可以使用多于一个常规全局数据。
  • ​ 声明可以选择的任何程序内提供的变量。
  • ​ 导入整个模块,可使用在另一个程序或子程序。

模块的语法

模块由两部分组成:

  • ​ 规范的一部分,语句声明
  • ​ 包含一部分用于子程序和函数定义

模块的一般形式是:

module name     
   [statement declarations]  
   [contains [subroutine and function definitions] ] 
end module [name]

使用一个模块到程序中

可以将一个程序或子程序通过使用声明的模块:

use name  

请注意

  • ​ 可以根据需要添加尽可能多的模块,在不同的文件中,并单独编译。
  • ​ 一个模块可以在各种不同的程序中使用。
  • ​ 一个模块在同一程序中可使用多次。
  • ​ 在模块规格说明部分内声明的变量,在模块是全局的。
  • ​ 在一个模块中声明的变量成为在模块中使用的任何程序或例程的全局变量。
  • ​ 使用声明可以出现在主程序中,或任何其他子程序或模块,它使用所述例程或在一个特定的模块声明的变量。

示例

下面的例子演示了这一概念:

module constants  
implicit none 

   real, parameter :: pi = 3.1415926536  
   real, parameter :: e = 2.7182818285 

contains      
   subroutine show_consts()          
      print*, "Pi = ", pi          
      print*,  "e = ", e     
   end subroutine show_consts 

end module constants 


program module_example     
use constants      
implicit none     

   real :: x, ePowerx, area, radius 
   x = 2.0
   radius = 7.0
   ePowerx = e ** x
   area = pi * radius**2     

   call show_consts() 

   print*, "e raised to the power of 2.0 = ", ePowerx
   print*, "Area of a circle with radius 7.0 = ", area  

end program module_example

当编译并执行上述程序,它会产生以下结果:

Pi = 3.14159274    
e =  2.71828175    
e raised to the power of 2.0 = 7.38905573    
Area of a circle with radius 7.0 = 153.938049   

在一个模块变量和子程序的访问

缺省情况下,在一个模块中的所有的变量和子程序被提供给正在使用的模块代码,通过 use 语句声明。

但是,可以控制模块代码中使用的private 和 public 属性的访问性。当声明一些变量或子程序为私有,这是不可以用在模块之外使用。

示例

下面的例子说明了这个概念:

在前面的例子中,有两个模块变量,e和PI。把它们设置为private并观察输出:

module constants  
implicit none 

   real, parameter,private :: pi = 3.1415926536  
   real, parameter, private :: e = 2.7182818285 

contains      
   subroutine show_consts()          
      print*, "Pi = ", pi          
      print*, "e = ", e     
   end subroutine show_consts 

end module constants 


program module_example     
use constants      
implicit none     

   real :: x, ePowerx, area, radius 
   x = 2.0
   radius = 7.0
   ePowerx = e ** x
   area = pi * radius**2     

   call show_consts() 

   print*, "e raised to the power of 2.0 = ", ePowerx
   print*, "Area of a circle with radius 7.0 = ", area  

end program module_example

​ 当编译和执行上面的程序,它提供了以下错误信息:

   ePowerx = e ** x
   1
Error: Symbol 'e' at (1) has no IMPLICIT type
main.f95:19.13:

   area = pi * radius**2     
   1
Error: Symbol 'pi' at (1) has no IMPLICIT type

由于e 和 pi两者都声明为private,module_example不能再访问这些变量程序。

但是其他模块子程序可以访问它们:

module constants  
implicit none 

   real, parameter,private :: pi = 3.1415926536  
   real, parameter, private :: e = 2.7182818285 

contains      
   subroutine show_consts()          
      print*, "Pi = ", pi          
      print*, "e = ", e     
   end subroutine show_consts 

   function ePowerx(x)result(ePx) 
   implicit none
      real::x
      real::ePx
      ePx = e ** x
   end function ePowerx

   function areaCircle(r)result(a)  
   implicit none
      real::r
      real::a
      a = pi * r**2  
   end function areaCircle

end module constants 


program module_example     
use constants      
implicit none     

   call show_consts() 

   Print*, "e raised to the power of 2.0 = ", ePowerx(2.0)
   print*, "Area of a circle with radius 7.0 = ", areaCircle(7.0)  

end program module_example

当编译并执行上述程序,它会产生以下结果:

Pi = 3.14159274    
e = 2.71828175    
e raised to the power of 2.0 = 7.38905573    
Area of a circle with radius 7.0 = 153.938049   

Fortran内部函数

内部函数为Fortran语言提供一些常见和重要的功能。我们已经讨论过阵列,字符和字符串一些函数。

内部函数可归类为:

  • ​ 数值函数
  • ​ 数学函数
  • ​ 数字查询函数
  • ​ 浮点操作函数
  • ​ 位操作函数
  • ​ 字符函数
  • ​ 类函数
  • ​ 逻辑函数
  • ​ 数组函数

我们在阵列章讨论的阵列功能。在下面的章节中,提供了与其他类别的所有这些功能的简要说明。

函数名称列,

  • ​ A 代表任何类型的数值变量
  • ​ R 代表一个真实的或整型变量
  • ​ X 和 Y 代表实际变量
  • ​ Z 代表复数变量
  • ​ W 表示实数或复数变量

数值函数

Function 描述
ABS (A) 返回A的绝对值
AIMAG (Z) 返回复数Z的虚部
AINT (A [, KIND]) 截断Z小数部分接近零,返回一个实数。
ANINT (A [, KIND]) 返回一个实数值,最接近的整数或整数。
CEILING (A [, KIND]) 返回比最小整数大于或等于数A.
CMPLX (X [, Y, KIND]) 其转换实数变量X和Y的一些复数X + iY; 如果Y不存在,则使用0。
CONJG (Z) 返回复数Z的复共轭
DBLE (A) 转换A成到双精度实数。
DIM (X, Y) 返回X和Y的正差
DPROD (X, Y) 返回实数 X 和 Y 产生的双精度
FLOOR (A [, KIND]) 提供了比最大的整数小于或等于数A.
INT (A [, KIND]) 将其转换为数字(真实或整数)为整数,截断向零的实部。
MAX (A1, A2 [, A3,…]) 返回的参数的最大值,相同类型
MIN (A1, A2 [, A3,…]) 返回的参数的最小值,相同类型
MOD (A, P) 返回用P除以A余数部分,这两个参数类型相同 (A-INT(A/P)*P)
MODULO (A, P) 返回一个模P:(A-FLOOR(A/P)*P)
NINT (A [, KIND]) 返回一个最接近整数A的数
REAL (A [, KIND]) 将其转换为实数类型
SIGN (A, B) 返回一个乘以P. 符号的绝对值基本上它转移B的标志为A.

示例

program numericFunctions
implicit none  

   ! define constants  
   ! define variables
   real :: a, b 
   complex :: z

   ! values for a, b 
   a = 15.2345
   b = -20.7689

   write(*,*) 'abs(a): ',abs(a),' abs(b): ',abs(b)   
   write(*,*) 'aint(a): ',aint(a),' aint(b): ',aint(b) 
   write(*,*) 'ceiling(a): ',ceiling(a),' ceiling(b): ',ceiling(b)   
   write(*,*) 'floor(a): ',floor(a),' floor(b): ',floor(b)  

   z = cmplx(a, b)
   write(*,*) 'z: ',z   

end program numericFunctions

当编译并执行上述程序,它会产生以下结果:

abs(a): 15.2344999   abs(b): 20.7688999    
aint(a): 15.0000000  aint(b): -20.0000000    
ceiling(a): 16  ceiling(b): -20
floor(a): 15  floor(b): -21
z: (15.2344999, -20.7688999)

数学函数

函数 描述
ACOS (X) 返回该反余弦在范围(0,π),以弧度的形式。
ASIN (X) 返回该反正弦在范围(-π/ 2,π/ 2),单位为弧度。
ATAN (X) 返回反正切的范围(-π/ 2,π/ 2),单位为弧度。
ATAN2 (Y, X) 返回反正切的范围(-π,π),以弧度表示。
COS (X) 返回参数的弧度的余弦值。
COSH (X) 返回参数的弧度的双曲余弦值。
EXP (X) 返回X的指数值
LOG (X) 返回X的自然对数值
LOG10 (X) 返回常用对数(10为基数)X的值
SIN (X) 返回参数的弧度的正弦值。
SINH (X) 返回参数的弧度双曲正弦。
SQRT (X) 返回X的平方根
TAN (X) 返回参数的弧度的切线。
TANH (X) 返回参数弧度的双曲正切值。

示例

下列程序计算水平和垂直位置x和y表示抛射时间,t:

这里, x = u t cos a 以及 y = u t sin a - g t2 / 2

program projectileMotion  
implicit none  

   ! define constants  
   real, parameter :: g = 9.8  
   real, parameter :: pi = 3.1415927  

   !define variables
   real :: a, t, u, x, y   

   !values for a, t, and u 
   a = 45.0
   t = 20.0
   u = 10.0

   ! convert angle to radians  
   a = a * pi / 180.0  
   x = u * cos(a) * t   
   y = u * sin(a) * t - 0.5 * g * t * t  

   write(*,*) 'x: ',x,'  y: ',y   

end program projectileMotion

​ 当编译并执行上述程序,它会产生以下结果:

x: 141.421356  y: -1818.57861  

数字查询函数

这些函数的工作在整数模型和浮点运算。该函数返回相同的种类作为变量X,它可以是实数,在某些情况下,拥有整数的性质。

函数 描述
DIGITS (X) 返回显著模型的位数。
EPSILON (X) 返回相比一个是几乎可以忽略不计的数目。换句话说,它返回最小值,使得REAL( 1.0, KIND(X)) + EPSILON(X)为不等于REAL( 1.0, KIND(X))。
HUGE (X) 返回模型最多数量
MAXEXPONENT (X) 返回该模型的最大指数
MINEXPONENT (X) 返回该模型的最小指数
PRECISION (X) 返回小数精度
RADIX (X) 返回该模型的基数
RANGE (X) 返回十进制指数范围
TINY (X) 返回该模型的最小正数

浮点操作函数

函数 描述
EXPONENT (X) 返回一个模型数的指数部分
FRACTION (X) 返回一个数的小数部分
NEAREST (X, S) 返回给定的方向最近的不同处理器编号
RRSPACING (X) 返回型号的邻近给定数量的相对间隔的倒数
SCALE (X, I) 乘以一个实数由基数的整数次幂
SET_EXPONENT (X, I) 返回一个数的指数部分
SPACING (X) 返回型号的绝对间隔接近指定数值

位操作函数

函数 描述
BIT_SIZE (I) 返回该模型的比特数
BTEST (I, POS) 位测试
IAND (I, J) 逻辑与
IBCLR (I, POS) 清除位
IBITS (I, POS, LEN) 位提取
IBSET (I, POS) 设置位
IEOR (I, J) 异或
IOR (I, J) 包括或
ISHFT (I, SHIFT) 逻辑移位
ISHFTC (I, SHIFT [, SIZE]) 循环移位
NOT (I) 逻辑补

字符函数

函数 描述
ACHAR (I) 它返回ASCII整理序列中的第i个字符。
ADJUSTL (STRING) 它通过调节删除任何前导空格和插入尾随空白留下的字符串
ADJUSTR (STRING) 它去除右尾随空白和插入前导空格调整字符串。
CHAR (I [, KIND]) 它返回特定机器整理序列中的第i个字符
IACHAR (C) 它返回字符的ASCII码排序序列中的位置。
ICHAR (C) 它返回字符在机器(处理器)特定排序序列中的位置。
INDEX (STRING, SUBSTRING [, BACK]) 它返回SUBSTRING内STRING最左边(最右边如果返回.TRUE。)起始位置。
LEN (STRING) 它返回字符串的长度。
LEN_TRIM (STRING) 它返回一个字符串的长度没有结尾的空白字符。
LGE (STRING_A, STRING_B) 词汇上大于或等于
LGT (STRING_A, STRING_B) 词汇上大于
LLE (STRING_A, STRING_B) 词汇上大于或等于以下
LLT (STRING_A, STRING_B) 词汇上小于
REPEAT (STRING, NCOPIES) 重复并置
SCAN (STRING, SET [, BACK]) 它返回STRING属于集,或者0,如果都不属于最左边(最右边如果返回.TRUE。)字符的索引。
TRIM (STRING) 删除结尾的空白字符
VERIFY (STRING, SET [, BACK]) 验证字符集的字符串

类型函数

函数 描述
KIND (X) 它返回种类类型的参数值。
SELECTED_INT_KIND (R) 它返回一种为特定网络版的指数范围类型的参数。
SELECTED_REAL_KIND ([P, R]) 实数类型的参数值,指定精度和范围

逻辑函数

Function 描述
LOGICAL (L [, KIND]) 逻辑型的不同种类型参数对象之间转换

Fortran数字精度

我们已经讨论过了,在旧版本的 Fortran,有两个实型类型:默认的实型和双精度型。

然而,Fortran语言90/95提供了更多通过种指定精度控制实数和整数数据类型。

类型属性

不同类型的数字都在计算机内部存储方式不同。 kind属性允许指定一个数字内部存储。例如,

real, kind = 2 :: a, b, c
real, kind = 4 :: e, f, g
integer, kind = 2 :: i, j, k
integer, kind = 3 :: l, m, n

在上述声明中,实际变量e,f和g 比实型变量 a,b 和 c 更精确。整数变数l,m 和 n,可以存储较大的值,并有更多的存储比整数变量I,J和k有更多位。虽然这是依赖于机器。

示例

program kindSpecifier
implicit none

   real(kind = 4) :: a, b, c
   real(kind = 8) :: e, f, g
   integer(kind = 2) :: i, j, k
   integer(kind = 4) :: l, m, n
   integer :: kind_a, kind_i, kind_e, kind_l

   kind_a = kind(a)
   kind_i = kind(i)
   kind_e = kind(e)
   kind_l = kind(l)

   print *,'default kind for real is', kind_a
   print *,'default kind for int is', kind_i
   print *,'extended kind for real is', kind_e
   print *,'default kind for int is', kind_l

end program kindSpecifier

当编译并执行上述程序,将产生以下结果:

default kind for real is 4
default kind for int is 2
extended kind for real is 8
default kind for int is 4

查询变量的大小

有一些内在的功能,用于询问数字的大小。

例如,bit_size(i)内部函数指定用于存储位数。对于实数,precision(x)内部函数,返回小数位精度的数字,而range(x)内部函数返回指数的十进制范围。

例子

program getSize
implicit none

   real (kind = 4) :: a
   real (kind = 8) :: b
   integer (kind = 2) :: i
   integer (kind = 4) :: j

   print *,'precision of real(4) =', precision(a)
   print *,'precision of real(8) =', precision(b)

   print *,'range of real(4) =', range(a)
   print *,'range of real(8) =', range(b)


   print *,'maximum exponent of real(4) =' , maxexponent(a)
   print *,'maximum exponent of real(8) =' , maxexponent(b)

   print *,'minimum exponent of real(4) =' , minexponent(a)
   print *,'minimum exponent of real(8) =' , minexponent(b)

   print *,'bits in integer(2) =' , bit_size(i)
   print *,'bits in integer(4) =' , bit_size(j)

end program getSize

当编译并执行上述程序,将产生以下结果:

precision of real(4) = 6
precision of real(8) = 15
range of real(4) = 37
range of real(8) = 307
maximum exponent of real(4) = 128
maximum exponent of real(8) = 1024
minimum exponent of real(4) = -125
minimum exponent of real(8) = -1021
bits in integer(2) = 16
bits in integer(4) = 32

获取类型值

Fortran语言提供了两个内部函数来获得类型值整数和实数的精度:

  • ​ selected_int_kind (r)
  • ​ selected_real_kind ([p, r])

selected_real_kind函数返回一个整数,一个给定的小数精度p 和十进制指数范围r 的类型的参数值。小数精度是明显的位数,而小数指数范围规定的最小和最大可表示数。因此该范围是从10-r 到 10+r。

例如,selected_real_kind (p = 10, r = 99) 返回所需的10精确到小数点后类型值,和一系列从10-99〜10+99。

示例

program getKind
implicit none

   integer:: i
   i = selected_real_kind (p = 10, r = 99) 
   print *,'selected_real_kind (p = 10, r = 99)', i

end program getKind

当编译并执行上述程序,将产生以下结果:

selected_real_kind (p = 10, r = 99) 8

Fortran编程风格

编程风格是所有关于下面的一些规则,同时制定方案。这些好的做法传递价值就类似可读性和明确性在程序中。

一个好的程序应该具有以下特点:

  • ​ 可读性
  • ​ 正确的逻辑结构
  • ​ 不言自明的注释和备注

例如,如果做类似下面的注释,它不会有太大的帮助:

! loop from 1 to 10 
do i=1,10  

但是,如果正在计算二项式系数,需要这个循环nCr,那么像这样的注释是有好处的:

! loop to calculate nCr 
do i=1,10
  • ​ 缩进代码块,使各个层次的代码清晰。
  • ​ 自我检查代码,以确保零会有类似除法,没有数值误错,负实数的负实数或对数平方根。
  • ​ 包括代码,以确保变量不采取非法或超范围值,即输入验证。
  • ​ 没有把检查是不必要的,并且会减慢执行。例如:
real :: x 
x = sin(y) + 1.0

if (x >= 0.0) then
   z = sqrt(x)
end if
  • ​ 采用适当的算法的代码编写明显。
  • ​ 拆分延续长表达式使用标记 ‘&’.
  • ​ 富有意义的变量名命名。

Fortran调试程序

调试工具用于搜索程序的错误。

通过代码调试器的程序步骤,并允许在程序执行期间,检查变量和其他数据对象的值。

它加载的源代码,运行在调试器中的程序。调试器调试程序是:

  • ​ 设置断点,
  • ​ 通过源代码步进,
  • ​ 设置观察点。

断点指定的程序应该停止,特别是后代码的临界行。这些变量后,程序执行在断点处进行检查。

调试程序也检查了源代码行。

观看点是在需要时进行检查,特别是在一个读或写操作的一些变量的值。

gdb调试器

gdb调试器,GNU调试器一般由Linux操作系统自带。对于X窗口系统,GDB自带的图形界面和程序命名为 xxgdb。

下表提供了GDB的一些命令:

命令 目的
break 设置一个断点
run 开始执行
cont 继续执行
next 只执行源代码的下一行,不进一步的任何函数调用
step 通过步入函数情况下,一个函数调用执行源代码的下一行

dbx调试器

还有另外一个调试器,dbx调试器,用在Linux。

下表列出了在dbx中的一些命令:

命令 目的
stop[var] 设置一个断点当变量var的值更改。
stop in [proc] 它停止执行当过程被进入
stop at [line] 它在指定行设置一个断点
run 开始执行
cont 继续执行
next 只执行源代码的下一行,不进入任何函数调用。
step 通过步入函数情况下,一个函数调用执行源代码的下一行。

文章作者: 杰克成
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 杰克成 !
评论
  目录