6

Visual C には、約 250 ケースの大きな switch ステートメントがあります。

#define BOP -42
#define COP -823
#define MOP -5759

int getScarFieldValue(int id, int ivIndex, int rayIndex, int scarIndex, int reamIndex)
{
    int returnValue = INT_MAX;  
    switch (id)
    {       
        case BOP      : returnValue  = Scar[ivIndex][rayIndex].bop[scarIndex][reamIndex];    break;
        case COP        : returnValue  = Scar[ivIndex][rayIndex].cop[scarIndex][reamIndex];       break;
        case MOP         : returnValue  = Scar[ivIndex][rayIndex].mop[scarIndex][reamIndex];     break;
        .....
        default:  return(INT_MAX);
     }
}

#defines には、-1 から -10,000 までの大きな範囲があることに気付くでしょう。物事は犬のように遅いので、これらの 250 の定義をより狭い (または連続した) 範囲に再定義するのに数時間を費やすと、速度が上がるのではないかと考えています。私は常に、コンパイラが数値を無関係にする方法でケース値を扱うと思っていましたが、その仮定を検証/無効にするための議論を見つけることができませんでした.

4

8 に答える 8

2

コンパイルされたコードを逆アセンブルし、コンパイラの動作を確認します。いくつかの異なるコンパイラからの出力を見てきましたが、大きな switch ステートメントは常に二分決定木またはジャンプ テーブルにコンパイルされていました。ジャンプ テーブルは取得できる最も最適なものであり、切り替えている値が狭い範囲にある場合、コンパイラによって生成される可能性が高くなります。また、一部のコンパイラでデフォルト ステートメントを使用するのにも役立ちます (ただし、他のコンパイラでは必要ありません)。

これは、逆アセンブルが唯一の適切な選択肢である状況の 1 つであり、このレベルでのコード生成の詳細が十分に文書化されていることはめったにありません。

于 2013-07-10T07:12:44.383 に答える
1

switchコードを読んで、 が何にコンパイルされるかを理解してください。

ハッシュ テーブルの実装が手元にある場合は、それを使用してみることができますが、もちろん、すべての「アクション」コードを、ハッシュ テーブルのルックアップ結果からジャンプできるものに抽出する必要があります。

GCC を使用している場合は、 GCC の計算された gotoと単純な並べ替えられた配列を組み合わせて簡単なテストを行い、古き良きバイナリ検索を使用できるようにします。後者は、コードによって実行される最悪の場合の比較の数を 250/2 から log 2 (250)、つまり約 8 に削減します。

これには、コンパイル時に宣言された (そしておそらく実行時に一度ソートされた) ルックアップ テーブルが必要になります。これは、メモリ オーバーヘッドの点で、ほとんどのハッシュテーブルが管理するよりもおそらく優れています。

于 2013-07-10T07:08:14.723 に答える
1

簡単な解決策: スイッチ ケースを複数のパーツに分割します。

if(id<=50)
{
    switch(id)
    {
      //All cases between 0 to 50
    }
}
else if (id>50 && id<=100)
{
    switch(id)
    {
      //All cases between 51 to 100
}
//and so on

範囲の選択はあなた次第です。そして、多くの範囲を作成しないでください。これにより、現在のコードよりも高速なコードが保証されます。あるいは、関数ポインターを使用して、ケースで実行されるステートメントを含む関数を作成することもできます。私はこの方法を好んだでしょう。

typedef struct
{
    void(*Cur_FunctnPtr)();     
}CMDS_Functn;

void (*Cur_Func)();
CMDS_Functn FunctionArray[66] = {
                    /*00-07*/    (*Func1),(*Func2),(*Func3),...
                    /*08-0F*/       

                    /*40-47*/       };

void my_func()
{
...  //what ever code
    Cur_Func = FunctionArray[id].Cur_FunctnPtr; //Load current Function Pointer
        (*Cur_Func)();
... // what ever code
}
于 2013-07-10T06:45:33.023 に答える
1

" " の代わりに hash table を検索できるように、hash tableを使用する必要があるかもしれませんswitch case

于 2013-07-10T06:31:20.237 に答える
0

可能性の高い id 値の分布の特徴がわかっている場合は、case ステートメントで最も可能性の高いものから最も可能性の低いものへの順序でそれらをテストします。

これが頻繁に呼び出される場合は、選択肢を Dictionary に保存することを検討することをお勧めします。それらはシリアル比較なしで解決されるため、実際に 10,002 の選択肢がある場合は、多くの時間を節約できます。

于 2013-07-10T06:27:32.490 に答える
0

問題は、ID の範囲が連続していないことです。対数の深さの条件のカスケード (ここでは約 8) よりも優れた処理を行うコンパイラはありません。

これを解決する方法はenum、連続した ID を取得する を使用することです。その後、コンパイラはジャンプ テーブルを使用して処理を高速化できます。それが機能するかどうかを本当に知るには、アプリケーションの残りの部分をチェックして、値の変更をサポートしているかどうかを確認する必要があります。

于 2013-07-10T06:28:24.153 に答える