演算子とフロー制御#

単純な数式と比較したコンピュータアルゴリズムの強力な利点の1つは、プログラムの_分岐_という形で現れます。これにより、プログラムは論理条件に基づいて次に実行する命令を決定できます。

プログラムフローを制御するには、主に2つの方法があります

  • _条件分岐_(if):ブール値(真または偽)に基づいてプログラムパスを選択します

  • _ループ_:コードの一部を複数回繰り返します

論理演算子#

条件分岐演算子を使用する前に、論理式を形成できる必要があります。

論理式を形成するには、以下の関係演算子セットを使用できます

演算子

代替

説明

==

.eq.

== 2つのオペランドが等しいかどうかをテストします

/=

.ne.

!= / <> 2つのオペランドが等しくないかどうかをテストします

>

.gt.

> 左のオペランドが右のオペランドよりも厳密に大きいかどうかをテストします

<

.lt.

< 左のオペランドが右のオペランドよりも厳密に小さいかどうかをテストします

>=

.ge.

>= 左のオペランドが右のオペランド以上かどうかをテストします

<=

.le.

<= 左のオペランドが右のオペランド以下かどうかをテストします


以下の論理演算子も使用できます

演算子

説明

.and.

左右両方のオペランドが真の場合に真

.or.

左または右、あるいは両方のオペランドが真の場合に真

.not.

右のオペランドが偽の場合に真

.eqv.

左のオペランドが右のオペランドと同じ論理値を持つ場合に真

.neqv.

左のオペランドが右のオペランドと反対の論理値を持つ場合に真


条件構造(if#

以下の例では、条件付きif構造を使用して、angle変数の性質を説明するメッセージを出力します

例:単一分岐if

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

この最初の例では、テスト式(angle < 90.0)が真の場合に_のみ_、if構造内のコードが実行されます。

ヒント

ifdoなどの構造内のコードは、インデントしてコードを読みやすくすることをお勧めします。

elseキーワードを使用して、構造に代替ブランチを追加できます

例:2分岐if-else

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

これで、if構造には2つの_ブランチ_がありますが、ifキーワードに続く論理式に応じて、_1つのブランチのみが実行されます_。

実際には、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はこのような場合に対処するための2つの実行可能文を提供しています。

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文は最も内側のループに作用します。

入れ子ループ制御:タグ#

あらゆるプログラミング言語で繰り返し発生するケースは、入れ子ループの使用です。入れ子ループとは、別のループ内にあるループのことです。Fortranでは、プログラマーが各ループに_タグ_を付けるか、または_名前_を付けることができます。ループにタグが付けられている場合、2つの潜在的な利点があります

  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 ループを do concurrent に単純に置き換えるだけでは、並列実行は保証されません。上記の説明は、正しい 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