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
编译并执行得很好。同样,我认为这是符合标准的代码和行为。
您似乎在使用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
但我希望这仅仅是因为这个例子过于简单了?:)
正如 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