愛しの Fortran・3改

Fortran について気の向くままに綴ります

INQUIRE 文で接続の性質を調べる

OPEN 文の ACTION 指定子と同様、以下の指定子の値を INQUIRE 文で調べることができます。

  • ACCESS
  • FORM
  • ASYNCHRONOUS

接続されていない装置あるいはファイルでは UNDEFINED が返されます。

ただ、そもそもこれらはプログラマが OPEN 文で指定して、 接続が続く限り変化することはないので、調べる意味があるのか? という疑問は湧きます。

ACCESSFORM に関しては理論上は事前接続の性質を確認する、 という使用法が考えられるかもしれません。 例えば装置 30 に書式なし直接探査ファイルを事前接続している前提のプログラムなら

      INQUIRE(30,ACCESS=ACCESS,FORM=FROM)

として ACCESSFORM を確認して、 想定と違えば警告を出してプログラム終了とか。

ただ、現代的には事前接続など使わず、単に望みの設定で OPEN すれば良さそうです。 そもそも最近の処理系で書式付き順番探査以外のファイルを事前接続できるのか、 やってみようと思い付いたこともないので知りません。

なお、事前接続では ASYNCHRONOUS は必ず NO です。

あとは装置番号だけ受けとって、 どんな接続でも適宜入出力するライブラリルーチン、とかでしょうか。 つまり OPEN する人と読み書きする人が別人の場合。 何のために?

ところで OPEN 文/INQUIRE 文の ACCESS、FORM 指定子は OPEN 文が導入された FORTRAN 77 以来の最初からある機能です (ただし、接続されていない場合の結果は不定から、 Fortran 90 で UNDEFINED を返すように変更された)。 ASYNCHRONOUS も非同期入出力が導入された Fortran 2003 で OPEN 文、INQUIRE 文同時に導入されました。 何かこう、実用的な要請じゃなくて、指定と確認はセット、 みたいな思想によるんでしょうね。

OPEN 文の ACTION 指定子 (後編)

前編では、ACTION 指定子の指定は省略しない、ということを書きました。 その理由が ACTION 指定子の既定値は処理系依存だから、なのですが、 ではなぜ処理系依存なのか。 少し欲張ったからなのです。

ACTION 指定子は決意表明で、表明したことで起きることはすべて処理系依存です。 一方、処理系はファイルの読み書き属性を(ユーザー権限も含めて)管理しているものです。 なので OPEN 文での ACTION 指定子の指定が、処理系が知る事情も含めて OPEN 文の成否に反映されることも期待されます。

つまり ACTION="READ" は規格上は WRITE 文に指定しない、 という決意表明ですが、処理系は「入出力誤り条件の集合は、処理系依存とする」 を適用して、OPEN 時に読み出し権限を確認する機会にできます (ACTION="WRITE" も同様)。

こちらの見方からすると、ACTION の指定値はファイルの性質によって決まります。 つまり読み出し権限のないファイルには WRITE しか指定できませんし、 書き込み権限のないファイルは READ でなければなりません。 どちらの権限もあれば READWRITE にできます (あるいはどちらかの権限があれば READWRITE にできる?)。 どれが適切かは処理系にしかわからないので、 だから ACTION の既定値は処理系依存にせざるをえなかった、ということでしょう。

OPEN 文で ACTION 指定子を省略したとき(しなかったときもですが) INQUIRE 文で ACTION 指定子の値を問い合わせることができます。

      INQUIRE(UNIT,ACTION=ACTION)

(指定子右辺の ACTION は長さ 5 文字以上の基本文字変数)。

また、ファイルの読み書きの権限があるかも INQUIRE 文で問い合わせができることになっています。

      INQUIRE(FILE="A",READ=READ,READWRITE=READWRITE,WRITE=WRITE)

(指定子右辺の READREADWRITEWRITE はそれぞれ長さ 1 文字以上の文字変数)。 ACTION="READ" で接続できるファイルは READ"YES"、そうでなければ "NO"、 不明なら "UNKNOWN" が返されます。 READWRITEWRITE も同様です。

ちなみに、筆者の使っているある処理系では

  • 書き込み権限のないファイル → READREADWRITEYESWRITENO

  • 読み出し権限のないファイル → READREADWRITENOWRITEYES

  • どちらもないファイル → 3 つとも NO

  • どちらもあるファイル → 3 つとも YES

となりました。

(おわり)

OPEN 文の ACTION 指定子 (前編)

ファイルを新規に接続する OPEN 文では必ず ACTION 指定子を指定します。

  • 入力用に接続(WRITE 文、PRINT 文、ENDFILE 文に指定しない)→ "READ"

  • 出力用に接続(READ 文に指定しない)→ "WRITE"

  • 入出力用に接続(使用制限なし)→ "READWRITE"

これはプログラマの「決意表明」です。 ACTION="READ" を指定して WRITE 文に使ったとき、 ACTION="WRITE" を指定して READ 文に使ったとき、 これは規格上は単に「規格合致でない = 動作は未定義」です。

常識的には、処理系は「入出力誤り条件の集合は、処理系依存とする」 を適用して、ACTION に反する入出力文を誤りとして処理することが期待されます (たぶん、現状すべての処理系がそうなっています)。

ACTION 指定子の既定値は処理系依存です。 だから必ずプログラムに明記します。

      OPEN(FILE="A",STATUS="REPLACE",NEWUNIT=UNIT)

でファイル A の既定値が ACTION="READ" というへそ曲がりな処理系も規格上は許されています。 (ま、実際は ACTION を指定せずに問題が起きる処理系は現実にはありませんし、 そのような処理系実装は考えにくいですが)。 ACTION の指定自体はプログラムの誤り (読むはずのファイルにうっかり書いてしまう) を防ぐのに有用なので、積極的に利用しましょう。

なお、ACTION 指定子は Fortran 90 で導入されたので、 必ず指定すべきなのに FORTRAN 77 時代の本には書いてないので注意が必要です。

既定が FORTRAN 77 と同様な意味になる READWRITE であれば指定を省略しても新たに問題を生じることはなかったはずです。 とうして既定が処理系依存なのかというと、そのあたりについては後編で。

(つづく)

整数型 (その1)

突然、整数型の現状について。

2021 年現在、整数型は 8 ビット、16 ビット、32 ビット、64 ビットの 4 種類の実装が普通です。処理系によっては 128 ビットの整数型があるものも。負の数は 2 の補数表現です。ただし、ビット数を n として、-2**(n-1) をトラップ表現にできる処理系もあるので、数値としては ±(2**(n-1)-1) 内で使うといいでしょう。Fortran に符号無し整数型はありません。

多くの処理系では基本整数型のビット数を選べますが、既定は 32 ビットが普通です(歴史的事情による)。例えば大きさ 2**31 の IEEE 倍精度の実数型 1 次元配列は 16 GB なので、最近の処理系では基本整数型では足りない場合が出てきます。悩ましい問題です。

対処法は 3 つのうちどれか。 1. 基本整数型ではなく、種別型パラメタを指定した整数型を使う。 2. 処理系依存の方法で基本整数型を 64 ビットにする。 3. とても大きい 1 次元配列の使用はあきらめる。

どれも一長一短あります。1. が本来想定されている対処法です。が、煩雑で誤りが混入しやすいのが難点です。2. は可能ならプログラムを書く側からすれば一番簡単な方法ですが、可搬性、互換性には不安があります。現状ではまだ 3. が現実的でしょうか。

(つづく)

ブログ紹介 (歴史編)

ブログのタイトルは「愛しの Fortran・3改」。FORTRAN III についてのブログではなくて、「愛しの Fortran」の 3 です。

1996 年頃(だったはずです)に、日本語で読める Fortran 解説のリンク集、という形で初代「愛しの Fortran」サイトを作りました。数年のうちにハードディスクの故障であえなくこの世から抹消されました。書いた本人以外にこのサイトの存在を覚えている人はいません。たぶん。

その後 2000 年代中頃にはブログ形式で気の向くままに Fortran について語る「Fortran 日記」と、そのブログ記事への事項別目次となるサイト「愛しの Fortran」(2代目)を書いてました。仕事帰りの通勤電車でガラケーでせっせと書いてましたが、機種変更したら英文、長文入力が苦痛な機種にあたってしまい。更新は途絶え、長年放置したあげく、いつしか両サイトともこの世から消えてしまいました。

さらに十数年ほど時は過ぎて 2021 年。私は幸い今も最新の Fortran 2018 でプログラムを書かせてもらってます。縮小印刷してホチキス止めして肌身離さず持ち歩いていた ISO Fortran 規格票も今ではスマホでどこでも参照できる時代になりました(JIS も)。それでふと思い出して突然開始したブログが「愛しの Fortran・3」です。先月、別のサイトで始めましたが、このほどはてなブログに引っ越してきて3改にしました。

実数値を文字列に変換する関数 (その5)

結果変数の長さ決めとその利用

書式仕様 (*(G0,1X)) または (*(G0)) での出力とともに使う、実数配列値を文字配列値に変換する関数の実装を説明しています。

結果変数の長さを決める際、

      L = 0
      DO I = 1, N
        WRITE(LINE,FMT) A(I)
        L = MAX(LEN_TRIM(LINE),L)
      END DO

として、全要素をいったん書いてみて必要な長さを実測しています。 ユーザーが FMT に渡した書式仕様が欄幅固定なら長さを決めるのに 1 つだけ選んで実測することも考えられますが、欄幅に 0 を指定して値ごとに欄幅が変わる場合に対応しています。

その後、割り付けた結果変数を使う際には、実測した長さで割り付けているにもかかわらず、いったん十分な長さの変数に書いたのを結果変数に代入し直しています。

      DO I = 1, N
        WRITE(LINE,FMT) A(I)
        RESULT(I) = LINE
      END DO

これは末尾に空白のある書式仕様が指定された場合、それが長さを決める際の LEN_TRIM で反映されないことに対応するためです。

その他、現状では FMT での改行の指定「/」はできない、などの仕様上の問題点はあります。

今回の実装では結果を配列にしましたが、いっそ配列入力に対してスカラ文字列を返すようにした方が使い勝手はいいかもしれません。

型宣言付き ALLOCATE 文、UBOUND と SIZE

実数値を文字列に変換する関数 (その4)

前回、書式仕様 (*(G0,1X)) または (*(G0)) での出力とともに使う目的で、実数配列値を文字配列値に変換する関数を示しました。今回はその内容の解説です。

まず、実数型配列の入力値に対して、文字型の配列値を返すので、その長さを決める必要がありました。入力配列の大きさを N、出力文字列の長さを L としたなら、出力配列の割り付けは

      ALLOCATE(CHARACTER(L) :: RESULT(N))

です(Fortran 2003 で導入された、型指定付きの ALLOCATE 文)。 世の中の Fortran 解説の多くは Fortran 95 で更新が止まっているものが多いので特に強調しました。

N はいつも通り、入力配列を A として

      N = UBOUND(A,1)

です。ちなみに、この場合は同じ結果になる

      N = SIZE(A)

を使わないのには理由があります。 A が 2 次元以上の配列で、2 つ目の引数 (DIM) を省略した場合に違いが出ます。 DIM のない UBOUND の結果は配列で、N = UBOUND(A)コンパイル時に見つかるエラーになります。 一方で DIM のない SIZE の結果は配列全体の大きさです。 添字の上限として使うつもりの N に入れるべき数値は次元の寸法であって、配列全体の大きさではないので、SIZE を使うのは不適切です。 この場合はコンパイル時には発見されず、実行時に結果が変になる、「バグ」となってしまって厄介です。 ただ、1 次元配列の場合はたまたま寸法と大きさが一致するので、SIZE を使ってしまう人もいます。 最初からすべて UBOUND に統一する方が無難です。

次に L の決め方ですが、もうだいぶ書いたのでそれは次回とします。

(つづく)