运算符和流程控制#
与简单的数学公式相比,计算机算法的一个强大的优势在于程序分支,程序可以根据逻辑条件决定接下来执行哪些指令。
控制程序流程主要有两种形式
条件(if):根据布尔值(真或假)选择程序路径
循环:重复代码的一部分多次
逻辑运算符#
在使用条件分支运算符之前,我们需要能够形成逻辑表达式。
要形成逻辑表达式,可以使用以下关系运算符集
运算符 |
替代 |
描述 |
---|---|---|
|
|
测试两个操作数是否相等 |
|
|
测试两个操作数是否不相等 |
|
|
测试左操作数是否严格大于右操作数 |
|
|
测试左操作数是否严格小于右操作数 |
|
|
测试左操作数是否大于或等于右操作数 |
|
|
测试左操作数是否小于或等于右操作数 |
以及以下逻辑运算符
运算符 |
描述 |
---|---|
|
如果左操作数和右操作数均为 TRUE,则为 TRUE |
|
如果左操作数或右操作数或两者均为 TRUE,则为 TRUE |
|
如果右操作数为 FALSE,则为 TRUE |
|
如果左操作数与右操作数具有相同的逻辑值,则为 TRUE |
|
如果左操作数与右操作数具有相反的逻辑值,则为 TRUE |
条件结构(if
)#
在以下示例中,条件if
结构用于打印一条消息来描述angle
变量的性质
示例:单分支if
if (angle < 90.0) then
print *, 'Angle is acute'
end if
在此第一个示例中,if
结构中的代码仅在测试表达式(angle < 90.0
)为真时执行。
提示
最好在if
和do
等结构中缩进代码,以使代码更易读。
我们可以使用else
关键字向结构添加备选分支
示例:双分支if
-else
if (angle < 90.0) then
print *, 'Angle is acute'
else
print *, 'Angle is obtuse'
end if
现在if
结构中有两个分支,但仅根据if
关键字后面的逻辑表达式执行一个分支。
我们实际上可以使用else if
添加任意数量的分支来指定更多条件
示例:多分支if
-else if
-else
if (angle < 90.0) then
print *, 'Angle is acute'
else if (angle < 180.0) then
print *, 'Angle is obtuse'
else
print *, 'Angle is reflex'
end if
当使用多个条件表达式时,仅当前面的表达式均未计算为真时,才会测试每个条件表达式。
循环结构(do
)#
在以下示例中,do
循环结构用于打印序列中的数字。do
循环具有一个整数计数器变量,用于跟踪当前正在执行的循环的哪一次迭代。在此示例中,我们为此计数器变量使用一个常见的名称:i
。
当我们定义do
循环的开始时,我们使用计数器变量名称后跟一个等号(=
)来指定计数变量的起始值和最终值。
示例:do
循环
integer :: i
do i = 1, 10
print *, i
end do
示例:带跳过的do
循环
integer :: i
do i = 1, 10, 2
print *, i ! Print odd numbers
end do
条件循环(do while
)#
可以使用while
关键字向do
循环添加条件。while()
中给定的条件计算结果为.true.
时,将执行循环。
示例:do while()
循环
integer :: i
i = 1
do while (i < 11)
print *, i
i = i + 1
end do
! Here i = 11
循环控制语句(exit
和 cycle
)#
通常情况下,如果满足某个条件,则需要停止循环。Fortran 提供了两个可执行语句来处理此类情况。
exit
用于过早退出循环。它通常包含在if
内部。
示例:带exit
的循环
integer :: i
do i = 1, 100
if (i > 10) then
exit ! Stop printing numbers
end if
print *, i
end do
! Here i = 11
另一方面,cycle
跳过循环中剩余的部分并进入下一个循环。
示例:带cycle
的循环
integer :: i
do i = 1, 10
if (mod(i, 2) == 0) then
cycle ! Don't print even numbers
end if
print *, i
end do
注意
当在嵌套循环中使用时,cycle
和exit
语句对最内层循环进行操作。
可并行化循环(do concurrent
)#
do concurrent
循环用于明确指定循环内部没有相互依赖关系;这告诉编译器它可以使用并行化/SIMD 来加速循环的执行,并更清晰地传达程序员的意图。更具体地说,这意味着任何给定的循环迭代都不依赖于其他循环迭代的先前执行。还需要任何可能发生的状态更改只能发生在每个 do concurrent
循环内。这些要求限制了可以在循环体中放置的内容。
仅仅用
do concurrent
替换do
循环并不能保证并行执行。上面给出的解释没有详细说明为了编写正确的do concurrent
循环需要满足的所有要求。编译器也可以自由地按照自己的方式进行,这意味着它们可能不会优化循环(例如,少量迭代执行简单的计算,如下面的示例)。通常,需要编译器标志来激活do concurrent
循环的可能并行化。
示例:do concurrent()
循环
real, parameter :: pi = 3.14159265
integer, parameter :: n = 10
real :: result_sin(n)
integer :: i
do concurrent (i = 1:n) ! Careful, the syntax is slightly different
result_sin(i) = sin(i * pi/4.)
end do
print *, result_sin