【问题标题】:R & Fortran callR & Fortran 调用
【发布时间】:2011-01-19 04:42:05
【问题描述】:

我没有使用 Fortran 的经验,但我试图通过 .Fortran() 函数从 R 调用它来运行该语言的一个非常简单的循环。每当我运行粘贴在下面的 R 代码的最后一行时,R gui 就会崩溃并且我没有得到任何结果。我有兴趣将实值 x 的向量从 Fortran 带回 R 以进行进一步分析。 g 为 0 到 1 之间的数值,n 为整数,均由 R 中的用户提供。

任何帮助将不胜感激!最好的,

文森特

在 bar.f 中保存的 Fortran 代码:

    subroutine bar(n, g, x)

      integer n
      double precision g
      double precision x(n)
      integer i
      x(1)=1
      do 100 i = 2, n
          x(i) = x(i-1) * g + 1
  100 continue

      end

在 Cygwin 中使用 gfortran 编译 DLL:

gfortran -shared -obar.dll bar.f

R 代码:

dyn.load("d:/bar.dll")
is.loaded("bar")
.Fortran("bar", n=as.integer(15), g=as.double(5), x=as.double(rnorm(5)))

【问题讨论】:

    标签: r fortran


    【解决方案1】:

    当我编译你的代码时,我可以执行一次对.Fortran 的调用。当我第二次运行它时,它崩溃了。但是,我注意到,如果我使为 x 传递的向量与为 n 传递的整数长度相同,则表明它应该是,即:

    .Fortran('bar', n = as.integer(15), g = as.double (5), x = as.double(rnorm(15)) )
    

    我可以根据需要多次运行该函数。所以问题可能是你告诉 Fortran 例程它有一个长度为 15 的向量可以使用,但只发送一个长度为 5 的向量。这可能导致 Fortran 例程访问它不应该访问的内存可以解释崩溃。

    由于看起来您无论如何都在例程中生成x 的所有值,您可以跳过生成随机数并使用R 的double(n) 函数发送一个空向量,其中n 是要生成的空向量:

    .Fortran('bar', n = as.integer(15), g = as.double(5), x = double(15))
    

    integercharacter 是有用的函数,它们返回像 double 这样的向量。

    还有一些关于 Fortran 风格的友好建议,因为您提到您刚刚开始使用该语言:

    • 使用.f90 扩展名命名文件可能是明智的——大多数编译器假定以.f 结尾的文件遵循旧的“固定格式”格式,即PITA它被设计用于打孔卡。

    • Do 100 ... 100 continue 语句是 Fortran 77 中结束循环的一种样式。现代等效为 Do .. end do

    • 对于 Fortran 函数和子例程,明智的做法是声明传入和传出例程的变量的“意图”。可用的意图声明是:

      • intent(in):表示仅作为输入进入例程的变量。一旦进入例程,它们应被视为参数,如果尝试更改它们,编译器将引发错误。

      • intent(out):表示其值应在例程中生成的变量作为输出。如果在例程中未分配意图输出变量,编译器将发出警告。

      • intent(inout):表示可以携带一组值进入例程并以不同值离开例程的变量。

      在变量上设置意图将有助于编译器生成警告和错误,这可能会为您节省一些寻找错误的时间。

    • Fortran 有一个默认行为,其中未在例程头中声明的任何变量如果其名称以 i-n 开头,则为整数,否则为实数。这可能会导致拼写错误的变量名称“神奇地”成为变量,而编译器不会注意到或告诉您。在您的例程顶部设置 implicit none 会禁用此行为,并允许编译器通知您可能很难追踪的错误。

    将这些建议考虑在内的子例程版本如下所示:

    subroutine bar(n, g, x)
      implicit none
    
      integer, intent(in):: n
      double precision, intent(in):: g
      double precision, intent(inout):: x(n)
    
      integer:: i
    
      x(1) = 1
      do i = 2, n
        x(i) = x(i - 1) * g + 1
      end do
    
    end subroutine bar
    

    此外,让 R 使用 R CMDSHLIB 子命令编译您的库很有用:

    R CMD SHLIB -o bar.dll bar.f90
    

    这将针对包含有用功能的 R 库编译您的程序——例如 BLAS 例程、统计例程和可以将信息打印到 R 控制台的方法。请参阅Writing R Extensions, Section 6 了解更多信息。

    希望这会有所帮助!

    【讨论】:

    • 哇,这是一个比我所希望的更好、更完整的解释。感谢您发现问题。现在一切正常!
    • 非常好的答案。但也请查看内联包,因为它有助于编译、链接和加载步骤。
    • 很好的解释! - R 包 dotCall64 中的.C64() 可用作.Fortran() 的更灵活/方便的替代方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-14
    • 1970-01-01
    相关资源
    最近更新 更多