如何在调用C例程之前有效地转换Fortran数组

时间:2013-07-05 20:35:05

标签: algorithm fortran fortran-iso-c-binding

假设我有以下Fortran子例程:

subroutine f_test(n,x,value)

    use iso_c_binding

    implicit none

    integer,      intent(in)  :: n
    real(kind=8), intent(in)  :: x(n)
    real(kind=8), intent(out) :: value

    integer(kind=c_int) :: n_
    real(kind=c_double) :: value_,x_(n)

    n_     = transfer( n, n_ )
    x(1:n) = transfer( x(1:n), x_(1:n) )

    call c_test(n_,x_,value_)

    value = transfer( value_, value )

end subroutine f_test

并且还假设c_test是指向C例程的指针,该例程对向量x起作用并在value变量中返回结果。

这很有效,但我有一个问题:

向量x的转换会极大地影响调用子例程f_test的算法的复杂性。我的意思是,如果这样的算法调用f_test n次,算法的复杂性将是二次的,但如果没有这种转换,它将只是线性的。因此,以这种方式进行的转换是不切实际的。有没有合理的方法来解决这个问题?

2 个答案:

答案 0 :(得分:3)

Fortran内在transfer不转换数字类型,它只是复制位,绕过类型。没有转换。如果integerinteger (c_int)应为不同类型,或real (kind=8)real (c_double)种不同类型,则必须进行转换,但转移不会进行转换。赋值语句或内部函数(如intreal)可能会影响转换。

我假设您使用real (kind=8)来表示8字节的实数。无法保证8的种类值对应于该类型。这已在Stackoverflow上多次讨论过,例如Fortran: integer*4 vs integer(4) vs integer(kind=4)

没有限定条件的integer类型和integer (c_int)可能相同,在这种情况下,无需转换。与其他类似...在这种情况下,编译器可能会接受call c_test(n,x,value),认识到类型是相同的,因为类型的数值是相同的,即使使用了不同的符号。为了更加可移植,您可以为输入参数设置intreal内部函数,并使用输出的赋值:

call c_test ( int (n, c_int), real (x, c_double), value_)
value = value_

如果您想确保不进行转换,可以在整个Fortran代码中使用integer (c_int)real (c_double)等。这也可以为您提供一种指定8字节实数的可移植方式。 (也可以使用ISO_FORTRAN_ENV来完成。)

答案 1 :(得分:3)

为什么使用转帐?如果C例程可以直接使用x的内部表示,那么只需将其传递给x。如果您要从kind 8转换为kind c_double,那么只需使用赋值。

C例程是否修改x或n(它是否按值取值?)?假设没有,并假设转移的使用不是出于其他一些未说明的原因 - 在许多平台上,C_double的值是8,默认的整数种类是c_int的值。捷径是值得的。

if (kind(x) == c_double .and. kind(n) == c_int) then
  call c_test(n, x, value)
else
  n_ = n
  x_ = x
  call c_test(n_, x_, value_)
  value = value_
end if