这不是关于模板黑客或处理编译器怪癖的问题。我理解为什么Boost库就是它们的样子。这是关于Boost数学库中sinc_pi
函数使用的实际算法。
函数sinc(x)
相当于sin(x)/x
。
在Boost数学库sinc_pi()
的{{3}}中,它表示" Taylor系列用于确保准确性"。这似乎是荒谬的,因为浮点数的划分不会导致精度损失比乘法更多。除非sin
的特定实现中存在错误,否则
double sinc(double x) {if(x == 0) return 1; else return sin(x)/x;}
好像很好。
我已经对此进行了测试,并且初始版本与Boost数学工具包中的最大版本之间的最大相对差异仅为所用类型的epsilon的一半,对于float和double,它将它放在与离散化误差相同的比例。此外,该最大差异不会发生在0附近,而是接近Boost版本使用部分泰勒级数(即abs(x) < epsilon**(1/4)
)的区间的末尾。这使得它看起来实际上是泰勒级数近似(非常轻微)错误,或者通过在间隔末端附近的精度损失或者通过多次操作的重复舍入来实现。
以下是我编写的用于测试此程序的结果,它在0和1之间迭代每个float
并计算Boost结果与天真结果之间的相对差异:
Test for type float:
Max deviation from Boost result is 5.96081e-08 relative difference
equals 0.500029 * epsilon
at x = 0.0185723
which is epsilon ** 0.25003
这是程序的代码。它可用于对任何浮点类型执行相同的测试,并且需要大约一分钟才能运行。
#include <cmath>
#include <iostream>
#include "boost/math/special_functions/sinc.hpp"
template <class T>
T sinc_naive(T x) { using namespace std; if (x == 0) return 1; else return sin(x) / x; }
template <class T>
void run_sinc_test()
{
using namespace std;
T eps = std::numeric_limits<T>::epsilon();
T max_rel_err = 0;
T x_at_max_rel_err = 0;
for (T x = 0; x < 1; x = nextafter(static_cast<float>(x), 1.0f))
{
T boost_result = boost::math::sinc_pi(x);
T naive_result = sinc_naive(x);
if (boost_result != naive_result)
{
T rel_err = abs(boost_result - naive_result) / boost_result;
if (rel_err > max_rel_err)
{
max_rel_err = rel_err;
x_at_max_rel_err = x;
}
}
}
cout << "Max deviation from Boost result is " << max_rel_err << " relative difference" << endl;
cout << "equals " << max_rel_err / eps << " * epsilon" << endl;
cout << "at x = " << x_at_max_rel_err << endl;
cout << "which is epsilon ** " << log(x_at_max_rel_err) / log(eps) << endl;
cout << endl;
}
int main()
{
using namespace std;
cout << "Test for type float:" << endl << endl;
run_sinc_test<float>();
cout << endl;
cin.ignore();
}