1

假设我有以下 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时间,算法的复杂度将是二次的,但如果没有这种转换,它将只是线性的。因此,以这种方式进行的这种转换是不切实际的。有什么合理的方法可以解决这个问题吗?

4

2 回答 2

3

Fortran 内在函数transfer不转换数字类型,它只是复制位,绕过类型。没有发生转换。如果integer并且integer (c_int)应该是不同的类型,或者real (kind=8)real (c_double)不同的类型,则需要进行转换,但不会通过传输来完成。赋值语句或内在函数,例如intreal可能影响转换。

我假设您使用real (kind=8)的意思是 8 字节实数。无法保证 kind 值 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 来完成。)

于 2013-07-05T21:20:59.290 回答
3

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

C 例程是否修改 x 或 n(是否按值取 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
于 2013-07-05T21:23:28.897 回答