• 追加された行はこの色です。
  • 削除された行はこの色です。
現在(&lastmod;)作成中です。
既に書いている内容も&color(#ff0000){大幅に変わる};のは間違いないので注意。

-------
#contents
-------

* 倍精度浮動小数点数の指定方法 [#w862937a]
** kindパラメータ [#je2ab609]
* アンケート(その01): 前回の講義について [#x99181c7]

#vote(簡単すぎた, 難しすぎた, ちょうどよかった)

* アンケート(その02): C言語との比較による説明の仕方について [#bad5d153]

#vote(Cとの比較で良い, CよりもJavaと比較して欲しい, 他の言語と比較はない方がわかりやすい)


* 倍精度浮動小数点数の指定方法 [#b90f3b3c]
** kindパラメータ [#wbd486cb]
計算科学では実数の物理量を数値的に表現するのに単精度ではなく、
倍精度の浮動小数点数を使うのが普通である。
(単精度実数では精度が不十分なため。)

まは、スーパーコンピュータは単精度浮動小数点ではなく、
倍精度浮動小数点数の演算(四則演算)を高速に処理できるよう設計されている。
従ってFortran90/95言語での倍精度浮動小数点数の表現方法に早めに慣れておくことは重要である。

Fortran90/95で倍精度浮動小数点数を表す方法は幾つかある。
最も簡単でportabilityの高い方法は以下の方法であろう。
まず、単精度浮動小数点数の精度に関係したある整数定数を定義する。
ここではその整数をSPという名前にする。
SPとはSingle Precision(単精度)の頭文字をとったものである。
 integer, parameter ::  SP = kind(1.0)
次に、このSPを使って単精度として指定した浮動小数点数の2倍の精度を持つ浮動小数点数、
つまり倍精度浮動小数点数に関係したある整数定数(ここではDPという名前)を以下のようにして定義する。
 integer, parameter ::  DP = selected_real_kind(2*precision(1.0_SP))
この整数定数DPはDouble Precisionを意味する。

こうして定義した二つの整数SPとDPを使って単精度浮動小数点や倍精度浮動小数点数を宣言する。
 real(kind=SP) :: a
 real(kind=DP) :: b
とすると、aは単精度浮動小数点、bは倍精度浮動小数点数である。

上のプログラムのkind=の部分は省略可能である。
つまり
 real(SP) :: a
 real(DP) :: b
としてもよい。

数値データの精度指定にもこのSPやDPを使う。
 a = 1.0_SP    ! 単精度の1.0
 b = 1.0_DP    ! 倍精度の1.0

サンプルプログラムを見てみよう。
 program double_precision_real
   implicit none
   integer, parameter ::  SP = kind(1.0)
   integer, parameter ::  DP = selected_real_kind(2*precision(1.0_SP))
   real(SP) :: a
   real(DP) :: b
   a = 3.1415926535897323846264338327950288_SP
   b = 3.1415926535897323846264338327950288_DP
   print *,' a, b = ', a, b
 end program double_precision_real

*  &color(#0000ff){【演習】}; [#m48e8fe5]
*  &color(#0000ff){【演習】}; [#m1ea2638]
上のプログラムをdouble_precision_real.f95という名前のファイルに保存し、
コンパイル&実行せよ。

*  &color(#0000ff){【演習】}; [#q0b52b51]
*  &color(#0000ff){【演習】}; [#u0b459f3]
double_precision_real.f95に現れる二つのkindパラメータSPとDPには実際にはどんな値が入っているか調べよ。

* 数字表現 [#ae7f1e3c]
* 数字表現 [#x3e65148]
- 浮動小数点数
-- 1.                  ! デフォルト精度
-- 0.1_SP            ! kindパラメタSPの浮動小数点数
-- 3.141593_DP       ! kindパラメタDPの浮動小数点数
-- 0.31415926535897932e-1_DP  ! 上に同じ


* 型名 [#zcec7fc0]
* アンケート:C言語について [#p6cfb1d3]

#vote(Cはよく知っている, Cは分からない(忘れた))


* 型名 [#hca8af14]
| 型 | C  ( C99 ) | Fortran90/95 | 補註 |
| 文字 | char | character | |
| 文字列 | char[n+1] | character(len=n) | nは文字長|
| 整数 | int | integer | integer(kind=4)でも可 |
| 実数 | float | real | real(kind=SP)でも可 |
| 倍精度実数 | double | real(kind=DP) |  |
| 「長い」整数  | long | integer(kind=8でも可) | kindの整数はシステム依存 |
| bool | ( _Bool ) | logical | 値は .true. または .false. |
| 複素数 | ( _Complex ) | complex |  |
| 構造体 | struct | type | 詳しくは後述 |

* 構造体 (derived type) [#ba362129]
* 構造体 (derived type) [#o99419e2]
C言語の構造体とほとんど同じである。下の例をみよ。
 program type
   implicit none
 
   type student
      character(len=20) :: first_name, last_name
      integer :: age
   end type student
 
   type(student) :: st
 
   st = student("Albert", "Einsten", 19)
 
   print *,st%first_name, st%last_name, st%age
 end program type
構造体のメンバにアクセスするのに%を使う。

構造体の入れ子も可能である。

構造体の配列も可能である。

構造体を構造体に代入(コピー)することも可能である。


*  &color(#0000ff){【演習】}; [#c4503552]
*  &color(#0000ff){【演習】}; [#na2ba0de]
上のプログラムをtype.f90に保存し、コンパイル&実行せよ。


*  &color(#0000ff){【演習】}; [#x688a5a6]
*  &color(#0000ff){【演習】}; [#od4538f0]
student型の構造体変数をもう一つ(例えばst2という名前)を作り、
stのデータをst2にコピーした上で first_name 要素を変更せよ。
stのデータをst2にコピーした上で、要素の一部(例えばage)を変更し、st2を出力せよ。


* 宣言 [#eb66eb68]
* 宣言 [#q0368b92]
C言語では変数の宣言はブロックの先頭にまとめて置く。(C99やC++はもっと自由だが。)
Fortran90/95でも同じ。


* 暗黙の型宣言 [#wf527db8]
* 暗黙の型宣言 [#tc2c33ff]
Fortran90/95ではimplicit noneを省略すると「暗黙の型宣言」をしたことになる。
暗黙の型宣言とは、次の6つのアルファベット i,j,k,l,m,n で始まる変数は整数である等のルールである。
使わない方がいい機能なので詳細は知らなくて良いだろう。
バグが入りやすいので、暗黙の型宣言は使わない方が良い。
Fortran90/95プログラムでは&color(#ff0000){常にimplicit none宣言をすること。};

* 暗黙の型宣言はなぜバグが入りやすいか [#mcfe6dfa]
* 暗黙の型宣言はなぜバグが入りやすいか [#w75e86a6]
宣言したつもりのない変数を間違って使っていても気がつかない可能性がある。
例えば、次のプログラムにはバグがある。すぐに見つけられるか?
 program use_implicit_none
   integer :: fresh_meat
   flesh_meat = 100 ! yen
   print *, "today's price = ", fresh_meat
 end program use_implicit_none

*  &color(#0000ff){【演習】}; [#w6bb1388]
*  &color(#0000ff){【演習】}; [#xd8471a3]
上のプログラムをuse_implicit_nene.f95というファイルに書き込み、コンパイル&実行せよ。

- バグがあるのにコンパイラは教えてくれないだけでなく、
何事もないかのように正常終了する。しかも、それらしい答えを返す。
つまりバグがあることにすら気がつかない!


*  &color(#0000ff){【演習】}; [#wcd4bb8a]
*  &color(#0000ff){【演習】}; [#i9399e76]
今作ったuse_implicit_nene.f95の2行目(program ...の次の行)に
implicit noneと書いてから、コンパイルせよ。

* 行の継続 [#m30d0acd]
* 行の継続 [#u8a3a60c]
行末に&をつけると継続行
 a = b + c + &
        d  + f

* セミコロン [#pd161e03]
* セミコロン [#y0eac818]
セミコロンは改行と同じ
 tmp = right
 right = left
 left = tmp
と
 tmp = right; right = left; left = tmp
は同じ。


* 1次元配列 [#i38a009f]
* 1次元配列 [#z78a9b40]
C言語では
 array01[NX];
が大きさNXの1次元配列である。
メモリ上に、array01[0], array01[1], array01[2], ..., array01[NX-1]と並んでいる。

Fortran90/95では
 integer, dimension(NX) :: array01
と宣言するとメモリ上に、array01(1), array01(2), array01(3), ..., array01(NX)と並ぶ。
&color(#ff0000){配列のインデックスは1から始まる。};

* &color(#0000ff){【演習】}; [#s889d20d]
* &color(#0000ff){【演習】}; [#db21d215]
大きさNXの1次元整数配列array_01を作り、
各要素に1,2,3,...,NXを代入した上で、
全要素の和をとるFortran90/95プログラムを書け。


* 2次元配列 [#p9faa01d]
* 2次元配列 [#ncd4eeca]
厳密に言えばC言語には2次元配列はない。
あるのは「配列の配列」である。
つまり二つの整数インデックスiとjを使って
 array02[j][i]
という形でアクセスできるものである。

このarray02を2次元配列とは呼べないということは、
array02のサイズ(インデックスiとjの範囲)は実行時に不定として、
array02をまるごと引数で受け取る関数がC言語では作れないことを考えれば納得出来るであろう。

* メモリ空間中での2次元配列の各要素の位置 [#n7fa7156]
* メモリ空間中での2次元配列の各要素の位置 [#a07128c6]
上記のarray02は、
 array02[0][0], array02[0][1], array02[0][2], ..., array02[0][NX-1]
と並び、そして
(それに続く場合もあるし、
まったく別の場所にあるかもしれない)ある位置から、
 array02[1][1], array02[1][1], array02[1][2], ..., array02[1][NX-1]
という順番で並ぶ。

一方、
Fortran90/95ではarray02(i,j)という形でアクセスできる量は本物の2次元配列である。
サイズがわかっている場合には
 integer, dimension(NX,NY) :: array02
と宣言する。
不明の場合には、
 integer, dimension(:,:) :: array02
と宣言し、後ほど(実行時に)メモリをallocateする。
メモリ上では、array02の要素は
 array02(1,1), array02(2,1), array02(3,1), ..., array02(NX,1), array02(1,2),...
に全ての要素(NX*NY個)が連続して並ぶ。

配列の要素がメモリ空間中に連続してあることは、
メモリへのアクセス速度が極めて重要となるスーパーコンピューティングでは極めて重要である。

* 3次元配列 [#t7bc922e]
* 3次元配列 [#s8cc6177]
C言語では
 array03[k][j][i]
が上の意味での「擬似」3次元配列である。

Fortran90/95では
 array03[i][j][k]
が3次元配列で、
宣言は
 integer, dimension(NX,NY,NZ) :: array03
または 
  integer, dimension(:,:,:) :: array03
とする。


* if構文 [#k2062c0c]
* if構文 [#i308f811]
if文はC言語とほとんど同じ。下の例を見れば一目瞭然であろう。
 if (criterion) then
   action
 end if

'''action'''が1行で書けるなら
 if ( criteron ) action
ともできる。

else-if構文も簡単である。
 if (criterion_1) then
   action_1
 else if (criterion_2 ) then
   action_2
 else if (criterion_3 ) then
   action_3
 end if

* 関係演算子 [#u0989cf8]
* 関係演算子 [#g5e70b10]
これも下の例を見ればわかるであろう。
 if (a==b) then   ! aとbが等しい
 if (a>b) then
 if (a>=b) then
 if (a<b) then
 if (a<=b) then
 if (a/=b) then    ! aとbが等しくない

* 関係演算子(古い書き方) [#v3610999]
* 関係演算子(古い書き方) [#r7c520aa]
上の関係演算子はそれぞれ下のようにも書ける。
 if (a.eq.b) then   ! aとbが等しい
 if (a.gt.b) then
 if (a.ge.b) then
 if (a.lt.b) then
 if (a.le.b) then
 if (a.ne.b) then   ! aとbが等しくない


* 論理値 [#a4ed9a0f]
* 論理値 [#f694601d]
bool変数はlogicalという型名を持ち、
 .true.
か
 .false.
の二つをとる。

 logical :: a, b, c
 a = .true.
 b = .false.
 c = a .and. b
 c = a .or. b
 c = .not.a


* 繰り返し構文(doループ) [#ee27c370]
* 繰り返し構文(doループ) [#uedfc000]

C言語でいうfor文である。

** incrementが1の場合のdo-loop [#j8365f46]
** incrementが1の場合のdo-loop [#me73416e]
 program do_loop
   implicit none
   integer :: i
   do i = 1 , 100
      print *, ' i = ', i
   end do
 end program do_loop

** incrementが2の場合のdo-loop [#sead8b8a]
** incrementが2の場合のdo-loop [#d5230d82]
 program do_loop
   implicit none
   integer :: i
   do i = 1 , 100 , 2
      print *, ' i = ', i
   end do
 end program do_loop

*  &color(#0000ff){【演習】}; [#w923f6c1]
*  &color(#0000ff){【演習】}; [#zed411bf]

- 上のプログラムをdo_loop.f95に保存し、increment値(上の場合2)を自由に変えて実行せよ。


- do_loop.f95のdo文を
 do i = 100 , -100 , -2 
として実行せよ。


* exitとcycle [#r48965b5]
* exitとcycle [#zf2e6992]
整数のカウンターのないdo-loopも可能である。
 do 
    ...
 end do 
このままだと無限ループになるので、通常はある条件を満たせばループから抜け出すようにする。

C言語だとbreak文でループから抜け出す。(正確には最も内側のループから抜け出す。)
Fortran90/95でbreakに相当するのはexitである。
 do 
   ...
   if (condition) exit !---+
 end do                !   | ループから抜け出す。
                       !<--+

C言語ではループの先頭に戻る時にはcontinue文を使うが、
それに相当するのはFortran90/95ではcycleである。

 do                     !<--+
   ...                  !   | 戻る
   if (condition) cycle !---+
   ...
 end do                      

* &color(#0000ff){【演習】}; [#d65d8f1f]
* &color(#0000ff){【演習】}; [#l1794fba]

if文、select case文、do文を使って自由にプログラムを作ってみよ。

* 関数 [#gc70e14f]
* 関数 [#r1a5bee4]
C言語と同様に関数(function)という手続き(procedure)は、
Fortran90/95プログラムの重要な構成部品である。
関数の使い方は以下の例を見ればわかるであろう。

*  &color(#0000ff){【演習】}; [#f9225f81]
*  &color(#0000ff){【演習】}; [#u6abbb06]
- 次のプログラムをfunction01.f95として保存し、実行せよ。
 integer function next_int(i)
   implicit none
   integer, intent(in) :: i
 
   next_int = i+1
 end function next_int
 
 program function01
   implicit none
   integer, external :: next_int
 
   print *, 'ans = ', next_int(-100)
 
 end program function01
intent(in)は引数iが入力引数であり、関数next_intの内部で変更されることがないことを保証するものである。
 
- 関数を以下のように内部副プログラムとしてメインの中に含むこともできる。
次のプログラムをfunction02.f95として保存し、実行せよ。
//(内部副プログラムについては後述。)
 program function02
   implicit none
 
   print *, 'ans = ', next_int(-100)
 
 contains
 
   integer function next_int(i)
     integer, intent(in) :: i
 
     next_int = i+1
   end function next_int
 
 end program function02


* サブルーチン [#k7df9b7e]
* サブルーチン [#j858d884]
関数の本来の機能は入力に応じて出力を返すものであるが、
出力(返り値)が不要な場合も多い。
C言語ではこのような場合void関数とするが、
Fortran90/95ではvoid関数をsubroutineと呼ぶ。

サブルーチンを呼び出すにはcall '''subroutine名'''とする。
以下の例をみよ。
 subroutine next_int(input, output)
   implicit none
   integer, intent(in)  :: input
   integer, intent(out) :: output
 
   output = input + 1
 end subroutine next_int
 
 program subroutine01
   implicit none
 
   integer :: i, j
   i = 10
   call next_int(i,j)
   print *, 'ans = ', j
 
 end program subroutine01

* 値渡しと参照渡し [#oc0716b7]
* 値渡しと参照渡し [#n02083fe]
C言語は値渡し、Fortran90/95は参照渡しである。
C言語が値渡しであることは、以下の例でkの値が変わっていないことから確認できる。
 void pass(int i)
 {
   i = 0;
   printf("i=%d\n", i);
 }
 
 main()
 {
   int k = 2010;
   printf("before: k = %d\n", k);
   pass(k);
   printf("after:  k = %d\n", k);
 }

これと'''似た'''プログラム(同じではない)をFortran90/95で書くと以下のようになる。
 subroutine pass(i)
   implicit none
   integer :: i
   i = 0;
   print *, "i=", i
 end subroutine pass
 
 program call_by_reference
   implicit none
   integer :: k = 2010
 
   print *, "before: k = ", k
   call pass(k)
   print *, "after:  k = ", k
 end program call_by_reference
このプログラムではkの値はサブルーチンpassを読んだ後に変更されている。

*  &color(#0000ff){【演習】}; [#b8f44e5b]
*  &color(#0000ff){【演習】}; [#w00a63d7]

上の二つのプログラムをそれぞれcall_by_value.c、call_by_reference.f95という名前で保存し、実行せよ。

* 入出力属性 [#sacdd71c]
* 入出力属性 [#qc7a9554]

値渡しに比べて参照渡しは値をコピーする必要がないので実行が速い。
だが、上のcall_by_reference.f95プログラムで見たように、
引数として渡した変数がそのサブルーチン内部で勝手に(誤って)変更されると見つけにくいバグになり、危険である。
このような事故を防ぐためにFortran90/95には引数に入出力属性をつけることができる。
サブルーチンincrementの引数iは入力属性をもつと指定すると(下のプログラムの2行目)、
コンパイラがエラーを出してくれる。
 subroutine increment(i)    ! コンパイルエラーを出してくれる
   integer, intent(in) :: i
   i = 0;
   print *, "i=", i
 end subroutine increment
 
 program call_by_reference
   implicit none
   integer :: k = 2010
 
   print *, "before: k = ", k
   call increment(k)
   print *, "after:  k = ", k
 end program call_by_reference


*  &color(#0000ff){【演習】}; [#leb503af]
*  &color(#0000ff){【演習】}; [#gd1ca64f]
call_by_reference.f95を上のように変更してコンパイルせよ。

* 入出力属性の種類 [#b45f1fe9]
* 入出力属性の種類 [#ded0a362]
入出力属性には以下の3種類がある。

| intent(in) | 入力 | その手続き内で値は変更されない変数 |
| intent(out) | 出力 | その手続き内で値が設定される変数 |
| intent(inout) | 入出力 | 両者の混合。デフォルト。 |

バグの混入を防ぐために、Fortran90/95プログラムでは&color(#ff0000){すべての引数に入出力属性をつける};ことを強く勧める。



* case 構文 [#s659af01]
* case 構文 [#pe0d97f8]
C言語でいうswitch文である。

 select  case (case expression)
 case (case selector 1)
   action 1
 case (case selector 2)
   action 2
 case (case selector 3)
   action 3
   .
   .
 case default   ! なくても良い。
   default action
 end select

C言語では普通breakが必要だがFortran90/95のcase文には不要である。

*  &color(#0000ff){【演習】}; [#l6f39b21]
*  &color(#0000ff){【演習】}; [#e8234997]

次のプログラムをcase.f95に保存し、実行せよ。
 program case
   implicit none
   integer :: month
 
   month = 6
 
   select case (month)
   case (1)
     print *,'January.'
   case (2)
     print *,'February'
   case (3:5)
     print *,'Spring'
   case default
     print *,'Other season'
  end select
 end program case

* 文字列の比較 [#v653840e]
* 文字列の比較 [#qa2a3c2b]

C言語では二つの文字列が等しいかどうかを判断するためにわざわざstrcmpを呼ぶ。
Fortran90/95では
 if (string1==string2) 
や
 if ( response == "what do you mean?" ) 
などと書ける。

従って長さの違う文字列もselect case構文で以下のように簡単に場合分けできる。
 program case_string
   implicit none
   character(len=*), parameter :: color = 'white'
 
   select case (color)
   case ('aka')
     print *, 'red'
   case ('ao')
     print *, 'blue'
   case ('midori')
     print *, 'green'
   case default
     print *, "I don't know the color."
  end select
 end program case_string

*  &color(#0000ff){【演習】}; [#qe42d107]
*  &color(#0000ff){【演習】}; [#pecc14bd]
上のプログラムをcase_string.f95というファイルに保存し、実行せよ。

* 様々な文字列操作 [#yb0f1e23]
* 様々な文字列操作 [#gbeafb3a]

ここでFortran90/95における文字列操作機能を紹介しておく。
参考までにCでの同様な操作をコメントに書いておいた。

 program strings
   implicit none
 
   character(len=*), parameter :: string01 = 'Computational'
   character(len=*), parameter :: string02 = 'Science'
 
   character(len=30) :: message30
 
 
   print *, ' length of string01 = ', len(string01)       ! strlen(string01)
   print *, ' string01==string02 = ', string01==string02  ! strcmp(string01,string02)
   print *, ' string01//string02 = ', string01//string02  ! strcat(string01,string02)
   print *, ' string01//string02 = ', string01//string02  ! strcat(string01,string02)
   print *, ' string01//string02//string02 = ', string01//string02//string02  ! ?
 
   message30 = string01   ! strcpy(message,string01)
   print *, ' message in 30 characters = ', message30
   print *, ' length of message30 is = ', len(message30)
   print *, ' length of message30 is = ', len_trim(message30)
 
   print *, ' message30(10:13) = ', message30(10:13)
   print *, ' message30//string02 = ', message30//string02
   print *, ' trim(message30)//string02 = ', trim(message30)//string02
 
 end program strings



* 配列演算機能: スカラーの代入 [#q59330e0]

まずはC言語版を見る。

 /* array01.c */
 #define NX 10
 #define NY 12
 #define NZ 14
 main()
 {
   int i, j, k;
   double A[NZ][NY][NX];
 
   for (k=0; k<NZ; k++) {
     for (j=0; j<NY; j++) {
       for (i=0; i<NX; i++) {
        A[k][j][i] = 0.0;
       }
     }
   }
 }

同じことをFortran90/95で「下手に」書けばこうなる。

 !
 ! array01.f95
 !
 module constants
   implicit none
   integer, parameter :: SP = kind(1.0)
   integer, parameter :: DP = selected_real_kind(2*precision(1.0_SP))
 
   integer, parameter :: NX = 10
   integer, parameter :: NY = 12
   integer, parameter :: NZ = 14
 end module constants
 
 program array01
   use constants
   implicit none
   integer :: i, j, k
   real(DP), dimension(NX,NY,NZ) ::  A
 
   do k =1 , NZ
     do j = 1 , NY
        do i = 1 , NX
           A(i,j,k) = 0.0
        end do
     end do
   end do
 end program array01


普通はこう書く。module constantsは同じなのでmainプログラムだけ示す。

 program array01
   use constants
   implicit none
   integer :: i, j, k
   real(DP), dimension(NX,NY,NZ) ::  A
   A = 0.0
 end program array01


* 配列演算機能: 配列の要素毎の計算(その1) [#re2501a5]

C言語で
 /*     array02.c	  */
 #define NX 10
 #define NY 12
 #define NZ 14
 main()
 {
   int i, j, k;
   double A[NZ][NY][NX];
   double B[NZ][NY][NX];
   double C[NZ][NY][NX];
   for (k=0; k<NZ; k++) {
     for (j=0; j<NY; j++) {
       for (i=0; i<NX; i++) {
         A[k][j][i] = 3*B[k][j][i]-C[k][j][i];
       }
     }
   }
 }

Fortran90/95ではこうなる。「下手」に書いた方法をコメントで示した。
(module constantsは同じ)

 program array02
   use constants
   implicit none
   integer :: i, j, k
   real(DP), dimension(NX,NY,NZ) ::  A, B, C
 !------------------------------------------
 !   do k =1 , NZ
 !     do j = 1 , NY
 !        do i = 1 , NX
 !           A(i,j,k) = 3*B(i,j,k)-C(i,j,k)
 !        end do
 !     end do
 !  end do
 !------------------------------------------
   A = 3*B-C
 end program array02


* 配列演算機能: 配列の要素毎の計算(その2) [#j62a06a1]
割り算でも同じである。

 !
 !  array03.f95
 !
 module constants
   implicit none
   integer, parameter :: SP = kind(1.0)
   integer, parameter :: DP = selected_real_kind(2*precision(1.0_SP))
 
   integer, parameter :: NX = 10
   integer, parameter :: NY = 12
   integer, parameter :: NZ = 14
 end module constants
 
 program array03
   use constants
   implicit none
   integer :: i, j, k
   real(DP), dimension(NX,NY,NZ) ::  A, B, C
 !------------------------------------------
 !   do k =1 , NZ
 !     do j = 1 , NY
 !        do i = 1 , NX
 !           A(i,j,k) = B(i,j,k)/C(i,j,k)
 !        end do
 !     end do
 !  end do
 !------------------------------------------
   A = B/C
 end program array03




------------------------------

as of &_now; (&counter;)