2015-10-15 52 views
0

我重載了算術/賦值操作符std::vector以便能夠執行一些基本的線性代數操作。但是,在鏈接這些操作時我遇到了一些性能問題。鏈接操作符時的編譯器優化

這裏是我的main.h內容:的main1.cpp

#include <vector> 
#include <stdlib.h> 

using namespace std; 

typedef vector<float> vec; 

inline vec& operator+=(vec& lhs, const vec& rhs) { 
    for (size_t i = 0; i < lhs.size(); ++i) { 
     lhs[i] += rhs[i]; 
    } 
    return lhs; 
} 

inline vec operator*(float lhs, vec rhs) { 
    for (size_t i = 0; i < rhs.size(); ++i) { 
     rhs[i] *= lhs; 
    } 
    return rhs; 
} 

內容:

內容的 main2.cpp
#include "main.h" 

// gcc 4.9.2 (-O3): 0m5.965s 
int main(int, char**) { 
    float x = rand(); 
    vec v1(1000); 
    vec v2(1000); 

    for (size_t i = 0; i < v1.size(); ++i) { 
     v1[i] = rand(); 
     v2[i] = rand(); 
    } 

    for (int i = 0; i < 10000000; ++i) { 
     v1 += x * v2; 

     // same as: 
     //vec y = x * v2; 
     //v1 += y; 
    } 
    return 0; 
} 

#include "main.h" 

// gcc 4.9.2 (-O3): 0m2.400s 
int main(int, char**) { 
    // same stuff 

    for (int i = 0; i < 10000000; ++i) { 
     for (size_t j = 0; j < v1.size(); ++j) { 
      v1[j] += x * v2[j]; 
     } 
    } 
    return 0; 
} 

第二個程序運行速度比第一快得多。我明白爲什麼會出現這種情況:第一個程序不是隻有一個循環,而是兩個循環,它分配一個臨時向量。

但這是我期望編譯器看到和優化的那種東西。或者我做錯了什麼?

我不記得有線性代數庫(如犰狳)有這個問題。他們如何解決這個問題?這是否涉及一些複雜的模板編程,還是有一些簡單的方法來幫助編譯器優化它?

+3

Armadillo大量使用表達式模板。 – 101010

+0

我的測量數據是1和0.85 –

+1

表達式模板幾乎可以肯定地解釋這種差異。 GMP使用類似的方法來減少不必要的工作;操作符返回描述沒有執行工作的邏輯操作的對象;如果後續操作可以以更有效的方式進行組合,則可以這樣做。它只是在賦值給一個具體類型時,表達式被解析/計算(通過隱式轉換),這可以減少工作(例如,對於1000+位,計算'(a * b)&1'可能是昂貴的) '/'b',但表達式模板可以分配'&1',因此乘法是在一個位上。 – ShadowRanger

回答

1

對於這個問題,有一些超級難看的模板元編程解決方案。但是隨後標準委員會發明瞭右值引用和移動語義的組合。仔細查看,找到解決方案的很多例子,而不會出現元編程的荒謬程度。

+1

我在代碼中沒有看到移動語義的任何有用的應用。 –

+0

@Dieter,我誤解了我認爲你是正確的,它需要非常複雜的模板元編程來避免爲臨時存儲'operator *()'的結果分配空間,C++ 11特性使得容易不太合適。 – JSF