运算符和流程控制#

与简单的数学公式相比,计算机算法的一个强大的优势在于程序分支,程序可以根据逻辑条件决定接下来执行哪些指令。

控制程序流程主要有两种形式

  • 条件(if):根据布尔值(真或假)选择程序路径

  • 循环:重复代码的一部分多次

逻辑运算符#

在使用条件分支运算符之前,我们需要能够形成逻辑表达式。

要形成逻辑表达式,可以使用以下关系运算符集

运算符

替代

描述

==

.eq.

测试两个操作数是否相等

/=

.ne.

测试两个操作数是否不相等

>

.gt.

测试左操作数是否严格大于右操作数

<

.lt.

测试左操作数是否严格小于右操作数

>=

.ge.

测试左操作数是否大于或等于右操作数

<=

.le.

测试左操作数是否小于或等于右操作数


以及以下逻辑运算符

运算符

描述

.and.

如果左操作数和右操作数均为 TRUE,则为 TRUE

.or.

如果左操作数或右操作数或两者均为 TRUE,则为 TRUE

.not.

如果右操作数为 FALSE,则为 TRUE

.eqv.

如果左操作数与右操作数具有相同的逻辑值,则为 TRUE

.neqv.

如果左操作数与右操作数具有相反的逻辑值,则为 TRUE


条件结构(if#

在以下示例中,条件if结构用于打印一条消息来描述angle变量的性质

示例:单分支if

if (angle < 90.0) then
  print *, 'Angle is acute'
end if

在此第一个示例中,if结构中的代码仅在测试表达式(angle < 90.0)为真时执行。

提示

最好在ifdo等结构中缩进代码,以使代码更易读。

我们可以使用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

循环控制语句(exitcycle#

通常情况下,如果满足某个条件,则需要停止循环。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

注意

当在嵌套循环中使用时,cycleexit语句对最内层循环进行操作。

嵌套循环控制:标签#

任何编程语言中都会出现一个反复出现的情况,即嵌套循环的使用。嵌套循环是指存在于另一个循环中的循环。Fortran 允许程序员标记命名每个循环。如果循环被标记,则有两个潜在的好处

  1. 可以提高代码的可读性(当命名有意义时)。

  2. exitcycle可以与标签一起使用,从而可以对循环进行非常细粒度的控制。

示例:带标签的嵌套循环

integer :: i, j

outer_loop: do i = 1, 10
  inner_loop: do j = 1, 10
    if ((j + i) > 10) then  ! Print only pairs of i and j that add up to 10
      cycle outer_loop  ! Go to the next iteration of the outer loop
    end if
    print *, 'I=', i, ' J=', j, ' Sum=', j + i
  end do inner_loop
end do outer_loop

可并行化循环(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