Search code examples
ctrigonometrypimath.h

Approximating atan without a math library


I've been googling around for a solution to this problem. I've seen a number of ways to calculate atan(theta) for any -1 <= theta <= 1, but I am not sure what to do when theta is bigger or smaller than those bounds.

I assume I need to add or subtract multiples of pi to offset it? Is this line of thinking correct?

Currently I have:

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

Which is using the taylor series.

And for the following code,

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");
}

It quickly loses control (as expected, as it's out of range):

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

Not pictured here, but the output is fairly accurate when theta is within the appropriate range.

So my question is what steps exactly need to be taken to the my_tan function to allow it to support wider bounds?

Been staring at this for a while and so any guidance that can be offered would be much appreciated


Solution

  • Let me complete your example and talk about some things that might help:

    #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");
        }
    }
    

    The term int x is an integer and you are approximating large angles. try to use doubles here you get no conversioncast errors.

    Now to your problem. The Taylor series you use only works if your |x| < 1.

    Taylor Series get inaccurate the more you get away from a given point or in your case zero (0+x).

    That series works well up to pi/4, even at that point it is very inaccurate but larger values get very bad. So for smaller angles it works well enough.