在开始学习Fortran语言的变量前,我们先通过在终端输出"hello world"了解下Fortran代码的结构:
program HelloWorld
implicit none
print *, 'Hello World!'
end program HelloWorld
我们首先声明了一个名为HelloWorld
的程序,并使用implicit none
语句来要求所有变量必须显式声明其类型,这样可以避免潜在的命名冲突和类型错误。随后使用print *
来输出字符串,在结尾通过end program
来结束程序。在代码中加入!
为插入注释。
变量赋值
接下来我们就可以开始学习Fortran语言中的变量了,在Fortran 中有 5 种内置数据类型:
-
integer —— 表示整数的数据,正数或负数
-
real —— 用于浮点数据(不是整数)
-
complex —— 由实部和虚部组成的对
-
character —— 用于文本数据
-
logical —— 用于表示布尔值(真或假)值的数据
接下来我们来看一下如何声明这些数据类型的变量,并给这些变量赋值:
! test.f90
program test
implicit none
integer :: age
real :: weight
complex :: frequency
character(len = 10) :: name
logical :: isOkay
age = 10
weight = 50.5
frequency = (1.0, 2.0)
name = 'GGBond'
isOkay = .true.
print *, "name:", name
print *, "age:", age
print *, "weight:", weight
print *, "frequency:", frequency
print *, "isOkay:", isOkay
end program test
使用命令编译并运行代码:
gfortran -o test test.f90
./test
有一点需要注意的是Fortran 代码不区分大小写;大家不必担心变量名的大小写,但保持一致是一种很好的做法。比如以下代码,age
变量在赋值时写成了Age
,但仍可以正常运行。
在赋值时大家也要注意一点,不要在声明时同时赋值,比如:
integer :: amount = 1
这不是一个推荐的初始化方式。在Fortran中,这种在声明时直接赋值给变量的做法会隐含地给该变量加上save
属性。save
属性意味着该变量在程序执行期间会保留其值,即使在不同的过程(如子程序或函数)调用之间也是如此。这通常用于需要在多次调用中保持状态的变量,比如计数器或累加器。对于大多数变量来说,并不希望它们自动保留上一次的值,因为这可能会导致难以追踪的错误和不可预测的程序行为。因此,良好的编程实践是在声明变量之后,再单独对它们进行初始化,如下所示:
integer :: amount
amount = 1
这样,amount
变量就没有save
属性,它只会在它被显式赋值时改变值,并且在每次过程调用时都会重新初始化(除非它被声明为静态变量或有其他的持久性机制)。
为了避免不必要的复杂性和潜在的错误,建议在Fortran中单独初始化变量,而不是在声明时同时赋值,除非您确实需要变量的save
属性。这样做可以使代码更清晰、更容易理解,并且更符合Fortran编程的最佳实践。
标准输入输出
我们将文本打印到命令窗口。这通常被称为写入 standard output
或 stdout
。我们可以使用print
语句将变量值打印到 stdout
,使用 read
语句从命令窗口读取值:
program read_values
implicit none
real :: x, y
print *, 'Please enter two numbers. '
read(*,*) x, y
print *, 'The sum and product of the numbers are ', x+y, x*y
end program read_values
如果想要控制输出的格式,特别是限制小数点后的位数,我们可以使用格式化输出语句,使用F
描述符来指定总宽度和小数点后的位数
program read_values
implicit none
real :: x, y
print *, 'Please enter two numbers. '
read(*,*) x, y
print '("The sum and product of the numbers are ", F8.2, " and ", F8.2)', x+y, x*y
end program read_values
表达式
常用的算术运算符集如下,按优先顺序列出:
运算符 | 描述 | 示例 |
---|---|---|
** | 幂运算(指数) | 3 ** 2 结果为 9 |
* | 乘法 | 3 * 2 结果为 6 |
/ | 除法 | 6 / 2 结果为 3 |
+ | 加法 | 3 + 2 结果为 5 |
- | 减法 | 5 - 2 结果为 3 |
// | 整除(取整后的除法结果) | 7 // 2 结果为 3 |
** | 取余(Fortran中可能使用MOD) | 7 % 2 (或MOD(7,2) )结果为 1 |
这里我们使用官方的案例代码:
program arithmetic
implicit none
real :: pi, radius, height, area, volume
pi = 3.1415927
print *, 'Enter cylinder base radius:'
read(*,*) radius
print *, 'Enter cylinder height:'
read(*,*) height
area = pi * radius**2
volume = area * height
print *, 'Cylinder radius is: ', radius
print *, 'Cylinder height is: ', height
print *, 'Cylinder base area is: ', area
print *, 'Cylinder volume is: ', volume
end program arithmetic
浮点精度
在Fortran编程中,浮点数的精度是至关重要的,因为它直接影响到数值计算的准确性和效率。Fortran语言提供了一种灵活的方式来显式声明所需的浮点精度,即通过kind
参数。这个参数允许指定变量应该使用的浮点类型,从而确保计算过程中的数值精度符合你的需求。
为了简化这个过程,Fortran的iso_fortran_env
内置模块为开发者预定义了常见的32位和64位浮点类型的kind
参数。通过使用这些预定义的参数可以轻松地创建具有特定浮点精度的变量。
以下是一个示例程序,展示了如何使用iso_fortran_env
模块中的real32
和real64
来声明32位和64位的浮点变量,并为它们赋值:
program float_precision_example
use, intrinsic :: iso_fortran_env, only: sp=>real32, dp=>real64
implicit none
! 声明32位和64位浮点变量
real(sp) :: float32_var
real(dp) :: float64_var
! 为变量赋值,使用显式后缀来指定字面常量的精度
float32_var = 1.0_sp ! 32位浮点数
float64_var = 1.0_dp ! 64位浮点数
! 输出变量的值
print*, '32-bit float:', float32_var
print*, '64-bit float:', float64_var
end program float_precision_example
在这个程序中,首先通过use
语句引入了iso_fortran_env
模块,并只导入了需要的real32
和real64
类型,分别将它们重命名为sp
和dp
以提高代码的可读性。然后声明了两个浮点变量float32_var
和float64_var
,分别具有32位和64位的精度。在赋值时使用了显式后缀_sp
和_dp
来指定字面常量的浮点精度,确保它们与变量的精度相匹配。最后使用print
语句输出了这两个变量的值。
块构造中的局部变量
Fortran 2008
标准引入了一个重要的概念——块(block
),它允许在程序或过程中使用具有局部作用域的变量。这一特性极大地增强了Fortran语言的灵活性和可读性,使得开发者能够更精确地控制变量的作用域和生命周期。
以下是一个示例,展示了如何在Fortran程序中使用块构造来定义局部作用域变量,并如何从模块中导入所需的内容:
module your_module
implicit none
integer :: n = 2
end module your_module
program main
implicit none
real :: x
! 开始一个块
block
! 在块内使用use语句导入模块中的特定内容
use your_module, only: n
! 定义一个局部作用域变量y
real :: y
! 为y赋值,并使用模块中的n进行计算
y = 2.0
x = y ** n
! 输出y的值
print *, 'Value of y within the block:', y
end block
! 输出x的值,x是在块外定义的,因此可以在此处访问
print *, 'Value of x after the block:', x ! 输出结果为 4.00000000
end program main
在这个示例中首先定义了一个名为your_module
的模块,其中包含一个整数变量n
。然后,在主程序main
中定义了一个实数变量x
。接下来使用block
关键字开始了一个新的块,并在这个块内导入了your_module
模块中的n
变量。在块内还定义了一个局部作用域变量y
,并为其赋值。然后使用y
和n
进行计算,并将结果赋值给x
。最后在块内输出了y
的值,并在块外输出了x
的值。
值得注意的是,尝试在块外访问y
会导致编译错误,因为y
仅在块的作用域内有效。这种局部作用域的管理方式有助于避免变量命名冲突,提高代码的可维护性。同时,通过块构造,开发者可以更加清晰地组织代码逻辑,使程序结构更加清晰易懂。