我有一个R包,它使用了许多Fortran子例程用于递归线性代数计算的嵌套循环(严重依赖于BLAS和LAPACK例程)。作为Fortran的接口,我使用了.Fortran
函数。我刚刚读了乔纳森卡拉汉的博客文章关于使用.Call
而不是.C
在C/c++写的子程序的情况下,它让我认为,它会更好地使用.Call
接口也使用Fortran子程序,通过在C写一个简单的包装器,然后调用Fortran子程序?
如前所述,我的Fortran代码在某种意义上非常简单,我只是使用双精度或整数类型的多维数组。但是我知道我必须在R端写很多检查,以确保一切都不会崩溃,因为我不小心忘记将一些矩阵的存储模式更改为整数或一些矩阵的维数被更改等。
子程序写成F90/95。
如果处理的是大型数据集,. call可能会快得多,因为每次调用函数时都不用复制数据。对于这个问题中描述的情况,将没有这样的优势,因为R 2.15.1发布说明中声明
. c()和. fortran()进行较少的复制:未命名的原始、逻辑、整数、实向量或复杂向量的参数在调用之前不会被复制,并且(命名或未命名)在调用之后也不会被复制。列表不再被复制(它们在C代码中应该是只读的)。
切换到。call意味着你放弃了。fortran接口的便利性。您将把sexp传递到C代码中,使用(可怕且没有良好文档的)R API对数据进行任何检查/操作,然后从C中调用Fortran函数。任何使用您的代码的人都必须了解R API和C/Fortran互操作。
R包dotCall64可能是一个有趣的替代方案。它提供.C64()
,这是外部函数接口的增强版本,即.C()
和.Fortran()
。
接口.C64()
可用于连接Fortran和C/c++代码。
- 的用法与
.C()
和.Fortran()
类似 - 提供了一种机制来避免不必要的只读和只写参数的副本
- 支持长向量(大于2^31-1个元素的向量)
- 支持64位整型参数
因此,可以避免不必要的只读参数副本,同时避免将.Call()
接口与C包装器函数结合使用。
- R包dotCall64: https://CRAN.R-project.org/package=dotCall64
- dotCall64描述,示例:https://doi.org/10.1016/j.softx.2018.06.002
- 使用dotCall64使稀疏矩阵代数R包spam与巨大的稀疏矩阵(大于2^31-1非零元素)兼容的示例:https://doi.org/10.1016/j.cageo.2016.11.015
我是dotCall64和spam的作者之一。