Fortran 简明教程
Fortran - Overview
Fortran,源自公式翻译系统,是一门通用、命令式的编程语言。它用于数值科学计算。
Fortran 最初由 IBM 于 20 世纪 50 年代开发,用于科学和工程应用。Fortran 长期霸屏此编程领域,并因以下原因而广泛用于高性能计算领域:
支持:
-
· 数值分析和科学计算
-
Structured programming
-
Array programming
-
Modular programming
-
Generic programming
-
· 超级计算机上的高性能计算
-
Object oriented programming
-
Concurrent programming
-
· 在计算机系统之间具有合理的移植性
Facts about Fortran
-
Fortran 由约翰·巴科斯于 1957 年领导的团队在 IBM 创建。
-
最初,名称通常全部大写,但当前标准和实现只要求第一个字母大写。
-
Fortran 代表公式翻译器。
-
最初开发用于科学计算,对字符字符串和其他通用编程所需结构的支持非常有限。
-
后来的扩展和完善使其成为具有良好可移植性的高级编程语言。
-
最初版本 Fortran I、II 和 III 现在被认为已过时。
-
仍在使用的最老版本是 Fortran IV 和 Fortran 66。
-
当今最常用的版本是:Fortran 77、Fortran 90 和 Fortran 95。
-
Fortran 77 将字符串添加为独立类型。
-
Fortran 90 添加各种线程和直接数组处理。
Fortran - Environment Setup
Setting up Fortran in Windows
G95 是用于在 Windows 中设置 Fortran 的 GNU Fortran 多架构编译器。Windows 版本使用 MinGW 模拟 Windows 上的 Unix 环境。安装程序处理此问题并自动将 g95 添加到 Windows PATH 变量。
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”的可执行文件 |
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
请注意 −
-
所有 Fortran 程序都以关键字 program 开头,以关键字 end program, 结尾,后跟程序的名称。
-
implicit none 语句允许编译器检查所有变量类型是否已正确声明。您必须始终在每个程序的开头使用 implicit none 。
-
Fortran 中的注释以感叹号 (!) 开始,因为此号 (在字符字符串中除外) 后的所有字符都会被编译器忽略。
-
print * 命令可在屏幕上显示数据。
-
缩进代码行有利于保持程序的可读性。
-
Fortran 同时允许使用大写字母和小写字母。Fortran 不区分大小写,但字符串文字除外。
Basics
Fortran 的 basic character set 包含 −
-
字母 A … Z 和 a … z
-
数字 0 … 9
-
the underscore (_) character
-
特殊字符 = : + 空格 - * / ( ) [ ] , . $ ' ! " % & ; < > ?
Tokens 由基本字符集中的字符组成。标记可以是关键字、标识符、常量、字符串文字或符号。
程序语句由标记组成。
Identifier
标识符是用来标识变量、过程或任何其他用户定义项的名称。Fortran 中的名称必须遵循以下规则 −
-
它不能长于 31 个字符。
-
它必须由字母数字字符(字母表中的所有字母和数字 0 到 9)和下划线(_)组成。
-
名称的第一个字符必须是字母。
-
Names are case-insensitive
Keywords
关键字是保留给语言的特殊单词。这些保留字不能用作标识符或名称。
下表列出了 Fortran 关键字——
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 |
read |
rewind |
Write |
Fortran - Data Types
Fortran 提供五种内在数据类型,但是,您还可以自己导出数据类型。这五种内在类型有——
-
Integer type
-
Real type
-
Complex type
-
Logical type
-
Character type
Integer Type
整型只能保存整数值。下面的示例将提取在常规的 4 字节整型中能保存的最大值——
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
它存储浮点数,例如 2.0、3.1415、-100.876 等。
传统上有两种不同的 real 类型:默认 real 类型和 double precision 类型。
然而,Fortran 90/95 通过我们会在本章学习的关于数字部分的 kind 规范符对 real 和 integer 数据类型的精度提供了更多的控制。
以下示例展示了 real 数据类型的使用方法——
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
它用于存储复数。一个复数有两部分,即实部和虚部。两个连续的数值存储单元存储这两部分。
例如,复数 (3.0, -5.0) 等于 3.0 – 5.0i
我们将在关于数字的章节中更详细地讨论复数类型。
Fortran - Variables
变量只不过是一个存储区域的名称,我们的程序可以对其进行操作。每个变量应该有特定的类型,它确定变量内存的大小和布局;可以在该内存内存储的值范围;以及可以应用于该变量的操作集。
变量的名称可以由字母、数字和下划线字符组成。Fortran 中的名称必须遵循以下规则:
-
它不能长于 31 个字符。
-
它必须由字母数字字符(字母表中的所有字母和数字 0 到 9)和下划线(_)组成。
-
名称的第一个字符必须是字母。
-
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
有两种类型的常量:
-
Literal constants
-
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 提供以下类型的运算符 -
-
Arithmetic Operators
-
Relational Operators
-
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 时要执行的其他语句。
以下是大多数编程语言中常见的典型决策结构的一般形式 −
Fortran 提供以下类型的决策构建。
Sr.No |
Statement & Description |
1 |
If… then construct @ |
2 |
If… then…else construct @ |
3 |
if…else if…else Statement @ |
4 |
nested if construct 您可以在另一个 if 或 else if 语句中使用一个 if 或 else if 语句。 |
5 |
select case construct select case 语句允许对变量进行测试,以使其相对于值列表相等。 |
6 |
nested select case construct 您可以在另一个 select case 语句中使用一个 select case 语句。 |
Fortran - Loops
在某些情况下,您需要多次执行代码块。通常,语句按顺序执行:函数中的第一个语句首先执行,其次是第二个语句,依此类推。
编程语言提供了各种控制结构,允许执行更复杂的路径。
循环语句允许我们多次执行一个语句或一组语句,以下是大多数编程语言中循环语句的一般形式 −
Fortran 提供以下类型的循环构造来处理循环要求。单击以下链接以查看其详细信息。
Sr.No |
Loop Type & Description |
1 |
do loop 此构造使语句或一系列语句能够在给定条件为真时进行迭代执行。 |
2 |
do while loop 在给定条件为真时重复语句或语句组。它在执行循环体之前测试条件。 |
3 |
nested loops 您可以在任何其他循环构造中使用一个或多个循环构造。 |
Fortran - Numbers
Fortran 中的数字由三种固有数据类型表示 −
-
Integer type
-
Real type
-
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
它存储浮点数,例如 2.0、3.1415、-100.876 等。
传统上有两种不同的 @ {s0} 类型:默认实数类型和 @ {s1} 类型。
但是,Fortran 90/95 通过我们稍后将研究的 @ {s2} 说明符提供了对实数和整数数据类型精度的更多控制。
以下示例展示了 real 数据类型的使用方法——
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
这用于存储复数。复数有两个部分:实部和虚部。两个连续的数值存储单元存储这两个部分。
例如,复数 (3.0, -5.0) 等于 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
连接运算符 // 连接字符。
以下示例演示了这一点−
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
连接操作符 // 连接字符串。
以下示例演示了这一点−
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
Some Array Related Terms
下表提供了一些与数组相关的术语:
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
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 允许定义派生数据类型。派生数据类型也称为“结构”,它由不同类型的数据对象组成。
派生数据类型用于表示记录。例如,想要跟踪图书馆中的书籍,则可能想要跟踪每本书的以下属性 −
-
Title
-
Author
-
Subject
-
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
指针可以指向 −
-
一段动态分配的内存。
-
与指针同类的数据对象,具有 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
空指针可以是 −
-
Undefined
-
Associated
-
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
请注意,每次运行代码时,内存地址都将不同。
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
其中,
-
fmt 是格式规范
-
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 是一组语句,可以执行明确定义的任务,并可以从程序中调用。信息(或数据)作为参数传递给调用程序和过程。
有两种类型的过程 −
-
Functions
-
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
请注意 −
-
您必须在主程序和过程中指定 implicit none 。
-
被调用函数中的参数 r 称为 dummy argument 。
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
模块就像是一个包,在您编写非常大的程序或者您的函数或子例程可用于多个程序时,可将它们保留在内。
模块为您提供一种将程序拆分成多个文件的方法。
模块用于:
-
打包子程序、数据和接口块
-
定义可供多个例程使用的全局数据。
-
声明可用于您选择的任何例程内的变量。
-
将整个模块导入到另一个程序或子例程中使用。
Syntax of a Module
一个模块包含两部分:
-
用于语句声明的规范部分
-
用于子例程和函数定义的包含部分
模块的常规形式如下:
module name
[statement declarations]
[contains [subroutine and function definitions] ]
end module [name]
Using a Module into your Program
您可以通过 use 语句在程序或子程序中合并一个模块 -
use name
请注意
-
可以根据需要添加尽可能多的模块,每个模块都将放在单独的文件中并单独编译。
-
一个模块可以用于各种不同的程序。
-
同一个程序中可以多次使用一个模块。
-
在模块说明部分声明的变量对模块是全局的。
-
在模块中声明的变量将成为使用该模块的任何程序或例程中的全局变量。
-
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 语句使用。
但是,您可以使用 private 和 public 属性控制模块代码的可访问性。当您将某些变量或子程序声明为私有的时,它在模块外部不可用。
Example
以下示例说明了这一概念 -
在前面的示例中,我们有两个模块变量, e 和 pi. ,让我们将它们设为私有的并观察输出 -
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, 都被声明为私有,因此程序 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 语言的一部分。我们已经在“数组”、“字符”和“字符串”章节中讨论了一些这些函数。
本征函数可以分类为 -
-
Numeric Functions
-
Mathematical Functions
-
Numeric Inquiry Functions
-
Floating-Point Manipulation Functions
-
Bit Manipulation Functions
-
Character Functions
-
Kind Functions
-
Logical Functions
-
Array Functions.
我们在“数组”章节中讨论了数组函数。在下一部分中,我们将提供其他类别的所有这些函数的简要说明。
在函数名列中,
-
A 表示任何类型的数值变量
-
R 表示实变量或整变量
-
X 和 Y 表示实变量
-
Z represents complex variable
-
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,…​]) 它返回参数的最大值,所有参数都同类型 |
14 |
MIN (A1, A2 [, A3,…​]) 它返回参数的最小值,所有参数都同类型 |
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 © 返回字符在 ASCII 整理序列中的位置。 |
6 |
ICHAR © 返回机器 (处理器) 特定整理序列中字符的位置。 |
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]) 验证字符串中的一组字符 |
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 提供了另外两个固有函数,以获取整数和实数所需精度的类型值−
-
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 所需的类型值。
Fortran - Program Libraries
有各种 Fortran 工具和库。有些是免费的,有些是付费服务。
以下是部分免费库:
-
RANDLIB、随机数和统计分布生成器
-
BLAS
-
EISPACK
-
GAMS-NIST 可用数学软件指南
-
NIST 中的部分统计和其他例程
-
LAPACK
-
LINPACK
-
MINPACK
-
MUDPACK
-
NCAR Mathematical Library
-
Netlib 数学软件、论文和数据库集合。
-
ODEPACK
-
ODERPACK,一组用于排名和排序的例程。
-
Expokit 用于计算矩阵指数
-
SLATEC
-
SPECFUN
-
STARPAC
-
StatLib statistical library
-
TOMS
-
Sorting and merging strings
以下库不免费:
-
NAG Fortran 数值库
-
Visual Numerics IMSL 库
-
Numerical Recipes
Fortran - Programming Style
编程风格涉及的是在开发程序时遵循一些规则。这些良好的做法会给您的程序带来可读性、明确性等价值。
一个好的程序应具备以下特点:
-
Readability
-
Proper logical structure
-
Self-explanatory notes and comments
例如,如果您做出如下评论,则不会有太大帮助:
! 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
-
使用适当算法编写清晰的代码。
-
使用延续标记“&”分割长表达式。
-
Making meaningful variable names.
Fortran - Debugging Program
调试工具用于在程序中搜索错误。
调试程序逐步执行代码,并允许您在程序执行期间检查变量和其他数据对象中的值。
它加载源代码,您需要在调试器中运行该程序。调试器通过以下方式调试程序:
-
Setting breakpoints,
-
逐步执行源代码
-
Setting watch points.
断点指定程序应停止的位置,尤其是在关键代码行之后。程序执行会在断点处检查变量之后。
调试程序按行检查源代码。
监视点是需要检查某些变量的值的点,特别是在读或写操作之后。