それは本当に単純な問題です:
Goプログラムをプログラミングしています。ボードをQVector<int>
またはQVector<Player>
で表す必要があります。
enum Player
{
EMPTY = 0,
BLACK = 1,
WHITE = 2
};
もちろん、整数の代わりにPlayerを使用すると遅くなると思います。しかし、enum
を使用する方がコーディングが優れていると思うので、どれだけ多くなるのだろうか。
(int
ではなく)プレーヤーの割り当てと比較に関していくつかのテストを行いました
QVector<int> vec;
vec.resize(10000000);
int size = vec.size();
for(int i =0; i<size; ++i)
{
vec[i] = 0;
}
for(int i =0; i<size; ++i)
{
bool b = (vec[i] == 1);
}
QVector<Player> vec2;
vec2.resize(10000000);
int size = vec2.size();
for(int i =0; i<size; ++i)
{
vec2[i] = EMPTY;
}
for(int i =0; i<size; ++i)
{
bool b = (vec2[i] == BLACK);
}
基本的に、それはわずか10%遅いです。続行する前に知っておくべきことは他にありますか?
ありがとう!
編集:10%の違いは私の想像の産物ではなく、QtとQVectorに固有のようです。 std :: vectorを使用すると、速度は同じになります
列挙型はコンパイル時に完全に解決され(整数リテラルとしての列挙型定数、整数変数としての列挙型変数)、それらを使用する際の速度の低下はありません。
一般に、平均列挙には、int
よりも大きい基になる型はありません(非常に大きな定数を入力しない限り)。実際、§7.2¶5では次のように明示されています。
列挙型の基になる型は、列挙型で定義されたすべての列挙型の値を表すことができる整数型です。列挙型の基になる型として使用される整数型は実装によって定義されますただし、基になる型は
int
列挙型の値がint
またはunsigned int
に収まらない場合を除きます。
列挙型は通常、コードの読み取りと保守を容易にするため、適切な場合は列挙型を使用する必要があります(「マジックナンバー」でいっぱいのプログラムをデバッグしようとしたことがありますか?:S
)。
結果について:おそらく、テスト方法では、「通常の」マシンでコードを実行したときに得られる通常の速度変動が考慮されていません。1;テストを何度も(100回以上)実行し、時間の平均と標準偏差を計算してみましたか?結果には互換性があるはずです。平均間の差はRSSの1倍または2倍を超えてはなりません。2 2つの標準偏差の(通常どおり、変動のガウス分布を想定)。
実行できるもう1つのチェックは、生成されたアセンブリコードを比較することです(g ++では、-S
スイッチで取得できます)。
一般に、列挙型を使用しても、パフォーマンスにまったく違いはありません。これをどのようにテストしましたか?
自分でテストを実行しました。違いは純粋なノイズです。
ちょうど今、私は両方のバージョンをアセンブラーにコンパイルしました。それぞれの主な機能は次のとおりです。
LFB1778:
pushl %ebp
LCFI11:
movl %esp, %ebp
LCFI12:
subl $8, %esp
LCFI13:
movl $65535, %edx
movl $1, %eax
call __Z41__static_initialization_and_destruction_0ii
leave
ret
LFB1774:
pushl %ebp
LCFI10:
movl %esp, %ebp
LCFI11:
subl $8, %esp
LCFI12:
movl $65535, %edx
movl $1, %eax
call __Z41__static_initialization_and_destruction_0ii
leave
ret
マイクロベンチマークに基づいてパフォーマンスに関する記述を行うことは危険です。データを歪める外部要因が多すぎます。
列挙型は遅くならないはずです。それらは整数として実装されます。
たとえば、Visual Studioを使用している場合は、次のような簡単なプロジェクトを作成できます。
a=Player::EMPTY;
「逆アセンブリに移動」を右クリックすると、コードは次のようになります。
mov dword ptr [a],0
したがって、コンパイラは列挙型の値を置き換え、通常はオーバーヘッドを生成しません。
さて、私はいくつかのテストを行いましたが、整数型と列挙型の間に大きな違いはありませんでした。また、一貫して約6%高速なcharフォームを追加しました(メモリの使用量が少ないので驚くことではありません)。次に、ベクトルではなくchar配列を使用したところ、300%高速でした。 QVectorが何であるかが与えられていないので、私が使用したstd :: vectorではなく、配列のラッパーである可能性があります。
これが私が使用したコードで、Dev Studio 2005の標準リリースオプションを使用してコンパイルされています。質問のコードをゼロに最適化できるため、時限ループを少し変更したことに注意してください(アセンブリコードを確認する必要があります)。 。
#include <windows.h>
#include <vector>
#include <iostream>
using namespace std;
enum Player
{
EMPTY = 0,
BLACK = 1,
WHITE = 2
};
template <class T, T search>
LONGLONG TimeFunction ()
{
vector <T>
vec;
vec.resize (10000000);
size_t
size = vec.size ();
for (size_t i = 0 ; i < size ; ++i)
{
vec [i] = static_cast <T> (Rand () % 3);
}
LARGE_INTEGER
start,
end;
QueryPerformanceCounter (&start);
for (size_t i = 0 ; i < size ; ++i)
{
if (vec [i] == search)
{
break;
}
}
QueryPerformanceCounter (&end);
return end.QuadPart - start.QuadPart;
}
LONGLONG TimeArrayFunction ()
{
size_t
size = 10000000;
char
*vec = new char [size];
for (size_t i = 0 ; i < size ; ++i)
{
vec [i] = static_cast <char> (Rand () % 3);
}
LARGE_INTEGER
start,
end;
QueryPerformanceCounter (&start);
for (size_t i = 0 ; i < size ; ++i)
{
if (vec [i] == 10)
{
break;
}
}
QueryPerformanceCounter (&end);
delete [] vec;
return end.QuadPart - start.QuadPart;
}
int main ()
{
cout << " Char form = " << TimeFunction <char, 10> () << endl;
cout << "Integer form = " << TimeFunction <int, 10> () << endl;
cout << " Player form = " << TimeFunction <Player, static_cast <Player> (10)> () << endl;
cout << " Array form = " << TimeArrayFunction () << endl;
}
コンパイラはenum
を整数に変換する必要があります。これらはコンパイル時にインライン化されるため、プログラムがコンパイルされると、整数自体を使用した場合とまったく同じになるはずです。
テストで異なる結果が得られる場合は、テスト自体で何かが起こっている可能性があります。それか、コンパイラがおかしな動作をしています。
これは実装に依存し、列挙型と整数型のパフォーマンスが異なり、アセンブリコードが同じまたは異なる可能性がありますが、コンパイラが最適ではない可能性があります。違いを得るいくつかの方法は次のとおりです。