2011-01-20 86 views
1

我運行下面的OpenMP代碼奇怪的漂浮行爲的OpenMP

 #pragma omp parallel shared(S2,nthreads,chunk) private(a,b,tid) 
    { 
     tid = omp_get_thread_num(); 
     if (tid == 0) 
     { 
      nthreads = omp_get_num_threads(); 
      printf("\nNumber of threads = %d\n", nthreads); 
     } 
     #pragma omp for schedule(dynamic,chunk) reduction(+:S2) 
     for(a=0;a<NREC;a++){ 
      for(b=0;b<NLIG;b++){ 
       S2=S2+cos(1+sin(atan(sin(sqrt(a*2+b*5)+cos(a)+sqrt(b))))); 
      } 
     } // end for a 
    } /* end of parallel section */ 

而對於NREC = NLIG = 1024點更高的價值,在8芯板,我起身到7加速。問題是,如果我比較變量S2的最終結果,它與序列版本中獲得的確切結果的差異在1%到5%之間。可能是什麼原因?我應該使用一些特定的編譯選項來避免這種奇怪的浮動行爲嗎?

回答

2

浮點數的加/減順序會影響精度。舉一個簡單的例子,假設您的機器存儲2個十進制數字,並計算1 + 0.04 + 0.04的值。

  • 如果你先做左側此外,你得到1.04,這是四捨五入到1秒除了將再次給予1,所以最後的結果是1

  • 如果你做正確的另外首先,你會得到0.08。添加到1,這給1.08四捨五入到1.1。

爲了獲得最大精度,最好從小到大添加值。

另一個原因可能是CPU上的浮點寄存器可能包含比主存儲器中的浮點數多的位。因此,如果某個中間結果被緩存在寄存器中,它會更加準確,但是如果它被換出到內存中,它會被截斷。請參閱this question in the C++ FAQ

+2

是的。減數中的增加順序也會影響結果,特別是如果值之間的差異很大。 – Kos 2011-01-20 16:27:31

0

衆所周知,當減去兩個大的值(或者添加兩個具有不同符號的大值)時,機器浮點運算會出現缺陷,從而產生較小的差異。因此,將振盪符號序列求和可能在每次迭代中引入嚴重的誤差。另一個有缺陷的情況是,兩個操作數的大小差別很大 - 較小的操作數實際上會取消。
將正負操作數分開並分別對每個組進行求和,然後將組結果相加(減去)可能會很有用。
如果準確性至關重要,則可能需要對每個組進行預先分類,並在每個組內執行兩次總和。第一筆錢將從中心走向最大(頭),第二筆將從最小(尾)走向中心。結果組總和將是部分運行的總和。