2011-02-24 39 views
1

當我調用下面的函數時,我正在開發的程序慢三倍。 這不會是壞的,如果它不被稱爲幾百萬次。C++函數max_element&iterator = 3x較慢

double obterNormLarguraBanda(const std::vector<double>& v, int periodos) 
{ 
    int aa; 
    double maximo, minimo, valor; 
    std::vector<double>::const_iterator inicio; 
    if (v.size() < periodos) 
    { 
     inicio = v.begin(); 
    } 
    else 
    { 
     inicio = v.end() - periodos; 
    } 
    maximo = *max_element(inicio, v.end(), excludeWrong); 
    minimo = *min_element(inicio, v.end(), excludeWrong); 
    return (v.back()-minimo)/(maximo - minimo); 
} 

bool excludeWrong(double i, double j) 
{ 
    if (i==-1 || j==-1) return false; 
    return i<j; 
} 

periodos取值500 有另一種方式來加快顯著這個功能呢?

路易斯

+2

你在調試模式下編譯?也許它使用安全的stl樣式實現,並且每次調用都受到檢查。嘗試開啓優化。 – 2011-02-24 15:05:46

+3

如果沒有'min_element'和'max_element',你可能會變得更好,並且執行一次迭代來找到兩者。 – 2011-02-24 15:10:20

+4

順便說一句''double''''''嚴格平等並不是一個好主意。 – sharptooth 2011-02-24 15:18:23

回答

3

編輯:時沒有注意到你的謂詞的使用(!西班牙扔我一個位)讓我改寫了幾分鐘......

max_elementmin_element通過一系列既迭代,整個步驟可以在一個功能中完成。

我相信一些編譯器在其STL中有一個minmax_element函數,但我不相信它是在標準中。你可以自己寫。我原本寫這是一個沒有模版的版本,但如果你有一個好的編譯器,它應該沒有區別。

嘗試這樣的事情(未經測試)

template <typename Iter, typename Pred> 
void minmax_element(Iter begin, Iter end, Iter& min, Iter& max, const Pred& comp) 
{ 
    min = begin; 
    max = begin; 

    typedef std::iterator_traits<Iter>::value_type T; 
    for (++begin; begin != end; ++begin) 
    { 
     if (comp(*max, *begin)) 
      max = begin; 
     else if (comp(*begin, *min)) 
      min = begin; 
    } 
} 

template <typename Iter> 
void minmax_element(Iter begin, Iter end, Iter& min, Iter& max) 
{ 
    minmax_element(begin, end, min, max, std::less<std::iterator_traits<Iter>::value_type>()); 
} 
+2

'std :: minmax_element'在C++ 0x的3225草案中,所以它將成爲標準。 – 2011-02-24 15:37:12

+0

@本Voigt:這是葡萄牙語,不是西班牙語!謝謝你的答案。我會實現它,儘管我對模板還不放心。 – Luis 2011-02-24 16:27:43

+0

信貸到期時給予貸款。這是rlbond的出色答案,以及對語言錯誤認識的不幸。 – 2011-02-24 16:41:54

1

你可以用一個單一的std::minmax_element()取代這兩個電話。

+0

注意:這可能需要使用C++ 0x庫的新編譯器。 – 2011-02-24 15:36:34

3

相反,別人怎麼說,我不相信這兩個電話與一個minmax_element()更換到std::max_element()std::min_element()將提高一個顯著的方式表現,因爲用1次操作迭代2 * n次或用2次操作迭代n次幾乎沒有區別。

但是,有什麼區別可以從算法中完全消除這兩個調用。也就是說,找到最小和最大元素,然後在新數據進入時檢查這些元素,而不是再次將新數據與整個容器進行比較。

double obterNormLarguraBanda(const std::vector<double>& v, 
           double maximo, double minimo) 
{ 
    return (v.back()-minimo)/(maximo - minimo); 
} 

bool excludeWrong(double i, double j) 
{ 
    if (i==-1 || j==-1) return false; 
    return i<j; 
} 

// usage example 
void f() 
{ 
    std::vector<double> v; 
    // ... 
    double maximo = *max_element(inicio, v.end(), excludeWrong); 
    double minimo = *min_element(inicio, v.end(), excludeWrong); 
    for(int i = 0; i != 1000; ++i) { 
     // if(! excludeWrong(new_datum, maximo)) maximo = new_datum; 
     // if(excludeWrong(new_datum, minimo)) minimo = new_datum; 
     double d = obterNormLarguraBanda(...); 
    } 
} 
+0

這是一個很好的觀點 - 有時候。我們沒有足夠的信息,只是這個功能被稱爲很多。如果他只是在傳輸數據流,則無法加速算法。 +1 – rlbond 2011-02-24 15:34:31

+0

誰說路易斯多次傳球?他只是說這個功能被多次使用。 – 2011-02-24 15:35:36

+0

無論如何,由於緩存未命中,在任何大型集合上迭代兩次比一次完成所有工作要昂貴得多。但是,500個元素不是一個大容器。 – 2011-02-24 15:39:19

0

關於什麼 - 對另一個實現,或者只是不調用這個函數,「慢3倍」?在第二種情況下,它可能只是算法複雜性而使其變慢。

你沒有解釋你的代碼是如何精確使用的,在某些情況下,你可以緩存最小/最大值的計算,而不是在循環中進行。例如,如果輸入向量很少改變,那麼每次重新計算都沒有意義。即使它發生變化,您也可以更新最小/最大值,而不必超過periodos元素(動態編程可能有所幫助)。

你也可以檢查生成的程序集來檢查奇怪的函數調用(例如迭代器安全檢查),我知道至少MSVC 2005/2008默認啓用它們,即使在發佈模式下(請參閱_SCL_SECURE宏)。

+0

我應該更清楚,對不起。這是沒有這個函數被調用的3倍。每次調用函數時都必須更改輸入向量。我正在使用g ++。 – Luis 2011-02-24 16:25:48

0

這不是對性能的具體問題的答案,所以也許它沒有價值。但似乎比較函數會導致意想不到的或可能實現相關的結果。如果比較的第一個值是-1,那麼它可以計算爲所有情況下的最小值和最大值。我測試了gcc v4.0.2和微軟的編譯器v15.00.21022.08。例如,以下內容:

std::vector<double> v; 
    v.push_back(-1); 
    v.push_back(1); 
    v.push_back(2); 
    cout << "min: " << *min_element(v.begin(), v.end(), excludeWrong) << endl; 
    cout << "max: " << *max_element(v.begin(), v.end(), excludeWrong) << endl; 

打印:

min: -1 
max: -1 

也許這就是理想的結果,但它似乎有點奇怪。

+0

感謝您指出這一點,即使它與問題沒有直接關係。 excludeWrong()作爲比較函數給出,如果第一個參數小於第二個參數,則返回「true」,否則返回false。因此,返回錯誤不是過濾掉某個值的方法 - 而是將比較混淆起來。 – 2011-08-17 09:34:28