R& Fortran调用 [英] R & Fortran call

查看:153
本文介绍了R& Fortran调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



任何帮助都将非常感谢! Best,



Vincent



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



$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $' )
整数i
x(1)= 1
do 100 i = 2,n
x(i)= x(i-1)* g + 1
100继续使用gfortran编译Cygwin中的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 )))


解决方案

当我编译你的代码时,我可以对 .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))

整数字符是返回像 double 的向量的有用函数。



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


  • 可能b明智地用 .f90 扩展名命名文件 - 以 .f 结尾的文件被大多数编译器坚持原来设计用于打卡的PITA旧的固定格式格式。

  • 100 ... 100 continue 语句是Fortran 77中结束循环的一种风格。现代等价物是 Do .. end do
  • 使用Fortran函数和子例程明智地声明变量传入和传出例程的意图。可用的意图声明为:


    • intent(in):表示仅作为输入进入例程的变量。一旦进入例程,它们应该被视为参数,如果有人试图改变它们,编译器会产生错误。

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


    • intent(inout):表示可能进入例程的变量携带一组特定的值,并将该例程保留为不同的值。




    在变量上设置意图可以帮助编译器生成警告和错误,从而为您节省一些bug。

  • Fortran具有默认行为,其中任何变量未声明在例程的头文件中,如果它的名字以in开头,则为整数,否则为真。这可能会导致拼写错误的变量名称神奇地变成变量,而编译器不会打扰或告诉您。在例程顶部设置 implicit none 可以禁止这种行为,并允许编译器通知您可能很难追查的错误。




考虑到这些建议的子程序版本如下所示:

 子程序bar(n,g,x)
隐式无

整数,意图(in):: n
双精度,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

结束子程序bar

另外,让R使用 SHLIB 子命令 R CMD

  R CMD SHLIB -o bar。 dll bar.f90 

这会针对包含有用函数的R库编译您的程序 - 例如作为BLAS r外观,统计例程和可以将信息打印到R控制台的方法。请参阅编写R扩展,第6部分了解更多信息。



希望这有助于您!


I don't have experience with Fortran, but I am trying to run a very simple loop in that language by calling it from R via the .Fortran() function. Whenever I run the last line of the R code that is pasted below, the R gui crashes and I get no result. I am interest in bringing back the vector of real values x from Fortran into R for further analysis. g is a numeric value between 0 and 1, and n an integer, and they are both supplied by the user in R.

Any help would be much appreciated! Best,

Vincent

Fortran code saved in bar.f:

    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

Compiling the DLL in Cygwin with gfortran:

gfortran -shared -obar.dll bar.f

R code:

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

解决方案

When I compile your code, I can execute the call to .Fortran once. When I run it a second time, it crashes. However, I noticed that if I make the vector passed for x the same length as the integer passed for n suggests it should be, i.e:

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

I can run the function as many times as I want. So the problem may be that you are telling the Fortran routine it has a vector of length 15 to work with, but are only sending in a vector of length 5. This could be causing the Fortran routine to access memory it is not supposed to which would explain a crash.

Since it looks like you are generating all values of x in the routine anyway, you could skip generating random numbers and just send in an empty vector using R's double(n) function, where n is the length of the empty vector you want to generate:

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

integer and character are useful functions that return vectors like double.

Also some friendly suggestions concerning Fortran style since you mention you are just getting started with the language:

  • It might be wise to name your files with a .f90 extension---files ending in .f are assumed by most compilers to adhere to the old "fixed-form" format which is a PITA as it was designed to be used on punch cards.

  • The Do 100 ... 100 continue statements are an style of ending loops in Fortran 77. The modern equivalent is Do .. end do.

  • With Fortran functions and subroutines, it is wise to declare the "intent" of variables passing in and out of the routine. The available intent declarations are:

    • intent(in): Signifies variables that are entering the routine only as inputs. Once inside the routine, they should be treated as parameters and the compiler will raise an error if any attempt is made to change them.

    • intent(out): Signifies variables whose values should be generated inside the routine as outputs. The compiler will issue a warning if an intent out variable is not assigned within the routine.

    • intent(inout): Signifies variables that may enter the routine carrying a certain set of values and leave the routine with different values.

    Setting intents on variables will help the compiler generate warnings and errors that may save you some bug hunting.

  • Fortran has a default behavior where any variable not declared in the header of the routine will be an integer if its name starts with i-n and real otherwise. This can cause misspelled variable names to "magically" become variables without the compiler batting an eye or telling you. Setting implicit none at the top of your routines disables this behavior and allows the compiler to notify you of mistakes that can be very hard to track down otherwise.

A version of your subroutine that takes these suggestions into account would look like the following:

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

Also, it is useful to let R compile your libraries using the SHLIB subcommand of R CMD:

R CMD SHLIB -o bar.dll bar.f90

This will compile your programs against the R libraries which contain useful functions---such as BLAS routines, stats routines and methods that can print information to the R console. See Writing R Extensions, Section 6 for more info.

Hope this helps!

这篇关于R& Fortran调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆