假设我们正在使用以列为主的顺序存储数组的语言.还假设我们有一个使用二维数组作为参数的函数,并返回它. 我想知道你是否可以声称,在调用函数时,为了使用逐列操作而不是逐行操作
我想知道你是否可以声称,在调用函数时,为了使用逐列操作而不是逐行操作,转换此数组通常是有利的(或者不是),或者转置否定了逐列操作的好处?
例如,在R中,我有一个名为y的类ts的对象,它具有维数n x p,即我有p次系列的长度为n.
我需要在Fortran中使用y进行一些计算,其中我有两个循环,具有以下类型的结构:
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子例程中的东西2会是这样的
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
方法的选择是否总是取决于维度n和p,或者可以说一种方法在计算速度和/或内存要求方面更好?在我的应用中,n通常远大于p,在大多数情况下为1到10.
更多的评论,买我想要一些代码:在旧学校f77下你基本上会被迫使用第二种方法作为y(1:p,i)
只是指向y(1,i)的指针,其中p值在内存中是连续的.
第一个结构
y(i,1:p)
是一个间隔在内存中的值列表,因此似乎需要将数据的副本传递给子例程.我说这似乎是因为我不知道现代优化编译器如何处理这些事情.在最坏的情况下,我倾向于认为它最好是冲洗,这可能真的很痛.想象一个如此大的数组,你需要页面交换来访问整个向量.
最后,解决这个问题的唯一方法就是自己测试一下
– – – – – 编辑
做了一点测试并确认了我的预感:传递行y(i,1:p)确实花费你和传递列y(1:p,i).我使用的子程序几乎没有什么可以看出差异.我对任何真正的子程序的猜测都是可以忽略不计的.
顺便说一句(也许这有助于理解发生了什么)在列中传递其他所有值
y(1:p:2,i)比通过整列需要更长(数量级),而连续传递每隔一个值会将时间减少一半而不是通过整行.
(使用gfortran 12 ..)