首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >避免循环中的条件语句

避免循环中的条件语句
EN

Stack Overflow用户
提问于 2021-11-13 14:26:37
回答 2查看 210关注 0票数 2

我的f90程序中有一部分占用了大量的计算时间。我基本上是在遍历三个矩阵(尺寸相同,尺寸高达250×250),并试图确保值保持在区间- 1.0,1.0的范围内。我知道最好的做法是避免循环中的条件,但我很难找到如何重写这段代码以获得最佳性能。有没有办法“解开”循环,或者使用某种内置函数来“向量化”条件语句?

代码语言:javascript
复制
do ind2 = 1, size(u_mat,2)
    do ind1 = 1,size(u_mat,1)
        ! Dot product 1 must be bounded between [-1,1]
        if (b1_dotProd(ind1,ind2) .GT. 1.0_dp) then
            b1_dotProd(ind1,ind2) = 1.0_dp
        else if (b1_dotProd(ind1,ind2) .LT. -1.0_dp) then
            b1_dotProd(ind1,ind2) = -1.0_dp
        end if
        ! Dot product 2 must be bounded between [-1,1]
        if (b2_dotProd(ind1,ind2) .GT. 1.0_dp) then
            b2_dotProd(ind1,ind2) = 1.0_dp
        else if (b2_dotProd(ind1,ind2) .LT. -1.0_dp) then
            b2_dotProd(ind1,ind2) = -1.0_dp
        end if
        ! Dot product 3 must be bounded between [-1,1]
        if (b3_dotProd(ind1,ind2) .GT. 1.0_dp) then
            b3_dotProd(ind1,ind2) = 1.0_dp
        else if (b3_dotProd(ind1,ind2) .LT. -1.0_dp) then
            b3_dotProd(ind1,ind2) = -1.0_dp
        end if
    end do
end do

值得的是,我正在使用ifort进行编译。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-11-13 14:49:25

为此,您可以使用内部的最小最大值函数。

由于它们都是元素,所以可以在整个数组中使用它们,如

代码语言:javascript
复制
b1_dotProd = max(-1.0_dp, min(b1_dotProd, 1.0_dp))

虽然有处理器指令允许在没有分支的情况下实现minmax,但它将取决于minmax的编译器实现是否实际完成,以及这是否确实更快,但至少要简洁得多。

票数 4
EN

Stack Overflow用户

发布于 2021-11-16 10:33:10

@veryreverie的答案肯定是正确的,但是有两件事需要考虑。

  1. where语句是另一个明智的选择。因为它仍然是有条件的选择--同样的警告

这是否真的避免了分支,如果它实际上更快,但它至少要简洁得多

仍然适用。

一个例子是:

代码语言:javascript
复制
    pure function clamp(X) result(res)
        real, intent(in) :: X(:)
        real :: res(size(X))
        where (X < -1.0)
            res = -1.0
        else where (X > 1.0)
            res = 1.0
        else
            res = X
        end where
    end function
  1. 如果您想将数据规范化为严格的1或-1,我实际上会考虑将数据类型更改为整数。然后,您可以实际使用a == 1等,而无需考虑浮点相等问题。根据您的代码,我还会考虑点积接近于零的情况。当然,这一点只适用于,如果你只感兴趣的标志。
代码语言:javascript
复制
    pure function get_sign(X) result(res)
        real, intent(in) :: X(:)
        integer :: res(size(X))
        ! Or use another appropiate choice to test for near_zero
        where (abs(X) < epsilon(X) * 10.)
            res = 0
        else where (X < 0.0)
            res = -1
        else where (X > 0.0)
            res = +1
        end where
    end function
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69955176

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档