Fortran 简明教程

Fortran - Quick Guide

Fortran - Overview

Fortran,源自公式翻译系统,是一门通用、命令式的编程语言。它用于数值科学计算。

Fortran 最初由 IBM 于 20 世纪 50 年代开发,用于科学和工程应用。Fortran 长期霸屏此编程领域,并因以下原因而广泛用于高性能计算领域:

支持:

  1. · 数值分析和科学计算

  2. Structured programming

  3. Array programming

  4. Modular programming

  5. Generic programming

  6. · 超级计算机上的高性能计算

  7. Object oriented programming

  8. Concurrent programming

  9. · 在计算机系统之间具有合理的移植性

Facts about Fortran

  1. Fortran 由约翰·巴科斯于 1957 年领导的团队在 IBM 创建。

  2. 最初,名称通常全部大写,但当前标准和实现只要求第一个字母大写。

  3. Fortran 代表公式翻译器。

  4. 最初开发用于科学计算,对字符字符串和其他通用编程所需结构的支持非常有限。

  5. 后来的扩展和完善使其成为具有良好可移植性的高级编程语言。

  6. 最初版本 Fortran I、II 和 III 现在被认为已过时。

  7. 仍在使用的最老版本是 Fortran IV 和 Fortran 66。

  8. 当今最常用的版本是:Fortran 77、Fortran 90 和 Fortran 95。

  9. Fortran 77 将字符串添加为独立类型。

  10. Fortran 90 添加各种线程和直接数组处理。

Fortran - Environment Setup

Setting up Fortran in Windows

G95 是用于在 Windows 中设置 Fortran 的 GNU Fortran 多架构编译器。Windows 版本使用 MinGW 模拟 Windows 上的 Unix 环境。安装程序处理此问题并自动将 g95 添加到 Windows PATH 变量。

installer setup
mini installer setup

How to use G95

在安装过程中,如果你选择“推荐”选项, g95 将自动添加到你的 PATH 变量。这意味着你可以直接打开一个新的命令提示符窗口并输入“g95”来启动编译器。以下是一些基本命令,助你入门。

Sr.No

Command & Description

1

g95 –c hello.f90 将 hello.f90 编译到名为 hello.o 的目标文件

2

g95 hello.f90 编译 hello.f90 并将其链接到可执行文件 a.out

3

g95 -c h1.f90 h2.f90 h3.f90 编译多个源文件。如果进行顺利,将创建 h1.o、h2.o 和 h3.o 对象文件

4

g95 -o hello h1.f90 h2.f90 h3.f90 编译多个源文件,并将其链接到一起,形成名为“hello”的可执行文件

Command line options for 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” 和 “.F03”结尾的名称指示。可指定多个源文件。也可指定对象文件,并将其链接起来形成可执行文件。

Fortran - Basic Syntax

Fortran 程序由各种程序单元组成,例如主程序、模块以及外部子程序或过程。

每个程序包含一个主程序,而且可以或不可以包含其他程序单元。主程序的语法如下所示 −

program program_name
implicit none

! type declaration statements
! executable statements

end program program_name

A Simple Program in 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

请注意 −

  1. 所有 Fortran 程序都以关键字 program 开头,以关键字 end program, 结尾,后跟程序的名称。

  2. implicit none 语句允许编译器检查所有变量类型是否已正确声明。您必须始终在每个程序的开头使用 implicit none

  3. Fortran 中的注释以感叹号 (!) 开始,因为此号 (在字符字符串中除外) 后的所有字符都会被编译器忽略。

  4. print * 命令可在屏幕上显示数据。

  5. 缩进代码行有利于保持程序的可读性。

  6. Fortran 同时允许使用大写字母和小写字母。Fortran 不区分大小写,但字符串文字除外。

Basics

Fortran 的 basic character set 包含 −

  1. 字母 A …​ Z 和 a …​ z

  2. 数字 0 …​ 9

  3. the underscore (_) character

  4. 特殊字符 = : + 空格 - * / ( ) [ ] , . $ ' ! " % & ; < > ?

Tokens 由基本字符集中的字符组成。标记可以是关键字、标识符、常量、字符串文字或符号。

程序语句由标记组成。

Identifier

标识符是用来标识变量、过程或任何其他用户定义项的名称。Fortran 中的名称必须遵循以下规则 −

  1. It cannot be longer than 31 characters.

  2. It must be composed of alphanumeric characters (all the letters of the alphabet, and the digits 0 to 9) and underscores (_).

  3. First character of a name must be a letter.

  4. Names are case-insensitive

Keywords

Keywords are special words, reserved for the language. These reserved words cannot be used as identifiers or names.

The following table, lists the Fortran keywords −

The non-I/O keywords

allocatable

allocate

assign

assignment

block data

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

The I/O related keywords

backspace

close

endfile

format

inquire

open

print

read

rewind

Write

Fortran - Data Types

Fortran provides five intrinsic data types, however, you can derive your own data types as well. The five intrinsic types are −

  1. Integer type

  2. Real type

  3. Complex type

  4. Logical type

  5. Character type

Integer Type

The integer types can hold only integer values. The following example extracts the largest value that can be held in a usual four byte integer −

program testingInt
implicit none

   integer :: largeval
   print *, huge(largeval)

end program testingInt

当您编译并执行以上程序时,将生成以下结果——

2147483647

Note that the huge() function gives the largest number that can be held by the specific integer data type. You can also specify the number of bytes using the kind specifier. The following example demonstrates this −

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

Real Type

It stores the floating point numbers, such as 2.0, 3.1415, -100.876, etc.

Traditionally there are two different real types, the default real type and double precision type.

However, Fortran 90/95 provides more control over the precision of real and integer data types through the kind specifier, which we will study in the chapter on Numbers.

The following example shows the use of real data type −

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

Complex Type

This is used for storing complex numbers. A complex number has two parts, the real part and the imaginary part. Two consecutive numeric storage units store these two parts.

For example, the complex number (3.0, -5.0) is equal to 3.0 – 5.0i

We will discuss Complex types in more detail, in the Numbers chapter.

Logical Type

There are only two logical values: .true. and .false.

Character Type

The character type stores characters and strings. The length of the string can be specified by len specifier. If no length is specified, it is 1.

For example,

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

The expression, name(1:4) would give the substring “Zara”.

Implicit Typing

Older versions of Fortran allowed a feature called implicit typing, i.e., you do not have to declare the variables before use. If a variable is not declared, then the first letter of its name will determine its type.

从 i、j、k、l、m 或 n 开始的变量名,被认为是整数变量,其它是实数变量。但是,必须将所有变量声明出来,因为这是良好的编程习惯。为此,您用以下语句开始程序:

implicit none

此语句关闭隐式类型。

Fortran - Variables

变量只不过是一个存储区域的名称,我们的程序可以对其进行操作。每个变量应该有特定的类型,它确定变量内存的大小和布局;可以在该内存内存储的值范围;以及可以应用于该变量的操作集。

变量的名称可以由字母、数字和下划线字符组成。Fortran 中的名称必须遵循以下规则:

  1. It cannot be longer than 31 characters.

  2. It must be composed of alphanumeric characters (all the letters of the alphabet, and the digits 0 to 9) and underscores (_).

  3. First character of a name must be a letter.

  4. Names are case-insensitive.

根据前一章中解释的基本类型,以下是有类型变量:

Sr.No

Type & Description

1

Integer 它只能存储整数。

2

Real 它存储浮点数。

3

Complex 它用于存储复数。

4

Logical 它存储逻辑布尔值。

5

Character 它存储字符或字符串。

Variable Declaration

变量在程序(或子程序)开始时在类型声明语句中进行声明。

变量声明的语法如下:

type-specifier :: variable_name

For example

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

Example

以下示例演示变量声明、赋值和屏幕显示:

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 Point"
   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 Point

Fortran - Constants

常量是指程序在其执行期间不能更改的固定值。这些固定值也称为 literals

常量可以是任意基本数据类型,例如整型常量、浮点常量、字符常量、复常量或字符串常量。只有两个逻辑常量: .true..false.

常量与常规变量一样,不同之处在于它们的的值在定义后不能修改。

Named Constants and Literals

有两种类型的常量:

  1. Literal constants

  2. Named constants

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

例如,以下是字面常量 -

Type

Example

Integer constants

0 1 -1 300 123456789

Real constants

0.0 1.0 -1.0 123.456 7.1E+10 -52.715E-30

Complex constants

(0.0, 0.0) (-123.456E+30, 987.654E-29)

Logical constants

.true. .false.

Character constants

“PQR”、“a”、“123’abc$% @!" " a quote "" " 'PQR' 'a' '123"abc$% @!‘’单引号’’ ‘”

已命名常量既有值又有名称。

已命名常量应在程序或过程的开头声明,如同变量类型声明,指示其名称和类型。已命名常量用参数属性声明。例如,

real, parameter :: pi = 3.1415927

Example

以下程序计算重力作用下垂直运动的位移。

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 - Operators

运算符是一个告诉编译器执行特定数学或逻辑操作的符号。Fortran 提供以下类型的运算符 -

  1. Arithmetic Operators

  2. Relational Operators

  3. Logical Operators

让我们逐个查看所有这些类型的运算符。

Arithmetic Operators

下表显示了 Fortran 支持的所有算术运算符。假设变量 A 保存 5,变量 B 保存 3,则 -

Operator

Description

Example

+

加法运算符,加两个操作数。

A + B 将得到 8

-

减法运算符,从第一个操作数中减去第二个操作数。

A - B 将得到 2

*

乘法运算符,将两个操作数相乘。

A * B 将得到 15

/

除法运算符,将分子除以分母。

A / B 将给出 1

**

指数运算符,将一个操作数提升到另一操作数的幂次。

A ** B 将给出 125

Relational Operators

下表显示了 Fortran 支持的所有关系运算符。假设变量 A 为 10,变量 B 为 20,则 −

Operator

Equivalent

Description

Example

==

.eq.

检查两个操作数的值是否相等,如果相等,则条件变为真。

(A == B) 不为真。

/=

.ne.

检查两个操作数的值是否相等,如果值不相等,则条件变为真。

(A != B) 为真。

>

.gt.

检查左操作数的值是否大于右操作数的值,如果大于,则条件变为真。

(A > B) 不为真。

<

.lt.

检查左操作数的值是否小于右操作数的值,如果小于,则条件变为真。

(A < B) 为真。

>=

.ge.

检查左操作数的值是否大于或等于右操作数的值,如果大于或等于,则条件变为真。

(A >= B) 不为真。

.le.

检查左操作数的值是否小于或等于右操作数的值,如果小于或等于,则条件变为真。

(A ⇐ B) 为真。

Logical Operators

Fortran 中的逻辑运算符仅针对逻辑值 .true. 和 .false. 工作。

下表显示了 Fortran 支持的所有逻辑运算符。假设变量 A 为 .true.,变量 B 为 .false.,则 −

Operator

Description

Example

.and.

称为逻辑 AND 运算符。如果两个运算数都非零,条件变为真。

(A .and. B) 为假。

.or.

称为逻辑 OR 运算符。如果任何一个运算数非零,条件变为真。

(A .or. B) 为真。

.not.

称为逻辑 NOT 运算符。用于反转操作数的逻辑状态。如果条件为 true,则逻辑 NOT 运算符会将其变为 false。

!(A .and. B) 为真。

.eqv.

称为逻辑等价运算符。用于检查两个逻辑值是否相等。

(A .eqv. B) 为假。

.neqv.

称为逻辑不等价运算符。用于检查两个逻辑值是否不等价。

(A .neqv. B) 为真。

Operators Precedence in Fortran

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

例如,x = 7 + 3 * 2;此处,x 被赋值为 13,而不是 20,因为运算符 * 优先级高于 +,因此其首先与 3*2 相乘,然后加到 7 中。

此处,优先级最高的运算符显示在表顶部,优先级最低的运算符显示在表底部。在表达式中,将首先评估优先级较高的运算符。

Category

Operator

Associativity

逻辑非和负号

.not. (-)

Left to right

Exponentiation

**

Left to right

Multiplicative

* /

Left to right

Additive

+ -

Left to right

Relational

< ⇐ > >=

Left to right

Equality

== /=

Left to right

Logical AND

.and.

Left to right

Logical OR

.or.

Left to right

Assignment

=

Right to left

Fortran - Decisions

决策结构要求程序员指定程序要评估或测试的一个或多个条件,以及在条件确定为 true 时要执行的语句或语句,另外还可选择在条件确定为 false 时要执行的其他语句。

以下是大多数编程语言中常见的典型决策结构的一般形式 −

decision making

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

Sr.No

Statement & Description

1

If… then construct @`{s0} 语句由一个逻辑表达式后跟一条或多条语句组成。

2

If… then…​else construct @`{s2} 语句后跟一个可选的 else statement, ,在逻辑表达式为假时执行。

3

if…​else if…​else Statement @`{s5} 语句构造可以有一个或多个可选的 else-if 构造。当 if 条件失败时,执行紧随其后的 else-if 。如果 else-if 也失败,则执行其后继 else-if 语句(如果存在),依此类推。

4

nested if construct 您可以在另一个 ifelse if 语句中使用一个 ifelse if 语句。

5

select case construct select case 语句允许对变量进行测试,以使其相对于值列表相等。

6

nested select case construct 您可以在另一个 select case 语句中使用一个 select case 语句。

Fortran - Loops

在某些情况下,您需要多次执行代码块。通常,语句按顺序执行:函数中的第一个语句首先执行,其次是第二个语句,依此类推。

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

循环语句允许我们多次执行一个语句或一组语句,以下是大多数编程语言中循环语句的一般形式 −

if conditional

Fortran 提供以下类型的循环构造来处理循环要求。单击以下链接以查看其详细信息。

Sr.No

Loop Type & Description

1

do loop 此构造使语句或一系列语句能够在给定条件为真时进行迭代执行。

2

do while loop 在给定条件为真时重复语句或语句组。它在执行循环体之前测试条件。

3

nested loops 您可以在任何其他循环构造中使用一个或多个循环构造。

Loop Control Statements

循环控制语句改变了它在正常序列中的执行。当执行退出一个作用域时,在该作用域中创建的所有自动对象会被销毁。

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

Sr.No

Control Statement & Description

1

exit 如果执行 exit 语句,则退出循环,并且程序的执行在 end do 语句之后的第一个可执行语句处继续。

2

cycle 如果执行 cycle 语句,则程序将从下一次迭代的开始继续。

3

stop 如果您希望停止程序的执行,则可以插入 stop 语句。

Fortran - Numbers

Fortran 中的数字由三种固有数据类型表示 −

  1. Integer type

  2. Real type

  3. Complex type

Integer Type

整型只能保存整数值。以下示例提取了一个普通四字节整数中可以保存的最大值 −

program testingInt
implicit none

   integer :: largeval
   print *, huge(largeval)

end program testingInt

当您编译并执行以上程序时,将生成以下结果——

2147483647

请注意, huge() 函数给出特定整数数据类型可以保存的最大数字。您还可以使用 kind 说明符指定字节数。以下示例对此进行了说明 -

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

Real Type

It stores the floating point numbers, such as 2.0, 3.1415, -100.876, etc.

传统上有两种不同的 @ {s0} 类型:默认实数类型和 @ {s1} 类型。

但是,Fortran 90/95 通过我们稍后将研究的 @ {s2} 说明符提供了对实数和整数数据类型精度的更多控制。

The following example shows the use of real data type −

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

Complex Type

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

For example, the complex number (3.0, -5.0) is equal to 3.0 – 5.0i

通用函数 @ {s3} 创建一个复数。它产生一个实部和虚部均为单精度的结果,而不管输入参数的类型如何。

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)

The Range, Precision and Size of Numbers

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

下表显示了整数的位数和范围 −

Number of bits

Maximum value

Reason

64

9,223,372,036,854,774,807

(2**63)–1

32

2,147,483,647

(2**31)–1

下表显示了实数的位数、最小值和最大值以及精度。

Number of bits

Largest value

Smallest value

Precision

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

The Kind Specifier

在科学编程中,人们经常需要了解正在完成工作的硬件平台的数据范围和精度。

固有函数 @ {s4} 允许您在运行程序之前查询硬件数据表示的详细信息。

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 :: 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 - Characters

Fortran 语言可以将字符视为单个字符或连续字符串。

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

字符常量是固定值字符字符串。

固有数据类型 @ {s5} 存储字符和字符串。字符串长度可以用 @ {s6} 说明符指定。如果未指定长度,则为 1。您可以按位置引用字符串中的各个字符;最左边的字符位于位置 1。

Character Declaration

声明字符类型数据与其他变量相同 −

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. Bean'

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

end program hello

当您编译并执行以上程序时,将生成以下结果——

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

Concatenation of Characters

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

The following example demonstrates this −

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. Bean'

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

end program hello

当您编译并执行以上程序时,将生成以下结果——

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

Some Character Functions

下表显示了一些常用的字符函数以及描述−

Sr.No

Function & Description

1

len(string) 它返回字符串的长度

2

index(string,sustring) 它在另一个字符串中查找子字符串的位置,如果未找到则返回 0。

3

achar(int) 它将整数转换为字符

4

iachar(c) 它将字符转换为整数

5

trim(string) 它返回删除尾部空格的字符串。

6

scan(string, chars) 它从左到右(除非 back=.true。)搜索“string”,查找“chars”中包含的任何字符的第一个出现。它返回一个表示该字符位置的整数,或者如果没有找到“chars”中的任何字符,则返回零。

7

verify(string, chars) 它从左到右(除非 back=.true。)扫描“string”,查找“chars”中不包含的任何字符的第一个出现。它返回一个表示该字符位置的整数,或者如果找不到“chars”中的任何字符,则返回零

8

adjustl(string) 它左对齐“string”中包含的字符

9

adjustr(string) 它右对齐“string”中包含的字符

10

len_trim(string) 它返回一个整数,该整数等于“string”的长度(len(string))减去尾部空格的数量。

11

repeat(string,ncopy) 它返回一个字符串,其长度等于“ncopy”乘以“string”的长度,并包含“ncopy”次连接的“string”副本。

Example 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.

Example 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 isMr.   Rowan          Atkinson
 Here isMr. Rowan Atkinson

Example 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

Checking Lexical Order of Characters

以下函数确定字符的词法序列−

Sr.No

Function & Description

1

lle(char, char) 比较第一个字符是否按词法顺序小于或等于第二个字符

2

lge(char, char) 比较第一个字符是否按词法顺序大于或等于第二个字符

3

lgt(char, char) 比较第一个字符是否按词法顺序大于第二个字符

4

llt(char, char) 比较第一个字符是否按词法顺序小于第二个字符

Example 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 - Strings

Fortran 语言可以将字符视为单个字符或连续字符串。

一个字符串可以只有单个字符长,甚至可以是零长。在 Fortran 中,字符常量是放在一对双引号或单引号中的。

固有数据类型 character 存储字符和字符串。字符串的长度可由 len specifier 指定。如果没有指定长度,则长度为 1。你可以在字符串中按位置来引用单个字符;最左边的字符位于位置 1。

String Declaration

字符串的声明与其他变量相同 −

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 isMr.   Rowan          Atkinson
A big hello from Mr. Bean

String Concatenation

连接操作符 // 连接字符串。

The following example demonstrates this −

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

Extracting Substrings

在 Fortran 中,你可以通过对字符串指定索引来从中提取子字符串,在成对的括号中给出子字符串的开始和结束索引。这称为范围说明符。

以下示例演示如何从字符串“hello world”中提取子字符串“world” −

program subString

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

end program subString

当您编译并执行以上程序时,将生成以下结果——

World

Example

以下示例使用 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

Trimming Strings

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

Example

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!

Left and Right Adjustment of Strings

函数 adjustl 接受一个字符串,并通过删除前导空格并将它们追加为尾部空格来返回它。

函数 adjustr 接受一个字符串,并通过删除尾部空格并将它们追加为前导空格来返回它。

Example

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

Searching for a Substring in a String

index 函数接受两个字符串,并检查第二个字符串是否为第一个字符串的子字符串。如果第二个参数是第一个参数的子字符串,则它将返回一个整数,该整数是第二个字符串在第一个字符串中的起始索引,否则返回 0。

Example

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 - Arrays

数组可以存储同一类型的固定大小的连续元素集合。数组用于存储数据集合,但将数组视为同类型变量的集合通常更有用。

所有阵列都包含连续的内存位置。最低地址对应于第一个元素,而最高地址对应于最后一个元素。

Numbers(1)

Numbers(2)

Numbers(3)

Numbers(4)

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

Declaring Arrays

使用 dimension 特性声明数组。

例如,要声明一个名为 number 的一维数组,其中包含 5 个元素的实数,则需要编写:

real, dimension(5) :: numbers

通过指定下标来引用数组的各个元素。数组的第一个元素的下标为 1。数组 numbers 包含五个实变量:numbers(1)numbers(2)numbers(3)numbers(4)numbers(5)

要创建一个名为 matrix 的 5 x 5 二维整数数组,请编写:

integer, dimension (5,5) :: matrix

也可以使用一些明确的下限声明一个数组,例如:

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

Assigning Values

可以针对各个成员分配值,例如:

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 /)

please note that there are no spaces allowed between the brackets ‘( ‘and the back slash ‘/’

Example

以下示例展示了上面讨论的概念。

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

下表提供了一些与数组相关的术语:

Term

Meaning

Rank

数组的维数。例如,对于名为 matrix 的数组,秩为 2,对于名为 numbers 的数组,秩为 1。

Extent

某个维度的元素数目。例如,numbers 数组的延伸为 5,名为 matrix 的数组在两个维度上的延伸为 3。

Shape

数组的形状是一维整数数组,包含每个维度中的元素数目(延伸)。例如,对于数组 matrix,形状为 (3, 3),对于 numbers 数组是 (5)。

Size

数组包含的元素数目。对于 matrix 数组,该值为 9,对于 numbers 数组,该值为 5。

Passing Arrays to Procedures

可以将数组作为参数传递给过程。以下示例演示了该概念:

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

Array Sections

到目前为止,我们只参考了整个数组,Fortran 提供了一种简单的方法,可以使用单个语句来引用几个元素或数组的一部分。

要访问数组部分,需要提供该部分的下限和上限,以及所有维度的步长(增量)。这种表示法称为 subscript triplet:

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

Array Intrinsic Functions

Fortran 90/95 提供了若干内在过程。它们可分为 7 类。

Fortran - Dynamic Arrays

一个 dynamic array 是一个其大小在编译时未知但会在执行时已知的数组。

使用特性 allocatable 声明动态数组。

例如,

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

必须声明数组的秩,即维度,但是,要为这样的数组分配内存,请使用 allocate 函数。

allocate ( darray(s1,s2) )

在程序中使用数组后,应使用 deallocate 函数释放所创建的内存。

deallocate (darray)

Example

以下示例展示了上面讨论的概念。

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

Use of Data Statement

使用 data 语句可以初始化多个数组,或者用于数组部分初始化。

数据语句的语法为 −

data variable / list / ...

Example

以下示例演示了此概念 −

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

Use of Where Statement

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

Example

以下示例演示了此概念 −

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 - Derived Data Types

Fortran 允许定义派生数据类型。派生数据类型也称为“结构”,它由不同类型的数据对象组成。

派生数据类型用于表示记录。例如,想要跟踪图书馆中的书籍,则可能想要跟踪每本书的以下属性 −

  1. Title

  2. Author

  3. Subject

  4. Book ID

Defining a Derived data type

要定义一个派生数据 type ,使用了 type 和 end type 语句。type 语句为程序定义了具有多个成员的新数据类型。type 语句的格式如下 −

type type_name
   declarations
end type

以下是你声明 Book 结构的方式 −

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

Accessing Structure Members

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

可以在类型声明语句中创建 Books 类型的结构,具体格式如下 −

type(Books) :: book1

可以使用组件选择器字符 (%) 访问结构的组件 −

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

Note that there are no spaces before and after the % symbol.

Example

以下程序说明了上述概念 −

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

Array of Structures

你还可以创建派生类型的数组 −

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 - Pointers

在大多数编程语言中,指针变量存储对象的内存地址。然而,在 Fortran 中,指针是一个数据对象,不仅可以存储内存地址,还具有更多功能。它还包含一个特定对象的一些其他信息,比如类型、级别、扩展名和内存地址。

通过分配或指针分配,可以将指针与目标关联。

Declaring a Pointer Variable

使用 pointer 属性声明指针变量。

以下示例展示了指针变量的声明 −

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

指针可以指向 −

  1. 一段动态分配的内存。

  2. 与指针同类的数据对象,具有 target 特性。

Allocating Space for a Pointer

allocate 语句允许为指针对象分配空间。例如 −

program pointerExample
implicit none

   integer, pointer :: p1
   allocate(p1)

   p1 = 1
   Print *, p1

   p1 = p1 + 4
   Print *, p1

end program pointerExample

编译并执行上述代码后,将产生以下结果 −

1
5

当不再需要时,应使用 deallocate 语句清空已分配的存储空间,并避免累积未使用且不可用的内存空间。

Targets and Association

目标是另一个普通变量,为其预留了空间。必须使用 target 特性声明目标变量。

使用关联运算符 (⇒) 将指针变量与目标变量关联起来。

让我们重写前一个示例来说明这个概念 −

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

空指针可以是 −

  1. Undefined

  2. Associated

  3. Disassociated

在上面的程序中,我们使用 ⇒ 运算符将指针 p1 与目标 t1 关联起来了。关联的函数测试指针的关联状态。

nullify 语句将指针与目标分离。

即使有多个指针指向同一目标,也不清空目标。不过,清空指针也暗示着无效化。

Example 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

请注意,每次运行代码时,内存地址都将不同。

Example 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 - Basic Input Output

到目前为止,我们已经看到,我们可以分别使用 read * statement, and display output to the screen using the *print 语句从键盘读取数据。这种输入-输出形式是 free format I/O,称为 list-directed 输入-输出。

自由格式简单 I/O 具有以下形式 −

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

然而,格式化 I/O 能让你更灵活地控制数据传输。

Formatted Input Output

格式化输入输出的语法如下 −

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

其中,

  1. fmt 是格式规范

  2. variable-list 是要从键盘读取或写入屏幕的变量列表

格式规范定义了格式化数据显示的方式。它包含一个字符串,其中包含括号中的一列 edit descriptors

edit descriptor 指示准确的格式,如字符和数字的显示宽度、小数点后的位数等。

For example

Print "(f6.3)", pi

下表描述了描述符:

Descriptor

Description

Example

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 的含义在下表中给出。实数值在其字段中右对齐。如果字段宽度不够容纳实数,则该字段将填充星号。请注意,要打印具有三个小数位的小数,需要至少十个字段宽度。一个用于尾数符号,两个用于零,四个用于尾数,两个用于指数本身。通常,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

以下符号与格式描述符一起使用:

Sr.No

Symbol & Description

1

c Column number

2

d 实数输入或输出的小数点右侧数字数

3

m 要显示的最小数字数

4

n 要跳过的空格数

5

r 重复计数 - 使用描述符或描述符组的次数

6

w 字段宽度 - 用于输入或输出的字符数

Example 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

Example 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

Example 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 = *******

The Format Statement

格式化语句允许您在一个语句中混合和匹配字符、整数和实数输出。以下示例对此进行了演示:

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 - File Input Output

Fortran 允许您从文件中读取数据和写入数据。

在上一章中,你已经看到了如何从终端读取数据以及将数据写入终端。在本章中,你将学习 Fortran 提供的文件输入和输出功能。

你可以读写一个或多个文件。OPEN、WRITE、READ 和 CLOSE 语句允许你实现这一点。

Opening and Closing Files

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

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

但是,open 语句的通用形式可能为:

open (list-of-specifiers)

下表描述了最常用的说明符:

Sr.No

Specifier & Description

1

[UNIT=] u 设备号 u 可以在 9-99 范围内的任意数字,并且它指示文件,你可以选择任意数字,但程序中的每个打开文件都必须具有唯一的数字。

2

IOSTAT= ios 这是一条 I/O 状态标识符,应为一个整数变量。如果 open 语句成功,则返回的 ios 值为零,否则返回非零值。

3

ERR = err 这是在发生任何错误的情况下控件跳转到的一个标签。

4

FILE = fname 文件名称,一个字符字符串。

5

STATUS = sta 它显示文件的先前状态。一个字符字符串,并且可以有三个值之一:NEW、OLD 或 SCRATCH。在关闭文件或程序结束时,将创建和删除一个临时文件。

6

ACCESS = acc 这是一条文件访问模式。可以有两个值之一:SEQUENTIAL 或 DIRECT。默认值为 SEQUENTIAL。

7

FORM = frm 它给出文件的格式化状态。可以有两个值之一:FORMATTED 或 UNFORMATTED。默认值为 UNFORMATTED。

8

RECL = rl 它指定直接访问文件中的每个记录的长度。

打开文件后,通过阅读和写入语句来访问它。完成后,应该使用 close 语句关闭它。

close 语句具有以下语法:

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

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

Example

此示例演示如何打开一个新文件以将一些数据写入文件中。

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 数组值写入其中。然后关闭文件。

Reading from and Writing into the File

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

它们具有以下语法 −

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

大多数规范符已在上面的表格中进行讨论。

END = s 规范符是一个语句标签,当程序达到文件结尾时,程序跳转到该标签。

Example

此示例演示了从文件中读取和写入文件。

在这个程序中,我们从上个示例中创建的文件 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 - Procedures

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

有两种类型的过程 −

  1. Functions

  2. Subroutines

Function

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

返回的数量称为 function value ,并且由函数名表示。

Syntax

函数的语法如下 −

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

请注意 −

  1. 您必须在主程序和过程中指定 implicit none

  2. 被调用函数中的参数 r 称为 dummy argument

The result Option

如果您希望将返回的值存储在函数名以外的其他名称中,可以使用 result 选项。

您可以将返回值变量名指定为 −

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

Subroutine

子例程不返回值,但可以修改其参数。

Syntax

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

Calling a Subroutine

您需要使用 call 语句调用子例程。

以下示例演示了子例程 swap 的定义和用法,该子例程更改了其参数的值。

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

Specifying the Intent of the Arguments

intent 属性允许您指定在过程中使用参数的目的。下表提供了 intent 属性的值 −

Value

Used as

Explanation

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

Recursive Procedures

当编程语言允许您在同一函数内调用函数时,就会发生递归。它称为函数的递归调用。

当过程直接或间接调用自身时,称为递归过程。您应该在声明前添加 recursive 一词来声明此类过程。

当函数以递归方式使用时,必须使用 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

Internal Procedures

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

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 - Modules

模块就像是一个包,在您编写非常大的程序或者您的函数或子例程可用于多个程序时,可将它们保留在内。

模块为您提供一种将程序拆分成多个文件的方法。

模块用于:

  1. 打包子程序、数据和接口块

  2. 定义可供多个例程使用的全局数据。

  3. 声明可用于您选择的任何例程内的变量。

  4. 将整个模块导入到另一个程序或子例程中使用。

Syntax of a Module

一个模块包含两部分:

  1. 用于语句声明的规范部分

  2. 用于子例程和函数定义的包含部分

模块的常规形式如下:

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

Using a Module into your Program

您可以通过 use 语句在程序或子程序中合并一个模块 -

use name

请注意

  1. 可以根据需要添加尽可能多的模块,每个模块都将放在单独的文件中并单独编译。

  2. 一个模块可以用于各种不同的程序。

  3. 同一个程序中可以多次使用一个模块。

  4. 在模块说明部分声明的变量对模块是全局的。

  5. 在模块中声明的变量将成为使用该模块的任何程序或例程中的全局变量。

  6. use 语句可以出现在主程序中,或者可以使用特定模块中声明的例程或变量的任何其他子程序或模块。

Example

以下示例演示了此概念 −

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

Accessibility of Variables and Subroutines in a Module

默认情况下,模块中的所有变量和子程序都可供使用模块代码的程序通过 use 语句使用。

但是,您可以使用 privatepublic 属性控制模块代码的可访问性。当您将某些变量或子程序声明为私有的时,它在模块外部不可用。

Example

以下示例说明了这一概念 -

在前面的示例中,我们有两个模块变量, epi. ,让我们将它们设为私有的并观察输出 -

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

由于 epi, 都被声明为私有,因此程序 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 - Intrinsic Functions

本征函数是一些通用且重要的函数,它是 Fortran 语言的一部分。我们已经在“数组”、“字符”和“字符串”章节中讨论了一些这些函数。

本征函数可以分类为 -

  1. Numeric Functions

  2. Mathematical Functions

  3. Numeric Inquiry Functions

  4. Floating-Point Manipulation Functions

  5. Bit Manipulation Functions

  6. Character Functions

  7. Kind Functions

  8. Logical Functions

  9. Array Functions.

我们在“数组”章节中讨论了数组函数。在下一部分中,我们将提供其他类别的所有这些函数的简要说明。

在函数名列中,

  1. A 表示任何类型的数值变量

  2. R 表示实变量或整变量

  3. X 和 Y 表示实变量

  4. Z represents complex variable

  5. W 表示实变量或复变量

Numeric Functions

Sr.No

Function & Description

1

ABS (A) 它返回 A 的绝对值

2

AIMAG (Z) 它返回复数 Z 的虚部

3

AINT (A [, KIND]) 它将 A 的小数部分截断为 0,返回一个实数,整数

4

ANINT (A [, KIND]) 它返回一个实数,最接近的整数或整数。

5

CEILING (A [, KIND]) 它返回大于或等于数字 A 的最小整数

6

CMPLX (X [, Y, KIND]) 它将实变量 X 和 Y 转换为复数 X+iY;如果 Y 为空,将使用 0

7

CONJG (Z) 它返回任意复数 Z 的复共轭

8

DBLE (A) 它将 A 转换为双精度实数

9

DIM (X, Y) 它返回 X 和 Y 的正差

10

DPROD (X, Y) 它返回 X 和 Y 的双精度实积

11

FLOOR (A [, KIND]) 它提供了小于或等于数字 A 的最大整数

12

INT (A [, KIND]) 它将数字(实数或整数)转换为整数,截断小数部分为 0

13

MAX (A1, A2 [, A3,&#8230;&#8203;]) 它返回参数的最大值,所有参数都同类型

14

MIN (A1, A2 [, A3,&#8230;&#8203;]) 它返回参数的最小值,所有参数都同类型

15

MOD (A, P) 它返回 A 除以 P 的余数,两个参数同类型(A-INT(A/P)*P)

16

MODULO (A, P) 它返回 A 模 P: (A-FLOOR(A/P)*P)

17

NINT (A [, KIND]) 它返回数字 A 的最近整数

18

REAL (A [, KIND]) 它转换为实数类型

19

SIGN (A, B) 它返回 A 的绝对值乘以 P 的符号。它基本上将 B 的符号传递给了 A。

Example

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)

Mathematical Functions

Sr.No

Function & Description

1

ACOS (X) 它返回 (0, π) 范围内的反余弦,以弧度为单位。

2

ASIN (X) 它返回 (-π/2, π/2) 范围内的反正弦,以弧度为单位。

3

ATAN (X) 它返回 (-π/2, π/2) 范围内的反正切,以弧度为单位。

4

ATAN2 (Y, X) 它返回 (-π, π) 范围内的反正切,以弧度为单位。

5

COS (X) 它返回以弧度为单位的参数的余弦。

6

COSH (X) 它返回以弧度为单位的参数的双曲余弦。

7

EXP (X) 它返回 X 的指数值。

8

LOG (X) 它返回 X 的自然对数值。

9

LOG10 (X) 它返回 X 的常用对数(以 10 为底)值。

10

SIN (X) 它返回以弧度为单位的参数的正弦。

11

SINH (X) 它返回以弧度为单位的参数的双曲正弦。

12

SQRT (X) 它返回 X 的平方根。

13

TAN (X) 它返回以弧度为单位的参数的正切。

14

TANH (X) 它返回以弧度为单位的参数的双曲正切。

Example

以下程序分别计算某个时间后的投射物水平和垂直位置 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

Numeric Inquiry Functions

这些函数适用于某一整数和浮点数算术模型。这些函数返回与变量 X 同样的数字的特性,该变量可以是实数值,在某些情况下还可以是整数。

Sr.No

Function & Description

1

DIGITS (X) 它返回模型的有效数字个数。

2

EPSILON (X) 它返回与 1 相比几乎可以忽略不计的数字。换言之,它返回的是一个最小值,使得 REAL( 1.0, KIND(X)) + EPSILON(X) 不等于 REAL( 1.0, KIND(X))。

3

HUGE (X) 它返回模型的最大数字

4

MAXEXPONENT (X) 它返回模型的最大指数

5

MINEXPONENT (X) 它返回模型的最小指数

6

PRECISION (X) 它返回十进制精度

7

RADIX (X) 它返回模型的基数

8

RANGE (X) 它返回十进制指数范围

9

TINY (X) 它返回模型的最小正值

Floating-Point Manipulation Functions

Sr.No

Function & Description

1

EXPONENT (X) 它返回模型数字的指数部分

2

FRACTION (X) 它返回数字的小数部分

3

NEAREST (X, S) 它返回指定方向下最接近的不同的处理器数字

4

RRSPACING (X) 它返回指定数字附近的模型数字的相对间距倒数

5

SCALE (X, I) 它将一个实数乘以其基数作为整数次方

6

SET_EXPONENT (X, I) 它返回数字的指数部分

7

SPACING (X) 它返回指定数字附近的模型数字的绝对间距

Bit Manipulation Functions

Sr.No

Function & Description

1

BIT_SIZE (I) 它返回模型的位数

2

BTEST (I, POS) Bit testing

3

IAND (I, J) Logical AND

4

IBCLR (I, POS) Clear bit

5

IBITS (I, POS, LEN) 取位

6

IBSET (I, POS) Set bit

7

IEOR (I, J) Exclusive OR

8

IOR (I, J) Inclusive OR

9

ISHFT (I, SHIFT) Logical shift

10

ISHFTC (I, SHIFT [, SIZE]) 循环移位

11

NOT (I) Logical complement

Character Functions

Sr.No

Function & Description

1

ACHAR (I) 返回 ASCII 整理序列中第 I 个字符。

2

ADJUSTL (STRING) 通过移除掉任何前导空格和插入尾随空格来调整字符串左方。

3

ADJUSTR (STRING) 通过移除掉尾随空格和插入前导空格来调整字符串右方。

4

CHAR (I [, KIND]) 返回机器特定整理序列中第 I 个字符。

5

IACHAR &#169; 返回字符在 ASCII 整理序列中的位置。

6

ICHAR &#169; 返回机器 (处理器) 特定整理序列中字符的位置。

7

INDEX (STRING, SUBSTRING [, BACK]) 返回 SUBSTRING 在 STRING 中最左边的 (如果 BACK 为 .TRUE.,则为最右边的) 开始位置。

8

LEN (STRING) 返回字符串的长度。

9

LEN_TRIM (STRING) 返回不包含尾随空格字符的字符串长度。

10

LGE (STRING_A, STRING_B) 词法上大于或等于

11

LGT (STRING_A, STRING_B) 词法上大于

12

LLE (STRING_A, STRING_B) 词法上小于或等于

13

LLT (STRING_A, STRING_B) 词法上小于

14

REPEAT (STRING, NCOPIES) Repeated concatenation

15

SCAN (STRING, SET [, BACK]) 返回 STRING 中最左边的 (如果 BACK 为 .TRUE.,则为最右边的) 字符在 SET 中的索引,如果一个也不属于 SET,则返回 0。

16

TRIM (STRING) 移除尾随空格字符

17

VERIFY (STRING, SET [, BACK]) 验证字符串中的一组字符

Kind Functions

Sr.No

Function & Description

1

KIND (X) 返回类型参数值。

2

SELECTED_INT_KIND &#174; 它返回给定指数范围的种类类型参数。

3

SELECTED_REAL_KIND ([P, R]) 给定精度和范围的实际种类类型参数值

Logical Function

Sr.No

Function & Description

1

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

Fortran - Numeric Precision

我们已经讨论过,在较早版本的 Fortran 中,存在两种 real 类型:默认实数类型和 double precision 类型。

然而,Fortran 90/95 通过 kind 规范提供了对实数和整数数据类型精度的更高控制。

The Kind Attribute

不同种类的数字在计算机内部的存储方式不同。 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 更大的值,并且具有更多的存储位数。但具体情况取决于机器。

Example

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

Inquiring the Size of Variables

有一些固有函数允许你询问数字的大小。

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

Example

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

Obtaining the Kind Value

Fortran 提供了另外两个固有函数,以获取整数和实数所需精度的类型值−

  1. selected_int_kind (r)

  2. 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 所需的类型值。

Example

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 - Program Libraries

有各种 Fortran 工具和库。有些是免费的,有些是付费服务。

以下是部分免费库:

  1. RANDLIB、随机数和统计分布生成器

  2. BLAS

  3. EISPACK

  4. GAMS-NIST 可用数学软件指南

  5. NIST 中的部分统计和其他例程

  6. LAPACK

  7. LINPACK

  8. MINPACK

  9. MUDPACK

  10. NCAR Mathematical Library

  11. Netlib 数学软件、论文和数据库集合。

  12. ODEPACK

  13. ODERPACK,一组用于排名和排序的例程。

  14. Expokit 用于计算矩阵指数

  15. SLATEC

  16. SPECFUN

  17. STARPAC

  18. StatLib statistical library

  19. TOMS

  20. Sorting and merging strings

以下库不免费:

  1. NAG Fortran 数值库

  2. Visual Numerics IMSL 库

  3. Numerical Recipes

Fortran - Programming Style

编程风格涉及的是在开发程序时遵循一些规则。这些良好的做法会给您的程序带来可读性、明确性等价值。

一个好的程序应具备以下特点:

  1. Readability

  2. Proper logical structure

  3. Self-explanatory notes and comments

例如,如果您做出如下评论,则不会有太大帮助:

! loop from 1 to 10
do i = 1,10

然而,如果您正在计算二项式系数,并且需要这个循环求 nCr,那么这样的注释会有帮助:

! loop to calculate nCr
do i = 1,10
  1. 缩进代码块以使各个级别的代码更加清晰。

  2. 自检代码以确保不会出现诸如除以零、负实数的平方根或负实数的对数之类的数值错误。

  3. 包括确保变量不采用非法值或超出范围值的代码,即输入验证。

  4. 避免在不必要的地方进行检查,从而减慢执行速度。例如:

real :: x
x = sin(y) + 1.0

if (x >= 0.0) then
   z = sqrt(x)
end if
  1. 使用适当算法编写清晰的代码。

  2. 使用延续标记“&”分割长表达式。

  3. Making meaningful variable names.

Fortran - Debugging Program

调试工具用于在程序中搜索错误。

调试程序逐步执行代码,并允许您在程序执行期间检查变量和其他数据对象中的值。

它加载源代码,您需要在调试器中运行该程序。调试器通过以下方式调试程序:

  1. Setting breakpoints,

  2. 逐步执行源代码

  3. Setting watch points.

断点指定程序应停止的位置,尤其是在关键代码行之后。程序执行会在断点处检查变量之后。

调试程序按行检查源代码。

监视点是需要检查某些变量的值的点,特别是在读或写操作之后。

The gdb Debugger

gdb 调试器,GNU 调试器随 Linux 操作系统提供。对于 X 窗口系统,gdb 带有一个图形界面,程序名为 xxgdb。

下表提供了一些 gdb 中的命令−

Command

Purpose

break

Setting a breakpoint

run

Starts execution

cont

Continues execution

next

仅执行源代码的下一行,而不进入任何函数调用

step

在函数调用中执行源代码的下一行,方法是进入函数。

The dbx Debugger

Linux 中还有另一个调试器 dbx 调试器。

下表提供了一些 dbx 中的命令 −

Command

Purpose

stop[var]

当变量 var 的值发生变化时设置一个断点。

stop in [proc]

当进入过程 proc 时停止执行

stop at [line]

它在特定行设置一个断点。

run

Starts execution.

cont

Continues execution.

next

仅执行源代码的下一行,而不进入任何函数调用。

step

在函数调用中执行源代码的下一行,方法是进入函数。