没有临时数组的Fortran求和(..)的计算?

没有临时数组的Fortran求和(..)的计算?,fortran,Fortran,就可读性而言,我觉得最好是写 momentum = sum( [( calculateMomentum(elements(i)), i=1, size(elements,1) )] ) 结束 因为第一个版本具有定义动量值的形式,而第二个版本对应于更低级别的累加指令。在具有更多参数和可能的多个索引的实际代码中,这种差异变得更加明显 但是,第一个版本分配了一个临时数组。作为一名人类程序员,我知道它可以优化,所以我想知道Fortran是否提供了一种语法,既不允许使用显式循环也不允许使用临时数组来计算

就可读性而言,我觉得最好是写

momentum = sum( [( calculateMomentum(elements(i)), i=1, size(elements,1) )] )
结束

因为第一个版本具有定义动量值的形式,而第二个版本对应于更低级别的累加指令。在具有更多参数和可能的多个索引的实际代码中,这种差异变得更加明显

但是,第一个版本分配了一个临时数组。作为一名人类程序员,我知道它可以优化,所以我想知道Fortran是否提供了一种语法,既不允许使用显式循环也不允许使用临时数组来计算和

使现代化 没有这样的构想。看起来好像没有语法,正如我所要求的那样。看

这很重要,但比我想象的要少。我已经做了自己的基准测试,使用了几个变量的矩阵乘法

Ci,j=Ci,j+Ai,k*Bk,j是最慢的,可能是因为每个步骤中都有不必要的数组访问

Ci,j=sum[Ai,k*Bk,j,k=1,N]`比1快10-20%,尽管使用了临时数组

tmp=tmp+Ai,k*Bk,j,即使用临时累加器变量,比2快约20%

C=matmulA,B是迄今为止最快的,相比之下,500x500矩阵的速度是3的25倍,2000x2000矩阵的速度增长到50倍,而其他变体的相对速度大致保持不变


一句话:当任务不能很容易地用优化的库函数或内在函数表示时,sum变量具有可行的性能,只应进行优化,如果在代码的这一部分中,性能真的如此重要。

是分配临时数组还是net取决于编译器中的优化。堆栈分配几乎是免费的。复制这些值可能需要更长的时间


如果编译器能够确保结果相同,那么它可能会优化不必要的步骤。但是,没有专门的语法。Fortran通常试图远离实际实现,并将大量工作留给编译器。

是否分配临时数组或net取决于编译器中的优化。堆栈分配几乎是免费的。复制这些值可能需要更长的时间


如果编译器能够确保结果相同,那么它可能会优化不必要的步骤。但是,没有专门的语法。Fortran通常会尽量远离实际实现,并在编译器上留下大量工作。

为了进行实验,我尝试了这段代码,它计算arr的逆和

然后,在我的电脑mac2012上,gfortran-10-O2 test.f90&&time./a.out给出

 val =    18.997896413852555       in    1.02999997      (s)
 val =    18.997896413852555       in    1.10099995      (s)
 val =    18.997896413852555       in    1.17600000      (s)
 ...

real    0m12.575s
user    0m8.142s
sys 0m4.387s
gfortran-10-O3给出

 val =    18.997896413852555       in   0.875000000      (s)
 val =    18.997896413852555       in   0.888000011      (s)
 val =    18.997896413852555       in   0.833000004      (s)
 ...

real    0m9.986s
user    0m5.738s
sys 0m4.210s
 val =    18.997896413852555       in   0.225999996      (s)
 val =    18.997896413852555       in   0.252000004      (s)
 val =    18.997896413852555       in   0.246999994      (s)
 ...
real    0m3.909s
user    0m3.009s
sys 0m0.867s
在这两种情况下,htop命令显示分配了约1.5 GB,如果L1和L2行使用每个约800 MB、约0.3秒的临时数组进行分配,这可能是合理的


因为没有用于创建迭代器的语法,所以我尝试将testfunc设置为元素或不纯净元素。这里唯一的区别是标有的行。为了进行实验,我尝试了这段代码,它计算了arr的逆和

然后,在我的电脑mac2012上,gfortran-10-O2 test.f90&&time./a.out给出

 val =    18.997896413852555       in    1.02999997      (s)
 val =    18.997896413852555       in    1.10099995      (s)
 val =    18.997896413852555       in    1.17600000      (s)
 ...

real    0m12.575s
user    0m8.142s
sys 0m4.387s
gfortran-10-O3给出

 val =    18.997896413852555       in   0.875000000      (s)
 val =    18.997896413852555       in   0.888000011      (s)
 val =    18.997896413852555       in   0.833000004      (s)
 ...

real    0m9.986s
user    0m5.738s
sys 0m4.210s
 val =    18.997896413852555       in   0.225999996      (s)
 val =    18.997896413852555       in   0.252000004      (s)
 val =    18.997896413852555       in   0.246999994      (s)
 ...
real    0m3.909s
user    0m3.009s
sys 0m0.867s
在这两种情况下,htop命令显示分配了约1.5 GB,如果L1和L2行使用每个约800 MB、约0.3秒的临时数组进行分配,这可能是合理的

因为没有用于创建迭代器的语法,所以我尝试将testfunc设置为元素或不纯净元素。这里唯一的区别是标有的行如果使用CalculateMontum和elemental函数,那么它可以用于标量值和数组

例如:

    elemental function calculateMomentum(obj, v) result(p)
    class(body), intent(in) :: obj
    real, intent(in) :: v
    real :: p
        p = obj%mass * v
    end function
您可以将上述内容应用于v的数组

有一个中间数组来保存这些值是有利的,因为它将数据保持在缓存线附近,并且sum函数将尽可能快

例如,假设类型主体如下所示

    type body
        real :: mass
    end type
如果使用CalculateMontum和elemental函数,则它可以用于标量值和数组

例如:

    elemental function calculateMomentum(obj, v) result(p)
    class(body), intent(in) :: obj
    real, intent(in) :: v
    real :: p
        p = obj%mass * v
    end function
您可以将上述内容应用于v的数组

有一个中间数组来保存这些值是有利的,因为它将数据保持在缓存线附近,并且sum函数将尽可能快

例如,假设类型主体如下所示

    type body
        real :: mass
    end type

语句中有一个数组构造函数,但这是可以避免的。在Python中,sum[fx for x in xs]和sumfx for x in xs。第一个版本创建了一个不必要的列表,就像Fortran创建了一个不必要的数组一样。我希望以某种方式确保,内在可能会做一些更类似于r=0的事情;Doi=1,Sizex;r=r+fxsi;在保持更具声明性的代码样式时结束do。@kdb Fortran中没有类似的东西。没有迭代器,没有闭包,没有延迟计算。从技术上讲,Fortran没有

创建一个不必要的数组。创建临时数组的是您正在使用的编译器。此外,您可以查看中间转储,而不是猜测gfortran在做什么。Try-fdump tree original和-fdump tree optimized尾部d可能不正确。最后,不要试图变得聪明,而是按照你想要的方式编写代码,即r=0,do i=1,sizexs;r=r+fxsi;终止do@evets也许您想将此问题解决到kdb?语句中有一个数组构造函数,但这是可以避免的。在Python中,sum[fx for x in xs]和sumfx for x in xs。第一个版本创建了一个不必要的列表,就像Fortran创建了一个不必要的数组一样。我希望以某种方式确保,内在可能会做一些更类似于r=0的事情;Doi=1,Sizex;r=r+fxsi;在保持更具声明性的代码样式时结束do。@kdb Fortran中没有类似的东西。没有迭代器,没有闭包,没有延迟计算。从技术上讲,Fortran不会创建不必要的数组。创建临时数组的是您正在使用的编译器。此外,您可以查看中间转储,而不是猜测gfortran在做什么。Try-fdump tree original和-fdump tree optimized尾部d可能不正确。最后,不要试图变得聪明,而是按照你想要的方式编写代码,即r=0,do i=1,sizexs;r=r+fxsi;终止do@evets也许你想把这个问题解决给kdb?那么答案是什么?也许标准中没有迭代器…?那么为什么你不把我放在你的答案中呢?也许我只是在抱怨,人们对你的答案投了赞成票,对我的答案投了反对票,但在我看来,答案应该首先,也是最重要的答案。然后展示有关性能的测试实验。也许我只是个脾气暴躁的od。@VladimirF嗨,我只是认为你的第一个答案已经给出了标准中严格的答案,我认为应该被接受cc:@kdd,所以我从不同的角度添加了一些实验,因为OP似乎也对相关代码感兴趣。不管怎样,我觉得元素是一个非常有用的特性。好吧,我认为在一个新的答案中说出要点总是好的,即使它以前已经说过了。那么答案是什么呢?也许标准中没有迭代器…?那么你为什么不把我放在你的答案中呢?也许我只是在抱怨,人们对你的答案投了赞成票,对我的答案投了反对票,但在我看来,答案应该首先,也是最重要的答案。然后展示有关性能的测试实验。也许我只是个脾气暴躁的od。@VladimirF嗨,我只是认为你的第一个答案已经给出了标准中严格的答案,我认为应该被接受cc:@kdd,所以我从不同的角度添加了一些实验,因为OP似乎也对相关代码感兴趣。不管怎样,我觉得元素是一个非常有用的特性。好吧,我认为在一个新的答案中说出要点总是好的,即使它以前已经说过了。
    type body
        real :: mass
    end type