1
4

3 回答 3

3

对于您问题中的情况,我根本不需要标量ii,您可以替换

  forall (i=1:20)
     ii = (i+1)/2

     b(i) = a(ii)
  end forall

  forall (i=1:20)
     b(i) = a((i+1)/2)
  end forall

在这种情况下,它会产生您想要的结果。至于你的问题:

A1:是的,如图所示。

A2: do concurrent是 Fortran 2008 中的标准功能,因此保证可以正常工作;保证您是否拥有最新的编译器并且该编译器已正确实现。到目前为止,我只使用do concurrent了最新版本的英特尔 Fortran 编译器,并且没有发现任何非标准行为。

在弗拉基米尔 F 发表评论后

是的,重写后的forall构造可能需要一个临时数组,但我相信我写的在语法上是正确的,并且在语义上等同于 OP 的原始代码。关于do concurrent构造的合法性,以下

do concurrent (i=1:20)
   b(i) = a((i+1)/2)
end do

编译并执行得很好。同样,我认为这是符合标准的代码和行为。

于 2013-09-11T11:51:35.670 回答
2

您似乎在使用forall我自然会使用do循环的地方:

do i=1,20
  ii=(i+1)/2
  b(i)=a(ii)
end do

forall语句对于要对整个数组赋值应用掩码的条件单行语句特别有用,但即便如此,我个人更喜欢do循环。

您的示例forall (i=1:10, j=1:10, i<=10)也没有多大意义,因为最终表达式不会掩盖任何值。

其他整个数组赋值背后的想法forall是编译器会知道如何更好地优化整个事情,但在实践中(嗯,至少自从我上次亲自检查以来),它通常会导致代码变慢。

编辑:

只是想提一下,最好将计算出的整数直接分配给 b 中的数组值,而不是通过使用 a 再次从内存中获取相同的东西:

do i=1,20
  b(i)=(i+1)/2
end do

但我希望这仅仅是因为这个例子过于简单了?:)

于 2013-09-11T11:58:15.587 回答
2

正如 Mark 指出的那样,在构造ii内部进行定义forall是不必要的,因为您可以a((i+1)/2)在定义中使用。作为另一种选择,如果您完全喜欢使用forall,您可以使用pure function(或 an elemental function)来设置索引:

program forall_test
   ...
  forall(i=1:20)
     b(i) = a(set(i))
  end forall 

contains
  pure function set(i)
    integer, intent(in) :: i
    integer :: set
    set = (i+1)/2
  end function set
end program

使用它a=(/1, 2, 3, 4, 5, 6, 7, 8, 9, 10/),我得到输出

1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10
于 2013-09-11T15:30:04.500 回答