Truncation in double precision numbers with atan C

Viewed 176

I am facing what I believe is a numerical precision issue in C with the tan/atan methods. I guess I am missing something here but I do not know what.

I have attached below code I am referring to, which attempts to compute some angles (a and b) from a series of numbers (m6, m7 and m8) that are trigonometric functions applied to these angles (as shown in the comments of the code), Then I am inverting those angles to reconstruct m6, m7 and m8 and comparing them with the original numbers, which I expected to match up to the 14th or 15th digit as I am using double numbers. However, as you can see from the output, there are some numerical differences I cannot explain for the atan cases. Does anyone have an insight on what is going on?

a - atan()  - -0.0003351970075579
a - atan2() - -0.0003351970075579
b - asin()  - 0.0000856336001047
m6 - got      [ -0.0000856336000000 ]
m6 - expected [ -0.0000856336000000 ]

m7 - got      [ -0.0003351970000519 ]
m7 - expected [ -0.0003351970000000 ]

m8 - got      [ 0.9999999401549271 ]
m8 - expected [ 0.9999999400000000 ]

You can execute the code in this link from codepad: http://codepad.org/lzMMcgnb

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

int main()
{
    /* m6 = -sin b*/
    double m6 = -0.0000856336;

    /* m7 = sin a * cos b */
    double m7 = -0.0003351970000000;

    /* m8 = cos a * cos b */
    double m8 = 0.9999999400000000;

    /* a = atan(m7 / m8) = atan2(m7,m8)*/
    double a1 = atan(m7 / m8);
    double a2 = atan2(m7 , m8);
    double b = -asin(m6);

    printf("a - atan()  - %.16f\n", a1);
    printf("a - atan2() - %.16f\n", a2);
    printf("b - asin()  - %.16f\n", b);

    /* Inverse transformation */
    double m6p = -sin(b);
    double m7p = sin(a2) * cos(b);
    double m8p = cos(a2) * cos(b);

    printf("m6 - got      [ %.16f ]\n", m6p);
    printf("m6 - expected [ %.16f ]\n\n", m6);
    printf("m7 - got      [ %.16f ]\n", m7p);
    printf("m7 - expected [ %.16f ]\n\n", m7);
    printf("m8 - got      [ %.16f ]\n", m8p);
    printf("m8 - expected [ %.16f ]\n", m8);

    return 1;

}
1 Answers

As a rule of thumb, any errors in the trigonometric functions which ship as a standard C library implementation that are in the 8th significant onwards ought to be considered as normal. (In my experience, implementations do a better job with sin and cos than with tan and this also applies to the inverses.)

Neither the C standard nor the IEEE754 floating point specifications (a common scheme adopted by floating point in C) require these functions to be as precise as the data types they use (cf. sqrt or the arithmetic operators +, -, *, and / which are required by IEEE754 to return the best possible result). And very many implementations plump for execution speed rather than accuracy.

If you need better precision then you'll need to switch out these functions to ones that guarantee better results.

Related