ページへ戻る
印刷
技術系備忘録/C++/最適化小手先テクニック/シフト演算の乗除算に注意すべし
をテンプレートにして作成 ::
シンクリッジ
xpwiki
:技術系備忘録/C++/最適化小手先テクニック/シフト演算の乗除算に注意すべし をテンプレートにして作成
開始行:
通説ですが、"2のべき乗での乗除算は、シフト演算(ビットシ...
CPUが高速化されたといっても、乗除算命令はそれなりに遅い処...
-List1
#prettify{{
int Test(int n)
{
// return n * 8; // 掛け算ではなく
return n << 3; // ビットシフトを使う
}
}}
8倍する掛け算なのですが、2進数の仕組みを利用し、ビット...
これは確かに有効な手段であり、古くからあるテクニックで、...
しかし、昨今のコンパイラは、わざわざシフト演算で記述をし...
こうなると、シフト演算で記述しようと、掛け算で記述しよう...
・
・
・
というわけで、以上でこのネタは終わりでもよいのですが、ち...
自分は、昨今の最適化コンパイラを使う場合、素直に掛け算で...
理由は、コードの見易さと間違いの避け易さからです。
2のべき乗という単純な場合であれば、どちらの書き方であっ...
15倍する例を見てみます。(List2)
-List2
#prettify{{
int Test(int n)
{
// return n * 15;
return ( n << 4 ) - n;
}
}}
これは、掛け算をビット演算に分解することで、掛け算命令を...
この場合、最適化の面から言えば問題ないかもしれませんが、...
さらに、最適化の面からも、実は正解ではなさそうです。
List2 をコンパイルした結果(アセンブラ)が List3 です。
-List3
#prettify{{
int Test(int n)
mov eax, DWORD PTR n
lea eax, DWORD PTR [eax+eax*2] // 3倍して
lea eax, DWORD PTR [eax+eax*4] // 5倍する
}
}}
期待した結果とは明らかに違いますが、これがコンパイラの最...
つまり、見辛い上に最適ではないコードを記述してしまったこ...
(というか、どっちの記述でも出力されるアセンブラは List3 ...
以上の結果からわかるように、定数の乗除算程度は、素直にコ...
もちろん、コンパイラが優秀であればという条件が必要になる...
/*
VisualC++の最適化性能がどんなもんか色々試しましたが、定数...
とはいえ、CPU特性などを考慮すると、どういうアセンブラが最...
今回の例でも、コンパイラの出力が最速なのかどうかは確認も...
*/
なお、一つ注意点があります。List4をご覧下さい。
-List4
#prettify{{
int Test(int n)
{
return n / 8;
}
}}
一見何も問題なさそうです。コンパイラはシフト演算するアセ...
しかし、この場合は期待通りにはなりません。
それは型が int (符号付) だからです。単純にビットシフトす...
どうすればよいかというと、符号付として処理する場合はどう...
しかし、"マイナス値の引数はあり得ない"という前提があるの...
-List5
#prettify{{
int Test(int n)
{
return (unsigned int)n / 8;
}
}}
unsigned int にキャストすることで、符号無しで処理しなさい...
もちろん、このキャストによるオーバーヘッドというのはあり...
まとめとして。
昨今の最適化コンパイラのおかげで、定数の乗除算はどのよう...
もちろん、最適化されないコンパイラや環境を使う場合、ビッ...
List2 のような往年のテクニックも十分活かせると思いますの...
なお、言うまでもないかもですが、本ネタは整数演算を前提に...
終了行:
通説ですが、"2のべき乗での乗除算は、シフト演算(ビットシ...
CPUが高速化されたといっても、乗除算命令はそれなりに遅い処...
-List1
#prettify{{
int Test(int n)
{
// return n * 8; // 掛け算ではなく
return n << 3; // ビットシフトを使う
}
}}
8倍する掛け算なのですが、2進数の仕組みを利用し、ビット...
これは確かに有効な手段であり、古くからあるテクニックで、...
しかし、昨今のコンパイラは、わざわざシフト演算で記述をし...
こうなると、シフト演算で記述しようと、掛け算で記述しよう...
・
・
・
というわけで、以上でこのネタは終わりでもよいのですが、ち...
自分は、昨今の最適化コンパイラを使う場合、素直に掛け算で...
理由は、コードの見易さと間違いの避け易さからです。
2のべき乗という単純な場合であれば、どちらの書き方であっ...
15倍する例を見てみます。(List2)
-List2
#prettify{{
int Test(int n)
{
// return n * 15;
return ( n << 4 ) - n;
}
}}
これは、掛け算をビット演算に分解することで、掛け算命令を...
この場合、最適化の面から言えば問題ないかもしれませんが、...
さらに、最適化の面からも、実は正解ではなさそうです。
List2 をコンパイルした結果(アセンブラ)が List3 です。
-List3
#prettify{{
int Test(int n)
mov eax, DWORD PTR n
lea eax, DWORD PTR [eax+eax*2] // 3倍して
lea eax, DWORD PTR [eax+eax*4] // 5倍する
}
}}
期待した結果とは明らかに違いますが、これがコンパイラの最...
つまり、見辛い上に最適ではないコードを記述してしまったこ...
(というか、どっちの記述でも出力されるアセンブラは List3 ...
以上の結果からわかるように、定数の乗除算程度は、素直にコ...
もちろん、コンパイラが優秀であればという条件が必要になる...
/*
VisualC++の最適化性能がどんなもんか色々試しましたが、定数...
とはいえ、CPU特性などを考慮すると、どういうアセンブラが最...
今回の例でも、コンパイラの出力が最速なのかどうかは確認も...
*/
なお、一つ注意点があります。List4をご覧下さい。
-List4
#prettify{{
int Test(int n)
{
return n / 8;
}
}}
一見何も問題なさそうです。コンパイラはシフト演算するアセ...
しかし、この場合は期待通りにはなりません。
それは型が int (符号付) だからです。単純にビットシフトす...
どうすればよいかというと、符号付として処理する場合はどう...
しかし、"マイナス値の引数はあり得ない"という前提があるの...
-List5
#prettify{{
int Test(int n)
{
return (unsigned int)n / 8;
}
}}
unsigned int にキャストすることで、符号無しで処理しなさい...
もちろん、このキャストによるオーバーヘッドというのはあり...
まとめとして。
昨今の最適化コンパイラのおかげで、定数の乗除算はどのよう...
もちろん、最適化されないコンパイラや環境を使う場合、ビッ...
List2 のような往年のテクニックも十分活かせると思いますの...
なお、言うまでもないかもですが、本ネタは整数演算を前提に...
ページ名: