5

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

例如,在 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

由于 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

我可以使用

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)

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

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

4

1 回答 1

3

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

y(1:p,i)

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

第一个构造

y(i,1:p)

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

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

----------edit 做了一些测试并证实了我的预感:传递行y(i,1:p)确实会花费你而不是传递列y(1:p,i)。我使用了一个几乎没有任何区别的子程序。我对任何真正的子程序的猜测都是可以忽略不计的。

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

y(1:p:2,i)比传递整列花费更长的时间(数量级),而传递一行中的每个其他值将时间减少一半,而不是传递整行。

(使用 gfortran 12 ..)

于 2013-03-02T14:49:08.357 回答