陣列的字首和(Prefix Sum)問題及其並行演算法
一、問題簡介
首先,我們來看一下什麼是字首和(Prefix Sum)問題。對於一個長度為N的陣列(假設下標從1到N),那麼字首和(有時也稱累加和cumulative sum)演算法的虛擬碼是下面這樣的
for(i=2;i<=N;i++)
V[i] = V[i-1] + V[i];
也就是說,對於一個輸入的陣列,我們所得之結果是一個等長的陣列,而結果陣列中的每個元素(假設是第x個元素)都是原陣列中對應位置的前x項和。例如:下圖所示為Prefix Sum問題的序列演算法的示意:
可見,序列版本的Prefix Sum問題的規模(size)是N-1,因為我們一共需要執行N-1次(加和)計算。而這個問題的深度(depth)也是N-1,因為
二、Upper/Lower 並行演算法
Upper/Lower演算法是一種基於分治法設計的用於解決Prefix Sum問題的並行化演算法。具體來說,Upper/Lower演算法會把數組裡的元素分成兩半,即lower half和high half。然後Prefix Sum會在lower half和high half
下圖給出的是包含逐層遞迴的全部執行過程。
如果我們用來表示在長度為N的輸入上執行的用於求解Prefix Sum問題的Upper/Lower演算法,那麼我們則有如下定理:
此外,如果N不是2的若干次冪,我們則可以用下面這個上下界來給出S(N)的範圍:
由於採用了二分法,所以我們可以知道的depth等於 t = log2N,其中N=2^t。
三、Odd/Even並行演算法
另外一種用於解決Prefix Sum問題的並行化演算法就是Odd/Even演算法,記作
Odd/Even演算法的執行中有個主要的步驟往復交替。首先,prefix sum的操作總是在偶數項上執行,如下圖所示:
其次,一旦偶數項上的操作執行完畢,那麼偶數上的結果就將被加到下一個(相鄰的)奇數項上,如下圖所示:
所以我們不難發現,在執行過程中,每次將輸入二分,都會使得操作的depth增加2層,一層是做相鄰兩個元素的加和,一層是將中間結果累加到相應的位置上去。當N=4時,的執行需要用到2層操作。現在考慮當N=2^t時,的depth為多少。根據之前的分析易得:
同樣地,我們還可以計算所涉及的size為(注意我們在計算時用到了等比數列的求和公式):
可見的size要比的size小很多,但同時的depth也要比的depth大很多。
四、Ladner-Fischer並行演算法
最後要介紹的這種並行演算法是由Ladner和Fischer在1980年左右提出的。Ladner-Fischer演算法使得我們可以在depth和size之間進行更加精細的平衡,它在很大程度上是Upper/Lower演算法和Odd/Even演算法的結合。例如下面是當N=8時,Ladner-Fischer演算法的執行示例:
下面是當N=16時,Ladner-Fischer演算法的執行示例:
此處我們也不再對Ladner-Fischer演算法的具體細節做過多的涉及,有興趣的讀者可以參閱相關資料以瞭解更多。
Ladner-Fischer演算法的size和depth分析比較複雜,我們這裡也不詳細討論(其中用到了斐波那契數的一些性質),下表總結對比了本文中提到的幾種並行演算法的情況:
(本文完)