最近、奇妙な問題に遭遇したとき、私は個人的なプロジェクトに取り組んでいました。
非常にタイトなループでは、0〜15の値の整数があります。値0、1、8、9の場合は-1を取得し、値4、5、12、13の場合は1を取得する必要があります。
私はいくつかのオプションを確認するためにgodboltを使用しましたが、コンパイラーがifチェーンと同じ方法でswitchステートメントを最適化できないようであることに驚きました。
リンクはここにあります:https://godbolt.org/z/WYVBFl
コードは次のとおりです。
const int lookup[16] = {-1, -1, 0, 0, 1, 1, 0, 0, -1, -1, 0, 0, 1, 1, 0, 0};
int a(int num) {
return lookup[num & 0xF];
}
int b(int num) {
num &= 0xF;
if (num == 0 || num == 1 || num == 8 || num == 9)
return -1;
if (num == 4 || num == 5 || num == 12 || num == 13)
return 1;
return 0;
}
int c(int num) {
num &= 0xF;
switch (num) {
case 0: case 1: case 8: case 9:
return -1;
case 4: case 5: case 12: case 13:
return 1;
default:
return 0;
}
}
私はbとcで同じ結果が得られると考えていましたが、解決策(switchステートメント-別の形式)がかなり遅いため、ビットハックを読んで効率的な実装を自分で作成できることを期待していました。
奇妙なことに、かなり最適化されていないか、ターゲットのハードウェアに依存する別のケースに削減されているb
間、ビットハックにコンパイルさc
れましたa
。
なぜこの矛盾があるのか誰かが説明できますか?このクエリを最適化する「正しい」方法は何ですか?
編集:
明確化
私が欲しいスイッチソリューションは、最速、または同様に「クリーン」なソリューションであること。ただし、私のマシンで最適化を使用してコンパイルすると、ifソリューションの方が大幅に高速になります。
デモンストレーション用の簡単なプログラムを作成したところ、TIOはローカルで見つけたのと同じ結果を得ました。オンラインで試してみてください!
static inline
ルックアップテーブルは少しスピードアップ:オンラインそれをお試しください!
if
それでもビートしますswitch
(奇妙にルックアップがさらに速くなります)[フォローするTIO]
-O3
にコンパイルc
しましたが、それよりもa
またはより悪い何かにコンパイルされましたb
(c
2つの条件付きジャンプといくつかのビット操作があったのに対して、1つの条件付きジャンプとより簡単なビット操作しかなかったb
)。素朴なアイテムごとのテストよりも優れています。ここで本当に何を求めているのかわかりません。単純な事実は、最適化コンパイラを回すことができるということですどんなにこれらのを任意の選択したので、それならば、他の、それがまたは行うことはありませんでしょう何のための厳格なルールはありません。