在没有数学库的情况下逼近atan

时间:2016-02-03 17:38:30

标签: c trigonometry pi math.h

我一直在谷歌上寻找解决这个问题的方法。我已经看到了许多方法来计算任何-1< = theta< = 1的atan(theta),但是当θ大于或小于那些边界时我不知道该怎么做。

我假设我需要加上或减去pi的倍数来抵消它?这种思路是否正确?

目前我有:

double my_atan(double x)
{
    return x - (x*x*x)/3 + (x*x*x*x*x)/5;
}

使用taylor series

对于以下代码,

int x;
for (x=0; x<M_PI*2; x++)
{
    printf("Actual: %f\n",    atan(x));
    printf("Approx: %f\n", my_atan(x));
    printf("\n");
}

它很快失去控制(如预期的那样,因为它超出了范围):

Actual: 0.000000
Approx: 0.000000

Actual: 0.785398
Approx: 0.866667

Actual: 1.107149
Approx: 5.733333

Actual: 1.249046
Approx: 42.600000

Actual: 1.325818
Approx: 187.466667

Actual: 1.373401
Approx: 588.333333

Actual: 1.405648
Approx: 1489.200000

此处未图示,但当θ在适当范围内时,输出相当准确。

所以我的问题是,究竟需要采取哪些步骤才能使my_tan函数支持更广泛的界限?

暂时盯着这一点,因此可以提供任何可以提供的指导

2 个答案:

答案 0 :(得分:3)

让我完成你的例子并谈谈可能会有所帮助的一些事情:

#include <stdio.h>
#include <math.h>


double my_atan(double x)
{
    return x - (x*x*x)/3 + (x*x*x*x*x)/5 - (x*x*x*x*x*x*x)/7;
}

int main()
{
    double x;
    for (x=0.0; x<M_PI*2; x+=0.1)
    {
        printf("x: %f\n",    x);
        printf("Actual: %f\n",    atan(x));
        printf("Approx: %f\n", my_atan(x));
        printf("\n");
    }
}

术语int x是一个整数,您接近大角度。尝试在这里使用双打,你没有转换错误。

现在你的问题。你使用的泰勒系列只有你的| x |才有效&LT; 1。

泰勒系列越不准确,越远离某一点或你的情况为零(0 + x)。

该系列可以很好地运行到pi/4,即使在那时它也是非常不准确的,但是更大的值会非常糟糕。所以对于较小的角度,它的效果非常好。

答案 1 :(得分:3)

我用于定点库的解是使用Remez algorithm的极小极大近似。即使在那里,我在三个范围内使用了一组不同的系数:0到0.5; 0.5到0.75和0.75到1.通过这种分解,我能够获得1 ULP的准确度。

然后你需要很好的参数减少来获得范围内的参数。在我的情况下,我使用了一个好的互惠函数来进行超过1的参数。以下是身份:

atan(-x) == -atan(x)

atan(x) == pi/2 - atan(1/x) // for x > 1

Taylor和Remez近似值nice blog post here;在该网站上也是Remez toolkit,用于查找所需的系数。