コンテンツに飛ぶ | ナビゲーションに飛ぶ

  • 日本語
  • English
 

sec3


3. プログラムの流れを変える                                   目次へ

 3.1.   論理IF文
 3.1.1. 関係演算子
 3.1.2. 論理演算子
 3.2.   ブロックIF構文
 3.2.1. ブロックIF構文のいろいろ
 3.2.2. 組込み関数
 3.3.   多数の分岐         [90]

 プログラムの文は,原則として上から順に実行される。この流れが変わるのは

 1) IF文やCASE文 [90] による選択実行
 2) DO文による繰り返しループ
 3) CALL文によるサブルーチンへの移動と,その終了(またはRETURN文)
  による復帰
 4) GOTO文によるジャンプ
 5) STOP文による停止
 6) 制御オプション付きREAD文の実行によるジャンプや停止

などである。このうち GOTO文 は,多用すると極めて読みにくいプログラムになるの
で,なるべく使わない方がよい。現在の仕様では GOTO文 を全く使わずにプログラミ
ング可能である。ここでは,最も基本的な IF文 と CASE文 を扱う。


3.1. 論理IF文


           IF(論理式)  実行文


(  )の中が真のときだけ実行文が実行され,偽のときはスキップして次の文が実行
される。


 論理式: 論理変数(.TRUE.または.FALSE.の値をとる変数),関係式など

 関係式:以下の関係演算子で構成される論理式


  例1 「入力された点数n(整数)が60以上のときだけ,カウンタkの値を1増加
     させる。」
               READ*, n
               IF(n >= 60) k = k+1

  例2 GOTO文との組合せがよく使われるが,乱用するとわかりにくいプログラムに
    なる。
               IF(x < 0.0) GOTO 999


 例題 3_1 「試験の合格者数の計算」


[ex3_1.f90]
    ! --- 成績チェック ---
         INTEGER :: n, s, k               ! 整数型変数の宣言
         s = 0; k = 0
   10    PRINT*,'Input mark for each student (or negative one to quit):'
         READ*, n;   IF(n < 0) GOTO 999
         s = s + 1
         IF(n >= 60) k = k + 1
         GOTO 10
   999   PRINT*, k,' students passed in this exam. Total =', s
         END

 注)これは2つのGOTO文が交差していてわかりにくく,あまり推薦できるプログラム
      ではない。5章の DO...EXIT 文で書く方がわかりやすい。


3.1.1.  関係演算子


(2つの数値データの間の大小関係式)   注:文字列の大小は → 7.1.5.

   大きい       .GT. または  >   (後の形は [90] のみ,以下同様)
   大きいか等しい   .GE. または  >=
   小さい       .LT. または  < 
   小さいか等しい   .LE. または  <=
   等しい       .EQ. または ==
   等しくない     .NE. または /=


   例  (x+y) .GT. 0.0      x /= a


3.1.2. 論理演算子


   論理否定      .NOT.   (単項演算で,「.NOT.論理式」の形)
   論理積       .AND.
   論理和       .OR.
   論理等価      .EQV.
   論理非等価     .NEQV.


 演算優先順序:かっこで囲まない限り,以下の順序で優先的に処理される:


    関係演算> .NOT.  > .AND. > .OR. > .EQV. と .NEQV.


 混乱を避けるため,( )を使う方がよい。

   例  (x > 1.0) .OR. (x <= 0.0)

 同じ順位のものは左から処理される。

   例  (x > 0.0) .OR.  (y > 0.0)
     もし x > 0.0 であれば,y > 0.0 を調べることなく全体として真となる。


(変な例)0 < x < 1 は,(0.0 < x) .AND. (x < 1.0) と書かなければならない。
     しかし,以下のプログラムは何もエラーなしに働いてくれる。ただし,
     x に何を入れても答えは'Included' であるが...何故だろう?

REAL :: x
READ *, x
IF(0.0 < x < 1.0) THEN
   PRINT *, "It is included in (0, 1)."
ELSE
   PRINT *, "It isn't included in (0, 1)."
END IF
END

ヒント:関係式の両辺のデータの型が異なるときは,変換して揃えてから比較する。



3.2. ブロックIF構文


 例題 3_2「実数xを入力し,xが負でないならばその平方根を出力する。」

[ex3_2.f90]
   ! --- Calculating Square Root ---     
      REAL :: x
      PRINT*, "Input a real number:"
      READ *, x
      IF(x >= 0.0) THEN
         PRINT*, SQRT(x)
      ELSE
         PRINT*,"Impossible for x < 0."
      END IF
   END



3.2.1. ブロックIF構文のいろいろ


  IF(論理式)THEN         IF(論理式)THEN         IF(論理式)THEN
     .........               ..........             ..........
     .........             ELSE                   ELSE IF(論理式)THEN
     .........               ..........             ..........
     .........               ..........           ELSE
     .........               ..........             ..........
   END IF                 END IF                 END IF


 1)最後の例では,分岐が何段階になってもよい。
 2)一つのIFブロックの中に,別のIFブロックがはまり込んでいてもよい(多重ブロ
  ック)。
 3)ブロックの途中に外から飛び込んではならない。したがって,多重になるときに
  はブロックが交差してはならない。

  注)BASIC流に,IF(...)実行文 ELSE 実行文 END IF  と,一つの文で書くことは
    できない。


3.2.2. 組込み関数

 上のプログラム例に書かれているSQRTのように,よく使われる算術関数は予めシステ
ムに用意されており,組込み関数という。(配列関数→6.5.,文字関数→7.1.6.)

 代表的な関数例: 変数xは実数型,i,jは整数型,aは共通を表す。例えば,2の
          平方根は SQRT(2.0) と書き,SQRT(2) は誤りとなる。

 実数型
    平方根 SQRT(x), 絶対値 ABS(x), 三角関数 SIN(x), COS(x), TAN(x), 
    逆三角関数 ASIN(x), ACOS(x), ATAN(x), 指数関数 EXP(x), 自然対数 LOG(x), 
    常用対数 LOG10(x), 双曲関数 SINH(x), COSH(x), TANH(x)
  以上は,引数を複素数型にすれば関数値も複素数型になる。
  AINT(x)   実数 x の整数部(小数点以下切捨て) 例  AINT(3.14) は 3.0
  ANINT(x)  実数 x を四捨五入  例 ANINT(3.14) は 3.0,ANINT(4.6) は 5.0
  REAL(i)   整数を実数化    例  REAL(5) は 5.0 となる。

 複素数型
  実数型の関数の引数に複素数型の値が代入されると,関数値も複素数型となる。
  (絶対値 ABS を除く。)この他に
  AIMAG 複素数の虚部を与える。
  REAL   複素数の実部を与える。
  CMPLX 実数を複素数化する。[実数 x が複素数 (x, 0.0) になる。]
    CONJG 共役複素数を求める。[複素数 (x, y) が (x, -y) となる。] 

 整数型
   MOD(i,j)   整数jを法とする除算(=iをjで割った剰り)
  INT(x)     xの切り捨て整数化   例  INT(3.14) は 3
    NINT(x)  xに一番近い整数(四捨五入で整数化)


  注)例えば,10進数の0.01は2進数で書くと無限小数になり,「切り捨て」が行われ
      ると,INT(100*1.01)が整数101になるとは限らないことがある。NINTならば101
      となる。

 その他
  MAX(a1,a2,...,an) 最大値
  MIN(a1,a2,...,an) 最小値

 ビット操作
  IAND(i,j)     ビットごとのAND演算(論理積)
  IOR(i,j)      ビットごとのOR演算 (論理和)
  IEOR(i,j)          ビットごとのXOR演算(排他論理和)
  NOT(i)             ビットごとのNOT演算(否定:0が1に,1が0に変わる。)
    IBITS(i,j,k)       整数iの第jビットから長さkビットを取り出す
    IBCLR(i,j)         整数iの第jビットを0にした整数
    IBSET(i,j)         整数iの第jビットを1にした整数
  ISHFT(i,j)         整数iのビット列をj桁シフトする
    ISHFTC(i,j)    同じく,サイクリックにシフトする

===============================================================================
「論理ビット演算」

       (i,j)  |  (0,0)   (0,1)   (1,0)   (1,1)        i   |   0    1
    ----------|---------------------------------    ------|------------
        AND   |    0       0       0       1         NOT  |   1    0
        OR    |    0       1       1       1    
        XOR   |    0       1       1       0    
 
================================================================================

 例題 3_3 「西暦n年が,うるう年か平年かを調べる。(注.「nが400で割り切れる」
       か,または「4で割り切れるが100では割り切れない」年がうるう年)」

[ex3_3.f90]
   ! --- Leap or not ---
      INTEGER :: n
      READ*, n
      IF( MOD(n, 400) == 0 ) THEN
         PRINT*, "うるう年"
      ELSE IF( MOD(n, 100) == 0 ) THEN
         PRINT*, "平年"
      ELSE IF( MOD(n, 4) == 0 ) THEN
         PRINT*, "うるう年"
      ELSE
         PRINT*, "平年"
      END IF
   END


[ex3_3_2.f90]
   ! --- Alternative Program ---
      INTEGER :: n
      READ*, n
      IF( ( (MOD(n, 4)==0) .AND. ( MOD(n, 100)/=0 ) )             & 
                           .OR.  ( MOD(n, 400)==0 )     ) THEN
          PRINT*,"うるう年です。"
      ELSE
          PRINT*,"平年です。"
      END IF
   END



3.3. 多数の分岐


 例題 3_4 「実数xを入力し,以下の三角波パルス関数F(x)の値を求めよ。
               F(x)= 0.0           x<28.0
                   = 0.5x-14.0     28.0≦x<30.0
                   =-0.5x+16.0     30.0≦x<32.0
                   = 0.0           32.0≦x      」

[ex3_4.f90]
    ! --- Triangle Pulse ---
         REAL :: x
         PRINT*, 'x?'
         READ*, x
            IF( x < 28.0 ) THEN
                  f = 0.0
            ELSE IF( x < 30.0 ) THEN    !  ここを(28.0 <= x).AND. (x < 30.0) 
                  f = 0.5*x - 14.0      !  と書く必要はないことに注意せよ。
            ELSE IF( x < 32.0 ) THEN
                  f = -0.5*x +16.0
            ELSE
                  f = 0.0
            END IF
         PRINT*, x, f
   END


 このような多重分岐には,もっと便利な SELECT CASE 文が用意されている。 [90]


 SELECT CASE文   [ラベル:]  SELECT CASE(式)            [90]
                            CASE(値または範囲)
                                       ...
                                    CASE(...)
                                       ...
                              END  SELECT [ラベル]


  CASE文の「範囲」は  下限:上限 の形で示し,一方を省略すれば上限なし(または
下限なし)となる。異なるCASE文の範囲(または値)に共通部分があってはならない。
また,全てのCASE文に書かれた選択条件以外のケースを全てまとめて指定する場合には
「CASE DEFAULT」 とする。CASE文が一つの文であることに注意。

  例  CASE(60:100)  PRINT*,"合格"   は誤り。 1行で書きたければ 
          CASE(60:100); PRINT*,"合格"  としなければならない。


 例題 3_5  「成績が80点以上は優,70点から79点までは良,60点から69点
       までは可,59点以下は不可,を判定せよ。」


[ex3_5.f90]
   ! --- Seiseki Hyouka ---
      INTEGER :: i, n1, n2, n3, n4
      n1=0; n2=0; n3=0; n4=0
   1  READ*, i ;    IF(i < 0 .OR. i > 100) GOTO  9
         SELECT CASE(i)
             CASE(80:)
                  PRINT*,'優' ;   n1 = n1 + 1
             CASE(70:79)
                  PRINT*,'良' ;   n2 = n2 + 1
             CASE(60:69)
                  PRINT*,'可' ;   n3 = n3 + 1
             CASE  DEFAULT
                  PRINT*,'不可';  n4 = n4 + 1
         END SELECT
      GO TO 1
   9  PRINT*, '  優=', n1, '  良=', n2, '  可=', n3, '  不可=', n4
      END


100点満点だけは「秀」としたければ,変数 n0 を追加した上で

       CASE(100)
                  PRINT*, '秀' ;  n0 = n0 + 1 

を加えればよい。ただし,上の CASE(80:) を重なりがないよう CASE(80:99) として
おく必要がある。 


 ⇒3章先頭へ ⇒4章へ