2011-07-19 55 views
11

C++で固定小数点クラスを実装しようとしていますが、パフォーマンスに問題があります。私は浮動小数点型の単純なラッパーに問題を減らしましたが、それはまだ遅いです。私の質問は - コンパイラが完全に最適化できないのはなぜですか?C++で単純な数値型ラッパークラスを最適化する方法は?

'float'バージョンは 'Float'より50%高速です。なぜ?!

(私はVisual C++ 2008を使用して、すべての可能なコンパイラのオプションをテストしました。

は、以下のコードを参照してください:

IMO
#include <cstdio> 
#include <cstdlib> 
#include "Clock.h"  // just for measuring time 

#define real Float  // Option 1 
//#define real float  // Option 2 

struct Float 
{ 
private: 
    float value; 

public: 
    Float(float value) : value(value) {} 
    operator float() { return value; } 

    Float& operator=(const Float& rhs) 
    { 
     value = rhs.value; 
     return *this; 
    } 

    Float operator+ (const Float& rhs) const 
    { 
     return Float(value + rhs.value); 
    } 

    Float operator- (const Float& rhs) const 
    { 
     return Float(value - rhs.value); 
    } 

    Float operator* (const Float& rhs) const 
    { 
     return Float(value * rhs.value); 
    } 

    bool operator< (const Float& rhs) const 
    { 
     return value < rhs.value; 
    } 
}; 

struct Point 
{ 
    Point() : x(0), y(0) {} 
    Point(real x, real y) : x(x), y(y) {} 

    real x; 
    real y; 
}; 

int main() 
{ 
    // Generate data 
    const int N = 30000; 
    Point points[N]; 
    for (int i = 0; i < N; ++i) 
    { 
     points[i].x = (real)(640.0f * rand()/RAND_MAX); 
     points[i].y = (real)(640.0f * rand()/RAND_MAX); 
    } 

    real limit(20 * 20); 

    // Check how many pairs of points are closer than 20 
    Clock clk; 

    int count = 0; 
    for (int i = 0; i < N; ++i) 
    { 
     for (int j = i + 1; j < N; ++j) 
     { 
      real dx = points[i].x - points[j].x; 
      real dy = points[i].y - points[j].y; 
      real d2 = dx * dx + dy * dy; 
      if (d2 < limit) 
      { 
       count++; 
      } 
     } 
    } 

    double time = clk.time(); 

    printf("%d\n", count); 
    printf("TIME: %lf\n", time); 

    return 0; 
} 
+2

最大限の最適化フラグをオンにしましたか?私はあなたがそれらをオンにすると魔法が起こっているのを見ました。 – iammilind

+0

アセンブリを生成し、違いがどこにあるのか確認してください... –

+0

すべてのメソッドを明示的に 'インライン'としてマークしようとする可能性があります –

答えて

4

を、それは、最適化フラグに関係しています。あなたのプログラムをg ++のlinux-64マシンでチェックしました。どんな最適化もなしに、それはあなたがどれより少ないと言われたのと同じ結果を与えます50%

最大限の最適化をオンにしたまま(すなわち、-O4)。どちらのバージョンも同じです。最適化をオンにしてチェックします。

+1

私はGCCをインストールしましたが、実際はうまくいきます! GCCでは1.13秒、VC++では1.70秒(フロート)または2.58秒(フロート)です。私はまた、 'dx * dx + dy * dy'を直接条件に移動すると、VC++のパフォーマンスが21%向上することも発見しました!どのようにVC++がそれほど最適化できないのでしょうか?私はすべての可能な最適化オプションを有効にし、さまざまな組み合わせをテストしました。 –

+0

Wow ... 'Win32'から 'x64'プラットフォームに切り替えたとき、実行時間は2.58から0.77秒に短縮されました!そしてそれは 'フロート'と 'フロート'と同じです。 –

2

さらに調査した結果、これはコンパイラの最適化パイプラインの問題であると徹底的に確信しています。この場合に生成されるコードは、非カプセル化を使用する場合と比較してかなりが悪いです。floatです。私の提案は、この潜在的な問題をMicrosoftに報告し、その問題について何を言いたいのかを見ることです。また、整数用に生成されたコードが最適に見えるので、このクラスの計画された固定小数点バージョンの実装に移行することをお勧めします。

4

お試しを参照してください。あなたのクラスは、コンパイラーがそれを最適化しない場合はオーバーヘッドがあるので、参照渡しのオーバーヘッドが小さくても、単にクラスをコピーするよりも高いかもしれません。したがって、この...

Float operator+ (const Float& rhs) const 
{ 
    return Float(value + rhs.value); 
} 

は一時オブジェクトを回避し、ポインタ参照のいくつかの間接を回避することができる。このような何か...

Float operator+ (Float rhs) const 
{ 
    rhs.value+=value; 
    return rhs; 
} 

になります。

+2

私はそれを試した - 動作しません。さらに59%も時間が増加します。 –

関連する問題