操作符和流程控制#

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

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

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

  • Loop:重复一段代码多次

逻辑运算符#

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

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

操作符  

选择  

描述

==

.eq.

测试两个操作数是否相等

/=

.ne.

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

>

.gt.

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

<

.lt.

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

>=

.ge.

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

<=

.le.

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


以及以下逻辑运算符:

操作符  

描述

.and.

如果左右操作数都为 TRUE,则为 TRUE

.or.

如果左侧或右侧为 TRUE 或者两个操作数都为 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 循环有一个整数 counter 变量,用于跟踪当前正在执行的循环迭代。在这个例子中,我们为这个计数器变量使用了一个通用名称: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 允许程序员对每个循环进行 tagname 。如果循环被标记,有两个潜在的好处:

  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