在Fortran中的特定索引处将数组添加到较长数组的巧妙方法?

时间:2018-09-05 12:52:19

标签: arrays algorithm indexing fortran fortran90

我有两(1d)个数组,一个长的A(大小为m)和一个较短的B(大小为n)。我想通过在特定索引处添加短数组的每个元素来更新长数组。

从原理上讲,数组的结构如下:

A = [a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 ...    am]
B = [   b1 b2 b3    b4 b5       b6      b7  b8  b9  ... bn   ]

我想通过添加A的相应元素来更新B

最直接的方法是拥有一些索引数组indarray(大小与B相同),它告诉我们A的哪个索引对应于B(i)

选项1

do i = 1, size(B)
    A(indarray(i)) = A(indarray(i)) + B(i)
end do

但是,我认为有一个组织可以解决这个问题,

  1. 以矢量方式进行此操作应该没有障碍。即每个i的更新都是独立的,可以按任何顺序进行。

  2. 无需在数组A中来回跳转。机器应该知道只遍历数组一次,仅在必要时更新A

  3. 应该不需要任何临时数组。

在Fortran中执行此操作的最佳方法是什么?

选项2

一种方法可能是使用PACKUNPACK和布尔型掩码M(与A相同),其作用与indarray相同:

A = [a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 ...    am]
B = [   b1 b2 b3    b4 b5       b6      b7  b8  b9  ... bn   ]
M = [.  T  T  T  .  T  T  .  .  T   .   T   T   T       T  . ]

(其中T代表.true...false.)。

代码就是

A = UNPACK(PACK(A, M) + B, M, A)

这非常简洁,可能满足(1)和(2)的要求(似乎在整个数组中执行了两个循环,而不仅仅是一个循环)。但是我担心机器会在此过程中创建一些临时数组,这似乎是不必要的。

选项3

whereUNPACK一起使用怎么办?

where (M)
    A =A + UNPACK(B, M, 0.0d0)
end where

这似乎与选项2相同(两个循环,可能会创建临时数组)。它还必须用M=.false.填充UNPACK数组中的0元素,这似乎是一种浪费。

选项4

在我的情况下,遮罩的.true.元素通常位于连续的块中(即,连续几个true,然后是一堆false,然后是另一个true,等等)。也许这可能会导致类似于选项1的情况。假设有K个块中的.true.个。我需要一个数组indstart(大小为K),该索引为每个真实块的开始处的A提供一个索引,以及一个索引blocksize(大小为{{1} })加上真正区块的长度。

K

至少这只会循环一次。这段代码似乎更明确地说明了数组中没有来回跳跃的事实。但是我认为编译器无法弄清楚(例如j = 1 do i = 1, size(indstart) i0 = indstart(i) i1 = i0 + blocksize(i) - 1 A(i0:i1) = A(i0:i1) + B(j:j+blocksize(i)-1) j = j + blocksize(i) end do 可能具有负值)。因此,此选项可能不会导致矢量化结果。

-

有什么想法可以做到这一点吗?在我的情况下,数组blocksizeindarrayMindstart只能创建一次,但必须对不同的数组blocksize进行多次添加操作和A(尽管这些数组将具有恒定的大小)。 B语句似乎很重要。

0 个答案:

没有答案