Optimization fortran 90(gfortran)是否优化了数组语法?

Optimization fortran 90(gfortran)是否优化了数组语法?,optimization,gfortran,Optimization,Gfortran,我在基于数组的解释语言方面做了很多工作,但我正在研究Fortran。在编写了第一段代码之后,我刚刚想到的问题是gfortran是否会通过将表达式放在单个循环中来使用数组语法优化表达式。在大多数基于数组的解释器中,诸如A=B/n*2*pi(其中B是数组)之类的表达式将需要5个循环和多个数组临时变量来计算。gfortran是否足够聪明,可以对此进行优化,我下面的代码(计算0到2pi数组的行)是否会像表达式周围的显式do循环一样高效?如果我担心性能,那么在使用数组语法时,有什么需要注意的吗 PROGR

我在基于数组的解释语言方面做了很多工作,但我正在研究Fortran。在编写了第一段代码之后,我刚刚想到的问题是gfortran是否会通过将表达式放在单个循环中来使用数组语法优化表达式。在大多数基于数组的解释器中,诸如A=B/n*2*pi(其中B是数组)之类的表达式将需要5个循环和多个数组临时变量来计算。gfortran是否足够聪明,可以对此进行优化,我下面的代码(计算0到2pi数组的行)是否会像表达式周围的显式do循环一样高效?如果我担心性能,那么在使用数组语法时,有什么需要注意的吗

PROGRAM  Sine
   IMPLICIT  NONE

   REAL, PARAMETER :: PI = 3.415926535
   INTEGER, PARAMETER :: z = 500
   INTEGER :: ier
   INTEGER, EXTERNAL :: PGBEG
   REAL, DIMENSION(z) :: x,y

   x=(indgen(z)-1.0)/z*(2*pi) ! This line...``
   y=sin(x)
   CALL plot(y,x)

   CONTAINS

     FUNCTION indgen(n) result(i)
       INTEGER :: n
       INTEGER, DIMENSION(n) :: i
       INTEGER :: l
       DO l=1,n
          i(l)=l
       END DO
     END FUNCTION indgen

    SUBROUTINE plot(y,x)
       REAL, DIMENSION(:) :: x,y
       ier=PGBEG(0,'/XWINDOW',1,1)
       CALL PGENV(0.0,7.0,-1.0,1.0,0,1)
       CALL PGLINE(SIZE(x),x,y)
       CALL PGEND()
     END SUBROUTINE plot

END PROGRAM Sine
对。 Fortran是编译的,而不是解释的。 它可以很好地处理循环。

是的。 Fortran是编译的,而不是解释的。
它可以很好地处理循环。

在gfortran中,您可以使用
-Warray temporaries
标志查看生成的所有数组temporaries。当我尝试您的示例时,不会生成额外的临时数组(除了存储indgen(z)结果所需的临时数组),因此我猜gfortran足够聪明

在gfortran中,您可以使用
-Warray temporaries
标志查看生成的所有数组temporaries。当我尝试您的示例时,不会生成额外的临时数组(除了存储indgen(z)结果所需的临时数组),因此我猜gfortran足够聪明

表达式
z*(2*pi)
是一个编译时常量,编译器可以很容易地验证它,因此无论如何,都不应该在运行时对其求值。此外,几乎所有现代编译器都应该在单个循环中执行一行“基本”数组操作,并且在许多情况下会生成SIMD指令(自动矢量化)

是否生成临时文件通常取决于每个元素是否可以独立处理,以及编译器是否能够证明这一点。朱晓蕾建议使用
-Warray temporaries
,这是一个很好的建议。不要将它与
-fcheck=array temp
混淆,我认为这只适用于为函数调用生成的临时值

下面是一个来自gfortran的消息示例:

foo.F90:4.12:

foo(1:20) = 2*foo(20:1:-1)
            1
Warning: Creating array temporary at (1)
函数调用将在单独的循环中完成,除非编译器可以内联它。编译器是否内联一个短函数是很难预测的;这可能取决于其他函数的定义位置、函数是否具有
pure
属性(尽管在实践中这似乎很少有关系)、编译器本身的供应商和版本以及传递的选项。一些编译器可以为此生成报告;我记得,英特尔编译器有一个不错的

编辑:也可以使用“隐含do循环”手动将表达式内联到这一行:

表达式
z*(2*pi)
是一个编译时常量,编译器可以很容易地验证它,因此不管如何,都不应该在运行时对其求值。此外,几乎所有现代编译器都应该在单个循环中执行一行“基本”数组操作,并且在许多情况下会生成SIMD指令(自动矢量化)

是否生成临时文件通常取决于每个元素是否可以独立处理,以及编译器是否能够证明这一点。朱晓蕾建议使用
-Warray temporaries
,这是一个很好的建议。不要将它与
-fcheck=array temp
混淆,我认为这只适用于为函数调用生成的临时值

下面是一个来自gfortran的消息示例:

foo.F90:4.12:

foo(1:20) = 2*foo(20:1:-1)
            1
Warning: Creating array temporary at (1)
函数调用将在单独的循环中完成,除非编译器可以内联它。编译器是否内联一个短函数是很难预测的;这可能取决于其他函数的定义位置、函数是否具有
pure
属性(尽管在实践中这似乎很少有关系)、编译器本身的供应商和版本以及传递的选项。一些编译器可以为此生成报告;我记得,英特尔编译器有一个不错的

编辑:也可以使用“隐含do循环”手动将表达式内联到这一行:


谢谢,但这并不能回答我的问题。我不是问编译器是否比解释器更好地处理循环,我是想弄清楚它是否将表达式封装在一个循环中,而不是像在许多解释的数组语言中那样依次执行每个操作。再仔细想想,我猜我的代码至少被编译为2个循环;一个在indgen中,一个(或多个?)来评估表达式的其余部分。谢谢,但这并不能回答我的问题。我不是问编译器是否比解释器更好地处理循环,我是想弄清楚它是否将表达式封装在一个循环中,而不是像在许多解释的数组语言中那样依次执行每个操作。再仔细想想,我猜我的代码至少被编译为2个循环;一个位于indgen内部,一个(或多个?)用于计算表达式的其余部分。