私は、メインのアルゴリズム、つまりsin(M_PI/N)
forでサインの一般的な値を使用する科学プログラムを書いていN = 1, 2, 3, 4, 5, 6
ます。
プログラムをできるだけ高速にしたいので、これらの値を何度も計算するのではなく、ベクトルに格納しようと考えました。次のようになります。
sin_pi_over_n_.clear();
sin_pi_over_n_.push_back(0.0);
sin_pi_over_n_.push_back(1.0);
sin_pi_over_n_.push_back(sqrt(3.0)/2.0);
sin_pi_over_n_.push_back(sqrt(2.0)/2.0);
sin_pi_over_n_.push_back(sqrt(2.0)*0.25*sqrt(5.0-sqrt(5.0)));
sin_pi_over_n_.push_back(0.5);
だから今、私のメインアルゴリズムでは、s = sin_pi_over_n_[n-1];
の代わりに書いていs = sin(M_PI/n);
ます。
しかし、驚いたことに、プログラムはほぼ 2 倍遅くなりました。ベクトルの値を読み取るのにそんなに時間がかかるのだろうか?しかし、それは問題ではないことに気付きました。
sin_pi_over_n_.push_back(sin(M_PI/1.0));
sin_pi_over_n_.push_back(sin(M_PI/2.0));
sin_pi_over_n_.push_back(sin(M_PI/3.0));
sin_pi_over_n_.push_back(sin(M_PI/4.0));
sin_pi_over_n_.push_back(sin(M_PI/5.0));
sin_pi_over_n_.push_back(sin(M_PI/6.0));
その後、プログラムは再び高速になります。それから私は考えました:サインの値に何か問題があります。しかし、クレイジーなことは、最後の行sin_pi_over_n_.push_back(sin(M_PI/6.0));
を置き換えるだけでもsin_pi_over_n_.push_back(0.5);
、プログラムが再び遅くなることです! 倍精度についてですか?std::cout << abs(sin(M_PI/6.0) - 0.5) << std::endl;
私はそれをちょっと疑っています0
.
おっと:今気づきました。std::cout << sin(M_PI/6.0) - 0.5 << std::endl;
( なしでabs
)尋ねると、 が得られ-5.55112e-17
ます。この振る舞いは私には信じられないように思えるので、私はまだ先に進んでその質問を投稿するつもりです. このような予測不可能な現象がパフォーマンスに大きな影響を与える場合、プログラムの速度を最適化するにはどうすればよいでしょうか?
あなたの洞察に感謝します!
編集:多分私は自分自身を十分に明確にしていません。私のプログラムには、 class がありAlgo
ます。プログラムを実行すると、ある関数、たとえばmy_function
が膨大な回数呼び出されます。この関数の 1 行は次のとおりs = sin(M_PI/n);
です。この行を に置き換えると思いましたs = sin_pi_over_n_[n-1];
。ここで、sin_pi_over_n_[n-1]
はクラスのメンバー変数として格納されているベクトルでありAlgo
、のコンストラクターに一度だけ入力しAlgo
ます。物事がより明確になることを願っています。
編集 2 : わかりました。さらにコードを投稿してほしいという方もいるようです。ここに来ます:
クラスAlgo
:
class Algo : public QThread
{
Q_OBJECT
public:
Algo() {}
void reset_algo(...)
public slots:
void run();
private:
void create_sines();
double super_total_neighbors_angle(const unsigned int &index, double &error);
double super_radius_update(const unsigned int &index, double &error);
// etc
std::vector<double> radii_;
std::vector<double> sin_pi_over_n_;
std::vector<unsigned int> neighbors_lists_sizes_;
// etc
};
メンバー関数create_sines
:
void Algo::create_sines()
{
sin_pi_over_n_.clear();
/*sin_pi_over_n_.push_back(0.0);
sin_pi_over_n_.push_back(1.0);
sin_pi_over_n_.push_back(0.5*sqrt(3.0));
sin_pi_over_n_.push_back(0.5*sqrt(2.0));
sin_pi_over_n_.push_back(0.25*sqrt(2.0)*sqrt(5.0-sqrt(5.0)));
sin_pi_over_n_.push_back(0.5);*/
sin_pi_over_n_.push_back(sin(M_PI/1.0));
sin_pi_over_n_.push_back(sin(M_PI/2.0));
sin_pi_over_n_.push_back(sin(M_PI/3.0));
sin_pi_over_n_.push_back(sin(M_PI/4.0));
sin_pi_over_n_.push_back(sin(M_PI/5.0));
sin_pi_over_n_.push_back(sin(M_PI/6.0));
return;
}
メンバー関数super_radius_update
(my_function
上記で名前を変更しました):
inline double Algo::super_radius_update(const unsigned int &index, double &error)
{
int n = neighbors_lists_sizes_[index];
double s = sin(super_total_neighbors_angle(index, error)*0.5/n);
double rv = radii_[index]*s/(1-s);
//s = sin(M_PI/n);
s = sin_pi_over_n_[n-1];
return (1-s)*rv/s;
}
クラス全体が少し長くて複雑なので、実行できる最小限の完全な例を送るのは難しいと思います。試すことはできますが、大量のコードを投稿する必要があり、抽出するのにかなりの時間がかかります...
Linux Ubuntu 12.04 64 ビット ラップトップで Qt クリエーター 4.8 64 ビットを使用しています。
編集 3 または 4 : すべての編集についてお詫び申し上げます。お伝えしなかった重要な情報がありますsuper_radius_update
。エラーが許容範囲内に収まるまで、プログラムは実行されます (基本的に関数を呼び出します)。結果として、プログラムが遅くなったり速くなったりするのは、 の実行時間ではなく、super_radius_update
その関数の呼び出し回数だと思います。そのような値を使用sin(M_PI/N)
すると、エラーが許容範囲に到達する速度に影響を与えます。