2015-05-28 38 views
2

我已經實現了一個算法,該算法在某些時刻需要計算向量元素的功效總和。權力是一個積極的雙重,在循環過程中不變。我想通了,這個計算是目前我的程序的瓶頸,不知道是否有一種方法可以加快下面的代碼片段:優化具有常數雙指數的權力總和

double SumOfPowers(std::vector<double>& aVector,double exponent) 
{ 
    double help = 0; 
    size_t sizeOfaVector = aVector.size(); 
    for (size_t k = 0; k < sizeOfaVector; k++) 
    { 
     help += std::pow(aVector[k], exponent); 
    } 
    return help; 
} 

我有一種感覺,就好像一個可以利用的事實,即指數在循環過程中不變,並減少昂貴的std :: pow調用。有沒有人知道更好的實現方式,或者是否有可以使用的庫函數來完成這項工作?

+0

我會首先檢查循環是否是向量化的。 – Petr

+0

@Petr:我該如何檢查? –

+0

你的矢量有多少個條目? –

回答

3

首先,檢查循環是否是向量化的。爲此,使用-O3(在這裏和下面我假設gcc編譯器;我對其他編譯器知之甚少,但我希望他們有類似的選項)構建程序。也可以添加-ftree-vectorizer-verbose=2選項以獲取關於哪些循環被矢量化的詳細輸出。你可能想玩弄選項來獲得你想要的輸出。

如果循環沒有矢量化,那麼你可以使它矢量化。您可能需要更改循環結構(例如,首先將所有權限計算爲單獨的數組,然後才計算總和),或者使用某種方式向編譯器通知更多信息,如restrict聲明,有關更多信息,請參閱"Auto-vectorization with gcc 4.7"討論。在最壞的情況下,我認爲,你可以手工實現矢量化,我記得有這樣的功能,見Intel's reference"A practical guide to SSE SIMD with C++"

對於Visual Studio,首先添加/Qvec-report:2選項以獲得詳細報告。以上所有其他建議也適用,您只需要找到相應的MSVC選項。


另一種加快速度的方法是使用-ffast-math選項犧牲精度。 AFAIK,標準pow函數使用一些高級邏輯來檢查基數或指數是否接近1的情況,以避免出現精度問題。如果這不是你的情況,你可能不需要這個邏輯。我想-ffast-math會刪除它,儘管您可能想要檢查它。

無論如何,您可以用exp(log(...)*...)替換pow,以避免手動進行這些檢查。這不會給你提速,但你可能會注意到一些好處。此外,如果您經常將相同的向量提升爲不同的指數,則可以預先計算log s。

+0

如果經常需要不同的權力,那麼將日誌相乘的建議可能非常有用 - 在這種情況下,應該存儲日誌而不是簡單的值。 –

+0

@TobySpeight,謝謝,補充了這一點。 – Petr

+0

@Petr我檢查了矢量化信息輸出。 (除了/ Qvec-report:2之外,還需要將警告至少設置爲4級(/ W4)。)循環沒有向量化。我更改了代碼以使用臨時向量來存儲權力,然後將它們與std :: accumulate相加。現在循環是矢量化的,sizeOfaVector = 10的時間減少了22%,sizeOfaVector = 100的時間減少了48%。太棒了!今天我學到了很多。非常感謝你。 –

2

不,恆指數不允許進行可行的優化,除非您的值經常重複(如果是這樣的話:memoize)。並行化是你最好的選擇(或者根本不需要pow

+0

這個函數在parallized循環中被調用,所以不幸的是,parallizing不能解決這個特定的問題。而且,這些值不會經常重複。也許我必須面對這樣一個事實,即我觸及了優化的極限。 –