2015-11-07 53 views
0

我想使用英特爾TBB parallel_reduce獲取由雙打組成的數組元素的總和。但是,與OpenMP縮減實施相比,結果不同。parallel_reduce上雙重返回不正確的結果

這裏是OpenMP的一個:

double dAverageTemp = 0.0; 
#pragma omp parallel for reduction(+:dAverageTemp) 
for (int i = 0; i < sCartesianSize; i++) 
    dAverageTemp += pdTempCurr[i]; 

此代碼返回正確的值,這是 「317.277 」;然而,這TBB代碼:

double dAverageTemp = tbb::parallel_reduce(tbb::blocked_range<double*>(pdTempCurr, pdTempCurr + sCartesianSize - 1), 
             0.0, 
             [](const tbb::blocked_range<double*> &r, double value) -> double { 
              return std::accumulate(r.begin(), r.end(), value); 
             }, 
             std::plus<double>() 
             ); 

堅持,結果是 「317.277 」。

我在這裏錯過了什麼?

+0

1e-4對很多域都很好。可能tbb和omp利用不同的優化。 –

+2

添加的順序根據並行度不同而不同。數學加法是關聯和可交換的,但浮點不是這樣。所以你必須期望總和根據加法的順序來改變。順便說一句,你爲什麼相信第一個答案更「正確」? – JSF

+0

顯然我對精度不滿意,並且詢問我是否錯過了任何東西。 @BrianCain – bigahega

回答

4

儘管所有關於求和順序的註釋都是完全正確的,但這裏的簡單事實是您的代碼中存在一個錯誤。所有std::thrust::tbb::算法或構造函數遵守相同的理念,當談到定義範圍,這是第一要素,以指示採取第一個元素不採取,像一個for (auto it = v.begin(); it < v.end(); it++)

因此,在這裏,你代碼tbb::blocked_range應該上升到pdTempCurr + sCartesianSize,而不是pdTempCurr + sCartesianSize - 1

它應該成爲:

double dAverageTemp = tbb::parallel_reduce(tbb::blocked_range<double*>(pdTempCurr, pdTempCurr + sCartesianSize), 
        0.0, 
        [](const tbb::blocked_range<double*> &r, double value) -> double { 
         return std::accumulate(r.begin(), r.end() value); 
        }, 
        std::plus<double>() 
      ); 

我的(野生)的猜測是,pdTempCurr[sCartesianSize-1]是圍繞0.0003將佔經歷的數值差異。