Fortran90(where)

ずっとFortran学習してますが、なかなか飽きません。飽きるまで続く気がしています。そして新たな発見。where構文。こんな強力な構文があるとは知りませんでした。
今回はwhereを使っていきます。

まずはwhereを使わない例です。doで回して配列aの要素が5より大きかったら、配列bに代入するときに、2倍にするプログラムです。

takk@deb9:~$ cat do.f90
      program main
        integer a(10),b(10)
        data a /1,2,3,4,5,6,7,8,9,10/

        do i=1,10
          if (a(i) > 5) then
            b(i) = a(i) * 2
          else
            b(i) = a(i)
          end if
        end do

        do i=1,10
         write(*,*) b(i)
        end do

        stop
      end
takk@deb9:~$ gfortran do.f90
takk@deb9:~$ ./a.out
           1
           2
           3
           4
           5
          12
          14
          16
          18
          20
takk@deb9:~$

6行目から2倍になってますね。

上のプログラムをwhereを使って作り直すとこうなります。

takk@deb9:~$ cat where.f90
      program main
        integer a(10),b(10)
        data a /1,2,3,4,5,6,7,8,9,10/

        where (a > 5)
         b = a * 2
        else where
         b = a
        end where

        do i=1,10
         write(*,*) b(i)
        end do

        stop
      end
takk@deb9:~$

いやあスゴイ。なんて簡潔に書けるのでしょうか。

実行するともちろん同じ結果になります。

takk@deb9:~$ gfortran where.f90
takk@deb9:~$ ./a.out
           1
           2
           3
           4
           5
          12
          14
          16
          18
          20
takk@deb9:~$

使い方は、whereとend whereの間に配列代入文を挿むだけ。

where 条件
  配列代入文
end where

もしくはこのパターン。

where 条件
  配列代入文1
else where
  配列代入文2
end where

配列代入文以外はだめなのでしょうか。配列代入の代わりにwriteを入れてみます。

takk@deb9:~$ cat where2.f90
      program main
        integer a(10),b(10)
        data a /1,2,3,4,5,6,7,8,9,10/

        where (a > 5)
         write(*,*) 'HELLO'
        end where

        stop
      end
takk@deb9:~$

ビルドエラーとなります。

takk@deb9:~$ gfortran where2.f90
where2.f90:6:27:

          write(*,*) 'HELLO'
                           1
Error: Unexpected WRITE statement in WHERE block at (1)
takk@deb9:~$

もちろんwhere構文内なので配列代入しかできないのであって、if文の中なら問題ないです。

takk@deb9:~$ gfortran if.f90
takk@deb9:~$ ./a.out
 HELLO
takk@deb9:~$ cat if.f90
      program main
        integer a(10)
        data a /1,2,3,4,5,6,7,8,9,10/

        if (a(6) > 5) then
         write(*,*) 'HELLO'
        end if

        stop
      end
takk@deb9:~$ gfortran if.f90
takk@deb9:~$ ./a.out
 HELLO
takk@deb9:~$

普通の代入はどうでしょうか。

takk@deb9:~$ cat where3.f90
      program main
        integer a(10),b(10)
        data a /1,2,3,4,5,6,7,8,9,10/

        where (a > 5)
         i = 1
        end where

        stop
      end
takk@deb9:~$ gfortran where3.f90
where3.f90:6:9:

          i = 1
         1
Error: WHERE assignment target at (1) has inconsistent shape
takk@deb9:~$

whereの中では、普通の代入もエラーとなりました。
やはり配列代入のみしか書くことはできないようです。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA