在 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
。
您可以在模块中保留 pi
和 dboard
,后者甚至不需要互操作。
这是跟进
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
。
您可以在模块中保留 pi
和 dboard
,后者甚至不需要互操作。