2

私は、メインのアルゴリズム、つまり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)すると、エラーが許容範囲に到達する速度に影響を与えます。

4

2 に答える 2

1
double rv = radii_[index]*s/(1-s);
return (1-s)*rv/s;

このコードは と に特異点がs = 0ありs = 1、どちらも発生し、特異点のために数値的に不安定になります。と の異なる計算で不安定性を引き起こした可能性がsin_pi_over_n_[0]ありsin_pi_over_n_[1]ます。

これは、計算ごとに異なる動作を説明するものではありませんがsin_pi_over_n_[5]、同様の不安定性が発生する可能性があります。

于 2012-07-04T16:27:41.737 に答える
0

指摘されたように、私のアルゴリズムは不安定であることが判明し、コンピューターや C++ のせいにすることはできませんでした ;)

于 2012-09-10T19:10:19.053 に答える