GPU 実装と比較するために、float と double の両方を使用する数値アルゴリズムのベンチマークを行うテンプレート コードを作成していました。
浮動小数点コードが遅いことがわかりました。Intel の Vtune Amplifier を使用して調査した結果、g++ が余分な x86 命令 (cvtps2pd/cvtpd2ps および unpcklps/unpcklpd) を生成して、いくつかの中間結果を float から double に変換してから再び戻すことを発見しました。このアプリケーションのパフォーマンスの低下は、ほぼ 10% です。
フラグ -Wdouble-promotion (ところで、-Wall または -Wextra には含まれていません) を使用してコンパイルした後、十分な g++ が結果が昇格されていることを警告しました。
これを以下に示す簡単なテストケースに減らしました。C++ コードの順序は、生成されるコードに影響することに注意してください。複合ステートメント (T d1 = log(r)/r;) は警告を生成しますが、分離されたバージョン (T d = log(r); d/=r;) は生成しません。
以下は、g++-4.6.3-1ubuntu5 と g++-4.7.3-2ubuntu1~12.04 の両方でコンパイルされ、同じ結果になりました。
コンパイル フラグは次のとおりです。
g++-4.7 -O2 -Wdouble-promotion -Wextra -Wall -pedantic -Werror -std=c++0x test.cpp -o test
#include <cstdlib>
#include <iostream>
#include <cmath>
template <typename T>
T f()
{
T r = static_cast<T>(0.001);
// Gives no double promotion warning
T d = log(r);
d/=r;
// Promotes to double
T d1 = log(r)/r;
return d+d1;
}
int main()
{
float f1 = f<float>();
std::cout << f1 << std::endl;
}
ここで、c++11 標準ではコンパイラの裁量が許可されていることを認識しています。しかし、なぜ順序が重要なのでしょうか?
この計算だけに float を使用するように g++ に明示的に指示できますか?
編集:Mike Seymourによって解決されました。C を呼び出す代わりに、 std::log を使用してオーバーロードされたバージョンのログを確実に取得する必要がありましたdouble log(double)
。これはコンバージョンであってプロモーションではないため、分離されたステートメントに対して警告は生成されませんでした。