转置数组以使用按列运算是否有益?

Jou*_*ske 5 performance fortran transpose r multidimensional-array

假设我们正在使用一种按列优先顺序存储数组的语言。还假设我们有一个使用二维数组作为参数并返回它的函数。我想知道您是否可以声称在调用函数时转置此数组通常是有益的(或不是),以便使用按列操作而不是按行操作,或者转置是否会否定逐列运算的好处?

作为一个例子,在 RI 中有一个名为 ts 类的对象,y其维度为n x p,即我有p长度为 的时间序列n

我需要y在 Fortran 中进行一些计算,其中有两个具有以下结构的循环:

do i = 1, n
  do j= 1, p
   !just an example, some row-wise operations  on `y`
   x(i,j) = a*y(i,j) 
   D = ddot(m,y(i,1:p),1,b,1) 
   ! ...
  end do
end do
Run Code Online (Sandbox Code Playgroud)

由于 Fortran(和 R 一样)使用按列存储,因此最好使用p x n数组进行计算。所以而不是

out<-.Fortran("something",y=array(y,dim(y)),x=array(0,dim(y)))
ynew<-out$out$y
x<-out$out$x
Run Code Online (Sandbox Code Playgroud)

我可以用

out<-.Fortran("something2",y=t(array(y,dim(y))),x=array(0,dim(y)[2:1]))
ynew<-t(out$out$y)
x<-t(out$out$x)
Run Code Online (Sandbox Code Playgroud)

其中 Fortran 子例程something2类似于

do i = 1, n
  do j= 1, p
   !just an example, some column-wise operations  on `y`
   x(j,i) = a*y(j,i) 
   D = ddot(m,y(1:p,i),1,b,1) 
   ! ...
  end do
end do
Run Code Online (Sandbox Code Playgroud)

方法的选择是否始终取决于维度np或者是否可以说一种方法在计算速度和/或内存要求方面更好?在我的应用程序中,n通常远大于p,在大多数情况下为 1 到 10。

age*_*ntp 3

更多评论,购买我想添加一些代码:在老式 f77 下,您基本上被迫使用第二种方法,因为

y(1:p,i)
Run Code Online (Sandbox Code Playgroud)

只是一个指向 y(1,i) 的指针,其中以下 p 值在内存中是连续的。

第一个构造

y(i,1:p)
Run Code Online (Sandbox Code Playgroud)

是内存中间隔的值列表,因此似乎需要复制数据以传递给子例程。我这么说似乎是因为我对现代优化编译器如何处理这些事情一无所知。我倾向于认为,最好的情况是洗一次,最坏的情况是这可能真的很疼。想象一下一个数组如此之大,您需要进行页面交换才能访问整个向量。

最后回答这个问题的唯一方法就是亲自测试一下

----------编辑做了一些测试并证实了我的预感:传递行y(i,1:p)确实会花费你与传递列相比y(1:p,i)。我使用了一个几乎不执行任何操作的子例程来查看差异。我猜对于任何真正的子程序来说,命中都是可以忽略不计的。

顺便说一句(也许这有助于理解发生了什么)传递列中的每个其他值

y(1:p:2,i)比传递整列需要更长的时间(数量级),而传递一行中的所有其他值与传递整行相比,时间会缩短一半。

(使用 gfortran 12..)