6

我在运行时收到以下警告:

...
forrtl: warning (402): fort: (1): In call to I/O Write routine, an array temporary was created for argument #2

forrtl: warning (402): fort: (1): In call to I/O Write routine, an array temporary was created for argument #3

forrtl: warning (402): fort: (1): In call to GERADHEIT_LINIAL, an array temporary was created for argument #2

forrtl: warning (402): fort: (1): In call to GERADHEIT_LINIAL, an array temporary was created for argument #3
...   

对于子例程/写语句的每次调用。

子程序的调用:

integer :: l,kreise
character(*)::setname
real(8),diemnsion(:,:,:),allocatable::stripe
integer,dimension(:)s(j)

...code and allocation of arrays...
 do j=n(1)
   call geradheit_linial (s(j),stripe(j,1:s(j),1),
&                       stripe(j,1:s(j),2),setname)
 end do

...

subroutine geradheit_linial (ndaten,x,r,setname)
  implicit none
  integer,intent(in) :: ndaten
  real(8),dimension(ndaten),intent(in)  :: x,r
  character(*),intent(in) :: setname   

和写声明:

    write(91,*)'Gerade: ',gerade(maxloc(reslt(1:i)),minsumloc,1),
&               gerade(maxloc(reslt(1:i)),minsumloc,2)

数组stripe分配有每个维度预期的最大值,因此大多数时候只有一个子集通过调用。

据我了解,就准确性而言,这并不是真正的问题,但可能会减慢程序的速度,因此完成了对 RAM 的大量写入。那么它会减慢我的计算速度(stripe可能有大约的维度stripe(100,300,3)并且可能在以后的某个时间变大)?我怎样才能避免这样的额外数组?

4

1 回答 1

7

我认为您收到此警告是因为子例程正在传递非连续数组部分,并且编译器已决定子例程应该获取包含必要值的连续临时数组。我希望子例程代码是以数组的形式编写的,并隐含地假设,就像我们在 Fortran 中编程时所做的那样,它是连续的。

如果我正确阅读了您的代码,则编译器会理解此语句

stripe(j,1:s(j),1)

意思是(好像是)

stripe(j,1,1)
stripe(j,2,1)
stripe(j,3,1)
...

因为,正如我希望您知道的那样,Fortran 数组存储时第一个索引值变化最快,因此您的数组部分跨越内存。

您可以使用编译器选项抑制警告noarg_temp_created。请注意,这只会抑制警告(我想这可能会节省程序运行时间的一小部分),它不会影响编译器的工作,仍然会创建临时数组。

您可以编写代码来创建包含要传递给子例程的部分的临时数组。我认为这样做没有多大优势。我希望编译器发出的代码优于您为如此简单的操作编写的任何代码。

或者,您可以在开始调用子例程之前对原始数组进行一次整形/置换,并为其提供正确的形状和排列以将其切成连续的块。然后在所有通话结束时取消排列/重塑。

回答您有关当前代码的相对性能和任何替代公式的问题的唯一决定性方法是将它们编码并拿出您的秒表。

于 2013-08-13T09:01:25.363 回答