89 関数ブロック (function blocks)

コマンド function は、gnuplot コードからなる名前付きブロックのヒアド キュメント形式による定義を意味する符号で、それは関数として呼び出すこと が可能です。 データブロックと同様、関数 (function) ブロックの名前は '$' で始まる必 要があります。その定義には、最大 9 つの名前付きの引数を指定できます。 それらの名前は、その関数ブロック内で局所変数として扱われます。以下参照: local (96), scope (26)

一度関数ブロックを定義すると、それを通常の関数を呼び出すのと同じように どこでもその名前で呼び出すことができます。返り値が適切でない場合、関数 ブロックを、数式の一部としてでなく、コマンド "evaluate" で呼び出すこと ができます。

例:


    function $sinc(arg) << EOF
        if (arg == 0) { return 1.0 }
        return sin(arg) / arg
    EOF


    gnuplot> plot $sinc(x) with lines title "sinc(x) as a function block"

名前付き引数の一覧は、関数ブロックの宣言時に指定する必要はありません。 コマンドラインで指定した関数の引数の個数とその値は、関数ブロックの内部 から、整数変数 ARGC とそれに対応する配列 ARGV[ARGC] でアクセスできます。 以下参照: ARGV (82.1)。これにより、可変な個数の引数を操作できる関数ブロック を定義することができます。call 文によるファイルの読み込みとは違い、 引数は文字列変数化 (例えば ARG1) はされません。

例:


    function $max << EOF
        local max = real("-Inf")
        if (ARGC == 0) { return NaN }
        do for [i=1:ARGC] {
            if (max < ARGV[i]) {
                max = ARGV[i]
            }
        }
        return max
    EOF
    gnuplot> foo = $max( f(A), 2.0, C, Array[3] )
    gnuplot> baz = $max( foo, 100. )

関数ブロックをサポートする一番の目的は、複雑な関数を gnuplot 内部で直 接定義できるようにすることです。もちろん、同じ関数を C や Fortran でコ ードした場合よりも実行速度は遅くなりますが、これは色々な目的に答えるこ とを可能にします。実行速度が重要な場合は、代わりにその関数を別にプラグ インとして実装すればいいでしょう (以下参照: plugins (25))。

関数ブロックを使う 2 つ目の目的は、gnuplot コマンドが、これを使う以外 には存在できないような状況でその実行を可能にすることです。例えばあなた が 2 つの CSV ファイルからのデータを描画したいが、一つのファイルはフィ ールドがカンマ区切りで、もう一方はセミコロン区切りであるとします。通常 この属性に対しては、事前にコマンド set datafile をセットしますが、そ れは plot コマンドが使用するすべてのファイルに適用されてしまいます。し かし我々は、各ファイルが plot コマンドで参照される直前にそれを設定する ように呼びだすような関数ブロックを定義できます。


    function $set_csv(char) << EOF
        set datafile separator char
    EOF
    plot tmp=$set_csv(",") FILE1, tmp=$set_csv(";") FILE2

制限:

関数ブロックを使う自明でない例として、複素対数ガンマ関数 lngamma に対 する 15 項 Lanczos 近似の実装とグラフがデモコレクション内にあります。 function_block.dem

この関数ブロックによる実装は、同じアルゴリズムで C で直接コードされて いる組み込み関数の lnGamma と比べて、だいたい 25 倍位遅いですが、それ でも対話型での 3 次元グラフの回転には十分な位の速さです。 デモにある関数定義は以下の通り。

15 項 Lanczos 近似を用いた log$\Gamma$(z) の関数ブロックによる実装
 
 array coef[15] = [ ... ]
  function $Lanczos(z) << EOD
     local Sum = coef[1] + sum [k=2:15] coef[k] / (z + k - 1)
     local temp = z + 671./128.
     temp = (z + 0.5) * log(temp) - temp
     temp = temp + log( sqrt(2*pi) * Sum/z )
     return temp
 EOD
  function $Reflect(z) << EOD
     local w = $Lanczos(1.0 - z)
     local temp = log( sin(pi * z) )
     return log(pi) - (w + temp)
 EOD
  my_lngamma(z) = (z == 0) ? NaN : (real(z) < 0.5) ? $Reflect(z) : $Lanczos(z)

関数ブロックの使用は試験段階です。 詳細は、リリース版に含まれる前に変更される可能性があります。

竹野茂治@新潟工科大学
2024-02-16