2009年12月16日水曜日

R 言語の FORTRAN 拡張を試す (続編)

昨日のエントリ「R 言語 の FORTRAN 拡張を試す」 に続き、.Fortran 関数で外部ルーティンへの引数渡しについてもう少し調べた。

.Fortran には外部ルーティン名、外部ルーティンへの引数を渡す。デフォルトでは、外部ルーティンへ引数として渡す R オブジェクトは直接渡されず、一旦オブジェクトを複製し、複製されたオブジェクトのアドレスが外部ルーティンへ渡る。


例えば double に 1.0 をセットする外部ルーティン set_one を考える。

      subroutine set_one(a)
      real*8 a
      a = 1.d0
      end

x に 0 をセットして set_one に渡すと、

> x <- 0
> result <- .Fortran("set_one", x)
> x
[1] 0
> result[[1]]
[1] 1

x は 0 のままで、.Fortran が返したリストに 1 がセットされた。
.Fortran には DUP というオプションがありデフォルトは TRUE になっている。この場合引数として渡された x(のアドレス)が直接外部ルーティンに渡されず、x の複製が作成され、そのアドレスが外部ルーティンに渡される。その複製されたアドレスに 1 がセットされ、返り値リストに紐付けされる。

次に DUP = FALSE で .Fortran を呼ぶと

> x <- 0
> result <- .Fortran("set_one", x, DUP = FALSE)
> x
[1] 1
> result[[1]]
[1] 1

x 自体も 1 に書き変わっているのがわかる。

余談であるが、私の理解が正しければ、x も result[[1]] も同じアドレスを指しているはずである。にもかかわらず

> x <- 2
> result[[1]]
[1] 1

x を 2 にしても、 result[[1]] は 2 にならない。これは x が 2 という新しいオブジェクトを指し示すようになったからだ。昨日定義した "foo" でやってみれば明らか。

> x <- double(10)
> x
 [1] 0 0 0 0 0 0 0 0 0 0
> result <- .Fortran("foo", x, as.integer(10), 1, DUP=FALSE)
> x
 [1] 1 1 1 1 1 1 1 1 1 1
> result
[[1]]
 [1] 1 1 1 1 1 1 1 1 1 1
[[2]]
[1] 10
[[3]]
[1] 1
> x[2] <- 2
> x
 [1] 1 2 1 1 1 1 1 1 1 1
> result[[1]]
 [1] 1 2 1 1 1 1 1 1 1 1

今度は x と result[[1]] が連動しているのがわかる。

0 件のコメント:

コメントを投稿