【问题标题】:How to optimize Fortran IF-ELSE in DO loop?如何在 DO 循环中优化 Fortran IF-ELSE?
【发布时间】:2019-03-13 07:54:06
【问题描述】:

下面这个函数在我的程序中用得最多。

    CONTAINS
     SUBROUTINE Delta4(R,Del)
      REAL(DP), DIMENSION(:), INTENT(IN) :: R
      REAL(DP), DIMENSION(:), INTENT(OUT) ::  Del
      INTEGER(I4B)  :: i, j, r_n, c_n
      REAL(DP) :: ar
      !r_n=size(R,1);
      Del=0.0_dp
      do i=1,4; ar=ABS(R(i))
          if (ar <= 1.0_dp) then
            Del(i)=(3.0_dp-2.0_dp*ar+  &
              sqrt(1.0_dp+4.0_dp*ar-4.0_dp*ar*ar))*0.125_dp
          else !! if (1.0_dp < ar .and. ar <= 2.0_dp)  then
            Del(i)=(5.0_dp-2.0_dp*ar-  &
              sqrt(-7.0_dp+12.0_dp*ar-4.0_dp*ar*ar))*0.125_dp
          end if
      end do

R, Del:长度为4的向量

所以我想提高这个功能的速度。
据我所知,if-else 分支很慢。此外,它处于do循环中。 如何优化它?

【问题讨论】:

  • 我添加了一个有趣的改进。
  • 你说 if-else 分支很慢:你做了什么测量?不衡量就优化是没有意义的!
  • 对不起弗朗索瓦,你是对的。我认为 if-else 很慢,因为它是条件语句。

标签: performance if-statement optimization fortran do-loops


【解决方案1】:

IMO 对这个函数几乎没有什么好处,它本质上是一堆算术运算。

您可以在其他常量中吸收*0.125_dp

更好的是,您可以将计算重写为(伪代码)

ar= 1 + 2 * ((ar > 1) - ar)
Del= (2 + ar + sqrt(1 - ar * ar)) * 0.125

这假设隐式转换 .false.0.true.1,这可能不适用于您的编译器。希望它被编译为无分支。

由于向量长度只有四,您可以完全展开循环(但也许编译器已经这样做了)。

我敢打赌,这不会产生明显的影响。

为了提高性能,您应该从更全局的角度审查代码,并可能考虑并行化。


更新:

正如@kvantour 所指出的,我放弃了更改符号。我们可以修复

i= 2 * (ar > 1) - 1
ar= i + 2 * (1 - ar)
Del= (2 + ar + i * sqrt(1 - ar * ar)) * 0.125

或者,

i= SIGN(1, ar - 1)

如果结果证明是有效的。

【讨论】:

  • 请注意,其中一个 sqrt 中有一个减号。
  • @kvantour:哎呀,是的。修复。
猜你喜欢
  • 2022-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多