使用real(A [,kind =])将单精度数组作为双精度传递给Fortran 90/2003中的子程序

时间:2014-04-01 22:15:23

标签: arrays fortran90 heap-memory floating-point-precision

我需要在代码的不同部分对变量执行单精度和双精度算术。基本上,我首先将变量声明为单精度。然后我调用子例程sub_a,它使用变量的双精度版本并对其执行双精度运算:

program main

 implicit none
 integer,parameter :: single = selected_real_kind(p=6,r=37)
 integer,parameter :: double = selected_real_kind(p=15,r=307)

 real(single),allocatable,dimension(:) :: A
 real(double),allocatable,dimension(:) :: B

 allocate(A(3),B(3))
 A=2 ! single precision
 A=A+3 ! single precision

 print '(a,1x,3(f20.15))','sqrt(A),single:',sqrt(A)
 print '(a,1x,I15)','mem_address of A before sub_a:',loc(A)

 call sub_a(real(A,kind=double),B) ! double precision
 print '(a,1x,3(f20.15))','sqrt(A),double:',B

 contains
   subroutine sub_a(a,b)
     real(double),dimension(:),intent(in) :: a
     real(double),dimension(:),intent(inout) :: b

     print '(a,1x,I15)','mem_address of A in sub_a:',loc(a)

     b=sqrt(a)

   end subroutine sub_a

end program main

如代码中所示,我在调用A之前获得了sub_a的内存地址,在A内获得了sub_a的内存地址,并且它们预计会有所不同。

我的问题是:

  1. A中的sub_a版本是否在堆内存中分配,所以我不应该担心大小限制?
  2. 写这个例子有没有潜在的问题/错误?
  3. 是否有更好的方法来捕获此示例中描述的目的,特别是对于较大尺寸的数组?
  4. 非常感谢

    更新 当使用gfortran4.6 / ifort13.1作为编译器时,我还没有遇到过非常大的数组的内存问题。 我计划使用@innoSPG的建议作为替代方法。

2 个答案:

答案 0 :(得分:1)

根据调用的性质,您在sub_a中拥有的A版本是由编译器包含的一段代码创建的临时数组。但是,如果你将操作非常大的数组,那不是一个好主意。

对于问题2.据我所知,没有错误。唯一的问题是临时阵列,如果您的系统上有大型阵列和有限内存,则可能会出现问题。

对于问题3.如果存在内存问题,可以编写sub_a以接受简单的精度,然后在计算中使用它之前转换sub_a中的每个元素。

答案 1 :(得分:0)

调用站点上的临时数组可以在堆栈或堆中进行,它取决于实现。编译器通常有控制行为的选项。

使用英特尔Fortran时,选项-heap-arrays nn不能被忽略或太低,因为性能会很糟糕。)

如果事先不知道大小,Gfortran会自动将它们放在堆上。最好使用-fstack-arrays来获得更好的性能(它包含在-Ofast中)。

您可以在其他编译器的文档中找到类似的选项。

我不会不惜一切代价担心和避免使用临时阵列。更短(更可读!)代码的可能性有时更重要。许多代码具有在初始化或最终输出期间仅执行一次的部分,其中性能损失通常是无关紧要的。我个人用它来使我的代码在这些部分更清晰(不在计算核心中)。