标量到数组的内在赋值

时间:2014-09-09 10:05:55

标签: fortran

从Fortran 2008规范,7.2.1.3.5

  

如果expr是标量且变量是数组,则将expr视为与其形状相同的数组。   变量,数组的每个元素都等于expr的标量值。

我见过以下编码样式:

integer, dimension(3) :: x
do i=1,3
  x(i) = 1
enddo

B:

integer, dimension(3) :: x
x(:) = 1

C:

integer, dimension(3) :: x
x = 1

将标量值分配给数组(性能和可读性)的最佳做法是什么?

注意: A 闻起来像Fortran77,我觉得 C 会让未来的读者感到困惑?

1 个答案:

答案 0 :(得分:2)

简短的答案:

根据我的经验,案例(A)总是优于Fortran数组语法。然后,情况(C)优于情况(B),仅在特殊情况下,编译器必须做一些额外的工作来理解(:)的含义,否则这两个符号通常是相同的。但是,到目前为止最好的选择似乎是DO CONCURRENT,IFF编译器支持它,比如英特尔Fortran编译器2015,我已经看到了DO CONCURRENT,IFF的性能提升,编译器优化标志已经开启。请注意其他Fortran编译器中的DO CONCURRENT状态,因为它们可能无法优化它并简单地将DO CONCURRENT转换为DO循环,在这种情况下可能会发生性能损失,具体取决于标头的写入方式(下面的详细解答)。

LONG ANSWER:

我今天上午通过以下代码比较了DO-loop与阵列分配与DO CONCURRENT的比较:

program performance_test
implicit none
integer :: i,j,k, nloop = 10**4
integer, dimension(:,:), allocatable :: variable
real*8  :: tstart,tend
allocate(variable(nloop,nloop))

call cpu_time(tstart)
do k = 1,10
  variable = 0.0
end do
call cpu_time(tend)
write(*,*) tend-tstart

call cpu_time(tstart)
do k = 1,10
  do j = 1,nloop
    do i = 1,nloop
      variable(i,j) = 0.0
    end do
  end do
end do
call cpu_time(tend)
write(*,*) tend-tstart

call cpu_time(tstart)
do k = 1,10
  do concurrent (j = 1:nloop, i = 1:nloop)
    variable(i,j) = 0.0
  end do
end do
call cpu_time(tend)
write(*,*) tend-tstart

call cpu_time(tstart)
do k = 1,10
  do i = 1,nloop
    do j = 1,nloop
      variable(i,j) = 0.0
    end do
  end do
end do
call cpu_time(tend)
write(*,*) tend-tstart

call cpu_time(tstart)
do k = 1,10
  do concurrent (i = 1:nloop, j = 1:nloop)
    variable(i,j) = 0.0
  end do
end do
call cpu_time(tend)
write(*,*) tend-tstart    

end program performance_test

编译器是Intel Fortran 2015。

结果:

DO CONCURRENT和简单的DO循环都赢得了Fortran数组语法(至少在这个例子中,据我所知)编译器优化标志是打开还是关闭,但只有当它完成Fortran列顺序时心里。从技术上讲,我不会想到如果我可以在下面使用DO CONCURRENT进行逐列或逐行讨论。没有优化标志,DO CONCURRENT基本上是简单的DO循环。使用优化标志,编译器本身将处理循环的顺序。

我迄今为止在英特尔Fortran编译器2015中使用DO CONCURRENT的经验:在复杂的DO循环中,编译器无法轻易破译并发性,与简单的DO循环相比,它会带来一些性能提升,而在其他情况下,它与DO循环,应该是,当它与OPENMP指令结合使用时,除了今天造成灾难之外,至少就我的实验而言。

没有编译器优化:

array syntax               :  4.44602850000000
do-loop, column-wise       :  3.82202450000000
do concurrent, column-wise :  3.91562510000000
do-loop, row-wise          :  19.1413227000000
do concurrent, row-wise    :  19.2817236000000

O2级别优化:

array syntax               :  0.218401400000000
do-loop, column-wise       :  0.187201200000000
do concurrent, column-wise :  0.171601100000000
do-loop, row-wise          :  0.187201200000000
do concurrent, row-wise    :  0.171601100000000