在 R 中使用 Fortran 子例程?未定义的符号

Use Fortran subroutine in R? Undefined symbol

这是跟进 。我将我的 Fortran 代码包装在一个模块中,现在它在我 运行:

时编译
R CMD SHLIB ./Fortran/Fpi.f90

这是我的 Fortran 代码:

Module Fpi 
IMPLICIT NONE
contains 
    subroutine pi(avepi, DARTS, ROUNDS)
    double precision, intent(out)   ::  avepi
    integer, intent(in)             ::  DARTS, ROUNDS
    integer                         ::  MASTER, rank, i, n
    integer, allocatable            ::  seed(:)
    double precision                ::  pi_est, homepi, pirecv, pisum, dboard

    ! we set it to zero in the sequential run
    rank = 0
    ! initialize the random number generator
    ! we make sure the seed is different for each task
    call random_seed()
    call random_seed(size = n)
    allocate(seed(n))
    seed = 12 + rank*11
    call random_seed(put=seed(1:n))
    deallocate(seed)

    avepi = 0
    do i = 0, ROUNDS-1
      pi_est = dboard(DARTS)
      ! calculate the average value of pi over all iterations
      avepi = ((avepi*i) + pi_est)/(i + 1)
    end do
    end subroutine pi


    double precision function dboard(darts)
    integer, intent(in)           :: darts
    double precision              :: x_coord, y_coord
    integer                       :: score, n

    score = 0
    do n = 1, darts
      call random_number(x_coord)
      call random_number(y_coord)

      if ((x_coord**2 + y_coord**2) <= 1.0d0) then
      score = score + 1
      end if
    end do
    dboard = 4.0d0*score/darts

    end function


end module Fpi 

我正在尝试 运行 在 R:

mypi <- function(DARTS, ROUNDS) {
  dyn.load("./Fortran/Fpi.so")
  retvals <- .Fortran("pi", DARTS = as.integer(DARTS) , ROUNDS = as.integer(ROUNDS), avepi = as.numeric(1))
  return(retvals$avepi)
}

mypi(DARTS = 50000, ROUNDS = 10)

我得到这个错误:

Error in dyn.load("./Fortran/Fpi.so") : 
  unable to load shared object '/home/ignacio/local/projects/PI/./Fortran/Fpi.so':
  /home/ignacio/local/projects/PI/./Fortran/Fpi.so: undefined symbol: dboard_

尝试修复 R 函数中 fortran 调用的名称。您在应该是 "Fpi" 的地方输入了 "pi"。另外,为什么不把函数带到你的路径中,而不是在函数内部传递一条长路径呢?

mypi <- function(DARTS, ROUNDS) {
  dyn.load("./Fortran/Fpi.so")
  retvals <- .Fortran("Fpi", DARTS = as.integer(DARTS) , ROUNDS = as.integer(ROUNDS), answer = as.numeric(1))
  return(retvals$answer)
}

mypi(DARTS = 50000, ROUNDS = 10)

显然我无法将子例程包装在模块中。此 Fortran 代码正在运行:

subroutine dboard(darts, dartsscore)
  implicit none
  integer, intent(in)           :: darts
  double precision, intent(out) :: dartsscore
  double precision              :: x_coord, y_coord
  integer                       :: score, n

score = 0
do n = 1, darts
  call random_number(x_coord)
  call random_number(y_coord)

  if ((x_coord**2 + y_coord**2) <= 1.0d0) then
  score = score + 1
  end if
end do

dartsscore = 4.0d0*score/darts

end subroutine dboard

subroutine pi(avepi, DARTS, ROUNDS)
  implicit none
  double precision, intent(out)   ::  avepi
  integer, intent(in)             ::  DARTS, ROUNDS
  integer                         ::  MASTER, rank, i, n
  integer, allocatable            ::  seed(:)
  double precision                ::  pi_est, homepi, pirecv, pisum

interface 
   subroutine dboard(darts, dartsscore)
      implicit none
      integer, intent(in)           :: darts
      double precision, intent(out) :: dartsscore
   end subroutine dboard
end interface

! we set it to zero in the sequential run
rank = 0
! initialize the random number generator
! we make sure the seed is different for each task
call random_seed()
call random_seed(size = n)
allocate(seed(n))
seed = 12 + rank*11
call random_seed(put=seed(1:n))
deallocate(seed)

avepi = 0
do i = 0, ROUNDS-1
  call dboard(darts, pi_est)
  ! calculate the average value of pi over all iterations
  avepi = ((avepi*i) + pi_est)/(i + 1)
end do
end subroutine pi    

这是 R 代码:

system("R CMD SHLIB ./Fortran/Fpi.f90")

mypi <- function(DARTS, ROUNDS) {
  dyn.load("./Fortran/Fpi.so")
  retvals <- .Fortran("pi", avepi = as.numeric(1), DARTS =  as.integer(DARTS), ROUNDS =  as.integer(ROUNDS))
  return(retvals$avepi)
}

mypi(DARTS = 50000, ROUNDS = 10)

您的问题归结为 dboard:

的声明
   double precision                ::  pi_est, homepi, pirecv, pisum, dboard

在这里你说 dboard 是一个 外部 函数,而不是模块过程。这就解释了为什么符号 dboard_ 起作用了。你想删除那个:

double precision                ::  pi_est, homepi, pirecv, pisum

而是在 pi 中依赖于 dboard 的模块过程性:pi 在没有这个声明的情况下已经知道它。

现在,除此之外,因为 pi 在一个模块中,所以该子例程本身将进行一些名称修改。我会通过使 pi 本身成为一个 (C) 可互操作的过程来解决这个问题。

Module Fpi 
  IMPLICIT NONE
contains 
  subroutine pi(avepi, DARTS, ROUNDS) bind(C)
    use, intrinsic :: iso_c_binding, only : c_double, c_int
    real(c_double), intent(out)   ::  avepi
    integer(c_int), intent(in)    ::  DARTS, ROUNDS
    ...

然后使用 .C 而不是 .Fortran

您可以在模块中保留 pidboard,后者甚至不需要互操作。