我正在编写一个科学程序,该程序在其主要算法中使用正弦的通用值,即sin(M_PI/N)N = 1, 2, 3, 4, 5, 6

因为我希望程序尽可能快,所以我想:让我们将这些值存储在 vector 中,而不是一遍又一遍地计算它们。看起来像这样:

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);

但是令我惊讶的是,该程序的运行速度几乎快一倍!我真的认为,读取 vector 中的值需要花费这么长时间吗?但是后来我意识到这不是问题所在:如果我改写
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));

然后程序又快了!然后我想到:我的罪恶值(value)观出了点问题。但是疯狂的事情是,即使我只用sin_pi_over_n_.push_back(sin(M_PI/6.0));替换了最后一行sin_pi_over_n_.push_back(0.5);,程序也再次变慢了!关于 double 吗?我有点怀疑:如果我询问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。我仍然要继续提出该问题,因为这种行为对我来说似乎不可思议。如果这种不可预测的现象对性能产生巨大影响,我如何才能优化程序的速度?

感谢您的见解!

编辑:也许我还不够清楚。在我的程序中,我有一个Algo类。当我执行程序时,某些函数(称为my_function)被调用了很多次。在此函数中,一行是:s = sin(M_PI/n);。我以为我会用s = sin_pi_over_n_[n-1];代替这一行,其中sin_pi_over_n_[n-1]是一个存储为Algo类的成员变量的 vector ,我将一劳永逸地填充到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 Creator 4.8 64位。

编辑3或4:对于所有编辑,我深表歉意。我没有告诉您一个重要的信息:程序将运行(基本上称为super_radius_update函数),直到某些错误在一定的公差范围内。因此,使程序变慢或变快的原因不是super_radius_update的执行时间,而是该函数的调用次数,我相信。对sin(M_PI/N)使用这样的值将对错误达到容错的速度产生影响。

最佳答案

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

该代码在s = 0s = 1处都具有奇异性,它们都发生,并且由于奇异性而在数值上不稳定。您可能通过sin_pi_over_n_[0]sin_pi_over_n_[1]的不同计算触发了不稳定。

虽然这不能解释不同sin_pi_over_n_[5]计算的不同行为,但可能会出现类似的不稳定情况。

关于c++ - C++:sin(M_PI/6)= 0.5?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11331932/

10-10 18:28