16

このコードスニペットがあったとしましょう:

#include <cmath>

// ...

float f = rand();
std::cout << sin(f) << " " << sin(f);

sin(f)明確に定義された関数と同様に、簡単な最適化があります。

float f = rand();
float sin_f = sin(f);
std::cout << sin_f << " " << sin_f;

これは、最新のC ++コンパイラが単独で実行することを期待するのに合理的な最適化ですか?または、コンパイラがsin(f)、等しい値に対して常に同じ値を返す必要があると判断する方法はありませんfか?

4

2 に答える 2

18

デフォルトの最適化フラグで構築されたg++の使用:

float f = rand();
40117e: e8 75 01 00 00          call   4012f8 <_rand>
401183: 89 44 24 1c             mov    %eax,0x1c(%esp)
401187: db 44 24 1c             fildl  0x1c(%esp)
40118b: d9 5c 24 2c             fstps  0x2c(%esp)
std::cout << sin(f) << " " << sin(f);
40118f: d9 44 24 2c             flds   0x2c(%esp)
401193: dd 1c 24                fstpl  (%esp)
401196: e8 65 01 00 00          call   401300 <_sin>  <----- 1st call
40119b: dd 5c 24 10             fstpl  0x10(%esp)
40119f: d9 44 24 2c             flds   0x2c(%esp)
4011a3: dd 1c 24                fstpl  (%esp)
4011a6: e8 55 01 00 00          call   401300 <_sin>  <----- 2nd call
4011ab: dd 5c 24 04             fstpl  0x4(%esp)
4011af: c7 04 24 e8 60 40 00    movl   $0x4060e8,(%esp)

で構築-O2

float f = rand();
4011af: e8 24 01 00 00          call   4012d8 <_rand>
4011b4: 89 44 24 1c             mov    %eax,0x1c(%esp)
4011b8: db 44 24 1c             fildl  0x1c(%esp)
std::cout << sin(f) << " " << sin(f);
4011bc: dd 1c 24                fstpl  (%esp)
4011bf: e8 1c 01 00 00          call   4012e0 <_sin>  <----- 1 call

このことから、最適化なしではコンパイラーが2つの呼び出しを使用し、最適化ありでは1つだけを使用することがわかります。経験的には、コンパイラーは呼び出しを最適化すると言えます。

于 2013-01-24T20:04:34.917 に答える
17

sin非標準の純粋な属性を持つGCCマークはかなり確実です。__attribute__ ((pure));

これには次の効果があります。

多くの関数は、戻り値を除いて効果がなく、それらの戻り値はパラメーターやグローバル変数のみに依存します。このような関数は、算術演算子と同じように、共通部分式除去とループ最適化の対象となる可能性があります。

http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

したがって、このような純粋な呼び出しが共通部分式除去によって最適化される可能性は非常に高くなります。

(更新:実際にはcmathはconstexprを使用しています。これは、同じ最適化を意味します)

于 2013-01-24T20:04:28.147 に答える