我需要在代码的不同部分对变量执行单精度和双精度算术。基本上,我首先将变量声明为单精度。然后我调用子例程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
的内存地址,并且它们预计会有所不同。
我的问题是:
A
中的sub_a
版本是否在堆内存中分配,所以我不应该担心大小限制?非常感谢
更新 当使用gfortran4.6 / ifort13.1作为编译器时,我还没有遇到过非常大的数组的内存问题。 我计划使用@innoSPG的建议作为替代方法。
答案 0 :(得分:1)
根据调用的性质,您在sub_a中拥有的A版本是由编译器包含的一段代码创建的临时数组。但是,如果你将操作非常大的数组,那不是一个好主意。
对于问题2.据我所知,没有错误。唯一的问题是临时阵列,如果您的系统上有大型阵列和有限内存,则可能会出现问题。
对于问题3.如果存在内存问题,可以编写sub_a以接受简单的精度,然后在计算中使用它之前转换sub_a中的每个元素。
答案 1 :(得分:0)
调用站点上的临时数组可以在堆栈或堆中进行,它取决于实现。编译器通常有控制行为的选项。
使用英特尔Fortran时,选项-heap-arrays n
(n
不能被忽略或太低,因为性能会很糟糕。)
-fstack-arrays
来获得更好的性能(它包含在-Ofast
中)。
您可以在其他编译器的文档中找到类似的选项。
我不会不惜一切代价担心和避免使用临时阵列。更短(更可读!)代码的可能性有时更重要。许多代码具有在初始化或最终输出期间仅执行一次的部分,其中性能损失通常是无关紧要的。我个人用它来使我的代码在这些部分更清晰(不在计算核心中)。