我已经实现了一个简单的程序,用于通过gnu科学库和libc测量sin计算性能。这是源代码:
#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毫秒
那么GSL比libc慢还可以吗?
答案 0 :(得分:1)
GSL使用软件sin(即使有可用的CPU sin),它也可以为您提供错误估计:gsl_sf_sin
只是当前gsl_sf_sin_e
的包装器(提供错误估计)。这个例程的速度没有优化太多。
另一方面,libc sin通常在速度方面进行了很好的优化。
此外,您的基准测试可能存在缺陷,因为如果启用了优化,编译器会优化sin
。
答案 1 :(得分:0)
很遗憾,我无法发表评论,因此将其作为单独的答案发布。 我认为@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是由科学家创建并供科学家使用的库。因此,您需要一种方法来控制结果及其正确性(有关详细信息,请参见上面的注释和this answer),在这种情况下,速度是次要的。
与此同时,您需要记住,系统三角函数是由聪明的IBM人实现的,他们知道如何快速(绝对不可读)。