LoginSignup
5
1

More than 3 years have passed since last update.

文字型変数の重箱の隅

Last updated at Posted at 2019-12-22

Advent Calendar 埋め草記事として、文字型変数の重箱の隅をつつくようなことを書かせていただきます。

内部ファイルへの I/O は pure

I/O は一般に副作用を持つ動作なので impure ですが、文字型を内部ファイルとして使う場合はどうなるのでしょう? 内部ファイルを使えば、数値を文字列に変換したり、文字列を数値に変換したりできますが、これは型変換を伴う代入の様に思えます。

文法書をしらべてみると、これは pure としていいようです。

プログラム例

内部ファイルを用いて実数を書いた文字列を実数に変換する関数を、pure で elemental な関数として定義して実際に使ってみます。

要素数3の文字列配列の実数値を、そのまま引数として渡して、一気に数値に変換しています。なお文字列の配列は文字列の長さをそろえる必要がありますが、人間が手で数えて等しい長さの文字列を与えるのは面倒なので、配列構成子 (array constructor) に変数型(と宣言長)を与えることで、自動で数えて調整してもらっています。

    module test_m
        implicit none
    contains
        pure elemental real function r_from_str(text) result(res)
            character(len = *), intent(in) :: text
            read(text, *) res
        end function r_from_str
    end module test_m


    program pure_internal_io
        use test_m
        implicit none
        character(len = :), allocatable :: str(:) 
        str = [character(len=20)::'1.0', '-2.0e-3', '3.14159265359']
        print *, r_from_str(str)
    end program pure_internal_io
   1.000000     -2.0000001E-03   3.141593

ところで、内部ファイルは書式付きの I/O なので、C 言語とかの atof 関数とかよりとても遅かったりします。

文字列定数に種 (kind)

整数型や実数型の定数などの種別を明示する時には、お尻の方に 3.14_real32 などとアンダースコアに続いて種を与えますが、文字列の場合はどうでしょうか?

文字列の場合は頭の方に与えます。

今まで使ったことが無かったですが、これは見かけが異常なプログラムを作るのにとても便利な気がします。

Fortran は予約語が無いことを利用し命令語を変数名とし、固定形式なら空白が無視されることから空白を単語の途中に挿入し、73 桁より先が無警告で切り捨てられることと合わせて、異常な見かけのプログラムを書くのにいい感じになりそうです。

プログラム例

ここでは dot という変数を文字型の種別として用いることで、内積を求める組み込み関数の dot_product と見かけの似た文字並び dot_'product(p, p)' を作っています。'product(p, p)' という文字定数の種を dot に指定しています。

Fortran 90 の時に日本が漢字対応を前提に文字型にも種を与えたのですが、残念なことにたいがいの Fortran コンパイラは unicode などの世になっても文字型の種対応がおざなりです。intel/gfortran/flang とも dot、npn とも 1 を返しました。今後 emoji 効果であるいは・・・

(異常なプログラムではありません。)

    program char_kind
        implicit none
        complex :: p(3) = [(1.0, 2.0), (2.0, 1.0), (1.0, 1.0)]
        integer, parameter :: dot = kind("a"), npn = kind("あ")

        print *, dot, npn

        print *, dot_product(p, p)
        print *, dot_'product(p, p)'
    end program char_kind

内積は複素ベクトルの内積を取っています。

           1           1
 (12.00000,0.0000000E+00)
 product(p, p)
5
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1