有没有考虑过C/C++函数中三角函数是如何计算出来的呢?
三角函数原理:数学书告诉我们任何函数都可以通过泰勒展开找到近似解。常见三角函数的泰勒展开如下:
实现代码为:
//以sin()为例
int main (void)
{
int n;
float x, term ,sum;
n=1;
printf("Enter a number x : ");
scanf("%f",&x); //输入值
term = sum = x;
do {
n+=2;
term *=(-x * x)/((float)(n)-1)/(float)(n); //阶乘过程存储
sum +=term; //计算多项式值
} while ( fabs(term)>=1e-8); //满足精度跳出循环
printf("sin(%f) = %f",x,sum); //结果输出,单位弧度
return 0;
}
atan优化:为了加速计算过程,可以使用多项式逼近的方法进行优化。 根据,可以将计算范围缩小到[0, pi/2]。即区3的值可以通过区2和区1值经过变换得到。 根据,可以将计算范围缩小到[0, pi/4]。即区2值可以通过区1值经过变换得到。
根据多项式近似 根据Remez算法或者切比雪夫近似可以得到pn的参数值。这里不在具体介绍,可以参考https://en.wikipedia.org/wiki/Remez_algorithm 根据Remez算法得到的程序实例:
a := min (|x|, |y|) / max (|x|, |y|)
s := a * a
r := ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a
if |y| > |x| then r := 1.57079637 - r
if x < 0 then r := 3.14159274 - r
if y < 0 then r := -r
以下是OpenCV的计算源码,位置在 opencv/sources/modules/core/src/mathfuncs.cpp 文件中。
static const float atan2_p1 = 0.9997878412794807f*(float)(180/CV_PI);
static const float atan2_p3 = -0.3258083974640975f*(float)(180/CV_PI);
static const float atan2_p5 = 0.1555786518463281f*(float)(180/CV_PI);
static const float atan2_p7 = -0.04432655554792128f*(float)(180/CV_PI);
float fastAtan2( float y, float x )
{
float ax = std::abs(x), ay = std::abs(y); //区域3转为区2和区1
float a, c, c2;
if( ax >= ay )
{
//区1计算方法
c = ay/(ax + (float)DBL_EPSILON);
c2 = c*c;
a = (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
}
else
{
//区2计算方法
c = ax/(ay + (float)DBL_EPSILON);
c2 = c*c;
a = 90.f - (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
}
if( x < 0 )
a = 180.f - a;
if( y < 0 )
a = 360.f - a;
return a;
}
可以看到稍微是有点区别的,两种方法和标准方法的误差图如下,红色是第一种方法误差图,蓝色线是OpenCV使用的误差结果,可以看出,OpenCV的拟合效果略优。
|