与libc相比,Gnu科学图书馆的性能较差



我实现了一个简单的程序来测量gnu科学库和libc的罪恶计算性能。这是一个源代码:

#include <iostream>
#include <vector>
#include <math.h>
#include <chrono>
#include <list>
#include "gsl/gsl_sf_trig.h"
int main()
{
std::uint32_t numStepsToCalculate = 1000000;
const double startX = 0.0;
const double finishX = M_PI*2;
const double stepX  = (finishX - startX)/numStepsToCalculate;
double currentX = startX;
std::list<double> res;
auto startT = std::chrono::steady_clock::now();
while ( currentX <= finishX ) {
res.push_back( sin ( currentX ) );
currentX += stepX;
}
auto endT = std::chrono::steady_clock::now();
auto diffT = endT - startT;
std::cout << "STD : " << std::chrono::duration <double, std::milli> (diffT).count() << " ms" << std::endl;
std::cout << "STD res size " << res.size() << std::endl;
std::list<double> resOpt;
currentX = startX;
auto startTopt = std::chrono::steady_clock::now();
while ( currentX <= finishX ) {
resOpt.push_back( gsl_sf_sin ( currentX ) );
currentX += stepX;
}
auto endTopt = std::chrono::steady_clock::now();
auto diffTopt = endTopt - startTopt;
std::cout << "GSL : " << std::chrono::duration <double, std::milli> (diffTopt).count() << " ms" << std::endl;
std::cout << "GSL res size " << resOpt.size() << std::endl;
return 0;
}

这是一个结果: 标准 : 57.8869 ms GSL : 106.787 ms

那么GSL比libc慢

可以吗?

GSL使用软件罪(即使CPU罪恶可用(,它也可以给你错误估计:gsl_sf_sin目前只是一个包装器gsl_sf_sin_e(给出错误估计(。此例程没有针对速度进行太多优化。

另一方面,libc sin通常针对速度进行了很好的优化。

此外,您的基准测试可能存在缺陷,因为如果启用了优化,编译器可能会优化sin

不幸的是,我无法发表评论,所以我将其作为单独的答案发布。 我认为@geza的回答是正确的,我只想补充一些细节。 根据GSL源代码,它们有自己的三角函数实现:

/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/
/* I would have prefered just using the library sin() function.
* But after some experimentation I decided that there was
* no good way to understand the error; library sin() is just a black box.
* So we have to roll our own.
*/
int
gsl_sf_sin_e(double x, gsl_sf_result * result)
{
/* CHECK_POINTER(result) */
{
const double P1 = 7.85398125648498535156e-1;
const double P2 = 3.77489470793079817668e-8;
const double P3 = 2.69515142907905952645e-15;
const double sgn_x = GSL_SIGN(x);
const double abs_x = fabs(x);
if(abs_x < GSL_ROOT4_DBL_EPSILON) {
const double x2 = x*x;
result->val = x * (1.0 - x2/6.0);
result->err = fabs(x*x2*x2 / 100.0);
return GSL_SUCCESS;
}
else {
double sgn_result = sgn_x;
double y = floor(abs_x/(0.25*M_PI));
int octant = y - ldexp(floor(ldexp(y,-3)),3);
int stat_cs;
double z;
if(GSL_IS_ODD(octant)) {
octant += 1;
octant &= 07;
y += 1.0;
}
if(octant > 3) {
octant -= 4;
sgn_result = -sgn_result;
}
z = ((abs_x - y * P1) - y * P2) - y * P3;
if(octant == 0) {
gsl_sf_result sin_cs_result;
const double t = 8.0*fabs(z)/M_PI - 1.0;
stat_cs = cheb_eval_e(&sin_cs, t, &sin_cs_result);
result->val = z * (1.0 + z*z * sin_cs_result.val);
}
else { /* octant == 2 */
gsl_sf_result cos_cs_result;
const double t = 8.0*fabs(z)/M_PI - 1.0;
stat_cs = cheb_eval_e(&cos_cs, t, &cos_cs_result);
result->val = 1.0 - 0.5*z*z * (1.0 - z*z * cos_cs_result.val);
}
result->val *= sgn_result;
if(abs_x > 1.0/GSL_DBL_EPSILON) {
result->err = fabs(result->val);
}
else if(abs_x > 100.0/GSL_SQRT_DBL_EPSILON) {
result->err = 2.0 * abs_x * GSL_DBL_EPSILON * fabs(result->val);
}
else if(abs_x > 0.1/GSL_SQRT_DBL_EPSILON) {
result->err = 2.0 * GSL_SQRT_DBL_EPSILON * fabs(result->val);
}
else {
result->err = 2.0 * GSL_DBL_EPSILON * fabs(result->val);
}
return stat_cs;
}
}
}

您应该记住,GSL 是由科学家和为科学家创建的库。因此,您需要一种方法来控制结果及其正确性(有关详细信息,请参阅上面的评论和此答案(,在这种情况下,速度是次要的。

同时,您需要记住,系统三角函数是由聪明的IBM人实现的,他们知道如何使其快速(并且绝对不可读(。

最新更新