我正在编写一个科学程序,它在其主要算法中使用正弦的共同值,即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);
.
但令我大吃一惊的是,该程序的速度几乎是原来的两倍!我想,真的,读取向量中的值需要那么长时间吗?但后来我意识到这不是问题所在:如果我改写
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
. 我仍然会继续发布这个问题,因为这种行为对我来说似乎不可思议。如果这种不可预知的现象对性能有如此大的影响,我怎么可能优化我的程序的速度?
感谢您的见解!
编辑:也许我还不够清楚。在我的程序中,我有一堂课Algo
。当我执行我的程序时,某个函数,比如说my_function
,被调用了很多次。在这个函数中,一行是: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 creator 4.8 64 位。
编辑 3 或 4:我为所有的编辑道歉。有一条重要的信息我没有告诉你:程序将运行(基本上是调用函数super_radius_update
),直到某些错误落在某个容差范围内。因此,我相信使程序变慢或变快的不是执行时间,super_radius_update
而是该函数的调用次数。使用这样或这样的值sin(M_PI/N)
将对错误达到容差的速度产生影响。